I am unable to set Double value in line chart. So i am converting Double value to float.
But the problem is that the value changed after convertion
ie from 253235661 to 253,235,664
Entry v1e1 = new Entry(Float.valueOf(dataByIndicatorAndArea.getValue().toString()), i);
kindly give the soultion
Unfortunately, floats aren't good for handling large numbers. Once they get too far up there they'll start losing precision. Tragically, floats are all MPAndroidChart knows.
Assuming your big numbers are all in the same ballpark as each other (it looks like you're using dates so I would assume so), you can work around this. When you get your first value, store it somewhere, and subtract it from every entry value as you add them. So numbers like 16314195, 16315200, 16316191 are stored as 0, 1005, 1996, and then convert them to a float. Then in a ValueFormatter for your axis, take that stored value, convert it back to the proper type, and add the stored value back in to get the original value, without loss of precision.
@Jetz72 tried the workaround but the data that is being returned to me in the IAxisValueFormatter is not the same, I have created an issue here #4003 which has code snippets, could you take a look at it.
Tragically, floats are all MPAndroidChart knows.
I strongly disagree that this is a problem. Floats where added because, by default, they allow for more precision than the original integer implementation and also to use the full range of numbers that a float knows (which is actually very large, including the extra decimals you get).
Another thing I disagree with is using Float.valueOf() to convert the string directly into a number. I don't understand how data is lost with a relatively small number for the available range. I doubt you are actually experiencing the exact string 253,235,664 being turned into 253235661 in your code, since the biggest accurate number you can attain with a float is something around:
340,282,346,638,528,860,000,000,000,000,000,000,000.000000
And that isn't even including the fact that you can use the tenths and hundredths place with no relative loss of precision.
Another detail, you have access to IAxisValueFormatter, use it to your advantage! Instead of storing the X index at whatever massive number you are using, store it at increments of 1. And then initialize your IAxisValueFormatter with the same data in your graph, but with the real X values, and just map them 1:1 as a label. That way you completely avoid converting the 253,235,664 into a number at all, you just use that exact same string as the label.
Instead of complaining about the surface limitations, look at all the things MPAndroidChart can do under the hood for you, which is often the way you should be doing it.
I doubt you are actually experiencing the exact string 253,235,664 being turned into 253235661 in your code, since the biggest accurate number you can attain with a float is something around:
340,282,346,638,528,860,000,000,000,000,000,000,000.000000
That's a bit misleading. Sure floats can handle that number accurately but only because that's the one everything remotely close to it gets rounded to. The non-exponent part of a float can only fit 23 bits of information. With only integers, you start to see loss of precision past 16777216. 253235661 does get rounded to 253235664, as the OP describes.
@Jetz72 I went over-the-top in the response with rounding, and indeed java rounds 253235661 to 253235664, assuming you are confirming by testing yourself.
However the underlying problem is NOT with the library. We can do nothing about float precision, and perhaps going to doubles may be a necessary step to alleviate this problem. However keep in mind, this sort of thing is well known in Java, it's not some new problem or bug that this library has yet to patch.
But like I've said before, the current implementation of floats is not the source of the problem. Only when others begin expecting floats to be perfect is when the problem manifests. The solution is simple, don't use such large numbers and expect absolute precision.
I assume your data source is precise, but a chart on a UI built to simplify the data into a more understandable format does not need precision to 9 decimals.
This library leaves the scope of the programmer and goes into the scope of the artist. You have to make the data understandable for users, and meaningful. For a Pie chart or Bar graph, literally no one will see the difference between 253235661 and 253235664 when the entire thing is plotted, and probably not care. If you were specifically comparing the two numbers, it would become obvious. But in that case you can just pass 1 and 4 into the chart, and add 253235660 to the labels with the ValueFormatter.
Instead of using 253235661 exactly in the value label, use 253M. It looks better and is much easier to understand the actual size than 253235661
Instead of complaining about the surface limitations, look at all the things MPAndroidChart can do under the hood for you, which is often the way you should be doing it.
@almic Yes, the weakness of the floating point format is not a consequence of the library. However, the library's decision to rely on that format means it carries that limitation all the same. There are workarounds, but the existence of a workaround speaks to the existence of a problem. It may not be realistically fixable, but it is still a problem. There have been many people here looking for information regarding how to correctly use timestamps as values, and perhaps the proper workaround for that could be made more clear in the wiki or documentation.
However, I feel like I should clarify that when I say:
Tragically, floats are all MPAndroidChart knows.
I do not intend it as a slight against the project or the work that has gone into it. You are right to point to what the library is capable of, as the end result works as intended. I was only lamenting the circumstances that ultimately make getting there less straightforward than one might hope for.
In any case, glad to see some development activity in this library. It's one I've found useful, and will no doubt need to make use of again at some point, so best of luck to you all.
@Jetz72 I agree that the documentation needs work. It's no secret that this library attracts an alarming amount of low quality issues asking for things to which the answer is most often a single method call. I'm actively working to fix this with issue templates pointing to the documentation, but so far it has done nothing to stop these kinds of issues.
The library is very bulky, and often the means to an end result aren't intuitive. A common question I've answered almost every day since I started work here has been using different axis labels, and many don't realize they can pass the data directly to the formatter to get more control of the data.
Either way, doubles could work. I'm going to keep this closed because it's still not a big deal. Users would prefer seeing 253M over 253235661 every time, at least when displayed in a chart format. Raw numbers? Obviously the full value, but you wouldn't be using this library if you wanted to show lists of raw numbers.
Please consider reopening this issue.
The fact that one has to employ a _workaround_ in order to chart Unix timestamps makes it pretty clear that there is a problem introduced by this library's reliance on float values. Discussing the strengths and weaknesses of float values only serves to divert attention from an issue that could be resolved by a change to this library. There is a fundamental flaw in representing chart data with imprecise float values.
Just like @Jetz72, I don't mean to diminish the great work that has been done here, and I don't want to come across as self-entitled or deserving of an immediate solution to this problem, which I have not presented myself.
However, this really _is_ a big deal, and makes it very difficult to implement a chart which plots anything against Unix timestamps - an extremely common reference value. How these timestamps are represented to the user is the responsibility of the ValueFormatter and really has nothing to do with which data type x and y values are stored against for the plotting of the chart. A consumer of this library should not have to perform preprocessing or otherwise mutate their source data so that it can be charted, only to mutate it back to its original value and then format it to present it accurately to the users.
I've seen a few similar issues where the solution has been 'use smaller values' or 'users don't want to see big numbers'. I cannot stress enough that this issue really has nothing at all to do with what the end user sees. Again, that is the responsibility of the ValueFormatter. The problem here, is that Unix timestamps cannot be _accurately_ represented by 32 bit floats in Java.
I think possibly the point being overlooked here is that, while FLOAT_MAX contains a huge number of digits (~45?), seemingly more than one could ever possibly need, the precision of Java floats is only 6-7 digits. So converting a Unix timestamp to a float causes data corruption, since they are (presently) 10 digits. This is entirely an issue about the preservation and plotting of data which requires a precision greater than that which float can hold, and easily resolved by migrating to double values.
@timusus I saw your recent contributions (issue wise) regarding this library and wanted to ask if you are interested in becoming a collaborator? :-)
Hi @PhilJay. I'd love to help out, but i don't think I've got all that much to offer. Mostly I was just trying to collate all the instances of this particular issue.
I have a bit of a habit of forgetting about libraries that I'm not actively integrating! I'll have a think about it, I appreciate the offer.
@timusus Hi! Thank you for referring to my PR https://github.com/PhilJay/MPAndroidChart/pull/4121.
I changed Float to Double to make it better as well.
@PhilJay Nice to meet you. Thank you for always using it. This PR is a devastating change, and Double has errors in big values, but I think that I can help you.
Hello, any update on this? I have the same issue and I am looking for a solution to plot a lot of points where X is unix timestamp. Now my entries gets collapsed since float is not precise enough to represent unix timestamp. :(
Most helpful comment
Please consider reopening this issue.
The fact that one has to employ a _workaround_ in order to chart
Unix timestampsmakes it pretty clear that there is a problem introduced by this library's reliance onfloatvalues. Discussing the strengths and weaknesses offloatvalues only serves to divert attention from an issue that could be resolved by a change to this library. There is a fundamental flaw in representing chart data with imprecisefloatvalues.Just like @Jetz72, I don't mean to diminish the great work that has been done here, and I don't want to come across as self-entitled or deserving of an immediate solution to this problem, which I have not presented myself.
However, this really _is_ a big deal, and makes it very difficult to implement a chart which plots anything against
Unix timestamps- an extremely common reference value. How these timestamps are represented to the user is the responsibility of theValueFormatterand really has nothing to do with which data type x and y values are stored against for the plotting of the chart. A consumer of this library should not have to perform preprocessing or otherwise mutate their source data so that it can be charted, only to mutate it back to its original value and then format it to present it accurately to the users.I've seen a few similar issues where the solution has been 'use smaller values' or 'users don't want to see big numbers'. I cannot stress enough that this issue really has nothing at all to do with what the end user sees. Again, that is the responsibility of the
ValueFormatter. The problem here, is thatUnix timestampscannot be _accurately_ represented by 32 bit floats in Java.I think possibly the point being overlooked here is that, while
FLOAT_MAXcontains a huge number of digits (~45?), seemingly more than one could ever possibly need, the precision of Javafloatsis only 6-7 digits. So converting aUnix timestampto afloatcauses data corruption, since they are (presently) 10 digits. This is entirely an issue about the preservation and plotting of data which requires a precision greater than that whichfloatcan hold, and easily resolved by migrating todoublevalues.