From 70530e616b9fcb26a40f3c64a74c33a938d0db30 Mon Sep 17 00:00:00 2001 From: Danielle Date: Tue, 9 Feb 2016 14:10:39 -0500 Subject: [PATCH 1/8] changed homepage word cloud to the d3-cloud format --- assets/js/index.controller.js | 71 +++++++++++++++++++++++++++++++++-- karma.conf.js | 1 + views/index.jade | 2 +- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/assets/js/index.controller.js b/assets/js/index.controller.js index 3ac8c0d..3c3f621 100644 --- a/assets/js/index.controller.js +++ b/assets/js/index.controller.js @@ -6,7 +6,73 @@ function IndexController ($scope) { - var diameter = 100, + var fill = d3.scale.category20(); + var words = [{ + text: "the", + frequency: 20 + }, { + text: "quick", + frequency: 10 + }, { + text: "brown", + frequency: 10 + }, { + text: "fox", + frequency: 10 + }, { + text: "jumps", + frequency: 10 + }, { + text: "over", + frequency: 10 + }, { + text: "lazy", + frequency: 10 + }, { + text: "dog", + frequency: 10 + }] + + d3.layout.cloud().size([300, 300]) + .words(words) + .rotate(function() { + return ~~(Math.random() * 2) * 90; + }) + .font("Impact") + .fontSize(function(d) { + return 3*(d.frequency) + }) + .on("end", draw) + .start(); + + + function draw(words) { + d3.select("#graph").append("svg") + .attr("width", 300) + .attr("height", 300) + .append("g") + .attr("transform", "translate(150,150)") + .selectAll("text") + .data(words) + .enter().append("text") + .style("font-size", function(d) { + return d.size + "px"; + }) + .style("font-family", "Impact") + .style("fill", function(d, i) { + return fill(i); + }) + .attr("text-anchor", "middle") + .attr("transform", function(d) { + return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; + }) + .text(function(d) { + return d.text; + }); + } + + +/* var diameter = 100, format = d3.format(",d"), color = d3.scale.category20c(); @@ -86,7 +152,6 @@ return {children: classes}; } - d3.select(self.frameElement).style("height", diameter + "px"); - + d3.select(self.frameElement).style("height", diameter + "px");*/ } })(); diff --git a/karma.conf.js b/karma.conf.js index 1c3da6a..56d95c3 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -18,6 +18,7 @@ module.exports = function(config) { 'public/bower_components/ng-file-upload/angular-file-upload-html5-shim.min.js', 'public/bower_components/angular/angular.min.js', 'public/bower_components/angular-mocks/angular-mocks.js', + 'public/bower_components/d3-cloud/d3.layout.cloud.js', 'public/bower_components/d3/d3.min.js', 'public/bower_components/lodash/dist/lodash.min.js', 'public/bower_components/ng-file-upload/angular-file-upload.min.js', diff --git a/views/index.jade b/views/index.jade index 049d976..4a3d298 100644 --- a/views/index.jade +++ b/views/index.jade @@ -13,10 +13,10 @@ head link(rel='stylesheet' href='css/app.css') link(rel='stylesheet' href='bower_components/font-awesome/css/font-awesome.css') link(href='bower_components/jsoneditor/dist/jsoneditor.min.css' rel='stylesheet' type='text/css') - script(src='bower_components/angular/angular.min.js') script(src="bower_components/jsoneditor/dist/jsoneditor.min.js") script(src='bower_components/d3/d3.min.js') + script(src='bower_components/d3-cloud/build/d3.layout.cloud.js') script(src='bower_components/lodash/dist/lodash.min.js') script(src='bower_components/ng-file-upload/angular-file-upload.min.js') script(src='bower_components/ui-router/release/angular-ui-router.min.js') From 1bc96a0f1a04d3011b2f38dbd88e553b0fe039d1 Mon Sep 17 00:00:00 2001 From: Danielle Date: Tue, 9 Feb 2016 14:35:57 -0500 Subject: [PATCH 2/8] adjusted the coloring for the homepage wordcloud so words didn't blend in with blue background --- assets/js/index.controller.js | 95 +++-------------------------------- 1 file changed, 7 insertions(+), 88 deletions(-) diff --git a/assets/js/index.controller.js b/assets/js/index.controller.js index 3c3f621..0fb3bbd 100644 --- a/assets/js/index.controller.js +++ b/assets/js/index.controller.js @@ -6,7 +6,7 @@ function IndexController ($scope) { - var fill = d3.scale.category20(); + var words = [{ text: "the", frequency: 20 @@ -33,14 +33,16 @@ frequency: 10 }] - d3.layout.cloud().size([300, 300]) + var fill = d3.scale.ordinal().range(["#ff7f0e","aec7e8","#ffbb78","#2ca02c","#ff9896","#9467bd","#17becf","#d62728","#d62728"]); + + d3.layout.cloud().size([450, 450]) .words(words) .rotate(function() { return ~~(Math.random() * 2) * 90; }) .font("Impact") .fontSize(function(d) { - return 3*(d.frequency) + return 4*(d.frequency) }) .on("end", draw) .start(); @@ -48,8 +50,8 @@ function draw(words) { d3.select("#graph").append("svg") - .attr("width", 300) - .attr("height", 300) + .attr("width", 400) + .attr("height", 400) .append("g") .attr("transform", "translate(150,150)") .selectAll("text") @@ -70,88 +72,5 @@ return d.text; }); } - - -/* var diameter = 100, - format = d3.format(",d"), - color = d3.scale.category20c(); - - var bubble = d3.layout.pack() - .sort(null) - .size([diameter, diameter]) - .padding(1.5); - - var svg = d3.select("#graph").append("svg") - .attr("class", "bubble") - .attr("viewBox", "0 0 100 100"); - - var root = {"name": "foo", - "children": [ - { - name: "the", - size: "20" - }, { - name: "quick", - size: "30" - }, { - name: "brown", - size: "10" - }, { - name: "fox", - size: "40" - }, { - name: "jumps", - size: "50" - }, { - name: "over", - size: "20" - }, { - name: "lazy", - size: "30" - }, { - name: "dog", - size: "10" - } - ]}; - - var node = svg.selectAll(".node") - .data(bubble.nodes(classes(root)) - .filter(function(d) { return !d.children; })) - .enter().append("g") - .attr("class", "node") - .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); - - node.append("title") - .text(function(d) { return d.className + ": " + format(d.value); }); - - node.append("circle") - .attr("r", function(d) { return d.r; }) - // Should really do this: - // .style("fill", function(d) { return color(d.packageName); }); - .style("fill", "#F36E21"); - - node.append("text") - .attr("dy", ".3em") - .style("text-anchor", "middle") - .attr("fill", "white") - .attr("font-size", function (d) { - return ((0.2 * d.className.length) + (0.5 * d.r)) + "px"; - }) - .text(function(d) { return d.className; }); - - // Returns a flattened hierarchy containing all leaf nodes under the root. - function classes(root) { - var classes = []; - - function recurse(name, node) { - if (node.children) node.children.forEach(function(child) { recurse(node.name, child); }); - else classes.push({packageName: name, className: node.name, value: node.size}); - } - - recurse(null, root); - return {children: classes}; - } - - d3.select(self.frameElement).style("height", diameter + "px");*/ } })(); From 9a0fcbebf7fa87557692f59ef6406f66179b0ae8 Mon Sep 17 00:00:00 2001 From: Danielle Date: Tue, 9 Feb 2016 14:39:14 -0500 Subject: [PATCH 3/8] modified word cloud position with css --- assets/js/index.controller.js | 8 ++++---- assets/stylesheets/app.less | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/assets/js/index.controller.js b/assets/js/index.controller.js index 0fb3bbd..d2ef251 100644 --- a/assets/js/index.controller.js +++ b/assets/js/index.controller.js @@ -35,14 +35,14 @@ var fill = d3.scale.ordinal().range(["#ff7f0e","aec7e8","#ffbb78","#2ca02c","#ff9896","#9467bd","#17becf","#d62728","#d62728"]); - d3.layout.cloud().size([450, 450]) + d3.layout.cloud().size([400, 400]) .words(words) .rotate(function() { return ~~(Math.random() * 2) * 90; }) .font("Impact") .fontSize(function(d) { - return 4*(d.frequency) + return 3.5*(d.frequency) }) .on("end", draw) .start(); @@ -50,8 +50,8 @@ function draw(words) { d3.select("#graph").append("svg") - .attr("width", 400) - .attr("height", 400) + .attr("width", 350) + .attr("height", 350) .append("g") .attr("transform", "translate(150,150)") .selectAll("text") diff --git a/assets/stylesheets/app.less b/assets/stylesheets/app.less index 4c09e61..800f3ef 100644 --- a/assets/stylesheets/app.less +++ b/assets/stylesheets/app.less @@ -129,3 +129,7 @@ body { .jsoneditor { height: 600px !important; } + +.graph{ + padding-top:20px; +} \ No newline at end of file From 9326008a88dc6e06d0199bd154fa60e0ac2ae54f Mon Sep 17 00:00:00 2001 From: Jeremy Vasta Date: Mon, 29 Feb 2016 13:51:24 -0500 Subject: [PATCH 4/8] Merge branch 'd3wordcloud' of https://github.com/Pastafarians/linguine-node Conflicts: assets/js/index.controller.js --- assets/js/analysis/new.controller.js | 65 +++----- assets/js/analysis/show.controller.js | 205 ++++++++++++++++++++++++++ assets/js/index.controller.js | 1 - bower.json | 1 + karma.conf.js | 1 + package.json | 2 +- views/templates/analysis/new.jade | 3 +- 7 files changed, 229 insertions(+), 49 deletions(-) diff --git a/assets/js/analysis/new.controller.js b/assets/js/analysis/new.controller.js index 39b7e35..d1a3fed 100644 --- a/assets/js/analysis/new.controller.js +++ b/assets/js/analysis/new.controller.js @@ -8,6 +8,8 @@ $scope.analysisNotSelected = true; $scope.needTokenizer = true; $scope.analysis = {analysisName: ""}; + $scope.preprocAvailable = true; + /* * Analyses are the crux of the NLP workflow, so they should be @@ -17,35 +19,12 @@ * by the tokenizerTypes and cleanupTypes objects. */ $scope.analysisTypes = [ - //{ - //name: "Part of Speech Tagging", - //unfriendly_name: "pos_tag", - //description: "Uses the TextBlob tagger to generate Part-of-Speech tags for text.", - //multipleCorporaAllowed: true - //}, - //{ - //name: "Sentence Tokenizer", - //unfriendly_name: "sentence_tokenize", - //description: "Uses the NLTK sentence tokenizer to break a corpus up into sentences.", - //multipleCorporaAllowed: false - //}, - //{ - //name: "Term Frequency - Inverse Document Frequency", - //unfriendly_name: "tfidf", - //description: "Uses the NLTK Punkt tokenizer to separate terms. Best applied to a large set of corpora. Useful for finding the most important words in the collection of words.", - //multipleCorporaAllowed: true - //}, - //{ - //name: "Topic Modeling", - //unfriendly_name: "topic_model", - //description: "Uses Gensim to detect and group the similar topics in a set of corpora.", - //multipleCorporaAllowed: true - //}, { name: "Term Frequency Analysis", unfriendly_name: "wordcloudop", description: "This operation uses the NLTK Punkt tokenizer to separate terms. Used for finding the most frequent words a single corpus.", multipleCorporaAllowed: false, + tokenAllowed: true, tokenizerRequired: true }, { @@ -53,12 +32,14 @@ unfriendly_name: "nlp-pos", description: "This operation performs a part of speech analysis on each word provided in the corpus. Each word will receive an identifier which represents the appropriate part of speech for the given word. ", multipleCorporaAllowed: false, + tokenAllowed: false, tokenizerRequired: false }, { name: "Named Entity Recognition (Stanford CoreNLP)", unfriendly_name: "nlp-ner", description: "This operation will classify each word in the corpus based on its status as a place, organization, location, or expression of time. If a term does not match as a named entity, it will recieve a status of '0' ", + tokenAllowed: false, multipleCorporaAllowed: false, tokenizerRequired: false } @@ -116,12 +97,10 @@ * Key[analysisUnfriendlyName] => value [cleanupUnfriendlyName1, unfriendlyName2, ... n] */ $scope.cleanupTypes = { - "pos_tag": [cleanups.stem_lancaster, cleanups.stem_porter, cleanups.stem_snowball, - cleanups.lemmatize_wordnet, cleanups.removecapsgreedy, cleanups.removecapsnnp, - cleanups.removepunct ], - "wordcloudop": [cleanups.stem_lancaster, cleanups.stem_porter, cleanups.stem_snowball, - cleanups.lemmatize_wordnet, cleanups.removecapsgreedy, cleanups.removecapsnnp, - cleanups.removepunct ] + "pos_tag": [cleanups.stem_lancaster, cleanups.stem_porter, cleanups.stem_snowball, cleanups.lemmatize_wordnet, cleanups.removecapsgreedy, cleanups.removecapsnnp, cleanups.removepunct ], + "wordcloudop": [cleanups.stem_lancaster, cleanups.stem_porter, cleanups.stem_snowball, cleanups.lemmatize_wordnet, cleanups.removecapsgreedy, cleanups.removecapsnnp, cleanups.removepunct ], + "nlp-pos": [], + "nlp-ner": [] }; $scope.tokenizerTypes = [ @@ -130,21 +109,6 @@ unfriendly_name: "word_tokenize_treebank", description: "Separates the text in each corpus into individual word tokens, using NLTK's Penn Treebank tokenizer. This is a good general purpose tokenizer to use." }, - //{ - //name: "Word Tokenize (Whitespace and Punctuation)", - //unfriendly_name: "word_tokenize_whitespace_punct", - //description: "Separates the text in each corpus into individual word tokens, splitting on whitespace and punctuation marks." - //}, - { - name: "Word Tokenize (Spaces)", - unfriendly_name: "word_tokenize_spaces", - description: "Separates the text in each corpus into individual word tokens, splitting on spaces." - }, - { - name: "Word Tokenize (Tabs)", - unfriendly_name: "word_tokenize_tabs", - description: "Separates the text in each corpus into individual word tokens, splitting on tabs." - } ]; $http.get('api/corpora') @@ -198,12 +162,23 @@ $scope.selectedTokenizer = e.tokenizer; $scope.needTokenizer = false; }; + + $scope.checkIfNoPreprocessingAvailable = function() { + var analysisName = $scope.selectedAnalysis.unfriendly_name; + var noCleanupTypes = $scope.cleanupTypes[analysisName].length == 0; + + if(noCleanupTypes && !$scope.selectedAnalysis.tokenAllowed) { + flash.info.setMessage("No preprocessing options are available for " + $scope.selectedAnalysis.name); + $rootScope.$emit("event:angularFlash"); + } + } $scope.onPreprocessingTabClick = function(e) { if(!$scope.selectedAnalysis) { flash.danger.setMessage('Please select an analysis before selecting preprocessing options.'); $rootScope.$emit("event:angularFlash"); } + $scope.checkIfNoPreprocessingAvailable(); }; $scope.onCorporaTabClick = function(e) { diff --git a/assets/js/analysis/show.controller.js b/assets/js/analysis/show.controller.js index 703e46a..a29d185 100644 --- a/assets/js/analysis/show.controller.js +++ b/assets/js/analysis/show.controller.js @@ -148,11 +148,216 @@ d3.select(self.frameElement).style("height", diameter + "px"); } + $scope.visualizeParseTree = function(sentiment) { + + //Move this to a listener when supporting multiple sentences + data = convertData($scope.results.parse); + renderTree(); + + //Converts results from flat to heirarchical + function convertData = function(words) { + + var rootNode = { 'id': 0, 'value': 'root', 'pos': 'root' }; + words.push(rootNode); + + var dataMap = words.reduce(function(map, node) { + map[node.id] = node; + return map; + }, {}); + + var treeData = []; + words.forEach(function(node) { + + var head = dataMap[node.head]; + + if (head) + (head.children || (head.children = [])).push(node); + else + treeData.push(node); + }); + + return treeData; + }; + + //Builds canvas and creates root + function renderTree = function () { + var tree = d3.layout.tree().nodeSize([100, 50]); + + tree.separation(function (a, b) { + var w1 = a.value.length; + var w2 = b.value.length; + + var scale = 0.13; + + return Math.ceil((w1 * scale) + (w2 * scale) / 2); + }); + + var svg = d3.select("#graph").append('svg') + .attr('class', 'svg-container') + .style('width', 1500) + .style('height', 1500) + .style('overflow', 'auto'); + + var canvas = svg.append('g') + .attr('class', 'canvas'); + + canvas.append('g') + .attr('transform', 'translate(500 , 10) scale(.75)'); + + var root = data[0]; + + update(root); + + return this; + }; + + //Draws the tree from the root + function update = function (source) { + + var diagonal = d3.svg.diagonal() + .projection(function (d) { + return [d.x, d.y]; + }); + + var nodes = this.tree(this.root).reverse(), + links = this.tree.links(nodes); + + nodes.forEach(function (d) { + d.y = d.depth * 100; + }); + + var node = this.svg.select('.canvas g') + .selectAll('g.node') + .data(nodes, function (d, i) { + return d.id || (d.id = ++i); + }); + + var nodeEnter = node.enter() + .append('g') + .attr('class', 'node') + .attr('transform', function (d) { + return 'translate(' + source.x + ', ' + source.y + ')'; + }); + + nodeEnter.append('circle') + .attr('r', 10) + .style('stroke', '#000') + .style('stroke-width', '3px') + .style('fill', '#FFF'); + + nodeEnter.append('text') + .attr('y', function (d, i) { + return (d.pos == 'root') ? -30 : 15; + }) + .attr('dy', '14px') + .attr('text-anchor', 'middle') + .text(function (d) { + return d.value; + }) + .style('fill', function (d, i) { + return (d.pos == 'root') ? '#CCC' : '#333'; + }) + .style('font-family', 'Cambria, Serif') + .style('letter-spacing', '2px') + .style('font-size', '18px') + .style('fill-opacity', 1); + if(sentiment){ + nodeEnter.append('text') + .attr('y', function (d, i) { + return (d.pos == 'root') ? 0 : -30; + }) + .attr('dy', '12px') + .attr('text-anchor', 'middle') + .attr('class', 'label') + .style('font-family', 'sans-serif') + .style('font-size', '12px') + .style('font-weight', 500) + .style('letter-spacing', '1px') + .style('fill', '#666') + .text(function (d) { + return d.tag; + }); + }else{ + nodeEnter.append('text') + .attr('y', function (d, i) { + return (d.pos == 'root') ? 0 : -30; + }) + .attr('dy', '12px') + .attr('text-anchor', 'middle') + .attr('class', 'label') + .style('font-family', 'sans-serif') + .style('font-size', '12px') + .style('font-weight', 500) + .style('letter-spacing', '1px') + .style('fill', '#666') + .text(function (d) { + switch(d.sentiment){ + case 0: + return "--"; + case 1: + return "-"; + case 3: + return "+"; + case 4: + return "++"; + default: + return ""; + }; + }); + } + + var nodeUpdate = node.transition() + .duration(500) + .attr('transform', function (d) { + return 'translate(' + d.x + ', ' + d.y + ')'; + }); + + var link = this.svg.select('.canvas g') + .selectAll('path.link') + .data(links, function (d) { + return d.target.id; + }); + + link.enter() + .insert('path', 'g') + .attr('class', 'link') + .style('stroke', '#CCC') + .style('stroke-width', '2px') + .style('fill', 'none') + .attr('d', function (d) { + var o = { + x: source.x, + y: source.y + }; + + return diagonal({ + source: o, + target: o + }); + }); + + link.transition() + .duration(500) + .attr('d', diagonal); + + nodes.forEach(function (d, i) { + d.x0 = d.x; + d.y0 = d.y; + }); + }; + } + + $scope.visualize = function () { if ($scope.analysis.analysis === "tfidf" ) { $scope.visualizeTfidf(); } else if ($scope.analysis.analysis == "wordcloudop") { $scope.visualizeWordcloud(); + } else if ($scope.analysis.analysis == "nlp-parse"){ + $scope.visualizeParseTree(false); + } + } else if ($scope.analysis.analysis == "nlp-sentiment"){ + $scope.visualizeParseTree(true); } } diff --git a/assets/js/index.controller.js b/assets/js/index.controller.js index d2ef251..2c0d3bb 100644 --- a/assets/js/index.controller.js +++ b/assets/js/index.controller.js @@ -6,7 +6,6 @@ function IndexController ($scope) { - var words = [{ text: "the", frequency: 20 diff --git a/bower.json b/bower.json index 38e9024..7d92b91 100644 --- a/bower.json +++ b/bower.json @@ -20,6 +20,7 @@ "angular-spinner": "~0.8.0", "bootstrap": "~3.2.0", "d3": "~3.4.13", + "d3-cloud": "~1.2.1", "font-awesome": "~4.2.0", "jsoneditor": "~4.2.1", "lodash": "~2.4.1", diff --git a/karma.conf.js b/karma.conf.js index 56d95c3..4d67a57 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -20,6 +20,7 @@ module.exports = function(config) { 'public/bower_components/angular-mocks/angular-mocks.js', 'public/bower_components/d3-cloud/d3.layout.cloud.js', 'public/bower_components/d3/d3.min.js', + 'public/bower_components/d3-cloud/build/d3.layout.cloud.js', 'public/bower_components/lodash/dist/lodash.min.js', 'public/bower_components/ng-file-upload/angular-file-upload.min.js', 'public/bower_components/ui-router/release/angular-ui-router.min.js', diff --git a/package.json b/package.json index e9209e1..d85f4da 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "test": "gulp test", - "start": "./bin/www", + "start": "node ./bin/www", "ldap": "./fix_ldap.sh" }, "repository": { diff --git a/views/templates/analysis/new.jade b/views/templates/analysis/new.jade index 6428bb2..eb539fd 100644 --- a/views/templates/analysis/new.jade +++ b/views/templates/analysis/new.jade @@ -30,8 +30,7 @@ tab(disabled="analysisNotSelected" heading='3. Select Preprocessing Options', ng-click="onPreprocessingTabClick(this)") .list-group - - a.list-group-item(ng-repeat="tokenizer in tokenizerTypes", + a.list-group-item(ng-show="selectedAnalysis.tokenAllowed" ng-repeat="tokenizer in tokenizerTypes", ng-class="{active:selectedTokenizer==tokenizer}", ng-click="onTokenizerClick(this)") h4.list-group-item-heading strong {{ tokenizer.name }} From db7df5a180876a5eedbd77b046ac988a3124667c Mon Sep 17 00:00:00 2001 From: Jeremy Vasta Date: Thu, 3 Mar 2016 14:05:45 -0500 Subject: [PATCH 5/8] Updated some formatting --- assets/js/analysis/show.controller.js | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/assets/js/analysis/show.controller.js b/assets/js/analysis/show.controller.js index ce21c43..f091c8f 100644 --- a/assets/js/analysis/show.controller.js +++ b/assets/js/analysis/show.controller.js @@ -170,7 +170,7 @@ renderTree(); //Converts results from flat to heirarchical - function convertData = function(words) { + function convertData(words) { var rootNode = { 'id': 0, 'value': 'root', 'pos': 'root' }; words.push(rootNode); @@ -192,10 +192,10 @@ }); return treeData; - }; + } //Builds canvas and creates root - function renderTree = function () { + function renderTree() { var tree = d3.layout.tree().nodeSize([100, 50]); tree.separation(function (a, b) { @@ -224,10 +224,10 @@ update(root); return this; - }; + } //Draws the tree from the root - function update = function (source) { + function update(source) { var diagonal = d3.svg.diagonal() .projection(function (d) { @@ -272,8 +272,6 @@ .style('fill', function (d, i) { return (d.pos == 'root') ? '#CCC' : '#333'; }) - .style('font-family', 'Cambria, Serif') - .style('letter-spacing', '2px') .style('font-size', '18px') .style('fill-opacity', 1); if(sentiment){ @@ -284,10 +282,8 @@ .attr('dy', '12px') .attr('text-anchor', 'middle') .attr('class', 'label') - .style('font-family', 'sans-serif') .style('font-size', '12px') .style('font-weight', 500) - .style('letter-spacing', '1px') .style('fill', '#666') .text(function (d) { return d.tag; @@ -300,13 +296,11 @@ .attr('dy', '12px') .attr('text-anchor', 'middle') .attr('class', 'label') - .style('font-family', 'sans-serif') .style('font-size', '12px') .style('font-weight', 500) - .style('letter-spacing', '1px') .style('fill', '#666') .text(function (d) { - switch(d.sentiment){ + switch(d.tag){ case 0: return "--"; case 1: @@ -359,18 +353,17 @@ d.x0 = d.x; d.y0 = d.y; }); - }; - } + } + }; - $scope.visualize = function () { + $scope.visualize = function(){ if ($scope.analysis.analysis === "tfidf" ) { $scope.visualizeTfidf(); } else if ($scope.analysis.analysis == "wordcloudop") { $scope.visualizeWordcloud(); } else if ($scope.analysis.analysis == "nlp-parse"){ $scope.visualizeParseTree(false); - } } else if ($scope.analysis.analysis == "nlp-sentiment"){ $scope.visualizeParseTree(true); } From 9dc1e3b00391e003c7cd42d6d2b396c8fa650e78 Mon Sep 17 00:00:00 2001 From: jmp3833 Date: Thu, 3 Mar 2016 18:48:52 -0500 Subject: [PATCH 6/8] Pass reference to tree to rendering function (cant use 'this') --- assets/js/analysis/show.controller.js | 17 +++++++++-------- views/templates/analysis/show.jade | 3 +-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/assets/js/analysis/show.controller.js b/assets/js/analysis/show.controller.js index f091c8f..216cca0 100644 --- a/assets/js/analysis/show.controller.js +++ b/assets/js/analysis/show.controller.js @@ -165,8 +165,9 @@ $scope.visualizeParseTree = function(sentiment) { - //Move this to a listener when supporting multiple sentences - data = convertData($scope.results.parse); + //Move this to a listener when supporting multiple sentences + //#TODO: Make this not a single sentence + data = convertData($scope.results[0].sentiment_json); renderTree(); //Converts results from flat to heirarchical @@ -221,27 +222,27 @@ var root = data[0]; - update(root); + update(root, tree, svg); return this; } //Draws the tree from the root - function update(source) { + function update(source, tree, svg) { var diagonal = d3.svg.diagonal() .projection(function (d) { return [d.x, d.y]; }); - var nodes = this.tree(this.root).reverse(), - links = this.tree.links(nodes); + var nodes = tree(source).reverse(), + links = tree.links(nodes); nodes.forEach(function (d) { d.y = d.depth * 100; }); - var node = this.svg.select('.canvas g') + var node = svg.select('.canvas g') .selectAll('g.node') .data(nodes, function (d, i) { return d.id || (d.id = ++i); @@ -321,7 +322,7 @@ return 'translate(' + d.x + ', ' + d.y + ')'; }); - var link = this.svg.select('.canvas g') + var link = svg.select('.canvas g') .selectAll('path.link') .data(links, function (d) { return d.target.id; diff --git a/views/templates/analysis/show.jade b/views/templates/analysis/show.jade index 9460be7..1f7f610 100644 --- a/views/templates/analysis/show.jade +++ b/views/templates/analysis/show.jade @@ -13,8 +13,7 @@ tabset(justified='true') tab(heading='Visualization') #graph - - div(ng-if="analysis.analysis !== 'wordcloudop'") + div(ng-if="analysis.analysis !== 'wordcloudop' && analysis.analysis !== 'nlp-sentiment'") h3 Hold tight. Visualizations for this analysis will be coming later this year! img(src="img/soon.png") From 9c66cc69bd6673dfb4cb29b1568a522145abea21 Mon Sep 17 00:00:00 2001 From: jmp3833 Date: Fri, 4 Mar 2016 09:55:13 -0500 Subject: [PATCH 7/8] Add deps_json to part of speech tagging visualization --- assets/js/analysis/show.controller.js | 7 +++++-- views/templates/analysis/show.jade | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/assets/js/analysis/show.controller.js b/assets/js/analysis/show.controller.js index 216cca0..e0aec6a 100644 --- a/assets/js/analysis/show.controller.js +++ b/assets/js/analysis/show.controller.js @@ -167,7 +167,10 @@ //Move this to a listener when supporting multiple sentences //#TODO: Make this not a single sentence - data = convertData($scope.results[0].sentiment_json); + + var dataToConvert = sentiment? $scope.results[0].sentiment_json : + $scope.results[0].deps_json; + data = convertData(dataToConvert); renderTree(); //Converts results from flat to heirarchical @@ -363,7 +366,7 @@ $scope.visualizeTfidf(); } else if ($scope.analysis.analysis == "wordcloudop") { $scope.visualizeWordcloud(); - } else if ($scope.analysis.analysis == "nlp-parse"){ + } else if ($scope.analysis.analysis == "nlp-pos"){ $scope.visualizeParseTree(false); } else if ($scope.analysis.analysis == "nlp-sentiment"){ $scope.visualizeParseTree(true); diff --git a/views/templates/analysis/show.jade b/views/templates/analysis/show.jade index 1f7f610..1ba7bd2 100644 --- a/views/templates/analysis/show.jade +++ b/views/templates/analysis/show.jade @@ -13,7 +13,8 @@ tabset(justified='true') tab(heading='Visualization') #graph - div(ng-if="analysis.analysis !== 'wordcloudop' && analysis.analysis !== 'nlp-sentiment'") + div(ng-if="analysis.analysis !== 'wordcloudop' && analysis.analysis !== 'nlp-sentiment' && analysis.analysis !== 'nlp-pos'") + h3 Hold tight. Visualizations for this analysis will be coming later this year! img(src="img/soon.png") From 296aacd529eb31d0a3e5c69e11dc70f5f544f31f Mon Sep 17 00:00:00 2001 From: jmp3833 Date: Fri, 4 Mar 2016 16:05:09 -0500 Subject: [PATCH 8/8] shrink them lines --- assets/js/index.controller.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/js/index.controller.js b/assets/js/index.controller.js index 2c0d3bb..6d692f3 100644 --- a/assets/js/index.controller.js +++ b/assets/js/index.controller.js @@ -32,7 +32,8 @@ frequency: 10 }] - var fill = d3.scale.ordinal().range(["#ff7f0e","aec7e8","#ffbb78","#2ca02c","#ff9896","#9467bd","#17becf","#d62728","#d62728"]); + var fill = d3.scale.ordinal().range(["#ff7f0e","aec7e8","#ffbb78", + "#2ca02c","#ff9896","#9467bd","#17becf","#d62728","#d62728"]); d3.layout.cloud().size([400, 400]) .words(words)