Dashboard line chart color

Does anyone know if I can change the color of a line based on the number received? For example I have a line chart that goes above and below 0. When it goes below 0 I want it to turn green, when it goes above 0 I want it to turn red.

I tried using a topic to only send and it is above or below 0 but when the graph won't leave a gap between points.

It is not possible to change the line color on fly but you must draw two lines and make gaps by sending payload null where gaps needed. A bit hacking way but something like this:

[{"id":"85de7d2a.d10f5","type":"ui_slider","z":"d65d7a10.498788","name":"","label":"slider","tooltip":"","group":"a4448716.200ac8","order":2,"width":0,"height":0,"passthru":true,"outs":"all","topic":"","min":"-5","max":10,"step":"0.1","x":260,"y":500,"wires":[["d58bdaf1.d93048"]]},{"id":"d58bdaf1.d93048","type":"function","z":"d65d7a10.498788","name":"","func":"var last = context.get('last') || 'under'\nvar undermessage = {topic:'under',payload:null}\nvar overmessage = {topic:'over',payload:null}\n\nif(msg.payload > 0){\n    if(last == 'under'){\n        undermessage.payload = msg.payload\n    }\n   overmessage.payload = msg.payload\n   last = 'over'\n}\nelse{\n    if(last == 'over'){\n        overmessage.payload = msg.payload\n    }\n    undermessage.payload = msg.payload\n    last = 'under'\n}\ncontext.set('last',last)\n\nreturn [[overmessage,undermessage]]","outputs":1,"noerr":0,"x":430,"y":500,"wires":[["277cf5b5.1c633a"]]},{"id":"277cf5b5.1c633a","type":"ui_chart","z":"d65d7a10.498788","name":"","group":"a4448716.200ac8","order":2,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"-5","ymax":"10","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f77b4","#ff0000","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":600,"y":500,"wires":[[]]},{"id":"125535f9.c93eca","type":"inject","z":"d65d7a10.498788","name":"","topic":"","payload":"[]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":430,"y":560,"wires":[["277cf5b5.1c633a"]]},{"id":"a4448716.200ac8","type":"ui_group","z":"","name":"LEVEL","tab":"6e01408.cda5dc","order":1,"disp":true,"width":"8","collapse":false},{"id":"6e01408.cda5dc","type":"ui_tab","z":"","name":"Home","icon":"track_changes","order":1,"disabled":false,"hidden":false}]

This is no full solution. Colors don't change always at your desired value
To get the thing working more precisely you'll probably need to send intermediate message for both lines with payload = your desired threshold value at the moment where threshold value is crossed.

EDIT:
I did some experiments to achieve better threshold crossing behavior and may be simplest way is to send threshold value for both topics and in addition send the original payload with slight delay back to function

image

[{"id":"85de7d2a.d10f5","type":"ui_slider","z":"d65d7a10.498788","name":"","label":"slider","tooltip":"","group":"a4448716.200ac8","order":2,"width":0,"height":0,"passthru":true,"outs":"all","topic":"","min":"-5","max":10,"step":"0.1","x":260,"y":500,"wires":[["d58bdaf1.d93048"]]},{"id":"d58bdaf1.d93048","type":"function","z":"d65d7a10.498788","name":"","func":"var last = context.get('last') || 'under'\nvar undermessage = {topic:'under',payload:null}\nvar overmessage = {topic:'over',payload:null}\nvar unsent = null\n\nif(msg.payload > 0){\n    if(last == 'under'){\n        undermessage.payload = 0\n        overmessage.payload = 0\n        unsent = msg\n    }\n    else{\n        overmessage.payload = msg.payload\n    }\n    last = 'over'\n}\nelse{\n    if(last == 'over'){\n        overmessage.payload = 0\n        undermessage.payload = 0\n        unsent = msg\n    }\n    else{\n        undermessage.payload = msg.payload\n    }\n    last = 'under'\n}\ncontext.set('last',last)\n\nreturn [[overmessage,undermessage],unsent]","outputs":2,"noerr":0,"x":430,"y":500,"wires":[["277cf5b5.1c633a"],["3679a19c.ac113e"]]},{"id":"277cf5b5.1c633a","type":"ui_chart","z":"d65d7a10.498788","name":"","group":"a4448716.200ac8","order":2,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"-5","ymax":"10","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f77b4","#ff0000","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":600,"y":500,"wires":[[]]},{"id":"125535f9.c93eca","type":"inject","z":"d65d7a10.498788","name":"","topic":"","payload":"[]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":450,"y":440,"wires":[["277cf5b5.1c633a"]]},{"id":"3679a19c.ac113e","type":"delay","z":"d65d7a10.498788","name":"","pauseType":"delay","timeout":"20","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":440,"y":580,"wires":[["d58bdaf1.d93048"]]},{"id":"a4448716.200ac8","type":"ui_group","z":"","name":"LEVEL","tab":"6e01408.cda5dc","order":1,"disp":true,"width":"8","collapse":false},{"id":"6e01408.cda5dc","type":"ui_tab","z":"","name":"Home","icon":"track_changes","order":1,"disabled":false,"hidden":false}]
2 Likes

Neat solution @hotnipi - worth putting on flows.nodered.org ?

Well for delay, if chart gets too many points in too short time frame it may cause some issues (rendering/performance) and this way it's kind of slightly prevented but of course, should work without delay also.

Edit: I see you removed the delay part ... but I leave my explanation anyway

For sharing, I think the docs/tutorial section should have dashboard section with such How To examples. There is many of such "not easy to find by just digging in documents and searching in forum" solutions and tricks for dashboard items. Gauge dynamic limits and look, Different icons (with dynamic color) in text widget, chart manipulations ... They come up time to time here in forum but every time different title and different wordings to ask basically same questions. And the forum search kind of works but only if you know how or what to search.

But for today and for community as always - sharing is our best friend :slight_smile:

Multicolor line with Dashboard Chart

Yes, a proper Dashboard introduction, examples, how-to docs has been on the to-do list for ever - By all means some pages as PR to the project would be a start and we can then link them from the README etc.

There is a flow for this already https://flows.nodered.org/flow/a78ac10821112eb07fb8be8957a9f7cb

I just discovered that too. And it is good to have them both as they do different things in different situations. :slight_smile:

[{"id":"d35fa016.a4e3c","type":"ui_slider","z":"7f6628bb.1a7bf8","name":"","label":"slider","tooltip":"","group":"e4b30ae.0ac5bf8","order":2,"width":0,"height":0,"passthru":true,"outs":"end","topic":"","min":"-1","max":"1","step":".1","x":630,"y":340,"wires":[["50b7ee76.5dc9b","540de43f.8b3b9c"]]},{"id":"532be957.f796b8","type":"ui_chart","z":"7f6628bb.1a7bf8","name":"threshold driven","group":"e4b30ae.0ac5bf8","order":2,"width":0,"height":0,"label":"threshold driven","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"-1","ymax":"1","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f77b4","#0df2be","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":1120,"y":380,"wires":[[]]},{"id":"63536e37.f08b3","type":"inject","z":"7f6628bb.1a7bf8","name":"Clear chart","topic":"","payload":"[]","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":920,"y":400,"wires":[["532be957.f796b8","bfdfa914.10fab8"]]},{"id":"e388eda7.fd5cd","type":"function","z":"7f6628bb.1a7bf8","name":"Sin","func":"msg.payload = Math.sin(msg.payload/4000)\nreturn msg;","outputs":1,"noerr":0,"x":630,"y":460,"wires":[["50b7ee76.5dc9b","540de43f.8b3b9c"]]},{"id":"d5bf32aa.f423a","type":"inject","z":"7f6628bb.1a7bf8","name":"0.5 sec timestamp","topic":"","payload":"","payloadType":"date","repeat":"0.5","crontab":"","once":false,"onceDelay":0.1,"x":650,"y":520,"wires":[["e388eda7.fd5cd"]]},{"id":"bfdfa914.10fab8","type":"ui_chart","z":"7f6628bb.1a7bf8","name":"occurrence driven","group":"e4b30ae.0ac5bf8","order":0,"width":0,"height":0,"label":"occurrence driven","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":1120,"y":420,"wires":[[]]},{"id":"50b7ee76.5dc9b","type":"function","z":"7f6628bb.1a7bf8","name":"change by occurrence","func":"let threshold = 0.5\nlet lowTopic = \"low\"\nlet highTopic = \"high\"\nlet thisTopic;\nlet totherTopic\nif (msg.payload > threshold) {\n    thisTopic = highTopic\n    totherTopic = lowTopic\n} else {\n    thisTopic = lowTopic\n    totherTopic = highTopic\n}\nlet lastTopic = context.get('last') || thisTopic\nlet msg2 = null\nif (thisTopic != lastTopic) {\n    // just crossed the threshold, send to both lines\n    msg.topic = lastTopic\n    msg2 = {payload: msg.payload, topic: thisTopic}\n} else {\n    msg.topic = thisTopic\n    msg2 = {payload: null, topic: totherTopic} // leave payload null to stop the line\n}\ncontext.set('last', thisTopic)\nreturn [[msg, msg2]];","outputs":1,"noerr":0,"x":890,"y":460,"wires":[["bfdfa914.10fab8"]]},{"id":"540de43f.8b3b9c","type":"function","z":"7f6628bb.1a7bf8","name":"change by threshold","func":"var last = context.get('last') || 'under'\nvar threshold = 0.5\nvar undermessage = {topic:'under',payload:null}\nvar overmessage = {topic:'over',payload:null}\nvar unsentmessage = null\n\nif(msg.payload > threshold){\n    if(last == 'under'){\n        undermessage.payload = threshold\n        overmessage.payload = threshold\n        unsentmessage = msg\n    }\n    else{\n        overmessage.payload = msg.payload\n    }\n    last = 'over'\n}\nelse{\n    if(last == 'over'){\n        overmessage.payload = threshold\n        undermessage.payload = threshold\n        unsentmessage = msg\n    }\n    else{\n        undermessage.payload = msg.payload\n    }\n    last = 'under'\n}\ncontext.set('last',last)\n\nreturn [unsentmessage,[overmessage,undermessage]]","outputs":2,"noerr":0,"x":890,"y":340,"wires":[["7a0695bc.6dfb7c"],["532be957.f796b8"]]},{"id":"7a0695bc.6dfb7c","type":"delay","z":"7f6628bb.1a7bf8","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":900,"y":280,"wires":[["540de43f.8b3b9c"]]},{"id":"e4b30ae.0ac5bf8","type":"ui_group","z":"","name":"LEVEL","tab":"d628dd08.bd0b5","order":1,"disp":true,"width":"8","collapse":false},{"id":"d628dd08.bd0b5","type":"ui_tab","z":"","name":"Home","icon":"track_changes","order":1,"disabled":false,"hidden":false}]
1 Like

Since I do but have access to my computer, which is which?

Lower is yours. And sure you'll need to try to see why and when the difference reveals pros and cons of each solution.

1 Like

Well this thread had lots of replies while I was away. Thanks everyone for the examples.

Can Anyone help how to make it 3 color chart. Like with specification limits - below zero red, above 3.75 yellow & in-between blue. I was trying myself but couldn't do it.

image

The same technique as for the two colour chart should do it, but with three lines obviously. Get it going with two colours first.

Sorry, I have extremely poor coding skills. :sob: . Can you guide me?

Have you got it working with two colours as in the example posted?

Yes. It already was as I only injected the payload & changed the threshold value.

Sorry, I don't understand. Do you have a flow working showing two colours? If so please post that flow so we can see exactly what you have. Just the chart node and the nodes feeding it.

check below flow

[{"id":"e301feb7.9dcda","type":"ui_template","z":"bc794abe.7829c8","group":"65dfd687.bc39a8","name":"temperature","order":1,"width":8,"height":3,"format":"<div id=\"{{'my_'+$id}}\">Machine status:</div>\n<script>\n(function(scope) {\n  scope.$watch('msg', function(msg) {\n    if (msg) {\n      // Do something when msg arrives\n      $(\"#my_\"+scope.$id).html(msg.payload);\n      $(\"#my_\"+scope.$id).closest(\"md-card\").css(\"background\",msg.background)\n      \n    }\n  });\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","x":990,"y":420,"wires":[[]]},{"id":"276d7dcc.a2f022","type":"template","z":"bc794abe.7829c8","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<p style=\"color:white;font-family:arial;text-align:center\">\n    <b>Melting Furnace Striko 1.2 Ton (Tower)\n    <div style=\"color:white;font-family:arial;text-align:center;font-size:200%\">Temperature</div>\n    <div style=\"color:white;font-family:arial;text-align:center;font-size:300%\">{{payload}}°C</div>\n    </b>\n</p>","output":"str","x":820,"y":420,"wires":[["e301feb7.9dcda"]]},{"id":"d9bfb672.382128","type":"switch","z":"bc794abe.7829c8","name":"","property":"payload","propertyType":"msg","rules":[{"t":"lt","v":"400","vt":"str"},{"t":"btwn","v":"400","vt":"num","v2":"600","v2t":"num"},{"t":"gt","v":"600","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":510,"y":420,"wires":[["ae03ebe8.e40e68"],["b63d1759.e15288"],["e2b2dd09.f9897"]]},{"id":"ce56d523.fdf078","type":"random","z":"bc794abe.7829c8","name":"","low":"0","high":"800","inte":"true","property":"payload","x":380,"y":420,"wires":[["d9bfb672.382128","8911b5dd.dc2808"]]},{"id":"fcf3c6aa.aa0238","type":"inject","z":"bc794abe.7829c8","name":"","props":[{"p":"payload"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":190,"y":420,"wires":[["ce56d523.fdf078","543b55e5.6dd26c","fa172037.0cd33"]]},{"id":"ae03ebe8.e40e68","type":"change","z":"bc794abe.7829c8","name":"Red","rules":[{"t":"set","p":"background","pt":"msg","to":"#ff0000","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":380,"wires":[["276d7dcc.a2f022"]]},{"id":"e2b2dd09.f9897","type":"change","z":"bc794abe.7829c8","name":"Yellow","rules":[{"t":"set","p":"background","pt":"msg","to":"#d6b911","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":460,"wires":[["276d7dcc.a2f022"]]},{"id":"b63d1759.e15288","type":"change","z":"bc794abe.7829c8","name":"Green","rules":[{"t":"set","p":"background","pt":"msg","to":"#00cc00","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":420,"wires":[["276d7dcc.a2f022"]]},{"id":"63a8b4ad.099d1c","type":"ui_chart","z":"bc794abe.7829c8","name":"Temperature","group":"65dfd687.bc39a8","order":4,"width":8,"height":5,"label":"Furnace Tower <div><strong>Temperature Chart</strong></div>","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#00cc00","#ff0000","#ee00ff","#eeff00","#0300cc","#28d76b","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"x":1410,"y":360,"wires":[[]]},{"id":"2d166fac.2df","type":"delay","z":"bc794abe.7829c8","name":"","pauseType":"delay","timeout":"20","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":1190,"y":420,"wires":[["8911b5dd.dc2808"]]},{"id":"8911b5dd.dc2808","type":"function","z":"bc794abe.7829c8","name":"prepare","func":"var last = context.get('last') || 'under'\nvar threshold = 600\nvar undermessage = {topic:'under',payload:null}\nvar overmessage = {topic:'over',payload:null}\nvar unsentmessage = null\n\nif(msg.payload > threshold){\n    if(last == 'under'){\n        undermessage.payload = threshold\n        overmessage.payload = threshold\n        unsentmessage = msg\n    }\n    else{\n        overmessage.payload = msg.payload\n    }\n    last = 'over'\n}\nelse{\n    if(last == 'over'){\n        overmessage.payload = threshold\n        undermessage.payload = threshold\n        unsentmessage = msg\n    }\n    else{\n        undermessage.payload = msg.payload\n    }\n    last = 'under'\n}\ncontext.set('last',last)\n\nreturn [[overmessage,undermessage],unsentmessage]","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1180,"y":360,"wires":[["63a8b4ad.099d1c"],["2d166fac.2df"]]},{"id":"65dfd687.bc39a8","type":"ui_group","name":"tower","tab":"8d457c5d.9a444","order":2,"disp":false,"width":24,"collapse":false},{"id":"8d457c5d.9a444","type":"ui_tab","name":"Melting Furnace Striko 1.2 Ton (Tower)","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

@sahsha your line chart portion looks exactly like the one from @hotNipi posted above.

Well, anyhow... I took a stab at a triple zone... but my mind blanked out somewhere along the line... and all I have is this hot mess :woozy_face:

[{"id":"ce56d523.fdf078","type":"random","z":"d6e12d45cb64fb57","name":"","low":"1","high":"100","inte":"false","property":"payload","x":380,"y":120,"wires":[["8911b5dd.dc2808"]]},{"id":"fcf3c6aa.aa0238","type":"inject","z":"d6e12d45cb64fb57","name":"","props":[{"p":"payload"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":210,"y":120,"wires":[["ce56d523.fdf078"]]},{"id":"63a8b4ad.099d1c","type":"ui_chart","z":"d6e12d45cb64fb57","name":"Temperature","group":"fd1405884c58884d","order":1,"width":8,"height":5,"label":"Temperature Chart","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"1","ymax":"100","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#ff0000","#eeff00","#00ff00","#ff00ff","#0300cc","#28d76b","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"x":730,"y":120,"wires":[[]]},{"id":"2d166fac.2df","type":"delay","z":"d6e12d45cb64fb57","name":"","pauseType":"delay","timeout":"20","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":550,"y":180,"wires":[["8911b5dd.dc2808"]]},{"id":"8911b5dd.dc2808","type":"function","z":"d6e12d45cb64fb57","name":"prepare","func":"var last = context.get('last') || 'under'\nvar threshold = 24.75\nvar threshold2 = 74.25\nvar undermessage = {topic:'under',payload:null}\nvar midmessage = {topic:'mid',payload:null}\nvar overmessage = {topic:'over',payload:null}\nvar unsentmessage = null\n\nif (msg.payload > threshold && msg.payload < threshold2) {\n    if (last == 'under') {\n        undermessage.payload = threshold\n        midmessage.payload = threshold\n        overmessage.payload = threshold\n        unsentmessage = msg\n    } else {\n        midmessage.payload = msg.payload\n    }\n    last = 'over'\n} else if (msg.payload > threshold2){\n    if (last == 'over') {\n        overmessage.payload = threshold\n        midmessage.payload = threshold\n        undermessage.payload = threshold\n        unsentmessage = msg\n    } else {\n        overmessage.payload = msg.payload\n    }\n    last = 'under'\n} else {\n    if (last == 'over') {\n        overmessage.payload = threshold\n        midmessage.payload = threshold\n        undermessage.payload = threshold\n        unsentmessage = msg\n    } else {\n        undermessage.payload = msg.payload\n    }\n    last = 'mid'\ncontext.set('last',last)\n}\nreturn [[overmessage,midmessage,undermessage],unsentmessage]","outputs":3,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":120,"wires":[["63a8b4ad.099d1c"],["63a8b4ad.099d1c"],["2d166fac.2df","63a8b4ad.099d1c"]]},{"id":"fd1405884c58884d","type":"ui_group","name":"Linechart","tab":"1bd622c73f6a0a87","order":1,"disp":true,"width":"6","collapse":false},{"id":"1bd622c73f6a0a87","type":"ui_tab","name":"Tripple","icon":"Line Chart","disabled":false,"hidden":false}]

@Gunner Similar case happened with me and more over my browser slowed down. So had to delete the edited function node to correct.

I see you have not based your flow on the one I posted, which was Dashboard chart - change line colour dependent on value (flow) - Node-RED (which I am the author of).