Problems duplicate x-axis labels with TimeSeries Month.class

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
lion_b1
Posts: 4
Joined: Fri Apr 13, 2007 2:35 pm

Problems duplicate x-axis labels with TimeSeries Month.class

Post by lion_b1 » Fri Apr 13, 2007 2:51 pm

Hello,

when I create a chart with TimeSeries and Moth.class the month label names from the x-axis will be repeated.

If I have January, February, March with data and the x-axis renderes the lables:

January January February March March

Tested with JFreeChart V1.0.5
Is there a way to prevent the double entries of the labels?
Any answere is highly appreciated.

Thanks.

Please find the code with test data here:

Code: Select all

package de.telenet.bargraph;
import java.awt.Color;
import java.awt.Font;
import java.awt.Paint;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Iterator;



import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickMarkPosition;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.TickUnitSource;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.ClusteredXYBarRenderer;
import org.jfree.data.time.Month;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;


public class BarChartTest extends ApplicationFrame {
	
	public final String DATEFORMAT_MONTH = "MMMM";
	public static final Paint LIGHT_RED = new java.awt.Color(255,191,233);
	public static final Paint COBALD = new java.awt.Color(40,71,102); 
	public static final Paint WHITE = new java.awt.Color(255, 255, 255);
	Date startDate = formatDate("01.01.2007 00:00:00"); //Begin of time range for x-axis
	Date endDate = formatDate("31.03.2007 00:00:00");  //End of time range for x-axis
	String labelXAxis1 = "Month";
	String labelYAxis1 = "Caller";
	String title = "Test BarGraph";
	int intervalInMinutes = 86400;
	TimeSeries tSeries1 = new TimeSeries("Total Calls", Month.class); // time series for graph, monthly view
	TimeSeries tSeries2 = new TimeSeries("Successfull Calls", Month.class); // 
	JFreeChart chart;
	XYPlot plot;
	NumberAxis axisNum;
	DateAxis axis;

	/**
	 * A test application showing a horizontal bar  chart.
	 */
	private static final long serialVersionUID = 1L;

		/**
	     * Creates a new demo instance.
	     *
	     * @param title  the frame title.
	     */
	    public BarChartTest(String title) {
	    	super(title);
	    	initTimeSeries();
	    	generateChart();
	        ChartPanel chartPanel = new ChartPanel(chart);
	        chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
	        setContentPane(chartPanel);
	    }
	    
	    /**
	     * Initalize time series with a sample dataset.
	     * 
	     */
	    private void initTimeSeries() { 
	    	List dates = new ArrayList();
	    	dates.add(formatDate("01.01.2007 00:00:00"));
	    	dates.add(formatDate("01.02.2007 00:00:00"));
	    	dates.add(formatDate("01.03.2007 00:00:00"));
	    Iterator it = dates.iterator();
		    while ( it.hasNext() ) {
		    	Date myDate = (Date) it.next();
		    	tSeries1.add(new Month ((Date) myDate), 25); //
		    	tSeries2.add(new Month ((Date) myDate), 10); //
		    }
	    }
	    
	    /**
	     *  generate JFreeGraph chart
	     */
	    private void generateChart() {
			//Create dataset needed by chart with time series
			TimeSeriesCollection dataset = new TimeSeriesCollection();
			dataset.addSeries(tSeries1);
			dataset.addSeries(tSeries2);
			
			chart = ChartFactory.createXYBarChart(
					this.getTitle(), //title
					"Month", // x-axis label
					true, // date axis?
					"Total Calls", // y-axis label
					dataset, // data
					PlotOrientation.VERTICAL, // orientation
					true, // create legend?
					true, // generate tooltips?
					false // generate URLs?
					);
		
			// customise chart
			chart.setBackgroundPaint(WHITE);
			
			//initialize the plot
			this.plot = chart.getXYPlot();

			//set the range axis to display integers only...
			ClusteredXYBarRenderer r = new ClusteredXYBarRenderer();
			
			r.setItemLabelGenerator(
		            new StandardXYItemLabelGenerator()
		        );
		
		   	r.setSeriesPaint(0, LIGHT_RED);
			r.setSeriesPaint(1, COBALD);
		 	
			// the margin between two bars is specified as a percentage of the bar
			// width
			// (for example, 0.10 is ten percent) and is the amount
			// that is trimmed from the bar width before the bar is displayed.
			r.setMargin(0.1);
			
			r.setToolTipGenerator(
		            new StandardXYToolTipGenerator(
		                StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,
		                new SimpleDateFormat("d.MM.y HH:mm"), new DecimalFormat("0,000.0")
		            )
		        );
			plot.setRenderer(r);
			//set colors
			plot.setBackgroundPaint(Color.lightGray);
			plot.setRangeGridlinePaint(Color.white);
		
			//Init Range (Y-Axis)
			this.axisNum = (NumberAxis) plot.getRangeAxis();
			//Use only integers for y-axis
			TickUnitSource units = NumberAxis.createIntegerTickUnits();
			axisNum.setStandardTickUnits(units);
			axisNum.setLabelFont(new Font("Arial", Font.PLAIN, 10));

			//Init Domain (X-Axis)
			//User date for x-axis
			this.axis = (DateAxis) plot.getDomainAxis();
			TickUnitSource unitsAxis = DateAxis.createStandardDateTickUnits();
			this.axis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
			this.axis.setStandardTickUnits(unitsAxis);
			this.axis.setRange(startDate, endDate);
			this.axis.setMinimumDate(startDate);
			this.axis.setMaximumDate(endDate);
		
			axis.setDateFormatOverride(new SimpleDateFormat(DATEFORMAT_MONTH, new Locale("en")));
			chart.setBackgroundPaint(WHITE);
				
			((JFreeChart) chart).getTitle().setFont(new Font("Arial", Font.TRUETYPE_FONT, 17));
			((JFreeChart) chart).getTitle().setPaint(new java.awt.Color(153, 153, 153));//#999999
		    
		}
	    
  
	    /**
	     * Format a string to a date object
	     * @param myDate
	     * @return
	     */
		private Date formatDate(String myDate) {

			DateFormat format = DateFormat.getDateTimeInstance();
			Date d = null;
			try {
				d = format.parse(myDate);
			} catch ( ParseException  e1 ) {}
		
			return d;
		}
		
	    /**
	     * Starting point for the demonstration application.
	     *
	     * @param args  ignored.
	     */
	    public static void main(String[] args) {

	        BarChartTest demo = new BarChartTest("Bar Chart Test Time Series");
	        demo.pack();
	        RefineryUtilities.centerFrameOnScreen(demo);
	        demo.setVisible(true);

	    }

	}




lion_b1
Posts: 4
Joined: Fri Apr 13, 2007 2:35 pm

More information

Post by lion_b1 » Mon Apr 16, 2007 3:17 pm

Hello,

additionally I found out the following behavior:

When I add two date values (April, May) the x-axis labels are displayed correctly without double names for the labels.

Also when I resize the chartPanel width from 500 to 300

Code: Select all

chartPanel.setPreferredSize(new java.awt.Dimension(300, 270));
the labels have no double values (in this case with three data values for January, February, March.

Additionally I removed

Code: Select all

axis.setDateFormatOverride(new SimpleDateFormat(DATEFORMAT_MONTH, new Locale("en")));
completely for testing and saw that it looks like that the plot object tries to optimize the values on x-axis and displays more labels than data values exists.
The displayed labels in this case are

15-Jan 30-Jan 14-Feb 1-Mrz 16-Mrz

The dataset are having just:
"01.01.2007 00:00:00"
"01.02.2007 00:00:00"
"01.03.2007 00:00:00"

Where does the values for the date calculation on x-axis came from?

Is there a workaround available for this behavior?

Should I submit a bug for this issue?

Please let me know.

Thanks.

Regards

Bernhard



Here the code where the labels are shown correctly:

Code: Select all

package de.telenet.jfree.timeseries;


import java.awt.Color;
import java.awt.Font;
import java.awt.Paint;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Iterator;



import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickMarkPosition;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.TickUnitSource;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.ClusteredXYBarRenderer;
import org.jfree.data.time.Month;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;


public class BarChartTest extends ApplicationFrame {
   
   public final String DATEFORMAT_MONTH = "MMMM";
   public static final Paint LIGHT_RED = new java.awt.Color(255,191,233);
   public static final Paint COBALD = new java.awt.Color(40,71,102);
   public static final Paint WHITE = new java.awt.Color(255, 255, 255);
   Date startDate = formatDate("01.01.2007 00:00:00"); //Begin of time range for x-axis
   Date endDate = formatDate("30.05.2007 00:00:00");  //End of time range for x-axis
   String labelXAxis1 = "Month";
   String labelYAxis1 = "Caller";
   String title = "Test BarGraph";
   int intervalInMinutes = 86400;
   TimeSeries tSeries1 = new TimeSeries("Total Calls", Month.class); // time series for graph, monthly view
   TimeSeries tSeries2 = new TimeSeries("Successfull Calls", Month.class); //
   JFreeChart chart;
   XYPlot plot;
   NumberAxis axisNum;
   DateAxis axis;

   /**
    * A test application showing a horizontal bar  chart.
    */
   private static final long serialVersionUID = 1L;

      /**
        * Creates a new demo instance.
        *
        * @param title  the frame title.
        */
       public BarChartTest(String title) {
          super(title);
          initTimeSeries();
          generateChart();
           ChartPanel chartPanel = new ChartPanel(chart);
           chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
           setContentPane(chartPanel);
       }
      
       /**
        * Initalize time series with a sample dataset.
        *
        */
       private void initTimeSeries() {
          List dates = new ArrayList();
          dates.add(formatDate("01.01.2007 00:00:00"));
          dates.add(formatDate("01.02.2007 00:00:00"));
          dates.add(formatDate("01.03.2007 00:00:00"));
          dates.add(formatDate("01.04.2007 00:00:00"));
          dates.add(formatDate("01.05.2007 00:00:00"));
       Iterator it = dates.iterator();
          while ( it.hasNext() ) {
             Date myDate = (Date) it.next();
             tSeries1.add(new Month ((Date) myDate), 25); //
             tSeries2.add(new Month ((Date) myDate), 10); //
          }
       }
      
       /**
        *  generate JFreeGraph chart
        */
       private void generateChart() {
         //Create dataset needed by chart with time series
         TimeSeriesCollection dataset = new TimeSeriesCollection();
         dataset.addSeries(tSeries1);
         dataset.addSeries(tSeries2);
         
         chart = ChartFactory.createXYBarChart(
               this.getTitle(), //title
               "Month", // x-axis label
               true, // date axis?
               "Total Calls", // y-axis label
               dataset, // data
               PlotOrientation.VERTICAL, // orientation
               true, // create legend?
               true, // generate tooltips?
               false // generate URLs?
               );
      
         // customise chart
         chart.setBackgroundPaint(WHITE);
         
         //initialize the plot
         this.plot = chart.getXYPlot();

         //set the range axis to display integers only...
         ClusteredXYBarRenderer r = new ClusteredXYBarRenderer();
         
         r.setItemLabelGenerator(
                  new StandardXYItemLabelGenerator()
              );
      
            r.setSeriesPaint(0, LIGHT_RED);
         r.setSeriesPaint(1, COBALD);
          
         // the margin between two bars is specified as a percentage of the bar
         // width
         // (for example, 0.10 is ten percent) and is the amount
         // that is trimmed from the bar width before the bar is displayed.
         r.setMargin(0.1);
         
         r.setToolTipGenerator(
                  new StandardXYToolTipGenerator(
                      StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,
                      new SimpleDateFormat("d.MM.y HH:mm"), new DecimalFormat("0,000.0")
                  )
              );
         plot.setRenderer(r);
         //set colors
         plot.setBackgroundPaint(Color.lightGray);
         plot.setRangeGridlinePaint(Color.white);
      
         //Init Range (Y-Axis)
         this.axisNum = (NumberAxis) plot.getRangeAxis();
         //Use only integers for y-axis
         TickUnitSource units = NumberAxis.createIntegerTickUnits();
         axisNum.setStandardTickUnits(units);
         axisNum.setLabelFont(new Font("Arial", Font.PLAIN, 10));

         //Init Domain (X-Axis)
         //User date for x-axis
         this.axis = (DateAxis) plot.getDomainAxis();
         TickUnitSource unitsAxis = DateAxis.createStandardDateTickUnits();
         this.axis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
         this.axis.setStandardTickUnits(unitsAxis);
         this.axis.setRange(startDate, endDate);
         this.axis.setMinimumDate(startDate);
         this.axis.setMaximumDate(endDate);
      
         axis.setDateFormatOverride(new SimpleDateFormat(DATEFORMAT_MONTH, new Locale("en")));
         chart.setBackgroundPaint(WHITE);
            
         ((JFreeChart) chart).getTitle().setFont(new Font("Arial", Font.TRUETYPE_FONT, 17));
         ((JFreeChart) chart).getTitle().setPaint(new java.awt.Color(153, 153, 153));//#999999
         
      }
      
 
       /**
        * Format a string to a date object
        * @param myDate
        * @return
        */
      private Date formatDate(String myDate) {

         DateFormat format = DateFormat.getDateTimeInstance();
         Date d = null;
         try {
            d = format.parse(myDate);
         } catch ( ParseException  e1 ) {}
      
         return d;
      }
      
       /**
        * Starting point for the demonstration application.
        *
        * @param args  ignored.
        */
       public static void main(String[] args) {

           BarChartTest demo = new BarChartTest("Bar Chart Test Time Series");
           demo.pack();
           RefineryUtilities.centerFrameOnScreen(demo);
           demo.setVisible(true);

       }

   }

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Post by david.gilbert » Wed Apr 18, 2007 9:52 am

The DateAxis doesn't look at your data values when it is working out the points to add tick marks. The mechanism is very similar to that used by the NumberAxis class - it looks up a table of "standard" tick sizes (which you can modify if you want) and chooses the smallest size that doesn't cause the tick labels to overlap.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

lion_b1
Posts: 4
Joined: Fri Apr 13, 2007 2:35 pm

Post by lion_b1 » Wed Apr 18, 2007 11:30 am

Hello David,

thanks for the answer.

I looked at the source but unfortunately I did not found out how to override the standard tick sizes.

Possibly the method:

Code: Select all

public static TickUnitSource createStandardDateTickUnits(TimeZone zone)
I would appreciate it very much, if you could give a short code example how to modify the standard tick sizes.
In this case, the tick sizes should be similair to the dataset values.

Thanks in advance.

Best Regards

Bernhard

lion_b1
Posts: 4
Joined: Fri Apr 13, 2007 2:35 pm

Post by lion_b1 » Wed Apr 18, 2007 3:01 pm

Hello David,

in the meantime I found a solution for the problem:

Code: Select all

         // set the tick size to one month, with formatting...
         DateFormat f1 = new SimpleDateFormat("MMMM");
         TickUnits monthUnits = new TickUnits();
         //months
         monthUnits.add(new DateTickUnit(DateTickUnit.MONTH, 1, f1 ));
         monthUnits.add(new DateTickUnit(DateTickUnit.MONTH, 2, f1 ));
         monthUnits.add(new DateTickUnit(DateTickUnit.MONTH, 3, f1 ));
         
         axis.setStandardTickUnits(monthUnits);
Of course I have to generate the integers for the month dynamic from the dataset.
With these changes I have the behavior that I expect.

Hope this helps others having the same problem. :D

Best Regards

Bernhard

jfreeuser2006
Posts: 59
Joined: Mon Nov 20, 2006 1:00 pm

Post by jfreeuser2006 » Fri Apr 27, 2007 7:27 am

Hello

I tried out your code and compiled it successfully but when i run it
i get this error:

Code: Select all

Exception in thread "main" java.lang.NullPointerException
        at java.util.Calendar.setTime(Calendar.java:1070)
        at org.jfree.data.time.Month.<init>(Month.java:149)
        at org.jfree.data.time.Month.<init>(Month.java:137)
        at xystepchartdemo.BarChartTest.initTimeSeries(BarChartTest.java:102)
        at xystepchartdemo.BarChartTest.<init>(BarChartTest.java:81)
        at xystepchartdemo.BarChartTest.main(BarChartTest.java:210)
Java Result: 1

jfreeuser2006
Posts: 59
Joined: Mon Nov 20, 2006 1:00 pm

Post by jfreeuser2006 » Mon Apr 30, 2007 1:20 am

The parsing of dates was throwing this exception.

Locked