Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support hv.Overlay as input to inspect_points #6360

Open
droumis opened this issue Aug 12, 2024 · 0 comments
Open

Support hv.Overlay as input to inspect_points #6360

droumis opened this issue Aug 12, 2024 · 0 comments
Labels
TRIAGE Needs triaging

Comments

@droumis
Copy link
Member

droumis commented Aug 12, 2024

Is your feature request related to a problem? Please describe.

inspect_points does not support overlays and must be used with a single element.

Describe the solution you'd like

Allow users to run insepect_points on an overlay, including multi_y Overlay.

Describe alternatives you've considered

Alternative is for users to define a custom class that runs the inspect_points _process on each of the Overlay's elements. However, this does not work for a multi_y Overlay, tracked as a related issue here.

Here is a simplish code example of using a custom class to iterate over an Overlay:

Code
import numpy as np
import pandas as pd
import holoviews as hv
from holoviews.streams import Tap
from holoviews.operation.datashader import datashade, inspect_points
import panel as pn

hv.extension('bokeh')
pn.extension('tabulator')

np.random.seed(42)
x = np.linspace(0, 10, 100)
y1 = np.sin(x) + np.random.normal(0, 0.1, 100)
y2 = np.cos(x) + np.random.normal(0, 0.1, 100)
df1 = pd.DataFrame({'x': x, 'y': y1, 'source': 'sin-red'})
df2 = pd.DataFrame({'x': x, 'y': y2, 'source': 'cos-blue'})

curve1 = datashade(hv.Curve(df1, kdims='x', vdims=['y', 'source']), cmap='red')
curve2 = datashade(hv.Curve(df2, kdims='x', vdims=['y', 'source']), cmap='blue')

overlay = (curve1 * curve2).opts(width=600)

class CustomInspectPoints(inspect_points):
    def _process(self, element, key=None):
        if isinstance(element, hv.Overlay):
            print(f'Overlay: {element}')
            hits = []
            tap_point = hv.Points([])
            for el in element.values():
                processed = super()._process(el)
                if not self.hits.empty:
                    tap_point = processed
                hits.append(self.hits)
            self.hits = pd.concat(hits, ignore_index=True)
            return tap_point
        return super()._process(element, key=key)

inspector = CustomInspectPoints.instance(pixels=10, streams=[Tap])
inspection = inspector(overlay).opts(hv.opts.Points(color='black', marker='circle', 
                                    size=8, fill_alpha=.1, line_alpha=.8))

def create_tap_table(hits):
    if hits is None or hits.empty:
        return pn.pane.Markdown("No points selected")
    return pn.widgets.Tabulator(hits[['x', 'y', 'source']], show_index=False)

tap_table = pn.bind(create_tap_table, hits=inspector.param.hits)

pn.Column(inspection * overlay, tap_table).servable()
GMT20240812-180736_Clip_inspect_overlay.mp4
@droumis droumis added the TRIAGE Needs triaging label Aug 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
TRIAGE Needs triaging
Projects
None yet
Development

No branches or pull requests

1 participant