问题
I've created a BarChart using MPAndroidChart and I'm entering the data dynamically. This means that I need my Y axis to also be determined dynamically. All of my data is represented as integers, however the Y axis is sometimes displaying the legend as decimal values with 1 decimal point.
I've attempted to use a ValueFormatter to round the values, but the problem is that sometimes the Y values aren't at integer value locations (ex. 0.8,1.6,2.4,etc). Therefore, if I just edit these to be integers they won't be in the right location.
Is there anyway that I can force the BarChart to only display values at Integer locations? Its ok if it skips some, in fact I want it to when the values get large.
Edit: When I said that the integers aren't in the right locations, I meant that once I modify what each label displays they aren't 'correct'. In my example I have 5 bars displaying the values 3,4,2,3,2. The first image is the 'default', the second is the image once I've edited the value formatter using:
myBarChart.getYLabels().setFormatter(new ValueFormatter()
{
@Override
public String getFormattedValue(float v)
{
return ((int) v)+"";
}
});
As we can see from these images, my integer values are not where they should be (and there are two '2s'). In this example I'd except it to display the values 0,1,2,3,4. If I have a lot more data I'm hoping it would be smart enough to only show what values I have room for, so for examples if the data contains values of 0-50 it would show something like 0,10,20,30,40,50 or possibly 0,15,30,45, etc.
回答1:
Allright, now I see your problem.
THe problem is that the YAxis
(YLabels) determines the number of digits and thus the steps between each label automatically.
Unfortunately it's currently not possible to customize how the axis computes itself or set custom labels.
I am considering to add such a feature in the future, where the user can self define which values are drawn as the axis labels.
Just a hint:
The mEntries
array that holds all the axis labels is public. So in general, you could modify it after it has been created.
However, I am absolutely not sure how the axis will behave if you manually modify it.
But maybe its worth a try :-) https://github.com/PhilJay/MPAndroidChart/blob/master/MPChartLib/src/com/github/mikephil/charting/components/YAxis.java
回答2:
Pretty simple. All you need is two things:
Axis value formatter
mChart.getAxisLeft().setValueFormatter(new ValueFormatter() { @Override public String getFormattedValue(float value) { return String.valueOf((int) Math.floor(value)); } });
Axis label count
int max = findMaxYValue(yourdata); // figure out the max value in your dataset mChart.getAxisLeft().setLabelCount(max);
回答3:
This is how I resolved this issue. It seems like the y axis is always drawn 1 over the max value(if its not force it). So set the label count 2 over the max value(include zero and one over your max) then all you need to do is remove the decimal with the axis formatter. This works if all your y values are integers, not sure how it would work with decimal values.
barChart.getAxisLeft().setLabelCount(maxYvalue + 2, true);
barChart.getAxisLeft().setAxisMinValue(0f);
barChart.getAxisLeft().setAxisMaxValue(maxYvalue + 1);
YAxisValueFormatter customYaxisFormatter = new YAxisValueFormatter() {
@Override
public String getFormattedValue(float value, YAxis yAxis) {
return String.valueOf((int)value);
}
};
barChart.getAxisLeft().setValueFormatter(customYaxisFormatter);
回答4:
After looking around with no solution available, I've decided to look into the javadoc and found out about this method: setGranularity(float)
. To force the YAxis to always display integers (or any interval you want), you just need to call this:
yAxisLeft.setGranularity(1.0f);
yAxisLeft.setGranularityEnabled(true); // Required to enable granularity
However, if the min and max values of the chart is too close, then the chart will not honor setLabelCount()
, unless when is forced (which will make the labels in decimal again), so you need to call this after setting data:
private void calculateMinMax(BarLineChartBase chart, int labelCount) {
float maxValue = chart.getData().getYMax();
float minValue = chart.getData().getYMin();
if ((maxValue - minValue) < labelCount) {
float diff = labelCount - (maxValue - minValue);
maxValue = maxValue + diff;
chart.getAxisLeft().setAxisMaximum(maxValue);
chart.getAxisLeft().setAxisMinimum(minValue);
}
}
And that's it!
回答5:
I know that I am answering very late, but I am trying to throw some more light on this issue so that future users have a bit more knowledge regarding the same.
I also faced the same issue. I used MyYAxisValueFormatter
to display only integer value in Y-Axis
. Below is the code for the same.
public class MyYAxisValueFormatter implements YAxisValueFormatter {
private DecimalFormat mFormat;
public MyYAxisValueFormatter () {
mFormat = new DecimalFormat("###,###,##0");
}
@Override
public String getFormattedValue(float value, YAxis yAxis) {
// write your logic here
// access the YAxis object to get more information
return mFormat.format(value);
}
}
By using this class what happens is definitely it displays the Y-Axis values in integer format but also duplicate some value. That is because of conversion of float value to integer.
Let say for example 0.4 will be converted to 0 so there will be two or may be more 0 values in Y-Axis.
I think this is what happening in case of @Fozefy
.
I implemented below given code to solve this issue and its work like a charm. I used setAxisMaxValue
function to set a custom maximum value for Y-axis and setLabelCount
to sets the number of label entries for the Y-Axis.
YAxis yAxis = chart.getAxis(YAxis.AxisDependency.LEFT);
// Minimum section is 1.0f, could be 0.25f for float values
float labelInterval = 1.0f / 2f;
int sections; //No of sections in Y-Axis, Means your Highest Y-value.
do {
labelInterval *= 2; //Interval between labels in Y-Axis
sections = ((int) Math.ceil(chart.getYMax() / labelInterval));
} while (sections > 10);
// If the ymax lies on one of the top interval, add another one for some spacing
if (chart.getYMax() == sections * labelInterval) {
sections++;
}
yAxis.setAxisMaximum(labelInterval * sections);
yAxis.setLabelCount(sections + 1, true);
Label interval remains one if your maximum y-value is less than 10 otherwise two. You can customize this behavior as per your requirement and also increase label interval by modifying do-while loop.
Also make sure that you are using setLabelCount(int count, boolean force)
method and passing force
value to true
.
回答6:
My Solution:
mChart.getAxisLeft().setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float value) {
return String.valueOf((int) Math.floor(value));
}
});
int max = (int) mChart.getData().getYMax();
mChart.getAxisLeft().setLabelCount(max);
回答7:
Here is the simple solution which will benefit someone who is looking for the answer.
Y-Axis labels count
barChart.getAxisLeft().setLabelCount(7, true); //if you want 6 labels then value should be 7
Calculate
maxValue
- Get
maxValue
from values need to be included in the chart
int maxValueMod = (maxValue + 2) % 6; //calc mod, here 2 is to display Legend and 6 is no of labels maxValue = maxValue + (6-maxValueMod); // calculate final maxValue to set in barchart barChart.getAxisLeft().setAxisMaximum(maxValue+2); ```
- Get
回答8:
To add to the solution, if someone just wants to remove the decimal and repeated values, you can do this :
IAxisValueFormatter yAxisValueFormatter = new IAxisValueFormatter() {
@Override
public String getFormattedValue(float v, AxisBase axisBase) {
//check for decimal value
if (v - (int) v != 0) {
return "";
} else {
return String.valueOf((int) v);
}
}
};
leftAxis.setValueFormatter(yAxisValueFormatter);
rightAxis.setValueFormatter(yAxisValueFormatter);
来源:https://stackoverflow.com/questions/28753540/force-barchart-y-axis-labels-to-be-integers