# Pie chart legend wrap or multiline

**URL:** <https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613>\
**Category:** Ignition\
**Tags:** ignition81, vision\
**Created:** [February 9, 2023, 9:26am UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613 "2023-02-09T09:26:47Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![zxcslo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zxcslo/32/61610_2.png) [@zxcslo](https://forum.inductiveautomation.com/u/zxcslo)\
**Post date:** [February 9, 2023, 9:26am UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/1 "2023-02-09T09:26:47Z")

</div>

I appeal to all java gurus in this community for help... 🙏  
I have a Pie Chart with a legend on the right side, where the text is sometimes too long and therefore the Pie Chart itself shrinks.

![Screenshot_64](https://us1.discourse-cdn.com/inductiveautomation/original/3X/6/f/6fe4fd5d14351584fc973e06463fd43af780a2fa.png)

But I need fixed width for the Pie Chart component.

![Screenshot_65](https://us1.discourse-cdn.com/inductiveautomation/original/3X/e/1/e1e1e29ea99ae747c5e3eb77570f439c40abadba.png)

Is it possible somehow to implement a multiline or word wrap to the legend of a Pie Chart?  
This is my code for configuring the chart in the configureChart Extension Functions:

> **Summary**
>
> ```auto
> def configureChart(self, chart):
> # Put your code here
> from org.jfree.chart.labels import PieSectionLabelGenerator
> from org.jfree.ui import RectangleEdge
> from org.jfree.chart.block import BlockBorder
> from org.jfree.chart import LegendItem
> from java.awt import Color
> 	
> class customLabelGenerator(PieSectionLabelGenerator):
> def __init__ (self):
> self.skupaj = 0.0
> self.vrednost = 0.0
> self.procent = 0.0
> 		
> def generateSectionLabel(self,dataset,key):
> self.skupaj = 0.0
> for kljuc in dataset.getKeys():
> self.skupaj += dataset.getValue(kljuc)
> 
> self.vrednost = dataset.getValue(key)
> stringvalue = myscripts.secondsToText3(self.vrednost)
> 			
> self.procent = int(round((self.vrednost * 100.0) / self.skupaj, 0))
> #print "self.procent1= ", self.procent
> 			
> #print "###################################"
> #result = key + " = " + stringvalue + " (" + str(self.procent) + "%)"
> #result = stringvalue + " (" + str(self.procent) + "%)"
> result = str(self.procent) + "%"
> #print "result= ", result
> return result
> 	
> plot = chart.getPlot()
> legend = chart.getLegend()
> 	
> plot.setLabelGenerator(customLabelGenerator())
> plot.setSimpleLabels(True)
> plot.setLabelBackgroundPaint(None)
> plot.setLabelOutlinePaint(None)
> plot.setLabelShadowPaint(None)
> plot.setBackgroundPaint(None)
> plot.setOutlineVisible(False)
> plot.setShadowPaint(None)
> 		
> legend.setFrame(BlockBorder.NONE)
> legend.setBackgroundPaint(None)
> legend.setPosition(RectangleEdge.RIGHT)
> 
> ```

I was searching the forum and found a couple of topics about a chart legend, but none for Pie Chart.  
Also, the internet is all about java code for [org.jfree.chart.JFreeChart](https://www.jfree.org/jfreechart/api/javadoc/org/jfree/chart/JFreeChart.html) which is like Klingon language to me... 🤪

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [February 9, 2023, 1:06pm UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/2 "2023-02-09T13:06:41Z")

</div>

Huh. I'd turn the legend off and use a template repeater beside it to show the legend names.

Extract the names and colors for the legends in the `configureChart` method and write a dataset to a custom property with the results. Use that custom property to drive the template repeater.

---

<div class="post-metadata">

**Author:** ![zxcslo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zxcslo/32/61610_2.png) [@zxcslo](https://forum.inductiveautomation.com/u/zxcslo)\
**Post date:** [February 9, 2023, 1:37pm UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/3 "2023-02-09T13:37:12Z")

</div>

> [@pturmel](#):
>
> Extract the names and colors for the legends

Very good suggestion, but I really don't know how to do that... (extract the names and colors). 🥺

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [February 9, 2023, 1:52pm UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/4 "2023-02-09T13:52:00Z")

</div>

> [@zxcslo](#):
>
> I really don't know how to do that

I haven't done it myself, so I don't either. It would take some time diving into the JFreeChart docs and introspecting Ignition's implementations of them. Not rocket science, but not trivial either.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [February 9, 2023, 4:24pm UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/5 "2023-02-09T16:24:45Z")

</div>

Possible via JFreeChart, but non-trivial:

> <https://stackoverflow.com/questions/10352977/jfree-chart-legend-with-line-break/10428292#10428292>

---

<div class="post-metadata">

**Author:** ![zxcslo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zxcslo/32/61610_2.png) [@zxcslo](https://forum.inductiveautomation.com/u/zxcslo)\
**Post date:** [February 9, 2023, 4:37pm UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/6 "2023-02-09T16:37:51Z")

</div>

Yes, I saw this, but I can't figure out how to do this in Ignition...

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [February 9, 2023, 7:21pm UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/7 "2023-02-09T19:21:21Z")

</div>

> [@pturmel](#):
>
> and use a template repeater beside it to show the legend names

~~I believe he meant power table.~~ This is a good idea and a simple approach. The legend names are taken from column zero of the chart.data dataset, and the colors occur in the order specified in one of the other chart properties. ~~I don't remember the name off the top of my head,~~ _The property is called sectionColors_ ~~but the colors wouldn't need to be extracted, just specified in the power table's **configureCell** extension function with if, elif `rowIndex % 10 == ' 0 through 9~~

**Edit:** if done from a power table, this would be the code to use on the configureCell extension function:

```auto
#def configureCell([...]): add the following code to the power table's configure cell extension function
	colors = self.parent.getComponent('Pie Chart').sectionColors #or the correct path to the chart if it's different
	color = colors[rowView % len(colors)]
	if colIndex == 0:
		return {'foreground': color}

```

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [February 10, 2023, 3:03am UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/8 "2023-02-10T03:03:50Z")

</div>

I finally got an opportunity to look at this, and I was able to accomplish the goal inherently with the StandardPieSectionLabelGenerator class and textwrap.

Here is the modified code example:

```auto
def configureChart(self, chart):
	
	#add this
	import textwrap 
	
	# and add StandardPieSectionLabelGenerator to the following line
	from org.jfree.chart.labels import PieSectionLabelGenerator, StandardPieSectionLabelGenerator 

	from org.jfree.ui import RectangleEdge
	from org.jfree.chart.block import BlockBorder
	from org.jfree.chart import LegendItem
	from java.awt import Color

	# add this class and modify the width as needed
	class WrappedStandardPieSectionLabelGenerator(StandardPieSectionLabelGenerator):
	    def generateSectionLabel(self, dataset, key):
	        label = StandardPieSectionLabelGenerator.generateSectionLabel(self, dataset, key)
	        wrapped_label = '\n'.join(textwrap.wrap(label, width=20))
	        return wrapped_label

	class customLabelGenerator(PieSectionLabelGenerator):
		def __init__ (self):
			self.skupaj = 0.0
			self.vrednost = 0.0
			self.procent = 0.0
		def generateSectionLabel(self,dataset,key):
			self.skupaj = 0.0
			for kljuc in dataset.getKeys():
				self.skupaj += dataset.getValue(kljuc)
			self.vrednost = dataset.getValue(key)
			stringvalue = myscripts.secondsToText3(self.vrednost)
			self.procent = int(round((self.vrednost * 100.0) / self.skupaj, 0))
			result = str(self.procent) + "%"
			return result
	plot = chart.getPlot()
	legend = chart.getLegend()

	#Add these two lines
	legendLabelGenerator = WrappedStandardPieSectionLabelGenerator()
	plot.setLegendLabelGenerator(legendLabelGenerator)

	plot.setLabelGenerator(customLabelGenerator())
	plot.setSimpleLabels(True)
	plot.setLabelBackgroundPaint(None)
	plot.setLabelOutlinePaint(None)
	plot.setLabelShadowPaint(None)
	plot.setBackgroundPaint(None)
	plot.setOutlineVisible(False)
	plot.setShadowPaint(None)
	legend.setFrame(BlockBorder.NONE)
	legend.setBackgroundPaint(None)
	legend.setPosition(RectangleEdge.RIGHT)

```

**Here is the result:**  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/e/3/e3b03edae55b7220e58b4fe510931a79e81e43bd.png)

---

<div class="post-metadata">

**Author:** ![zxcslo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zxcslo/32/61610_2.png) [@zxcslo](https://forum.inductiveautomation.com/u/zxcslo)\
**Post date:** [February 10, 2023, 7:45am UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/9 "2023-02-10T07:45:27Z")

</div>

This community is the best... Thank you @justinedwards.jle 👍  
That is exactly what I need except...  
the text in the legend is centered and should be left aligned...

I'm looking into this '[textwrap](https://docs.python.org/3/library/textwrap.html)' but I can't find anything for alignment...

Also for 'PieSectionLabelGenerator' I can't find anything for text alignment... 😕

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [February 10, 2023, 10:01am UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/10 "2023-02-10T10:01:17Z")

</div>

I couldn't find a native way to get left alignment either, but I found a way to closely emulate it.

At first I tried simply making all of the lines the same length with whitespace, but that didn't work presumably because of kerning and variable letter widths. I ended up finding a way to [get the width of a string in pixels](https://stackoverflow.com/a/258499/13360064) using fontMetrics, and I created a comparative string of underscores that is arbitrarily longer than any line that can be generated from a maxWidth I specify in the second line of the generateSectionLabel function. The for each line, I find the difference between the width of the comparative string and the width of the line, and then I divide that difference by the width of a single space to calculate how many spaces I have to add to each line to make all of the lines the same width.

It's not perfect, and if you look closely, you can see slight misalignments, but it's pretty close.  
**Here is the result:**  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/2/0/20969d2b697037df0b6ae24c7c145eebe0613896.png)

**Here is the source code:**

> **Source Code**
>
> ```auto
> import textwrap 
> from org.jfree.chart.labels import PieSectionLabelGenerator, StandardPieSectionLabelGenerator 
> from org.jfree.ui import RectangleEdge
> from org.jfree.chart.block import BlockBorder
> from org.jfree.chart import LegendItem
> from java.awt import Color, FontMetrics, Graphics
> from java.awt.image import BufferedImage
> pieChart = self
> class WrappedStandardPieSectionLabelGenerator(StandardPieSectionLabelGenerator):
> def generateSectionLabel(self, dataset, key):
> label = StandardPieSectionLabelGenerator.generateSectionLabel(self, dataset, key)
> maxWidth = 20
> wrapped_lines = textwrap.wrap(label, width=maxWidth)
> font = pieChart.legendFont
> image = BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB)
> g = image.createGraphics()
> g.setFont(font)
> fm = g.getFontMetrics()
> alignmentwidth = maxWidth + 10
> comparitiveString = '_' * alignmentwidth
> comparitiveLength = fm.stringWidth(comparitiveString)
> whiteSpaceWidth = fm.stringWidth(' ')
> aligned_lines = [line + ' ' * int(float((comparitiveLength - fm.stringWidth(line)))/float(whiteSpaceWidth)) for line in wrapped_lines]
> aligned_label = '\n'.join(aligned_lines)
> g.dispose()
> return aligned_label
> class customLabelGenerator(PieSectionLabelGenerator):
> def __init__ (self):
> self.skupaj = 0.0
> self.vrednost = 0.0
> self.procent = 0.0
> def generateSectionLabel(self,dataset,key):
> self.skupaj = 0.0
> for kljuc in dataset.getKeys():
> self.skupaj += dataset.getValue(kljuc)
> self.vrednost = dataset.getValue(key)
> stringvalue = myscripts.secondsToText3(self.vrednost)
> self.procent = int(round((self.vrednost * 100.0) / self.skupaj, 0))
> result = str(self.procent) + "%"
> return result
> plot = chart.getPlot()
> legend = chart.getLegend()
> legendLabelGenerator = WrappedStandardPieSectionLabelGenerator()
> plot.setLegendLabelGenerator(legendLabelGenerator)
> plot.setLabelGenerator(customLabelGenerator())
> plot.setSimpleLabels(True)
> plot.setLabelBackgroundPaint(None)
> plot.setLabelOutlinePaint(None)
> plot.setLabelShadowPaint(None)
> plot.setBackgroundPaint(None)
> plot.setOutlineVisible(False)
> plot.setShadowPaint(None)
> legend.setFrame(BlockBorder.NONE)
> legend.setBackgroundPaint(None)
> legend.setPosition(RectangleEdge.RIGHT)
> 
> ```

**Edit:** Changed `pieChart.labelFont` to `pieChart.legendFont`

---

<div class="post-metadata">

**Author:** ![zxcslo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zxcslo/32/61610_2.png) [@zxcslo](https://forum.inductiveautomation.com/u/zxcslo)\
**Post date:** [February 10, 2023, 11:47am UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/11 "2023-02-10T11:47:39Z")

</div>

Vau, you're truly amazing... 🤪  
Thank you @justinedwards.jle for your effort.  
Really appreciated... 👍

If you ever set foot in Slovenia, all the beer you can drink is waiting for you... 🍻

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [February 11, 2023, 8:34am UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/12 "2023-02-11T08:34:06Z")

</div>

I had another idea on this, and I did some looking into font properties. Consequently, I found [a list of monospace fonts](https://en.wikipedia.org/wiki/List_of_monospaced_typefaces) that don't kern and keep the same width no matter the letter. I did a quick experiment and discovered a mistake in my code. Originally, I was using the labelFont field to set the font metric, but this is not correct. The legend gets its font from a separate legendFont field.

In any case, after correcting that, I set the font to Courier New, Plain and eliminated the arbitrary +10 from my alignmentwidth variable. Afterwards, the left align came out perfect every time. Of course, this means that the alignmentwidth variable is not needed, and the maxWidth variable could be used exclusively.

Here is the result using Consolas ([another font on the list](https://en.wikipedia.org/wiki/List_of_monospaced_typefaces))  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/4/1/415e593e7438de65dae2d12d8babceae977c064f.png)

As you can see, using any monospace font corrects the slight left alignment deviations from the previous example.

---

<div class="post-metadata">

**Author:** ![zxcslo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zxcslo/32/61610_2.png) [@zxcslo](https://forum.inductiveautomation.com/u/zxcslo)\
**Post date:** [February 12, 2023, 5:46am UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/13 "2023-02-12T05:46:12Z")

</div>

Again, thank you @justinedwards.jle for your effort. 👍  
This is what I came up with:

 ![Screenshot_12](https://us1.discourse-cdn.com/inductiveautomation/original/3X/8/3/835314cb204159bc3c78d0e2282dd30fa20ec5ed.png)  
The top Pie Chart is with your code and the other two are Pie Charts without legend (disabled) and template repeater on the right side (as @pturmel suggested).  
It turns out that with a template repeater wasn't so hard to do...

But I prefer everything done with only one component if it's possible (Pie Chart) and @justinedwards.jle proved that is possible.

Now I (we) have two solutions instead of one (choices, choices,...).

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [February 12, 2023, 8:05am UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/14 "2023-02-12T08:05:20Z")

</div>

...so he **DID** mean template repeater; **my apologies for the mistake**. The repeater choice looks good, but does it remain centered on the graph when there is something other than 5 items? I actually did do a mock up with a power table, but I abandoned the approach because it didn't look like it was going to be as simple as I had initially envisioned. Seven or more items generated a scroll bar, and one or two items looked funny because it was off center. Also, getting a bullet point to render correctly looked like it was going to be a problem.

I suppose if anybody wanted to pursue a third option, here are the notes I had typed up from that attempt along with the scripting I had developed:

> **Power Table Approach Notes**
>
> ```auto
> #custom method on the power table within a template to be triggered from the table's initialize extension function, and the pie charts data property change event:
> #def populateTabel(self)
> headers = ['bullets', 'label']
> bulletPoint = '•'
> chartData = []
> pieData = self.parent.getComponent('Pie Chart').data
> for row in range(pieData.rowCount):
> rowData = []
> rowData.append(bulletPoint)
> rowData.append(pieData.getValueAt(row, 0))
> chartData.append(rowData)
> self.data = system.dataset.toDataSet(headers, chartData)
> #develop a way to remove the table's outer border and add it here
> #preset bullet column width here or do it by triggering the defaultTableConfig event
> #=========================
> #Power Table to be configured in this way:
> #Header Visible = False
> #bind Background Color to its container's background color
> #Show Vertical Grid = False
> #Show Horizontal Grid = False
> #Row Selection Allowed = False
> #Column Selection Allowed = False
> #preadd columns bullets and label to table's data property
> #Set the wrapText property of the label Column to true in the Column Attributes Data dataset
> #=========================
> #def configureCell([...]): add the following code to the power table's configure cell extension function
> colors = self.parent.getComponent('Pie Chart').sectionColors
> color = colors[rowView % len(colors)]
> if colIndex == 0:
> return {'foreground': color}
> 
> ```

---

<div class="post-metadata">

**Author:** ![zxcslo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zxcslo/32/61610_2.png) [@zxcslo](https://forum.inductiveautomation.com/u/zxcslo)\
**Post date:** [February 12, 2023, 8:49am UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/15 "2023-02-12T08:49:33Z")

</div>

Well, yes, the template repeater is also **not** a universal approach.  
If there is a need for more than 5 items, then the template will need a '_correction_' like font size, label height, width, ...  
Every individual need will need the adoption of a template and repeater.  
But then, more than five or six items in Pie Chart will look... crowded...

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [February 13, 2023, 5:05am UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/16 "2023-02-13T05:05:43Z")

</div>

> [@justinedwards.jle](#):
>
> I set the font to Courier New, Plain

Quick, pedantic note - if you use the "logical" font name ["Monospaced"](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/Font.html#MONOSPACED) you will get a platform-agnostic monospace font 'for free'. In Ignition's case, it will be Noto Sans Mono which should look pretty cohesive with the rest of the platform.

---

<div class="post-metadata">

**Author:** ![zacharyw.larson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zacharyw.larson/32/23749_2.png) [@zacharyw.larson](https://forum.inductiveautomation.com/u/zacharyw.larson)\
**Post date:** [July 20, 2023, 6:34pm UTC](https://forum.inductiveautomation.com/t/pie-chart-legend-wrap-or-multiline/69613/17 "2023-07-20T18:34:37Z")

</div>

Is there an option where the "g" looks more like Monaco "g"?

I like that monospaced has 0, O, I, L, l, and i all easy to identify.  
It is good.
