PolyDraw and PolyEdit Tools' Vertices Not Hiding When Switching to Points in Holoviews

I’m using a panel widget to toggle between drawing points and polygons with the PointDraw and PolyDraw streams in Holoviews. When “Points” is selected, only the Points layer is visible and the PointDraw tool is active, and when “Polygons” is selected the Polygons layer is visible and PolyDraw is active.

My problem: when switching from “Polygons” back to “Points,” the polygon vertices from the PolyDraw tool remain visible and don’t disappear as expected. A similar problem happens when activating the PolyEdit tool instead of PolyDraw: if the polygon is selected (vertices are visible) and I switch back to “Points”, the vertices remain visible alongside the Points.

Here is a minimal example:

import holoviews as hv
import panel as pn
from holoviews import streams
import param
pn.extension()

select_button = pn.widgets.RadioButtonGroup(options=['Points', 'Polygons'], value='Points')
active_tool_stream = streams.Stream.define('ActiveToolStream', t=streams.param.String(default=''))()

@param.depends(select_button.param.value)
def points_layer(value):
    points = hv.Points([(0, 0), (0.25, 0.25)], kdims=['Longitude', 'Latitude']).opts(size=8, color='red')
    if value == "Points":
        points = points.opts(visible=True)
        active_tool_stream.event(t='point_draw')
    else:
        points = points.opts(visible=False)
        active_tool_stream.event(t='poly_draw') # comment this line and uncomment below to test poly_edit
        # active_tool_stream.event(t='poly_edit') 
    return points

@param.depends(select_button.param.value)
def polygons_layer(value):
    polys = hv.Polygons([[(1, 0), (1, 1), (0, 1)]], kdims=['Longitude', 'Latitude'])
    if value == "Points":
        polys = polys.opts(visible=False)
    else:
        polys = polys.opts(visible=True)
    return polys

dm_points = hv.DynamicMap(points_layer)
point_draw_stream = hv.streams.PointDraw(source=dm_points, num_objects=2, drag=True)

dm_polys = hv.DynamicMap(polygons_layer)
poly_draw_stream = hv.streams.PolyDraw(source=dm_polys, num_objects=1, drag=True, show_vertices=True)
poly_edit_stream = hv.streams.PolyEdit(source=dm_polys)

overlay = (dm_points * dm_polys).apply.opts(
    active_tools=[active_tool_stream.param.t],
    height=400, width=400
)

layout = pn.Column(select_button, overlay)
layout

This is how it looks after switching from “Polygons” to “Points” (only red points should be visible):

image

Is this a bug? In any case, any ideas on how to solve this will be appreciated!

Thank you!

Is visible a valid opt? Otherwise, Maybe try using alpha=0

It seems to be doing the same as alpha=0. Somehow the change in alpha/visible is reaching the drawn polygon, but it’s not getting all the way to whatever is rendering its vertices.

I kept trying things and found a partial workaround using a Pipe stream to alternate between empty data and the drawn polygon data for the Polygons layer, instead of changing alpha/visible opts (see code at the bottom). I say “partial” because it helps with the PolyDraw case, but the issue persists for the PolyEdit tool: if I select the polygon to edit it (vertices appear to signal that the polygon is selected) and switch to “Points” before de-selecting the polygon, then the vertices fail to disappear with the polygon. I wonder if I can avoid the issue, maybe by manipulating the polygon selection? If I could de-select the polygon when select_button is switched to “Points”, then the vertices should disappear as needed. Do you think I could do that?

I’m totally open to direct solutions to the vertices ignoring changes in the DynamicMap opts as well! But a workaround seems more likely at this point.

Thanks again!

Updated code:

# To see "ghost vertices": select "Polygons", activate edit tool in toolbar, 
# select polygon by long-pressing it, switch to "Points".
# You'll see the vertices of the polygon still showing.

import holoviews as hv
import panel as pn
from holoviews import streams
import param

pn.extension()

select_button = pn.widgets.RadioButtonGroup(options=['Points', 'Polygons'], value='Points')
active_tool_stream = streams.Stream.define('ActiveToolStream', t=streams.param.String(default=''))()
poly_data_pipe = streams.Pipe(data={'Longitude': [], 'Latitude': []})
poly_data_store = {'Longitude': [0, 1, 1], 'Latitude': [1, 1, 0]}

@param.depends(select_button.param.value)
def points_layer(value):
    points = hv.Points([(0, 0), (2, 2)], kdims=['Longitude', 'Latitude']).opts(size=8, color='red')
    if value == "Points": 
        points = points.opts(alpha=1) # points.opts(visible=True)
        active_tool_stream.event(t='point_draw')
    else:
        points = points.opts(alpha=0) # points.opts(visible=False)
        active_tool_stream.event(t='poly_draw') 
        # active_tool_stream.event(t='poly_edit') 
    return points

@param.depends(select_button.param.value, poly_data_pipe.param.data)
def polygons_layer(value, data):
    polys = hv.Polygons(data, kdims=['Longitude', 'Latitude'])
    return polys

dm_points = hv.DynamicMap(points_layer)
point_draw_stream = hv.streams.PointDraw(source=dm_points, num_objects=2, drag=True)

dm_polys = hv.DynamicMap(polygons_layer)
poly_draw_stream = hv.streams.PolyDraw(source=dm_polys, num_objects=1, drag=True, show_vertices=True)
poly_edit_stream = hv.streams.PolyEdit(source=dm_polys)

@param.depends(select_button.param.value, watch=True)
def update_polygon_data(value):
    if value == "Points":
        global poly_data_store
        if poly_draw_stream.data['xs']:
            lon = poly_draw_stream.data['xs'][0]
            lat = poly_draw_stream.data['ys'][0]
        else:
            lon = []
            lat = []
        poly_data_store = {'Longitude': lon, 'Latitude': lat}
        poly_data_pipe.send({'Longitude': [], 'Latitude': []})
    else:
        poly_data_pipe.send(poly_data_store)

overlay = (dm_points * dm_polys).apply.opts(
    active_tools=[active_tool_stream.param.t],
    height=400, width=400
)

layout = pn.Column(select_button, overlay)
layout

Seems like a bug which stems from the vertices points not associated with the polygons. I wonder if you can disable show_vertices?

Indeed there is a show_vertices attribute for both the PolyDraw and PolyEdit streams. Thanks for the suggestion! And as a note for anyone reading, there is also a vertex_style parameter.

However, setting the attribute to False (poly_draw_stream.show_vertices=False) does nothing to the layout, unless I call it again in a subsequent notebook cell. I wish I could treat it as an event (poly_draw_stream.event(show_vertices=False)), but show_vertices is not a parameter. Same applies to vertex_style. I wonder if there would be way to somehow refresh the overlay so it could take into account the changing values of show_vertices/vertex_style dynamically.

Yeah I’m not sure; perhaps file a bug in HoloViews!

Yeah that’s probably the best. Thank you for your time and ideas!