2

I have timeSeries containing number of visitors for a web page in two days and then referential timeSeries containing number of visitors for a web page in other two days. I successfully put these datasets into one chart, but it seems that secondary domain axis I added is much narrower and thus it is impossible to compare those values.

enter image description here

Can I set the width of those axes to be the same?

EDIT: I posted my method to create JFreeChart down below. There is 48 values for both datasets.

public JFreeChart HourChart(CampaignWatcher choosenWatcher) throws UnknownHostException {
    ArrayList<ArrayList<HourObject>> data = GetWatcherData(choosenWatcher);
    TimeSeries timeSeries = new TimeSeries("Number of visitors");
    TimeSeries timeSeriesRef = new TimeSeries("Referential number of visitors");


    for(int i = 0; i<data.get(0).size();i++) {

        timeSeries.add(new Hour(data.get(0).get(i).hour,data.get(0).get(i).day,data.get(0).get(i).month,data.get(0).get(i).year),data.get(0).get(i).logObjects.size());
    }

    if(choosenWatcher.compareWithRef){
        for(int i = 0; i<data.get(1).size();i++) {
            timeSeriesRef.add(new Hour(data.get(1).get(i).hour,data.get(1).get(i).day,data.get(1).get(i).month,data.get(1).get(i).year),data.get(1).get(i).logObjects.size());
        }
    }

    TimeSeriesCollection dataset = new TimeSeriesCollection();
    dataset.addSeries(timeSeries);

    JFreeChart timeChart = ChartFactory.createTimeSeriesChart(choosenWatcher.name,"Hours","Number of visitors",dataset);

    timeChart.setBackgroundPaint(Color.white);

    XYPlot plot = (XYPlot) timeChart.getPlot();
    plot.setBackgroundPaint(Color.WHITE);
    plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
    plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
    plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
    //plot.setDomainCrosshairVisible(true);
    //plot.setRangeCrosshairVisible(true);

    XYItemRenderer r = plot.getRenderer();
    if (r instanceof XYLineAndShapeRenderer) {
        XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r;
        renderer.setDefaultLinesVisible(true);
        renderer.setDefaultShapesFilled(true);
        renderer.setDrawSeriesLineAsPath(true);
    }

    DateAxis axis = (DateAxis) plot.getDomainAxis();
    axis.setDateFormatOverride(new SimpleDateFormat("dd/MMM/yyyy HH"));

    DateAxis axisRef = new DateAxis("Referential hours");
    axisRef.setDateFormatOverride(new SimpleDateFormat("dd/MMM/yyyy HH"));


    plot.setDomainAxis(1, axisRef);

    plot.setDomainAxisLocation(1,AxisLocation.BOTTOM_OR_RIGHT);

    TimeSeriesCollection datasetRef = new TimeSeriesCollection();
    datasetRef.addSeries(timeSeriesRef);
    plot.setDataset(1,datasetRef);

    plot.mapDatasetToDomainAxis(1,1);
    plot.mapDatasetToRangeAxis(1,0);

    XYLineAndShapeRenderer renderer0 = new XYLineAndShapeRenderer();
    XYLineAndShapeRenderer renderer1 = new XYLineAndShapeRenderer();

    plot.setRenderer(0, renderer0);
    plot.setRenderer(1, renderer1);

    plot.getRendererForDataset(plot.getDataset(0)).setSeriesPaint(0, Color.red);
    plot.getRendererForDataset(plot.getDataset(1)).setSeriesPaint(0, Color.blue);

    plot.setDomainPannable(true);
    plot.setRangePannable(true);

    ValueAxis valAxis = plot.getRangeAxis();

    valAxis.setAutoRange(true);

    return timeChart;
}
Tyro
  • 103
  • 11
  • Although using differing fonts, the axes are identical in screen length and time span. The intervals appear to be consecutive, and I see that both show fewer visitors at night and more during the day. What did you expect to see? In any case, please [edit] your question to include a [mcve] that shows the chart you illustrate. – trashgod Apr 07 '19 at 02:16
  • As you can see in the picture, even though both those charts should present 48 hours. However blue chart line ends sooner than red line, blue circles are not at the same position (on domain axis) as red rectangles. – Tyro Apr 07 '19 at 10:39
  • I presume that the times differ; your [mcve] may clarify. – trashgod Apr 07 '19 at 10:50
  • @trashgod yes, there are data from 21st of March to 22nd of March (red) and from 23rd of March to 24th of March (blue). But there is same amount of hours. – Tyro Apr 07 '19 at 12:53
  • Look at each timestamp's milliseconds from the [epoch](https://stackoverflow.com/search?tab=votes&q=user%3a230513%20%5bjfreechart%5d%20epoch). – trashgod Apr 07 '19 at 18:54

1 Answers1

2

The comparison approach shown in your fragment appears sound, but I suspect that your unseen data has multiple, varying timestamps for a given hourly interval, which the DateAxis faithfully reports.

The variation below clears the smaller Calendar fields, as shown here, to synthesize a DAYS worth of data. The resulting Hour instances have matching hour fields in each series. The example also omits the ChartFactory to avoid the unwanted ChartTheme axis label font.

To get the result you want, you're going have to resample your data to have matching hour fields for each period that you add() to a TimeSeries.

image

import java.awt.Color;
import java.awt.EventQueue;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.swing.JFrame;
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.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Hour;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;

/**
 * @see https://stackoverflow.com/a/55584636/230513
 * @see https://stackoverflow.com/q/55553082/230513
 */
public class HourTest {

    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MMM HH");
    private static final int DAYS = 1;

    private Calendar getCalendar() {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);return c;
    }

    private void display() {
        JFrame f = new JFrame("HourTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        TimeSeries timeSeries = new TimeSeries("Number of visitors");
        TimeSeries refSeries = new TimeSeries("Reference number of visitors");
        Calendar c1 = getCalendar();
        Calendar c2 = getCalendar();
        c2.add(Calendar.DAY_OF_YEAR, -DAYS);
        for (int i = 0; i < 24 * DAYS; i++) {
            timeSeries.add(new Hour(c1.getTime()), i + 2);
            c1.add(Calendar.HOUR, 1);
            refSeries.add(new Hour(c2.getTime()), i + 1);
            c2.add(Calendar.HOUR, 1);
        }
        TimeSeriesCollection dataset = new TimeSeriesCollection(timeSeries);
        TimeSeriesCollection refDataset = new TimeSeriesCollection(refSeries);
        NumberAxis valueAxis = new NumberAxis("Number of visitors");
        valueAxis.setAutoRangeIncludesZero(false);
        DateAxis timeAxis = new DateAxis("Hours");
        timeAxis.setDateFormatOverride(DATE_FORMAT);
        DateAxis refAxis = new DateAxis("Reference hours");
        refAxis.setDateFormatOverride(DATE_FORMAT);
        XYPlot plot = new XYPlot(dataset, timeAxis, valueAxis, null);
        plot.setBackgroundPaint(Color.WHITE);
        plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
        plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
        plot.setDomainAxis(1, refAxis);
        plot.setDomainAxisLocation(1, AxisLocation.BOTTOM_OR_RIGHT);
        plot.setDataset(1, refDataset);
        plot.mapDatasetToDomainAxis(1, 1);
        XYLineAndShapeRenderer renderer0 = new XYLineAndShapeRenderer();
        renderer0.setSeriesPaint(0, Color.red);
        XYLineAndShapeRenderer renderer1 = new XYLineAndShapeRenderer();
        renderer1.setSeriesPaint(0, Color.blue);
        plot.setRenderer(0, renderer0);
        plot.setRenderer(1, renderer1);
        plot.setDomainPannable(true);
        plot.setRangePannable(true);
        JFreeChart timeChart = new JFreeChart("Main stats", plot);
        timeChart.setBackgroundPaint(Color.white);

        f.add(new ChartPanel(timeChart));
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new HourTest()::display);
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Also consider a histogram, seen [here](https://stackoverflow.com/a/28519356/230513), for ease of comparison. – trashgod Apr 10 '19 at 16:55