Generate offline graph and save in PNG

Hi All,

I am looking for a way to generate a graph in the background and save it as a PNG or similar image format. I want to be able to request a graph in Telegram and have Node Red send the image of the generated graph back. So there will be no dashboard involved.

I have seen how I can use plotly to generate the file and also save in PNG. I even have a sample flow from the old Google Group but it relies on a ui_template to render the graph and save it which is not good for me.

Converting this example to a standalone js or py is way above my head. Has somebody done something similar before?


Hello Csongor, I've found myself in the same question. Did you find the solution to this?

If you are using node-red V1.3.x you can use functionexternalmodules


  1. Add requires for chart.js and canvas

  2. Enter code to generate a chart in the on message

Demo flow...

[{"id":"1b1e2516d420ad11","type":"function","z":"553814a2.1248ec","name":"","func":"\nconst createCanvas = Canvas.createCanvas;\nconst canvas = createCanvas(320, 320)\ = {\"background-color\": \"white\"};\nconst ctx = canvas.getContext('2d');\n\nvar myChart = new Chart(ctx, {\n    type: \"pie\",\n    data: {\n        labels: [\"Red\", \"Blue\", \"Yellow\", \"Green\", \"Purple\", \"Orange\"],\n        datasets: [\n            {\n                label: \"# of Votes\",\n                data: [12, 19, 3, 5, 2, 3],\n                backgroundColor: [\n                    \"rgba(255, 99, 132, 0.2)\",\n                    \"rgba(54, 162, 235, 0.2)\",\n                    \"rgba(255, 206, 86, 0.2)\",\n                    \"rgba(75, 192, 192, 0.2)\",\n                    \"rgba(153, 102, 255, 0.2)\",\n                    \"rgba(255, 159, 64, 0.2)\"\n                ],\n                borderColor: [\n                    \"rgba(255, 99, 132, 1)\",\n                    \"rgba(54, 162, 235, 1)\",\n                    \"rgba(255, 206, 86, 1)\",\n                    \"rgba(75, 192, 192, 1)\",\n                    \"rgba(153, 102, 255, 1)\",\n                    \"rgba(255, 159, 64, 1)\"\n                ],\n                borderWidth: 1\n            }\n        ]\n    },\n    options: {\n        responsive: false, //MUST BE false to avoid errors\n        animation: false, //MUST BE false to avoid errors\n        scales: {\n            yAxes: [\n                {\n                    ticks: {\n                        beginAtZero: true\n                    }\n                }\n            ]\n        }\n    }\n});\n\nctx.globalCompositeOperation = 'destination-over'\nctx.fillStyle = \"white\";\nctx.fillRect(0, 0, canvas.width, canvas.height);\n\ncanvas.toBuffer(function (err, buf) {\n    if (err) throw err;\n    msg.payload = buf;\n    node.send(msg);\n    //fs.writeFileSync(\"chart.png\", buf);\n});","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"Chart","module":"chart.js"},{"var":"Canvas","module":"canvas"}],"x":1610,"y":1500,"wires":[["81ecc8eadd602295"]]},{"id":"efd0d429627d8545","type":"inject","z":"553814a2.1248ec","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1440,"y":1500,"wires":[["1b1e2516d420ad11"]]},{"id":"81ecc8eadd602295","type":"file","z":"553814a2.1248ec","name":"","filename":"chartimage.png","appendNewline":false,"createDir":false,"overwriteFile":"true","encoding":"none","x":1800,"y":1500,"wires":[["460ac2f955f85fa9"]]}]
1 Like

Thanks Steve,

To be honest, I forgot about this thread. Since I found the node-red-contrib-chart-image (node) - Node-RED component and used that to generate a custom image. I also made a video on that: Generate chart images in Node-Red for email or chat messages - YouTube

But your example looks interesting. To be honest, I was looking for a way to create a bespoke picture from Node-Red. Something like a KPI where I have a value, which is maybe color coded by threshold values, combined with for example a trend arrow. For this I could just use the canvas object without the chart.js, to draw in a canvas and finally export that to a PNG file. Which I can attach to an email to send in a Telegram message.

I thought I would try something different :smiley: Silly me...

  • Couldn't get anything to look like your example images, then figured out the setting functionExternalModules to true. Edit, stop NR, start NR, read some messages about detected changes but all is compatible and so on... so carry on... :heavy_check_mark:

  • Entered the example values in the Setup... but see an "unexpected error" :x:


  • Tried to dig a bit deeper into the 404 error that eventually shows when trying to run the flow... :x:
node-pre-gyp ERR! install response status 404 Not Found on 
node-pre-gyp WARN Pre-built binaries not installable for canvas@2.8.0 and node@14.17.2 (node-v83 ABI, glibc) (falling back to source compile with node-gyp) 
node-pre-gyp WARN Hit error response status 404 Not Found on 
Package pixman-1 was not found in the pkg-config search path.
Perhaps you should add the directory containing `pixman-1.pc'
to the PKG_CONFIG_PATH environment variable
No package 'pixman-1' found
gyp: Call to 'pkg-config pixman-1 --libs' returned exit status 1 while in binding.gyp. while trying to load binding.gyp
gyp ERR! configure error 
gyp ERR! stack Error: `gyp` failed with exit code: 1
gyp ERR! stack     at ChildProcess.onCpExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/l...
  • But then realized my entire dashboard is MIA :scream: :x: :x: :x:


... So... before I go and try to reverse the suspected culprit... setting functionExternalModules back to false... I figured I would post this, in case there is something else I need to know?

EDIT - Can't wait :innocent: I restored the above setting to false and restarted NR, and all is good again.

Guess I will forget purdy charts and loading random "demos" and stick with blinking dashboard LEDs for a little longer :blush: