How do I access the selected element when using PolyDraw/PolyEdit?

Sample code from the docs:

import numpy as np
import holoviews as hv
from holoviews import opts, streams

hv.extension('bokeh')

np.random.seed(42)
polys = hv.Polygons([hv.Box(*i, spec=np.random.rand()/3)
                     for i in np.random.rand(10, 2)])
ovals = hv.Polygons([hv.Ellipse(*i, spec=np.random.rand()/3)
                     for i in np.random.rand(10, 2)])
poly_edit = streams.PolyEdit(source=polys, vertex_style={'color': 'red'}, shared=True)
poly_edit2 = streams.PolyEdit(source=ovals, shared=True)

(polys * ovals).opts(
    opts.Polygons(active_tools=['poly_edit'], fill_alpha=0.4, height=400, width=400))

This allows users select and interact with the objects in the drawing. How would one go about accessing the selection? I know there has to be a stream in there somewhere, I just can’t figure out where.

To access the selection you should use the Selection1D stream just like other elements.

box_sel = Selection1D(source=polys)
oval_sel = Selection1D(source=ovals)

and then access the selection with:

polys.iloc[box_sel.index]
ovals.iloc[oval_sel.index]

I had tried Selection1D but I couldn’t get it work alongside the poly_edit. I assumed this was because there was already an underlying stream in the poly_edit tool. This is an example of what I’ve tried:

polys = hv.Polygons([
    {('x', 'y'): [[0,0],[0,1],[1,1]], 'name':'foo'},
    {('x', 'y'): [[0,2],[2,2],[2,3]], 'name':'bar'}
], vdims=['name'])

poly_select = hv.streams.Selection1D(source=polys)
poly_edit = streams.PolyEdit(
    source=polys, 
    vertex_style={'color': 'blue', 'size': 4}
)
poly_draw = streams.PolyDraw(
    source=polys, 
    drag=False, 
    show_vertices=True, 
    vertex_style={'color': 'blue', 'size': 4}
)

dmap = hv.DynamicMap(lambda index: polys.iloc[index] if index else polys, streams=[poly_select])

dmap.opts(opts.Polygons(tools=['tap', 'hover', 'poly_edit','poly_draw']))

The tap tool works, but the drawing tools do not.

Try making the DynamicMap the source. That said I’m kind of confused about what you’re trying to achieve? You are using the Selection1D callback index in the DynamicMap? That means when you click on a polygon it’ll apply the selection and delete the other polygons…

polys = hv.Polygons([
    {('x', 'y'): [[0,0],[0,1],[1,1]], 'name':'foo'},
    {('x', 'y'): [[0,2],[2,2],[2,3]], 'name':'bar'}
], vdims=['name'])

poly_select = hv.streams.Selection1D()
dmap = hv.DynamicMap(lambda index: polys.iloc[index] if index else polys, streams=[poly_select])

poly_edit = hv.streams.PolyEdit(
    source=dmap, 
    vertex_style={'color': 'blue', 'size': 4}
)
poly_draw = hv.streams.PolyDraw(
    source=dmap, 
    drag=False, 
    show_vertices=True, 
    vertex_style={'color': 'blue', 'size': 4}
)

dmap.opts(hv.opts.Polygons(tools=['tap', 'hover']))

The drawing tools don’t work in your example either, but maybe I should clarify my usecase. I am trying to create polygons and assign some values to those polygons. Theoretically I could use annotators for some simple attributing, but I hit a bug (https://github.com/holoviz/holoviews/issues/4340). Most likely I’ll need more complex attributing anyway so I intend to create a Panel app to assign these attributes.

When I click on the polygons with poly_edit it highlights a polygon. If I could just get access to the highlighted polygon index, I can achieve what I need. I guess I just thought/hoped that since the highlighting mechanism is already in place, that there was an underlying stream inside of the PolyEdit that I could access.

Theoretically I could use annotators for some simple attributing, but I hit a bug (Drawing 2D elements with Annotators throws js error · Issue #4340 · holoviz/holoviews · GitHub).

Fixed here Fix undefined Javascript variables in bokeh links by philippjfr · Pull Request #4341 · holoviz/holoviews · GitHub

The drawing tools don’t work in your example either, but maybe I should clarify my usecase.

They certainly do for me, so this is worth following up on.

When I click on the polygons with poly_edit it highlights a polygon. If I could just get access to the highlighted polygon index, I can achieve what I need. I guess I just thought/hoped that since the highlighting mechanism is already in place, that there was an underlying stream inside of the PolyEdit that I could access.

Yeah, there isn’t but what you’re doing with the DynamicMap in your example does not match what you describe in your use case.

I think I kind of headed off in the wrong direction with the dmap. I pulled master after the Annotator bug fix and it looks like I can achieve mostly what I want with them using this workflow:

poly_annotate = hv.annotate.instance()
poly_layout = poly_annotate(hv.Polygons([]), annotations=['Label'])
poly_layout

Draw a polygon, select it, then use

poly_annotate.selected

to access the selection. That gives me the selected element itself (an hv.Polygon), not an index in terms of the hv.Table or the full polygons dataset. Is there an easy way to get that?

Or is there a parameter that I can watch so that I can do something every time the selection changes?