# Personal opinions about best practices for Panel + HoloViews

**URL:** <https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789>\
**Category:** Showcase\
**Tags:** panel, hvplot\
**Created:** [January 28, 2024, 5:54am UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789 "2024-01-28T05:54:11Z")\
**Posts on this page:** 12\
**Page:** 2

<div class="post-metadata">

**Author:** ![fmfreeze](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/fmfreeze/32/1704_2.png) [@fmfreeze](https://discourse.holoviz.org/u/fmfreeze)\
**Post date:** [February 29, 2024, 8:22pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/21 "2024-02-29T20:22:52Z")

</div>

Sorry, but I still don’t see the relation to the modal-browser issue.  
Do you think because of endless dmap retriggering the object is not rendered in chrome/edge?

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [February 29, 2024, 9:14pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/22 "2024-02-29T21:14:22Z")

</div>

Oh sorry, I’m just using this thread to take notes for an eventual best practices guide; not as a reply to your question.

---

<div class="post-metadata">

**Author:** ![StuckDuckF](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/stuckduckf/32/4347_2.png) [@StuckDuckF](https://discourse.holoviz.org/u/StuckDuckF)\
**Post date:** [March 4, 2024, 2:26pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/23 "2024-03-04T14:26:57Z")

</div>

I would love to see how you create more complicated Holoviews objects from scratch and even more interested in how you set options. I have been struggling setting `opts` such as `line_color` or other more niche options while overlaying geofeatures and other plots (Say `FilledContours`, `WindBarbs` and `coastline`). It gets even trickier if you try and change them later as now it is an `Overlay`.

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [March 19, 2024, 10:17pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/24 "2024-03-19T22:17:48Z")

</div>

> I have been struggling setting `opts` such as `line_color` or other more niche options while overlaying geofeatures and other plots

You can target specific elements: `Overlay([hv_obj1, hv_obj2]).opts("Curve", line_color="red")`

* * *

Collecting more best practices things here:

- Generally, try to replace HoloViews usage with hvPlot. At a certain point of complexity, such as with the use of ‘.select’, it might be better to stick with HoloViews.
- Almost always, try to replace the use of `datashade` with `rasterize` (read [this page](https://holoviews.org/user_guide/Large_Data.html)). Essentially, `rasterize` allows Bokeh to handle the colormapping instead of Datashader.
- Remove all `pn.interact` usage
- Try to avoid `.param.watch()` usage. This is [pretty low-level and verbose approach](https://param.holoviz.org/user_guide/Dependencies_and_Watchers.html#watchers) Prefer using `pn.bind()`. Read [this page](https://panel.holoviz.org/explanation/api/reactive.html) for explanation.
- For apps built using a class approach, when they create a `view()` method and call it directly, update the class by inheriting from `pn.viewable.Viewer` and replace `view()` by ` __panel__ ()`. Here is an [example](https://panel.holoviz.org/gallery/nyc_deckgl.html).

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [April 11, 2024, 6:10pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/25 "2024-04-11T18:10:16Z")

</div>

Revising:

```python
set loading=True/False inside a try/finally block 6 so that widgets are disabled while loading, and upon completion/something goes wrong, the widgets are always reactivated.

```

Philipp mentioned we could simply do `with param.update`

```auto
import time
import panel as pn

pn.extension()

layout = pn.WidgetBox(pn.widgets.TextInput(), pn.widgets.Button(name="Click me!"))
layout

```

```auto
with layout.param.update(loading=True):
    time.sleep(2)
    layout[0].value = "Loaded!"

```

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [April 17, 2024, 5:00pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/26 "2024-04-17T17:00:27Z")

</div>

From Marc

> <https://github.com/holoviz/panel/pull/4281#issuecomment-2061774424>
>
> There's still a lot of valuable stuff in here and it overlaps a bit with @ahuang…11's suggestion of adding a best practices guide. So I'd suggest that I close this for now but perhaps Andrew could revive this in form of a "Performance Checklist" how-to guide.

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [April 17, 2024, 8:37pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/27 "2024-04-17T20:37:56Z")

</div>

Using flexbox instead of column / row

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [May 6, 2024, 2:21pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/28 "2024-05-06T14:21:20Z")

</div>

Adding another to the list: toggling axiswise, framewise, shared\_axes,

> [@Redim behaves differently in different contexts](https://discourse.holoviz.org/t/redim-behaves-differently-in-different-contexts/7207):
>
> I’m doing some experiments in a notebook to work out some data flow for a larger application. I have the following code: # cell1 import holoviews as hv import numpy as np import pandas as pd import panel as pn hv.extension('bokeh') pn.extension() # cell2 df = pd.DataFrame({k: np.random.default\_rng().random(100) + i for i, k in enumerate('abcd')}) pipe = hv.streams.Pipe() dm = hv.DynamicMap(hv.Dataset, streams=[pipe]) # cell3 pipe.send(df) # cell4 def plot(elem, x\_col, y\_col): range\_x = …

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [May 9, 2024, 8:29pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/29 "2024-05-09T20:29:42Z")

</div>

Started migrating over here; let me know if you have feedback!

> <https://github.com/holoviz/panel/pull/6819>
>
> Starts migrating the collection from https://discourse.holoviz.org/t/personal-op…inions-about-best-practices-for-panel-holoviews/6789/27 to the official docs page, with examples
> 
> Thus far, I think it can be broken down into two sections: Dev Experience (or I was also thinking 'Nice to knows') and User Experience, and thus two separate notebooks.
> 
> Feedback appreciated on how to proceed (and what's missing; in particular, how to add it to the index).

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [May 16, 2024, 6:59pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/30 "2024-05-16T18:59:39Z")

</div>

Widgets should not be used like param

> <https://github.com/holoviz/param/issues/832>
>
> Param was designed to support nested Parameterized objects, where the value of a… Parameter is a Parameterized that has its own Parameters:
> 
> 
> \`\`\`python
> import param, panel as pn
> 
> class P(param.Parameterized):
> x = param.Integer(5)
> y = param.ClassSelector(param.Parameterized, default=pn.widgets.IntSlider(value=7))
> 
> @param.depends("y.value", watch=True)
> def fn(self):
> self.x = self.y.value
> 
> p = P()
> 
> p.y.value=32
> p.x
> \# 32
> \`\`\`
> 
> Here the value of \`y\` is a Parameterized that happens to be a \[HoloViz Panel\](https://panel.holoviz.org) widget that has a Parameter named \`value\`, and you can see that Param code can depend on that widget's Parameters.
> 
> However, several Panel core developers have noticed Panel users writing classes like:
> 
> \`\`\`python
> import param, panel as pn
> 
> class P(param.Parameterized):
> x = param.Integer(5)
> y = pn.widgets.IntSlider(value=7)
> 
> @param.depends("y.value", watch=True)
> def fn(self):
> self.x = self.y.value
> 
> p = P()
> 
> p.y.value=32
> p.x
> \# 32
> \`\`\`
> 
> This code was not anticipated when writing Param but it happens to work in this case, because the dependency code does not actually check that \`y\` was defined as a Parameter before fetching the \`value\` parameter from that object. And the code makes sense at a semantic level, because both a \`param.Integer\` and a \`pn.widgets.IntSlider\` are objects that have an underlying integer value, so it would seem reasonable to be able to use a widget the same way one uses a Parameter.
> 
> However, because this case was never intended to be supported, a widget used as if it were a Parameter does not actually work like a Parameter in all cases. In particular, the Parameter \`x\` will be instantiated into an object, giving the object an independent copy of the value for \`x\`, while the widget \`y\` is a normal Python class attribute, and will thus not be instantiated. So things will seem to be working, but if the class P is ever instantiated more than once, \`x\` will be independent per object, and \`y\` will be shared across all objects, leading to untold subtle bugs.
> 
> A user can currently avoid this issue by moving the widget definition out of the class and into the constructor:
> 
> \`\`\`python
> import param, panel as pn
> 
> class P(param.Parameterized):
> x = param.Integer(5)
> 
> def \_\_init\_\_(self, \*\*params):
> super().\_\_init\_\_(\*\*params)
> self.y = pn.widgets.IntSlider(value=7)
> 
> @param.depends("y.value", watch=True)
> def fn(self):
> self.x = self.y.value
> 
> p = P()
> 
> p.y.value=21
> p.x
> \# 5 # Why is this not 32?
> \`\`\`
> 
> But that's a lot wordier, fails to declare the Parameter value in the class's manifest of Parameters, and in this case doesn't work (maybe because of https://github.com/holoviz/param/issues/829?).
> 
> Because people seem to fall into the trap of putting widgets at the class level quite a bit, I think we should do something about it. The options I can think of are:
> 
> 1. Warn people not to do this! If we find a Parameterized as a class attribute, and certainly if we find one being depended on, warn that this attribute will not behave like a true Parameter and will not be instantiated per object, and point people to an implementation like the first one above.
> 
> 2. If we find a Parameterized \`q\` as a class attribute of a Parameterized class, treat it as if there were a Parameter declared like \`param.ClassSelector(param.Parameterized, default=q)\`. We probably wouldn't actually create such a Parameter, but we'd instantiate a copy of the Parameterized into each object as if we had. I.e., just accept that people will do this, and treat it as legal. In practice I'd guess it's only Panel users who expect such usage to work, but the implementation would be for any Parameterized, and maybe there are other similar applications for this approach.
> 
> 3. Under the theory that people are treating Panel Widgets and Parameters as interchangeable, one could imagine doing even more magic, so that if we find a Panel Widget (or e.g. use duck typing and find a Parameterized with a \`value\` Parameter), treat it as if they had actually declared that Parameter in this class (\`y=param.Integer(7)\` here, where \`y\` becomes a reference to the \`value\` parameter of this widget). It's hard to pin down how that could work, and it would be Panel-specific deep magic, so it would be hard to convince me that it's a good idea, but I wanted to list the idea concretely just so that we can be sure that what people seem to be assuming would work is really not something we should ever be supporting.
> 
> Personally, I vote against 3, and by default I'd vote for 1 because 2 doesn't solve a problem I have. But if 2 makes sense to other people and would support new users better, I don't think it would be difficult to implement, and I don't think it would affect code that's currently working properly. Any thoughts from others?

> [@Declaring new widgets with param.Parameterized and use decorators](https://discourse.holoviz.org/t/declaring-new-widgets-with-param-parameterized-and-use-decorators/7244/2):
>
> I don’t it’s good practice to define widgets like you would define params. Instead, you can define params like this: import panel as pn import param pn.extension() class MyWidget(param.Parameterized): button\_event = param.Event() value = param.Integer(default=0) def \_\_init\_\_(self, \*\*params): super().\_\_init\_\_(\*\*params) self.button = pn.widgets.Button.from\_param(self.param.button\_event) self.value\_pane = pn.widgets.IntInput.from\_param(self.param.value) …

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [July 16, 2024, 6:22pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/31 "2024-07-16T18:22:47Z")

</div>

I finally had a chance to update the PR [panel/examples/best\_practices.ipynb at 819c891d75a08bc52113f528bca2a24602e5ef0c · holoviz/panel · GitHub](https://github.com/holoviz/panel/blob/819c891d75a08bc52113f528bca2a24602e5ef0c/examples/best_practices.ipynb)

If you have any thoughts, happy to hear them here [Start best practices notebook by ahuang11 · Pull Request #6819 · holoviz/panel · GitHub](https://github.com/holoviz/panel/pull/6819)

---

<div class="post-metadata">

**Author:** ![ahuang11](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/ahuang11/32/4947_2.png) [@ahuang11](https://discourse.holoviz.org/u/ahuang11)\
**Post date:** [September 16, 2024, 10:45pm UTC](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789/32 "2024-09-16T22:45:03Z")

</div>

It is now live!

If you have additional opinions on what to be added, please create a PR to add it!  
[https://panel.holoviz.org/how\_to/best\_practices/index.html](https://panel.holoviz.org/how_to/best_practices/index.html)

[Previous page](https://discourse.holoviz.org/t/personal-opinions-about-best-practices-for-panel-holoviews/6789.md?page=1)
