Jittered-categorical doesn't move when corresponding range is reordered

I have a scatter plot involving a categorical axis in which I’d like to have some jitter to the categorical values. The jitter function accomplishes this, providing the corresponding factor range as range argument. But when I reorder the range (and axis), the jittered points don’t move along with it as I expected—they stay put. If this is the intended behavior, is there a straightforward way I can get the jittered values to move when the range changes? Below is a brief example where a button reverses a categorical axis: red jittered points move, blue jittered ones don’t. (Tested in 2.2.0, 2.2.3, 2.3.0dev8)

from bokeh.transform import jitter
from bokeh.models import ColumnDataSource, FactorRange, CustomJS
from bokeh.models.widgets import Button
from bokeh.layouts import column
from bokeh.plotting import figure
from bokeh.io import show

source = ColumnDataSource({
    'name': ['a', 'a', 'a', 'a', 'a'],
    'val': [1, 1, 1, 1, 1],

p = figure(x_range=FactorRange(factors=['a', 'b']),  
           y_range=(0, 2), plot_width=200, plot_height=200)

p.scatter(x=jitter('name', 0.5, range=p.x_range), y='val', size=5, alpha=0.5, color='blue', source=source)
p.scatter(x='name', y=jitter('val', 0.5), size=5, color='red', alpha=0.5, source=source)

button = Button(label='Reorder factors')
button.js_on_click(CustomJS(args={'x_range': p.x_range}, code="""
    const factors = [...x_range.factors];
    const reversed = factors.reverse();
    x_range.factors = reversed;
column = column(button, p)

@sggaffney Looking at the BokehJS code I am afraid this is simply a deficiency in the current caching behavior of the jitter transform. [1] It is caching the final computed values but it should really just cache the offsets. This will have to be addressed in Bokeh itself, and I don’t have any immediate workaround to suggest. Please file a bug report issue with all of your information.

  1. and just FYI it is caching at all because if it recomputes all the time, then e.g it recomputes every mouse move of a pan operation, and that is definitely not desirable. ↩︎

1 Like