leeoniya / uPlot

📈 A small, fast chart for time series, lines, areas, ohlc & bars
MIT License
8.72k stars 383 forks source link

Inconsistent Y-axis, when y scale is set to distr: 2 the tick values are displayed as timestamps #786

Open FilipLeonard opened 1 year ago

FilipLeonard commented 1 year ago

Setting scales.y.distr: 2 displays timestamp values for the y-axis ticks, instead of the squashed original y values. The context is that the data points are always integers and represent domain concepts that can never be fractional (e.g. family members count), often small (e.g. 1, 2). Nevertheless uPlot's linear distribution also displays the in-between fractional values, ([1, 1.25, 1.5, 1.75, 2, ..]) as tick labels on the y axis. Rounding them with something like tick.toFixed(0) yields an awkward chart where the y-axis shows duplicates ([1, 1, 1, 2, 2, ..]). I was expecting scales.y.distr: 2 to get rid of the fractional values but instead it shows timestamps. Is this normal behaviour? Does distr option work for the y axis?

https://jsfiddle.net/eytuajg0/61/

leeoniya commented 1 year ago

i think what you're looking for is to customize axis.incrs of the y axis, and only provide integer divisors for the scale range. e.g.:

https://jsfiddle.net/gry4b8do/

axes: [
  {},
  {
    incrs: [1, 2, 5, 10, 20, 25, 50]
  },
],

image

leeoniya commented 1 year ago

to address your original question, distr: 2 is really meant for sequential / ascending progressions of values. its primary use case is when you have text labels for x values and need them to be uniformly spaced, or you have timestamps but want to ignore long peruods with no data (like weekends with no trading activity for candlesticks). in both of those cases you just want an equal spacing as if the values were 1,2,3 regardless of their actual data value.

to make distr: 2 work for y scales would require to scan all the y data, get unique values, sort them ascending, and assign 1,2,3 to them. it would be expensive (for typical timeseries datasets). the main use case might be stepped lines with text states for y values where you only have at most a couple hundred datapoints with at most 5 or 10 distinct states. in that case the y axis would have to grab tick labels from the data. we're kinda doing something like this in https://github.com/grafana/grafana/pull/60068, actually. maybe it makes sense to add support for this 🤔 , but it doesnt sound like your use case.

FilipLeonard commented 1 year ago

i think what you're looking for is to customize axis.incrs of the y axis, and only provide integer divisors for the scale range. e.g.:

Thanks for the quick response! You're right, setting incrs solves my problem ✅.

to make distr: 2 work for y scales would require to scan all the y data, get unique values, sort them ascending, and assign 1,2,3 to them. it would be expensive (for typical timeseries datasets). the main use case might be stepped lines with text states for y values where you only have at most a couple hundred datapoints with at most 5 or 10 distinct states. in that case the y axis would have to grab tick labels from the data. we're kinda doing something like this in grafana/grafana#60068, actually. maybe it makes sense to add support for this 🤔 , but it doesnt sound like your use case.

Yes, it doesn't sound like my use case. For instance, if the data points represent population counts and you'd like to have as Y ticks the states of settlement hierarchy (e.g. [isolated home, hamlet, village, town, city, ..]), and finally you'd like to plot all the settlements of a country, looking at the data points populations and deriving the y labels from there. I assume you're referring to something like this.