How to update data of contour in CustomJS fun?

I want to update the data(x, y, z) of contour plot in customjs, but I do not know how to access the x, y, z property in js context since contour does not support ColumnDataSource.

By the way, I find change the property of ploting object(figure, ) in js is complicated. For example, I change the title of figure by accessing p.properties.title.obj.title.text = .... Is there exist a simple and uniform way to access the property of ploting object(figure, ) in js context?

from bokeh.models import (ColumnDataSource, CustomJS, Label, DateSlider, LabelSet, 
Button, CategoricalColorMapper, HoverTool, Label, SingleIntervalTicker, Slider)
from bokeh.plotting import figure, show, save, output_file
from bokeh.layouts import column, row, layout
from bokeh.palettes import Sunset8

import numpy as np
import pandas as pd


x, y = np.meshgrid(np.linspace(0, 3, 40), np.linspace(0, 2, 30))
x = x.reshape(1, 30, 40)
y = y.reshape(1, 30, 40)
x = np.repeat(x, 5, axis=0)
y = np.repeat(y, 5, axis=0)
z = np.random.rand(5, 30, 40)

step_times = pd.date_range("2022-1-1", freq="d", periods=5)
step_times_str = [str(t) for t in step_times]

frames_data = {}
for i, t in enumerate(step_times):
    frames_data.update({str(t): {"x": x[i, ...], "y": y[i, ...], "z": z[i,...]}})
frame_data = ColumnDataSource(data=dict(frames_data[step_times_str[0]]))


p = figure(width=550, height=300, x_range=(0, 3), y_range=(0, 2), title="title")

xx = frame_data.data["x"]
yy = frame_data.data["y"]
zz = frame_data.data["z"]
levels = np.linspace(0, 1, 5)
contour_renderer = p.contour(xx, yy, zz, levels, fill_color=Sunset8, line_color="black")

colorbar = contour_renderer.construct_color_bar()
p.add_layout(colorbar, "right")

button = Button(label='Update contour',  width=80)
callback_button_reset = CustomJS(args=dict(
    p=p, t=step_times_str,
    c=contour_renderer, df_all=frames_data
), code="""
    p.properties.title.obj.title.text = t[1];

    console.log(c.properties);
    console.log(c.x);   //undefined
    c.x = df_all[t[1]]["x"];
    c.y = df_all[t[1]]["y"];
    c.z = df_all[t[1]]["z"];
""")
button.js_on_click(callback_button_reset)


output_file("contour.html")
lay = layout([p, button])
save(lay)

Hi @swpper1 While it is technically possible, in principle, to update a contour glyph from a CustomJS, in practice it is really not possible in any reasonable way. That is because, unlike many other things in Bokeh, the work is not done on the JavaScript side. Bokeh uses the contourpy library, which is actually a Python binding for a C++ library, to do the actual contour computations. So, it’s fairly straightforward to update Bokeh contour plots from Python (and there is an example that demonstrates this), but in order to update from JS the only options would be:

  • Compute new contour data manually in JavaScript. You would need to find or write a JavaScript contouring algorithm (e.g. “marching squares”) yourself, to use inside the CustomJS
  • Pre-compute all possible contour data for every contour level you expect to need up front in Python, and ship all that hard-coded data inside the CustomJS to switch between (probably expensive in terms of data size).

cc @Ian_Thomas to comment on any future possibilities, such as possibly adding a contouring algorithm directly to BokehJS (and to correct anything I got wrong above).

1 Like

Everything @Bryan says is correct.

As for the possibility of porting contourpy from Python to JavaScript, I have no plans to do that and I am not aware of anyone else who would be interested in doing it. It would be an interesting challenge to port, although probably it would be more sensible to port to WASM rather than JavaScript, but that is a separate issue from packaging it and then having to support it for many years. The latter is probably only going to happen if there is some financial backing for this approach.

1 Like

@Bryan @Ian_Thomas Thank you for your explanation. I see the crux of the matter. Bokeh is a good visualization package and I hope it to be better. :smile:

FYI I have ported in d3’s contour (which uses marching squares) → GitHub - d3/d3-contour: Compute contour polygons using marching squares. for gridded data (or gridded irregular data myself via an interpolant of my choice (e.g. kriging, rbf, idw etc) successfully. I have also dabbled with this branch GitHub - Fil/d3-tricontour: Create contours from non-gridded data with meandering triangles. as well. I don’t know how performance compares though.

2 Likes

@gmerritt123 Thank you.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.