I've been playing with Plotly for a few days, and have received a lot of kind support from @bakman2, so would like to share what I've got so far, in case anyone else is interested.
The complete flow as attached below.
The usual way to install a 3rd party script/library is to create a static folder, install & run the script/library from there. However, in these examples there is no need to do this, as plotly.js is being loaded using a CDN and a ui-template
node.
In all 3 examples, the chart data is formed from an object of arrays, comprising of the x & y data values, such as {"x":["Saturday","Sunday","Monday"],"y":["58.6","65.7","43"]}
.
For the chart to fill the dashboard element size, data must to be injected into the chart, otherwise the chart will be collapsed.
Example 1 is a simple static line chart, in which I've disabled interactivity (incl zoom & pan) to make it easier use on a phone. To do this, I added { displayModeBar: false }, { staticPlot: true }, { displaylogo: false }
to the Plotly.newPlot
command.
Example 2 has been structured to be a Bar chart, by adding type: 'bar',
to the data
section. Again, this is also a static chart.
Example 3 is an interactive chart, which has a modal toolbar top right, to zoom, pan, change the scaling etc. (it can also be 'pinched' & 'double tapped' on a phone/tablet)
I've also introduced an additional datasource - windspeed
& windgusts
, and placed them on 2 different axis (left & right).
Finally, I've formatted the left axis data to be a Bar chart. whilst the right axis data is a dashed line.
If you look through the respective ui_template
node's code, you can see what I've added/removed to change the layouts, to build up how the data is presented.
To find out more about the plethora of layout functions, have a look at plotly.com.
(Not wishing to insult your intelligence... but) I found the easiest way to shortcut the very lengthy plotly documentation (which covers both javascript & Python) is to simply google search, prefacing the search with plotly javascript
, so for example plotly javascript bar chart
.
[{"id":"5e0d9a67.116c84","type":"ui_template","z":"a444a9ff.e7a408","group":"2e16cb22.999174","name":"Load Plotly CDN","order":17,"width":0,"height":0,"format":"<script src=\"https://cdn.plot.ly/plotly-latest.min.js\"></script>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"global","x":580,"y":3120,"wires":[[]]},{"id":"1ca80c56.a7c7d4","type":"comment","z":"a444a9ff.e7a408","name":"Plotly example flows","info":"","x":150,"y":3120,"wires":[]},{"id":"c5db9e69.e34e5","type":"inject","z":"a444a9ff.e7a408","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"","payloadType":"str","x":130,"y":3200,"wires":[["a230896e.9204c8"]]},{"id":"a230896e.9204c8","type":"change","z":"a444a9ff.e7a408","name":"World temperatures - bar chart","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"x\":[\"London\",\"Canberra\",\"Paris\",\"Vienna\",\"Dhaka\",\"Brussels\",\"Sofia\",\"Ottawa\"],\"y\":[\"58.6\",\"65.7\",\"43\",\"48\",\"73.4\",\"53.5\",\"67.1\",\"38.9\"]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":3200,"wires":[["75a92564.21e79c"]]},{"id":"75a92564.21e79c","type":"ui_template","z":"a444a9ff.e7a408","group":"6aa20356.9b59bc","name":"Example 2","order":2,"width":16,"height":8,"format":"<div id=\"example2\"></div>\n<script>\n\n// Initialize chart\nvar data = [{x:[0],y:[0]}];\nvar layout = {\n title:'Awaiting data',\n };\nPlotly.newPlot('example2', data, layout);\n\n// Update data & layout\n(function(scope) {\n scope.$watch('msg', function(msg) {\n if (msg) {\n \n var data = [{\n x:msg.payload.x,\n y:msg.payload.y,\n type: 'bar',\n connectgaps: true\n }];\n \n var layout = {\n title: \"World Temperatures (2)\",\n titlefont: {\n size: 22,\n },\n autosize: true,\n plot_bgcolor: '#ffffff',\n paper_bgcolor: '#ffffff',\n 'xaxis': {\n title: 'Location',\n fixedrange: true\n },\n 'yaxis': {\n title: 'Temperature °F',\n fixedrange: true\n }\n };\n\n Plotly.newPlot('example2', data, layout, { displayModeBar: false }, { staticPlot: true }, { displaylogo: false },)\n }\n });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":600,"y":3200,"wires":[[]]},{"id":"10ba8dc7.179372","type":"change","z":"a444a9ff.e7a408","name":"wind/gusts twin axis line chart","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"wind\":[\"20.2\",\"19.1\",\"15.0\",\"12.9\",\"9.8\",\"7.6\",\"6.5\",\"6.4\",\"6.2\",\"6.1\",\"6.0\",\"5.8\",\"5.7\",\"8.6\",\"12.5\",\"18.5\",\"24.5\",\"27.5\",\"28.5\",\"28\"],\"gust\":[\"27.3\",\"24.4\",\"22.5\",\"18.4\",\"17.4\",\"15.3\",\"13.2\",\"11.2\",\"9.1\",\"8.0\",\"8.0\",\"11.9\",\"13.8\",\"15.8\",\"17.7\",\"20.6\",\"24.5\",\"28.4\",\"30.3\",\"31.2\"],\"time\":[\"2020-07-24 16:49:29\",\"2020-07-24 16:59:29\",\"2020-07-24 17:09:29\",\"2020-07-24 17:19:29\",\"2020-07-24 17:29:29\",\"2020-07-24 17:39:29\",\"2020-07-24 17:49:29\",\"2020-07-24 17:59:29\",\"2020-07-24 18:09:29\",\"2020-07-24 18:19:29\",\"2020-07-24 18:29:29\",\"2020-07-24 18:39:29\",\"2020-07-24 18:49:29\",\"2020-07-24 18:59:29\",\"2020-07-24 19:09:29\",\"2020-07-24 19:19:29\",\"2020-07-24 19:29:29\",\"2020-07-24 19:39:29\",\"2020-07-24 19:49:29\",\"2020-07-24 19:59:29\"]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":3240,"wires":[["15fd89a9.5f48a6"]]},{"id":"32886b1c.7c3c64","type":"inject","z":"a444a9ff.e7a408","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"","payloadType":"str","x":130,"y":3240,"wires":[["10ba8dc7.179372"]]},{"id":"66e905d7.65d2bc","type":"inject","z":"a444a9ff.e7a408","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"","payloadType":"str","x":130,"y":3160,"wires":[["324422cd.18882e"]]},{"id":"324422cd.18882e","type":"change","z":"a444a9ff.e7a408","name":"UK Temperature - line chart","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"x\":[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"],\"y\":[\"4.6\",\"4.9\",\"9.3\",\"14.2\",\"17.4\",\"19.3\",\"20.8\",\"21.6\",\"19.2\",\"14.3\",\"9.8\",\"6.3\"]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":3160,"wires":[["2e5762f6.c687fe"]]},{"id":"2e5762f6.c687fe","type":"ui_template","z":"a444a9ff.e7a408","group":"6aa20356.9b59bc","name":"Example 1","order":1,"width":16,"height":8,"format":"<div id=\"example1\"></div>\n<script>\n\n// Initialize chart\nvar data = [{x:[0],y:[0]}];\nvar layout = {\n title:'Awaiting data',\n };\nPlotly.newPlot('example1', data, layout);\n\n// Update data & layout\n(function(scope) {\n scope.$watch('msg', function(msg) {\n if (msg) {\n \n var data = [{\n x:msg.payload.x,\n y:msg.payload.y,\n connectgaps: true\n }];\n\n var layout = {\n title: \"Monthly UK Temperatures (1)\",\n titlefont: {\n size: 22,\n },\n autosize: true,\n plot_bgcolor: '#ffffff',\n paper_bgcolor: '#ffffff',\n 'xaxis': {\n title: 'Month',\n fixedrange: true\n },\n 'yaxis': {\n title: 'Average Temperature °C',\n mode: 'lines',\n fixedrange: true\n }\n };\n\n Plotly.newPlot('example1', data, layout, { displayModeBar: false }, { staticPlot: true }, { displaylogo: false },)\n }\n });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":600,"y":3160,"wires":[[]]},{"id":"15fd89a9.5f48a6","type":"ui_template","z":"a444a9ff.e7a408","group":"6aa20356.9b59bc","name":"Example 3","order":3,"width":16,"height":8,"format":"<div id=\"example3\"></div>\n<script>\n\n// Initialize chart\nvar layout = {\n title:'Awaiting data',\n };\nvar data = [{x:[0],y:[0]}];\nPlotly.newPlot('example3', data, layout);\n\n// Update data & layout\n(function(scope) {\n scope.$watch('msg', function(msg) {\n if (msg) {\n \n var winddata = {\n x:msg.payload.time,\n y:msg.payload.wind,\n name: 'wind-speed',\n type: 'bar',\n marker: {\n color: '#8080ff',\n opacity: 0.7,\n line: {\n color: '#0033cc',\n width: 1.5\n }\n },\n connectgaps: true\n };\n \n var gustdata = {\n x:msg.payload.time,\n y:msg.payload.gust,\n name: 'wind-gust',\n mode: 'lines',\n line: {\n dash: 'dashdot',\n color: '#ff0000'\n },\n yaxis: 'y2',\n connectgaps: true\n };\n\nvar data = [gustdata,winddata];\n\n var layout = {\n title: 'Windspeed & Gust data (3)',\n titlefont: {\n size: 22,\n },\n showlegend: false,\n plot_bgcolor: '#ffffff',\n paper_bgcolor: '#ffffff',\n 'yaxis': {\n title: 'Windspeed mph',\n range: [0, 35],\n color: '#0000ff'\n },\n 'yaxis2': {\n title: 'WindGusts mph',\n range: [0, 35],\n color: '#ff0000',\n overlaying: 'y',\n side: 'right'\n },\n 'xaxis': {\n title: 'Time recorded',\n 'tickformat': '%X'\n }\n };\n\n console.log(data,layout)\n Plotly.newPlot('example3', data, layout, { modeBarButtonsToRemove: ['toImage','toggleSpikelines'], displaylogo: false})\n };\n });\n})(scope);\n</script>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":600,"y":3240,"wires":[[]]},{"id":"2e16cb22.999174","type":"ui_group","z":"","name":"Chart","tab":"567d8fae.98148","order":1,"disp":false,"width":"10","collapse":false},{"id":"6aa20356.9b59bc","type":"ui_group","z":"","name":"examples","tab":"d5ad8b85.f5ba18","order":1,"disp":true,"width":16,"collapse":false},{"id":"567d8fae.98148","type":"ui_tab","z":"","name":"Realtime Power","icon":"dashboard","order":1,"disabled":false,"hidden":false},{"id":"d5ad8b85.f5ba18","type":"ui_tab","z":"","name":"Plotly","icon":"dashboard","disabled":false,"hidden":false}]
EDIT 27/7 - Improved initialization of chart