The size of a pie chart

The diameter of a pie chart seems to be determined by the specified height of the widget, so a 6x10 chart looks like this.
Note that there is some headroom at the top and bottom (outlined in green) but no space at the sides for sector labels (outlined in red)

While a 6x6 chart looks like this. There is space for the labels (green outline) but too cramped at top and bottom (red)

Far from being a perfect compromise, a 6x8 chart falls down in both respects.
(On my PC, using a theme with 48px row height, this is almost exactly square, 468 x 468px)

Maybe we should just use auto and let the widget choose the best settings? Sadly not.
image

Proposed fix / enhancement

I suggest that the chart diameter should be based on the widget display width, not height.
Ideally we could specify the percentage width, but a fixed percentage of the widget width might suffice - 60% maybe.
It would then be down to the user to specify enough dashboard rows to comfortably fit their data.
For an Auto dimensioned chart, it should be 60% of the group width and tall enough to contain the data.

The total height of the widget is determined by the number of rows specified in the size, and by the row height set in the theme. Assuming that we are talking about Grid layout, then the total width is determined by the number of columns specified in the config, by the window size, and by the Responsive Layouts settings in the page config. If you shrink the window width up or down it will affect what the images you posted look like.

The size available for the pie chart section of the widget is determined by taking the total height and subtracting from that a space for the title and legends (if these are specified). Then the radius is chosen to be the max that will fit in the available width and height, whichever is the larger. At least I think that is how it works. This is not perfect as it may not allow room for the labelling round the circle, as you point out. I don't know whether the eCharts library allows one to specify the size such that it wlll shrink the radius if necessary to fit the labels in.

If that were done then sometimes it would not fit vertically in the space available, so would be clipped or overlap other stuff.

This does not work.
Since the legends can wrap onto multiple rows, insufficient headroom is sometimes allowed.

With the greatest respect for whoever first coded the pie chart and the difficult compromises they faced, a sizing algorithm which causes some of the widget not to be rendered at all is a bug.

Indeed. That's exactly why I said the user would have to specify enough rows to comfortably fit the data.

Correct, it is a compromise. If you can tell me how to work out how many rows the legends will need then I could implement that. In the mean time, for any particular case the user can use msg.ui_update.chartOptions to configure the chart for his particular use case.

That was not me of course. Would not having the pie overlap the widgets below the allotted space also be a bug? Again, please check the eCharts docs and tell me how to determine how much width is available for the pie chart in the general case and it should be possible to improve that by shrinking the pie radius to allow room for the labelling.

Unfortunately, since the widget width varies with the window width, displaying the chart on different devices, or even varying the width of the browser window, would need a different number of rows for different window widths.
Again, for any particular use case the dimensions can be tweaked using the chartOptions. Not a perfect solution I know.

Some DB2 widgets have previously allowed some elements to overflow the widget's allotted size. It is indeed a bug. As far as I know, no such bugs remain in the wild.
The only appropriate behaviour is for overflow to be hidden, but for it to be possible to fix by choosing a more appropriate widget size.
But with this widget, there are no height and width combinations for this dataset without cropping or internal overlap.

I faced exactly this difficulty trying to fit the forecast location etc in my weather widget. In that case I chose to adjust the font size to fit it in one row, subject to maximum and minimum pixel size contraints.
Not sure if a similar approach would work for the legend of a pie chart because there could be a lot of wedges of the pie; wrapping to another line is inevitable.
It is, I think, possible for widget elements to magically move up or down so a multiple line legend fits comfortably. Such a strategy would collect any unused space at the bottom of the widget, and the user might be able to tweek the widget height to minimise this space for their data at all the resolutions they need. The weather widget does this.
As I said, this pie chart widget seems to prohibit such tweeking.

Virtually anything can be configured using msg.ui_update.chartOptions. Nothing is prohibited.

For reference, the radius and position of the pie chart can be configured using something like this

msg = {
  ui_update: {
    "chartOptions": {
      "series": [
        {
          "name": "series_name",
          "type": "pie",
          "radius": ["0%","30%"],  // inner and outer radius
          "center": ['60%', '50%'] // position (x, y)
        }
      ]
    }
  }
}

Unfortunately this doesn't work at the moment, it was timely you prompting me to check exactly how to do this as it identified a bug. The next release, due within a couple of days, should fix it.

[Edit] The dimensions can also be specified in px from the top left hand corner of the widget.

1 Like

Wouldn't an "easy" answer be to add another config input that specifies a % that impacts the pie itself? E.g. 100% would be the default with results as now. 80% would make the pie smaller by 20% allowing additional room for the legend and labels.

If there were someone who really knows eCharts inside out who can tell us how to arrange the parts to get the best fit in the available space then that would be a good start.

1 Like

It looks as though the truncation of labels is done by the eCharts code, not the ui-chart widget. So even if we could mislead eCharts about the true width of the widget, it would probably still truncate the labels.

There is an example in the echarts docs which implies you can reduce the space allocated to the pie.


I have no idea how the dashboard invokes eCharts, but this looks related to what Colin said above re msg.ui_update. Can it be that 100% is the default and we could supply a different value?

Hopefully when the next dash board release is published we will get a clearer idea.

Thanks for your efforts @Colin !

Good spot, should be easy enough to be added to the node.

As I posted, you can easily do that using msg.ui_update.chartOptions.

The default size is dependent on whether the legends are shown or not.

Well yes but it is not a success. I assumed this was the issue you expect to be fixed by the imminent release.
Before

After

Probably.

I have managed to shrink the pie and make the sector labels visible, using ui_update

{
  "chartOptions":
   {
      "width":"100%",
      "height":"60%"
   }
}

So far it's at the expense of losing the legend. :anxious_face_with_sweat:

V1.30.1 is available, try again using the radius and center.

I do think it's behaving better now, can't put my finger on exactly how.

Anyway, here is a 6x8 pie chart.
The Series is msg.topic, which is blank (I believe this must point to something which exists, even if it's an empty string, otherwise the chart is not generated, or else there is no legend.).
X is key: fuel and Y is key: perc.

The input data in a change node

[{"id":"69571cc08e407e2c","type":"change","z":"4d1c504a2f7936b7","g":"6215e22159f537bb","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"[{\"fuel\":\"biomass\",\"perc\":8.6},{\"fuel\":\"coal\",\"perc\":0},{\"fuel\":\"imports\",\"perc\":10.7},{\"fuel\":\"gas\",\"perc\":38.5},{\"fuel\":\"nuclear\",\"perc\":11.3},{\"fuel\":\"other\",\"perc\":0},{\"fuel\":\"hydro\",\"perc\":0},{\"fuel\":\"solar\",\"perc\":0},{\"fuel\":\"wind\",\"perc\":30.9}]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":300,"y":220,"wires":[["97f88bdfa8c46899"]]}]

If I pass it msg.ui_update like this (Note I replaced your single quotes with double to test the same ui_update in a change node which abhors single quotes)

msg = {
  ui_update: {
    "chartOptions": {
      "series": [
        {
          "name": "series_name",
          "type": "pie",
          "radius": ["0%","70%"],  // inner and outer radius
          "center": ["40%", "50%"] // position (x, y)
        }
      ]
    }
  }
}
return msg;

Then the chart is redrawn like this - basically it works.

There is a But...
Click to show the left sidebar and the widget is resized, losing the labels on the LHS. I think this suggests that the only viable value for center, at least on a grid layout dashboard, is 50%, nn%.


And if you make the browser window narrower, the chart does get smaller, but before it does, the labels get truncated with ellipsis

On my screen, I found that these values give a chart which fits without truncation at all browser sizes.

msg = {
  ui_update: {
    "chartOptions": {
      "series": [
        {
          "name": "series_name",
          "type": "pie",
          "radius": ["0%","45%"],  // inner and outer radius
          "center": ["50%", "50%"] // position (x, y)
        }
      ]
    }
  }
}
return msg;

This is the minimum displayed size.

Important discovery

Reloading the page destroys the chart. In short, this is not a viable approach.

Another caveat.

You can inject both a payload and ui_update in the same message.
However, if the ui_update includes chart_options.series.name, then the legend shows one extra name and the chart itself is utterly borked.

In summary, the radius and center options can only be implemented by sending first the data and then ui_update.

There are other echart settings that you can send simultaneously with payload, series seems to be an exception.

I presume you have upgraded the dashboard to 1.30.1

It should not, can you post an example flow please?
Have you got client data enabled for ui-chart on that page (in the page settings). It should not generally be enabled.

That should not be necessary, but I had to put some effort into making it work, so it is possible that there is another edge case I had not found. Again, post a failing flow please.

It is chartOptions not chart_options, and chartOptions.series should always be an array.

$ node-red --version
Node-RED v5.0.0-beta.1
Node.js v24.12.0
Linux 6.12.47+rpt-rpi-v8 arm64 LE

@flowfuse/node-red-dashboard is v1.30.1

Sorry, I can't find this option, but I have never knowingly tampered with it.

Yes, a typo.

The Buttons group contains the steps in order to get a clean dashboard, and break it.
I have a button and exec node to restart Node-red. ctrl f5 and reload page are of course manual steps.

[{"id":"c92fa447f93ccd52","type":"tab","label":"Flow 3","disabled":false,"info":"","env":[]},{"id":"fc174fb26fc43ef6","type":"ui-button","z":"c92fa447f93ccd52","group":"58c9e23af88edc69","name":"","label":"1 Clear Charts","order":1,"width":"2","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"[]","payloadType":"json","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":120,"y":40,"wires":[["c18bfb65bac66ca8"]]},{"id":"21db0d6bb0d3bf86","type":"ui-button","z":"c92fa447f93ccd52","group":"58c9e23af88edc69","name":"","label":"4 Inject Data","order":4,"width":"2","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":130,"y":160,"wires":[["d6b205901b7756b2"]]},{"id":"e4075de9bc93d616","type":"ui-button","z":"c92fa447f93ccd52","group":"58c9e23af88edc69","name":"","label":"5 ui_update","order":5,"width":"2","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":130,"y":200,"wires":[["11fc6323fa17aea7"]]},{"id":"0d26d234f1d4cb56","type":"ui-button","z":"c92fa447f93ccd52","group":"58c9e23af88edc69","name":"","label":"2 Restart Nodered","order":2,"width":"2","height":"1","emulateClick":false,"tooltip":"","color":"","bgcolor":"","className":"","icon":"","iconPosition":"left","payload":"sudo systemctl restart nodered","payloadType":"str","topic":"topic","topicType":"msg","buttonColor":"","textColor":"","iconColor":"","enableClick":true,"enablePointerdown":false,"pointerdownPayload":"","pointerdownPayloadType":"str","enablePointerup":false,"pointerupPayload":"","pointerupPayloadType":"str","x":110,"y":80,"wires":[["1b97b6a0ac1e17fa"]]},{"id":"1b97b6a0ac1e17fa","type":"exec","z":"c92fa447f93ccd52","command":"","addpay":"payload","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"","x":310,"y":80,"wires":[[],[],[]]},{"id":"c59c2afbc160261f","type":"ui-template","z":"c92fa447f93ccd52","group":"","page":"6656fb14ebb2b340","ui":"","name":"Outline widgets","order":0,"width":0,"height":0,"head":"","format":".nrdb-ui-widget {\n    outline: 1px solid red;\n}","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"page:style","className":"","x":540,"y":200,"wires":[[]]},{"id":"d6b205901b7756b2","type":"change","z":"c92fa447f93ccd52","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"[{\"fuel\":\"biomass\",\"perc\":8.6},{\"fuel\":\"coal\",\"perc\":0},{\"fuel\":\"imports\",\"perc\":10.7},{\"fuel\":\"gas\",\"perc\":38.5},{\"fuel\":\"nuclear\",\"perc\":11.3},{\"fuel\":\"other\",\"perc\":0},{\"fuel\":\"hydro\",\"perc\":0},{\"fuel\":\"solar\",\"perc\":0},{\"fuel\":\"wind\",\"perc\":30.9}]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":160,"wires":[["c18bfb65bac66ca8"]]},{"id":"c18bfb65bac66ca8","type":"ui-chart","z":"c92fa447f93ccd52","group":"91a81e37e2bafe93","name":"#2","label":"Experiment #2","order":1,"chartType":"pie","category":"topic","categoryType":"msg","xAxisLabel":"","xAxisProperty":"fuel","xAxisPropertyType":"property","xAxisType":"radial","xAxisFormat":"","xAxisFormatType":"auto","xmin":"","xmax":"","yAxisLabel":"","yAxisProperty":"perc","yAxisPropertyType":"property","ymin":"","ymax":"","bins":10,"action":"replace","stackSeries":false,"pointShape":"circle","pointRadius":4,"showLegend":true,"removeOlder":1,"removeOlderUnit":"3600","removeOlderPoints":"","colors":["#0095ff","#ff0000","#ff7f0e","#2ca02c","#a347e1","#d62728","#ff9896","#9467bd","#c5b0d5"],"textColor":["#666666"],"textColorDefault":true,"gridColor":["#e5e5e5"],"gridColorDefault":true,"width":"6","height":"8","className":"","interpolation":"linear","x":530,"y":40,"wires":[[]]},{"id":"11fc6323fa17aea7","type":"function","z":"c92fa447f93ccd52","name":"function 5","func":"msg = {\n  ui_update: {\n    \"chartOptions\": {\n      \"series\": [\n        {\n          \"name\": \"series_name\",\n          \"type\": \"pie\",\n          \"radius\": [\"0%\",\"45%\"],  // inner and outer radius\n          \"center\": [\"50%\", \"50%\"] // position (x, y)\n        }\n      ]\n    }\n  }\n}\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":200,"wires":[["c18bfb65bac66ca8"]]},{"id":"e524a5874babe3f6","type":"ui-text","z":"c92fa447f93ccd52","group":"58c9e23af88edc69","order":3,"width":0,"height":0,"name":"","label":"3 Ctrl f5 refresh","format":"{{msg.payload}}","layout":"row-center","style":false,"font":"","fontSize":16,"color":"#717171","wrapText":false,"className":"","value":"payload","valueType":"msg","x":120,"y":120,"wires":[]},{"id":"fb72a8b60121b332","type":"ui-text","z":"c92fa447f93ccd52","group":"58c9e23af88edc69","order":6,"width":0,"height":0,"name":"","label":"6 Reload page","format":"{{msg.payload}}","layout":"row-center","style":false,"font":"","fontSize":16,"color":"#717171","wrapText":false,"className":"","value":"payload","valueType":"msg","x":120,"y":240,"wires":[]},{"id":"58c9e23af88edc69","type":"ui-group","name":"Buttons","page":"6656fb14ebb2b340","width":"2","height":1,"order":2,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"6656fb14ebb2b340","type":"ui-page","name":"Pies","ui":"d0aaeb56c796f1d4","path":"/pies","icon":"home","layout":"grid","theme":"57e1923decfbf45b","breakpoints":[{"name":"Default","px":"0","cols":"3"},{"name":"Tablet","px":"576","cols":"6"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":1,"className":"","visible":true,"disabled":false},{"id":"91a81e37e2bafe93","type":"ui-group","name":"Chart","page":"6656fb14ebb2b340","width":6,"height":1,"order":1,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"d0aaeb56c796f1d4","type":"ui-base","name":"My Dashboard","path":"/dashboard","appIcon":"","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"headerContent":"page","navigationStyle":"default","titleBarStyle":"default","showReconnectNotification":true,"notificationDisplayTime":1,"showDisconnectNotification":true,"allowInstall":true},{"id":"57e1923decfbf45b","type":"ui-theme","name":"Basic Blue Theme","colors":{"surface":"#4d58ff","primary":"#0094ce","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"2px","density":"default"}},{"id":"7a4a7ce0b2f4b498","type":"global-config","env":[],"modules":{"@flowfuse/node-red-dashboard":"1.30.1"}}]

This is after step 5


And step 6. Note "series_name" added to the legend as well as the hole in the pie (which is now showing two series, concentrically).