When it comes to UI design, percentages can be a pain! At the convergence of UI/UX, mathematics, and computer mathematics it’s quite easy to find yourself in a situation as seen in this chart:
There is a problem with this chart? Did you spot it?
26 + 61 + 12 = 99
The percentages do not add up to 100. What’s going on? Is the data wrong? What follows is an explanation of the problem and a solution I implemented for use with Google Polymer applications.
Computation vs Display
When I ran into this issue my initial suspicion was that I’d simply made an error in the calculations; that my data was wrong. Unfortunately the answer is not that simple. Take the classic example of adding thirds:
33.3333 + 33.3333 + 33.3333 = 99.9999
If the sum is rounded, the total will be 100. But the truth of the math doesn’t matter in a chart. The chart should convey the information in an easy-to-understand format. If I round these numbers for display, I would end up with a chart displaying “33” for each row. The math isn’t wrong, but the visual representation is. As a user I know the values are wrong, but I don’t know why.
I figured with the power of the internet it would be trivial to find a solution for this issue so I set about doing some research. I was surprised to find a wide variety of answers. One suggestion was to add a text explanation to the effect of “numbers may be wrong due to rounding”. Other systems simply don’t provide a solution. Another missed the mark, suggesting that the sum will be correct if you don’t round each number before summing. This is true, but misses the point. The fact is this is a problem without a “perfect” solution because rounding numbers introduces errors. I want to display rounded values for ease of use, but my computations need to be as accurate as possible.
Largest Remainder Method
I finally settled on using the largest remainder method as described in this Stack Overflow answer:
- For each item in the sum, get the floor value
- Sum the floored values
- Get the difference between this sum and 100
- Sort the floored values by their remainders
- Distribute the difference by adding 1 to each value and subtracting 1 from the difference until the difference is 0
Remember that no matter what, rounding introduces errors. Using the largest remainder method for the previous example, the values become [34, 33, 33]. However, I think for a dashboard-type chart this kind of error is acceptable. If the numbers need to be more mathematically accurate, it would be better to use a report of the data, rather than a chart.
This implementation of the largest remainder method is available as a Polymer Web component and can be used like so:
<nuxeo-util-largest-remainder values-to-fix="[33.3, 33.3, 33.3]"
You can find more information in the documentation page (with demo).