Parameters, interactivity,
and deployment

Build-a-Dashboard Workshop

Dr. Mine Çetinkaya-Rundel

Duke University

Posit, PBC

2024-08-12

Deployment

Dashboard deployment

Dashboards are typically just static HTML pages so can be deployed to any web server or web host.

Static Rendered a single time (e.g. when underlying data won’t ever change)
Scheduled Rendered on a schedule (e.g. via cron job) to accommodate changing data.
Parameterized Variations of static or scheduled dashboards based on parameters.
Interactive Fully interactive dashboard using Shiny (requires a server for deployment).

Parameters

Parameters

dashboard-r.qmd
---
title: "Parameters"
format: 
  dashboard:
    logo: images/beetle.png
params:
  class: "compact"
---

```{r}
library(ggplot2)
library(dplyr)
mpg <- mpg |>
  filter(class == params$class)
```

## Value boxes {height="25%"}

::: {.valuebox icon="car-front-fill" color="info"}
Class

`{r} params$class`
:::

```{r}
#| label: calculate-values
lowest_mileage_cty <- mpg |>
  filter(cty == min(cty)) |>
  distinct(cty) |>
  pull(cty)

highest_mileage_cty <- mpg |>
  filter(cty == max(cty)) |>
  distinct(cty) |>
  pull(cty)
  
rounded_mean_city_mileage <- mpg |>
  summarize(round(mean(cty), 2)) |>
  pull()
```

```{r}
#| content: valuebox
#| title: "Least efficient"
#| icon: fuel-pump-fill
#| color: danger
list(
  value = paste(lowest_mileage_cty, "mpg")
)
```

```{r}
#| content: valuebox
#| title: "Most efficient"
list(
  icon = "fuel-pump",
  color = "success",
  value = paste(highest_mileage_cty, "mpg")
)
```

::: {.valuebox icon="fuel-pump" color="secondary"}
Average city mileage

`{r} rounded_mean_city_mileage` mpg
:::

## Plots {height="75%"}

```{r}
#| title: Highway vs. city mileage
ggplot(mpg, aes(x = cty, y = hwy)) +
  geom_point()
```

```{r}
#| title: Drive types
ggplot(mpg, aes(x = drv)) +
  geom_bar()
```

Parameters

dashboard-py.qmd
---
title: "Parameters"
format: 
  dashboard:
    logo: images/beetle.png
params:
  class: "compact"
---

```{r}
library(ggplot2)
library(dplyr)
mpg <- mpg |>
  filter(class == params$class)
```

## Value boxes {height="25%"}

::: {.valuebox icon="car-front-fill" color="info"}
Class

`{r} params$class`
:::

```{r}
#| label: calculate-values
lowest_mileage_cty <- mpg |>
  filter(cty == min(cty)) |>
  distinct(cty) |>
  pull(cty)

highest_mileage_cty <- mpg |>
  filter(cty == max(cty)) |>
  distinct(cty) |>
  pull(cty)
  
rounded_mean_city_mileage <- mpg |>
  summarize(round(mean(cty), 2)) |>
  pull()
```

```{r}
#| content: valuebox
#| title: "Least efficient"
#| icon: fuel-pump-fill
#| color: danger
list(
  value = paste(lowest_mileage_cty, "mpg")
)
```

```{r}
#| content: valuebox
#| title: "Most efficient"
list(
  icon = "fuel-pump",
  color = "success",
  value = paste(highest_mileage_cty, "mpg")
)
```

::: {.valuebox icon="fuel-pump" color="secondary"}
Average city mileage

`{r} rounded_mean_city_mileage` mpg
:::

## Plots {height="75%"}

```{r}
#| title: Highway vs. city mileage
ggplot(mpg, aes(x = cty, y = hwy)) +
  geom_point()
```

```{r}
#| title: Drive types
ggplot(mpg, aes(x = drv)) +
  geom_bar()
```

Parameters

dashboard-py.qmd
---
title: "Parameters"
format: 
  dashboard:
    logo: images/beetle.png
params:
  class: "midsize"
---

```{r}
library(ggplot2)
library(dplyr)
mpg <- mpg |>
  filter(class == params$class)
```

## Value boxes {height="25%"}

::: {.valuebox icon="car-front-fill" color="info"}
Class

`{r} params$class`
:::

```{r}
#| label: calculate-values
lowest_mileage_cty <- mpg |>
  filter(cty == min(cty)) |>
  distinct(cty) |>
  pull(cty)

highest_mileage_cty <- mpg |>
  filter(cty == max(cty)) |>
  distinct(cty) |>
  pull(cty)
  
rounded_mean_city_mileage <- mpg |>
  summarize(round(mean(cty), 2)) |>
  pull()
```

```{r}
#| content: valuebox
#| title: "Least efficient"
#| icon: fuel-pump-fill
#| color: danger
list(
  value = paste(lowest_mileage_cty, "mpg")
)
```

```{r}
#| content: valuebox
#| title: "Most efficient"
list(
  icon = "fuel-pump",
  color = "success",
  value = paste(highest_mileage_cty, "mpg")
)
```

::: {.valuebox icon="fuel-pump" color="secondary"}
Average city mileage

`{r} rounded_mean_city_mileage` mpg
:::

## Plots {height="75%"}

```{r}
#| title: Highway vs. city mileage
ggplot(mpg, aes(x = cty, y = hwy)) +
  geom_point()
```

```{r}
#| title: Drive types
ggplot(mpg, aes(x = drv)) +
  geom_bar()
```

Rendering with parameter

Use the -P command line option to vary the parameter:

quarto render dashboard-r.qmd -P class:"suv"

Parameters

dashboard-py.qmd
---
title: "Valueboxes"
format: dashboard
---

```{python}
from plotnine import ggplot, aes, geom_point, geom_bar
from plotnine.data import mpg
```

```{python}
#| tags: [parameters]

car_class = "compact"
```

```{python}
#| label: filter-for-class
filtered_mpg = mpg[mpg['class'] == car_class]
filtered_mpg.reset_index(drop=True, inplace=True)
```

## Value boxes {height="25%"}

::: {.valuebox icon="car-front-fill" color="info"}
Class

`{python} car_class`
:::

```{python}
#| label: calculate-values
lowest_mileage_index = filtered_mpg['cty'].idxmin()
lowest_mileage_car = filtered_mpg.iloc[lowest_mileage_index]
lowest_mileage_cty = filtered_mpg.loc[lowest_mileage_index, 'cty']

highest_mileage_index = filtered_mpg['cty'].idxmax()
highest_mileage_car = filtered_mpg.iloc[highest_mileage_index]
highest_mileage_cty = filtered_mpg.loc[highest_mileage_index, 'cty']

mean_city_mileage = filtered_mpg['cty'].mean()
rounded_mean_city_mileage = round(mean_city_mileage, 2)
```

```{python}
#| content: valuebox
#| title: "Least efficient"
#| icon: fuel-pump-fill
#| color: danger
dict(
  value = str(f"{lowest_mileage_cty} mpg")
)
```

```{python}
#| content: valuebox
#| title: "Most efficient"
dict(
  icon = "fuel-pump",
  color = "success",
  value = str(f"{highest_mileage_cty} mpg")
)
```

::: {.valuebox icon="fuel-pump" color="secondary"}
Average city mileage

`{python} str(rounded_mean_city_mileage)` mpg
:::

## Plots {height="75%"}

```{python}
#| title: Highway vs. city mileage
(
    ggplot(filtered_mpg, aes(x = "cty", y = "hwy"))
    + geom_point()
)
```

```{python}
#| title: Drive types
(
    ggplot(filtered_mpg, aes(x = "drv"))
    + geom_bar()
)
```

Interactivity

Interactivity with Shiny

  • The Shiny package (for R and for Python) provides an easy way to build web applications with R.

  • Quarto dashboards can include embedded Shiny components (e.g., a plot with sliders that control its inputs) to add interactivity.

  • Ladder of complexity/customization: Quarto dashboard > Quarto dashboard with Shiny components > Shiny dashboard

Deployment of interactive dashboards

Server

On-Prem

Serverless

Using Pyodide

[Example]

Using ShinyLive

Other interactivity

  • Observable JS for client-side interactivity using the Observable dialect of JavaScript.

  • Jupyter Widgets or htmlwidgets for client-side interactivity based on standard Python and R JavaScript widget frameworks.

Your turn

Start

  • Option 1 - Cloud: Go to Posit Cloud for the workshop, open project titled 4 - Parameters, interactivity, and deployment.

  • Option 2 - Local: Clone the GitHub repo posit-conf-2024/olympicdash (https://github.com/posit-conf-2024/olympicdash) and work on olympicdash-r-4.qmd.

Python - Local: Clone the GitHub repo posit-conf-2024/olympicdash (https://github.com/posit-conf-2024/olympicdash) and work on olympicdash-py-4.qmd.

Goal

Deploy your latest dashboard to QuartoPub.

Stretch goal: Add parameter and/or interactivity to your dashboard for narrowing down to or picking a year.

10:00

Wrap up

Time for Q&A!

Q&A after workshop

https://github.com/quarto-dev/quarto-cli/discussions

Feedback

Please fill out the workshop survey at https://pos.it/conf-workshop-survey.

Learning More

About Quarto https://quarto.org/
Quarto Dashboards https://quarto.org/docs/dashboards/
Shiny for R https://shiny.posit.co/r/
Shiny for Python https://shiny.posit.co/r/getstarted/shiny-basics/lesson1/index.html/

Quarto at posit::conf(2024) - Tuesday

… and many more on Wednesday!

Thank you!

https://pos.it/conf-workshop-survey