Daniel
Daniel

Reputation: 2592

Jfreechart optimize X axis labels

In JFreechart I have an X axis with dates (and times).

How can I ask JFreechart to optimize them and make the most out of it?

Right now it contains more label than the space and all the labels gets converted into '...'.

enter image description here

It is totally fine if not all ticks will have labels, but I want as much as can be (if they fit and can be displayed fully).

How can I achieve this?

UPDATE1:

Here is the complete minimal source to reproduce the truncated labels. (also updated the screenshot). JFreechart does not handle the optimization by default:

import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;

public class LineChart_AWT extends ApplicationFrame {

    public LineChart_AWT( String applicationTitle , String chartTitle ) {
          super(applicationTitle);
          JFreeChart lineChart = ChartFactory.createLineChart(
             chartTitle,
             "Dates","Temperature",
             createDataset(),
             PlotOrientation.VERTICAL,
             true,true,false);

          CategoryPlot plot = (CategoryPlot) lineChart.getPlot();
          plot.getRangeAxis().setRange(25, 27);

          ChartPanel chartPanel = new ChartPanel( lineChart );
          chartPanel.setPreferredSize( new java.awt.Dimension( 560 , 367 ) );
          setContentPane( chartPanel );
       }

       private DefaultCategoryDataset createDataset( ) {
          DefaultCategoryDataset dataset = new DefaultCategoryDataset( );

          dataset.addValue( 26.44,"Temperature","2019-08-18 00:00");
          dataset.addValue( 26.2,"Temperature","2019-08-18 01:00");
          dataset.addValue( 25.93,"Temperature","2019-08-18 02:00");
          dataset.addValue( 25.71,"Temperature","2019-08-18 03:00");
          dataset.addValue( 25.54,"Temperature","2019-08-18 04:00");
          dataset.addValue( 25.42,"Temperature","2019-08-18 05:00");
          dataset.addValue( 25.25,"Temperature","2019-08-18 06:00");
          dataset.addValue( 25.19,"Temperature","2019-08-18 07:00");
          dataset.addValue( 25.25,"Temperature","2019-08-18 08:00");
          dataset.addValue( 25.36,"Temperature","2019-08-18 09:00");
          dataset.addValue( 25.52,"Temperature","2019-08-18 10:00");
          dataset.addValue( 25.86,"Temperature","2019-08-18 11:00");
          dataset.addValue( 26.51,"Temperature","2019-08-18 12:00");
          dataset.addValue( 26.82,"Temperature","2019-08-18 13:00");


          return dataset;
       }

       public static void main( String[ ] args ) {
          LineChart_AWT chart = new LineChart_AWT(
             "X-axis demo" ,
             "X-axis labels are truncated");

          chart.pack( );
          RefineryUtilities.centerFrameOnScreen( chart );
          chart.setVisible( true );
       }
    }

UPDATE2:

I prefer the 45° rotation for the X-axis labels as @trashgod recommended. However this approach is not working fine when more data comes into the picture:

enter image description here

Is it possible to set the maximal allowable labels count? I would set it to some default value like 5 or 6. Or, it is also fine to define a margin or padding for increasing readability if this would hide the surroundings.

Upvotes: 3

Views: 3666

Answers (1)

trashgod
trashgod

Reputation: 205785

Your updated example creates a CategoryDataset and uses the ChartFactory method, createLineChart(), to create a CategoryPlot. You can adjust the label positions for readability as shown here and below. Moreover,

it would be nice to have a vertical grid line only when the label is visible and hide all other grid lines.

plot.getDomainAxis().setCategoryLabelPositions(
    CategoryLabelPositions.UP_45);
plot.setDomainGridlinesVisible(true);
plot.setRangeGridlinesVisible(false);

enter image description here

More generally, create a TimeSeries and use the corresponding ChartFactory method, createTimeSeriesChart(). The resulting DateAxis will automatically adjust the labels when the enclosing chart is resized. In addition,

  • You can adjust the date format as shown here.

  • To establish the chart's initial size, override getPreferredSize(), as suggested here.

  • When using setRange(), query the underlying dataset, as shown below.

  • Construct and manipulate Swing GUI objects only on the event dispatch thread.

Adjustable

import java.awt.Dimension;
import java.awt.EventQueue;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.ui.ApplicationFrame;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Day;
import org.jfree.data.time.Hour;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;

public class TempChart extends ApplicationFrame {

    public TempChart(String applicationTitle, String chartTitle) {
        super(applicationTitle);
        TimeSeries s = createSeries();
        JFreeChart chart = ChartFactory.createTimeSeriesChart(
            chartTitle, "Date", "Temperature", new TimeSeriesCollection(s));

        XYPlot plot = (XYPlot) chart.getPlot();
        plot.getRangeAxis().setRange(Math.floor(s.getMinY()), Math.ceil(s.getMaxY()));

        ChartPanel chartPanel = new ChartPanel(chart) {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(560, 367);
            }
        };
        add(chartPanel);
    }

    private TimeSeries createSeries() {
        TimeSeries series = new TimeSeries("Temperature");

        series.add(new Hour(0, new Day()), 26.44);
        series.add(new Hour(1, new Day()), 26.2);
        series.add(new Hour(2, new Day()), 25.93);
        series.add(new Hour(3, new Day()), 25.71);
        series.add(new Hour(4, new Day()), 25.54);
        series.add(new Hour(5, new Day()), 25.42);
        series.add(new Hour(6, new Day()), 25.25);
        series.add(new Hour(7, new Day()), 25.19);
        series.add(new Hour(8, new Day()), 25.25);
        series.add(new Hour(9, new Day()), 25.36);
        series.add(new Hour(10, new Day()), 25.52);
        series.add(new Hour(11, new Day()), 25.86);
        series.add(new Hour(12, new Day()), 26.51);
        series.add(new Hour(13, new Day()), 26.82);

        return series;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                TempChart chart = new TempChart(
                    "Temperature demo", "Time Axis labels adjust on resize");
                chart.pack();
                chart.setLocationRelativeTo(null);
                chart.setVisible(true);
            }
        });
    }
}

Upvotes: 4

Related Questions