panel icon indicating copy to clipboard operation
panel copied to clipboard

Responsive sizing_mode does not work for plotly backend in HoloViews pane

Open MarcSkovMadsen opened this issue 2 years ago • 21 comments

I'm on the main branch of Panel. I was trying to create a Chat with hvPlot application where users can specify the plotting backend they prefer in natural language. Unfortunately the plotly plot does not resize to the width and height of its container.

Its also an issue for me at work as many developers and users prefer the Plotly output. And they also prefer responsive sizing modes such that their apps works on big screens, laptop screens and when doing presentations.

import panel as pn
import hvplot.pandas
from bokeh.sampledata.penguins import data as df

pn.extension("plotly")

plot = df.hvplot.scatter(x='bill_length_mm', y='bill_depth_mm', by='species')

component = pn.Column(
    pn.pane.HoloViews(plot, backend="plotly", sizing_mode="stretch_both"),
    sizing_mode="stretch_both", styles={"background": "salmon"}
)

pn.template.FastListTemplate(
    title="Paint It, Black",
    main=[component],
).servable()

image

Additional Information

The matplotlib and bokeh backends works.

MarcSkovMadsen avatar Dec 10 '23 06:12 MarcSkovMadsen

If there is a workaround I would really like to know it. Then I could get the chat app fully working.

MarcSkovMadsen avatar Dec 10 '23 06:12 MarcSkovMadsen

You need to actually activate the plotly backend in hvPlot and use the responsive option:

import hvplot
import panel as pn
import hvplot.pandas
from bokeh.sampledata.penguins import data as df

hvplot.extension('plotly')

plot = df.hvplot.scatter(x='bill_length_mm', y='bill_depth_mm', by='species', responsive=True)

component = pn.Column(
    pn.pane.HoloViews(plot, backend="plotly"), styles={"background": "salmon"}
)

pn.template.FastListTemplate(
    title="Paint It, Black",
    main=[component],
).servable()

philippjfr avatar Dec 14 '23 09:12 philippjfr

Over all it is very hard for Panel to try to override settings applied to a plot that the user might have created. While it would be nice for pn.pane.HoloViews(..., sizing_mode='stretch_both') to override what the user specified when creating the plot it's not straightforward and it would be quite difficult to support robustly.

philippjfr avatar Dec 14 '23 09:12 philippjfr

If you try the example, then something is wrong; The position of the tool icons

image

I don't see any errors in the browser console.

I'm on the current main branch of Panel using

plotly==5.18.0 bokeh==3.3.2 holoviews==1.18.1 hvplot==0.9.0

MarcSkovMadsen avatar Dec 14 '23 12:12 MarcSkovMadsen

Yep was looking at that this morning. It's missing our patched plotly.css file for some reason.

philippjfr avatar Dec 14 '23 12:12 philippjfr

Does that also solve the fast "dark" mode issue. In dark mode the tool icons are also dark and cannot be seen.

MarcSkovMadsen avatar Dec 14 '23 13:12 MarcSkovMadsen

You need to actually activate the plotly backend in hvPlot and use the responsive option:

import hvplot
import panel as pn
import hvplot.pandas
from bokeh.sampledata.penguins import data as df

hvplot.extension('plotly')

plot = df.hvplot.scatter(x='bill_length_mm', y='bill_depth_mm', by='species', responsive=True)

component = pn.Column(
    pn.pane.HoloViews(plot, backend="plotly"), styles={"background": "salmon"}
)

pn.template.FastListTemplate(
    title="Paint It, Black",
    main=[component],
).servable()

In this example you are cheating :-). You are using hvplot.extension("plotly"). If you are using pn.extension("plotly") then its not working.

import hvplot
import panel as pn
import hvplot.pandas
from bokeh.sampledata.penguins import data as df

pn.extension('plotly')

plot = df.hvplot.scatter(x='bill_length_mm', y='bill_depth_mm', responsive=True)

pane = pn.pane.HoloViews(plot, backend="bokeh", sizing_mode="stretch_both")

component = pn.Tabs(
    pane, ("Hello", "Hello"), styles={"background": "salmon"}, sizing_mode="stretch_both"
)

def  handle(_=None):
    component[0]=pn.pane.HoloViews(plot, backend="plotly", sizing_mode="stretch_both")

update = pn.widgets.Button(name="Update", on_click=handle)

pn.template.FastListTemplate(
    title="Paint It, Black",
    sidebar=[update],
    main=[component],
).servable()

https://github.com/holoviz/panel/assets/42288570/74d2aa23-3e9f-44fb-b1cd-bd936128fdd4

MarcSkovMadsen avatar Dec 14 '23 13:12 MarcSkovMadsen

That is in no way cheating, it's following what the hvPlot docs tell you to do to use the Plotly backend: https://hvplot.holoviz.org/user_guide/Plotting_with_Plotly.html

Callingpn.extension('plotly') has no effect on what hvPlot does and should have no effect on what hvPlot does.

philippjfr avatar Dec 14 '23 13:12 philippjfr

Workaround

If you use the below

hvplot.extension("plotly")
pn.extension('plotly')

Then it works

https://github.com/holoviz/panel/assets/42288570/52ed0099-2774-4e31-a5e0-c63851f7ccdf

MarcSkovMadsen avatar Dec 14 '23 13:12 MarcSkovMadsen

That is in no way cheating, it's following what the hvPlot docs tell you to do to use the Plotly backend: https://hvplot.holoviz.org/user_guide/Plotting_with_Plotly.html

Callingpn.extension('plotly') has no effect on what hvPlot does and should have no effect on what hvPlot does.

Hmmm. So user should combine hvplot and panel extension?

hvplot.extension("plotly")
pn.extension('plotly')

MarcSkovMadsen avatar Dec 14 '23 13:12 MarcSkovMadsen

They certainly should not have to call the panel extension. What definitely has to happen is that hvPlot has to be told to render using plotly instead of the default which is bokeh, ideally that could be done without calling hvplot.extension, i.e. if that's not already possible you should be able to do something like df.hvplot.scatter(..., backend='plotly') or similar.

philippjfr avatar Dec 14 '23 13:12 philippjfr

I do need to call pn.extension("plotly"). Otherwise I get

2023-12-14 13:00:45,048 PlotlyPlot was not imported on instantiation may not render in the served application. Ensure you add the following to the top of your application:

pn.extension('plotly')

MarcSkovMadsen avatar Dec 14 '23 13:12 MarcSkovMadsen

Is the solution to document in the HoloViews reference guide that when using hvPlot and the plotly backend you will need to add both hvplot.extension("plotly") and pn.extension("plotly")?

It is not obvious. If you come from Streamlit, Gradio etc. backgrounds you don't have to do this kind of thing. Its done for you.

MarcSkovMadsen avatar Dec 14 '23 13:12 MarcSkovMadsen

I do need to call pn.extension("plotly"). Otherwise I get

Cannot reproduce this.

It is not obvious. If you come from Streamlit, Gradio etc. backgrounds you don't have to do this kind of thing

I would argue this isn't true at all. hvPlot has an API and you have to correctly use that API to tell it to render with a backend other than the default (i.e. bokeh). The fact that hvplot.extension happens to share a name with pn.extension does not mean they do the same thing, perhaps for clarity it should be hvplot.set_backend('plotly') instead.

philippjfr avatar Dec 14 '23 13:12 philippjfr

But I tell it (dynamically) in the HoloViews pane to use the plotly backend. I expected it to be controlled there. I would expect the HoloViews pane to tell hvPlot/ HoloViews everything it needs to render with the backend I specify. But it seems I need to control it twice.

MarcSkovMadsen avatar Dec 14 '23 13:12 MarcSkovMadsen

But I tell it (dynamically) in the HoloViews pane to use the plotly backend. I expected it to be controlled there. I would expect the HoloViews pane to tell hvPlot/ HoloViews everything it needs to render with the backend I specify.

Unfortunately by that point it's too late, the problem is that hvPlot sets options only for the currently selected backend, which means that if you tell the plot to be responsive=True then that only applies to the Bokeh backend by default. This is a limitation of HoloViews and/or hvPlot, and could maybe be addressed there, e.g. we could decide to simply apply options for any plotting library that is loaded at execution time.

philippjfr avatar Dec 14 '23 13:12 philippjfr

This is also demonstrates the problem I have. I would like to enable bokeh as my default renderer. But support dynamically changing to plotly and having stretch_width working.

But instead the hvplot renderer takes precedence to the backend of the HoloViews pane.

image

MarcSkovMadsen avatar Dec 14 '23 13:12 MarcSkovMadsen

I thought we had an issue about this in hvPlot but it was probably closed when we implemented the backend support. I agree this is a significant point of friction and would help sell one of the core features of hvPlot.

philippjfr avatar Dec 14 '23 13:12 philippjfr

And setting plotly first and then bokeh is not a workaround.

https://github.com/holoviz/panel/assets/42288570/ba34500d-419f-44e1-9954-e0620398aee2

MarcSkovMadsen avatar Dec 14 '23 13:12 MarcSkovMadsen

Ok. I've added an issue to PANEL-CHAT-EXAMPLES that plotly plots don't stretch and I don't know how to solve the problem.

I can't see how to use hvplot.extension("plotly") solution because then that takes precedence over HoloViews pane backend setting.

MarcSkovMadsen avatar Dec 14 '23 13:12 MarcSkovMadsen

The reference documentation for the HoloViews pane is also much more aligned with what I was trying to do

https://panel.holoviz.org/reference/panes/HoloViews.html#switching-backends

There is an example where its shown (indicated?) you can dynamically switch backends, but the example would never work as it does not add plotly neither to the pn.extension or some hvplot/ holoviews extension. And then there is the problem of responsive resizing too.

I believe this documentation should be fixed too. In general I would say the HoloViews reference notebook has not had the love it deserves. Everything about using hvPlot/ HoloViews plots with Panel should be clearly explained. Its the most expected use case.

MarcSkovMadsen avatar Dec 16 '23 06:12 MarcSkovMadsen