MPAndroidChart: negative values in pie chart or custom labels - android

In my Android application I have to show my income and expense amounts in a piechart. The expense amounts will be negative. The amounts are of type float. So is it possible to display both negative and positive values in a pie chart using MPAndroidChart library?
I have tried with some negative and positive integer values and the result is horible. The pie-chart will behave crazy like a rummy board or illumination screen.
If I can't have negative values in a pie chart, is it possible to show the labels in negative by even though the actual values are positive?

You are essentially asking how to customise the labels on an MPAndroidChart chart. This can be done easily by writing your own implementation of the interface IValueFormatter.
IValueFormatter has one method that you need to implement:
getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler)`
You use the parameters of the method to construct the label you want as a String. You want a minus sign "-" in front so you simply do this:
return "-" + mFormat.format(value) + " %";
Here is the complete implementation:
public class NegativePercentFormatter implements IValueFormatter
protected DecimalFormat mFormat;
public NegativePercentFormatter() {
mFormat = new DecimalFormat("###,###,##0.0");
}
public NegativePercentFormatter(DecimalFormat format) {
this.mFormat = format;
}
#Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return "-" + mFormat.format(value) + " %";
}
}

Related

How to set two decimal point into Bar Entry in Mp android Bar Chart in Android

How to set J SON data in bar entry in two decimal point?
You can use The ValueFormatter interface
The IValueFormatter interface can be used to create custom-made formatter classes that allow to format values within the chart (from DataSets) in a specific way before drawing them.
For using the IValueFormatter, simply create a new class and let it implement the interface and return whatever you want to be displayed from the getFormattedValue(...) method.
Creating a Formatter
public class MyValueFormatter implements IValueFormatter {
private DecimalFormat mFormat;
public MyValueFormatter() {
mFormat = new DecimalFormat("###,###,##0.0"); // use one decimal
}
#Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
// write your logic here
return mFormat.format(value) + " $"; // e.g. append a dollar-sign
}
}
Then, set your formatter to the ChartData or DataSet object:
// usage on whole data object
lineData.setValueFormatter(new MyValueFormatter());
// usage on individual dataset object
lineDataSet.setValueFormatter(new MyValueFormatter());
Predefined Formatters
LargeValueFormatter: Can be used for formatting large values >
"1.000". It will turn values like "1.000" into "1k", "1.000.000" will
be "1m" (million), "1.000.000.000" will be "1b" (billion) and values
like one trillion will be e.g. "1t".
PercentFormatter: Used for
displaying a "%" sign after each value with 1 decimal digit.
Especially useful for the PieChart. 50 -> 50.0 %
StackedValueFormatter: A formatter specifically designed to be used
with stacked BarChart. It allows to specify whether all stack values
should be drawn or just the top value.

Passing current time in milliseconds to MPChart breaks it

I have tried figuring this out, but it doesn't add up. The data doesn't appear as it should.
First I generate dummy data. This is done async because I need time between the calls to System.currentTimeMillis to get some spacing between them. (Look aside the crappy code here, this is just debug data that will not be in the release. Using Thread.sleep on the main thread is a bad idea considering ANR's)
public class AsyncGeneration extends AsyncTask<String, String, String>{
public AsyncGeneration() {
super();
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
#Override
protected void onCancelled(String s) {
super.onCancelled(s);
}
#Override
protected void onCancelled() {
super.onCancelled();
}
#Override
protected String doInBackground(String... strings) {
while(root == null) {
try {
Thread.sleep(200);
}catch(InterruptedException e){}
}
List<Entry> rdata = new ArrayList<>();
for(int i = 1; i < 30; i++){
try{
Thread.sleep(200);
}catch(Exception e){
//IGNORE
}
float time = System.currentTimeMillis();
Log.e("GChart", "Timex: " + time);
Session s = new Session(r.nextInt(5000), time);//Replace time with the index in the for-loop and it works for some reason
rdata.add(new Entry(s.getXValue(), s.getYValue()));
Log.e("GChart", "Timey: " + s.getXValue());
}
final List<Entry> entries = rdata;
OverviewFragment.this.getActivity().runOnUiThread(() ->{
LineDataSet data = new LineDataSet(entries, "Distance");
data.setCircleColor(Color.parseColor("#FF0000"));
LineData lineData = new LineData(data);
tab1chart.setData(lineData);
tab1chart.invalidate(); // refresh
tab1chart.getXAxis().setValueFormatter(new DateFormatter());
tab1chart.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM);
tab1chart.getXAxis().setTextSize(10f);
tab1chart.getXAxis().setTextColor(Color.RED);
tab1chart.getXAxis().setDrawAxisLine(true);
tab1chart.getXAxis().setDrawGridLines(true);
tab1chart.getAxisLeft().setValueFormatter(new DistanceValueFormatter());
tab1chart.getAxisLeft().setDrawGridLines(true);
Log.v("Chart", "Chart data loaded and invalidated");//This prints
});
return null;
}
}
So far everything looks fine. The data gets put into the chart, no exceptions, no crashes.
When the chart renders, a single data point shows up at the far-left of the chart. I generate 30 data points, one shows up.
That's issue #1: Only one data point shows up.
Issue #2 is slightly harder. The entire X axis at the bottom disappears. X axis is gone and when zooming, the Y axis, and its text also disappears. This is fairly hard to explain, so here is a screenshot:
It is worth mentioning the fact that if I pass i in the for-loop as the time, it shows up just as expected: all the axises are in place, zoom doesn't break anything.
(Float values can take the same values as Longs except they have decimals in addition.)
And in addition, I format the data:
public class DateFormatter implements IAxisValueFormatter {
SimpleDateFormat formatter;
public DateFormatter(){
formatter = new SimpleDateFormat("dd/MM/yy, HH:mm");
}
#Override
public String getFormattedValue(float value, AxisBase axis) {
//This method is never called. Nothing is returned
if(axis instanceof XAxis) {
String formatted = formatter.format(new Date((long) value));
Log.d("Formatter", "Formatted \"" + value + "\" to \"" + formatted + "\".");
return formatted;
}
return "Not supported";
}
}
Removing the formatter doesn't change anything, the axis is still gone. Zoom still breaks the Y axis.
So my question is: How do I fix this? I don't get why the chart doesn't work when I pass the current time in milliseconds (and I checked the values with debug output, floats can handle it). I got some debug output earlier that eventually stopped coming at all that showed the value passed to the formatter was values < 2000. I can't reproduce this any more though
The chart itself doesn't appear to be broken but from touch events it looks like every single point is pushed into the same X coordinate but only one point renders. When I touch the chart, the orange-ish lines show up indicating the position of a data point. It pops up on points that aren't visible.
When I pass the for-loop index as the X value, it works as expected, the formatter works fine (looking aside the fact that it shows the date as in 1970, but it is counted as 1 millisecond into the epoch, so that is to expect)
I looked at this as well on formatting the date. When I then try passing the milliseconds since the epoch, the chart stops working.
I'm using MPChart v 3.0.2, compiling against Android 26, using Java 8, and running Android Studio 3.0 beta 2
As for the layout, it is just a LinearLayout with a LineChart in it.
This should work, but it breaks when I pass it the current time in milliseconds for some reason. Passing any other data (as long as the numbers aren't that big) works fine.
The two images are not how the chart is supposed to look. The X axis is supposed to be visible, but for some reason it isn't along with a large amount of the data.
This is known issue of Android MPChart (have a read this thread). Time series chart supported in MPChart - You can set time (in millis) as X values for Hourly Charts.
But too many consecutive data (points) won't correctly plot in Line Charts. Because Entry object will accept only float values due to some performance constraints.
So, keep the first value as the reference and subtract each up coming value from reference value & divide by some constants (say 1000) .So , you X value set will be like 10,20,30....& so on.
Do the reverse logic in your Axis Value formatter to render the X Axis Label properly (see the code snippet).
lineChart.getXAxis().setValueFormatter(new IAxisValueFormatter() {
#Override
public String getFormattedValue(float value, AxisBase axis) {
SimpleDateFormat format2 = new SimpleDateFormat("HH:mm:ss");
return format2.format(new Date(firstTimeStamp + ((long) value) * 1000L));
}
});

How to remove decimal value from the Barchart?

I want to remove decimal value from the BarChart in MPAndroidChart. Even though I have taken it as a Integer value while displaying it is showing decimal and adding up .0 for my value as.
ex: If my value is 65, it is displaying 75.0.(I want to remove that .0 part)
I m using the library called "mpandroidchartlibrary-2-1-4"
below is my code snippet in integer.
Double a= Double.parseDouble(total_week);
int b=a.intValue();
Double a1= Double.parseDouble(complitiontest);
int b1=a1.intValue();
Log.d("duoosfsd","**** "+b1);
entries.add(new BarEntry(b,0));
entries.add(new BarEntry(b1,1));
Here the b1 is value which is Integer value even when I print in log it prints only as 75 but while showing it will show as 75.0.
Attached screenshot please check.
public class MyValueFormatter implements ValueFormatter {
private DecimalFormat mFormat;
public MyValueFormatter() {
mFormat = new DecimalFormat("#");
}
#Override
public String getFormattedValue(float value) {
return mFormat.format(value);
}
}
call this on BarData class object
data.setValueFormatter(new MyValueFormatter());
I did try for same and below worked for me.
new DecimalFormat("#").format(100.0);
You first need to check the mpandroidchartlibrary-2-1-4 library's code.
In that library find the method which is used to display the number on the bar.
As per my understanding, it converts integer into float or either it is displaying float value to the bar at the time of display.
Advice : Please check library code and understand it first. And if you find something and want to change it, then you have to import this project as library and then only you can do changes as per your requirement.

Customsing x-axis labels in android-graphview

I am using android-graphview to display bar graph in android app. On X-axis I want to display labels as 'day-of-the-week,hour-of-the-day' like 'Mon,14.00'. So original x value(it may be date or time in milliseconds) in data point is totally done away with. I know we can do some customization in setLabelFormatter, but as far as I understand you can do some append to original value, not totally remove it.
Is there a way out for it?
use the DefaultLabelFormatter override the format method and call the super implementation. then you can append your text to the string.
Example:
graph.getGridLabelRenderer().setLabelFormatter(new DefaultLabelFormatter() {
#Override
public String formatLabel(double value, boolean isValueX) {
if (isValueX) {
// show normal x values
return super.formatLabel(value, isValueX);
} else {
// show currency for y values
return super.formatLabel(value, isValueX) + " €";
}
}
});

How to display names and percentages in a pie chart legend using mpchartlib

I want to display a pie chart like this
Please note that I do not want to display the names of items and theirs values inside of each slice because I am having allot of items and when I displaying all names into slices the names and values aren't intelligible.
I don't know if this will help you of not
but you can pass the value to a TextView and per my knowledge, I only can change the TextView value on method public void onValueSelected(Entry e, int dataSetIndex, Highlight h)
I'm doing it like this
desc.setText(code.get(h.getXIndex()) + " - " + name.get(h.getXIndex()) + ", Area: " + area.get(h.getXIndex()));
where code, name, and area is ArrayList<String> name, code, area;

Categories

Resources