How to remove decimal value from the Barchart? - android

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.

Related

How to add decimal values to entries for chart using MpAndroidChart Library?

I'm trying to create a line chart in Android using MPAndroidChart Library and as entries I have values like 1200.10, 1300.70 and so on, but on my chart the values are rounded (1200, 1301), and I want to display the original values. How can I do that? I tried different solutions but couldn't solve the problem yet. I'm using the Kotlin language. Thanks!
for (item in reversedCashList) {
if (i <= daysNmb) {
var cashValue: String = transformDataForChart(item.value!!)
dataValsEntries.add(Entry(i, cashValue.toFloat()))
i++
}
}
Also, I'm using this formatter Class to format my values because the initial format is like 120.200,10 and I changed them to 120200.10 but this values is displayed as 120200. My Formatter Class:
private fun transformDataForChart(totalValue: String): String {
return if (totalValue.contains(".")) {
val test = totalValue.replace(".", "")
test.replace(",", ".")
} else {
totalValue.replace(",", ".")
}
}
You can try with BigDecimal, something like BigDecimal.valueOf(X).setScale(decimalPlace(usually 2), BigDecimal.ROUND_HALF_UP).floatValue()
The idea is that float cannot hold so many values as the Double, I've encountered this issue as some point as well, and I had to change everything to Double just to make it more easier to maintain... Therefor I don't think is a straight-forward method to keep everything you need in the float format.

Custom x-axis labelling in MPAndroid Chart

I want the x-axis labelling to be as shown in the above picture. I have tried using the AxisValueFormatter interface but what it does is repeat the label 'jh ow' 3 times from 0 to 1, while missing out some of the labels shown here.
This is the output I am getting. While the shape of the graph is correct, the labels are not.
I am sharing the graph data so that anyone interested can try and make the graph as shown. Any help would be great, thank you.
Using MPAndroid is not important. Any help from any other library is fine too.
The data are:
"lables" : ["jh ow", "n ih l", "b iy", "hh iy r", "s uw n"]
"values":[[{"x":"0.00","y":"0.00"},{"x":"0.99","y":"0.00"}],
[{"x":"0.99","y":"1.00"},{"x":"1.19","y":"0.50"}]
, [{"x":"1.19","y":"0.50"},{"x":"1.37","y":"0.50"}]
, [{"x":"1.37","y":"0.50"},{"x":"1.59","y":"0.50"}]
, [{"x":"1.59","y":"0.50"},{"x":"2.12","y":"1.00"}]]
You just make a simple list of string like this in activity page;
final ArrayList<String> xVals= new ArrayList<>();
xVals.add("jh ow");
xVals.add("n ih l");
xVals.add("b iy");
xVals.add("hh iy r");
xVals.add("s uw n");
and Then you do this;
xAxis.setValueFormatter(new MyXAxisDateArrayFormatter(xVals));
your MyXAxisDateArrayFormatter.java
public class MyXAxisDateArrayFormatter implements IAxisValueFormatter {
private String[] mValues;
public MyXAxisDateArrayFormatter(String[] values) {
this.mValues = values;
}
#Override
public String getFormattedValue(float value, AxisBase axis) {
// "value" represents the position of the label on the axis (x or y)
return mValues[(int) value];
}
}
It worked on me
Nevermind, I was able to achieve this by using an older version of MPAndroidChart library and it worked like a charm.

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 handle time series in MPAndroidChart?

I want to add the following sort of data (can be any number of such pairs under 1000) to the newly introduced timeseries chart in MPAndroidChart library
Value : 50.0 at 1472112259
Value : 49.0 at 1472112294
Value : 50.0 at 1472112329
Value : 50.0 at 1472112360
Value : 50.0 at 1472112392
The following data will be fetched from the array.
Right now, I guess there is some mess up with the timestamps.
Here is the complete code: https://gist.github.com/utkarshns/e1723dcc57022fcd392bc3b127b6c898
UNIX timestamps will be parsed to required time format after I can successfully add values to the graph.
Currently, the problem I face is that the timestamps probably get clipped and values are overwritten which leads to a pretty messed up graph with really weird x-axis values.
Update:
Screenshots:
http://imgur.com/a/dGfmz
The problem is that Float values can't hold very big numbers and still be accurate, so you need a separate List with these timestamp values. BigDecimal should be ok for this purpose. Your distances must be in accordance to the time gaps between your events. Just iterate from the start date to end date keeping count of how many timestamps you have and add Entry with count from the timestamps you wish your value to be.
Long myValues[] = {1472112259L, 1472112294L, 1472112329L, 1472112360L, 1472112392L};// your values
ArrayList<Entry> values = new ArrayList<>();// Entry List
Long start = 1472112259L;//start
Long end = 1472112392L;//end
List<BigDecimal> mList = new ArrayList<>(); //Decimal list which holds timestamps
int count = 0;
for (Long i = start; i <= end; i++) {
mList.add(new BigDecimal(i));
if (myValues.equals(i)) {
values.add(new Entry(count, 50));
}
count++;//always increment
}
And your ValueFormatter should look like this:
AxisValueFormatter() {
private FormattedStringCache.Generic<Long, Date> mFormattedStringCache = new FormattedStringCache.Generic<>(new SimpleDateFormat("HH:mm:ss"));
#Override
public String getFormattedValue ( float value, AxisBase axis){
return mFormattedStringCache.getFormattedValue(new Date(mList.get((int)value).longValueExact()*1000), value);
}
#Override
public int getDecimalDigits () {
return 0;
}
}
If you have any question or something is unclear I'll be happy to help.

Categories

Resources