Skip to content

Commit

Permalink
Clarified wording in best practices docs (#7290)
Browse files Browse the repository at this point in the history
Co-authored-by: Philipp Rudiger <[email protected]>
  • Loading branch information
jbednar and philippjfr authored Sep 18, 2024
1 parent 37c9ec6 commit c83c112
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 18 deletions.
14 changes: 7 additions & 7 deletions doc/how_to/best_practices/dev_experience.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ The best practices described on this page serve as a checklist of items to keep

### Good

Be sure to bind on `obj.param.{parameter}`, not just `{parameter}`.
Be sure to bind `obj.param.{parameter}` (the Parameter object), not just `{parameter}` (the current Parameter value).

```{pyodide}
def show_clicks(clicks):
Expand All @@ -35,7 +35,7 @@ pn.Row(button, clicks)

### Wrong

If only on `{parameter}`, it will not trigger an update on change.
Binding to `{parameter}` will bind to the single current value of the parameter, _not_ to the underlying object, and so it will not trigger an update on change.

```{pyodide}
def show_clicks(clicks):
Expand All @@ -50,7 +50,7 @@ pn.Row(button, clicks)

### Good

Instead of inheriting from `param.Parameterized`, using `pn.viewable.Viewer` allows direct invocation of the class, resembling a native Panel object.
`param.Parameterized` is a very general class that can be used separately from Panel for working with Parameters. But if you want a Parameterized class to use with Panel, it is usually appropriate to inherit from the Panel-specific class `pn.viewable.Viewer` instead, because `Viewer` allows direct invocation of the class, resembling a native Panel object.

For example, it's possible to use `ExampleApp().servable()` instead of `ExampleApp().view().servable()`.

Expand All @@ -70,7 +70,7 @@ ExampleApp().servable();

### Okay

This method works, but should be reserved for cases where there's no Panel output.
Inheriting from `param.Parameterized` also works, but should be reserved for cases where there's no Panel output.

```python
class ExampleApp(param.Parameterized):
Expand All @@ -90,7 +90,7 @@ ExampleApp().view().servable();

### Good

To translate multiple parameters into widgets, use `pn.Param`.
To translate multiple Parameters into widgets, use `pn.Param`.

```{pyodide}
class ExampleApp(pn.viewable.Viewer):
Expand Down Expand Up @@ -225,7 +225,7 @@ ExampleApp()

### Wrong

Widgets should not be used as parameters since all instances of the class will share the widget class:
Widgets should not be used as if they were Parameters, because then all instances of your new class will share a single set of instantiated widgets, confusing everyone:

```{pyodide}
class ExampleApp(pn.viewable.Viewer):
Expand Down Expand Up @@ -312,7 +312,7 @@ pn.Row(slider, output)

### Good

For functions that trigger side effects, i.e. do not return anything (or returns None), be sure to set `watch=True` on `pn.bind` or `pn.depends`.
For functions that trigger side effects, i.e. do not return anything (or return None), be sure to set `watch=True` on `pn.bind` or `pn.depends`.

```{pyodide}
def print_clicks(clicks):
Expand Down
21 changes: 10 additions & 11 deletions doc/how_to/best_practices/user_experience.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pn.Row(button, progress)

### Okay

The following shows setting parameters individually, which could be inefficient.
The following shows setting parameters individually, which could be inefficient and may temporarily leave the object in an inconsistent state.

```{pyodide}
def run(event):
Expand All @@ -69,7 +69,7 @@ pn.Row(button, progress)

### Good

To prevent sliders from triggering excessive callbacks, set `throttled=True` so that it only triggers once upon mouse-up.
When callbacks are expensive to run, you can prevent sliders from triggering too many callbacks, by setting `throttled=True`. When throttled, callbacks will be triggered only once, upon mouse-up.

```{pyodide}
pn.extension(throttled=True)
Expand All @@ -85,7 +85,7 @@ pn.Row(slider, output)

### Good

Alternatively, limit the scope by binding against `value_throttled` instead of `value`.
Alternatively, you can apply throttling only to the specific widgets with the most expensive callbacks, by binding to `value_throttled` instead of `value`.

```{pyodide}
def callback(value):
Expand All @@ -99,7 +99,7 @@ pn.Row(slider, output)

### Bad

If the operation is expensive, binding against `value` can be really slow.
Binding against `value` can be really slow for expensive callbacks.

```{pyodide}
def callback(value):
Expand All @@ -115,7 +115,7 @@ pn.Row(slider, output)

### Good

Its easy defer the execution of all bound and displayed functions with `pn.extension(defer_load=True)` (note this applies to served applications, not to interactive notebook environments):
It's easy to defer the execution of all bound and displayed functions with `pn.extension(defer_load=True)` (note this applies to served applications, not to interactive notebook environments):

```{pyodide}
pn.extension(defer_load=True, loading_indicator=True)
Expand Down Expand Up @@ -222,7 +222,7 @@ layout

### Good

Wrap the decorator `pn.cache` for automatic handling.
Wrap your callback with a `pn.cache` decorator so that values are automatically cached so that expensive computations are not repeated.

```{pyodide}
@pn.cache
Expand All @@ -237,7 +237,7 @@ pn.Row(slider, output)

### Okay

Or, manually handle the cache with `pn.state.cache`.
Or, manually handle the cache yourself with `pn.state.cache`.

```{pyodide}
def callback(value):
Expand All @@ -257,7 +257,7 @@ pn.Row(slider, output)

### Good

To prevent the plot from resetting to its original axes ranges when zoomed in, simply wrap `hv.DynamicMap`.
When you are working with HoloViews or hvPlot in Panel, you can prevent the plot from resetting to its original axes ranges when zoomed in by wrapping it with `hv.DynamicMap`.

```{pyodide}
import numpy as np
Expand Down Expand Up @@ -328,13 +328,12 @@ pn.Row(

### Good

Imagine Panel components as placeholders and use them as such rather than re-creating them on update.
Imagine Panel components as placeholders and use them as such, rather than re-creating them on update.

```{pyodide}
def randomize(event):
df_pane.object = pd.DataFrame(np.random.randn(10, 3), columns=list("ABC"))
button = pn.widgets.Button(name="Compute", on_click=randomize)
df_pane = pn.pane.DataFrame()
button.param.trigger("clicks") # initialize
Expand All @@ -344,7 +343,7 @@ pn.Column(button, df_pane)

### Okay

This instantiates the `pn.pane.DataFrame` on every click.
If your callback returns a Panel object rather than the underlying object being displayed, you'll end up instantiating the `pn.pane.DataFrame` on every click (which is typically slower and will often have distracting flickering).

```{pyodide}
def randomize(clicks):
Expand Down

0 comments on commit c83c112

Please sign in to comment.