I'm using MPAndroidChart and I know this topic is covered quite a bit in the docs, so apologies if I've missed something obvious, but I'm having a bit of trouble formatting timestamp values into dates on the x-axis of my Linechart.
It appears that getFormattedValue() isn't being invoked for my x-axis value for whatever reason. If i debug AxisBase, it only seems to looking to format the y-axis values, which i do not have a custom formatter set on.
Here is the code snippets, taken mostly from the Github docs:
LineChart chart = (LineChart) findViewById(R.id.chart);
XAxis xAxis = chart.getXAxis();
// set min timestamp to Jul 2017
HourAxisValueFormatter(Long.parseLong("1499814559"));
xAxis.setValueFormatter(new IAxisValueFormatter() {
// THIS IS NEVER INVOKED!
#Override
public String getFormattedValue(float value, AxisBase axis)
{
return new Date(Long.parseLong(""+value)).toString();
}
});
// rating is a map of timestamp to numeric value, both stored
// as strings
for (Map.Entry<String, String> rating : ratings.entrySet()) {
String timestamp = rating.getKey();
String ratingValue = rating.getValue();
entries.add(new Entry(Float.parseFloat(timestamp),
Float.parseFloat(ratingValue)));
}
// add entries to dataset
LineDataSet dataSet = new LineDataSet(entries, "Ratings");
LineData lineData = new LineData(dataSet);
chart.setData(lineData);
chart.invalidate(); // refresh'
I'm using version 3.0.2 of the library:
compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'
Thanks in advance, Gary
EDIT per request for desired output/actual output:
Ideally i would have a series of dates along the x-axis , e.g. 10/7, 11/8, 12/8, etc. constructed from the Epoch values I've provided. I know the code above wont format it in that format as it stands, but just want to get it formatting to any date value initially (so ignore that for now), the crux of the issue is that my formatter isn't getting invoked at all.
Below is a screenshot of the current output, it only prints a single value on the x=0 line (note even though there are multiple y values being provided, i wonder if they are all on the same x=0 line does it just draw the last point or something?):
Debugging the timestamp values above, Float.parseFloat(timestamp) is equal to 1.50516885e^12. The actual timestamp value for example is 1505168846751, but after parsing to a Float is rounded, and given an exponent value.
EDIT 2 :
Screen grab of the values supplied as 'entries' to the LineDataSet:
EDIT 3:
The issue appears to be to do with the size/format of the timestamp values for the x-values I'm providing, changing these to small float values in the range 1.0 -> 20.0f, causes the formatter to be invoked as expected. I need to debug the code further to see why the exponential timestamp values are not being formatted.
From looking into this i think this is a limitation at the moment, for this specific use case (timestamps are very close together) since Entry will only accept floating point values, my timestamps are all getting passed as 1.50516885e^12, even though the precise timestamp values are slightly different. When AxisRenderer works out the range for the x-axis then is sees it as 0, and sets the entries to 0 also, in this block here
Related
I'm developing fitness application where I would like to display chart of user running activities over months, so something like this:
Graph how I want it
I'm using MPAndroidChart for it, but I'm getting some weird values on the x axis (the y axis is alright).
I have a map (monthMileage in the code sample), where the key is the month and the year in string, so for example Jul 2020 as "072020" and the value is the total distance of km which user ran that month.
profileViewModel.monthOverview.observe(viewLifecycleOwner, Observer { monthMileage ->
val entries = ArrayList<BarEntry>()
for ((k, v) in monthMileage) {
entries.add(BarEntry(k, v.toFloat()))
}
val dataSet = BarDataSet(entries, "Monthly mileage")
val barData = BarData(dataSet)
activity_graph.xAxis.labelCount = entries.size
activity_graph.xAxis.valueFormatter = ActivityGraphFormatter()
activity_graph.axisRight.axisMinimum = 0.toFloat()
activity_graph.axisLeft.axisMinimum = 0.toFloat()
activity_graph.data = barData
activity_graph.invalidate()
})
This is how I'm trying to set data to the Bar Chart. The x value is the month-year string to Float and y is the total distance. I use custom value formatter, which looks weird, but should be working with the right values (and the values are still wrong even when I don't use the formatter so there's error probably somewhere else). In the whole process the values in the entries, data set and data are still the values I'm expecting, but when it's set to the graph it's just wrong.
For example for 72020 and 62020 I'm getting 65000 and 70000.
There's probably some correlation I don't see so I welcome all advicess or if anybody knows about some nicer chart library for android mobile app, I've been searching, but all the time everybody is just praising MPAndroidChart.
I want my application to be able to display frequency response graphs but I cannot find any graphing library that has this functionality. I am currently using MPAndroidChart for some other charts (and it is great !) but sadly I could not find any way to use it to do log plots. I have also tried using numAndroidCharts (numcharts logplot example), but that library seems broken/outdated since i couldn't even get the example code to work properly. Is there anyway that you know of to achieve this ?
I use MPAndroidChart with a log scale with converted values.
For example if your value is 1E-5:
value = 1E-5;
Entry entry = new Entry();
entry.setX(Math.log10(value)); // entry.getX() will return -5
Because your value now is -5 you need to create an AxisFormatter to show that it really represents an logarithmic value:
public class Log10AxisValueFormatter implements IAxisValueFormatter {
#Override
public String getFormattedValue(float value, AxisBase axis) {
return String.format(Locale.ENGLISH, "%.2E", Math.pow(10,value));
}
}
You need to set an instance of this to your axis when you create your chart:
XAxis xAxis = chart.getXAxis();
xAxis.setValueFormatter(new Log10AxisValueFormatter());
When I zoom my Chart by X axle, graph disappears.Why this can happen?
Lib version - MPAndroidChart:v3.0.0-beta1
enter image description here
I used example LineChartTime. And edited long hourMillis = 36000L; in setData() function, and got problem with graph view.
UPDATED!!!
The problem become when time sampling smaller then 360000 millis or 6 minutes. When 1 hour like in example "LineChartTime" everything is ok. But if I reduce x value from 1451606400000L to 0 and make time sampling equal 1 millis everything is ok. So I think that main problem in float type of x value, that process incorrect big LONG values.
So, I found temporary solution.
When I get current time, I reduce it on 1451606400000L (2016 01.01 00:00) and draw not so big values, but also change Formatter string
xAxis.setValueFormatter(new AxisValueFormatter() {
private FormattedStringCache.Generic<Long, Date> mFormattedStringCache = new FormattedStringCache.Generic<>(new SimpleDateFormat("yyyy dd MMM HH:mm"));
#Override
public String getFormattedValue(float value, AxisBase axis) {
Long v = (long) value + 1451606400000L;
return mFormattedStringCache.getFormattedValue(new Date(v), v);
}
If someone have another solution please let me know.
When you zoom in, the library does not render values that are outside of the visible area. The algorithms here use the float type (probably for many good reasons), but this causes problems with "large" numbers.
float is internally a 32-bit IEEE 754, which means that it can represent only about 7 significant digits. Timestamps in milliseconds will get their last digits truncated (at least for the purposes of determining which lines to draw), so some of your lines wil disappear.
Option 1:
Use timestamps within range of float precision, or at least closer to it.
If you are plotting current data, substract a stored value of System.currentTimeMillis() from your timestamps and add the same value back when formatting, as you did in your own solution. If you can live with 1-second precision, divide your timestamps by 60000 and adjust the formatter accordingly.
Option 2: Patch the library to draw lines outside of the visible area.
A quick fix that will work if you don't have a large dataset is to render everything. For line charts, change the contents of the following 2 methods in BarLineChartBase.java near line 1280 like this:
public float getLowestVisibleX() {
return mXAxis.mAxisMinimum;
}
public float getHighestVisibleX() {
return mXAxis.mAxisMaximum;
}
This is probably wildly inefficient, which may or may not be an issue depending on your dataset size.
I use the Amazing MPChart, however i have trouble setting other than index values
on on the X-Axis.
Do anyone know how to set it, should i modify labels of the axis?
The documentation say that the x-value is set in the data object, bit
X-values is always and index, as far as i can see.
My goal is to have values of time on the x-axis, statistics for 1 week 2 weeks one month etc.
You can do this by using these line of code. You can understand this code if you are familiar with mpchartlibrary android.
ArrayList<String> xVals = new ArrayList<String>();
xVals.add("1 week");
xVals.add("1 Month");
data= new LineData(xVals, setData);
mChart.setData(data);
2 Questions about the MPAndroidChart library.
All my yvalues are integers, but displayed as Decimals.
How can I get them displayed as integers (without the digits)?
How can I prevent that the ylabels are also shows as decimals?
I know there is a setFormatter for the yvalues, just don't understand how to use...
Have a look at the IValueFormatter interface provided by the library. With that interface, you can completely customize what gets displayed on the chart based on your own logic.
Usage:
chart.setValueFormatter(new YourValueFormatter());
YLabels yl = chart.getYLabels();
yl.setFormatter(new YourValueFormatter());
UPDATE (for versions 2.0.0+ of this [library][2]):
Now, a ValueFormatter can be set for each DataSet separately, or the same ValueFormatter can be set for the whole data object containig all DataSets. Furthermore, the YLabels class is now called YAxis.
Example:
// set for whole data object (individual DataSets also possible)
LineData data = new LineData(...);
data.setValueFormatter(new YourValueFormatter());
// YLabels are now called YAxis
YAxis yAxis = mChart.getAxisLeft(); // get the left or right axis
yAxis.setValueFormatter(new YourAxisValueFormatter());
UPDATE (for versions 3.0.0+ of this [library][2]):
The interfaces for formatting have been renamed and extended in their functionality. Now, the IAxisValueFormatter can be used to format values of both XAxis and YAxis. The IValueFormatter interface is used to customize chart values.
Link to the ValueFormatter documentation.
If all you want is to change the number of decimal places on the values, the
DefaultValueFormatter will suffice.
pieDataSet.setDefaultValueFormatter(new DefaultValueFormatter(digits = 1))
//where digits is the number of decimal places
The example above will format 88.65 as 88.7