-
Notifications
You must be signed in to change notification settings - Fork 163
Description
When using a FastXYSeries on a plot with fixed domain boundaries but auto range boundaries, the bounds are incorrectly calculated in SeriesUtils.
Below is a modified version of SimpleXYPlotActivity which demonstrates the issue.
package com.androidplot.demos;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import com.androidplot.xy.BoundaryMode;
import com.androidplot.xy.FastXYSeries;
import com.androidplot.xy.LineAndPointFormatter;
import com.androidplot.xy.RectRegion;
import com.androidplot.xy.XYGraphWidget;
import com.androidplot.xy.XYPlot;
import com.google.common.math.Stats;
import java.text.DecimalFormat;
import java.util.ArrayList;
/**
* A simple XYPlot
*/
public class SimpleXYPlotActivity extends Activity {
private XYPlot plot;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_xy_plot_example);
// initialize our XYPlot reference:
plot = (XYPlot) findViewById(R.id.plot);
// create a couple arrays of y-values to plot:
final ArrayList<Integer> times = new ArrayList<>();
final ArrayList<Integer> values = new ArrayList<>();
for (int i = 0; i < 10; i++) {
times.add(i);
values.add(2 * i);
}
FastXYSeries fastXYSeries = new FastXYSeries(){
@Override
public int size() {
return times.size();
}
@Override
public Number getX(int index) {
return times.get(index);
}
@Override
public Number getY(int index) {
return values.get(index);
}
@Override
public String getTitle() {
return "Isaac's crazy thing";
}
@Override
public RectRegion minMax() {
Stats yStats = Stats.of(values);
return new RectRegion(
times.get(0),
times.get(times.size() - 1),
yStats.min(),
yStats.max()
);
}
};
// add a new series' to the xyplot:
plot.addSeries(fastXYSeries, new LineAndPointFormatter(Color.RED, Color.BLUE, null, null));
plot.setDomainLowerBoundary(5, BoundaryMode.FIXED);
plot.setDomainUpperBoundary(9, BoundaryMode.FIXED);
plot.getGraph().getLineLabelStyle(XYGraphWidget.Edge.BOTTOM).setFormat(new DecimalFormat());
}
}
SeriesUtils.minMax will return bounds with a minimum Y and maximum Y both set to the maxY or the series.
public static RectRegion minMax(XYConstraints constraints, XYSeries... seriesArray) {
final RectRegion bounds = new RectRegion();
// make sure there is series data to iterate over:
if (seriesArray != null && seriesArray.length > 0) {
// iterate over each series
for (XYSeries series : seriesArray) {
// if this is an advanced xy series then minMax have already been calculated for us:
if(series instanceof FastXYSeries) {
final RectRegion seriesBounds = ((FastXYSeries) series).minMax();
if (seriesBounds == null) {
continue;
}
if(constraints == null) {
bounds.union(seriesBounds);
} else {
//the following condition will be false
if (constraints.contains(seriesBounds.getMinX(), seriesBounds.getMinY())) {
bounds.union(seriesBounds.getMinX(), seriesBounds.getMinY());
}
//the following condition will be true
if (constraints.contains(seriesBounds.getMaxX(), seriesBounds.getMaxY())) {
bounds.union(seriesBounds.getMaxX(), seriesBounds.getMaxY());
}
}
} else if (series.size() > 0) {
for (int i = 0; i < series.size(); i++) {
final Number xi = series.getX(i);
final Number yi = series.getY(i);
// if constraints have been set, make sure this xy coordinate exists within them:
if (constraints == null || constraints.contains(xi, yi)) {
bounds.union(xi, yi);
}
}
}
}
}
return bounds;
}
I've fixed it by writing a method which constrains the seriesBounds in my fork's branch. I'm not sure this is the right fix though, so I didn't make a pull request. My linked change puts data back on the screen but the y range still includes the full extents of the FastXYSeries instead of the constrained FastXYSeries. I wondered if there shouldn't be a method like Region yMinMax(Number xMin, Number xMax) to better calculate that or if I should just tell my implementations of FastXYSeries to consider the current boundary settings while calculating minmax. Thoughts?
