Would like XYSeries plots to support Fixed Range as TimesSer

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
Bob Orchard

Would like XYSeries plots to support Fixed Range as TimesSer

Post by Bob Orchard » Thu Aug 22, 2002 1:33 pm

The FixedAutoRange attribute that can be specified in a ValueAxis and therefore available to a DateAxis and a NumberAxis allows one to have a scrolling window of fixed size to display data in a manner like a ticker tape. This is demonstrated in the DynamicDataDemo example provided with JFreeChart. However, this only works for a DateAxis (more specifically for the HorizontalDateAxis) and not for a NumberAxis (and in particular not for a HorizontalNumberAxis).

To address this I modified the HorizontalNumberAxis.java file.

/**
* Rescales the axis to ensure that all data is visible.
*/
protected void autoAdjustRange() {

if (plot==null) return; // no plot, no data

if (plot instanceof HorizontalValuePlot) {
HorizontalValuePlot hvp = (HorizontalValuePlot)plot;

Range r = hvp.getHorizontalDataRange();
if (r==null) r = new Range(DEFAULT_MINIMUM_AXIS_VALUE, DEFAULT_MAXIMUM_AXIS_VALUE);
double upper = r.getUpperBound();
double lower = r.getLowerBound();
double range = upper-lower;

*** // if fixed auto range then calc the required range
*** if (this.fixedAutoRange>0.0) {
*** lower = upper - (long)fixedAutoRange;
*** }
// otherwise ensure the autorange is at least <minRange> in size...
else
{ double minRange = this.autoRangeMinimumSize.doubleValue();
if (range<minRange) {
upper = (upper+lower+minRange)/2;
lower = (upper+lower-minRange)/2;
}



}

The 4 lines of code with *** are all that was changed. I realize that this is pretty minimal and I made some very major assumptions about the interaction with autoRangeIncludesZero and autoRangeStickyZero etc. but this seemed the logical behavior. I.e. that if a fixed auto range is specified then including zeros and sticky zeros are not relevant. At any rate it would be useful I think if something like this could be done for the NumberAxis. Comments? Suggestions for improvement? Was there a reason it was never done in the first place?

Related to this is the ability to delete portions of a series data set. For example with a fixed auto range for a times series data set one might be appending new data as it arrives every second or so. But after some time the data set will become extremely large (we might have a program running continuously tracking the temperature or some other parameter. So it is necessary to remove some of the older values. The TimesSeries class has a delete method that allows this to be done. So again it makes sense for the XYSeries to also have this feature. To do this I modified 2 files in JCommon:

XYSeries.java
-------------

/**
* Deletes data between the start and end index.
*/
public XYSeries delete(int start, int end) {

XYSeries removed = this.createCopy(start, end);

for (int i=0; i<removed.getItemCount(); i++) {
data.remove(start);
}
fireSeriesChanged();
return removed;
}

This is similar to the routine in TimeSeries.java so it also returns the Series that was removed from the original series. My thought on this is that it should just return a void. The overhead for this default behavior doesn’t seem justified since most of the time it will not be used. If one really needs it they can use the CreateCopy method themselves to get the portion that will be removed. I also had to add the CreateCopy method and make the class cloneable.

/**
* Returns a clone of the XY series.
*/
public Object clone() {

Object clone = createCopy(0, this.getItemCount()-1);
return clone;

}

/**
* Creates a new XY series by copying a subset of the data in this series.
*/
public XYSeries createCopy(int start, int end) {

XYSeries copy = (XYSeries)super.clone();
copy.listeners = new java.util.ArrayList();
copy.propertyChangeSupport = new PropertyChangeSupport(copy);

copy.data = new java.util.ArrayList();
if (data.size()>0) {
for (int index=start; index<=end; index++) {
XYDataPair pair = (XYDataPair)this.data.get(index);
XYDataPair clone = (XYDataPair)pair.clone();
try {
copy.add(clone);
}
catch (SeriesException e) {
System.err.println("XYSeries.createCopy(): unable to add cloned data pair.");
}
}
}

return copy;

}

and because of this I had to make the XYDataPair cloneable as well.

XYDataPair.java


Now this whole idea of modifying a series data set (or other data sets I suppose) can lead to some issues wrt safe display of the data. If one does a clear of an XYSeries or TimeSeries (or a delete) of some portion of the data then it is possible for the asynchronous drawing routines to cause an exception, most likely an out of bounds error. For example, if one adds a value to the data set and the graph is signaled to be redrawn, but before the redraw is completed the data set is modified (some elements removed) then the redraw can cause an exception. This I know since it happened when I deleted some elements from the data set. It is a timing issue so won’t always happen. When I changed from add to end of dataset, then delete first element I sometimes saw the problem. If I deleted from the data set first, then added to the end the problem never occurred. It appears that the graphics system obtained the length of the dataset and was iterating on it to draw the graph … was interrupted … and by the time it resumed the data set had one less element than it expected. This is a more general problem, perhaps a bug of the 2D graphics package. I’m not sure. Any comments?

Perhaps the ‘safe’ approach it to require users to copy the data set minus the elements to be deleted, then add the new elements and then replace the old dataset in the plot with the new one. This of course has other issues such as performance, especially if the data sets are large.

Cheers, bob.

Bob Orchard

Re: Would like XYSeries plots to support Fixed Range as Time

Post by Bob Orchard » Mon Aug 26, 2002 1:26 pm

Any comments on this?

David Gilbert

Re: Would like XYSeries plots to support Fixed Range as Time

Post by David Gilbert » Mon Aug 26, 2002 9:59 pm

Hi Bob,

I will have some time to look at this one tomorrow.

Regards,

DG

David Gilbert

Re: Would like XYSeries plots to support Fixed Range as Time

Post by David Gilbert » Tue Aug 27, 2002 5:54 pm

Hi Bob,

I've updated XYSeries as you've suggested. The fixedAutoRange doesn't seem as useful (to me) on XYSeries compared to a time series, but it doesn't hurt for it to be there.

I agree with you on the return value for the delete(...) method, the code worked that way originally because I was focussed on something else other than writing clean code (so thanks for the feedback!). I've made the new delete method return void, I hope I remember to go back and change BasicTimeSeries also.

The timing issue you refer to, I think will require some thread synchronisation code to solve. I've done some reading about it, but need to research a little further before I dive in and make too many changes.

Regards,

DG

Bob Orchard

Re: Would like XYSeries plots to support Fixed Range as Time

Post by Bob Orchard » Thu Aug 29, 2002 2:15 pm

I appreciate the effort involved in this ..... a lot of users with a lot of requests.

I agree that the fixedAutoRange is less useful for XYSeries but I actually found it simpler to use than time series in a case where the time between y values wasn't really important.

The synchronization problem might be tricky. Swing doesn't like threads ... at least it didn't and I recall having to work hard to get Swing to behave properly with an old project. In particular I used thing like:

SwingUtilities.invokeAndWait( rcbThread );
SwingUtilities.invokeLater( vapcThread );
SwingUtilities.invokeAndWait( sstThread );

where the threads were things like:

class ViewAreaPaintComponentThread implements Runnable
{
public void run()
{
// paint the truck driving area
parent.viewArea.paintComponent(parent.viewArea.getGraphics());
}
}

etc.

Cheers, Bob.

Locked