# How to render a chart image to send to an email, telegram,

**URL:** <https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989>\
**Category:** General\
**Created:** [29 January 2025 17:17 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989 "2025-01-29T17:17:14Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![ortegafernando](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ortegafernando/32/98049_2.png) [@ortegafernando](https://discourse.nodered.org/u/ortegafernando)\
**Post date:** [29 January 2025 17:17 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/1 "2025-01-29T17:17:14Z")

</div>

Hi, I used a lot this chart-image node but now it is outdated , difficult/impossible to install.

> [@Save Chart as picture to attach to mail](https://discourse.nodered.org/t/save-chart-as-picture-to-attach-to-mail/68915/29?page=2):
>
> well it is already doing more than half of the job, i just need to put my dynamic data into it, so i am improvising the node. as i said, i am not even a beginner i am just copying and modifying the node from example to get first the output right, and then see how it works. by the way , i am now successfully getting the data into the example using flow.get method in the function node, i was able to get the flow.get into the right position in the function node, by trial and error. [image] this …

> **[GitHub - gemini86/node-red-contrib-chart-image](https://github.com/gemini86/node-red-contrib-chart-image)**
>
> Contribute to gemini86/node-red-contrib-chart-image development by creating an account on GitHub.

Does anybody know any similar solution ?

It is a node to render a chart image so you can use it to send to an email, telegram, ....

Thanks.

---

<div class="post-metadata">

**Author:** ![M-a-r-t-i-n](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/m-a-r-t-i-n/32/52391_2.png) [@M-a-r-t-i-n](https://discourse.nodered.org/u/M-a-r-t-i-n)\
**Post date:** [29 January 2025 18:34 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/2 "2025-01-29T18:34:05Z")

</div>

I don’t use a node to do this. I use a function node to create a url containing all my data points, and that is then sent via a http request node to the web page [quickchart.io](http://quickchart.io). That page request returns an image of the chart. I save it to a file, and then attach it to the email or telegram message.

---

<div class="post-metadata">

**Author:** ![ortegafernando](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ortegafernando/32/98049_2.png) [@ortegafernando](https://discourse.nodered.org/u/ortegafernando)\
**Post date:** [29 January 2025 20:17 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/3 "2025-01-29T20:17:37Z")

</div>

@M-a-r-t-i-n Thanks a lot, it is a possibility, but it is a pitty not to have a node for that so we don't depend on an external service.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [29 January 2025 20:33 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/4 "2025-01-29T20:33:38Z")

</div>

What are you using to render the chart? Some chart libraries probably have API's to render to an image?

---

<div class="post-metadata">

**Author:** ![M-a-r-t-i-n](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/m-a-r-t-i-n/32/52391_2.png) [@M-a-r-t-i-n](https://discourse.nodered.org/u/M-a-r-t-i-n)\
**Post date:** [29 January 2025 20:33 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/5 "2025-01-29T20:33:46Z")

</div>

I agree.. I would have preferred to have a node doing it, but that was the best I could come up with when I needed a quick solution. Best of luck with your search.

---

<div class="post-metadata">

**Author:** ![ortegafernando](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ortegafernando/32/98049_2.png) [@ortegafernando](https://discourse.nodered.org/u/ortegafernando)\
**Post date:** [29 January 2025 20:40 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/6 "2025-01-29T20:40:33Z")

</div>

I think that the node I was using did with canvas and charjs, not external api. It is ony to be able to render the image by my own resources, without any external service that some day could close, not be online, or whatever.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [30 January 2025 00:44 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/7 "2025-01-30T00:44:23Z")

</div>

A quick search suggests some possibilities:

> **[Brave Search](https://search.brave.com/search?q=chartjs%2Brender%2Bto%2Bimage&summary=1&conversation=e678b91daf0d145860194d)**
>
> Search the Web. Privately. Truly useful results, AI-powered answers, & more. All from an independent index. No profiling, no bias, no Big Tech.

---

<div class="post-metadata">

**Author:** ![ortegafernando](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ortegafernando/32/98049_2.png) [@ortegafernando](https://discourse.nodered.org/u/ortegafernando)\
**Post date:** [30 January 2025 06:59 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/8 "2025-01-30T06:59:53Z")

</div>

Thanks a lot @TotallyInformation

It is not a node, but seems to be easy to implement.

But again, it depends on an external web service: _" The renderer is based on QuickChart, a free and open-source web service for generating static charts. View the main QuickChart repository [here](https://github.com/typpo/quickchart)"_, isnt it?

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [30 January 2025 07:13 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/9 "2025-01-30T07:13:42Z")

</div>

Search results & the ai answers will vary from person to person.

One of the suggestions was to use [chartjs-node-canvas - npm](https://www.npmjs.com/package/chartjs-node-canvas) Which does not use heavy computational Dom but instead the canvas library.

To use that node, you would need to import it in the setup tab of a function node. You will probably need to add a particular version of canvas also since it is a peer dependency (it's mentioned in the readme).

This article will help with importing regular npm packages: [Use any npm module in Node-RED • FlowFuse](https://flowfuse.com/blog/2023/06/import-modules/)

For anyone wondering why this is so tricky: nodejs does not have DOM (ie nodejs is not a browser) so it's not a simple case of rendering a chart in a full browser environment.

---

<div class="post-metadata">

**Author:** ![Kundepuu](https://avatars.discourse-cdn.com/v4/letter/k/bcef8e/32.png) [@Kundepuu](https://discourse.nodered.org/u/Kundepuu)\
**Post date:** [31 January 2025 03:01 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/10 "2025-01-31T03:01:50Z")

</div>

I use amcharts:It can export many file types.  
Export menu is fully customizable

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/6/f/6f4d336c8df466abc569896ace28d151c39e4a90.png)

this is exported ,jpg pic

 ![chart](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/e/de7a6e5ceb9d4cbf650f80b5627a25c3692edc0c.jpeg)

---

<div class="post-metadata">

**Author:** ![ortegafernando](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ortegafernando/32/98049_2.png) [@ortegafernando](https://discourse.nodered.org/u/ortegafernando)\
**Post date:** [26 February 2025 17:41 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/11 "2025-02-26T17:41:55Z")

</div>

@M-a-r-t-i-n could you please share a json flow from nodered in which you use [quickchart.io](http://quickchart.io) http request? Thanks.,

---

<div class="post-metadata">

**Author:** ![M-a-r-t-i-n](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/m-a-r-t-i-n/32/52391_2.png) [@M-a-r-t-i-n](https://discourse.nodered.org/u/M-a-r-t-i-n)\
**Post date:** [27 February 2025 11:32 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/12 "2025-02-27T11:32:52Z")

</div>

I dont post code here often so I hope I've got this right.

It is a simple demo that plots temperature over a few days.  
The temperatures are used to format a URL that is then sent to the request node.  
The image is returned which is then sent to a file write node. you will obviously need  
to change the path and or filename to suite your own needs.  
After that I would create either an email or telegram message to send the image.

```auto
[
    {
        "id": "fbcb693089bdd79f",
        "type": "function",
        "z": "2c04f0acbc9c4dba",
        "name": "dummy temperature history",
        "func": "\nmsg.payload = [\n\n{ x: new Date(\"1 feb 2025 3:42\"), y: 10},\n{ x: new Date(\"2 feb 2025 6:32\"), y: 12},\n{ x: new Date(\"3 feb 2025 14:34\"), y: 8},\n{ x: new Date(\"5 feb 2025 17:30\"), y: 6},\n{ x: new Date(\"6 feb 2025 13:38\"), y: 18},\n{ x: new Date(\"8 feb 2025 20:34\"), y: 17},\n{ x: new Date(\"9 feb 2025 22:12\"), y: 8},\n{ x: new Date(\"11 feb 2025 2:16\"), y: 11},\n{ x: new Date(\"13 feb 2025 22:52\"), y: 18},\n{ x: new Date(\"14 feb 2025 23:12\"), y: 8},\n{ x: new Date(\"19 feb 2025 21:12\"), y: 5},\n\n];\n\nreturn msg; \n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 380,
        "y": 1760,
        "wires": [
            [
                "efc2b30100e770e6"
            ]
        ]
    },
    {
        "id": "efc2b30100e770e6",
        "type": "function",
        "z": "2c04f0acbc9c4dba",
        "name": "create chart URL ",
        "func": "\nlet ymax = 30;\nlet ymin = 0;\nvar date = new Date();\nvar month = date.getMonth();\n\n// form the URL for the graph.\n\nlet history_array = msg.payload;\n\n// try to show the last month or so of data.\n\nlet end = history_array.length;\nlet start = end - 200;\n\nif ( start < 0) start = 0;\n\nmsg.span = end - start;\n\n// now got and form the url for the chart.\n\nmsg.url = \"https://quickchart.io/chart?c={\";\n\nmsg.url = msg.url + \"options: {scales: {yAxes: [{ticks: {min: \"+ymin+\",max:\"+ymax+\",stepSize: 5}}]}},\";\nmsg.url = msg.url + \"type:%27line%27,data:{labels:[\";\n\n//msg.url = \"https://quickchart.io/chart?c={type:%27line%27,data:{labels:[\";\n\nlet timestamp = new Date();\n\nlet i;\n\nfor( i=start; i < end;)\n{\n timestamp.setTime( history_array[i].x );\n\n let date = timestamp.toLocaleDateString();\n \n msg.url = msg.url + \"%27\" + \" \" + date + \"%27\";\n\n if ( i+1 < end ) msg.url = msg.url + \",\"\n\n i++;\n};\n\n\nmsg.url = msg.url + \"],datasets:[{label:%27°C%27,data:[\";\n\nfor( i=start; i < end; )\n{\n msg.url = msg.url + history_array[i].y\n\n if ( i+1 < end ) msg.url = msg.url + \",\";\n\n i++; \n};\n\nmsg.url = msg.url + \"], fill:false, pointRadius:1 }]}}\"\n\nmsg.payload = msg.url;\n\nreturn msg;\n\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 630,
        "y": 1760,
        "wires": [
            [
                "dd278b25841ba63a"
            ]
        ]
    },
    {
        "id": "dd278b25841ba63a",
        "type": "http request",
        "z": "2c04f0acbc9c4dba",
        "name": "Request Outdoor temp Chart",
        "method": "GET",
        "ret": "bin",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 880,
        "y": 1760,
        "wires": [
            [
                "4cdc9645994af0cf"
            ]
        ]
    },
    {
        "id": "4cdc9645994af0cf",
        "type": "function",
        "z": "2c04f0acbc9c4dba",
        "name": "Set filename ",
        "func": "// check the response code.\n\nif ( msg.statusCode != 200 ) return null;\n\nmsg.filename = \"/data/UserData/temp/outdoor_temp_history.jpg\";\n\nreturn msg;",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 330,
        "y": 1840,
        "wires": [
            [
                "bda45ba208eb68b7"
            ]
        ]
    },
    {
        "id": "bda45ba208eb68b7",
        "type": "file",
        "z": "2c04f0acbc9c4dba",
        "name": "Write Image",
        "filename": "filename",
        "filenameType": "msg",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 530,
        "y": 1840,
        "wires": [
            []
        ]
    },
    {
        "id": "5127db1c3f754e10",
        "type": "inject",
        "z": "2c04f0acbc9c4dba",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 160,
        "y": 1760,
        "wires": [
            [
                "fbcb693089bdd79f"
            ]
        ]
    }
]

```

The resulting image,

 ![outdoor_temp_history](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/2/22dc6ed5676485e5d46a0261fe7d630ac8e8175b.png)

---

<div class="post-metadata">

**Author:** ![smanjunath211](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/smanjunath211/32/95742_2.png) [@smanjunath211](https://discourse.nodered.org/u/smanjunath211)\
**Post date:** [27 February 2025 12:33 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/13 "2025-02-27T12:33:47Z")

</div>

Works perfectly for me.

> **A Tip: (Please ignore if you already knew)**
>
> _Using Compact mode, you can post the code in a single line._
> 
> ```auto
> [{"id":"fbcb693089bdd79f","type":"function","z":"0637174b7a71a782","name":"dummy temperature history","func":"\nmsg.payload = [\n\n{ x: new Date(\"1 feb 2025 3:42\"), y: 10},\n{ x: new Date(\"2 feb 2025 6:32\"), y: 12},\n{ x: new Date(\"3 feb 2025 14:34\"), y: 8},\n{ x: new Date(\"5 feb 2025 17:30\"), y: 6},\n{ x: new Date(\"6 feb 2025 13:38\"), y: 18},\n{ x: new Date(\"8 feb 2025 20:34\"), y: 17},\n{ x: new Date(\"9 feb 2025 22:12\"), y: 8},\n{ x: new Date(\"11 feb 2025 2:16\"), y: 11},\n{ x: new Date(\"13 feb 2025 22:52\"), y: 18},\n{ x: new Date(\"14 feb 2025 23:12\"), y: 8},\n{ x: new Date(\"19 feb 2025 21:12\"), y: 5},\n\n];\n\nreturn msg; \n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":960,"wires":[["efc2b30100e770e6"]]},{"id":"efc2b30100e770e6","type":"function","z":"0637174b7a71a782","name":"create chart URL ","func":"\nlet ymax = 30;\nlet ymin = 0;\nvar date = new Date();\nvar month = date.getMonth();\n\n// form the URL for the graph.\n\nlet history_array = msg.payload;\n\n// try to show the last month or so of data.\n\nlet end = history_array.length;\nlet start = end - 200;\n\nif ( start < 0) start = 0;\n\nmsg.span = end - start;\n\n// now got and form the url for the chart.\n\nmsg.url = \"https://quickchart.io/chart?c={\";\n\nmsg.url = msg.url + \"options: {scales: {yAxes: [{ticks: {min: \"+ymin+\",max:\"+ymax+\",stepSize: 5}}]}},\";\nmsg.url = msg.url + \"type:%27line%27,data:{labels:[\";\n\n//msg.url = \"https://quickchart.io/chart?c={type:%27line%27,data:{labels:[\";\n\nlet timestamp = new Date();\n\nlet i;\n\nfor( i=start; i < end;)\n{\n timestamp.setTime( history_array[i].x );\n\n let date = timestamp.toLocaleDateString();\n \n msg.url = msg.url + \"%27\" + \" \" + date + \"%27\";\n\n if ( i+1 < end ) msg.url = msg.url + \",\"\n\n i++;\n};\n\n\nmsg.url = msg.url + \"],datasets:[{label:%27°C%27,data:[\";\n\nfor( i=start; i < end; )\n{\n msg.url = msg.url + history_array[i].y\n\n if ( i+1 < end ) msg.url = msg.url + \",\";\n\n i++; \n};\n\nmsg.url = msg.url + \"], fill:false, pointRadius:1 }]}}\"\n\nmsg.payload = msg.url;\n\nreturn msg;\n\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":610,"y":960,"wires":[["dd278b25841ba63a"]]},{"id":"dd278b25841ba63a","type":"http request","z":"0637174b7a71a782","name":"Request Outdoor temp Chart","method":"GET","ret":"bin","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":860,"y":960,"wires":[["4cdc9645994af0cf"]]},{"id":"4cdc9645994af0cf","type":"function","z":"0637174b7a71a782","name":"Set filename ","func":"// check the response code.\n\nif ( msg.statusCode != 200 ) return null;\n\nmsg.filename = \"/temp/outdoor_temp_history.jpg\";\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":1040,"wires":[["bda45ba208eb68b7"]]},{"id":"bda45ba208eb68b7","type":"file","z":"0637174b7a71a782","name":"Write Image","filename":"filename","filenameType":"msg","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":510,"y":1040,"wires":[[]]},{"id":"5127db1c3f754e10","type":"inject","z":"0637174b7a71a782","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":140,"y":960,"wires":[["fbcb693089bdd79f"]]}]
> 
> ```

---

<div class="post-metadata">

**Author:** ![M-a-r-t-i-n](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/m-a-r-t-i-n/32/52391_2.png) [@M-a-r-t-i-n](https://discourse.nodered.org/u/M-a-r-t-i-n)\
**Post date:** [27 February 2025 12:35 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/14 "2025-02-27T12:35:26Z")

</div>

Thanks for the tip. I didn’t realise that.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [13 March 2025 12:35 UTC](https://discourse.nodered.org/t/how-to-render-a-chart-image-to-send-to-an-email-telegram/94989/15 "2025-03-13T12:35:42Z")

</div>

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.
