Skip to content

Commit

Permalink
Minor docs fixes (#4901)
Browse files Browse the repository at this point in the history
* Fixed typos and made minor clarifications

* Added stub Bokeh+Panel section
  • Loading branch information
jbednar committed May 19, 2023
1 parent 0586bae commit a8d3a76
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 11 deletions.
7 changes: 4 additions & 3 deletions doc/explanation/api/parameterized.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ The parameterized approach is a powerful way to encapsulate computation in self-
## Pros:

+ Declarative way of expressing parameters and dependencies between parameters and computation
+ The resulting code is not tied to any particular GUI framework and can be used in other contexts as well
+ The GUI code encodes less of the underlying domain-specific code, making it easier to update either the GUI or the underlying computation without introducing bugs. With the reactive API, the GUI code explicitly lists allowed parameter types ranges that must match what the underlying code does, while with the Declarative API the underlying code both declares and uses the Parameters, providing a single place to control and update that information, without having it duplicated at the GUI level.
+ Information about parameter types and allowed ranges is stored directly with the code that uses it, making it easier for programmers to reason about the core code and to detect issues with user-provided values.
+ Like the reactive API, the resulting core code is not tied to any particular GUI framework and can be used in other contexts as well
+ Compared to the reactive API, the core code itself can _also_ be updated and improved without necessarily needing any changes to the GUI code, because the GUI code rarely needs to encode detailed information about the core code.

## Cons:

- Requires writing classes
- Requires writing Python classes, which are not otherwise commonly used in data science
- Less explicit about widgets to use for each parameter; can be harder to customize behavior than if widgets are instantiated explicitly

## Explanation
Expand Down
4 changes: 2 additions & 2 deletions doc/explanation/api/reactive.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Panel's reactive programming API `pn.bind` allows a programmer to indicate that

## Cons:

+ Compared to the Declarative API approach, the resulting GUI code is tightly tied to the underlying domain-specific code, because it must declare valid types and ranges for widgets that must match what the underlying code accepts.
+ Compared to the Declarative API approach, the resulting GUI code encodes details about the underlying computation and thus must be updated whenever the underlying non-GUI code arguments or options change.

## Explanation

Expand Down Expand Up @@ -77,4 +77,4 @@ pn.Row(
)
```

This alternative way of specifying the same app lets you declare the dependency between a function argument and a widget (or *Parameter*) from the start, which can be clearer if you know the function will always and only be used in a GUI. Otherwise, the `pn.bind` version is greatly **preferred**, because it allows you to keep the Panel-specific code separate (even in a different Python module or file) from the underlying analysis and plotting code so that you can invoke the underlying code whether or not you have installed Panel.
This alternative way of specifying the same app lets you declare the dependency between a function argument and a widget (or *Parameter*) from the start, which can be clearer if you know the function will always and only be used in a GUI. Otherwise, the `pn.bind` version is greatly preferred, because it allows you to keep the Panel-specific code separate (even in a different Python module or file) from the underlying analysis and plotting code so that you can invoke the underlying code whether or not you have installed Panel.
2 changes: 1 addition & 1 deletion doc/explanation/components/components_custom.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

When building custom applications and dashboards it is frequently useful to extend Panel with custom components to fit a specialized need. Panel provides multiple mechanisms to extend and compose different components or even add entirely new components.

This Background page will focus on the building of entirely new components. Making full new components can be straightforward in the simplest cases, but it does requires knowledge of web technologies like HTML, CSS, and JavaScript. Alternatively, to learn how to compose existing Panel components into an easily reusable unit that behaves like a native Panel component, see the [How-to > Combine Existing Components](../../how_to/custom_components/custom_viewer.md) page.
This Background page will focus on the building of entirely new components. Making full new components can be straightforward in the simplest cases, but it does require knowledge of web technologies like HTML, CSS, and JavaScript. Alternatively, to learn how to compose existing Panel components into an easily reusable unit that behaves like a native Panel component, see the [How-to > Combine Existing Components](../../how_to/custom_components/custom_viewer.md) page.

## ReactiveHTML components

Expand Down
4 changes: 3 additions & 1 deletion doc/explanation/dependencies/bokeh.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Panel and Bokeh

WIP
Bokeh is a well-established library for building JavaScript-based plots and applications in Python. Panel is not tied to Bokeh's plotting support in any way, but it does build on infrastructure provided by Bokeh, specifically Bokeh's model base classes, layouts, widgets, and (optionally) its server. Using Bokeh components in the higher-level Panel library lets you make use of a solid, well supported low-level toolkit to build apps and dashboards, while letting you include plots from any supported library.

Conversely, what Panel adds on top of Bokeh is full bidirectional communication between Python and JavaScript both in a Jupyter session (classic notebook or Jupyter Lab) and in a standalone Bokeh server, making it trivial to move code between Jupyter and server contexts. It then uses this two-way "comms" support to provide reactive widgets, containers, and views that make it simple to put together widget-controlled objects accessible from either Python or JavaScript. Finally, Panel adds a large set of wrappers for common plot and image types so that they can easily be laid out into small apps or full dashboards.
8 changes: 4 additions & 4 deletions doc/getting_started/core_concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ text.value # 👈 the "value" Parameter of this widget reflects the current valu
text.param.value # 👈 can be used as a reference to the live value
```

We will dive into this more deeply later, for now just remember that parameters (whether associated with widgets or not) allow you to pass around a reference to a value that automatically updates if the original value changes.
We will dive into this more deeply later, for now just remember that parameter objects (whether associated with widgets or not) allow you to pass around a reference to a value that automatically updates if the original value changes.

## Display and rendering

Expand Down Expand Up @@ -218,7 +218,7 @@ df_pane.servable()
:::{admonition} Note
:class: info

In the notebook the `.servable()` method is effectively a no-op. This means you can add it the components you want to add to the rendered app but also see it rendered inline. This makes it possible to build components sequentially in a notebook while simultaneously building an application to be served. If you want to mark someething servable but do _not_ want it rendered inline, just put a semicolon (';') after it to tell Jupyter not to render it even if it is the last item in the cell.
In the notebook the `.servable()` method is effectively a no-op. This means you can add it the components you want to add to the rendered app but also see it rendered inline. This makes it possible to build components sequentially in a notebook while simultaneously building an application to be served. If you want to mark something servable but do _not_ want it rendered inline, just put a semicolon (';') after it to tell Jupyter not to render it even if it is the last item in the cell.
:::

## Widgets
Expand All @@ -236,12 +236,12 @@ def square(x):
pn.Row(pn.bind(square, x))
```

The `pn.bind` function lets us bind widget or a *Parameter* **object** to a function that returns an item to be displayed. Once bound, the function can be added to a layout or rendered directly using `pn.panel` and `.servable()`. In this way you can express reactivity between widgets and output very easily. Even better, if you use a Panel-aware library like hvPlot, you often don't even need to write and bind a function explicitly, as hvPlot's [.interactive](https://hvplot.holoviz.org/user_guide/Interactive.html) DataFrames already create reactive pipelines by accepting widgets and parameters for most arguments and options.
The `pn.bind` function lets us bind a widget or a *Parameter* **object** to a function that returns an item to be displayed. Once bound, the function can be added to a layout or rendered directly using `pn.panel` and `.servable()`. In this way you can express reactivity between widgets and output very easily. Even better, if you use a Panel-aware library like hvPlot, you often don't even need to write and bind a function explicitly, as hvPlot's [.interactive](https://hvplot.holoviz.org/user_guide/Interactive.html) DataFrames already create reactive pipelines by accepting widgets and parameters for most arguments and options.

:::{admonition} Reminder
:class: info

Remember how we talked about the difference between a *Parameter* **value** and a *Parameter* **object**. In the previous example the widget itself is effectively an alias for the *Parameter* object, i.e. the binding operation is exactly equivalent to `pn.bind(square, x.param.value)`. This is true for all widgets: the widget object is treated as an alias for the widget's `value` *Parameter*. So you can generally either pass in the widget (as a convenient shorthand) or the underlying parameter object.
Remember how we talked about the difference between a *Parameter* **value** and a *Parameter* **object**. In the previous example the widget itself is effectively an alias for the *Parameter* object, i.e. the binding operation is exactly equivalent to `pn.bind(square, x.param.value)`. This is true for all widgets: the widget object is treated as an alias for the widget's `value` *Parameter* object. So you can generally either pass in the widget (as a convenient shorthand) or the underlying *Parameter* object.
:::

The binding approach above works, but it is quite heavy handed. Whenever the slider value changes, Panel will re-create a whole new Pane and re-render the output. If we want more fine-grained control we can instead explicitly instantiate a `Markdown` pane and pass it bound functions and *Parameters* by reference:
Expand Down

0 comments on commit a8d3a76

Please sign in to comment.