Hi,
I have an application with two linked plots, one of which supports a point-draw tool to interactively move to a point of interest (similar in behavior to a slider UI in a 1D case, which I’d prefer not to use in my particular end-use scenario).
The second link plot displays data on a constrained curve (or surface) corresponding to that selection.
I apply client-side transforms to enforce the constraints.
The interactions and displays work as expected, but I notice that in general the underlying source data is not guaranteed to be consistent with what is shown on the plot. The mismatch happens when a move or add action puts the point of interest outside of the allowable domain.
Is there a preferred way to achieve the desired consistency for this particular use case?
I am using bokeh 2.0.1 and running as a server. A simple example to illustrate the problem follows, and a screen capture of the simplified illustrative example is attached.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
"""
import numpy as np
from bokeh.plotting import figure, curdoc
from bokeh.transform import transform
from bokeh.layouts import column
from bokeh.models import LinearInterpolator
from bokeh.models import ColumnDataSource, PointDrawTool
def data_cb(attr, old, new):
print("X OLD:{:+.3f} NEW:{:+.3f}".format(old['xpt'][0],new['xpt'][0]))
# Constrained point viewer
p0 = figure(x_range=(-1.333,1.333), y_range=(-1.333,1.333), width=500, height=500)
p0.toolbar_location = None
# Linked x- selector figure
p1 = figure(x_range=p0.x_range, y_range=p0.y_range, width=500, height=30, background_fill_color='#000000')
p1.xaxis.major_label_text_color = None
p1.xaxis.major_label_text_font_size = '0pt'
p1.xaxis.ticker.desired_num_ticks = 0
p1.yaxis.ticker.desired_num_ticks = 0
p1.toolbar_location = None
# Quadratic reference curve
xq = np.arange(-1.000,1.001,0.001)
yq = 2.000*(xq ** 2) - 1.000
Sq = ColumnDataSource(data=dict(xq=xq, yq=yq))
p0.line(x='xq', y='yq', source=Sq, line_color='#AAAAAA')
# Point on curve
# Linear interpolators constrain interactive taps to reference curve
li_x = LinearInterpolator(x='xq', y='xq', data=Sq, clip=False)
li_y = LinearInterpolator(x='xq', y='yq', data=Sq, clip=False)
Spt = ColumnDataSource(data=dict(xpt=[xq[500]]))
Spt.on_change('data', data_cb)
r0 = p0.circle(x=transform('xpt', li_x), y=transform('xpt', li_y), source=Spt, size=12, fill_color='#000000', line_color='#000000')
r1 = p1.circle(x=transform('xpt', li_x), y=0.0, source=Spt, size=12, fill_color='#FFFFFF', line_color='#FFFFFF')
_drawtool = PointDrawTool(renderers=[r1], add=True, num_objects=1)
p1.add_tools(_drawtool)
p1.toolbar.active_tap = _drawtool
curdoc().add_root(column(p0,p1))