I’ve got one Easy Chart overlayed on top of a second Easy Chart. The Background Color and Plot Background properties are set to transparent for the Easy Chart at the front of the Z-order so that the Easy Chart behind it can be seen. Each chart has only 1 pen. One chart has its Y-axis labels on the left and the other has its Y-axis labels on the right. One chart has its X-axis labels on the bottom and the other has its X-axis labels on the top. Both charts will always show data for the same duration (e.g. 1 hr) but could have differing start times. I’ve set the X and Y position values of the two charts so that their plot areas align perfectly. The problem I have is that when I select a different tag for one of the charts, the width of the plot area for that chart expands (anywhere from 3 to 6 pixels in my testing). Is there a way to prevent the plot width from changing?
There isn’t really a need for the second chart. In my experience you would be better off setting the range axis for the second tag to be on the right. If they don’t share the same domain units (not really sure how having different units would work) you can add a second domain axis and set it to be on the top.
Honestly, I think they need to share the exact same domain axis(in most cases this is the x-axis) for the chart to really show useful comparisons.
Also, unless there is some other specific reason you’re using the Easy chart, I find the standard chart component to be far more friendly in situations like this.
What I’m trying to do is allow tag data from one piece of equipment to be displayed on the same chart as tag data from a downstream piece of equipment, but with different domain (X-axis) values. The production process is a continuous stream and we’re measuring the physical characteristics of the product as it moves through the process. For example, say we’re measuring an upstream oven temperature and a downstream oven temperature and we know the time it takes the product 10 minutes to get from the 1st oven to the 2nd oven. We can then plot both oven temperatures on the same chart but with a 10 minute offset in the 2 X-axes and see both temperatures to which a specific part of the stream was exposed.
Your suggestion makes a lot of sense, but I don’t see how to add a second domain axis or how I would associate a pen with a 2nd domain axis. I’m guessing it’s going to take more exploitation of the jfree chart in the configureChart extension function, but I’m just not familiar with that API. Any additional guidance would be appreciated.
So the simplest way to achieve this is to use the Standard Chart Components Chart Customizer.
- Add an additional Dataset
- Add an additional X-Axis
- Configure the Axis Location to be on the TOP
- Add an additional Y-Axis
- Configure the Axis Location to be on the Right
- Assign the X and Y axis to the dataset in the Dataset Properties Tab
Once you’ve done this all you need to do is generate the two datasets of data and assign them. The new dataset will appear as a custom property on the chart component, you can assign Tag History Bindings to the datasets. No scripting is needed.
Of course you can also accomplish a similar thing with scripting if you so desire, though it is far from trivial.
Here is a sample that assumes you have a dataset property on the parent container of the chart (I used a standard chart component to write the code, but the code will work on an easy chart as well just may need to tweak it to get to the right container). This is by no means a complete solution but it should be enough to get someone started should they really want to use an easy chart with multiple datasets.
from org.jfree.data.xy import DefaultXYDataset from org.jfree.chart.axis import DateAxis,AxisLocation from org.jfree.chart import LegendItem from java.awt import Color #get a reference to the plot plot = chart.getPlot() #create a new Dataset to hold the second set of data newDs = DefaultXYDataset() #The series data must be an array of length 2 where each element is a double array of the same length #The date axis uses milliseconds since epoch the system.date.toMillis() function will return this value seriesData = [[system.date.toMillis(self.parent.data2.getValueAt(row,0)) for row in range(self.parent.data2.rowCount)],[self.parent.data2.getValueAt(row,1) for row in range(self.parent.data2.rowCount)]] #Add the series data to the dataset and assign the dataset to the plot. newDs.addSeries('Ouptut Temp',seriesData) #an index other than 0 must be supplied here otherwise the original dataset will be overwritten plot.setDataset(1,newDs) #Add a new domain axis to the plot and map the dataset to it, an index other than 0 must be used for the new Axis #Cloning the existing DomainAxis makes this a bit simpler plot.setDomainAxis(1,plot.getDomainAxis(0).clone()) plot.setDomainAxisLocation(1,AxisLocation.TOP_OR_LEFT) plot.mapDatasetToDomainAxis(1,1) #Add a new range axis to the plot and map the dataset to it, an index other than 0 must be used for the new Axis #Cloning the existing RangeAxis makes this a bit simpler plot.setRangeAxis(1,plot.getRangeAxis(0).clone()) plot.setRangeAxisLocation(1,AxisLocation.BOTTOM_OR_RIGHT) plot.mapDatasetToRangeAxis(1,1) #Add a legend item for the new dataset legItems = plot.getLegendItems() newLegItem = LegendItem(newDs.getSeriesKey(0),newDs.getSeriesKey(0),'','',legItems.get(0).getLine(),legItems.get(0).getLineStroke(),Color.red) legItems.add(newLegItem) plot.setFixedLegendItems(legItems) #Add a new renderer for the new dataset and change the color #Cloning the existing XYItemRenderer makes this a bit simpler r = plot.getRenderer().clone() r.setSeriesPaint(0,Color.red) plot.setRenderer(1,r,True)
That’s impressive, thank you. I like the idea of using the standard chart, with a lot less scripting. I’ll take a look at the pros and cons, though.
I really appreciate your help.
Using the Chart component and adding the required number of datasets and axes works really well to meet my requirements for displaying analog historian data. An additional requirement is to include discrete data not necessarily from the historian database and I’m finding that the Chart component draws the trend line as if I want it to interpolate values between the provided data points. Is there a way to force it to render the trend line as a horizontal line between the data points in the provided dataset? If not, I may have to manipulate the dataset to get it to render appropriately.
Are you wanting to add a horizontal marker (single horizontal line across the whole chart), or are you trying to represent step changes in discrete data?
Step changes for discrete data.
So for the dataset that has the discrete data in it, set the Renderer to XY Step Renderer
Thank you, I think it’s working as desired with the following code in the configureChart extension function:
from org.jfree.chart import renderer from org.jfree.chart.renderer.xy import XYStepRenderer from org.jfree.chart.renderer.xy import StandardXYItemRenderer # This information would actually come from a source outside this script. tag0Type = 'Discrete' tag1Type = 'Discrete' # Initialize the renderes for each tag. tag0Renderer = StandardXYItemRenderer() tag1Renderer = StandardXYItemRenderer() # If the tag should be rendered with step changes then modify the renderer type. if tag0Type == 'Discrete': tag0Renderer = XYStepRenderer() if tag1Type == 'Discrete': tag1Renderer = XYStepRenderer() # Get a reference to the plot. plot = chart.getPlot() # Set the color of the 2 new renderers to the original colors. tag0Renderer.setSeriesPaint(0, plot.getRendererForDataset(plot.getDataset(0)).getSeriesPaint(0)) tag1Renderer.setSeriesPaint(0, plot.getRendererForDataset(plot.getDataset(1)).getSeriesPaint(0)) plot.setRenderers([tag0Renderer, tag1Renderer])