Visual Sentiment Comparator

By this flow it is possible to compare the sentiments of twitter streams from two different topics/terms. There are calculated the average scores of the last 10 tweets for each term all the time and visualized in a line chart with an update each second. The terms can be changed over the UI also. Additionally there are displayed the top 10 and the worst 10 tweets scored so far for both terms.

[{"id":"ff2f8615.098e2","type":"twitter in","z":"558ac18.6e701c","twitter":"","tags":"","user":"false","name":"","topic":"tweets","inputs":1,"x":536.3333740234375,"y":368.7777099609375,"wires":[["ed08319.3d6fbd"]]},{"id":"a8c99683.05e568","type":"sentiment","z":"558ac18.6e701c","name":"","x":827.0001220703125,"y":375.44439697265625,"wires":[["5199662f.f92fd8","32c6bfbd.113668"]]},{"id":"bbd3b962.0ff068","type":"ui_chart","z":"558ac18.6e701c","name":"","group":"421cae4c.b21998","order":0,"width":"27","height":"9","label":"Dictionary Sentiment Scores","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"bezier","nodata":"","dot":false,"ymin":"-4","ymax":"4","removeOlder":"20","removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":735.8331909179688,"y":859.6112060546875,"wires":[[],[]]},{"id":"5199662f.f92fd8","type":"function","z":"558ac18.6e701c","name":"term1","func":"msg.term=\"term1\";\n\nreturn msg;","outputs":1,"noerr":0,"x":1125.6668090820312,"y":373.7777099609375,"wires":[["e410bff4.43721"]]},{"id":"457fd2df.52e584","type":"inject","z":"558ac18.6e701c","name":"","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"x":157.16665649414062,"y":925.9445190429688,"wires":[["cac2cd66.857368","73a7aa3c.ea129c","36829940.28eb86"]]},{"id":"cac2cd66.857368","type":"function","z":"558ac18.6e701c","name":"draw Term1 chart","func":"var term = global.get(\"term1\");\nif(typeof term !==\"undefined\"){\n    msg.payload = global.get(\"meanSentiment\"+term);\n    msg.topic = term;\n    return msg;\n}","outputs":1,"noerr":0,"x":546.1666564941406,"y":798.9445190429688,"wires":[["bbd3b962.0ff068"]]},{"id":"73a7aa3c.ea129c","type":"function","z":"558ac18.6e701c","name":"draw Term2 chart","func":"var term = global.get(\"term2\");\nif(typeof term !==\"undefined\"){\n    msg.payload = global.get(\"meanSentiment\"+term);\n    msg.topic = term;\n    return msg;\n}\n","outputs":1,"noerr":0,"x":542.1666564941406,"y":920.9445190429688,"wires":[["bbd3b962.0ff068"]]},{"id":"fb155085.6f9c68","type":"twitter in","z":"558ac18.6e701c","twitter":"","tags":"","user":"false","name":"","topic":"tweets","inputs":1,"x":535.3333740234375,"y":516.777717590332,"wires":[["9514363c.83a12"]]},{"id":"698286fa.f83d2","type":"ui_text_input","z":"558ac18.6e701c","name":"","label":"Term 2","group":"421cae4c.b21998","order":0,"width":0,"height":0,"passthru":false,"mode":"text","delay":"1000","topic":"","x":205.8333740234375,"y":474.5277404785156,"wires":[["18879738.e71339"]]},{"id":"2b12ec5b.b1ec8c","type":"ui_text_input","z":"558ac18.6e701c","name":"","label":"Term 1","group":"421cae4c.b21998","order":0,"width":0,"height":0,"passthru":false,"mode":"text","delay":"1000","topic":"","x":204.8333740234375,"y":399.7777099609375,"wires":[["142d2bb3.7623b4"]]},{"id":"142d2bb3.7623b4","type":"function","z":"558ac18.6e701c","name":"preprocess","func":"msg.term = msg.payload;\nvar term = msg.term.replace(\" \",\"_\").replace(/[\"']/g, \"\");\nnode.log(\"term is\"+term);\nglobal.set(\"term1\",term);\nreturn msg;","outputs":1,"noerr":0,"x":376.3333740234375,"y":369.77771759033203,"wires":[["ff2f8615.098e2"]]},{"id":"18879738.e71339","type":"function","z":"558ac18.6e701c","name":"preprocess","func":"msg.term = msg.payload;\nvar term = msg.term.replace(\" \",\"_\").replace(/[\"']/g, \"\");\nglobal.set(\"term2\",term);\nreturn msg;","outputs":1,"noerr":0,"x":371.3333740234375,"y":515.777717590332,"wires":[["fb155085.6f9c68"]]},{"id":"de0ca02d.2527c8","type":"sentiment","z":"558ac18.6e701c","name":"","x":819.33349609375,"y":522.1110534667969,"wires":[["df2968fa.a0a53","32c6bfbd.113668"]]},{"id":"df2968fa.a0a53","type":"function","z":"558ac18.6e701c","name":"term2","func":"msg.term=\"term2\";\n\nreturn msg;\n","outputs":1,"noerr":0,"x":1128.6666870117188,"y":520.4443664550781,"wires":[["e410bff4.43721"]]},{"id":"a89135c8.ce2fa8","type":"ui_button","z":"558ac18.6e701c","name":"","group":"421cae4c.b21998","order":0,"width":0,"height":0,"passthru":false,"label":"clear","color":"","bgcolor":"","icon":"","payload":"[]","payloadType":"json","topic":"","x":505.1665954589844,"y":860.9445190429688,"wires":[["bbd3b962.0ff068"]]},{"id":"4bb6800a.990ef8","type":"ui_text","z":"558ac18.6e701c","group":"b428221f.de387","order":0,"width":"24","height":"22","name":"","label":"Top 10 Samples","format":"{{msg.payload}}","layout":"col-center","x":747.1666564941406,"y":1007.9445190429688,"wires":[]},{"id":"36829940.28eb86","type":"function","z":"558ac18.6e701c","name":"print sample table","func":"function createTable(top10_1,flop10_1,top10_2,flop10_2){\n    \n    var table = \"<table style=\\\"width:100%;font-size:20px;\\\">\";\n    table+=\"<tr><th>Rank</th><th>Tweet</th><th>Score</th></tr>\";\n    \n    if(typeof top10_1!==\"undefined\"){\n        for(var i=0;i<top10_1.length;i++){\n            table+=\"<tr><td>\"+(i+1)+\"</td><td>\"+top10_1[i].text+\"</td><th>\"+top10_1[i].score+\"</td></tr>\";\n        }\n    }\n    table+=\"</table>\";\n    \n    table+=\"<p><br><br><table style=\\\"width:100%;font-size:20px;\\\">\";\n    table+=\"<tr><th>Rank</th><th>Tweet</th><th>Score</th></tr>\";\n    \n    if(typeof flop10_1!==\"undefined\"){\n        for(var n=0;n<flop10_1.length;n++){\n            table+=\"<tr><td>\"+(n+1)+\"</td><td>\"+flop10_1[n].text+\"</td><th>\"+flop10_1[n].score+\"</td></tr>\";\n        }\n    }\n    table+=\"</table>\";\n    \n    table+= \"<p><br><br><table style=\\\"width:100%;font-size:20px;\\\">\";\n    table+=\"<tr><th>Rank</th><th>Tweet</th><th>Score</th></tr>\";\n    if(typeof top10_2!==\"undefined\"){\n        for(var l=0;l<top10_2.length;l++){\n            table+=\"<tr><td>\"+(l+1)+\"</td><td>\"+top10_2[l].text+\"</td><th>\"+top10_2[l].score+\"</td></tr>\";\n        }\n    }\n    table+=\"</table>\";\n    \n    table+=\"<p><br><br><table style=\\\"width:100%;font-size:20px\\\">\";\n    table+=\"<tr><th>Rank</th><th>Tweet</th><th>Score</th></tr>\";\n    \n    if(typeof flop10_2!==\"undefined\"){\n        for(var k=0;k<flop10_2.length;k++){\n            table+=\"<tr><td>\"+(k+1)+\"</td><td>\"+flop10_2[k].text+\"</td><th>\"+flop10_2[k].score+\"</td></tr>\";\n        }\n    }\n    table+=\"</table>\";\n    \n    return table;\n}\nvar term1 = global.get(\"term1\");\nvar term2 = global.get(\"term2\");\nmsg.payload = createTable(global.get(\"top10\"+term1), global.get(\"flop10\"+term1),global.get(\"top10\"+term2), global.get(\"flop10\"+term2));\nreturn msg;","outputs":1,"noerr":0,"x":544.0831909179688,"y":1005.9445190429688,"wires":[["4bb6800a.990ef8"]]},{"id":"eea69e42.c5fcf8","type":"inject","z":"558ac18.6e701c","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"x":167.27777099609375,"y":1113.388951619466,"wires":[["19b180d9.33ae77"]]},{"id":"19b180d9.33ae77","type":"function","z":"558ac18.6e701c","name":"global functions","func":"function update10Function(){\n    return ((compare, name, msg)=>{\n        var ten = global.get(name);\n        if(typeof ten===\"undefined\"){\n            ten = [];\n            ten.push({\n                \"text\":msg.tweet.text,\n                \"score\":msg.sentiment.score\n            });\n            global.set(name,ten);\n            //node.log(JSON.stringify(ten));\n        }\n        else{\n            if(containsAlready(msg.tweet.text,ten)){\n                return;\n            }\n            var added = false;\n            //node.log(\"start defined: \"+JSON.stringify(ten));\n            for(var i=0;i<ten.length;i++){\n                if(compare(msg.sentiment.score,ten[i].score)){\n                    var entry = {\n                        \"text\":msg.tweet.text,\n                        \"score\":msg.sentiment.score\n                    };\n                    ten.splice(i, 0, entry);\n                    added=true;\n                    break;\n                }\n            }\n            if(added===false && ten.length<10){\n                ten.push({\n                    \"text\":msg.tweet.text,\n                    \"score\":msg.sentiment.score\n                });\n            }\n            ten.splice(10,ten.length-10);\n            node.log(\"end\"+JSON.stringify(ten));\n        }\n    });\n}\n\nfunction containsAlready(tweet, ten){\n    var prefix = tweet.substring(0,tweet.length/2);\n    return ten.map(e=>e.text).filter(e=>e.indexOf(prefix)>-1).length>0\n}\nglobal.set(\"update10\",update10Function());\nreturn msg;","outputs":1,"noerr":0,"x":397.27777099609375,"y":1115.6389770507812,"wires":[[]]},{"id":"cb43471d.a49f88","type":"inject","z":"558ac18.6e701c","name":"","topic":"","payload":"Microsoft","payloadType":"str","repeat":"","crontab":"","once":true,"x":139.20004272460938,"y":317.74440002441406,"wires":[["142d2bb3.7623b4","2b12ec5b.b1ec8c"]]},{"id":"3f0a858d.3b15b2","type":"inject","z":"558ac18.6e701c","name":"","topic":"","payload":"Uber","payloadType":"str","repeat":"","crontab":"","once":true,"x":152.66668701171875,"y":555.6110687255859,"wires":[["18879738.e71339","698286fa.f83d2"]]},{"id":"e410bff4.43721","type":"function","z":"558ac18.6e701c","name":"calculate average sentiment","func":"var term = global.get(msg.term);\nvar sampleSize = 10;\nvar sentiments = global.get(\"sentiments\"+term);\nif(typeof sentiments ===\"undefined\"){\n    sentiments =[];\n    global.set(\"sentiments\"+term,sentiments);\n}\nsentiments.push(msg.sentiment.score);\n\nif(sentiments.length>sampleSize){\n    sentiments.splice(0,sentiments.length-sampleSize);\n}\n\nvar sum = sentiments.reduce((e,r)=>e+r);\nglobal.set(\"meanSentiment\"+term,sum/sentiments.length);\n\nglobal.get(\"update10\")(((a,b)=>a>b),\"top10\"+term, msg);\nglobal.get(\"update10\")(((a,b)=>a<b),\"flop10\"+term, msg);\n\nmsg.payload = msg.sentiment.score;\n\n\nreturn msg;","outputs":1,"noerr":0,"x":1304.9501342773438,"y":444.0943298339844,"wires":[[]]},{"id":"eb2340c9.9326c","type":"comment","z":"558ac18.6e701c","name":"Inits the globally used functions once at startup","info":"","x":263.99999237060547,"y":1063.4237098693848,"wires":[]},{"id":"f53511.e32942f","type":"comment","z":"558ac18.6e701c","name":"Periodically triggers the drawing","info":"","x":190.24998474121094,"y":854.6737060546875,"wires":[]},{"id":"9884ec41.9ccdd","type":"comment","z":"558ac18.6e701c","name":"Calculates sentiment scores","info":"","x":176.9167022705078,"y":269.2568817138672,"wires":[]},{"id":"ed08319.3d6fbd","type":"function","z":"558ac18.6e701c","name":"filter","func":"var term = global.get(\"term1\");\nif(msg.payload.indexOf(term)!==-1 && msg.lang===\"en\"){\n    return msg;\n}\n","outputs":1,"noerr":0,"x":651.5000610351562,"y":309.4444122314453,"wires":[["a8c99683.05e568"]]},{"id":"9514363c.83a12","type":"function","z":"558ac18.6e701c","name":"filter","func":"var term = global.get(\"term2\");\nif(msg.payload.indexOf(term)!==-1 && msg.lang===\"en\"){\n    return msg;\n}\n","outputs":1,"noerr":0,"x":636.7500610351562,"y":605.111083984375,"wires":[["de0ca02d.2527c8"]]},{"id":"32c6bfbd.113668","type":"debug","z":"558ac18.6e701c","name":"","active":false,"console":"false","complete":"true","x":959.8215942382812,"y":446.6110534667969,"wires":[]},{"id":"421cae4c.b21998","type":"ui_group","z":"","name":"Compare Sentiments","tab":"2cd5a76b.109eb8","disp":true,"width":"27"},{"id":"b428221f.de387","type":"ui_group","z":"","name":"Samples","tab":"8f4da24a.0719b8","disp":true,"width":"24"},{"id":"2cd5a76b.109eb8","type":"ui_tab","z":"","name":"Sentiment","icon":"dashboard"},{"id":"8f4da24a.0719b8","type":"ui_tab","z":"","name":"Top Tweets","icon":"dashboard"}]
BennoBodensee

Flow Info

created 1 week, 2 days ago

Node Types

Core
  • comment (x3)
  • debug (x1)
  • function (x11)
  • inject (x4)
  • sentiment (x2)
  • twitter in (x2)
Other
  • ui_button (x1)
  • ui_chart (x1)
  • ui_group (x2)
  • ui_tab (x2)
  • ui_text (x1)
  • ui_text_input (x2)

Tags

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