Skip to content

Commit

Permalink
Docs: Interactivity, widgets and dashboards
Browse files Browse the repository at this point in the history
  • Loading branch information
georgestagg committed Jul 30, 2024
1 parent 62ca149 commit 4168850
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 102 deletions.
4 changes: 2 additions & 2 deletions docs/_quarto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ website:
contents:
- other/tables.qmd
- other/resources.qmd
- other/html.qmd
- other/python.qmd
- other/htmlwidgets.qmd
- other/jupyter.qmd
- other/slides.qmd
- section: Reference
contents:
Expand Down
110 changes: 110 additions & 0 deletions docs/interactive/dashboards.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
title: Dashboard Example
subtitle: Interactive Quarto Dashboards with WebAssembly computation
format: live-dashboard
pyodide:
packages:
- numpy
- scipy
- matplotlib
---

## Row

### {.sidebar}

```{ojs}
viewof aRange = Inputs.range([0, 180], {value: 0, step: 0.5, label: "angle"});
viewof sRange = Inputs.range([0, 50], {value: 10, step: 0.5, label: "sigma"});
viewof bRange = Inputs.range([0, 20], {value: 2.5, step: 0.2, label: "beta"});
viewof rRange = Inputs.range([0, 50], {value: 28, step: 0.5, label: "rho"});
viewof cmap = Inputs.select(
[
'viridis', 'plasma', 'inferno', 'magma', 'cividis',
'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn',
'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink',
'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia',
'hot', 'afmhot', 'gist_heat', 'copper'
],
{ value: 'viridis', label: "Color map" }
);
angle = debounce(viewof aRange);
sigma = debounce(viewof sRange);
beta = debounce(viewof bRange);
rho = debounce(viewof rRange);
// From @mbostock/debouncing-input
function debounce(input, delay = 500) {
return Generators.observe(notify => {
let timer = null;
let value;
function inputted() {
if (timer !== null) return;
notify(value = input.value);
timer = setTimeout(delayed, delay);
}
function delayed() {
timer = null;
if (value === input.value) return;
notify(value = input.value);
}
input.addEventListener("input", inputted), inputted();
return () => input.removeEventListener("input", inputted);
});
}
```

### Column

::: {.card height="100%" title="The Lorenz System"}

```{pyodide}
#| edit: false
#| echo: false
#| fig-width: 8
#| fig-height: 7
#| input:
#| - sigma
#| - beta
#| - rho
#| - angle
#| - cmap
# Based on ipywidgets/docs/source/examples/Lorenz Differential Equations.ipynb
import numpy as np
from scipy import integrate
from matplotlib import pyplot as plt
def solve_lorenz(N=10, angle=0.0, max_time=4.0, sigma=10.0, beta=8./3, rho=28.0, cmap = "viridis"):
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1], projection='3d')
ax.axis('off')
ax.set_xlim((-25, 25))
ax.set_ylim((-35, 35))
ax.set_zlim((5, 55))
def lorenz_deriv(x_y_z, t0, sigma=sigma, beta=beta, rho=rho):
x, y, z = x_y_z
return [sigma * (y - x), x * (rho - z) - y, x * y - beta * z]
np.random.seed(1)
x0 = -15 + 30 * np.random.random((N, 3))
t = np.linspace(0, max_time, int(250*max_time))
x_t = np.asarray([integrate.odeint(lorenz_deriv, x0i, t)
for x0i in x0])
colors = plt.get_cmap(cmap)(np.linspace(0, 1, N))
for i in range(N):
x, y, z = x_t[i,:,:].T
lines = ax.plot(x, y, z, '-', c=colors[i])
plt.setp(lines, linewidth=1)
ax.view_init(30, angle)
plt.show()
solve_lorenz(angle = angle, sigma = sigma, beta = beta, rho = rho, cmap = cmap)
```
:::
4 changes: 2 additions & 2 deletions docs/interactive/reactivity.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,11 @@ Notice how re-evaluating the code block reactively updates the value calculated
You might see an OJS error breifly appear as the page loads. This is normal, caused by the fact that the variables defined by the `quarto-live` cell do not exist until after the WebAssembly engine has loaded and executed the code block contents.
:::

## Interactive documents and dashboards
## Interactive documents

The above described OJS integration can be used to implement complex computational and statistical methods using R or Python code, executed under WebAssembly, which can then be invoked reactively with OJS.

This is a useful pattern for creating engaging documents and interactive dashboards using a serverless client-side rendering approach.
This is a useful pattern for creating engaging documents with a client-side rendering approach. See also this [Quarto dashboard example](dashboards.qmd).

::: {.callout-note}
Invoking exported R and Python functions from OJS is generally more efficient than re-evaluating a `quarto-live` code block, since the code does not need to be re-parsed each time it needs to run.
Expand Down
61 changes: 0 additions & 61 deletions docs/other/html.qmd

This file was deleted.

86 changes: 86 additions & 0 deletions docs/other/htmlwidgets.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
title: HTML Widgets
engine: knitr
format: live-html
toc: true
webr:
packages:
- rgl
- gt
- leaflet
---

{{< include ../_extensions/live/_knitr.qmd >}}

```{webr}
#| edit: false
#| output: false
library(htmltools)
library(rgl)
library(gt)
library(leaflet)
```

The `quarto-live` extension has support for displaying the output of R's popular [`htmltools`](https://rstudio.github.io/htmltools/) and [htmlWidgets](https://www.htmlwidgets.org/) packages, making rich HTML and JavaScript output possible with interactive code blocks.

## Example: `htmltools`

```{webr}
tags$div(
tags$h3("Hello from", tags$code("htmltools"), "!"),
tags$p(
"This is some HTML output from",
tags$a(
"htmltools",
href = "https://rstudio.github.io/htmltools/"
),
"."
),
tags$p(
"Below is a checkbox, feel free to",
tags$em("check"),
"it out!"
),
tags$input(type="checkbox")
)
```

## Example: `htmlwidgets`

### Leaflet

```{webr}
leaflet() |>
addTiles() |>
addMarkers(lng = 174.768, lat = -36.852, popup = "The birthplace of R")
```

### rgl

```{webr}
options(rgl.printRglwidget = TRUE)
theta <- seq(0, 6 * pi, len = 100)
xyz <- cbind(sin(theta), cos(theta), theta)
lineid <- plot3d(xyz,
type = "l", alpha = 1:0, lwd = 5, col = "blue"
)["data"]
browsable(
tagList(
rglwidget(
elementId = "example", width = 800, height = 400,
controllers = "player"
),
playwidget("example", ageControl(
births = theta, ages = c(0, 0, 1),
objids = lineid, alpha = c(0, 1, 0)
),
start = 1, stop = 6 * pi, step = 0.1,
rate = 6, elementId = "player"
)
)
)
```

::: {.callout-note}
At the moment `htmltools` cannot be used as reactive inputs for `quarto-live`'s [OJS integration](../interactive/reactivity.qmd). This is planned to be added in a future release of `quarto-live`.
:::
68 changes: 68 additions & 0 deletions docs/other/jupyter.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
title: Jupyter Widgets
format: live-html
toc: true
resources:
- "images"
pyodide:
packages:
- matplotlib
- ipywidgets
---

The `quarto-live` extension has support for displaying several types of `ipython` [rich output](https://ipython.readthedocs.io/en/stable/interactive/plotting.html#rich-outputs) and [Jupyter Widgets](https://ipywidgets.readthedocs.io/en/latest/) with interactive code blocks.

## Example: `ipython` rich output

```{pyodide}
from IPython.display import HTML
from IPython.display import Image
display(HTML("<h3>Hello from <code>ipython</code>!</h3>"))
display(HTML("<p>This is HTML output, and below is an image.</p>"))
Image(filename='images/python-logo.png')
```

## Example: Jupyter Widgets

```{pyodide}
import ipywidgets as widgets
out = widgets.Output(
layout={'border': '1px solid black', 'padding': '1em'}
)
out.append_display_data(
widgets.IntSlider(
value=7, min=0, max=10, step=1,
description='Slider:',
disabled=False,
)
)
out.append_display_data(
widgets.Text(
value="Hello",
description='Text:',
disabled=False
)
)
out.append_display_data(
widgets.Dropdown(
options=[('One', 1), ('Two', 2), ('Three', 3)],
value=2,
description='Number:',
)
)
out.append_display_data(
widgets.ColorPicker(
concise=False,
description='Color picker',
value='blue',
disabled=False
)
)
out
```

::: {.callout-note}
At the moment Jupyter widgets cannot be used as reactive inputs for `quarto-live`'s [OJS integration](../interactive/reactivity.qmd). This is planned to be added in a future release of `quarto-live`.
:::

37 changes: 0 additions & 37 deletions docs/other/python.qmd

This file was deleted.

0 comments on commit 4168850

Please sign in to comment.