leeoniya / uPlot

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

add base 2 and base e scale.distr options #304

Closed leeoniya closed 3 years ago

leeoniya commented 3 years ago

scale.distr mapping:

  1. linear
  2. ordinal
  3. log10
  4. log2 (new)
  5. log (new)
derekkraan commented 3 years ago

There is no difference between log10 and log2 or log (I think you mean ln), they are linearly scaled relative to one another. In other words, the shape of the graph will be the same, since the scale of the y-axis is eventually scaled linearly by (min_y, max_y) values in the graph.

log_base_b(x) = log_base_a(x) / log_base_a(b)

This division by log_base_a(b) is a constant. Therefore, the graphs for any log graph will look exactly the same.

leeoniya commented 3 years ago

heh, thanks for chiming in :)

i guess the main effect this will have is how the min/max is padded/snapped and how axis splits (ticks) are chosen. in this case it should be sufficient to use an e.g. base2 axis.incrs divisor array and tweak scale.range logic. then an arbitrary base can be chosen via a new scale.base instead of making pre-defined ones. :thinking:

derekkraan commented 3 years ago

I was actually going to ask about that, we have a lot of this happening in our logscale graphs, but I don't see how to tweak that.

So a feature that would allow us to change this would be awesome

image

leeoniya commented 3 years ago

can you post an easily runnable fiddle with your chart config that exhibits the above behavior?

generally, increasing axis.space should reduce the tick density. im not sure how you got the chart in the image since the default log axis.values logic tries to ensure there's enough space to fit a label without overlap between 10 and 7 before choosing to go any denser:

https://github.com/leeoniya/uPlot/blob/master/src/opts.js#L449

EDIT: nevermind, i see you're customizing axis.values :D. please put up a fiddle anyways, i'd like to play around with it.

leeoniya commented 3 years ago

also, the different line color of the series in the 100ms+ range tells me it may need to be on its own, separate scale & additional y axis on the right. that will give you a lot more visual resolution in the sub 1ms series.

derekkraan commented 3 years ago

Yep, that's what we have. Let me show you the whole graph: image

I'm also trying to figure out how to get a fiddle working with uplot, so that should be coming.

leeoniya commented 3 years ago

Let me show you the whole graph:

oh, lol.

that's quite the latency range, good sir!

I'm also trying to figure out how to get a fiddle working with uplot, so that should be coming.

e.g. https://jsfiddle.net/3p4o0s5z/

i've also opened #305 for a possible improvement

derekkraan commented 3 years ago

that's quite the latency range, good sir!

Haha yes, yes it is. It's also an artificial example. 10ms -> 20s latency range is fairly normal though in my experience.

derekkraan commented 3 years ago

Aha, I think I figured it out. If you provide a values callback in the axes (to format them or whatever) then the filtering doesn't appear to happen.

https://jsfiddle.net/vwfqacox/3/

derekkraan commented 3 years ago

Uhh so exactly what you wrote in #305 actually, now that I am looking at it again.

leeoniya commented 3 years ago

i've decoupled axis.filter() from axis.values() in https://github.com/leeoniya/uPlot/commit/c898d24c56ec3e1c314b0721353d9a0bc6b41a07

this now works as expected: https://jsfiddle.net/zhpqkdo1/

leeoniya commented 3 years ago

gave Math.log2 a go in https://github.com/leeoniya/uPlot/tree/log2 to see how much would need to be touched, and even before a final cleanup it turns out not very much, which is nice. one minor breaking change would need to expand the uPlot.rangeLog() signature to accept a base argument.

still some questions around whether to handle numbers < 1, like 2^-5. also, log2 is a middle ground between linear and log10, for which the split gen strategies are very different. log2 is a hybrid in that its splits are always evenly spaced (like linear) since they're always at power boundaries, while the scale and increment finding is similar to log10, where the splits can be variable if you choose to show and annotate the 1/10th magnitude lines.

i think there needs to be a bit of rework to have log scales generate their evenly-spaced power-boundary splits, similar to linear but in log space instead of raw values - this can be done using near-identical strategy to linear. then afterwards the log10 variant needs to splice in the 1/10th magnitude splits. it'd be kind of like a majors -> minors pass.

leeoniya commented 3 years ago

i've pushed a bunch of commits that add scale.log, which can be either 10 (default) or 2:

https://leeoniya.github.io/uPlot/demos/log-scales2.html