Divide By Zero on setMajorTickFrequency


#1

Hi All,

I have been asked to vary the major tick frequency based on pre-defined zoom levels. So, I have determined how many major ticks I want to have, at what times in my application, and have tried to set the major tick frequency for a time axis. So far, this is always resulting in a crash. The stacktrace looks like the following:

java.lang.ArithmeticException: divide by zero
            at com.shinobicontrols.charts.cw.a(SourceFile:288)
            at com.shinobicontrols.charts.cw.a(SourceFile:238)
            at com.shinobicontrols.charts.cw.e(SourceFile:227)
            at com.shinobicontrols.charts.cw.d(SourceFile:161)
            at com.shinobicontrols.charts.cw.a(SourceFile:58)
            at com.shinobicontrols.charts.Axis.a(SourceFile:2386)
            at com.shinobicontrols.charts.x.a(SourceFile:233)
            at com.shinobicontrols.charts.t.onDraw(SourceFile:54)
            at android.view.View.draw(View.java:14465)

Here’s the chart setup code I’m using, which sets up three X axes in the same chart, with a time axis for a Y axis. We want the Y axis to show new data entering from the bottom of the chart, so we’ve set all of the Date stamps to negative numbers as a workaround.

private void setupChart(ShinobiChart chart) {

        ChartStyle chartStyle = chart.getStyle();

        mTimeAxis = new SpecialDateTimeAxis(TimeZone.getTimeZone(mWell.getTimezone()));

        NumberAxis xAxis = new NumberAxis();
        final AxisStyle xAxisStyle = xAxis.getStyle();
        xAxisStyle.getTickStyle().setLabelsShown(false);
        xAxisStyle.getTickStyle().setMinorTicksShown(false);
        xAxisStyle.getTickStyle().setMajorTicksShown(false);
        xAxis.setCurrentDisplayedRangePreservedOnUpdate(false);
        xAxis.setDefaultRange(new NumberRange(0.0, 0.01));
        chart.addXAxis(xAxis);

        NumberAxis xAxis2 = new NumberAxis();
        final AxisStyle xAxisStyle2 = xAxis2.getStyle();
        xAxisStyle2.getTickStyle().setLabelsShown(false);
        xAxisStyle2.getTickStyle().setMinorTicksShown(false);
        xAxisStyle2.getTickStyle().setMajorTicksShown(false);
        xAxis2.setCurrentDisplayedRangePreservedOnUpdate(false);
        xAxis2.setDefaultRange(new NumberRange(0.0, 0.01));
        chart.addXAxis(xAxis2);

        NumberAxis xAxis3 = new NumberAxis();
        final AxisStyle xAxisStyle3 = xAxis3.getStyle();
        xAxisStyle3.getTickStyle().setLabelsShown(false);
        xAxisStyle3.getTickStyle().setMinorTicksShown(false);
        xAxisStyle3.getTickStyle().setMajorTicksShown(false);
        xAxis3.setCurrentDisplayedRangePreservedOnUpdate(false);
        xAxis3.setDefaultRange(new NumberRange(0.0, 0.01));
        chart.addXAxis(xAxis3);

        // axis for displaying static vertical grid lines
        NumberAxis gridAxis = new NumberAxis();
        final AxisStyle gridAxisStyle = gridAxis.getStyle();
        gridAxisStyle.getTickStyle().setLabelsShown(false);
        gridAxisStyle.getTickStyle().setMinorTicksShown(false);
        gridAxisStyle.getTickStyle().setMajorTicksShown(false);
        gridAxisStyle.getGridlineStyle().setGridlinesShown(true);
        gridAxis.setCurrentDisplayedRangePreservedOnUpdate(false);
        gridAxis.setDefaultRange(new NumberRange(0.0, 100.0));

        // Set up specific grid lines
        List<Double> tickMarkValues = new ArrayList<>();
        tickMarkValues.add(0.0);
        tickMarkValues.add(25.0);
        tickMarkValues.add(50.0);
        tickMarkValues.add(75.0);
        tickMarkValues.add(100.0);
        gridAxis.setMajorTickMarkValues(tickMarkValues);

        mAnnotationAxis = gridAxis;

        chart.addXAxis(gridAxis);

        chart.setYAxis(mTimeAxis);
        mTimeAxis.enableGesturePanning(true);
        mTimeAxis.enableMomentumPanning(true);
        mTimeAxis.enableGestureZooming(true);
        mTimeAxis.enableBouncingAtLimits(true);
        mTimeAxis.allowPanningOutOfDefaultRange(true);
        mTimeAxis.allowPanningOutOfMaxRange(true);
        mTimeAxis.enableAnimation(true);
        mTimeAxis.setExpectedLongestLabel("");
        final AxisStyle style = mTimeAxis.getStyle();
        style.getGridlineStyle().setGridlinesShown(true);
        style.getTickStyle().setLabelsShown(true);
        style.getTickStyle().setTickGap(-50f);
        style.getTickStyle().setMinorTicksShown(true);
        style.getTickStyle().setMajorTicksShown(true);
        style.getTickStyle().setLabelTextSize(10.0f);

        mTimeAxis.setCurrentDisplayedRangePreservedOnUpdate(true);

        xAxis.enableAnimation(false);
        xAxis.enableGesturePanning(false);
        xAxis.enableMomentumPanning(false);

        xAxis2.enableAnimation(false);
        xAxis2.enableGesturePanning(false);
        xAxis2.enableMomentumPanning(false);

        xAxis3.enableAnimation(false);
        xAxis3.enableGesturePanning(false);
        xAxis3.enableMomentumPanning(false);
}

I am using 1.5.1 version of ShinobiControls on Android. My code is very simple at the moment, here’s the method that crashes things:

public void onEvent(SnapRangeChangedEvent event) {
    int majorGridLines = event.getSnapRange().getMajorGridLines();
    mTimeAxis.setMajorTickFrequency(new DateFrequency(majorGridLines, DateFrequency.Denomination.MINUTES));
} 

Thanks for any ideas you might have.


#2

Hello,

Thanks for getting in touch.

Currently we have no known issues in this area of the code. The one difference that stands out from the typical usecase of a DateTimeAxis is the fact that you flip the y axis by means of negative Dates. 

Is it possible for you to try running the code with the ‘date flipping’ functionality temporarily commented out?
Thanks,

Kai.


#3

Just as an update to anyone reading this post, the ‘divide by zero’ error occurs when you try to set a major tick frequency *and* have set the expected longest label to “” (i.e. the empty string). Furthermore, due to a known bug this will only happen for Y axes.

Setting the expected longest label to “” is a trick employed when moving the tick marks onto the plot area - it allows the space the labels would have taken up in the axis to be reduced. It has to be said that this isn’t really what it was intended for; in a sense setting an expected longest label of “” implies you wouldn’t be able to see the label at all. However, being able to place the tick marks on the plot area does seem to be a fairly common use case.

Both of the issues described above will be looked into but for the time being, you may find the ShinobiChart.OnTickMarkUpdateListener useful to hide ticks, or even draw extra ticks, based on their value.

Kind regards,

Patrick