Dense DateTimeTicker

Hello! I have realized I am far too dumb to be able to use DateTimeTicker…

I would like to make it so that my plot has always 10 ticks with their respective DateTime visible. The number 10 is arbitrary. I just want a more dense ticker than the default one.

Here is an example code with me specifying the ticker as suggested by the source code of the DateTimeTicker.

from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, Plot, AdaptiveTicker, DaysTicker

import numpy as np
import pandas as pd

ONE_MILLI = 1.0
ONE_SECOND = 1000.0
ONE_MINUTE = 60.0 * ONE_SECOND
ONE_HOUR = 60 * ONE_MINUTE

TICKERS = [
    AdaptiveTicker(
        mantissas=[1],
        base=10,
        min_interval=ONE_HOUR,
        max_interval=2*ONE_HOUR,
        num_minor_ticks=0
    )
]


p = figure(width=300, height=300, tools="pan,reset,save,box_zoom,zoom_in,zoom_out", x_axis_type="datetime", sizing_mode="stretch_both")
p.xaxis.ticker.tickers = TICKERS

POINTS_COUNT = 100000
source = ColumnDataSource(data={"x": pd.date_range(start="2022-01-01", end="2022-01-03", periods=POINTS_COUNT), "y": np.random.rand(1, POINTS_COUNT)[0]})
doc = curdoc()

p.scatter(source=source)

doc.add_root(p)

This works well for the view we get on startup but the ticks get sparse as we zoom in. I try adding another AdaptiveTicker and that’s where the trouble starts. The behaviour of zoom seems to be changing almost randomly. How does the CompositeTicker decide which AdaptiveTicker to use? It’s really hard for me to deduce that from user’s perspective.

On the other hand, maybe there is a simpler method of making sure we get two or more times ticks visible everytime?

I don’t think what you want is going to be trivial.

The built-in tickers for basic numerical ranges (e.g. seconds and below) very intentionally try to pick “nice” locations (as defined by Heckbert’s “Nice Numbers” algorithm). There’s no guarantee that, for a fixed N, that there are exactly N “nice” numbers in the current range interval. For larger ranges, tickers use human-sensible tick intervals like days, weeks, months, etc… Again, there’s no guarantee that, for a fixed N, that there are exactly N “nice” numbers in the current range interval.

It’s certainly possible to write a ticker that always chooses exactly N evenly spaced ticks, regardless of range interval, but then the ticks would generally land at “ugly” locations. There’s never been any demand for that, so we have not put any effort into it. I think you would need to create your own custom extension for this.

It’s really hard for me to deduce that from user’s perspective.

I have to be honest, and say that, while technically “public API”, these classes are deep in the weeds, and it was never an expectation that end-users would use them directly (I think you are the first person to try in 10+ years).

How does the CompositeTicker decide which AdaptiveTicker to use?

Each “sub” ticker should state a min_interval and max_interval to specify over what scales it can apply. The top-level ticker uses this information to choose.

I guess I should also check: have you tried increasing desired_num_ticks ? That won’t let you get a specific number of ticks all the time (it’s just a “hint” to the ticker), but if all you want is more ticks, then setting a higher value may get you what you want.

I did try desired_num_ticks in the example above but it doesn’t seem to change anything.

Thank you for the explanation though! I understand now that this is not a trivial thing to achieve!

I had another idea as well. Does bokeh provide some way of showing Tick Label for a minor tick? That would also solve my problem.

Not presently (no one has ever asked for it). You could make a GitHub Issue to request it as a new feature in the future, but that won’t solve your immediate problem. Unfortunately I don’t have any simple workaround to suggest, either.

I did try desired_num_ticks in the example above but it doesn’t seem to change anything.

Might also be worth making an issue for this too, with a small example to demonstrate. IMO this property has never gotten much attention. Maybe it doesn’t work or maybe it is so vaguely specified that “working” is hard to define. (It’s described as a “hint” but even I don’t know what that really means, and I wrote the code — 10+ years ago). I think maybe the meaning of this property could be tightened up for adaptive tickers, i.e. desired_num_ticks could be strictly interpreted as a minimum number, with the ticker moving to the next “level” if the standard level does not provide enough locations. Would require some investigation but seems plausible offhand.

Sure thing, thank you for the exhausting explanations!

It’s more of a quality of life feature than anything else so it’s not that important.
I did create github issue so that people could ask for the status there rather than opening another discussion on discourse [FEATURE] Dense Ticker · Issue #12660 · bokeh/bokeh · GitHub.

Thanks for the help!

1 Like