How to capture point clicks and holoviews table changes and reflect in original DataFrame

The below code allows you to edit the DataFrames and other parameters have that updated in the chart and table but I can’t find a way to capture the point clicks or holoviews Table changes and update the dataframe with these as well. Can anybody help?

import panel as pn
import param
import numpy as np
import holoviews as hv
from holoviews import opts
import random

hv.extension("bokeh")
pn.extension()


class CirclePoints(param.Parameterized):

    df_circle_points = param.DataFrame(
        pd.DataFrame(
            {"x": [3, 2.6, -3.85, 0], "y": [2.6, -3, 1, 4], "z": [0.2, 0.4, 0.6, 0.8]}
        )
    )
    df_circle_points_old = param.DataFrame(
        pd.DataFrame(
            {"x": [3, 2.6, -3.85, 0], "y": [2.6, -3, 1, 4], "z": [0.2, 0.4, 0.6, 0.8]}
        )
    )
    radius = param.Number(4.0)
    circle_centre_x = param.Number(0.0)
    circle_centre_y = param.Number(0.0)
    num_points = param.Integer(4, bounds=(0, 20))

    @param.depends("df_circle_points", watch=True)
    def points_change(self):
        df_new = self.df_circle_points_old.merge(
            self.df_circle_points, how="outer", indicator=True
        ).loc[lambda x: x["_merge"] == "right_only"]
        print(df_new)
        self.df_circle_points_old = self.df_circle_points.copy()

    def table(self):
        return hv.Table(self.df_circle_points, ["x", "y"], "z")

    @param.depends("df_circle_points", "radius", "circle_centre_x", "circle_centre_y")
    def view(self):
        buffer = 0.2
        hv_points = hv.Points(self.df_circle_points, vdims="z").redim.range(
            x=(
                min(np.min(self.df_circle_points.x), -self.radius) - buffer,
                max(np.max(self.df_circle_points.x), self.radius) + buffer,
            ),
            y=(
                min(np.min(self.df_circle_points.y), -self.radius) - buffer,
                max(np.max(self.df_circle_points.y), self.radius) + buffer,
            ),
        )
        point_stream = streams.PointDraw(
            data=hv_points.columns(),
            num_objects=self.num_points,
            source=hv_points,
            empty_value=0,
        )
        table = self.table()

        DataLink(hv_points, table)

        circle_and_points = (
            hv_points
            * hv.Ellipse(self.circle_centre_x, self.circle_centre_y, 2 * self.radius)
            + table
        ).opts(
            opts.Layout(merge_tools=False),
            opts.Points(
                active_tools=["point_draw"],
                color="z",
                height=400,
                size=10,
                tools=["hover"],
                width=400,
                cmap="RdYlGn",
            ),
            opts.Table(editable=True),
        )

        return circle_and_points


circle_pts = CirclePoints(name="Test")
pn.Column(pn.Row(circle_pts.param), pn.Row(circle_pts.view)).show()
1 Like