holoviz / hvplot

A high-level plotting API for pandas, dask, xarray, and networkx built on HoloViews
https://hvplot.holoviz.org
BSD 3-Clause "New" or "Revised" License
1.07k stars 104 forks source link

dynamic=False not work if I change the widget_location #1241

Open MarcSkovMadsen opened 8 months ago

MarcSkovMadsen commented 8 months ago

I'm playing around with Quarto. I would like to test how I can embed hvPlot plots.

I believe this issue has nothing to do with quarto. I just think that when you change the widget_location the dynamic=False or HoloMap is not working.

Does not work

---
title: hvPlot in Quarto Examples
format: html
---

This is a hvPlot embedded in a Quarto document.

```{python}
import hvplot.pandas
import numpy as np
import pandas as pd

hvplot.extension("bokeh") # Needed for 'quarto preview' to work
frequencies = [0.5, 0.75, 1.0, 1.25]

def sine_curve(phase, freq):
    xvals = np.arange(100)
    yvals = np.sin(phase+freq*xvals)
    return pd.DataFrame({'x': xvals, 'y': yvals, 'phase': phase, 'freq': freq}, columns=['x', 'y', 'phase', 'freq'])

df = pd.concat([sine_curve(0, f) for f in frequencies])

df.hvplot.line('x', 'y', groupby='freq', dynamic=False, responsive=True, height=400, widget_location='top_left')

```bash
quarto preview script.qmd --port 5008

https://github.com/holoviz/hvplot/assets/42288570/61d0640e-01d5-4df7-9bce-3cc67a92c705

Works

Here I don't change the widget_location.

---
title: hvPlot in Quarto Examples
format: html
---

This is a hvPlot embedded in a Quarto document.

```{python}
import hvplot.pandas
import numpy as np
import pandas as pd

hvplot.extension("bokeh") # Needed for 'quarto preview' to work
frequencies = [0.5, 0.75, 1.0, 1.25]

def sine_curve(phase, freq):
    xvals = np.arange(100)
    yvals = np.sin(phase+freq*xvals)
    return pd.DataFrame({'x': xvals, 'y': yvals, 'phase': phase, 'freq': freq}, columns=['x', 'y', 'phase', 'freq'])

df = pd.concat([sine_curve(0, f) for f in frequencies])

df.hvplot.line('x', 'y', groupby='freq', dynamic=False, responsive=True, height=400)


https://github.com/holoviz/hvplot/assets/42288570/a5a12e98-bf73-4994-948d-ce728e82cfcc

## Versions

panel==1.3.5 bokeh==3.3.2 holoviews==1.18.1 hvplot==0.9.1
maximlt commented 8 months ago

Hi @MarcSkovMadsen, I can't reproduce this bug.

hvplot_widgetloc_not_dynamic

I believe this issue has nothing to do with quarto.

I guess it has something to do with Quarto :) I'd be inclined to close this issue?

ahuang11 commented 2 months ago

If you export to HTML, it breaks. I suspect the widget_location is dependent on a server, while the other one is jslinked.

import hvplot.pandas
import numpy as np
import pandas as pd

hvplot.extension("bokeh") # Needed for 'quarto preview' to work
frequencies = [0.5, 0.75, 1.0, 1.25]

def sine_curve(phase, freq):
    xvals = np.arange(100)
    yvals = np.sin(phase+freq*xvals)
    return pd.DataFrame({'x': xvals, 'y': yvals, 'phase': phase, 'freq': freq}, columns=['x', 'y', 'phase', 'freq'])

df = pd.concat([sine_curve(0, f) for f in frequencies])

hvplot.save(df.hvplot.line('x', 'y', groupby='freq', dynamic=False, responsive=True, height=400, widget_location='top_left'), 'test.html')

Something to do with this(?) in panel/pane/holoviews.py


    @param.depends('widget_type', 'widgets', watch=True)
    def _update_widgets(self, *events):
        if self.object is None:
            widgets, values = [], []
        else:
            direction = getattr(self.widget_layout, '_direction', 'vertical')
            widgets, values = self.widgets_from_dimensions(
                self.object, self.widgets, self.widget_type, direction
            )
        self._values = values

        # Clean up anything models listening to the previous widgets
        for cb in list(self._internal_callbacks):
            if cb.inst in self.widget_box.objects:
                cb.inst.param.unwatch(cb)
                self._internal_callbacks.remove(cb)

        # Add new widget callbacks
        for widget in widgets:
            watcher = widget.param.watch(self._widget_callback, 'value')
            self._internal_callbacks.append(watcher)

        self.widget_box[:] = widgets
        if ((widgets and self.widget_box not in self._widget_container) or
            (not widgets and self.widget_box in self._widget_container) or
            not self._initialized):
            self._update_layout()