mpandroidchart - How can I avoid the repeated valu

2019-01-18 09:38发布

问题:

I want to avoid the repeated values and the -0 values in Y-Axis, avoiding the image situation.

I have these ideas to solve this, but any solution:

  1. Limit the zoom before having repeated values in YAxis, therefore stop the infinite zoom-in on the chart
  2. Get the YAxis values and remove the duplicate values.

回答1:

tl;dr You can do this by changing the label count in onChartScale.

First, you want your listener set up:

chart.setOnChartGestureListener(this); // set a listener ;)

You try to get the top/bottom drawn values and check what gets drawn on the screen. Apply some basic calculations, and you're set.

The following code will draw 2 labels if the zoom level gets (too) high and up to 9 otherwise:

@Override
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
    final YAxis yAxis = mChart.getAxisLeft();
    final Transformer transformer = mChart.getTransformer(YAxis.AxisDependency.LEFT);

    // ...minor dirty hack
    final PointD top = transformer.getValuesByTouchPoint(0, 0);
    final PointD bottom = transformer.getValuesByTouchPoint(0, mChart.getHeight());
    final int diff = (int)(top.y - bottom.y);

    // draw 2-9 axis labels
    final int count = Math.min(9, Math.max(diff, 2));

    Log.d("scale", String.format("scale %f: diff %d and count %d", scaleY, diff, count));

    // "force" the count, for there are drawing issues where none get drawn on high zoom levels (just try it out)
    yAxis.setLabelCount(count, true);
}

// todo implement other interface methods

The value formatter and everything else stays the same.

And some ugly screenshot to show that it works :D



回答2:

code like this:

    mchart.setAutoScaleMinMaxEnabled(false);
    mchart.getAxisLeft().setAxisMaxValue(10);
    mchart.getAxisLeft().setAxisMinValue(5);
    mchart.getAxisRight().setAxisMaxValue(10);
    mchart.getAxisRight().setAxisMinValue(5);

or:

boolean a = isReady;
 mchart.getAxisLeft().setFormater(new format(float b){ return "" ;})

When u get data :

    mchart.setAutoScaleMinMaxEnabled(true);
    mchart.getAxisLeft().resetAxisMaxValue();
    mchart.getAxisLeft().resetAxisMinValue();
    mchart.getAxisRight().resetAxisMaxValue();
    mchart.getAxisRight().resetAxisMinValue(5);

I have no code by my hand.



回答3:

Though this is an older question I'd like to add to it for future reference. Newer versions of the library have a little known feature that resolves the duplicated labels, called granularity. This is way simpler to use than the older solutions (though to be fair, this wasn't available at the time those were posted).

You can always check the latest AxisBase Javadocs (3.0.0-beta1) for a more detailed explanation. Here are the relevant methods:

  • setGranularity(float granularity): Set a minimum interval for the axis when zooming in. The axis is not allowed to go below that limit. This can be used to avoid label duplicating when zooming in.
  • setGranularityEnabled(boolean enabled): Enabled/disable granularity control on axis value intervals. If enabled, the axis interval is not allowed to go below a certain granularity.

So in your case you'd need to set the granularity to 0.1f since you have one decimal point. The following snippet of code should avoid the repeated values on the axis:

YAxis yAxis = mChart.getAxisLeft();
yAxis.setGranularityEnabled(true);
yAxis.setGranularity(0.1f);


回答4:

If you are using IAxisValueFormatter the problem might be in the conversion of float to Int when trying to access the values array.

For me the solution was to

IAxisValueFormatter numAppointmentsXAxisFormatter = new IAxisValueFormatter() {
    @Override
    public String getFormattedValue(float value, AxisBase axis) {

        int index = (int)Math.ceil(value);
        if(index < 0){
            index = 0;
        }else if(index >= numAppointmentsLabels.size()){
            index = numAppointmentsLabels.size()-1;
        }

        return numAppointmentsLabels.get(index);
    }
};

I also added +1 to the label count

chart.getXAxis().setLabelCount(numValue+1, true);

Hope it helps



回答5:

I have never used MPAndroidCharts before, but just a little search here and there got me this method which I think would be useful.

public void setLabelCount(int count, boolean force) {

        if (count > 25)
            count = 25;
        if (count < 2)
            count = 2;

        mLabelCount = count;
        mForceLabels = force;
    }

The description says that "exact specified count of labels will be drawn and evenly distributed alongside the axis". If you can make it work in your favor, you might be able to limit the zoom.

Also, there is another method-

public int getLabelCount() {
        return mLabelCount;
    }

This returns the number of labels on the axis. Hope this helps.

https://github.com/PhilJay/MPAndroidChart/blob/5a15715b25991e3d61d27d552f9eba45975d65e7/MPChartLib/src/com/github/mikephil/charting/components/YAxis.java



回答6:

You can set granularity to your required value to prevent the repetition when zoomed.

mBarChart.getAxisLeft().setGranularity(1f);  // y-axis scale will be 0,1,2,3,4....
mBarChart.getAxisLeft().setGranularityEnabled(true);

If you want to set granularity dynamically, then implement IAxisValueFormatter and compare the return value to get the difference and set Granularity to that difference.

    private float yAxisScaleDifference = -1;
    private boolean granularitySet = false;
    //say the values returned by IAxisFormatter is in hundreds: 100, 200, 300...
    mBarChart.getAxisLeft.setValueFormatter(new IAxisValueFormatter() {
    @Override
    public String getFormattedValue(float v, AxisBase axisBase) {
        if(!granularitySet) {

            if(yAxisScaleDifference == -1) {
                yAxisScaleDifference = v;  //10
            }
            else {
                float diff = v - yAxisScaleDifference;  //200 - 100 = 100
                if(diff >= 1000) {
                    yAxisLeft.setGranularity(1000f);  
                }
                else if(diff >= 100) {
                    yAxisLeft.setGranularity(100f);  //set to 100
                }
                else if(diff >= 1f) {
                    yAxisLeft.setGranularity(1f);
                }
                granularitySet =true;
            }
        }
        return val;
    }
});

Another Example:

say Y-Axis returns [1200,3400,8000,9000....]
  first time: 1200
  second time: 3400 - 1200 = 2200
  granularity set to 1000

If the difference is not uniform you have to use array to store the differences and take the average to get the right granularity.