BoxandWhisker timing plot

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
bztom333
Posts: 10
Joined: Sat Aug 20, 2016 12:29 am
antibot: No, of course not.

BoxandWhisker timing plot

Post by bztom333 » Tue Aug 23, 2016 3:31 am

Is it possible to do render a boxandwhisker chart with value domain and date/time range?

for example:

This is the normal way to fill the data:
[code]
private BoxAndWhiskerXYDataset createDataset() {
final int ENTITY_COUNT =1;

DefaultBoxAndWhiskerXYDataset dataset = new DefaultBoxAndWhiskerXYDataset("Test");

for (int i = 0; i < ENTITY_COUNT; i++) {
Date date = DateUtilities.createDate(2003, 7, i + 1, 12, 0);
List values = new ArrayList();
for (int j = 0; j < 2; j++) {
values.add(new Double(180000));
values.add(new Double(180000*1.05));
values.add(new Double(180000*1.10));
values.add(new Double(180000*1.15));
values.add(new Double(180000*1.20));
values.add(new Double(180000*1.25));

}
dataset.add(date, BoxAndWhiskerCalculator.calculateBoxAndWhiskerStatistics(values));
}
return dataset;
}[/code]


is it possible to modify existing add method it to accept following:

import org.joda.time;
...
private BoxAndWhiskerXYDataset createDataset() {
final int ENTITY_COUNT =1;

for (int i = 0; i < ENTITY_COUNT; i++) {

new Double ThresholdValue =180000;
List<LocalDate> localDates = new ArrayList();
LocalDate localDate = LocalDate.ofInstant( 2016 , 1 , 1 ) ;
for (int j = 0; j < 5; j++) {
localDates.add( localDate );
// Set up the next loop.
localDate = localDate.plusDays( 1 );
}
dataset.add(ThresholdValue, BoxAndWhiskerCalculator.calculateBoxAndWhiskerStatistics(localDate));
}
return dataset;
}
}[/code]

This is a BoxAndWhisker chart with a single fixed Y-value, the variable date_time value. It's looks like this: |----[ ]----| box will stretch by on x-axis for number of days in the list.
Last edited by bztom333 on Tue Aug 23, 2016 6:07 pm, edited 1 time in total.

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

Re: BoxandWhisker timing plot

Post by paradoxoff » Fri Aug 26, 2016 8:43 am

You obviously can't use the LocalDate instance "localDate" as parameter for BoxAndWhiskerCalculator.calculateBoxAndWhiskerStatistics, but you could use the List instance localDates. This will lead to an Exception, since the BoxAndWhiskerCalculator assumes that the supplied list is list of Numbers, and a LocalDate is not a Number. You also can´t directly convert that to an e. g. long, because the time zone information is missing. So convert the LocalDate to LocalDateTime, convert that to a ZonedDateTime, and convert that to an Instant and finally a long by calling topEpochMillis().
Another suggetions: use instances of org.jfree.data.time.Day.

bztom333
Posts: 10
Joined: Sat Aug 20, 2016 12:29 am
antibot: No, of course not.

Re: BoxandWhisker timing plot

Post by bztom333 » Sat Aug 27, 2016 7:45 am

I was hoping to modify the xybarrender to do render a boxandwhisker chart with DATE as timeline and a range is a NumberAxis.

Code: Select all

package misc.test;


import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;

import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.chart.renderer.xy.GradientXYBarPainter;
import org.jfree.chart.renderer.xy.XYBarPainter;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.time.Day;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.XYIntervalSeries;
import org.jfree.data.xy.XYIntervalSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RefineryUtilities;
 

/**
 * A simple demonstration application showing an {@link MyXYBarRenderer}
 * plotting data from a {@link XYIntervalSeriesCollection}.
 */
public class XYBarChartDemo7 extends ApplicationFrame {

    /**
     * Constructs the demo application.
     *
     * @param title  the frame title.
     */
    public XYBarChartDemo7(String title) {
        super(title);
        JPanel chartPanel = createDemoPanel();
        chartPanel.setPreferredSize(new java.awt.Dimension(500, 300));
        setContentPane(chartPanel);
    }

    private static JFreeChart createChart(IntervalXYDataset dataset) {
        JFreeChart chart = ChartFactory.createXYBarChart("XYBarChartDemo7",
                "Date", true, "Y", dataset, PlotOrientation.HORIZONTAL,
                true, false, false);


        XYPlot plot = (XYPlot) chart.getPlot();
        //plot.setRangePannable(true);
        plot.setRangeAxis(new DateAxis("Date"));
        
        plot.setDomainAxis(new NumberAxis("CFS"));
         
        XYBarRenderer renderer = (XYBarRenderer) plot.getRenderer() ;
        		
        renderer.setDrawBarOutline(true);
       
       // renderer.setSeriesOutlinePaint(1,Color.BLACK);
       // renderer.setSeriesOutlinePaint(2,Color.BLACK);
       // renderer.setSeriesOutlinePaint(3,Color.BLACK);
        renderer.setUseYInterval(true);
      //  renderer.setBaseItemLabelsVisible(true);
       // renderer.setBaseFillPaint(Color.white);  
     
        XYBarPainter painter = new XYBarPainter() {

        	@Override
        	public void paintBarShadow(Graphics2D g2, XYBarRenderer renderer, int row, int column, RectangularShape bar, RectangleEdge base, boolean pegShadow) {
          	}

        	@Override
        	public void paintBar(Graphics2D g2, XYBarRenderer renderer, int row, int column, RectangularShape bar, RectangleEdge base) {
        	// TODO Auto-generated method stub
        	bar.setFrame(bar.getX(), bar.getY() , bar.getWidth() + 8, bar.getHeight());
        	// g2.setBackground(Color.GREEN);
        	
        	//Shape box = new Rectangle2D.Double(bar.getX(), bar.getY() , bar.getWidth() + 8, bar.getHeight() );
 		   
        	g2.setColor(Color.BLACK);
            g2.draw(bar);
        	 

        	/*double xxmid=bar.getCenterX();
			double yyMax=bar.getMaxY();
			double yyMin=bar.getMinY();
			double xx=bar.getMinX();
			double yyQ1=bar.getMinY();
			double yyQ3=bar.getMaxY()*/;
			
			// draw the upper whisker
		     //g2.draw(new Line2D.Double(xxmid, yyMax, xxmid, yyQ3));
		    //  g2.draw(new Line2D.Double(xx, yyMax, xx + bar.getBounds().getCenterY(), yyMax));
		
		     // draw the lower whisker
		   //  g2.draw(new Line2D.Double(xxmid, yyMin, xxmid, yyQ1));
		    // g2.draw(new Line2D.Double(xx, yyMin, xx + bar.getWidth(), yyMin));
        	 }
        	};
         renderer.setBarPainter(painter);
         plot.setRenderer(renderer);
      //  plot.setBackgroundPaint(Color.lightGray);
      //  plot.setDomainGridlinePaint(Color.white);
       // plot.setRangeGridlinePaint(Color.white);
       //  plot.setOutlinePaint(Color.black);
       // ChartUtilities.applyCurrentTheme(chart);

        return chart;
        
        
    }

    /**
     * Creates a sample dataset.
     *
     * @return A dataset.
     */
    private static IntervalXYDataset createDataset() {
        Day d0 = new Day(12, 6, 2007);
        Day d1 = new Day(13, 6, 2007);
        Day d2 = new Day(14, 6, 2007);
        Day d3 = new Day(15, 6, 2007);
        Day d4 = new Day(16, 6, 2007);
        Day d5 = new Day(17, 6, 2007);
        XYIntervalSeriesCollection dataset = new XYIntervalSeriesCollection();
        XYIntervalSeries s1 = new XYIntervalSeries("Sampson Road 57.7ft");
        XYIntervalSeries s2 = new XYIntervalSeries("Uncle Joe Lane 65.7ft");
        XYIntervalSeries s3 = new XYIntervalSeries("Bob Main Lain 77.2ft");
       
       // addItem(s1, d0, d1, 1800);
        //addItem(s1, d3, d3, 1000);
         addItem(s2, d4, d5, 200);
         addItem(s3, d3, d4, 2000);
        dataset.addSeries(s1);
        dataset.addSeries(s2);
        dataset.addSeries(s3);
        return dataset;
    }

    private static void addItem(XYIntervalSeries s, RegularTimePeriod p0,
            RegularTimePeriod p1, int index) {
        s.add(index, index - 0.45, index + 200.45, p0.getFirstMillisecond(),
                p0.getFirstMillisecond(), p1.getLastMillisecond());
    }

    /**
     * Creates a panel for the demo.
     *
     * @return A panel.
     */
    public static JPanel createDemoPanel() {
        return new ChartPanel(createChart(createDataset()));
    }

    /**
     * Starting point for the demonstration application.
     *
     * @param args  ignored.
     */
    public static void main(String[] args) {
        XYBarChartDemo7 demo = new XYBarChartDemo7(
                "JFreeChart : BoxAndWhisker Timging Chart");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }

}
 

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

Re: BoxandWhisker timing plot

Post by paradoxoff » Sat Aug 27, 2016 11:19 am

You are not using any of the BoxAndWhisker classes, half of the code is commented out, you are using a bar painter that does not fill the bars but only draws them, 3 of the 6 day instances and one of the 3 series is not used at all.
I really wonder what is the exact problem.

John Matthews
Posts: 513
Joined: Wed Sep 12, 2007 3:18 pm

Re: BoxandWhisker timing plot

Post by John Matthews » Sat Aug 27, 2016 7:22 pm

You can use PlotOrientation.HORIZONTAL , as shown here and use a Date, or its formatted String, as the columnKey when adding data to an instance of DefaultBoxAndWhiskerCategoryDataset.

bztom333
Posts: 10
Joined: Sat Aug 20, 2016 12:29 am
antibot: No, of course not.

Re: BoxandWhisker timing plot

Post by bztom333 » Sun Aug 28, 2016 8:26 am

Great suggestion, however; is it possible to cast or override the string y-axis to be a number axis?
Want to draw some things like below:

Code: Select all

 10|     |------[‾‾‾‾‾‾‾|‾‾‾‾‾]------|
 |               ‾‾‾‾‾‾‾‾‾‾‾‾
 |
--------------d1----d2---d3-------------

Trying to plot...

For a given y value, there are potentially up to 21 value of dates. 1st date is valued at 0% increment. So 2nd day is valued @5%., 3rd date is valued at 10% and so on up to 100%.


I Only want to render one box and whisker chart that will stretch horizontally if more dated is added. See above Drawing.

I am trying to show the relationship of a given y value that % would likely to occur over the a periods of time,hence timing plot.

May be I was barking on the wrong tree. 8)

John Matthews
Posts: 513
Joined: Wed Sep 12, 2007 3:18 pm

Re: BoxandWhisker timing plot

Post by John Matthews » Sun Aug 28, 2016 11:33 pm

You could try using milliseconds for the values and a DateAxis for the domain.

bztom333
Posts: 10
Joined: Sat Aug 20, 2016 12:29 am
antibot: No, of course not.

Re: BoxandWhisker timing plot

Post by bztom333 » Fri Sep 02, 2016 8:20 am

This is the closest thing that I can sort of generate the desire plot for a " BoxAndWhisker Timing Plot". It would be nice if someone with intimate knowledge of the API framework to include a new enhancement in future release of the BoxAndWhiskerrenderer to allow a proper way to generate this kind of chart. Again, this is no mean the real thing.

Code: Select all

package misc.test;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import javax.swing.JPanel;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBoxAndWhiskerRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.statistics.BoxAndWhiskerCalculator;
import org.jfree.data.statistics.BoxAndWhiskerXYDataset;
import org.jfree.data.statistics.DefaultBoxAndWhiskerXYDataset;
import org.jfree.data.time.Day;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
 
/** 
 * A simple demonstration application showing how to create a "box-and-whisker  Timing "
 * chart. 
 */ 


public class BoxAndWhiskerChartTimingDemo extends ApplicationFrame { 
 
    /** 
     * Creates a new demo instance. 
     * 
     * @param title  the frame title. 
     */ 

    
    public BoxAndWhiskerChartTimingDemo(String title) { 
 
        super(title); 
        JPanel chartPanel = createDemoPanel(); 
        chartPanel.setPreferredSize(new Dimension(500, 270)); 
        
        setContentPane(chartPanel); 
    }
 
    NumberAxis xAxis = new NumberAxis("CFS");
    XYPlot plot;
    DateAxis  dateaxis = new DateAxis("Ensemble Timing");
   
    /** 
     * Returns a sample dataset. 
     *  
     * @return The dataset. 
     */ 
    
    private static BoxAndWhiskerXYDataset createDataset() { 
        final int VALUE_COUNT = 6; 
        DefaultBoxAndWhiskerXYDataset result = new DefaultBoxAndWhiskerXYDataset("Timing Series Demo"); 
        RegularTimePeriod t = new Day(); 
        for (int i = 0; i <1; i++) { 
            List values = createValueList(0, 100, VALUE_COUNT); 
             result.add(t.getStart(),  
              BoxAndWhiskerCalculator.calculateBoxAndWhiskerStatistics(values)); 
             t = t.next(); 
        } 
        return result; 
    } 
     
    private static List createValueList(double lowerBound, double upperBound,  int count) { 
        List result = new java.util.ArrayList(); 
        for (int i = 0; i<count; i++) { 
            result.add(new Double(5));    
            result.add(new Double(10));
            result.add(new Double(15));
            result.add(new Double(20));
            result.add(new Double(25));
            result.add(new Double(30));
        } 
        return result; 
     
    } 
     
    /** 
     * Creates a sample chart. 
     *  
     * @param dataset  the dataset. 
     *  
     * @return The chart. 
     */ 
    private JFreeChart createChart(BoxAndWhiskerXYDataset dataset) { 
         
        DateAxis domainAxis = new DateAxis("Day"); 
        NumberAxis rangeAxis = new NumberAxis("Value"); 
        XYItemRenderer renderer = new XYBoxAndWhiskerRenderer(); 
      
 
        plot = new XYPlot(dataset, domainAxis, rangeAxis, renderer); 
        JFreeChart chart = new JFreeChart("Box-and-Whisker Chart Timing Plot", plot); 
      
        
        chart.setBackgroundPaint(Color.white); 
        plot.setOrientation(PlotOrientation.HORIZONTAL);
 
        plot.setBackgroundPaint(Color.lightGray); 
        plot.setDomainGridlinePaint(Color.white); 
        plot.setDomainGridlinesVisible(true); 
        plot.setRangeGridlinePaint(Color.white); 

        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        rangeAxis.setVisible(false);
        domainAxis.setVisible(false);
       
      
      
        Date minDate = new Date();
        Date maxDate = new Date();
        String dateFormat = "MM/dd/yyyy HH:mm";   
      
        
        //set min and max range date
        Calendar cal = new GregorianCalendar();
   
         
        cal.setTime(minDate);
        
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        
        minDate = cal.getTime();
        
        cal.set(Calendar.HOUR_OF_DAY, 9);
        
        maxDate = cal.getTime();
        dateaxis.setRange(minDate, maxDate);
         dateaxis.setDateFormatOverride(new SimpleDateFormat(dateFormat));
       
        plot.setRangeAxis(1, dateaxis);
        plot.setRangeAxisLocation(1,AxisLocation.BOTTOM_OR_RIGHT);
    
        xAxis.setRange(100000,270000);
       
        plot.setDomainAxis(1,xAxis);
        plot.setDomainAxisLocation(1,AxisLocation.BOTTOM_OR_LEFT);
        
        return chart; 
         
    } 
     
    /** 
     * Creates a panel for the demo (used by SuperDemo.java). 
     *  
     * @return A panel. 
     */ 
    public  JPanel createDemoPanel() { 
        JFreeChart chart = createChart(createDataset()); 
        return new MyChartPanel(chart); 
    } 
     
    /** 
     * Starting point for the demonstration application. 
     * 
     * @param args  ignored. 
     */ 
    public static void main(String[] args) { 
 
        BoxAndWhiskerChartTimingDemo demo = new BoxAndWhiskerChartTimingDemo( 
            "Box-and-Whisker Timing Plot - Fake It Until You Make It."); 
        demo.pack(); 
        RefineryUtilities.centerFrameOnScreen(demo); 
        demo.setVisible(true); 
 
    } 
 
    public class MyChartPanel extends ChartPanel
    {
        public MyChartPanel(JFreeChart chart)
        {
            super(chart);
        }

        @Override
        public void restoreAutoDomainBounds()
        {
            super.restoreAutoDomainBounds();
            // Set your desired range
            xAxis.setRange(100000,270000);

        }
        
     

        @Override
        public void restoreAutoRangeBounds()
        {
            super.restoreAutoRangeBounds();
            // Set your desired range
           
            Date minDate = new Date();
            Date maxDate = new Date();
            String dateFormat = "MM/dd/yyyy HH:mm";   
            //set min and max range date
            Calendar cal = new GregorianCalendar();
            cal.setTime(minDate);
            cal.set(Calendar.HOUR_OF_DAY, 0);
            cal.set(Calendar.MINUTE, 0);
            minDate = cal.getTime();
            cal.set(Calendar.HOUR_OF_DAY, 9);
             maxDate = cal.getTime();
            
            dateaxis.setRange(minDate, maxDate);
            dateaxis.setDateFormatOverride(new SimpleDateFormat(dateFormat));
            
            
        }
    }
} 


John Matthews
Posts: 513
Joined: Wed Sep 12, 2007 3:18 pm

Re: BoxandWhisker timing plot

Post by John Matthews » Sat Sep 03, 2016 4:17 am

Also consider the DateAxis methods setVerticalTickLabels and setDateFormatOverride.

Locked