I think it should work with the addition of the tap.event() mehtod and directly plotting the self.x and self.y. Here the update x,y is directly within the plot function. It should also work if you keep it as in your example. Maybe you check how often these update functions are getting called because they might loop.
Best regards
import param
import holoviews as hv
import panel as pn
pn.extension()
class TapTest(pn.custom.PyComponent):
x = param.Number(default=0)
y = param.Number(default=0)
def __init__(self, **params):
super().__init__(**params)
self._tap = hv.streams.Tap()
hv_pane = pn.pane.HoloViews()
hv_pane.object = hv.DynamicMap(self.plot, streams=[self._tap])
pn.bind(self.update_tap, self.param.x, self.param.y, watch=True)
self._layout = pn.Column(hv_pane, self.param.x, self.param.y)
def update_tap(self, x, y):
self._tap.event(x=x, y=y)
def plot(self, x, y):
if x and y:
self.param.update(x=x, y=y)
return hv.Points([(self.x, self.y)]).opts(tools=['tap'])
def __panel__(self):
return self._layout
pn.serve(TapTest())
thanks for writing an issue. As I am quite interested in working with biderectional tools, I tried few more things and came up with this. I don’t know exactly whats going on with the added callback and how it is connected to the the tab tool within the plot and I have also no idea why it does not create an infinite loop.
However, also not optimal.
import param
import panel as pn
import holoviews as hv
from holoviews.streams import Tap, Stream
from holoviews.plotting.bokeh.callbacks import TapCallback
from numbers import Number
pn.extension()
class TapBi(Tap):
"""
The x/y-position of a tap or click in data coordinates.
"""
x_sel = param.ClassSelector(class_=Number, default=None,)
y_sel = param.ClassSelector(class_=Number, default=None,)
def transform(self):
return {'x_sel': self.x,
'y_sel': self.y}
Stream._callbacks['bokeh'].update({TapBi: TapCallback})
class TapTest(pn.custom.PyComponent):
tap = TapBi()
def __init__(self, **params):
super().__init__(**params,)
hv_pane = pn.pane.HoloViews()
hv_pane.object = hv.DynamicMap(self.plot, streams=[self.tap])
self._layout = pn.Column(hv_pane, self.tap.param.x_sel, self.tap.param.y_sel)
@param.depends('tap.x_sel', 'tap.y_sel', watch=True)
def trigger_tap(self, **kwargs):
print("update")
self.tap.event(x=self.tap.x_sel, y=self.tap.y_sel)
def plot(self,x,y, **kwargs):
return hv.Points([(x, y)]).opts(tools=['tap'])
def __panel__(self):
return self._layout
pn.serve(TapTest())