Search code examples
javascripttypescriptplotly

precision in Plotly histogram value %{x}


I'm using Plotly to display an histogram with an hovertemplate displaying the value from the group. I need to display a precision to 3 digit, even when the data are big, however Plotly seems to round the value before that so with below example, hovertempalte jump from "28200.000 - 28500.000" to "28600.00 - 28800.00" and value 28589.02 is absorb by the second bar whereas it's below the min from the range.

Is there any option to change that precision on the %{x} value ? I tryed to use hoverformat: .3f but it only add 0 to the end so it doesn't fix.

You can find the example here: https://stackblitz.com/edit/typescript-plotly-hfluqw?file=index.ts

const appDiv: HTMLElement = document.getElementById('app');
appDiv.innerHTML = `<div style="width: 100%; height: 100%" id="chart"></div>`;
import { newPlot } from 'plotly.js-dist';

const data = [
  {
    type: 'histogram',
    marker: { color: 'red' },
    mode: 'lines+markers',
    x: [25000, 28333.952, 28334.08, 28589.02, 28945.89],
    xbins: {
      start: 25000,
      end: 29340.479,
      size: 394.589,
    },
    hovertemplate: 'value: %{x}',
  },
];
const layout = {
  bargap: 0.1,
  hovermode: 'closest',
  xaxis: {
    hoverformat: ',.3f',
  },
};

newPlot('chart', data, layout);

EDIT: fix the point within the range gap

I finally fix the biggest part of my issue by removing the start & end values from the xbins, leaving it to default from Plotly's logic. The displayed values are still rounded, so there is a jump, but the range always cover all points, so in above example the ranges were fixed to "28.1k - 28.4k" and "28.5k - 28.7k". I think the start and end were shifting this and broke some Plotly rounding logic.


Solution

  • Unfortunately, it seems that currently this is expected behavior, and that's just how Plotly internal bin range "shrinkage" works.

    There's an open Github issue asking a similar, more simple question: How come a bin size of 50 displays ranges of 0-40, 50-90, etc, as shown in this live demo?

    A developer explains:

    This is all in service of greater clarity at the bin edges. To be precise, what's happening here is two things:

    • We detected that the data values are all integers, so we shifted the bin edges down 0.5 to ensure that NO values are exactly at a bin edge. You can see this if you zoom in, the bins actually go -0.5 -> 49.5, 49.5 -> 99.5, 99.5 -> 149.5 etc
    • But listing exactly those values in the hover label would be confusing: what are half-integer values doing in a label for integer data? So we look at the data again and ask: what's the closest any value gets to the left or right edge of a bin? In this case it's 0.5 from the left edge and 9.5 from the right, and based on the bin width of 50 we can always represent these values with a zero at the end, so that's what we do - 0-40, 50-90, 100-140 etc. If you add a value that's just a little closer to the right edge of a bin - say change one of the 140s to 141 - you'll see the labels change to 0-49, 50-99, 100-149 etc, since we can no longer round to a bigger digit.

    What we really DON'T want to do is have labels 50-100 and 100-150, because then it's ambiguous in which bin we put a value of exactly 100. But you could perhaps argue that the bin shift should match the range shrinkage - ie because we shifted the bins exactly 0.5 here we should also shrink the ranges we report by exactly 0.5 on each side, to 50-99, or if we want to keep 50-90 we should shift the bins by 5.

    This explanation applies for your case as well: If you'll try to add the value 28551, which is exactly at the right edge of the 8th bin\left edge of the 9th bin (because: 25000 + (394.589 * 9) = 28551.301), you'll notice that the hovered bin edges becomes very precise - as you can see here.

    So it seems that there's not much to do about it, at least for now.