Remove outlies of boxplot, thanks!

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
lamz138138
Posts: 3
Joined: Wed Nov 25, 2015 4:48 pm
antibot: No, of course not.

Remove outlies of boxplot, thanks!

Post by lamz138138 » Wed Nov 25, 2015 5:22 pm

Hi, I had learn to use JFreeChart, and it had helped me a lot!

Now I am strugging with boxplot, and I faild to sovle the problem after goolgling several days. Any suggestion would be gratefull!

My questions are: 1) How can I remove the outliners in the boxplot? 2) Can I draw a circle (line) to each box like mean or median?

So I try to make a new Java script extend BoxAndWhiskerRenderer, and rewrite the metod of drawHighFarOut, drawLowFarOut, but it doesn't work. Also, I think I can add some function in this new class to add new circle or line, following is what I had done:

1) Install JFreeChart:
a) Cp *jar file in lib to WEB-INF/lib;
b) add following code to web.xml:
<servlet>
<servlet-name>DisplayChart</servlet-name>
<servlet-class>org.jfree.chart.servlet.DisplayChart</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DisplayChart</servlet-name>
<url-pattern>/servlet/DisplayChart</url-pattern>
</servlet-mapping>

2) Make new Java script to replace the funciton of BoxAndWhiskerRenderer:
public class boxplot extends BoxAndWhiskerRenderer{
private void drawHighFarOut(double aRadius, Graphics2D g2, double xx,
double m) {
g2.draw(null);
}
private void drawLowFarOut(double aRadius, Graphics2D g2, double xx,
double m) {
g2.draw(null);
}
}

3) Write code in my jsp web (maybe you only need to see row "boxplot boxRendererTheta = new boxplot"):
DefaultBoxAndWhiskerCategoryDataset dataBoxThetaRhesusBackground = new DefaultBoxAndWhiskerCategoryDataset();
dataBoxTheta.add(data1, "","A");
dataBoxTheta.add(data2, "","B");
dataBoxTheta.add(data3, "","C");
dataBoxTheta.add(data4, "","D");
dataBoxTheta.add(data5, "","E");
dataBoxTheta.add(data6, "","F");
dataBoxTheta.add(data7, "","G");

CategoryAxis boxDomainAxisTheta = new CategoryAxis("");
boxDomainAxisTheta.setLabelFont(new Font("Arial",Font.BOLD,25));
boxDomainAxisTheta.setTickLabelFont(new Font("Arial", Font.BOLD, 20));
boxDomainAxisTheta.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(0.5));
boxDomainAxisTheta.setAxisLinePaint(Color.black);
NumberAxis boxNumberAxisTheta = new NumberAxis("Population Mutation Rate");
boxNumberAxisTheta.setLabelFont(new Font("Arial",Font.BOLD,25));
boxNumberAxisTheta.setTickLabelFont(new Font("Arial", Font.BOLD, 20));
boxNumberAxisTheta.setUpperMargin(0.15);
boxNumberAxisTheta.setAxisLinePaint(Color.black);

boxplot boxRendererTheta = new boxplot(); //* Demo is BoxAndWhiskerRenderer boxRendererTheta = new BoxAndWhiskerRenderer (), I revised here expected the code of drawing outline would fail
boxRendererTheta.setMeanVisible(false);
boxRendererTheta.setSeriesPaint(0,Color.red);

CategoryPlot boxPlotTheta = new CategoryPlot(dataBoxTheta, boxDomainAxisTheta,boxNumberAxisTheta,boxRendererTheta);
boxPlotTheta.setBackgroundPaint(Color.white);
boxPlotTheta.setOutlinePaint(Color.white);
boxPlotTheta.setDomainGridlinePaint(Color.black);
boxPlotTheta.setRangeGridlinePaint(Color.black);
boxPlotTheta.setForegroundAlpha(0.6f);
JFreeChart boxChartTheta = new JFreeChart("Whole Genome Distribution",new Font("SansSerif",Font.BOLD, 14),boxPlotTheta,false);
boxChartTheta.setBackgroundPaint(Color.white);
ChartRenderingInfo infoTheta = new ChartRenderingInfo(new StandardEntityCollection());
String filenameBoxTheta = ServletUtilities.saveChartAsPNG(boxChartTheta, 800, 500, infoTheta, session);
String graphURLBoxTheta = request.getContextPath() + "/servlet/DisplayChart?filename=" + filenameBoxTheta;

<div style="float: left; margin-left: 1em"><img src="<%= graphURLBoxTheta %>" width=550 height=330 border=0 usemap="#<%= filenameBoxTheta %>"></div>

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Remove outlies of boxplot, thanks!

Post by paradoxoff » Fri Nov 27, 2015 12:39 pm

Your approach doesn´t work because the method has a private modifier. In order for this change to take effect, you would also have to copy/paste the drawHorizontalItem aund drawVerticalItem methods from the BoxAndWhiskerRenderer class to your renderer class. Better yet: make the drawHighFarOut/drawLowFarOut methods protected, but that would involve a change to the JFreeChart source and a recompilation of the package.

lamz138138
Posts: 3
Joined: Wed Nov 25, 2015 4:48 pm
antibot: No, of course not.

Re: Remove outlies of boxplot, thanks!

Post by lamz138138 » Fri Nov 27, 2015 2:05 pm

Hi, paradoxoff, thank you for your reply very much!

I would follow your suggestion, I would post my code if it work!

Best wishes!

lamz138138
Posts: 3
Joined: Wed Nov 25, 2015 4:48 pm
antibot: No, of course not.

Re: Remove outlies of boxplot, thanks!

Post by lamz138138 » Tue Dec 01, 2015 6:42 am

I had solved my problem by following paradoxoff's suggestion, I rewrite drawHorizontalltem and drawVerticalItem to move outliers, and revised the method of drawing mean value to display my value. I post my code here so as it would help others:

package org.test;

import java.awt.*;
import java.awt.List;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.*;

import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.EntityCollection;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.Outlier;
import org.jfree.chart.renderer.OutlierList;
import org.jfree.chart.renderer.OutlierListCollection;
import org.jfree.chart.renderer.category.BoxAndWhiskerRenderer;
import org.jfree.chart.renderer.category.CategoryItemRendererState;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.statistics.BoxAndWhiskerCategoryDataset;
import org.jfree.ui.RectangleEdge;

/**
* Created with IntelliJ IDEA.
* User: TheOne
* Date: 15-11-27
* Time: 下午11:17
* To change this template use File | Settings | File Templates.
*/
public class boxplot extends BoxAndWhiskerRenderer {

private String synonmousValue;
private String nonsynonmousValue;
private String cdsValue;
private String utrValue;
private String exonValue;
private String intronValue;
private String intergenicValue;

public void setSynonmousValue(String value){
this.synonmousValue = value;
}

public void setNonsynonmousValue (String value){
this.nonsynonmousValue = value;
}

public void setCdsValue (String value){
this.cdsValue = value;
}

public void setUtrValue (String value){
this.utrValue = value;
}

public void setExonValue (String value){
this.exonValue = value;
}

public void setIntronValue (String value){
this.intronValue = value;
}

public void setIntergenicValue (String value){
this.intergenicValue = value;
}

public void drawHorizontalItem(Graphics2D g2,
CategoryItemRendererState state, Rectangle2D dataArea,
CategoryPlot plot, CategoryAxis domainAxis, ValueAxis rangeAxis,
CategoryDataset dataset, int row, int column) {
BoxAndWhiskerCategoryDataset bawDataset
= (BoxAndWhiskerCategoryDataset) dataset;

double categoryEnd = domainAxis.getCategoryEnd(column,
getColumnCount(), dataArea, plot.getDomainAxisEdge());
double categoryStart = domainAxis.getCategoryStart(column,
getColumnCount(), dataArea, plot.getDomainAxisEdge());
double categoryWidth = Math.abs(categoryEnd - categoryStart);

double yy = categoryStart;
int seriesCount = getRowCount();
int categoryCount = getColumnCount();

if (seriesCount > 1) {
double seriesGap = dataArea.getHeight() * getItemMargin()
/ (categoryCount * (seriesCount - 1));
double usedWidth = (state.getBarWidth() * seriesCount)
+ (seriesGap * (seriesCount - 1));
// offset the start of the boxes if the total width used is smaller
// than the category width
double offset = (categoryWidth - usedWidth) / 2;
yy = yy + offset + (row * (state.getBarWidth() + seriesGap));
}
else {
// offset the start of the box if the box width is smaller than
// the category width
double offset = (categoryWidth - state.getBarWidth()) / 2;
yy = yy + offset;
}

g2.setPaint(getItemPaint(row, column));
Stroke s = getItemStroke(row, column);
g2.setStroke(s);

RectangleEdge location = plot.getRangeAxisEdge();

Number xQ1 = bawDataset.getQ1Value(row, column);
Number xQ3 = bawDataset.getQ3Value(row, column);
Number xMax = bawDataset.getMaxRegularValue(row, column);
Number xMin = bawDataset.getMinRegularValue(row, column);

Shape box = null;
if (xQ1 != null && xQ3 != null && xMax != null && xMin != null) {

double xxQ1 = rangeAxis.valueToJava2D(xQ1.doubleValue(), dataArea,
location);
double xxQ3 = rangeAxis.valueToJava2D(xQ3.doubleValue(), dataArea,
location);
double xxMax = rangeAxis.valueToJava2D(xMax.doubleValue(), dataArea,
location);
double xxMin = rangeAxis.valueToJava2D(xMin.doubleValue(), dataArea,
location);
double yymid = yy + state.getBarWidth() / 2.0;
double halfW = (state.getBarWidth() / 2.0) * this.getWhiskerWidth();

// draw the box...
box = new Rectangle2D.Double(Math.min(xxQ1, xxQ3), yy,
Math.abs(xxQ1 - xxQ3), state.getBarWidth());
if (this.getFillBox()) {
g2.setColor(Color.red);
g2.fill(box);
}

Paint outlinePaint = getItemOutlinePaint(row, column);
//if (this.useOutlinePaintForWhiskers) {
// g2.setPaint(outlinePaint);
//}
// draw the upper shadow...
g2.draw(new Line2D.Double(xxMax, yymid, xxQ3, yymid));
g2.draw(new Line2D.Double(xxMax, yymid - halfW, xxMax,
yymid + halfW));

// draw the lower shadow...
g2.draw(new Line2D.Double(xxMin, yymid, xxQ1, yymid));
g2.draw(new Line2D.Double(xxMin, yymid - halfW, xxMin,
yy + halfW));

g2.setStroke(getItemOutlineStroke(row, column));
g2.setPaint(outlinePaint);
g2.draw(box);
}
g2.setPaint(this.getArtifactPaint());

double aRadius; // average radius
//Number xMean = bawDataset.getMeanValue(row, column);
//Number xMean = this.synonmousValue;
Number xValue;
if(column == 0 && this.synonmousValue != null){
xValue = Double.parseDouble(this.synonmousValue);
}else if (column == 1 && this.nonsynonmousValue != null){
xValue = Double.parseDouble(this.nonsynonmousValue);
}else if (column == 2 && this.cdsValue != null){
xValue = Double.parseDouble(this.cdsValue);
}else if (column == 3 && this.utrValue != null){
xValue = Double.parseDouble(this.utrValue);
}else if (column == 4 && this.exonValue != null){
xValue = Double.parseDouble(this.exonValue);
}else if (column == 5 && this.intronValue != null){
xValue = Double.parseDouble(this.intronValue);
}else if (column == 6 && this.intergenicValue != null){
xValue = Double.parseDouble(this.intergenicValue);
}else{
xValue = null;
}
if (xValue != null) {
double xxValue = rangeAxis.valueToJava2D(xValue.doubleValue(),
dataArea, location);
aRadius = state.getBarWidth() / 8;
// here we check that the average marker will in fact be
// visible before drawing it...
if ((xxValue > (dataArea.getMinX() - aRadius))
&& (xxValue < (dataArea.getMaxX() + aRadius))) {
Ellipse2D.Double avgEllipse = new Ellipse2D.Double(xxValue
- aRadius * 3.5, yy + aRadius * 0.5, aRadius * 1, aRadius * 1);
g2.fill(avgEllipse);
g2.draw(avgEllipse);
}
}

if (this.isMedianVisible()) {
Number xMedian = bawDataset.getMedianValue(row, column);
if (xMedian != null) {
double xxMedian = rangeAxis.valueToJava2D(xMedian.doubleValue(),
dataArea, location);
g2.draw(new Line2D.Double(xxMedian, yy, xxMedian,
yy + state.getBarWidth()));
}
}

if (state.getInfo() != null && box != null) {
EntityCollection entities = state.getEntityCollection();
if (entities != null) {
addItemEntity(entities, dataset, row, column, box);
}
}
}
public void drawVerticalItem(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
ValueAxis rangeAxis, CategoryDataset dataset, int row, int column) {
BoxAndWhiskerCategoryDataset bawDataset
= (BoxAndWhiskerCategoryDataset) dataset;

double categoryEnd = domainAxis.getCategoryEnd(column,
getColumnCount(), dataArea, plot.getDomainAxisEdge());
double categoryStart = domainAxis.getCategoryStart(column,
getColumnCount(), dataArea, plot.getDomainAxisEdge());
double categoryWidth = categoryEnd - categoryStart;

double xx = categoryStart;
int seriesCount = getRowCount();
int categoryCount = getColumnCount();

if (seriesCount > 1) {
double seriesGap = dataArea.getWidth() * getItemMargin()
/ (categoryCount * (seriesCount - 1));
double usedWidth = (state.getBarWidth() * seriesCount)
+ (seriesGap * (seriesCount - 1));
// offset the start of the boxes if the total width used is smaller
// than the category width
double offset = (categoryWidth - usedWidth) / 2;
xx = xx + offset + (row * (state.getBarWidth() + seriesGap));
}
else {
// offset the start of the box if the box width is smaller than the
// category width
double offset = (categoryWidth - state.getBarWidth()) / 2;
xx = xx + offset;
}

double yyAverage;
double yyOutlier;

Paint itemPaint = getItemPaint(row, column);
g2.setPaint(itemPaint);
Stroke s = getItemStroke(row, column);
g2.setStroke(s);

double aRadius = 0; // average radius

RectangleEdge location = plot.getRangeAxisEdge();

Number yQ1 = bawDataset.getQ1Value(row, column);
Number yQ3 = bawDataset.getQ3Value(row, column);
Number yMax = bawDataset.getMaxRegularValue(row, column);
Number yMin = bawDataset.getMinRegularValue(row, column);
Shape box = null;
if (yQ1 != null && yQ3 != null && yMax != null && yMin != null) {

double yyQ1 = rangeAxis.valueToJava2D(yQ1.doubleValue(), dataArea,
location);
double yyQ3 = rangeAxis.valueToJava2D(yQ3.doubleValue(), dataArea,
location);
double yyMax = rangeAxis.valueToJava2D(yMax.doubleValue(),
dataArea, location);
double yyMin = rangeAxis.valueToJava2D(yMin.doubleValue(),
dataArea, location);
double xxmid = xx + state.getBarWidth() / 2.0;
double halfW = (state.getBarWidth() / 2.0) * this.getWhiskerWidth();

// draw the body...
box = new Rectangle2D.Double(xx, Math.min(yyQ1, yyQ3),
state.getBarWidth(), Math.abs(yyQ1 - yyQ3));
Paint outlinePaint = getItemOutlinePaint(row, column);
//if (this.useOutlinePaintForWhiskers) {
// g2.setPaint(outlinePaint);
//}
// draw the upper shadow...
g2.draw(new Line2D.Double(xxmid, yyMax, xxmid, yyQ3));
g2.draw(new Line2D.Double(xxmid - halfW, yyMax, xxmid + halfW, yyMax));

// draw the lower shadow...
g2.draw(new Line2D.Double(xxmid, yyMin, xxmid, yyQ1));
g2.draw(new Line2D.Double(xxmid - halfW, yyMin, xxmid + halfW, yyMin));

g2.setStroke(getItemOutlineStroke(row, column));
g2.setPaint(outlinePaint);
g2.draw(box);
}

g2.setPaint(this.getArtifactPaint());
if (state.getInfo() != null && box != null) {
EntityCollection entities = state.getEntityCollection();
if (entities != null) {
addItemEntity(entities, dataset, row, column, box);
}
}

if (this.getFillBox()) {
g2.setColor(Color.red);
g2.fill(box);
}

if (this.isMedianVisible()) {
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));
}
}

//Number yMean = bawDataset.getMeanValue(row, column);
//Number yMean = this.synonmousValue;
Number yValue;
if(column == 0 && this.synonmousValue != null){
yValue = Double.parseDouble(this.synonmousValue);
}else if (column == 1 && this.nonsynonmousValue != null){
yValue = Double.parseDouble(this.nonsynonmousValue);
}else if (column == 2 && this.cdsValue != null){
yValue = Double.parseDouble(this.cdsValue);
}else if (column == 3 && this.utrValue != null){
yValue = Double.parseDouble(this.utrValue);
}else if (column == 4 && this.exonValue != null){
yValue = Double.parseDouble(this.exonValue);
}else if (column == 5 && this.intronValue != null){
yValue = Double.parseDouble(this.intronValue);
}else if (column == 6 && this.intergenicValue != null){
yValue = Double.parseDouble(this.intergenicValue);
}else{
yValue = null;
}
if (yValue != null) {
yyAverage = rangeAxis.valueToJava2D(yValue.doubleValue(),
dataArea, location);
aRadius = state.getBarWidth() / 8;
// here we check that the average marker will in fact be
// visible before drawing it...
if ((yyAverage > (dataArea.getMinY() - aRadius))
&& (yyAverage < (dataArea.getMaxY() + aRadius))) {
Ellipse2D.Double avgEllipse = new Ellipse2D.Double(
xx + aRadius * 3.5, yyAverage - aRadius * 0.5, aRadius * 1,
aRadius * 1);
g2.fill(avgEllipse);
g2.draw(avgEllipse);
}
}
}
}

Locked