I need to plot a number of functions defined analytically (via
CustomJSExpr). As far as I understand, Bokeh requires using explicitly
set x array for plot. But amount of (x,y) points that are actually
needed to draw plot lines depend heavily on the range selected by user:
as range becomes smaller, x points should be placed more densely to
keep plots accurate. And using small steps for x over the whole range is
undesirable because functions are quite costly to re-evaluate after
their parameters are interactively changed.
Iāve looked at topic
but I havenāt identified an example which is close enough to my case.
What Iād like to have is not actually a downsampling of dataset, but
dynamic generation of ādatasetā (i.e., x values).
I think using CustumJSExpr will not work well if your goal is non-uniform sampling, since each expression only affects on thing (i.e. x- or y-coordinates) at a time. I think youād find better success using a CustomJS callback on range updates. The callback can compute first compute the appropriate x-coordinate distribution based on the range, and then compute the y-values for those computed c-coordinate [1]. Then you can set both the new data for both x and y fields at the same time to update the plot.
āDerived datasourcesā indeed sounds like a great concept which describes very well what Iām doing now. I actually have āsmallā datasources with pairs (x, amplitude), from which I build compositions of Gaussian functions, centered in those xāes, scaled by respective amplitudes, and sigma value is taken from UI setting. Each of those compositions form a glyph on the plot. And on top of that, I have āsummingā glyph which displays a sum of a few other existing Bokeh glyphs selected by user in UI and multiplied by with user-specified coefficients.
However, that topic doesnāt provide an actual outline how to implement proper derived datasource in JS, and corresponding feature request has not been addressed yet too.
Make a ābaseā CDS (or, probably better, a custom DataModel) to hold the process variables from which to create your derived CDS.
Instantiate (you can do this python side or JS-side) an empty CDS to hold your derived data.
Point your renderers etc. to run off the derived CDS.
Build CustomJS (to trigger on user action) that willā¦
Collect all necessary widget states/views, and update the ābaseā CDS or DataModel
Determine the appropriate range/resolution to evaluate the functionā¦ e.g. simple 1D case, say user is zoomed to x = 1 to 100 on the figure, therefore weāll evaluate our function at 1000 points evenly spaced from from x=1 to 100, so populate an array accordingly, e.g. var xs = [1,1.1,1.2....99.9,100]
Evaluate the function at those values e.g. var ys = xs.map(y=>some_function(y,....other widget state variables as args)
Update the derived CDS with those values e.g. `derived_src.data = {āxsā:xs,āysā:ys}
Obviously this can get more complex, as you can āstackā derived datasources on top of each other etc, but the overall paradigm doesnāt change. When user changes something, check the necessary states, determine the right range/resolution to evaluate things, evaluate them, and update the derived datasources with that.