Skip to content

Linked Charts with Charba: small date intervals can be a problem #89

@Speykious

Description

@Speykious

I want to be able to create linked time series charts with Charba, where zooming and panning in one zooms in the other.

The previous issue #88 derived into a discussion about this, so I wanted to properly continue it here.
When doing my tests to synchronize charts, I realized that it wasn't working because of the random dataset example I was working with.

With the following code:

private TimeSeriesLineChartWidget createLineChart() {
    TimeSeriesLineChartWidget chart = new TimeSeriesLineChartWidget();

    TimeSeriesLineOptions chartOptions = chart.getOptions();
    chartOptions.setResponsive(true);
    chartOptions.setAspectRatio(3.5);
    chartOptions.setMaintainAspectRatio(true);
    chartOptions.getLegend().setDisplay(true);
    chartOptions.getTitle().setDisplay(true);
    chartOptions.getTitle().setText("oui");
    chartOptions.getTooltips().setEnabled(true);
    chartOptions.setAnimationEnabled(false);
    chartOptions.getDecimation().setEnabled(true);
    chartOptions.getDecimation().setAlgorithm(DecimationAlgorithm.MIN_MAX);

    // tooltip interaction options
    Interaction interaction = chartOptions.getInteraction();
    interaction.setMode(InteractionMode.NEAREST);
    interaction.setAxis(InteractionAxis.X);
    interaction.setIntersect(false);

    // axes options
    CartesianTimeSeriesAxis xAxis = chartOptions.getScales().getTimeAxis();
    xAxis.getTitle().setDisplay(true);
    xAxis.getTitle().setText("Time");
    xAxis.getTicks().setSource(TickSource.DATA);
    xAxis.getTime().setUnit(TimeUnit.SECOND);
    xAxis.getTime().getDisplayFormats().setDisplayFormat(TimeUnit.SECOND, "m’ss”");
    xAxis.getTime().getDisplayFormats().setDisplayFormat(TimeUnit.MINUTE, "H:mm:ss");
    xAxis.getTime().getDisplayFormats().setDisplayFormat(TimeUnit.HOUR, "H:mm:ss");

    xAxis.setMin((ScaleContext context) -> {
        return _minDate;
    });

    xAxis.setMax((ScaleContext context) -> {
        return _maxDate;
    });

    CartesianLinearAxis yAxis = chartOptions.getScales().getLinearAxis();
    yAxis.getTitle().setDisplay(true);
    yAxis.getTitle().setText("Fromage");
    yAxis.setDisplay(true);
    yAxis.setBeginAtZero(true);

    // zoom options
    ZoomOptions zoomOptions = new ZoomOptions();
    zoomOptions.getPan().setEnabled(true);
    zoomOptions.getPan().setModifierKey(ModifierKey.ALT);
    zoomOptions.getPan().setMode(Mode.X);
    zoomOptions.getZoom().setMode(Mode.X);
    zoomOptions.getZoom().getDrag().setEnabled(true);
    zoomOptions.getZoom().getWheel().setEnabled(true);
    zoomOptions.getZoom().getWheel().setSpeed(0.3);
    zoomOptions.getZoom().getWheel().setModifierKey(ModifierKey.ALT);
    zoomOptions.getZoom().getPinch().setEnabled(true);
    zoomOptions.store(chart);

    zoomOptions.getZoom().setCompletedCallback((ZoomContext context) -> {
        CartesianTimeSeriesAxis timeAxis = chartOptions.getScales().getTimeAxis();
        ScaleItem scaleAxis = chart.getNode().getScales().getItems().get(timeAxis.getId().value());

        for (TimeSeriesLineChartWidget rawChart : _rawCharts) {
            if (rawChart == chart)
                continue;
            _minDate = scaleAxis.getMinAsDate();
            _maxDate = scaleAxis.getMaxAsDate();
            rawChart.update();
        }
    });

    long start = new Date().getTime();

    TimeSeriesItem[] data = new TimeSeriesItem[20];
    for (int i = 0; i < data.length; i++)
        data[i] = new TimeSeriesItem(new Date((long) i + start), Random.nextDouble());

    // dataset
    TimeSeriesLineDataset dataset = chart.newDataset();
    dataset.setLabel("fromage");
    dataset.setBorderColor(Color.CHARBA);
    dataset.setBorderWidth(1);
    dataset.setPointRadius(0);
    dataset.setParsing(false);
    dataset.setTimeSeriesData(data);

    chart.getData().setDatasets(dataset);

    _rawCharts.add(chart);
    return chart;
}

as soon as I try to zoom, the synchronization completely breaks and the second graph shows nothing (the actual graph is there, but hidden far to the right).
image

I realized after hours of debugging, with the help of a coworker, that the dataset may have been too short and too compact - maybe I was losing precision on the dates?

And so I tried the code above, with these modifications:

     TimeSeriesItem[] data = new TimeSeriesItem[20];
     for (int i = 0; i < data.length; i++)
-        data[i] = new TimeSeriesItem(new Date((long) i + start), Random.nextDouble());
+        data[i] = new TimeSeriesItem(new Date(((long) i) * 17271 + start), Random.nextDouble());

And now it works!
image

I'm glad I managed to fix my problem, but I was wondering why the dates I generated created this problem in the first place. For our use-case, it will probably not be relevant, but it's probably important to mention here that such a thing is happening.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions