import numpy as np

from bokeh.models import Button, Column, ColumnDataSource, CustomJS, Jitter, LabelSet
from bokeh.plotting import figure, output_file, show

N = 1000

source = ColumnDataSource(data=dict(
    x=np.ones(N), xn=2*np.ones(N), xu=3*np.ones(N), y=np.random.random(N)*10
))

normal = Jitter(width=0.2, distribution="normal")
uniform = Jitter(width=0.2, distribution="uniform")

p = figure(x_range=(0, 4), y_range=(0,10), toolbar_location=None, x_axis_location="above")
p.circle(x='x',  y='y', color='firebrick', source=source, size=5, alpha=0.5)
p.circle(x='xn', y='y', color='olive',     source=source, size=5, alpha=0.5)
p.circle(x='xu', y='y', color='navy',      source=source, size=5, alpha=0.5)

label_data = ColumnDataSource(data=dict(
    x=[1,2,3], y=[0, 0, 0], t=['Original', 'Normal', 'Uniform']
))
label_set = LabelSet(x='x', y='y', text='t', y_offset=-4, source=label_data,
                     text_baseline="top", text_align='center')
p.add_layout(label_set)

callback = CustomJS(args=dict(source=source, normal=normal, uniform=uniform), code="""
    const data = source.data;
    for (let i = 0; i < data.y.length; i++) {
        data.xn[i] = normal.compute(data.x[i] + 1);
    }
    for (let i = 0; i < data.y.length; i++) {
        data.xu[i] = uniform.compute(data.x[i] + 2);
    }
    source.change.emit();
""")

button = Button(label='Press to apply Jitter!', width=300)
button.js_on_click(callback)

output_file("transform_jitter.html", title="Example Jitter Transform")

show(Column(button, p))

@@ -13,16 +13,56 @@
  as np%0A%0A
+from bokeh.core.properties import field%0A
 from bok
@@ -177,152 +177,124 @@
 ure,
- output_file,
  show%0A%0A
-N = 1000%0A%0Asource = ColumnDataSource(data=dict(%0A    x=np.ones(N), xn=2*np.ones(N), xu=3*np.ones(N), y=np.random.random(N)*10%0A
+x = np.ones(1000)%0Ay = np.random.random(1000)*10%0A%0Asource = ColumnDataSource(data=dict(x=x, xn=2*x, xu=3*x, y=y
 ))%0A%0A
@@ -556,32 +556,38 @@
 e=5, alpha=0.5)%0A
+%0Ar1 = 
 p.circle(x='xn',
@@ -609,19 +609,108 @@
 olive', 
-   
+source=source, size=5, alpha=0.5)%0An1 = p.circle(x=field('xn', normal), y='y', color='olive',
  source=
@@ -708,32 +708,46 @@
 , source=source,
+%0A             
  size=5, alpha=0
@@ -748,18 +748,39 @@
 lpha=0.5
-)%0A
+, visible=False)%0A%0Ar2 = 
 p.circle
@@ -809,20 +809,108 @@
 'navy', 
-    
+source=source, size=5, alpha=0.5)%0Au2 = p.circle(x=field('xu', uniform), y='y', color='navy',
  source=
@@ -908,32 +908,46 @@
 , source=source,
+%0A             
  size=5, alpha=0
@@ -948,16 +948,31 @@
 lpha=0.5
+, visible=False
 )%0A%0Alabel
@@ -1273,53 +1273,34 @@
 ict(
-source=source, normal=normal, uniform=uniform
+r1=r1, n1=n1, r2=r2, u2=u2
 ), c
@@ -1311,272 +1311,72 @@
 %22%22%22%0A
-    
+for (
 const 
-data = source.data;%0A    for (let i = 0; i %3C data.y.length; i++) %7B%0A        data.xn%5Bi%5D = normal.compute(data.x%5Bi%5D + 1);%0A    %7D%0A    for (let i = 0; i %3C data.y.length; i++) %7B%0A        data.xu%5Bi%5D = uniform.compute(data.x%5Bi%5D + 2);%0A    %7D%0A    source.change.emit();
+r of %5Br1, n1, r2, u2%5D) %7B%0A    r.visible = !r.visible%0A%7D
 %0A%22%22%22
@@ -1414,13 +1414,14 @@
  to 
-apply
+toggle
  Jit
@@ -1472,80 +1472,8 @@
 k)%0A%0A
-output_file(%22transform_jitter.html%22, title=%22Example Jitter Transform%22)%0A%0A
 show

fix transform jitter example (#11781)