# Syntax to change color of report time series chart legend

**URL:** <https://forum.inductiveautomation.com/t/syntax-to-change-color-of-report-time-series-chart-legend/99826>\
**Category:** Ignition\
**Tags:** ignition81, reporting\
**Created:** [December 13, 2024, 10:00pm UTC](https://forum.inductiveautomation.com/t/syntax-to-change-color-of-report-time-series-chart-legend/99826 "2024-12-13T22:00:58Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 13, 2024, 10:00pm UTC](https://forum.inductiveautomation.com/t/syntax-to-change-color-of-report-time-series-chart-legend/99826/1 "2024-12-13T22:00:58Z")

</div>

I have a time series chart in Ignition 8.1

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/0/7/07a177282e6c51007af645d7ab83e745e969163c.png)

I can change the limit line color from the default red to green using the following script.

```python
Limit = data['tagPath1_ReportLimit']
green = Color(0, 255, 0)
stroke = BasicStroke(2.0)

markerLimit = ValueMarker(Limit, green, stroke)

chart.getPlot().addRangeMarker(markerLimit)
```

But what is the syntax to change the limit line color shown in the legend?

---

<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:** [December 13, 2024, 10:58pm UTC](https://forum.inductiveautomation.com/t/syntax-to-change-color-of-report-time-series-chart-legend/99826/2 "2024-12-13T22:58:39Z")

</div>

I'm assuming the limit in the legend is a fake item you're inserting, since the value marker is what's actually drawing the green line?

You could probably work off the example in this post to customize the rendered legend item; you won't need all this but it should get you started:

> [@EasyChart legend: increase key line width and change colours](https://forum.inductiveautomation.com/t/easychart-legend-increase-key-line-width-and-change-colours/15337/6):
>
> Well, that ended up being way more involved than I figured it would be. But because I enjoyed myself: (Preemptive disclaimer: Don’t even think of trying to call in to support if this doesn’t work for you) from org.jfree.chart.renderer.xy import XYLineAndShapeRenderer from org.jfree.chart import LegendItem legend = chart.getLegend() plot = chart.getPlot() renderer = plot.getRenderer() class CustomRenderer(XYLineAndShapeRenderer): def getLegendItem(self, dataset, series): original =…

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 13, 2024, 11:06pm UTC](https://forum.inductiveautomation.com/t/syntax-to-change-color-of-report-time-series-chart-legend/99826/3 "2024-12-13T23:06:47Z")

</div>

Heh heh, I have been trying to work off that example actually but not having any luck. The legend item is "fake" in the sense that I generate the "limit line" from a tag property.

This is my full script that gets called:

```python
def gwConfigureChart(data, chart):
	"""Adds a limit line to a report chart."""
	from java.awt import Color
	from java.awt import BasicStroke;
	from org.jfree.chart.plot import ValueMarker
	import math
	
	plot = chart.getXYPlot()
	
	dataset = plot.getDataset()
	
	lowerBound = chart.getPlot().getRangeAxis().getLowerBound()
	upperBound = chart.getPlot().getRangeAxis().getUpperBound()
	
	Limit = data['tagPath1_ReportLimit']
	ReportDataAboveLimit = data['tagPath1_ReportDataAboveLimit']
	
	red = Color(255, 0, 0)
	green = Color(0, 255, 0)
	
	stroke = BasicStroke(2.0)
	
	if Limit <= lowerBound:
		chart.getPlot().getRangeAxis().setLowerBound(Limit - math.floor(Limit * 0.05))
		
	if Limit >= upperBound:
		chart.getPlot().getRangeAxis().setUpperBound(Limit + math.ceil(Limit * 0.05))
	
	if ReportDataAboveLimit:
		if data['tagPath1_MinValue'] > Limit:
			markerLimit = ValueMarker(Limit, green, stroke)
		else:
			markerLimit = ValueMarker(Limit, red, stroke)
	else:
		if data['tagPath1_MaxValue'] > Limit:
			markerLimit = ValueMarker(Limit, red, stroke)
		else:
			markerLimit = ValueMarker(Limit, green, stroke)

	chart.getPlot().addRangeMarker(markerLimit)
	
	plot.getRangeAxis().setLabel(data['tagPath1_ReportYAxisTitle'])
```

which generates this:

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/0/a/0afbfa34297ec163dbdf013aa4b9f9a33508c354.png)

and the modified code:

```python
def gwConfigureChart(data, chart):
	"""Adds a limit line to a report chart."""
	from java.awt import Color
	from java.awt import BasicStroke;
	from org.jfree.chart.plot import ValueMarker
	import math
	
	## modified
	from org.jfree.chart.renderer.xy import XYLineAndShapeRenderer
	from org.jfree.chart import LegendItem
	legend = chart.getLegend()
	plot = chart.getPlot()
	renderer = plot.getRenderer()
	
	class CustomRenderer(XYLineAndShapeRenderer):
		def getLegendItem(self, dataset, series):
			original = renderer.getLegendItem(dataset, series)
			new = LegendItem(
				original.getLabel(),
				original.getDescription(),
				original.getToolTipText(),
				"", #urlText
				original.getShape(),
				original.getLinePaint(), #set fill paint to line paint
				original.getOutlineStroke(),
				original.getOutlinePaint()
			)
			new.setSeriesIndex(series)
			new.setDatasetIndex(dataset)
			return new
		
		def getLegendItems(self):
			collection = XYLineAndShapeRenderer.getLegendItems(self)
			for ds in range(plot.getDatasetCount()):
				for series in range(plot.getSeriesCount()):
					legend = self.getLegendItem(ds, series)
					collection.add(legend)
			return collection

	dataset = plot.getDataset()
	
	lowerBound = chart.getPlot().getRangeAxis().getLowerBound()
	upperBound = chart.getPlot().getRangeAxis().getUpperBound()
	
	Limit = data['tagPath1_ReportLimit']
	ReportDataAboveLimit = data['tagPath1_ReportDataAboveLimit']
	
	red = Color(255, 0, 0)
	green = Color(0, 255, 0)
	
	stroke = BasicStroke(2.0)
	
	if Limit <= lowerBound:
		chart.getPlot().getRangeAxis().setLowerBound(Limit - math.floor(Limit * 0.05))
		
	if Limit >= upperBound:
		chart.getPlot().getRangeAxis().setUpperBound(Limit + math.ceil(Limit * 0.05))
	
	if ReportDataAboveLimit:
		if data['tagPath1_MinValue'] > Limit:
			markerLimit = ValueMarker(Limit, green, stroke)
		else:
			markerLimit = ValueMarker(Limit, red, stroke)
	else:
		if data['tagPath1_MaxValue'] > Limit:
			markerLimit = ValueMarker(Limit, red, stroke)
		else:
			markerLimit = ValueMarker(Limit, green, stroke)

	chart.getPlot().addRangeMarker(markerLimit)
	
	plot.getRangeAxis().setLabel(data['tagPath1_ReportYAxisTitle'])
	
	newRenderer = CustomRenderer(True, False)
	newRenderer.setBaseSeriesVisibleInLegend(True)
	legend.setSources([newRenderer])
```

which currently generates the same thing.

I don't really understand what a renderer is or how to use it appropriately [obviously].

Any help is appreciated.

---

<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:** [December 13, 2024, 11:18pm UTC](https://forum.inductiveautomation.com/t/syntax-to-change-color-of-report-time-series-chart-legend/99826/4 "2024-12-13T23:18:36Z")

</div>

Try (this is totally untested) poking in a fake LegendItem to the LegendItemCollection that's being returned in `getLegendItems`:

```python
	red = Color(255, 0, 0)
	green = Color(0, 255, 0)
	
	class CustomRenderer(XYLineAndShapeRenderer):
		def getLegendItem(self, dataset, series):
			original = renderer.getLegendItem(dataset, series)
			new = LegendItem(
				original.getLabel(),
				original.getDescription(),
				original.getToolTipText(),
				"", #urlText
				original.getShape(),
				original.getLinePaint(), #set fill paint to line paint
				original.getOutlineStroke(),
				original.getOutlinePaint()
			)
			new.setSeriesIndex(series)
			new.setDatasetIndex(dataset)
			return new
		
		def getLegendItems(self):
			collection = XYLineAndShapeRenderer.getLegendItems(self)
			for ds in range(plot.getDatasetCount()):
				for series in range(plot.getSeriesCount()):
					legend = self.getLegendItem(ds, series)
					collection.add(legend)

			### add a new, fake legend item
			collection.add(LegendItem(
				"Limit",
				None,
				None,
				None,
				collection[0].shape
				red,
				collection[0].outlineStroke,
				collection[0].outlinePaint
			))

			return collection

```

Basically, you're convincing the chart to render an additional item it doesn't have.

Disclaimer: The easier path forward at this point might be to just have a static value dataset (created by script in your report data config) that you just attach to the same chart, no need to get so fancy in `configureChart`.

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 13, 2024, 11:27pm UTC](https://forum.inductiveautomation.com/t/syntax-to-change-color-of-report-time-series-chart-legend/99826/5 "2024-12-13T23:27:54Z")

</div>

Well I tested it and no luck.

```python
def gwConfigureChart(data, chart):
	"""Adds a limit line to a report chart."""
	from java.awt import Color
	from java.awt import BasicStroke;
	from org.jfree.chart.plot import ValueMarker
	import math
	
	## modified
	from org.jfree.chart.renderer.xy import XYLineAndShapeRenderer
	from org.jfree.chart import LegendItem
	legend = chart.getLegend()
	plot = chart.getPlot()
	renderer = plot.getRenderer()
	
	red = Color(255, 0, 0)
	green = Color(0, 255, 0)
	
	class CustomRenderer(XYLineAndShapeRenderer):
		def getLegendItem(self, dataset, series):
			original = renderer.getLegendItem(dataset, series)
			new = LegendItem(
				original.getLabel(),
				original.getDescription(),
				original.getToolTipText(),
				"", #urlText
				original.getShape(),
				original.getLinePaint(), #set fill paint to line paint
				original.getOutlineStroke(),
				original.getOutlinePaint()
			)
			new.setSeriesIndex(series)
			new.setDatasetIndex(dataset)
			return new
		
		def getLegendItems(self):
			collection = XYLineAndShapeRenderer.getLegendItems(self)
			for ds in range(plot.getDatasetCount()):
				for series in range(plot.getSeriesCount()):
					legend = self.getLegendItem(ds, series)
					collection.add(legend)
			
			### add a new, fake legend item
			collection.add(LegendItem(
				"Limit",
				None,
				None,
				None,
				collection.get(0).shape,
				red,
				collection.get(0).outlineStroke,
				collection.get(0).outlinePaint
			))
			
			return collection

	dataset = plot.getDataset()
	
	lowerBound = chart.getPlot().getRangeAxis().getLowerBound()
	upperBound = chart.getPlot().getRangeAxis().getUpperBound()
	
	Limit = data['tagPath1_ReportLimit']
	ReportDataAboveLimit = data['tagPath1_ReportDataAboveLimit']
	
	
	
	stroke = BasicStroke(2.0)
	
	if Limit <= lowerBound:
		chart.getPlot().getRangeAxis().setLowerBound(Limit - math.floor(Limit * 0.05))
		
	if Limit >= upperBound:
		chart.getPlot().getRangeAxis().setUpperBound(Limit + math.ceil(Limit * 0.05))
	
	if ReportDataAboveLimit:
		if data['tagPath1_MinValue'] > Limit:
			markerLimit = ValueMarker(Limit, green, stroke)
		else:
			markerLimit = ValueMarker(Limit, red, stroke)
	else:
		if data['tagPath1_MaxValue'] > Limit:
			markerLimit = ValueMarker(Limit, red, stroke)
		else:
			markerLimit = ValueMarker(Limit, green, stroke)

	chart.getPlot().addRangeMarker(markerLimit)
	
	plot.getRangeAxis().setLabel(data['tagPath1_ReportYAxisTitle'])
	
	newRenderer = CustomRenderer(True, False)
	newRenderer.setBaseSeriesVisibleInLegend(True)
	legend.setSources([newRenderer])
	
```

Resulting error:

```python
17:25:24.041 [AWT-EventQueue-0] WARN reporting.TimeseriesChart - Error drawing component.
org.python.core.PyException: TypeError: 'org.jfree.chart.LegendItemCollection' object is unsubscriptable
```

and the timeseries chart is now blank.

Yes, I think I'll take a look at inserting a static dataset.

---

<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:** [December 13, 2024, 11:28pm UTC](https://forum.inductiveautomation.com/t/syntax-to-change-color-of-report-time-series-chart-legend/99826/6 "2024-12-13T23:28:55Z")

</div>

> [@bmeyers](#):
>
> `collection[0]`

Try swapping these for `.get(0)`, as in `collection.get(0).shape` and so on; should fix that immediate error.

I got my Kotlin and Python mixed up 😄

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [December 13, 2024, 11:32pm UTC](https://forum.inductiveautomation.com/t/syntax-to-change-color-of-report-time-series-chart-legend/99826/7 "2024-12-13T23:32:58Z")

</div>

Hey, it did something. Thanks for the help.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/d/a/dacdb1711036c4772dbf3b646e61258e6c82c6ba.png)
