I work on ioGAS which uses JFreeChart a lot. We needed a Tukey plot, to identify outliers in Geochem data. Rather than starting from scratch it was easier to use the JFree framework.
Essentially I have written a new renderer to replace the existing one. See header below.
If this is useful I can send the source code (somewhere?).
I had to make a couple of very minor changes to supporting classes also.
Cheers
Rob Wall.
/**
*
* A box-and-whisker renderer that displays all the outliers and far outliers individually,
* like a regular Tukey Plot. (based on the JFreeChart BoxAndWhiskerRenderer that */
public class TukeyBoxAndWhiskerRenderer extends AbstractCategoryItemRenderer
implements Cloneable, PublicCloneable,
Serializable {
I have written a new BoxAndWhisker Renderer -
-
- JFreeChart Project Leader
- Posts: 11734
- Joined: Fri Mar 14, 2003 10:29 am
- antibot: No, of course not.
- Contact:
Hi Rob,
Great! If you post the code to the Patch Manager at SourceForge, I'll take a look at it (and I'm sure some others will too):
http://sourceforge.net/tracker/?group_i ... tid=315494
Great! If you post the code to the Patch Manager at SourceForge, I'll take a look at it (and I'm sure some others will too):
http://sourceforge.net/tracker/?group_i ... tid=315494
David Gilbert
JFreeChart Project Leader
Read my blog
Support JFree via the Github sponsorship program
JFreeChart Project Leader


ok - will post when i get password
I'll post when I get a password back from sourceforge...
All I have done is:::
Added: TukeyBoxAndWhiskerRenderer (this is the new bit)
Changes:
* BoxAndWhiskerCalculator.java
Have changed tukey constants from 1.5 / 2 to 1.5 /3
Have made this class calc absolute min and max also.
* BoxAndWhiskerItem.java
Stores the absolute min and max (constructors and
accessors changed)
* DefaultBoxAndWhiskerCategoryDataset.java
Added accessors to get the absolute min and max
* BoxAndWhiskerItemTests.java
* DefaultBoxAndWhiskerCategoryDatasetTests.java
Added some weak tests to these two classes
===============
Here is guts of change from existing renderer if anyone is desperate...
// draw median...
Number yMedian = bawDataset.getMedianValue(row, column);
if (yMedian != null) {
double yyMedian = rangeAxis.valueToJava2D(
yMedian.doubleValue(), dataArea, location
);
g2.draw(
new Line2D.Double(
xx, yyMedian, xx + state.getBarWidth(), yyMedian
)
);
}
// draw yOutliers (all of them)
double maxAxisValue = rangeAxis.valueToJava2D(
rangeAxis.getUpperBound(), dataArea, location
) + aRadius;
double minAxisValue = rangeAxis.valueToJava2D(
rangeAxis.getLowerBound(), dataArea, location
) - aRadius;
g2.setPaint(p);
double oRadius = state.getBarWidth() / 6;
List outliers = new ArrayList();
List farOutliers = new ArrayList();
List yOutliers = bawDataset.getOutliers(row, column);
if (yOutliers != null) {
for (int i = 0; i < yOutliers.size(); i++) {
double outlier = ((Number) yOutliers.get(i)).doubleValue();
Number minOutlier = bawDataset.getMinOutlier(row, column);
Number maxOutlier = bawDataset.getMaxOutlier(row, column);
Number minRegular = bawDataset.getMinRegularValue(row, column);
Number maxRegular = bawDataset.getMaxRegularValue(row, column);
if (outlier > maxOutlier.doubleValue()) {
addOutlier(state, dataArea, rangeAxis, xx, location, farOutliers, outlier, oRadius);
}
else if (outlier < minOutlier.doubleValue()) {
addOutlier(state, dataArea, rangeAxis, xx, location, farOutliers, outlier, oRadius);
}
else if (outlier > maxRegular.doubleValue()) {
addOutlier(state, dataArea, rangeAxis, xx, location, outliers, outlier, oRadius);
}
else if (outlier < minRegular.doubleValue()) {
addOutlier(state, dataArea, rangeAxis, xx, location, outliers, outlier, oRadius);
}
}
//draw near outliers as circles
for (Iterator iterator = outliers.iterator(); iterator.hasNext();) {
Outlier outlier = (Outlier) iterator.next();
Point2D point = outlier.getPoint();
drawEllipse(point, outlier.getRadius(), g2);
}
//draw far outliers as triangles
for (Iterator iterator = farOutliers.iterator(); iterator.hasNext();) {
Outlier outlier = (Outlier) iterator.next();
Point2D point = outlier.getPoint();
drawUpTriangle(point, outlier.getRadius(), g2);
}
}
// collect entity and tool tip information...
if (state.getInfo() != null) {
EntityCollection entities
All I have done is:::
Added: TukeyBoxAndWhiskerRenderer (this is the new bit)
Changes:
* BoxAndWhiskerCalculator.java
Have changed tukey constants from 1.5 / 2 to 1.5 /3
Have made this class calc absolute min and max also.
* BoxAndWhiskerItem.java
Stores the absolute min and max (constructors and
accessors changed)
* DefaultBoxAndWhiskerCategoryDataset.java
Added accessors to get the absolute min and max
* BoxAndWhiskerItemTests.java
* DefaultBoxAndWhiskerCategoryDatasetTests.java
Added some weak tests to these two classes
===============
Here is guts of change from existing renderer if anyone is desperate...
// draw median...
Number yMedian = bawDataset.getMedianValue(row, column);
if (yMedian != null) {
double yyMedian = rangeAxis.valueToJava2D(
yMedian.doubleValue(), dataArea, location
);
g2.draw(
new Line2D.Double(
xx, yyMedian, xx + state.getBarWidth(), yyMedian
)
);
}
// draw yOutliers (all of them)
double maxAxisValue = rangeAxis.valueToJava2D(
rangeAxis.getUpperBound(), dataArea, location
) + aRadius;
double minAxisValue = rangeAxis.valueToJava2D(
rangeAxis.getLowerBound(), dataArea, location
) - aRadius;
g2.setPaint(p);
double oRadius = state.getBarWidth() / 6;
List outliers = new ArrayList();
List farOutliers = new ArrayList();
List yOutliers = bawDataset.getOutliers(row, column);
if (yOutliers != null) {
for (int i = 0; i < yOutliers.size(); i++) {
double outlier = ((Number) yOutliers.get(i)).doubleValue();
Number minOutlier = bawDataset.getMinOutlier(row, column);
Number maxOutlier = bawDataset.getMaxOutlier(row, column);
Number minRegular = bawDataset.getMinRegularValue(row, column);
Number maxRegular = bawDataset.getMaxRegularValue(row, column);
if (outlier > maxOutlier.doubleValue()) {
addOutlier(state, dataArea, rangeAxis, xx, location, farOutliers, outlier, oRadius);
}
else if (outlier < minOutlier.doubleValue()) {
addOutlier(state, dataArea, rangeAxis, xx, location, farOutliers, outlier, oRadius);
}
else if (outlier > maxRegular.doubleValue()) {
addOutlier(state, dataArea, rangeAxis, xx, location, outliers, outlier, oRadius);
}
else if (outlier < minRegular.doubleValue()) {
addOutlier(state, dataArea, rangeAxis, xx, location, outliers, outlier, oRadius);
}
}
//draw near outliers as circles
for (Iterator iterator = outliers.iterator(); iterator.hasNext();) {
Outlier outlier = (Outlier) iterator.next();
Point2D point = outlier.getPoint();
drawEllipse(point, outlier.getRadius(), g2);
}
//draw far outliers as triangles
for (Iterator iterator = farOutliers.iterator(); iterator.hasNext();) {
Outlier outlier = (Outlier) iterator.next();
Point2D point = outlier.getPoint();
drawUpTriangle(point, outlier.getRadius(), g2);
}
}
// collect entity and tool tip information...
if (state.getInfo() != null) {
EntityCollection entities
-
- Posts: 59
- Joined: Fri Feb 23, 2007 7:41 am
Hi,
The changes made are just the ones we need for our project. It would also be nice
1) to have setters for the paint used to draw outliers and farouts.
2) The Radius of the mean, outlier and farout should not depend on the width of the box. When the number of boxes are few (for e.g. 1 -3 ), the radius is very large and the resulting plot does not look good.
Regards,
Priya
The changes made are just the ones we need for our project. It would also be nice
1) to have setters for the paint used to draw outliers and farouts.
2) The Radius of the mean, outlier and farout should not depend on the width of the box. When the number of boxes are few (for e.g. 1 -3 ), the radius is very large and the resulting plot does not look good.
Regards,
Priya
-
- JFreeChart Project Leader
- Posts: 11734
- Joined: Fri Mar 14, 2003 10:29 am
- antibot: No, of course not.
- Contact:
OK. I don't use this chart type myself, so patches from others are welcome.
David Gilbert
JFreeChart Project Leader
Read my blog
Support JFree via the Github sponsorship program
JFreeChart Project Leader


I will post changes
ok I am trying again to get a sourceforge password, so I can submit the changes properly.