Search code examples
matplotlibbokehpanelholoviews

How to place a widget over a panel HoloViews dynamic map


I am trying to display the widgets of a HoloViews dynamic plot (Select, Slider, etc.) over the plot. All I can find is the widget_location argument which takes the location relative to the plot (‘left’ , ‘right’, …). But I want it to be placed over the plot, not next to it. I was wondering if there is a way for doing this?

P.S. for instance there is opts(colorbar_opts={'location':(float,float)}) which can be used to place the colorbar where you want. It would be very useful to have a similar option for widgets.


Solution

  • OK, I found the solution! I have to use custom CSS. The code below shows how to do it.

    import holoviews as hv
    import panel as pn
    pn.extension('ace')
    hv.extension("bokeh")
    
    
    plots = {}
    for i in range(5,10):
        data = {
            "x": list(range(0,i)), "y": [i]*i
        }
        plots[i]=hv.Curve(data).opts(width=500)
    hvmap = hv.HoloMap(plots)
    
    left_pos = pn.widgets.IntSlider(value=5, step=1, start=-1000, end=5, name="x")
    top_pos = pn.widgets.IntSlider(value=5, step=1, start=5, end=200, name="y")
    style = pn.pane.HTML(height=0, width=0, sizing_mode="fixed", margin=0)
    css = pn.widgets.Ace(height=150)
    
    @pn.depends(left_pos=left_pos, top_pos=top_pos, watch=True)
    def _update_css(left_pos, top_pos):
        value = f"""
    .bk.panel-widget-box {{
        left: {left_pos}px !important;
        top: {top_pos}px !important;
    }}
    """
        css.value = value
        style.object = "<style>" + value + "</style>"
    
    pn.Column("""# How to overlay widgets on HoloViews Map?
    
    We will be using css to overlay and Panel to create the this tool""",
        hvmap,
        "## Settings",
        left_pos,
        top_pos,
        css,
        style,
    ).servable()
    

    All credits goes to Marc Skov Madsen. Original answer here