Build-a-Dashboard Workshop
Duke University
Posit, PBC
2024-08-12
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). |
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()
```
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()
```
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()
```
Use the -P
command line option to vary the parameter:
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()
)
```
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
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.
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.
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
Please fill out the workshop survey at https://pos.it/conf-workshop-survey.
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/ |
Automated Reporting With Quarto: Beyond Copy And Paste - 2:40 PM - 4:00 PM PDT Columbia A/B
Making Decisions With Data - 2:40 PM - 4:00 PM PDT 300 | Columbia D
… and many more on Wednesday!