Twitter Sentiments D3 Display

This sample application demonstrates the use of twitter sentiment analysis and displays it on a d3 collapsible tree. To use: Connect a CloudantDB service to your node-red application, double click on the cloudant node and select the created service, set your database name. Connect your twitter account to your twitter node. Deploy application. Once deployed, wait for fews mins to have some twitter sentiments in the database, you can check your database to confirm existing data.

In your browser, run the /twittersentiments in your browser for results.

[{"id":"7827030f.4e41ec","type":"http in","z":"4d0c4142.50641","name":"","url":"/twittersentiments","method":"get","swaggerDoc":"","x":127,"y":165,"wires":[["7f49ecf1.382984"]]},{"id":"6cffddd3.2350a4","type":"http response","z":"4d0c4142.50641","name":"","x":742.5,"y":168,"wires":[]},{"id":"c96f63b1.a6f44","type":"twitter in","z":"4d0c4142.50641","twitter":"","tags":"","user":"true","name":"","topic":"tweets","x":89,"y":288,"wires":[["389355c4.aa267a"]]},{"id":"9888d330.500a7","type":"cloudant out","z":"4d0c4142.50641","name":"","cloudant":"","database":"","service":"","payonly":false,"operation":"insert","x":525.5,"y":271,"wires":[]},{"id":"389355c4.aa267a","type":"sentiment","z":"4d0c4142.50641","name":"","x":307.5,"y":275,"wires":[["9888d330.500a7"]]},{"id":"7bb4a7c0.758fd8","type":"template","z":"4d0c4142.50641","name":"HTML","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Title</title>\n    <style>\n        {{{payload.style}}}\n    </style>\n    <script src=\"https://d3js.org/d3.v3.min.js\"></script>\n\n    <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js\"></script>\n    <!-- Latest compiled and minified CSS -->\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u\" crossorigin=\"anonymous\">\n\n    <!-- Optional theme -->\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css\" integrity=\"sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp\" crossorigin=\"anonymous\">\n\n    <!-- Latest compiled and minified JavaScript -->\n    <script src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js\" integrity=\"sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa\" crossorigin=\"anonymous\"></script>\n</head>\n<body>\n    <header class=\"text-center\">\n        <h1>Twitter Sentiments</h1>\n        <h2>Sentiments on Users Post</h2>\n    </header>\n<div class=\"row\">\n<div class=\"col-md-12\">\n    <p id=\"test\" style=\"display: none;\">{{{payload.final_result}}}</p>\n<script>\nvar url  = window.location.host\n{{{ payload.script }}}\nd3Function()\n</script>\n</div>\n</div>\n</body>\n</html>","x":603.5,"y":167,"wires":[["6cffddd3.2350a4"]]},{"id":"c184a053.9fa9b","type":"template","z":"4d0c4142.50641","name":"CSS","field":"payload.style","fieldType":"msg","format":"css","syntax":"mustache","template":".node {\n    cursor: pointer;\n}\n\n.node circle {\n    fill: #fff;\n    stroke: steelblue;\n    stroke-width: 1.5px;\n}\n\n.node text {\n    font: 10px sans-serif;\n}\n\n.link {\n    fill: none;\n    stroke: #ccc;\n    stroke-width: 1.5px;\n}\n\nheader{\n    background-color: #1d1e1f;\n    color: white;\n    min-height: 200px;\n    padding-top: 50px;\n}\n","x":467.35711669921875,"y":164.28571319580078,"wires":[["7bb4a7c0.758fd8"]]},{"id":"7f49ecf1.382984","type":"template","z":"4d0c4142.50641","name":"JS","field":"payload.script","fieldType":"msg","format":"javascript","syntax":"mustache","template":"var d3Function = function d3Function() {\n\n        var margin = {top: 20, right: 120, bottom: 20, left: 120},\n            width = 960 - margin.right - margin.left,\n            height = 800 - margin.top - margin.bottom;\n\n        var i = 0,\n            duration = 750,\n            root;\n\n        var tree = d3.layout.tree()\n            .size([height, width]);\n\n        var diagonal = d3.svg.diagonal()\n            .projection(function (d) {\n                return [d.y, d.x];\n            });\n\n        var svg = d3.select(\"body\").append(\"svg\")\n            .attr(\"width\", width + margin.right + margin.left)\n            .attr(\"height\", height + margin.top + margin.bottom)\n            .append(\"g\")\n            .attr(\"transform\", \"translate(\" + margin.left + \",\" + margin.top + \")\");\n\n        // root = final_result;\n        // root.x0 = height / 2;\n        // root.y0 = 0;\n\n        // function collapse(d) {\n        //     if (d.children) {\n        //         d._children = d.children;\n        //         d._children.forEach(collapse);\n        //         d.children = null;\n        //     }\n        // }\n\n        // root.children.forEach(collapse);\n        // update(root, tree);\n        \n        d3.json(\"https://\"+url+\"/sentiments\", function(error, flare) {\n            if (error) throw error;\n\n            root = flare;\n            root.x0 = height / 2;\n            root.y0 = 0;\n\n            function collapse(d) {\n                if (d.children) {\n                    d._children = d.children;\n                    d._children.forEach(collapse);\n                    d.children = null;\n                }\n            }\n\n            root.children.forEach(collapse);\n            update(root);\n        });\n        \n        d3.select(self.frameElement).style(\"height\", \"800px\");\n\n        function update(source) {\n\n            // Compute the new tree layout.\n            var nodes = tree.nodes(root).reverse(),\n                links = tree.links(nodes);\n\n            // Normalize for fixed-depth.\n            nodes.forEach(function(d) { d.y = d.depth * 180; });\n\n            // Update the nodes…\n            var node = svg.selectAll(\"g.node\")\n                .data(nodes, function(d) { return d.id || (d.id = ++i); });\n\n            // Enter any new nodes at the parent's previous position.\n            var nodeEnter = node.enter().append(\"g\")\n                .attr(\"class\", \"node\")\n                .attr(\"transform\", function(d) { return \"translate(\" + source.y0 + \",\" + source.x0 + \")\"; })\n                .on(\"click\", click);\n\n            nodeEnter.append(\"circle\")\n                .attr(\"r\", 1e-6)\n                .style(\"fill\", function(d) { return d._children ? \"lightsteelblue\" : \"#fff\"; });\n\n            nodeEnter.append(\"text\")\n                .attr(\"x\", function(d) { return d.children || d._children ? -10 : 10; })\n                .attr(\"dy\", \".35em\")\n                .attr(\"text-anchor\", function(d) { return d.children || d._children ? \"end\" : \"start\"; })\n                .text(function(d) { return d.name; })\n                .style(\"fill-opacity\", 1e-6);\n\n            // Transition nodes to their new position.\n            var nodeUpdate = node.transition()\n                .duration(duration)\n                .attr(\"transform\", function(d) { return \"translate(\" + d.y + \",\" + d.x + \")\"; });\n\n            nodeUpdate.select(\"circle\")\n                .attr(\"r\", 4.5)\n                .style(\"fill\", function(d) { return d._children ? \"lightsteelblue\" : \"#fff\"; });\n\n            nodeUpdate.select(\"text\")\n                .style(\"fill-opacity\", 1);\n\n            // Transition exiting nodes to the parent's new position.\n            var nodeExit = node.exit().transition()\n                .duration(duration)\n                .attr(\"transform\", function(d) { return \"translate(\" + source.y + \",\" + source.x + \")\"; })\n                .remove();\n\n            nodeExit.select(\"circle\")\n                .attr(\"r\", 1e-6);\n\n            nodeExit.select(\"text\")\n                .style(\"fill-opacity\", 1e-6);\n\n            // Update the links…\n            var link = svg.selectAll(\"path.link\")\n                .data(links, function(d) { return d.target.id; });\n\n            // Enter any new links at the parent's previous position.\n            link.enter().insert(\"path\", \"g\")\n                .attr(\"class\", \"link\")\n                .attr(\"d\", function(d) {\n                    var o = {x: source.x0, y: source.y0};\n                    return diagonal({source: o, target: o});\n                });\n\n            // Transition links to their new position.\n            link.transition()\n                .duration(duration)\n                .attr(\"d\", diagonal);\n\n            // Transition exiting nodes to the parent's new position.\n            link.exit().transition()\n                .duration(duration)\n                .attr(\"d\", function(d) {\n                    var o = {x: source.x, y: source.y};\n                    return diagonal({source: o, target: o});\n                })\n                .remove();\n\n            // Stash the old positions for transition.\n            nodes.forEach(function(d) {\n                d.x0 = d.x;\n                d.y0 = d.y;\n            });\n        }\n\n\n        // Toggle children on click.\n        function click(d) {\n            if (d.children) {\n                d._children = d.children;\n                d.children = null;\n            } else {\n                d.children = d._children;\n                d._children = null;\n            }\n            update(d);\n        }\n};\n// d3Function();","x":314.21429443359375,"y":164.57142639160156,"wires":[["c184a053.9fa9b"]]},{"id":"253230ab.cb009","type":"http in","z":"4d0c4142.50641","name":"","url":"/sentiments","method":"get","swaggerDoc":"","x":96.42857360839844,"y":372.4285888671875,"wires":[["8d9c9bd3.61e858"]]},{"id":"8d9c9bd3.61e858","type":"cloudant in","z":"4d0c4142.50641","name":"","cloudant":"","database":"","service":"","search":"_all_","design":"","index":"","x":310.4999694824219,"y":370.5714416503906,"wires":[["39719f9b.ff37"]]},{"id":"39719f9b.ff37","type":"function","z":"4d0c4142.50641","name":"Convert","func":"var new_result = msg.payload;\nvar final_result = {};\nvar positive_sentiment = {};\nvar negative_sentiment = {};\npositive_sentiment[\"name\"] = \"Positive\";\nnegative_sentiment[\"name\"] = \"Negative\";\npositive_sentiment[\"children\"] = [];\nnegative_sentiment[\"children\"] = [];\nfor (var i in new_result) {\n    p_sentiment = new_result[i][\"sentiment\"][\"positive\"];\n    n_sentiment = new_result[i][\"sentiment\"][\"negative\"];\n\n    if (p_sentiment.length > 0){\n        user_sent_list = [];\n        user_sent = {};\n        user_sent[\"name\"] = new_result[i][\"topic\"];\n        user_sent[\"children\"] = [];\n        for (var value in p_sentiment) {\n            children = {};\n            children[\"name\"] = p_sentiment[value];\n            user_sent[\"children\"].push(children)\n        }\n        positive_sentiment[\"children\"].push(user_sent)\n    }\n\n\n    if (n_sentiment.length > 0) {\n        user_sent_list = [];\n        user_sent = {};\n        user_sent[\"name\"] = new_result[i][\"topic\"];\n        user_sent[\"children\"] = [];\n        for (value in n_sentiment) {\n            children = {};\n            children[\"name\"] = n_sentiment[value];\n            user_sent[\"children\"].push(children)\n        }\n        negative_sentiment[\"children\"].push(user_sent)\n    }\n}\n\nfinal_result[\"name\"] = \"Twitter Sentiments\";\nfinal_result[\"children\"] = [];\nfinal_result[\"children\"].push(positive_sentiment);\nfinal_result[\"children\"].push(negative_sentiment);\n\nmsg.payload = final_result\n\nreturn msg;","outputs":1,"noerr":0,"x":502.357177734375,"y":370.857177734375,"wires":[["1b162125.7ffa7f"]]},{"id":"1b162125.7ffa7f","type":"http response","z":"4d0c4142.50641","name":"","x":674.0714721679688,"y":371.5714111328125,"wires":[]}]
Abiwax

Flow Info

created 7 months, 1 week ago

Node Types

Core
  • function (x1)
  • http in (x2)
  • http response (x2)
  • sentiment (x1)
  • template (x3)
  • twitter in (x1)
Other

Tags

  • twitter
  • d3
  • cloudant
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option