From 8fbc32fc329d864aed8da1cc8c08c961c00a88e6 Mon Sep 17 00:00:00 2001 From: appletreeisyellow Date: Thu, 11 Feb 2016 15:29:30 -0800 Subject: [PATCH 01/22] fix(charts): fix the label of pie chart. Now support labelling in strings --- app/scripts/analysis/charts/charts.coffee | 75 +++++++++-------------- 1 file changed, 28 insertions(+), 47 deletions(-) diff --git a/app/scripts/analysis/charts/charts.coffee b/app/scripts/analysis/charts/charts.coffee index 4641ecf3..3ee303ec 100644 --- a/app/scripts/analysis/charts/charts.coffee +++ b/app/scripts/analysis/charts/charts.coffee @@ -130,7 +130,7 @@ charts = angular.module('app_analysis_charts', []) for i in [1...len] by 1 tmp = - x: parseFloat _chartData[$scope.graphInfo.x][i].value + x: _chartData[$scope.graphInfo.x][i].value obj.push tmp else if $scope.graphInfo.y isnt "" and $scope.graphInfo.z is "" @@ -138,8 +138,8 @@ charts = angular.module('app_analysis_charts', []) for i in [1...len] by 1 tmp = - x: parseFloat _chartData[$scope.graphInfo.x][i].value - y: parseFloat _chartData[$scope.graphInfo.y][i].value + x: _chartData[$scope.graphInfo.x][i].value + y: _chartData[$scope.graphInfo.y][i].value obj.push tmp else @@ -147,9 +147,9 @@ charts = angular.module('app_analysis_charts', []) for i in [1...len] by 1 tmp = - x: parseFloat _chartData[$scope.graphInfo.x][i].value - y: parseFloat _chartData[$scope.graphInfo.y][i].value - z: parseFloat _chartData[$scope.graphInfo.z][i].value + x: _chartData[$scope.graphInfo.x][i].value + y: _chartData[$scope.graphInfo.y][i].value + z: _chartData[$scope.graphInfo.z][i].value obj.push tmp return obj @@ -396,74 +396,55 @@ charts = angular.module('app_analysis_charts', []) .factory 'pie', [ () -> - pieData = null + valueSum = 0 makePieData = (data) -> - pieMax = d3.max(data, (d)->parseFloat d.x) - pieMin = d3.min(data, (d)->parseFloat d.x) - maxPiePieces = 7 # set magic constant to variable - rangeInt = Math.ceil((pieMax - pieMin)/maxPiePieces) - console.log rangeInt - piePieces = new Array(maxPiePieces - 1) # create array with numbers of pie pieces - for i in [0..maxPiePieces-1] by 1 - piePieces[i] = [] - - for el in data - index = Math.floor((el.x - pieMin)/rangeInt) - piePieces[index].push(el.x) # assign each el.x to a piePiece - console.log "piePieces[" + index + "]=" + piePieces[index] - - obj = {} - for i in [0..maxPiePieces-1] by 1 - obj[i] = piePieces[i].length - - pieData = d3.entries obj - for d in pieData - d.key = (d.key*rangeInt)+pieMin+"-"+((d.key-1)*rangeInt)+pieMin - return pieData + counts = {} + for i in [0..data.length-1] by 1 + currentVar = data[i].x + counts[currentVar] = counts[currentVar] || 0 + counts[currentVar]++ + valueSum++ + obj = d3.entries counts + return obj _drawPie = (data,width,height,_graph) -> - makePieData(data) radius = Math.min(width, height) / 2 - arc = d3.svg.arc() .outerRadius(radius) .innerRadius(0) - labelArc = d3.svg.arc() - .outerRadius(radius-10) - .innerRadius(radius-10) - - color = d3.scale.ordinal().range(["#ffffcc","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#0c2c84"]) - + #color = d3.scale.ordinal().range(["#ffffcc","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#0c2c84"]) + color = d3.scale.category20c() arcOver = d3.svg.arc() .outerRadius(radius + 10) - # .innerRadius(0+10) pie = d3.layout.pie() -#.value (d) -> d.count - .value (d) -> parseFloat d.value - type = (d) -> - d.y = +d.y - return d + .value((d)-> d.value) + .sort(null) + + formatted_data = makePieData(data) + console.log pie(formatted_data) arcs = _graph.selectAll(".arc") - .data(pie(pieData)) + .data(pie(formatted_data)) .enter() .append('g') .attr("class", "arc") arcs.append('path') .attr('d', arc) - .attr('fill', (d) -> color(d.data.key)) - .on('mouseenter', (d) -> d3.select(this).attr("stroke","white").transition().attr("d", arcOver).attr("stroke-width",5)) + .attr('fill', (d) -> color(d.data.value)) + .on('mouseenter', (d) -> d3.select(this).attr("stroke","white") .transition().attr("d", arcOver).attr("stroke-width",3)) .on('mouseleave', (d) -> d3.select(this).transition().attr('d', arc).attr("stroke", "none")) arcs.append('text') .attr('id','tooltip') .attr('transform', (d) -> 'translate('+arc.centroid(d)+')') .attr('text-anchor', 'middle') - .text (d) -> d.data.key + .text (d) -> d.data.key + ': ' + parseFloat(100*d.data.value/valueSum).toFixed(2) + '%' + drawPie: _drawPie + ] .factory 'bubble', [ From c852685dd1efcf7e5bbd0cd62d5af847f96736fe Mon Sep 17 00:00:00 2001 From: appletreeisyellow Date: Thu, 11 Feb 2016 15:53:40 -0800 Subject: [PATCH 02/22] fix(charts): fixes the domain of x-axis of Histogram --- app/scripts/analysis/charts/charts.coffee | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/app/scripts/analysis/charts/charts.coffee b/app/scripts/analysis/charts/charts.coffee index 3ee303ec..a9c7dca5 100644 --- a/app/scripts/analysis/charts/charts.coffee +++ b/app/scripts/analysis/charts/charts.coffee @@ -311,14 +311,14 @@ charts = angular.module('app_analysis_charts', []) .factory 'histogram',[ () -> - _drawHist = (_graph,data,container,gdata,width,height) -> + _drawHist = (_graph,data,container,gdata,width,height,ranges) -> container.append('input').attr('id', 'slider').attr('type','range').attr('min', '1').attr('max','10').attr('step', '1').attr('value','5') bins = null dataHist = null arr = data.map (d) -> parseFloat d.x - x = d3.scale.linear().domain([0,d3.max arr]).range([0,width]) + x = d3.scale.linear().domain([ranges.xMin, ranges.xMax]).range([0,width]) plotHist = (bins) -> @@ -326,7 +326,7 @@ charts = angular.module('app_analysis_charts', []) container.append('text').attr('id', 'slidertext').text('Bin Slider: '+bins).attr('position','relative').attr('left', '50px') dataHist = d3.layout.histogram().bins(bins)(arr) - y = d3.scale.linear().domain([0, d3.max dataHist.map (i) -> i.length]).range([0, height]) + y = d3.scale.linear().domain([0,d3.max dataHist.map (i) -> i.length]).range([height,0]) yAxis = d3.svg.axis().scale(y).orient("left") xAxis = d3.svg.axis().scale(x).orient("bottom") @@ -365,19 +365,21 @@ charts = angular.module('app_analysis_charts', []) bar.enter() .append("g") + rect_width = width/bins bar.append('rect') -# .style('fill', 'steelblue') - .attr('x', (d,i) -> x d.x) + .attr('x', (d) -> x d.x) .attr('y', (d) -> height - y d.y) - .attr('width', (d) -> x d.dx) + .attr('width', rect_width) .attr('height', (d) -> y d.y) + .attr("stroke","white") + .attr("stroke-width",1) .on('mouseover', () -> d3.select(this).transition().style('fill', 'orange')) .on('mouseout', () -> d3.select(this).transition().style('fill', 'steelblue')) bar.append('text') - .attr('x', (d,i) -> x d.x) + .attr('x', (d) -> x d.x) .attr('y', (d) -> height - y d.y) - .attr('dx', (d) -> .5*x d.dx) + .attr('dx', (d) -> .5*rect_width) .attr('dy', '20px') .attr('fill', '#fff') .attr('text-anchor', 'middle') @@ -602,7 +604,7 @@ charts = angular.module('app_analysis_charts', []) when 'Bubble Chart' bubble.drawBubble(ranges,width,height,_graph,data,gdata,container) when 'Histogram' - histogram.drawHist(_graph,data,container,gdata,width,height) + histogram.drawHist(_graph,data,container,gdata,width,height,ranges) when 'Pie Chart' _graph = svg.append('g').attr("transform", "translate(300,250)").attr("id", "remove") pie.drawPie(data,width,height,_graph) From 4e4b9f97bd7202e690b2bc932bedfd4628ebc5bc Mon Sep 17 00:00:00 2001 From: Nellie Ponarul Date: Mon, 15 Feb 2016 14:06:56 -0800 Subject: [PATCH 03/22] feat(charts): add categorical data format for pie chart and bar charts --- app/partials/analysis/charts/sidebar.jade | 3 + app/scripts/analysis/charts/charts.coffee | 143 +++++++++++++--------- 2 files changed, 86 insertions(+), 60 deletions(-) diff --git a/app/partials/analysis/charts/sidebar.jade b/app/partials/analysis/charts/sidebar.jade index 99368294..10d7b604 100644 --- a/app/partials/analysis/charts/sidebar.jade +++ b/app/partials/analysis/charts/sidebar.jade @@ -4,6 +4,9 @@ div(ng-controller="sideChartsCtrl") h4 Variables div p {{graphSelect.message}} + div(ng-show=categorical).form-inline + input(ng-model="selectorCat" type="checkbox" id="categorical") + p X is a categorical variable div.form-inline div.form-horizontal(ng-show="graphSelect.x") label(for = "x") Add X diff --git a/app/scripts/analysis/charts/charts.coffee b/app/scripts/analysis/charts/charts.coffee index 4641ecf3..b0ce8688 100644 --- a/app/scripts/analysis/charts/charts.coffee +++ b/app/scripts/analysis/charts/charts.coffee @@ -71,7 +71,9 @@ charts = angular.module('app_analysis_charts', []) $scope.selector1 = {} $scope.selector2 = {} $scope.selector3 = {} + $scope.selectorCat = false + $scope.categorical = false $scope.graphInfo = graph: "" @@ -85,7 +87,7 @@ charts = angular.module('app_analysis_charts', []) x: true y: false z: false - message: "Choose a numerical variable for x and a categorical variable for y." + message: "Choose a numerical variable for x and a categorical variable for y, or choose a categorical variable for x and indicate that it is categorical." , name: 'Scatter Plot' value: 1 @@ -121,7 +123,39 @@ charts = angular.module('app_analysis_charts', []) $scope.createGraph = () -> - graphFormat = () -> + if $("input[id='categorical']:checked").length > 0 + selectorCat = true + else + selectorCat = false + + categoricalGraphFormat = () -> + len = _chartData[0].length + obj = [] + + #check if first value is a string + if isNaN(parseFloat _chartData[$scope.graphInfo.x][0].value) + #makes array of all the categorical values + names = [] + names[0] = _chartData[$scope.graphInfo.x][0].value + for i in [0...len] by 1 + if jQuery.inArray(_chartData[$scope.graphInfo.x][i].value, names) == -1 + names.push _chartData[$scope.graphInfo.x][i].value + + #creates count objects with the categorical values + for j in [0...names.length] by 1 + tmp = + label: names[j] + count: 0 + obj.push tmp + + #iterates through the data and adds counts + for k in [0...len] by 1 + for j in [0...obj.length] by 1 + if names[j] == _chartData[$scope.graphInfo.x][k].value + obj[j].count++ + + return obj + numericGraphFormat = () -> obj = [] len = _chartData[0].length @@ -130,7 +164,7 @@ charts = angular.module('app_analysis_charts', []) for i in [1...len] by 1 tmp = - x: parseFloat _chartData[$scope.graphInfo.x][i].value + x: _chartData[$scope.graphInfo.x][i].value obj.push tmp else if $scope.graphInfo.y isnt "" and $scope.graphInfo.z is "" @@ -138,8 +172,8 @@ charts = angular.module('app_analysis_charts', []) for i in [1...len] by 1 tmp = - x: parseFloat _chartData[$scope.graphInfo.x][i].value - y: parseFloat _chartData[$scope.graphInfo.y][i].value + x: _chartData[$scope.graphInfo.x][i].value + y: _chartData[$scope.graphInfo.y][i].value obj.push tmp else @@ -147,13 +181,16 @@ charts = angular.module('app_analysis_charts', []) for i in [1...len] by 1 tmp = - x: parseFloat _chartData[$scope.graphInfo.x][i].value - y: parseFloat _chartData[$scope.graphInfo.y][i].value - z: parseFloat _chartData[$scope.graphInfo.z][i].value + x: _chartData[$scope.graphInfo.x][i].value + y: _chartData[$scope.graphInfo.y][i].value + z: _chartData[$scope.graphInfo.z][i].value obj.push tmp return obj - send = graphFormat() + if selectorCat + console.log categoricalGraphFormat() + + send = numericGraphFormat() results = data: send xLab: _headers[$scope.graphInfo.x], @@ -166,6 +203,10 @@ charts = angular.module('app_analysis_charts', []) $scope.changeName = () -> $scope.graphInfo.graph = $scope.graphSelect.name $scope.createGraph() + if $scope.graphSelect.name == "Bar Graph" + $scope.categorical = true + else + $scope.categorical = false $scope.changeVar = (selector,headers, ind) -> for h in headers @@ -311,14 +352,14 @@ charts = angular.module('app_analysis_charts', []) .factory 'histogram',[ () -> - _drawHist = (_graph,data,container,gdata,width,height) -> + _drawHist = (_graph,data,container,gdata,width,height,ranges) -> container.append('input').attr('id', 'slider').attr('type','range').attr('min', '1').attr('max','10').attr('step', '1').attr('value','5') bins = null dataHist = null arr = data.map (d) -> parseFloat d.x - x = d3.scale.linear().domain([0,d3.max arr]).range([0,width]) + x = d3.scale.linear().domain([ranges.xMin, ranges.xMax]).range([0,width]) plotHist = (bins) -> @@ -326,7 +367,7 @@ charts = angular.module('app_analysis_charts', []) container.append('text').attr('id', 'slidertext').text('Bin Slider: '+bins).attr('position','relative').attr('left', '50px') dataHist = d3.layout.histogram().bins(bins)(arr) - y = d3.scale.linear().domain([0, d3.max dataHist.map (i) -> i.length]).range([0, height]) + y = d3.scale.linear().domain([0,d3.max dataHist.map (i) -> i.length]).range([height,0]) yAxis = d3.svg.axis().scale(y).orient("left") xAxis = d3.svg.axis().scale(x).orient("bottom") @@ -365,19 +406,21 @@ charts = angular.module('app_analysis_charts', []) bar.enter() .append("g") + rect_width = width/bins bar.append('rect') -# .style('fill', 'steelblue') - .attr('x', (d,i) -> x d.x) + .attr('x', (d) -> x d.x) .attr('y', (d) -> height - y d.y) - .attr('width', (d) -> x d.dx) + .attr('width', rect_width) .attr('height', (d) -> y d.y) + .attr("stroke","white") + .attr("stroke-width",1) .on('mouseover', () -> d3.select(this).transition().style('fill', 'orange')) .on('mouseout', () -> d3.select(this).transition().style('fill', 'steelblue')) bar.append('text') - .attr('x', (d,i) -> x d.x) + .attr('x', (d) -> x d.x) .attr('y', (d) -> height - y d.y) - .attr('dx', (d) -> .5*x d.dx) + .attr('dx', (d) -> .5*rect_width) .attr('dy', '20px') .attr('fill', '#fff') .attr('text-anchor', 'middle') @@ -396,74 +439,55 @@ charts = angular.module('app_analysis_charts', []) .factory 'pie', [ () -> - pieData = null + valueSum = 0 makePieData = (data) -> - pieMax = d3.max(data, (d)->parseFloat d.x) - pieMin = d3.min(data, (d)->parseFloat d.x) - maxPiePieces = 7 # set magic constant to variable - rangeInt = Math.ceil((pieMax - pieMin)/maxPiePieces) - console.log rangeInt - piePieces = new Array(maxPiePieces - 1) # create array with numbers of pie pieces - for i in [0..maxPiePieces-1] by 1 - piePieces[i] = [] - - for el in data - index = Math.floor((el.x - pieMin)/rangeInt) - piePieces[index].push(el.x) # assign each el.x to a piePiece - console.log "piePieces[" + index + "]=" + piePieces[index] - - obj = {} - for i in [0..maxPiePieces-1] by 1 - obj[i] = piePieces[i].length - - pieData = d3.entries obj - for d in pieData - d.key = (d.key*rangeInt)+pieMin+"-"+((d.key-1)*rangeInt)+pieMin - return pieData + counts = {} + for i in [0..data.length-1] by 1 + currentVar = data[i].x + counts[currentVar] = counts[currentVar] || 0 + counts[currentVar]++ + valueSum++ + obj = d3.entries counts + return obj _drawPie = (data,width,height,_graph) -> - makePieData(data) radius = Math.min(width, height) / 2 - arc = d3.svg.arc() .outerRadius(radius) .innerRadius(0) - labelArc = d3.svg.arc() - .outerRadius(radius-10) - .innerRadius(radius-10) - - color = d3.scale.ordinal().range(["#ffffcc","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#0c2c84"]) - + #color = d3.scale.ordinal().range(["#ffffcc","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#0c2c84"]) + color = d3.scale.category20c() arcOver = d3.svg.arc() .outerRadius(radius + 10) - # .innerRadius(0+10) pie = d3.layout.pie() -#.value (d) -> d.count - .value (d) -> parseFloat d.value - type = (d) -> - d.y = +d.y - return d + .value((d)-> d.value) + .sort(null) + + formatted_data = makePieData(data) + console.log pie(formatted_data) arcs = _graph.selectAll(".arc") - .data(pie(pieData)) + .data(pie(formatted_data)) .enter() .append('g') .attr("class", "arc") arcs.append('path') .attr('d', arc) - .attr('fill', (d) -> color(d.data.key)) - .on('mouseenter', (d) -> d3.select(this).attr("stroke","white").transition().attr("d", arcOver).attr("stroke-width",5)) + .attr('fill', (d) -> color(d.data.value)) + .on('mouseenter', (d) -> d3.select(this).attr("stroke","white") .transition().attr("d", arcOver).attr("stroke-width",3)) .on('mouseleave', (d) -> d3.select(this).transition().attr('d', arc).attr("stroke", "none")) arcs.append('text') .attr('id','tooltip') .attr('transform', (d) -> 'translate('+arc.centroid(d)+')') .attr('text-anchor', 'middle') - .text (d) -> d.data.key + .text (d) -> d.data.key + ': ' + parseFloat(100*d.data.value/valueSum).toFixed(2) + '%' + drawPie: _drawPie + ] .factory 'bubble', [ @@ -621,11 +645,10 @@ charts = angular.module('app_analysis_charts', []) when 'Bubble Chart' bubble.drawBubble(ranges,width,height,_graph,data,gdata,container) when 'Histogram' - histogram.drawHist(_graph,data,container,gdata,width,height) + histogram.drawHist(_graph,data,container,gdata,width,height,ranges) when 'Pie Chart' _graph = svg.append('g').attr("transform", "translate(300,250)").attr("id", "remove") pie.drawPie(data,width,height,_graph) when 'Scatter Plot' scatterplot.drawScatterplot(data,ranges,width,height,_graph,container,gdata) ] - From 66f4bef50847154168721f831e074b42b425f08b Mon Sep 17 00:00:00 2001 From: alxndrkalinin Date: Mon, 15 Feb 2016 18:30:49 -0500 Subject: [PATCH 04/22] refactor(kmeans): move datect k button up to k dropdown #SOCRFW-216 --- .../tools/machineLearning/kMeans/sidebar.jade | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/partials/analysis/tools/machineLearning/kMeans/sidebar.jade b/app/partials/analysis/tools/machineLearning/kMeans/sidebar.jade index d85813b4..959ed2d0 100644 --- a/app/partials/analysis/tools/machineLearning/kMeans/sidebar.jade +++ b/app/partials/analysis/tools/machineLearning/kMeans/sidebar.jade @@ -23,8 +23,15 @@ div(ng-controller="kMeansSidebarCtrl") input(type="checkbox", ng-model="labelson") | Labels present div.form-group - label k   - select(ng-model="k", ng-options="k for k in ks").form-control + fieldset.form-inline + label k   + select(ng-model="k", ng-options="k for k in ks").form-control + button.btn.btn-info( + type="submit" + aria-label="Get k value" + ng-click="detectKValue()" + ng-disabled="!labelson") + | Detect k div.checkbox(ng-hide="!labelson") label input( @@ -38,12 +45,6 @@ div(ng-controller="kMeansSidebarCtrl") div.form-group label Initialization   select(ng-model="initMethod", ng-options="init for init in inits").form-control - button.btn.btn-info( - type="submit" - aria-label="Get k value" - ng-click="detectKValue()" - ng-disabled="!labelson") - | Detect k button.btn.btn-primary( type="submit" aria-label="Run k-Means" From e01dc52802d75654328591845dc6955135324c67 Mon Sep 17 00:00:00 2001 From: alxndrkalinin Date: Tue, 16 Feb 2016 10:04:36 -0500 Subject: [PATCH 05/22] fix(kmeans): allow accuracy calculation when k corresponds to num of unique labels #SOCRFW-218 --- app/scripts/analysis/tools/machineLearning/kMeans/kmeans.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/analysis/tools/machineLearning/kMeans/kmeans.coffee b/app/scripts/analysis/tools/machineLearning/kMeans/kmeans.coffee index 3cc2682c..e14eec19 100644 --- a/app/scripts/analysis/tools/machineLearning/kMeans/kmeans.coffee +++ b/app/scripts/analysis/tools/machineLearning/kMeans/kmeans.coffee @@ -191,7 +191,7 @@ kMeans = angular.module('app_analysis_kMeans', []) data = ([row[xCol], row[yCol]] for row in data.data) # re-check if possible to compute accuracy - if $scope.labelson and $scope.k is $scope.numUniqueLabels and $scope.accuracyon + if $scope.labelson and $scope.k is $scope.numUniqueLabels.num and $scope.accuracyon acc = on obj = From 99a6242c9c6037e9499efb04448744915a980295 Mon Sep 17 00:00:00 2001 From: alxndrkalinin Date: Tue, 16 Feb 2016 11:04:28 -0500 Subject: [PATCH 06/22] feat(kmeans): dynamically update data points on change of variable #SOCRFW-217 --- .../tools/machineLearning/kMeans/sidebar.jade | 99 ++++++++++--------- .../machineLearning/kMeans/kmeans.coffee | 17 +++- 2 files changed, 65 insertions(+), 51 deletions(-) diff --git a/app/partials/analysis/tools/machineLearning/kMeans/sidebar.jade b/app/partials/analysis/tools/machineLearning/kMeans/sidebar.jade index 959ed2d0..3ef32d46 100644 --- a/app/partials/analysis/tools/machineLearning/kMeans/sidebar.jade +++ b/app/partials/analysis/tools/machineLearning/kMeans/sidebar.jade @@ -1,54 +1,55 @@ div(ng-controller="kMeansSidebarCtrl") form legend Parameters - div.checkbox - label - input(type="checkbox", ng-model="wholedataseton") - | Cluster whole dataset (visualize 2D projection) - div.form-group - label X column   - //- show data header column names - select(ng-model="xCol", ng-options="col for col in cols").form-control - div.form-group - label Y column   - //- show data header column names - select(ng-model="yCol", ng-options="col for col in cols").form-control - div.form-group - fieldset(ng-disabled="!labelson") - label Labels column   + fieldset(ng-disabled="kmeanson") + div.checkbox + label + input(type="checkbox", ng-model="wholedataseton") + | Cluster whole dataset (visualize 2D projection) + div.form-group + label X column   //- show data header column names - select(ng-model="labelCol", ng-options="col for col in cols").form-control - div.checkbox - label - input(type="checkbox", ng-model="labelson") - | Labels present - div.form-group - fieldset.form-inline - label k   - select(ng-model="k", ng-options="k for k in ks").form-control - button.btn.btn-info( + select(ng-model="xCol", ng-options="col for col in cols", ng-change="updateDataPoints()").form-control + div.form-group + label Y column   + //- show data header column names + select(ng-model="yCol", ng-options="col for col in cols", ng-change="updateDataPoints()").form-control + div.form-group + fieldset(ng-disabled="!labelson") + label Labels column   + //- show data header column names + select(ng-model="labelCol", ng-options="col for col in cols").form-control + div.checkbox + label + input(type="checkbox", ng-model="labelson") + | Labels present + div.form-group + fieldset.form-inline + label k   + select(ng-model="k", ng-options="k for k in ks").form-control + button.btn.btn-info( + type="submit" + aria-label="Get k value" + ng-click="detectKValue()" + ng-disabled="!labelson") + | Detect k + div.checkbox(ng-hide="!labelson") + label + input( + type="checkbox" + ng-model="accuracyon" + ng-disabled="k !== numUniqueLabels.num || labelCol !== numUniqueLabels.labelCol") + | Compute accuracy + div.form-group + label Distance   + select(ng-model="dist", ng-options="dist for dist in distances").form-control + div.form-group + label Initialization   + select(ng-model="initMethod", ng-options="init for init in inits").form-control + button.btn.btn-primary( type="submit" - aria-label="Get k value" - ng-click="detectKValue()" - ng-disabled="!labelson") - | Detect k - div.checkbox(ng-hide="!labelson") - label - input( - type="checkbox" - ng-model="accuracyon" - ng-disabled="k !== numUniqueLabels.num || labelCol !== numUniqueLabels.labelCol") - | Compute accuracy - div.form-group - label Distance   - select(ng-model="dist", ng-options="dist for dist in distances").form-control - div.form-group - label Initialization   - select(ng-model="initMethod", ng-options="init for init in inits").form-control - button.btn.btn-primary( - type="submit" - aria-label="Run k-Means" - ng-click="run()" - ng-disabled="kmeanson") - | Run  - span.glyphicon.glyphicon-refresh(aria-hidden="true", ng-class="running") + aria-label="Run k-Means" + ng-click="run()" + ng-disabled="kmeanson") + | Run  + span.glyphicon.glyphicon-refresh(aria-hidden="true", ng-class="running") diff --git a/app/scripts/analysis/tools/machineLearning/kMeans/kmeans.coffee b/app/scripts/analysis/tools/machineLearning/kMeans/kmeans.coffee index e14eec19..c840ab5b 100644 --- a/app/scripts/analysis/tools/machineLearning/kMeans/kmeans.coffee +++ b/app/scripts/analysis/tools/machineLearning/kMeans/kmeans.coffee @@ -87,6 +87,9 @@ kMeans = angular.module('app_analysis_kMeans', []) # safe enforce $scope.$digest to activate directive watchers $timeout updateChartData + $scope.$on 'kmeans:updateDataPoints', (event, dataPoints) -> + _update dataPoints + _finish = (results=null) -> msgManager.broadcast 'kmeans:done', results showResults results @@ -117,9 +120,14 @@ kMeans = angular.module('app_analysis_kMeans', []) wholedataseton: true accuracyon: false + updateDataPoints = (data) -> + xCol = data.header.indexOf $scope.xCol + yCol = data.header.indexOf $scope.yCol + data = ([row[xCol], row[yCol]] for row in data.data) + msgManager.broadcast 'kmeans:updateDataPoints', data + # set initial values for sidebar controls initSidebarControls = (initControlValues) -> - params = kmeans.getParameters() $scope.ks = [params.minK..params.maxK] $scope.distances = params.distances @@ -149,6 +157,10 @@ kMeans = angular.module('app_analysis_kMeans', []) $scope.kmeanson = off if $scope.labelson $scope.numUniqueLabels = detectKValue data + $scope.updateDataPoints = () -> + updateDataPoints data + $timeout -> + updateDataPoints data setDetectedKValue = (detectedK) -> if detectedK.num <= 10 @@ -219,6 +231,7 @@ kMeans = angular.module('app_analysis_kMeans', []) msgScope: ['kMeans'] listener: (msg, data) -> updateSidebarControls(data) + updateDataPoints(data) $scope.detectKValue = -> detectedK = detectKValue data setDetectedKValue detectedK @@ -558,7 +571,7 @@ kMeans = angular.module('app_analysis_kMeans', []) distanceType = distanceType.toLowerCase() initMethod = initMethod.toLowerCase() - _updateGraph data +# _updateGraph data if initMethod is 'forgy' centroids = _initCentroids data, k From 76c51bb3db5f75a44726476c1e48cfc0978b04da Mon Sep 17 00:00:00 2001 From: appletreeisyellow Date: Tue, 16 Feb 2016 14:01:18 -0800 Subject: [PATCH 07/22] fix(charts): fixed Pie Chart, now support data as number --- app/scripts/analysis/charts/charts.coffee | 29 ++++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/app/scripts/analysis/charts/charts.coffee b/app/scripts/analysis/charts/charts.coffee index a9c7dca5..5833ca99 100644 --- a/app/scripts/analysis/charts/charts.coffee +++ b/app/scripts/analysis/charts/charts.coffee @@ -400,12 +400,28 @@ charts = angular.module('app_analysis_charts', []) () -> valueSum = 0 makePieData = (data) -> + valueSum = 0 counts = {} - for i in [0..data.length-1] by 1 - currentVar = data[i].x - counts[currentVar] = counts[currentVar] || 0 - counts[currentVar]++ - valueSum++ + if(!isNaN(data[0].x)) # data is number + pieMax = d3.max(data, (d)-> parseFloat d.x) + pieMin = d3.min(data, (d)-> parseFloat d.x) + maxPiePieces = 7 # set magic constant to variable + rangeInt = Math.ceil((pieMax - pieMin) / maxPiePieces) + counts = {} + for val in data + index = Math.floor((val.x - pieMin) / rangeInt) + groupName = index + "-" + (index + rangeInt) + console.log groupName + counts[groupName] = counts[groupName] || 0 + counts[groupName]++ + valueSum++ + else # data is string + for i in [0..data.length-1] by 1 + currentVar = data[i].x + counts[currentVar] = counts[currentVar] || 0 + counts[currentVar]++ + valueSum++ + obj = d3.entries counts return obj @@ -425,7 +441,8 @@ charts = angular.module('app_analysis_charts', []) .sort(null) formatted_data = makePieData(data) - console.log pie(formatted_data) + console.log formatted_data + #console.log pie(formatted_data) arcs = _graph.selectAll(".arc") .data(pie(formatted_data)) From c4944869466254e8d3a402cab15569aa08436861 Mon Sep 17 00:00:00 2001 From: appletreeisyellow Date: Tue, 16 Feb 2016 15:16:06 -0800 Subject: [PATCH 08/22] fix(charts): fix Bubble Chart: Radius support to show color for string --- app/scripts/analysis/charts/charts.coffee | 435 ++++++++++++---------- 1 file changed, 235 insertions(+), 200 deletions(-) diff --git a/app/scripts/analysis/charts/charts.coffee b/app/scripts/analysis/charts/charts.coffee index a9c7dca5..1664ca7f 100644 --- a/app/scripts/analysis/charts/charts.coffee +++ b/app/scripts/analysis/charts/charts.coffee @@ -3,213 +3,213 @@ charts = angular.module('app_analysis_charts', []) .factory('app_analysis_charts_constructor', [ - 'app_analysis_charts_manager' - (manager)-> - (sb)-> + 'app_analysis_charts_manager' + (manager)-> + (sb)-> - manager.setSb sb unless !sb? - _msgList = manager.getMsgList() + manager.setSb sb unless !sb? + _msgList = manager.getMsgList() - init: (opt) -> - console.log '%cCHARTS: charts init called' + init: (opt) -> + console.log '%cCHARTS: charts init called' - destroy: () -> + destroy: () -> - msgList: _msgList -]) + msgList: _msgList + ]) .factory( 'app_analysis_charts_manager', [ - ()-> - _sb = null + ()-> + _sb = null - _msgList = - outgoing: ['get table'] - incoming: ['take table'] - scope: ['charts'] + _msgList = + outgoing: ['get table'] + incoming: ['take table'] + scope: ['charts'] - _setSb = (sb) -> - _sb = sb + _setSb = (sb) -> + _sb = sb - _getSb = () -> - _sb + _getSb = () -> + _sb - _getMsgList = () -> - _msgList + _getMsgList = () -> + _msgList - getSb: _getSb - setSb: _setSb - getMsgList: _getMsgList -]) + getSb: _getSb + setSb: _setSb + getMsgList: _getMsgList + ]) .controller('mainChartsCtrl', [ - 'app_analysis_charts_manager' - '$scope' - (ctrlMngr,$scope) -> - _chart_data = null + 'app_analysis_charts_manager' + '$scope' + (ctrlMngr,$scope) -> + _chart_data = null - _updateData = () -> - $scope.chartData = _chart_data + _updateData = () -> + $scope.chartData = _chart_data - $scope.$on 'charts:graphDiv', (event, data) -> - _chart_data = data - _updateData() -]) + $scope.$on 'charts:graphDiv', (event, data) -> + _chart_data = data + _updateData() + ]) .controller('sideChartsCtrl',[ - 'app_analysis_charts_manager' - '$scope' - '$rootScope' - '$stateParams' - '$q' - 'app_analysis_charts_dataTransform' - (ctrlMngr, $scope, $rootScope, $stateParams, $q, dataTransform) -> - _chartData = null - _headers = null - - $scope.selector1 = {} - $scope.selector2 = {} - $scope.selector3 = {} - - - $scope.graphInfo = - graph: "" - x: "" - y: "" - z: "" - - $scope.graphs = [ - name: 'Bar Graph' - value: 0 - x: true - y: false - z: false - message: "Choose a numerical variable for x and a categorical variable for y." - , - name: 'Scatter Plot' - value: 1 - x: true - y: true - z: false - message: "Choose an x variable and a y variable." - , - name: 'Histogram' - value: 2 - x: true - y: false - z: false - message: "Choose an x variable. Use the slider below the histogram to adjust the number of bins." - , - name: 'Bubble Chart' - value: 3 - x: true - y: true - z: true - message: "Choose an x variable, a y variable and a radius variable." - , - name: 'Pie Chart' - value: 4 - x: true - y: false - z: false - message: "Choose one variable to put into a pie chart." - - ] - $scope.graphSelect = {} - - - - $scope.createGraph = () -> - graphFormat = () -> - obj = [] - len = _chartData[0].length - - if $scope.graphInfo.y is "" and $scope.graphInfo.z is "" + 'app_analysis_charts_manager' + '$scope' + '$rootScope' + '$stateParams' + '$q' + 'app_analysis_charts_dataTransform' + (ctrlMngr, $scope, $rootScope, $stateParams, $q, dataTransform) -> + _chartData = null + _headers = null + + $scope.selector1 = {} + $scope.selector2 = {} + $scope.selector3 = {} + + + $scope.graphInfo = + graph: "" + x: "" + y: "" + z: "" + + $scope.graphs = [ + name: 'Bar Graph' + value: 0 + x: true + y: false + z: false + message: "Choose a numerical variable for x and a categorical variable for y." + , + name: 'Scatter Plot' + value: 1 + x: true + y: true + z: false + message: "Choose an x variable and a y variable." + , + name: 'Histogram' + value: 2 + x: true + y: false + z: false + message: "Choose an x variable. Use the slider below the histogram to adjust the number of bins." + , + name: 'Bubble Chart' + value: 3 + x: true + y: true + z: true + message: "Choose an x variable, a y variable and a radius variable." + , + name: 'Pie Chart' + value: 4 + x: true + y: false + z: false + message: "Choose one variable to put into a pie chart." + + ] + $scope.graphSelect = {} + + + + $scope.createGraph = () -> + graphFormat = () -> obj = [] - - for i in [1...len] by 1 - tmp = - x: _chartData[$scope.graphInfo.x][i].value - obj.push tmp - - else if $scope.graphInfo.y isnt "" and $scope.graphInfo.z is "" - obj = [] - - for i in [1...len] by 1 - tmp = - x: _chartData[$scope.graphInfo.x][i].value - y: _chartData[$scope.graphInfo.y][i].value - obj.push tmp - - else - obj = [] - - for i in [1...len] by 1 - tmp = - x: _chartData[$scope.graphInfo.x][i].value - y: _chartData[$scope.graphInfo.y][i].value - z: _chartData[$scope.graphInfo.z][i].value - obj.push tmp - - return obj - send = graphFormat() - results = - data: send - xLab: _headers[$scope.graphInfo.x], - yLab: _headers[$scope.graphInfo.y], - zLab: _headers[$scope.graphInfo.z], - name: $scope.graphInfo.graph - - $rootScope.$broadcast 'charts:graphDiv', results - - $scope.changeName = () -> - $scope.graphInfo.graph = $scope.graphSelect.name - $scope.createGraph() - - $scope.changeVar = (selector,headers, ind) -> - for h in headers - if selector.value is h.value then $scope.graphInfo[ind] = parseFloat h.key - $scope.createGraph() - - sb = ctrlMngr.getSb() - - token = sb.subscribe - msg:'take table' - msgScope:['charts'] - listener: (msg, _data) -> - _headers = d3.entries _data.header - $scope.headers = _headers - _chartData = dataTransform.format(_data.data) - - sb.publish - msg:'get table' - msgScope:['charts'] - callback: -> sb.unsubscribe token - data: - tableName: $stateParams.projectId + ':' + $stateParams.forkId -]) + len = _chartData[0].length + + if $scope.graphInfo.y is "" and $scope.graphInfo.z is "" + obj = [] + + for i in [1...len] by 1 + tmp = + x: _chartData[$scope.graphInfo.x][i].value + obj.push tmp + + else if $scope.graphInfo.y isnt "" and $scope.graphInfo.z is "" + obj = [] + + for i in [1...len] by 1 + tmp = + x: _chartData[$scope.graphInfo.x][i].value + y: _chartData[$scope.graphInfo.y][i].value + obj.push tmp + + else + obj = [] + + for i in [1...len] by 1 + tmp = + x: _chartData[$scope.graphInfo.x][i].value + y: _chartData[$scope.graphInfo.y][i].value + z: _chartData[$scope.graphInfo.z][i].value + obj.push tmp + + return obj + send = graphFormat() + results = + data: send + xLab: _headers[$scope.graphInfo.x], + yLab: _headers[$scope.graphInfo.y], + zLab: _headers[$scope.graphInfo.z], + name: $scope.graphInfo.graph + + $rootScope.$broadcast 'charts:graphDiv', results + + $scope.changeName = () -> + $scope.graphInfo.graph = $scope.graphSelect.name + $scope.createGraph() + + $scope.changeVar = (selector,headers, ind) -> + for h in headers + if selector.value is h.value then $scope.graphInfo[ind] = parseFloat h.key + $scope.createGraph() + + sb = ctrlMngr.getSb() + + token = sb.subscribe + msg:'take table' + msgScope:['charts'] + listener: (msg, _data) -> + _headers = d3.entries _data.header + $scope.headers = _headers + _chartData = dataTransform.format(_data.data) + + sb.publish + msg:'get table' + msgScope:['charts'] + callback: -> sb.unsubscribe token + data: + tableName: $stateParams.projectId + ':' + $stateParams.forkId + ]) .factory('app_analysis_charts_dataTransform',[ - () -> + () -> - _transpose = (data) -> - data[0].map (col, i) -> data.map (row) -> row[i] + _transpose = (data) -> + data[0].map (col, i) -> data.map (row) -> row[i] - _transform = (data) -> - for col in data - obj = {} - for value, i in col - obj[i] = value - d3.entries obj + _transform = (data) -> + for col in data + obj = {} + for value, i in col + obj[i] = value + d3.entries obj - _format = (data) -> - return _transform(_transpose(data)) + _format = (data) -> + return _transform(_transpose(data)) - transform: _transform - transpose:_transpose - format: _format -]) + transform: _transform + transpose:_transpose + format: _format + ]) #.factory 'stackedBar', [ # () -> @@ -400,12 +400,28 @@ charts = angular.module('app_analysis_charts', []) () -> valueSum = 0 makePieData = (data) -> + valueSum = 0 counts = {} - for i in [0..data.length-1] by 1 - currentVar = data[i].x - counts[currentVar] = counts[currentVar] || 0 - counts[currentVar]++ - valueSum++ + if(!isNaN(data[0].x)) # data is number + pieMax = d3.max(data, (d)-> parseFloat d.x) + pieMin = d3.min(data, (d)-> parseFloat d.x) + maxPiePieces = 7 # set magic constant to variable + rangeInt = Math.ceil((pieMax - pieMin) / maxPiePieces) + counts = {} + for val in data + index = Math.floor((val.x - pieMin) / rangeInt) + groupName = index + "-" + (index + rangeInt) + #console.log groupName + counts[groupName] = counts[groupName] || 0 + counts[groupName]++ + valueSum++ + else # data is string + for i in [0..data.length-1] by 1 + currentVar = data[i].x + counts[currentVar] = counts[currentVar] || 0 + counts[currentVar]++ + valueSum++ + obj = d3.entries counts return obj @@ -425,7 +441,8 @@ charts = angular.module('app_analysis_charts', []) .sort(null) formatted_data = makePieData(data) - console.log pie(formatted_data) + #console.log formatted_data + #console.log pie(formatted_data) arcs = _graph.selectAll(".arc") .data(pie(formatted_data)) @@ -457,16 +474,26 @@ charts = angular.module('app_analysis_charts', []) xAxis = d3.svg.axis().scale(x).orient('bottom') yAxis = d3.svg.axis().scale(y).orient('left') - r = d3.scale.linear() - .domain([d3.min(data, (d)-> parseFloat d.z), d3.max(data, (d)-> parseFloat d.z)]) - .range([3,15]) - - rValue = (d)->parseFloat d.z + zIsNumber = !isNaN(data[0].z) + + r = 0 + rValue = 0 + if(zIsNumber) + r = d3.scale.linear() + .domain([d3.min(data, (d)-> parseFloat d.z), d3.max(data, (d)-> parseFloat d.z)]) + .range([3,15]) + rValue = (d) -> parseFloat d.z + else + r = d3.scale.linear() + .domain([5, 5]) + .range([3,15]) + rValue = (d) -> d.z tooltip = container .append('div') .attr('class', 'tooltip') - # .style('opacity', 0) + + color = d3.scale.category10() # x axis _graph.append("g") @@ -476,7 +503,6 @@ charts = angular.module('app_analysis_charts', []) .append('text') .attr('class', 'label') .attr('transform', 'translate(' + (width / 2) + ',' + 40 + ')') -# .style('text-anchor', 'end') .text gdata.xLab.value # y axis @@ -489,21 +515,31 @@ charts = angular.module('app_analysis_charts', []) .attr('y', -50 ) .attr('x', -(height / 2)) .attr("dy", ".71em") -# .style("text-anchor", "end") .text gdata.yLab.value - # create circle _graph.selectAll('.circle') .data(data) .enter().append('circle') - .attr('fill', 'yellow') + .attr('fill', + if(zIsNumber) + 'yellow' + else + (d) -> color(d.z)) .attr('opacity', '0.7') - .attr('stroke', 'orange') + .attr('stroke', + if(zIsNumber) + 'orange' + else + (d) -> color(d.z)) .attr('stroke-width', '2px') .attr('cx', (d) -> x d.x) .attr('cy', (d) -> y d.y) - .attr('r', (d) -> r d.z) + .attr('r', (d) -> + if(zIsNumber) # if d.z is number, use d.z as radius + r d.z + else # else, set radius to be 8 + 8) .on('mouseover', (d) -> tooltip.transition().duration(200).style('opacity', .9) tooltip.html('
'+gdata.zLab.value+': '+ rValue(d)+'
') @@ -611,4 +647,3 @@ charts = angular.module('app_analysis_charts', []) when 'Scatter Plot' scatterplot.drawScatterplot(data,ranges,width,height,_graph,container,gdata) ] - From bebffed06f449f5b5fb90a9ffd55e8147c1c2619 Mon Sep 17 00:00:00 2001 From: alxndrkalinin Date: Tue, 16 Feb 2016 18:47:41 -0500 Subject: [PATCH 09/22] chore: add repo to package.json --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index b184ef99..aca62a20 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,10 @@ "version": "v0.1.5-alpha.3", "description": "Flexible HTML5/JS toolkit for interactive data analysis and visuzalization", "homepage": "https://github.com/SOCR/SOCRAT", + "repository": { + "type": "git", + "url": "https://github.com/SOCR/SOCRAT.git" + }, "devDependencies": { "coffee-script": "*", "grunt": "^0.4.5", From db37a79031ba5fcd6face57168daf4ab5ff81b2f Mon Sep 17 00:00:00 2001 From: appletreeisyellow Date: Tue, 16 Feb 2016 15:53:04 -0800 Subject: [PATCH 10/22] Revert to c494486 --- app/partials/analysis/getData/main.jade | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/app/partials/analysis/getData/main.jade b/app/partials/analysis/getData/main.jade index b9920fe1..52f6b767 100644 --- a/app/partials/analysis/getData/main.jade +++ b/app/partials/analysis/getData/main.jade @@ -1,25 +1,19 @@ div(ng-controller='getDataMainCtrl') h1 Get Data - //br p.lead To perform any analysis, you need data to begin with. Choose one of the available methods |to get the data into the web-app. form.socrData(collapse="showState.socrData") legend SOCR Datasets div.form-group - select.form-control( - ng-model="socrdataset", - ng-options="item as item.name for item in socrDatasets track by item.id") - button.btn.btn-primary(ng-click="getSocrData()") Load + div.worldBank(collapse="showState.worldBank") h3 WorldBank Data span Size: - input(type="text",class="input-mini", ng-model="size") - select(style="width:100%;margin:0px", ng-model="option") option(value='4.2_BASIC.EDU.SPENDING') Education Spending option(value='2.4_OOSC.RATE') Out of School Children rate - button.btn.btn-primary(ng-click="getWB()") Load + button.btn.btn-medium(ng-click="getWB()") Go div.generate(collapse="showState.generate") ul.nav.nav-pills.nav-stacked From f0cd35e27d0d685a2832ca68246f9d497ed78b7e Mon Sep 17 00:00:00 2001 From: appletreeisyellow Date: Tue, 16 Feb 2016 16:07:14 -0800 Subject: [PATCH 11/22] fix(charts): fix conflict in Pie Chart --- app/scripts/analysis/charts/charts.coffee | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/scripts/analysis/charts/charts.coffee b/app/scripts/analysis/charts/charts.coffee index a0d910fe..1664ca7f 100644 --- a/app/scripts/analysis/charts/charts.coffee +++ b/app/scripts/analysis/charts/charts.coffee @@ -411,11 +411,7 @@ charts = angular.module('app_analysis_charts', []) for val in data index = Math.floor((val.x - pieMin) / rangeInt) groupName = index + "-" + (index + rangeInt) -<<<<<<< HEAD #console.log groupName -======= - console.log groupName ->>>>>>> 76c51bb3db5f75a44726476c1e48cfc0978b04da counts[groupName] = counts[groupName] || 0 counts[groupName]++ valueSum++ @@ -445,11 +441,7 @@ charts = angular.module('app_analysis_charts', []) .sort(null) formatted_data = makePieData(data) -<<<<<<< HEAD #console.log formatted_data -======= - console.log formatted_data ->>>>>>> 76c51bb3db5f75a44726476c1e48cfc0978b04da #console.log pie(formatted_data) arcs = _graph.selectAll(".arc") From d6f1468f42490fdb25aa690a0007cbfe00e93148 Mon Sep 17 00:00:00 2001 From: alxndrkalinin Date: Tue, 16 Feb 2016 21:41:59 -0500 Subject: [PATCH 12/22] fix(getData, analysis menu): prevent default on a elements #SOCRFW-219 --- app/partials/analysis-nav.jade | 2 +- app/partials/analysis/getData/sidebar.jade | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/partials/analysis-nav.jade b/app/partials/analysis-nav.jade index 4fd690bb..1d4b89bf 100644 --- a/app/partials/analysis-nav.jade +++ b/app/partials/analysis-nav.jade @@ -5,7 +5,7 @@ ul.nav.navbar-nav li(ng-class="getClass('/wrangleData')") a(ng-href='#/wrangleData') Wrangle Data li.dropdown - a(href="#", data-toggle="dropdown", role="button", aria-haspopup="true", aria-expanded="false").dropdown-toggle + a(href="", data-toggle="dropdown", role="button", aria-haspopup="true", aria-expanded="false").dropdown-toggle | Tools   span.caret ul.dropdown-menu diff --git a/app/partials/analysis/getData/sidebar.jade b/app/partials/analysis/getData/sidebar.jade index 5cdc84d5..dba1c36d 100644 --- a/app/partials/analysis/getData/sidebar.jade +++ b/app/partials/analysis/getData/sidebar.jade @@ -2,28 +2,28 @@ div(ng-controller="getDataSidebarCtrl") p. Data input div.list-group a#getDataGrid.list-group-item( - href="#" + href="" ng-click="show('grid')" ng-class="{active:selected == 'getDataGrid'}") | Copy-paste to spreadsheet a#getDataSocrData.list-group-item( - href="#" + href="" ng-click="show('socrData')" ng-class="{active:selected == 'getDataSocrData'}") | Load SOCR dataset a#getDataWorldBank.list-group-item( - href="#" + href="" ng-click="show('worldBank')" ng-class="{active:selected == 'getDataWorldBank'}") | Load data from WorldBank a#getDataGenerate.list-group-item.disabled( - href="#" + href="" ng-click="show('generate')" ng-class="{active:selected == 'getDataGenerate'}") | Use data generator - a.list-group-item.disabled(href="#", ng-click="getJson()", ng-class="{active:selected == 'getDataJson'}") + a.list-group-item.disabled(href="", ng-click="getJson()", ng-class="{active:selected == 'getDataJson'}") | Parse JSON fileParse SOCR Data page - a.list-group-item.disabled(href="#", ng-click="save()", ng-class="{active:selected == 'getDataSocrPage'}") + a.list-group-item.disabled(href="", ng-click="save()", ng-class="{active:selected == 'getDataSocrPage'}") | Parse SOCR Data page // From a79e2b5ab9063516f34f73b6dd28a9450a1d85a5 Mon Sep 17 00:00:00 2001 From: alxndrkalinin Date: Tue, 16 Feb 2016 22:14:24 -0500 Subject: [PATCH 13/22] chore: update bower dependencies --- bower.json | 34 +++++++++++++++++----------------- package.json | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/bower.json b/bower.json index d4b68ce5..7c76bf99 100644 --- a/bower.json +++ b/bower.json @@ -1,34 +1,34 @@ { "author": "Alexandr Kalinin, Selvam Palanimalai", "name": "SOCRAT", - "version": "v0.1.5-alpha.3", + "version": "v0.1.5-alpha.4", "description": "Flexible HTML5/JS toolkit for interactive data analysis and visuzalization", "homepage": "https://github.com/SOCR/SOCRAT", "dependencies": { - "angular": "^1.3.0", + "angular": "^1.5.0", "jquery-layout": "~1.4.3", "jquery-highlight": "~3.3.0", "jquery-hoverintent": "https://github.com/briancherne/jquery-hoverIntent.git#~1.8.1", - "datatables": "DataTables#~1.10.9", - "d3": "~3.5.6", - "angular-animate": "^1.3.0", - "angular-cookies": "^1.3.0", - "angular-messages": "^1.3.0", - "angular-resource": "^1.3.0", - "angular-route": "^1.3.0", - "angular-sanitize": "^1.3.0", - "angular-touch": "^1.3.0", - "angular-ui": "~0.4.0", + "datatables": "DataTables#~1.10.11", + "d3": "~3.5.15", + "angular-animate": "^1.5.0", + "angular-cookies": "^1.5.0", + "angular-messages": "^1.5.0", + "angular-resource": "^1.5.0", + "angular-route": "^1.5.0", + "angular-sanitize": "^1.5.0", + "angular-touch": "^1.5.0", + "angular-ui": "^0.4.0", "angular-ui-router": "~0.2.15", - "ngHandsontable": "angular-ui-handsontable#~0.7.0", + "ngHandsontable": "angular-ui-handsontable#~0.8.0", "wrangler": "https://github.com/alxndrkalinin/wrangler.git", - "bootstrap": "^3.2.0", - "angular-bootstrap": "~0.14.2", - "jstat": "~1.4.6", + "bootstrap": "^3.3.6", + "angular-bootstrap": "~1.1.2", + "jstat": "~1.5.2", "jsfeat": "~0.0.8" }, "devDependencies": { - "angular-mocks": "^1.3.0" + "angular-mocks": "^1.5.0" }, "appPath": "app", "moduleName": "expApp", diff --git a/package.json b/package.json index aca62a20..9c011b76 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "author": "Alexandr Kalinin, Selvam Palanimalai", "name": "SOCRAT", - "version": "v0.1.5-alpha.3", + "version": "v0.1.5-alpha.4", "description": "Flexible HTML5/JS toolkit for interactive data analysis and visuzalization", "homepage": "https://github.com/SOCR/SOCRAT", "repository": { From 0ab2741b4ec74c422d9eeecb6566713fb5d8ebd0 Mon Sep 17 00:00:00 2001 From: alxndrkalinin Date: Tue, 16 Feb 2016 22:17:13 -0500 Subject: [PATCH 14/22] fix(getData): fix collapsing of main area options #SOCRFW-219 --- app/partials/analysis/getData/main.jade | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/partials/analysis/getData/main.jade b/app/partials/analysis/getData/main.jade index b9920fe1..0fbe1095 100644 --- a/app/partials/analysis/getData/main.jade +++ b/app/partials/analysis/getData/main.jade @@ -4,7 +4,7 @@ div(ng-controller='getDataMainCtrl') p.lead To perform any analysis, you need data to begin with. Choose one of the available methods |to get the data into the web-app. - form.socrData(collapse="showState.socrData") + form.socrData(uib-collapse="showState.socrData") legend SOCR Datasets div.form-group select.form-control( @@ -12,7 +12,7 @@ div(ng-controller='getDataMainCtrl') ng-options="item as item.name for item in socrDatasets track by item.id") button.btn.btn-primary(ng-click="getSocrData()") Load - div.worldBank(collapse="showState.worldBank") + div.worldBank(uib-collapse="showState.worldBank") h3 WorldBank Data span Size: input(type="text",class="input-mini", ng-model="size") @@ -21,7 +21,7 @@ div(ng-controller='getDataMainCtrl') option(value='2.4_OOSC.RATE') Out of School Children rate button.btn.btn-primary(ng-click="getWB()") Load - div.generate(collapse="showState.generate") + div.generate(uib-collapse="showState.generate") ul.nav.nav-pills.nav-stacked li a Binomial Coin Toss From 8d1dcd39f42bb27b81177372fd230489e07a8794 Mon Sep 17 00:00:00 2001 From: appletreeisyellow Date: Thu, 18 Feb 2016 13:42:25 -0800 Subject: [PATCH 15/22] fix(getData): fix load SOCR dataset --- app/partials/analysis/getData/main.jade | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/partials/analysis/getData/main.jade b/app/partials/analysis/getData/main.jade index c88781e8..54fb97dd 100644 --- a/app/partials/analysis/getData/main.jade +++ b/app/partials/analysis/getData/main.jade @@ -1,19 +1,25 @@ div(ng-controller='getDataMainCtrl') h1 Get Data + //br p.lead To perform any analysis, you need data to begin with. Choose one of the available methods |to get the data into the web-app. form.socrData(uib-collapse="showState.socrData") legend SOCR Datasets div.form-group - + select.form-control( + ng-model="socrdataset", + ng-options="item as item.name for item in socrDatasets track by item.id") + button.btn.btn-primary(ng-click="getSocrData()") Load div.worldBank(uib-collapse="showState.worldBank") h3 WorldBank Data span Size: + input(type="text",class="input-mini", ng-model="size") + select(style="width:100%;margin:0px", ng-model="option") option(value='4.2_BASIC.EDU.SPENDING') Education Spending option(value='2.4_OOSC.RATE') Out of School Children rate - button.btn.btn-medium(ng-click="getWB()") Go + button.btn.btn-primary(ng-click="getWB()") Load div.generate(uib-collapse="showState.generate") ul.nav.nav-pills.nav-stacked @@ -29,9 +35,4 @@ div(ng-controller='getDataMainCtrl') a The Beta Distribution Experiment br - handsontable(purpose="json") - - - - - + handsontable(purpose="json") \ No newline at end of file From 45e2342fdc1d9ead00d0757a951e38a062e46345 Mon Sep 17 00:00:00 2001 From: appletreeisyellow Date: Thu, 18 Feb 2016 21:10:36 -0800 Subject: [PATCH 16/22] feat(chart): scatter plot uses one color to represent data --- app/scripts/analysis/charts/charts.coffee | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/app/scripts/analysis/charts/charts.coffee b/app/scripts/analysis/charts/charts.coffee index 5fc86af1..9682f3f0 100644 --- a/app/scripts/analysis/charts/charts.coffee +++ b/app/scripts/analysis/charts/charts.coffee @@ -254,8 +254,8 @@ charts = angular.module('app_analysis_charts', []) yMap = (d)-> y yValue(d) # set up fill color - cValue = (d)-> d.y - color = d3.scale.category10() + #cValue = (d)-> d.y + #color = d3.scale.category10() # x axis _graph.append("g") @@ -265,7 +265,6 @@ charts = angular.module('app_analysis_charts', []) .append('text') .attr('class', 'label') .attr('transform', 'translate(' + (width / 2) + ',' + 40 + ')') -# .style('text-anchor', 'end') .text gdata.xLab.value # y axis @@ -278,14 +277,12 @@ charts = angular.module('app_analysis_charts', []) .attr('y', -50 ) .attr('x', -(height / 2)) .attr("dy", ".71em") -# .style("text-anchor", "end") .text gdata.yLab.value # add the tooltip area to the webpage tooltip = container .append('div') .attr('class', 'tooltip') - # .style('opacity', 0) # draw dots _graph.selectAll('.dot') @@ -295,7 +292,8 @@ charts = angular.module('app_analysis_charts', []) .attr('r', 5) .attr('cx', xMap) .attr('cy', yMap) - .style('fill', (d)->color cValue(d)) + .style('fill', 'DodgerBlue') + .attr('opacity', '0.5') .on('mouseover', (d)-> tooltip.transition().duration(200).style('opacity', .9) tooltip.html('
(' + xValue(d)+ ',' + yValue(d) + ')
') @@ -303,10 +301,7 @@ charts = angular.module('app_analysis_charts', []) .on('mouseout', (d)-> tooltip. transition().duration(500).style('opacity', 0)) - - drawScatterplot: _drawScatterplot - ] .factory 'histogram',[ @@ -320,7 +315,6 @@ charts = angular.module('app_analysis_charts', []) arr = data.map (d) -> parseFloat d.x x = d3.scale.linear().domain([ranges.xMin, ranges.xMax]).range([0,width]) - plotHist = (bins) -> $('#slidertext').remove() container.append('text').attr('id', 'slidertext').text('Bin Slider: '+bins).attr('position','relative').attr('left', '50px') @@ -343,7 +337,6 @@ charts = angular.module('app_analysis_charts', []) .append('text') .attr('class', 'label') .attr('transform', 'translate(' + (width / 2) + ',' + 40 + ')') -# .style('text-anchor', 'end') .text gdata.xLab.value # y axis @@ -356,7 +349,6 @@ charts = angular.module('app_analysis_charts', []) .attr('y', -50 ) .attr('x', -(height / 2)) .attr("dy", ".71em") -# .style("text-anchor", "end") .text "Count" bar = _graph.selectAll('.bar') @@ -463,7 +455,6 @@ charts = angular.module('app_analysis_charts', []) .text (d) -> d.data.key + ': ' + parseFloat(100*d.data.value/valueSum).toFixed(2) + '%' drawPie: _drawPie - ] .factory 'bubble', [ @@ -559,7 +550,6 @@ charts = angular.module('app_analysis_charts', []) x.domain([d3.min(data, (d)->parseFloat d.x), d3.max(data, (d)->parseFloat d.x)]) y.domain([d3.min(data, (d)->parseFloat d.y), d3.max(data, (d)->parseFloat d.y)]) - _graph.append('g') .attr('class', 'x axis') .attr('transform', 'translate(0,' + height + ')') From 814c466c65578bc933eb62437ca53be40946d29b Mon Sep 17 00:00:00 2001 From: alxndrkalinin Date: Mon, 22 Feb 2016 15:34:28 -0500 Subject: [PATCH 17/22] fix(app): remove double registration of charts module --- app/app.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/app.coffee b/app/app.coffee index 3fca2c7e..cefba07b 100644 --- a/app/app.coffee +++ b/app/app.coffee @@ -240,10 +240,9 @@ App.run([ core.register 'charts', charts core.start 'charts' + #core.register 'importer', importer #core.start 'importer' - core.register 'charts', charts - core.start 'charts' # add module to the list of Tools to appear in Tools tab dropdown tools = [ From 85e8fce7d132d5129bfa34c2eea26b926a0bb2d9 Mon Sep 17 00:00:00 2001 From: alxndrkalinin Date: Mon, 22 Feb 2016 17:34:18 -0500 Subject: [PATCH 18/22] feat(getData): add parsing flat JSON files by URL #SOCRFW-220 --- app/partials/analysis/getData/main.jade | 11 +++++- app/partials/analysis/getData/sidebar.jade | 16 +++++--- app/scripts/analysis/getData/getData.coffee | 43 ++++++++++++++++----- app/styles/custom.less | 21 +++++++++- 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/app/partials/analysis/getData/main.jade b/app/partials/analysis/getData/main.jade index 0fbe1095..0a712e07 100644 --- a/app/partials/analysis/getData/main.jade +++ b/app/partials/analysis/getData/main.jade @@ -22,7 +22,7 @@ div(ng-controller='getDataMainCtrl') button.btn.btn-primary(ng-click="getWB()") Load div.generate(uib-collapse="showState.generate") - ul.nav.nav-pills.nav-stacked + ul.nav.nav-pills.nav-stacked.disabled li a Binomial Coin Toss li @@ -34,6 +34,15 @@ div(ng-controller='getDataMainCtrl') li a The Beta Distribution Experiment + form.jsonUrl(uib-collapse="showState.jsonParse") + legend Enter URL to parse JSON file + div.form-group + label(for="getDataJsonUrlInput").sr-only Enter URL + div.btn-group.btn-group-justified(role="group") + input#getDataJsonUrlInput(type='text', placeholder='URL to JSON ...', ng-model="jsonUrl").form-control + span#getDataJsonUrlClear(ng-click="jsonUrl=''").glyphicon.glyphicon-remove-circle + button.btn.btn-primary(ng-click="getJsonByUrl()") Parse + br handsontable(purpose="json") diff --git a/app/partials/analysis/getData/sidebar.jade b/app/partials/analysis/getData/sidebar.jade index dba1c36d..de05de60 100644 --- a/app/partials/analysis/getData/sidebar.jade +++ b/app/partials/analysis/getData/sidebar.jade @@ -16,15 +16,21 @@ div(ng-controller="getDataSidebarCtrl") ng-click="show('worldBank')" ng-class="{active:selected == 'getDataWorldBank'}") | Load data from WorldBank - a#getDataGenerate.list-group-item.disabled( + a#getDataGenerate.list-group-item( href="" ng-click="show('generate')" ng-class="{active:selected == 'getDataGenerate'}") | Use data generator - a.list-group-item.disabled(href="", ng-click="getJson()", ng-class="{active:selected == 'getDataJson'}") - | Parse JSON fileParse SOCR Data page - a.list-group-item.disabled(href="", ng-click="save()", ng-class="{active:selected == 'getDataSocrPage'}") - | Parse SOCR Data page + a#getDataJson.list-group-item( + href="" + ng-click="show('jsonParse')" + ng-class="{active:selected == 'getDataJson'}") + | Parse JSON file by URL + a#getDataSocrPage.list-group-item.disabled( + href="" + ng-click="save()" + ng-class="{active:selected == 'getDataSocrPage'}") + | Parse SOCR Data page by URL // accordion(close-others="true") diff --git a/app/scripts/analysis/getData/getData.coffee b/app/scripts/analysis/getData/getData.coffee index 41173ae7..5de01be0 100644 --- a/app/scripts/analysis/getData/getData.coffee +++ b/app/scripts/analysis/getData/getData.coffee @@ -106,10 +106,11 @@ getData = angular.module('app_analysis_getData', [ console.log 'handsontable data updated to db' _setData = (data) -> - console.log '%c inputCache set called for the project'+$stateParams.projectId+':'+$stateParams.forkId, 'color:steelblue' + console.log '%c inputCache set called for the project' + $stateParams.projectId + ':' + $stateParams.forkId, + 'color:steelblue' # TODO: fix checking existance of parameters to default table name #SOCR-140 - if data? or $stateParams.projectId? or $stateParams.forkId? + if data? or $stateParams.projectId? or $stateParams.forkId? _data = data unless data is 'edit' # clear any previous db update broadcast messages @@ -239,7 +240,7 @@ getData = angular.module('app_analysis_getData', [ # get the sandbox made for this module # sb = getDataSb.getSb() # console.log 'sandbox created' - $scope.jsonUrl = 'url..' + $scope.jsonUrl = '' flag = true $scope.selected = null @@ -265,12 +266,17 @@ getData = angular.module('app_analysis_getData', [ $scope.selected = 'getDataWorldBank' $scope.$emit 'change in showStates', 'worldBank' - when 'generate' + when 'generate' $scope.selected = 'getDataGenerate' $scope.$emit 'change in showStates', 'generate' + when 'jsonParse' + $scope.selected = 'getDataJson' + $scope.$emit 'change in showStates', 'jsonParse' + # getJson $scope.getJson = -> + console.log 123 console.log $scope.jsonUrl if $scope.jsonUrl is '' @@ -359,6 +365,7 @@ getData = angular.module('app_analysis_getData', [ d3.text url, (dataResults) -> if dataResults?.length > 0 + # parse to unnamed array dataResults = d3.csv.parseRows dataResults _data = columnHeader: dataResults.shift() @@ -376,12 +383,32 @@ getData = angular.module('app_analysis_getData', [ else console.log 'rejected:' + msg + $scope.getJsonByUrl = -> + d3.json $scope.jsonUrl, + (dataResults) -> + if dataResults?.length > 0 + _data = + columnHeader: dataResults.shift() + data: [null, dataResults] + # purpose is helps in pin pointing which + # handsontable directive to update. + purpose: 'json' + console.log 'resolved' + # pass a message to update the handsontable div + # data is the formatted data which plugs into the + # handontable. + $scope.$emit 'update handsontable', _data + # switch the accordion from getJson to grid + # $scope.$emit("change in showStates","grid") + else + console.log 'rejected:' + msg + try - _showState = new showState(['grid', 'socrData', 'worldBank', 'generate'], $scope) + _showState = new showState(['grid', 'socrData', 'worldBank', 'generate', 'jsonParse'], $scope) catch e console.log e.message - # Adding Listeners + # adding listeners $scope.$on 'update showStates', (obj, data) -> _showState.set data @@ -389,7 +416,7 @@ getData = angular.module('app_analysis_getData', [ console.log 'get data main div loaded' ]) -# Helps sidebar accordion to keep in sync with the main div. +# Helps sidebar accordion to keep in sync with the main div .factory('showState', -> (obj, scope) -> if arguments.length is 0 @@ -410,8 +437,6 @@ getData = angular.module('app_analysis_getData', [ scope.showState[index] = false else scope.showState[i] = true - #console.log "final state" - #console.log scope.showState ) # ### diff --git a/app/styles/custom.less b/app/styles/custom.less index c18e50d2..ad9284b4 100644 --- a/app/styles/custom.less +++ b/app/styles/custom.less @@ -72,7 +72,7 @@ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); to { transform: scale( 1 ) rotate( 360deg ); } } -#nav-clear-tool-search { +.clear-search-input { position: absolute; right: 15px; top: 0; @@ -84,6 +84,23 @@ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); color: #ccc; } -#nav-tool-search { +.margin-search-input { margin: 2px 10px; } + +#nav-clear-tool-search { + .clear-search-input +} + +#nav-tool-search { + .margin-search-input +} + +#getDataJsonUrlClear { + .clear-search-input; + right: 5px; +} + +#getDataJsonUrlInput { + padding-right: 20px; +} From 57cdaa7b7b31a43d149d45de283c90b38b3080f5 Mon Sep 17 00:00:00 2001 From: Nellie Ponarul Date: Mon, 22 Feb 2016 22:17:38 -0800 Subject: [PATCH 19/22] fix(charts): bar chart for single numerical and categorical variable --- app/partials/analysis/charts/sidebar.jade | 6 +- app/scripts/analysis/charts/charts.coffee | 295 ++++++++++++++++++---- 2 files changed, 245 insertions(+), 56 deletions(-) diff --git a/app/partials/analysis/charts/sidebar.jade b/app/partials/analysis/charts/sidebar.jade index 10d7b604..8b336ad8 100644 --- a/app/partials/analysis/charts/sidebar.jade +++ b/app/partials/analysis/charts/sidebar.jade @@ -4,7 +4,7 @@ div(ng-controller="sideChartsCtrl") h4 Variables div p {{graphSelect.message}} - div(ng-show=categorical).form-inline + //div(ng-show=categorical).form-inline input(ng-model="selectorCat" type="checkbox" id="categorical") p X is a categorical variable div.form-inline @@ -14,6 +14,10 @@ div(ng-controller="sideChartsCtrl") div.form-horizontal(ng-show="graphSelect.y") label(for = "y") Add Y select#y.form-control(ng-change="changeVar(selector2,headers,'y');" ng-model="selector2" ng-options="v as v.value for v in headers") + div(ng-show = "labelVar") + input(ng-model="labelCheck" type="checkbox" id = "label") + p Check if Y variable is the labels column + div.form-horizontal(ng-show="graphSelect.z") label(for = "z") Add Radius select#z.form-control(ng-change="changeVar(selector3,headers,'z');" ng-model="selector3" ng-options="v as v.value for v in headers") diff --git a/app/scripts/analysis/charts/charts.coffee b/app/scripts/analysis/charts/charts.coffee index 9682f3f0..a75633d9 100644 --- a/app/scripts/analysis/charts/charts.coffee +++ b/app/scripts/analysis/charts/charts.coffee @@ -83,9 +83,9 @@ charts = angular.module('app_analysis_charts', []) name: 'Bar Graph' value: 0 x: true - y: false + y: true z: false - message: "Choose a numerical variable for x and a categorical variable for y." + message: "Choose a numerical or categorical variable for x. If you have one choose a label variable for y." , name: 'Scatter Plot' value: 1 @@ -163,8 +163,17 @@ charts = angular.module('app_analysis_charts', []) $rootScope.$broadcast 'charts:graphDiv', results + $scope.labelVar = false + $scope.labelCheck = null $scope.changeName = () -> $scope.graphInfo.graph = $scope.graphSelect.name + +# if selector.value is "Bar Chart" +# $scope.labelVar = true +# $rootScope.emit 'Charts: labels y', $scope.labelCheck +# else +# $scope.labelVar = false + $scope.createGraph() $scope.changeVar = (selector,headers, ind) -> @@ -172,6 +181,7 @@ charts = angular.module('app_analysis_charts', []) if selector.value is h.value then $scope.graphInfo[ind] = parseFloat h.key $scope.createGraph() + sb = ctrlMngr.getSb() token = sb.subscribe @@ -211,30 +221,6 @@ charts = angular.module('app_analysis_charts', []) format: _format ]) -#.factory 'stackedBar', [ -# () -> -# _drawStack = (width, height, ) -> -# x = d3.scale.ordinal() -# .rangeRoundBands([0, width], .1) -# -# y = d3.scale.linear() -# .rangeRound([height, 0]) -# -# color = d3.scale.ordinal() -# .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]) -# -# xAxis = d3.svg.axis() -# .scale(x) -# .orient("bottom") -# -# yAxis = d3.svg.axis() -# .scale(y) -# .orient("left") -# .tickFormat(d3.format(".2s")) -# -# -# drawStack:_drawStack -#] .factory 'scatterplot', [ () -> @@ -542,46 +528,238 @@ charts = angular.module('app_analysis_charts', []) .factory 'bar', [ () -> + _setAxisPar = (x,y,xAxis,yAxis,type, width, height) -> + ord = d3.scale.ordinal() + lin = d3.scale.linear() + + switch type + when "xCat" or "xCatAndyNum" + x = ord.rangeRoundBands([0, width], .1) + y = lin.range([ height, 0 ]) + when "xNum" or "xNumAndyCat" + x = lin.range([ 0, width ]) + y = ord.rangeRoundBands([height, 0], .1) + when "xNumAndyNum" + x = lin.range([ 0, width ]) + y = lin.range([ height, 0 ]) + else + alert "Two categorical variables" + + + xAxis = d3.svg.axis().scale(x).orient('bottom') + yAxis = d3.svg.axis().scale(y).orient('left') + _drawBar = (width,height,data,_graph,gdata) -> x = d3.scale.linear().range([ 0, width ]) y = d3.scale.linear().range([ height, 0 ]) + + xAxis = d3.svg.axis().scale(x).orient('bottom') yAxis = d3.svg.axis().scale(y).orient('left') x.domain([d3.min(data, (d)->parseFloat d.x), d3.max(data, (d)->parseFloat d.x)]) y.domain([d3.min(data, (d)->parseFloat d.y), d3.max(data, (d)->parseFloat d.y)]) - _graph.append('g') - .attr('class', 'x axis') - .attr('transform', 'translate(0,' + height + ')') - .call xAxis - .append('text') - .attr('class', 'label') - .attr('x', width-80) - .attr('y', 30) - .text gdata.xLab.value + #without y + if !data[0].y + #Works + if isNaN data[0].x + counts = {} + for i in [0..data.length-1] by 1 + currentVar = data[i].x + counts[currentVar] = counts[currentVar] || 0 + counts[currentVar]++ + counts = d3.entries counts +# console.log counts + x = d3.scale.ordinal().rangeRoundBands([0, width], .1) + xAxis = d3.svg.axis().scale(x).orient('bottom') + x.domain(counts.map (d) -> d.key) + y.domain([d3.min(counts, (d)-> parseFloat d.value), d3.max(counts, (d)-> parseFloat d.value)]) + + _graph.append('g') + .attr('class', 'x axis') + .attr('transform', 'translate(0,' + height + ')') + .call xAxis + .append('text') + .attr('class', 'label') + .attr('transform', 'translate(' + (width / 2) + ',' + 40 + ')') + .text gdata.xLab.value + + _graph.append('g') + .attr('class', 'y axis') + .call yAxis + .append('text') + .attr('transform', 'rotate(-90)') + .attr('y', -50 ) + .attr('x', -(height / 2)) + .attr('dy', '1em') + .text "Count" + + # create bar elements + _graph.selectAll('rect') + .data(counts) + .enter().append('rect') + .attr('class', 'bar') + .attr('x',(d)-> x d.key ) + .attr('width', x.rangeBand()) + .attr('y', (d)-> y d.value ) + .attr('height', (d)-> Math.abs(height - y d.value)) + .attr('fill', 'steelblue') + + + else #data is numerical and only x. height is rect width, width is x of d.x, + #y becomes the categorical + y = d3.scale.ordinal().rangeRoundBands([height, 0], .1) + yAxis = d3.svg.axis().scale(y).orient('left') + + y.domain((d) -> d.x) + + _graph.append('g') + .attr('class', 'x axis') + .attr('transform', 'translate(0,' + height + ')') + .call xAxis + .append('text') + .attr('class', 'label') + .attr('transform', 'translate(' + (width / 2) + ',' + 40 + ')') + .text gdata.xLab.value + + _graph.append('g') + .attr('class', 'y axis') + .call yAxis + .append('text') + .attr('transform', 'rotate(-90)') + .attr('y', -50 ) + .attr('x', -(height / 2)) + .attr('dy', '1em') + .text "Null" + + rectWidth = height/data.length + # create bar elements + _graph.selectAll('rect') + .data(data) + .enter().append('rect') + .attr('class', 'bar') + #.attr('x',(d)-> x d.x ) + .attr('width', (d)-> x d.x) + .attr('y', (d,i)-> i*rectWidth) + .attr('height', rectWidth) + .attr('fill', 'steelblue') + + + + #with y + else + #y is categorical + if isNaN data[0].y + + y = d3.scale.ordinal().range([height,0]) + y.domain(data.map (d) -> d.y) + yAxis = d3.svg.axis().scale(y).orient('left') + + _graph.append('g') + .attr('class', 'x axis') + .attr('transform', 'translate(0,' + height + ')') + .call xAxis + .append('text') + .attr('class', 'label') + .attr('x', width-80) + .attr('y', 30) + .text gdata.xLab.value + + _graph.append('g') + .attr('class', 'y axis') + .call yAxis + .append('text') + .attr('transform', 'rotate(-90)') + .attr("x", -80) + .attr("y", -40) + .attr('dy', '1em') + .text gdata.yLab.value + + _graph.selectAll('rect') + .data(data) + .enter().append('rect') + .attr('class', 'bar') + .attr('x',(d)-> x d.x ) + .attr('width', (d) -> Math.abs(x d.x)) + .attr('y', (d)-> y d.y ) + .attr('height', y.rangeBand()) + .attr('fill', 'steelblue') + + + else if isNaN data[0].x and !isNaN data[0].y + x = d3.scale.ordinal().rangeRoundBands([0, width], .1) + xAxis = d3.svg.axis().scale(x).orient('bottom') + x.domain(data.map (d) -> d.x) + y.domain([d3.min(data, (d)-> parseFloat d.x), d3.max(data, (d)-> parseFloat d.x)]) + + _graph.append('g') + .attr('class', 'x axis') + .attr('transform', 'translate(0,' + height + ')') + .call xAxis + .append('text') + .attr('class', 'label') + .attr('transform', 'translate(' + (width / 2) + ',' + 40 + ')') + .text gdata.xLab.value + + _graph.append('g') + .attr('class', 'y axis') + .call yAxis + .append('text') + .attr('transform', 'rotate(-90)') + .attr('y', -50 ) + .attr('x', -(height / 2)) + .attr('dy', '1em') + .text "Count" + + # create bar elements + _graph.selectAll('rect') + .data(data) + .enter().append('rect') + .attr('class', 'bar') + .attr('x',(d)-> x d.x ) + .attr('width', x.rangeBand()) + .attr('y', (d)-> y d.y ) + .attr('height', (d)-> Math.abs(height - y d.y)) + .attr('fill', 'steelblue') + + + else if !isNaN data[0].y and !isNaN data[0].x + rectWidth = width / data.length + + _graph.append('g') + .attr('class', 'x axis') + .attr('transform', 'translate(0,' + height + ')') + .call xAxis + .append('text') + .attr('class', 'label') + .attr('x', width-80) + .attr('y', 30) + .text gdata.xLab.value + + _graph.append('g') + .attr('class', 'y axis') + .call yAxis + .append('text') + .attr('transform', 'rotate(-90)') + .attr("x", -80) + .attr("y", -40) + .attr('dy', '1em') + .text gdata.yLab.value + + + # create bar elements + _graph.selectAll('rect') + .data(data) + .enter().append('rect') + .attr('class', 'bar') + .attr('x',(d)-> x d.x ) + .attr('width', rectWidth) + .attr('y', (d)-> y d.y ) + .attr('height', (d)-> Math.abs(height - y d.y) ) + .attr('fill', 'steelblue') - _graph.append('g') - .attr('class', 'y axis') - .call yAxis - .append('text') - .attr('transform', 'rotate(-90)') - .attr("x", -80) - .attr("y", -40) - .attr('dy', '1em') - .text gdata.yLab.value - rectWidth = width / data.length - # create bar elements - _graph.selectAll('rect') - .data(data) - .enter().append('rect') - .attr('class', 'bar') - .attr('x',(d)-> x d.x ) - .attr('width', rectWidth) - .attr('y', (d)-> y d.y ) - .attr('height', (d)-> Math.abs(height - y d.y) ) - .attr('fill', 'steelblue') drawBar: _drawBar ] @@ -609,10 +787,14 @@ charts = angular.module('app_analysis_charts', []) if newChartData gdata = newChartData data = newChartData.data +# _label = null + + console.log data #id = '#'+ newInfo.name container = d3.select(elem.find('div')[0]) container.selectAll('*').remove() + console.log "test" svg = container.append('svg').attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom) #svg.select("#remove").remove() _graph = svg.append('g').attr("transform", "translate(" + margin.left + "," + margin.top + ")") @@ -624,6 +806,9 @@ charts = angular.module('app_analysis_charts', []) xMax: d3.max data, (d) -> parseFloat d.x yMax: d3.max data, (d) -> parseFloat d.y +# $scope.on 'Charts: labels y', (events, data) -> +# _label = data + switch gdata.name when 'Bar Graph' bar.drawBar(width,height,data,_graph,gdata) From 126793095c9be31e605b3860ced95c2073be5d88 Mon Sep 17 00:00:00 2001 From: Nellie Ponarul Date: Wed, 24 Feb 2016 10:40:40 -0800 Subject: [PATCH 20/22] fix(charts): fixed bar chart --- app/scripts/analysis/charts/charts.coffee | 222 +++++++++++++--------- 1 file changed, 137 insertions(+), 85 deletions(-) diff --git a/app/scripts/analysis/charts/charts.coffee b/app/scripts/analysis/charts/charts.coffee index a75633d9..9784c7a0 100644 --- a/app/scripts/analysis/charts/charts.coffee +++ b/app/scripts/analysis/charts/charts.coffee @@ -85,7 +85,7 @@ charts = angular.module('app_analysis_charts', []) x: true y: true z: false - message: "Choose a numerical or categorical variable for x. If you have one choose a label variable for y." + message: "Use option x to choose a numerical or categorical variable, or choose one categorical variable and one numerical variable." , name: 'Scatter Plot' value: 1 @@ -114,6 +114,13 @@ charts = angular.module('app_analysis_charts', []) y: false z: false message: "Choose one variable to put into a pie chart." + , + name: 'Stream Graph' + value: 5 + x: true + y: true + z: false + message: "Choose two numerical variables" ] $scope.graphSelect = {} @@ -168,11 +175,6 @@ charts = angular.module('app_analysis_charts', []) $scope.changeName = () -> $scope.graphInfo.graph = $scope.graphSelect.name -# if selector.value is "Bar Chart" -# $scope.labelVar = true -# $rootScope.emit 'Charts: labels y', $scope.labelCheck -# else -# $scope.labelVar = false $scope.createGraph() @@ -222,9 +224,9 @@ charts = angular.module('app_analysis_charts', []) ]) -.factory 'scatterplot', [ +.factory 'scatterPlot', [ () -> - _drawScatterplot = (data,ranges,width,height,_graph,container,gdata) -> + _drawScatterPlot = (data,ranges,width,height,_graph,container,gdata) -> x = d3.scale.linear().domain([ranges.xMin,ranges.xMax]).range([ 0, width ]) y = d3.scale.linear().domain([ranges.yMin,ranges.yMax]).range([ height, 0 ]) @@ -287,7 +289,7 @@ charts = angular.module('app_analysis_charts', []) .on('mouseout', (d)-> tooltip. transition().duration(500).style('opacity', 0)) - drawScatterplot: _drawScatterplot + drawScatterPlot: _drawScatterPlot ] .factory 'histogram',[ @@ -651,7 +653,7 @@ charts = angular.module('app_analysis_charts', []) #y is categorical if isNaN data[0].y - y = d3.scale.ordinal().range([height,0]) + y = d3.scale.ordinal().rangeRoundBands([0, height], .1) y.domain(data.map (d) -> d.y) yAxis = d3.svg.axis().scale(y).orient('left') @@ -679,97 +681,145 @@ charts = angular.module('app_analysis_charts', []) .data(data) .enter().append('rect') .attr('class', 'bar') - .attr('x',(d)-> x d.x ) + #.attr('x',(d)-> x d.x ) .attr('width', (d) -> Math.abs(x d.x)) .attr('y', (d)-> y d.y ) .attr('height', y.rangeBand()) .attr('fill', 'steelblue') - else if isNaN data[0].x and !isNaN data[0].y - x = d3.scale.ordinal().rangeRoundBands([0, width], .1) - xAxis = d3.svg.axis().scale(x).orient('bottom') - x.domain(data.map (d) -> d.x) - y.domain([d3.min(data, (d)-> parseFloat d.x), d3.max(data, (d)-> parseFloat d.x)]) - - _graph.append('g') - .attr('class', 'x axis') - .attr('transform', 'translate(0,' + height + ')') - .call xAxis - .append('text') - .attr('class', 'label') - .attr('transform', 'translate(' + (width / 2) + ',' + 40 + ')') - .text gdata.xLab.value - - _graph.append('g') - .attr('class', 'y axis') - .call yAxis - .append('text') - .attr('transform', 'rotate(-90)') - .attr('y', -50 ) - .attr('x', -(height / 2)) - .attr('dy', '1em') - .text "Count" - - # create bar elements - _graph.selectAll('rect') - .data(data) - .enter().append('rect') - .attr('class', 'bar') - .attr('x',(d)-> x d.x ) - .attr('width', x.rangeBand()) - .attr('y', (d)-> y d.y ) - .attr('height', (d)-> Math.abs(height - y d.y)) - .attr('fill', 'steelblue') + else if !isNaN data[0].y + if isNaN data[0].x + console.log "xCat and yNum" + x = d3.scale.ordinal().rangeRoundBands([0, width], .1) + x.domain(data.map (d) -> d.x) + xAxis = d3.svg.axis().scale(x).orient('bottom') + #y.domain([d3.min(data, (d)-> parseFloat d.y), d3.max(data, (d)-> parseFloat d.y)]) + + _graph.append('g') + .attr('class', 'x axis') + .attr('transform', 'translate(0,' + height + ')') + .call xAxis + .append('text') + .attr('class', 'label') + .attr('transform', 'translate(' + (width / 2) + ',' + 40 + ')') + .text gdata.xLab.value + + _graph.append('g') + .attr('class', 'y axis') + .call yAxis + .append('text') + .attr('transform', 'rotate(-90)') + .attr('y', -50 ) + .attr('x', -(height / 2)) + .attr('dy', '1em') + .text "Count" + + # create bar elements + _graph.selectAll('rect') + .data(data) + .enter().append('rect') + .attr('class', 'bar') + .attr('x',(d)-> x d.x ) + .attr('width', x.rangeBand()) + .attr('y', (d)-> y d.y ) + .attr('height', (d)-> Math.abs(height - y d.y)) + .attr('fill', 'steelblue') + else + + #else if !isNaN data[0].y and !isNaN data[0].x + rectWidth = width / data.length + + _graph.append('g') + .attr('class', 'x axis') + .attr('transform', 'translate(0,' + height + ')') + .call xAxis + .append('text') + .attr('class', 'label') + .attr('x', width-80) + .attr('y', 30) + .text gdata.xLab.value + + _graph.append('g') + .attr('class', 'y axis') + .call yAxis + .append('text') + .attr('transform', 'rotate(-90)') + .attr("x", -80) + .attr("y", -40) + .attr('dy', '1em') + .text gdata.yLab.value + + + # create bar elements + _graph.selectAll('rect') + .data(data) + .enter().append('rect') + .attr('class', 'bar') + .attr('x',(d)-> x d.x ) + .attr('width', rectWidth) + .attr('y', (d)-> y d.y ) + .attr('height', (d)-> Math.abs(height - y d.y) ) + .attr('fill', 'steelblue') - else if !isNaN data[0].y and !isNaN data[0].x - rectWidth = width / data.length - - _graph.append('g') - .attr('class', 'x axis') - .attr('transform', 'translate(0,' + height + ')') - .call xAxis - .append('text') - .attr('class', 'label') - .attr('x', width-80) - .attr('y', 30) - .text gdata.xLab.value - - _graph.append('g') - .attr('class', 'y axis') - .call yAxis - .append('text') - .attr('transform', 'rotate(-90)') - .attr("x", -80) - .attr("y", -40) - .attr('dy', '1em') - .text gdata.yLab.value - - - # create bar elements - _graph.selectAll('rect') - .data(data) - .enter().append('rect') - .attr('class', 'bar') - .attr('x',(d)-> x d.x ) - .attr('width', rectWidth) - .attr('y', (d)-> y d.y ) - .attr('height', (d)-> Math.abs(height - y d.y) ) - .attr('fill', 'steelblue') + drawBar: _drawBar +] +.factory 'streamGraph', [ + () -> - drawBar: _drawBar + _randomSample = (data, n) -> + #take an array of objects, and the desired number of random ones. return array of objects + for d in data + d.x = +d.x + d.y = +d.y + + random = [] + for i in [0...n-1] by 1 + random.push(data[Math.floor(Math.random() * data.length)]) + return random + + _streamGraph = (data,ranges,width,height,_graph) -> + n = 20 + m = 100 + stack = d3.layout.stack().offset('wiggle') + layers = stack(d3.range(n).map () -> _randomSample(data,m)) + console.log layers + x = d3.scale.linear() + .domain([0, m - 1]) + .range([0, width]); + + y = d3.scale.linear() + .domain([0, d3.max(layers, (layer)-> d3.max(layer, (d) -> return d.y0 + d.y))]) + .range([height, 0]) + + color = d3.scale.linear() + .range(["#aad", "#556"]) + + area = d3.svg.area() + .x((d) -> x d.x) + .y0((d) -> y d.y0) + .y1((d) -> y(d.y0 + d.y)) + + _graph.selectAll("path") + .data(layers) + .enter().append("path") + .attr("d", area) + .style("fill", () -> color(Math.random())) + + streamGraph: _streamGraph ] .directive 'd3Charts', [ - 'scatterplot', + 'scatterPlot', 'histogram', 'pie', 'bubble', - 'bar' - (scatterplot,histogram,pie,bubble,bar) -> + 'bar', + 'streamGraph' + (scatterPlot,histogram,pie,bubble,bar,streamGraph) -> restrict: 'E' template: "
" link: (scope, elem, attr) -> @@ -820,5 +870,7 @@ charts = angular.module('app_analysis_charts', []) _graph = svg.append('g').attr("transform", "translate(300,250)").attr("id", "remove") pie.drawPie(data,width,height,_graph) when 'Scatter Plot' - scatterplot.drawScatterplot(data,ranges,width,height,_graph,container,gdata) + scatterPlot.drawScatterPlot(data,ranges,width,height,_graph,container,gdata) + when 'Stream Graph' + streamGraph.streamGraph(data,ranges,width,height,_graph) ] From d9aa3a26d33cbd3fc3e25f4265a06e3d850704c3 Mon Sep 17 00:00:00 2001 From: alxndrkalinin Date: Thu, 25 Feb 2016 16:50:00 -0500 Subject: [PATCH 21/22] fix(README): fix line breaks in installation instructions --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 434d9285..69d54c9d 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Clone the repository. $> git clone https://github.com/SOCR/SOCRAT.git Now, lets install all the dependencies. Go into the root folder, + $> cd SOCRAT $> npm install $> bower install @@ -72,7 +73,7 @@ Copyright and License **The LGPL v3.0 License** -Copyright (c) 2013-2015 Statistics Online Computational Resource [(SOCR)](http://www.StatisticsResource.org) +Copyright (c) 2013-2016 Statistics Online Computational Resource [(SOCR)](http://www.StatisticsResource.org) All SOCR programs, materials, tools and resources are developed by and freely disseminated to the entire community. Users may revise, extend, redistribute, modify under the terms of the Lesser GNU General Public License From fe8dec24fcd887b73d025466a83ea972f73074c7 Mon Sep 17 00:00:00 2001 From: alxndrkalinin Date: Thu, 25 Feb 2016 16:52:31 -0500 Subject: [PATCH 22/22] chore: version bump to 0.1.5-alpha.5 #SOCRFW-222 --- bower.json | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bower.json b/bower.json index 7c76bf99..73270917 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "author": "Alexandr Kalinin, Selvam Palanimalai", "name": "SOCRAT", - "version": "v0.1.5-alpha.4", + "version": "v0.1.5-alpha.5", "description": "Flexible HTML5/JS toolkit for interactive data analysis and visuzalization", "homepage": "https://github.com/SOCR/SOCRAT", "dependencies": { diff --git a/package.json b/package.json index 9c011b76..a4f4e60f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "author": "Alexandr Kalinin, Selvam Palanimalai", "name": "SOCRAT", - "version": "v0.1.5-alpha.4", + "version": "v0.1.5-alpha.5", "description": "Flexible HTML5/JS toolkit for interactive data analysis and visuzalization", "homepage": "https://github.com/SOCR/SOCRAT", "repository": { @@ -54,5 +54,5 @@ "scripts": { "test": "grunt test" }, - "license": "MIT" + "license": "LGPL v3.0" }