Just started using the MPAndroidChart version 3.0.0 beta and i have created a project that can show my values in a bar chart. My question is where do i add and display labels.
Each Bar should have its own label eg. "Flue", "Cheese" etc at the bottom. Not sure what function does this, am actively searching and reading the Docs/Wiki but no joy currently.
Depending on your preferences, you can use the data property of an Entry to store the label and then return it in your IAxisValueFormatter implementation:
public class LabelValueFormatter implements IAxisValueFormatter {
private final DataSet mData;
public LabelValueFormatter(DataSet data) {
mData = data;
}
#Override
public String getFormattedValue(float value, AxisBase axis) {
// return the entry's data which represents the label
return (String) mData.getEntryForXPos(value, DataSet.Rounding.CLOSEST).getData();
}
}
This approach allows you to use the Entry constructor (or BarEntry in this case) to add the labels, which can improve the readability of your code:
ArrayList<BarEntry> entries = new ArrayList<>();
for (int i = 0; i < length; i++) {
// retrieve x-value, y-value and label
entries.add(new BarEntry(x, y, label));
}
BarDataSet dataSet = new BarDataSet(entries, "description");
BarData data = new BarData(dataSet);
mBarChart.setData(data);
mBarChart.getXAxis().setValueFormatter(new LabelValueFormatter(data));
Also check out this answer for more information and an alternative approach on using labels with the BarChart and the new 3.0.0 version of the library.
Related
i am using MPAndroidChart barchart ... every thing is okay except the x-axis... my bars are not aligned properly on labels. when i zoome the chart then bars come on its labels but that zoom is not what i wanted and also when i zooming the labels repeat until next and so on.
my data is like eg:
age(x) weight(y)
2 90
5 100
7 200
10 300
the age is my labels and it is string type ... i need it to be string label.
this is what i got
this is my code in c#
//-----chart-------------
barChart = FindViewById<BarChart>(Resource.Id.barChart);
List<BarEntry> entries = new List<BarEntry>();
List<string> labelz = new List<string>();
int c = 0;
foreach(var rec in weighting_lst)
{
entries.Add(new BarEntry(c, rec.Weight));
labelz.Add(rec.Age.ToString());
c++;
}
BarDataSet dataset = new BarDataSet(entries, "وزن به گرم");
BarData data = new BarData(dataset);
var xdata = barChart.XAxis;
xdata.ValueFormatter = new MyLabelFormatter(labelz);
xdata.SetCenterAxisLabels(false);
barChart.Data = data;
barChart.SetScaleEnabled(true);
barChart.SetFitBars(true);
public class MyLabelFormatter : Java.Lang.Object, IAxisValueFormatter
{
//private string[] customLabels = new string[] { "A", "B", "C", "D", "E", "F" };
public List<string> label_lst = new List<string>();
public MyLabelFormatter(List<string> _label_lst)
{
label_lst = _label_lst;
}
public string GetFormattedValue(float value, AxisBase axis)
{
return label_lst[(int)value % label_lst.Count];
}
}
for x position of bar entry i just use integer called c which increases by 1 on each loop so it gives me like 0f,1f,2f,......
i added xdata.Granularity = 1f; and it works for me .... xdata is my Xaxis
I am working with a project which is using MPAndroidChart library which makes me really crazy, I want to remove it.
The problem is I have created a custom ValueFormatter and I can't understand where these values come from, all are wrong.
private void setData() {
for (int i = 1; i <= 10; i++) {
Entry entry = new Entry(i, i);
values.add(entry);
}
IAxisValueFormatter valueFormatter = new myValueFormatter();
XAxis xAxis = mChart.getXAxis();
xAxis.setValueFormatter(valueFormatter);
LineDataSet set1 = new LineDataSet(values, "DataSet 1");
ArrayList<ILineDataSet> dataSets = new ArrayList<ILineDataSet>();
dataSets.add(set1); // add the datasets
// create a data object with the datasets
LineData data = new LineData(dataSets);
// set data
mChart.setData(data);
}
custom formatter class:
I have an array which has 1,2,3,4,5,6,7,8,9,10 values
but I get 2,4,6,8,10 values in getFormattedValue method.
public classmyValueFormatter implements IAxisValueFormatter {
#Override
public String getFormattedValue(float value, AxisBase axis) {
System.out.println(value); //Here I get odd values where they come from I don't know.
}
}
Well, generally that's how library is written. Have a look here:
https://github.com/PhilJay/MPAndroidChart/blob/master/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/XAxisRenderer.java#L205
String label = mXAxis.getValueFormatter().getFormattedValue(mXAxis.mEntries[i / 2], mXAxis);
Author's intention was probably to give more spacing between labels. If you think this is a bug, submit issue to library's repository on Github.
I have a small problem. I'm trying to make a listView of BarCharts, where xAxis represents categories, and yAxis - cost.
Here is my data.
entry
entries.add(new BarEntry(xAxis, cost, categoryName));
xAxis is just a position in chart, I put category name as 3rd parameter. Then I put it in array list of BarData
ArrayList<BarData> months = new ArrayList<>();
BarDataSet set = new BarDataSet(entries, monthName);
ArrayList<IBarDataSet> dataSets = new ArrayList<>();
dataSets.add(set);
BarData barData = new BarData(dataSets);
months.add(barData);
Then in adapter I set value formatter
BarData data = getItem(position);
...
xAxis.setValueFormatter(new MyValueFormatter(data.getDataSetByIndex(0)));
and in MyValueFormatter I'm trying to get category name from entry and set it as xAxis value.
public class MyValueFormatter implements IAxisValueFormatter {
private IBarDataSet mDataSet;
public StatisticByMonthValueFormatter(IBarDataSet data) {
mDataSet = data;
}
#Override
public String getFormattedValue(float value, AxisBase axis) {
return (String) mDataSet.getEntryForIndex((int) value).getData();
}
}
This woks, but sometimes when I'm scrolling list view I get
java.lang.IndexOutOfBoundsException: Invalid index 4, size is 2.
I know, that bug in the getFormattedValue method in MyValueFormatter, but i don't understand how can I fix this, or how implement this in the right way?
DataSet#getEntryForIndex(int index)
is the wrong method to call here. Entry in a DataSet are stored in a backing array and this method will get the Entry at that index in the backing array. This doesn't always correspond to the Entry for that x-value (the x-value on the chart). Hence, the IndexOutOfBoundsException.
You would want to do something this instead:
return (String) mDataSet.getEntryXPos(float value).getData();
See the javadoc for DataSet for further explanation
Here is static value of integer
private int upload=14, bill=15, unbill=85, total=100, unupload=12, sign=10, unsign=90, print=12, unprint=88;
Set entry of pie chart
ArrayList<Entry> entries = new ArrayList<>();
entries.add(new Entry(bill, 0));
entries.add(new Entry(unbill, 1));
entries.add(new Entry(print, 2));
entries.add(new Entry(unprint, 3));
entries.add(new Entry(sign, 4));
entries.add(new Entry(unsign, 5));
entries.add(new Entry(upload, 6));
entries.add(new Entry(unupload, 7));
int colors[] ={Color.rgb(84, 139, 221), Color.rgb(251, 249, 146),Color.rgb(151, 212, 153), Color.rgb(183, 144, 189),Color.rgb(226, 148, 188),Color.rgb(208, 189, 121),Color.rgb(185, 147, 134),Color.rgb(206, 139, 130)};
Here I am using Mikephil PieChart, below I added entries in dataset.
PieDataSet dataset = new PieDataSet(entries, "Graph");
dataset.setColors(colors);
dataset.setSliceSpace(3f);
I am getting this output. So i want to remove decimal places which I mentioned in
Output is perfect. I just want output without decimal places. How can I do that?
set ValueFormatter as follows
pieData.setValueFormatter(new ValueFormatter() {
#Override
public String getFormattedValue(float value) {
return String.valueOf((int) Math.floor(value));
}
});
The question is essentially the same as this one which has a good answer already. This relevant question also has canonical answer by the library author. It's great to ask questions, but in the future you can avoid downvotes to your questions by researching them before hand to make sure they have not already been asked.
There is absolutely no need to add the library as a .jar file and edit the library code as in the previous low-quality answer. This just defeats the whole purpose of using a library and using build tools like Gradle.
As per the exact inside the accepted answer to the duplicate linked above, write a class that implements IValueFormatter like this:
public class IntValueFormatter implements IValueFormatter {
#Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return String.valueOf((int) value);
}
}
Then you consume it like this:
pieDataSet.setValueFormatter(new IntValueFormatter());
First Step:
Please put this below "PercentFormatter" class in your package folder:
public class PercentFormatter extends ValueFormatter {
public DecimalFormat mFormat;
private PieChart pieChart;
public PercentFormatter() {
mFormat = new DecimalFormat("###,###,##");
}
public PercentFormatter(PieChart pieChart) {
this();
this.pieChart = pieChart;
}
#Override
public String getFormattedValue(float value) {
return mFormat.format(value) + " %";
}
#Override
public String getPieLabel(float value, PieEntry pieEntry) {
if (pieChart != null && pieChart.isUsePercentValuesEnabled()) {
// Converted to percent
return getFormattedValue(value);
} else {
// raw value, skip percent sign
return mFormat.format(value);
}
}
}
Second Step:
In your activity where the Piedata set, add value format in the PieDataset that way:
pieDataSet.setValueFormatter(new PercentFormatter());
PieData pieData = new PieData(pieDataSet);
pieChart.setData(pieData);
That way, we can remove the decimal point in the Pie data.
You need to create a custom percentFormatter to format the percentage presentation on a chart.
public class Remover extends PercentFormatter {
private DecimalFormat mDecimalFormat;
public Remover (DecimalFormat format) {
this.mDecimalFormat = format;
}
#Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return "% " + mDecimalFormat.format(value) ;
}
}
You can then assign this formatter to your chart by calling setValueFormatter() on the chart object.
return String.valueOf(Math.floor(value)).replace(".0","") This worked for me
if you can input integer value as parameter you can or if the library method doesnt accepts integer value you have to customize the library !
I am using MPAndroidChart and have the need to plot a number of datasets using ScatterChart. As the number of datasets is dynamic, I used a logic that creates a combination of color and shape for each dataset. The resultant chart looks like this. As you can see, in this example, there are ten datasets, each represented by a unique Shape+Color combination. The problem is with the legend shapes. How do I change the legend shapes to match with the dataset shapes?
Chart:
Source Code:
private static final int SCATTER_SHAPES_MOD = 4; //there are four shapes
private static final int SCATTER_COLOR_MOD = 5; //there are five colors
for (int i=0; i < dataSeries.size(); i++) {
ScatterDataSet set = new ScatterDataSet(dataSeries.get(i), choiceArray[i]);
set.setScatterShape(ScatterShapeArray[i % SCATTER_SHAPES_MOD]);
set.setColor(ColorTemplate.COLORFUL_COLORS[i % SCATTER_COLOR_MOD]);
set.setScatterShapeSize(10f);
set.setDrawValues(false); // Hide data labels
dataSets.add(set); // add the dataset
}
if (dataSeries.size() > 0) {
data = new ScatterData(xVals, dataSets);
// Set chart data
chart.setData(data);
}
Actually, now Dear Philipp has added that functionality, I think he forgot to update here, hence I am updating so that for someone it may help.
There is a new function called setCustom in legend class which can be used for the above purpose.I have tested it.Please find code below. The looping is done with dataSets I had already(ScatteredDataSet in my case).
List<LegendEntry> entries = new ArrayList<>();
for (int i = 0; i < dataSets.size(); i++) {
final LegendEntry entry = new LegendEntry();
IScatterDataSet set = dataSets.get(i);
String Label = set.getLabel();
if (Label.equalsIgnoreCase("A")) {
entry.form = Legend.LegendForm.CIRCLE;
entry.formColor = set.getColor();
entry.label = Label;
} else if(Label.equalsIgnoreCase("B")){
entry.form = Legend.LegendForm.CIRCLE;
entry.formColor = set.getColor();
entry.label = Label;
} else if(Label.equals("C")){
entry.form = Legend.LegendForm.SQUARE;
entry.formColor = set.getColor();
entry.label = Label;
}
else if (entry.formColor == ColorTemplate.COLOR_NONE ||
entry.formColor == 0) {
entry.form = Legend.LegendForm.EMPTY;
entry.label = Label;
}
entries.add(entry);
}
LegendEntry[] mEntries = entries.toArray(new LegendEntry[entries.size()]);
Legend l = mChart.getLegend();
l.setCustom(mEntries);
l.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.RIGHT);
l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
l.setDrawInside(false);
l.setXOffset(10f);
I Thank Philipp for this awesome library.
NOTE:Only limitation I see is that LegendForm has only few shapes as enum which can't be altered and Scatter chart has more shapes which can't be replicated in Legends!If there is a way please post here.
Unfortunately that is currently not possible by default.
You will have to modify the library to get the behaviour you are describing.
I might add a feature like that in the future.