Background

Row

Dashboards

  • Browser-based dashboards and interactive visualizations are becoming increasingly common and accessible
  • With a relatively shallow learning-curve, an R user can use the flexdashboard, plotly and crosstalk packages to generate interactive dashboards for exploring data and models
  • The concept is demonstrated on the Skeleton page using a simple data-set and linear regression; this can be extended to more complex cases

Note: this document is meant to be a high-level overview of constructing a dashboard using flexdashboard, plotly and crosstalk. This is not a definitive guide to each package nor is this the only approach to constructing a dashboard using R. Please refer to the links provided for more details on how to use the packages highlighted here.

Row

flexdashboard

  • Uses rmarkdown to render a group of related figures, tables and text into a dashboard
  • Layout is flexible and the components automatically re-size to fill the browser and adapt to mobile displays
  • Supports a wide range of components, including base plot, ggplots, gauges, tables and htmlwidgets such as plotly, leaflet and DT
  • Optionally use shiny or crosstalk to bolster interactivity

Source: https://rmarkdown.rstudio.com/flexdashboard/

plotly

  • A graphing package that works like other R plots except it produces interactive visualizations
  • The package allows the user to create interactive web graphics from ggplot2 graphs
  • Also provides a more ‘direct’ link to the core plotly.js JavaScript library using syntax inspired by the grammar of graphics

Source: https://plotly-r.com

crosstalk

  • Enables cross-widget interactions by linking brushing and/or filtering across multiple views
  • i.e. Interactions with one plot can affect change in another plot
  • Supports a wide range of htmlwidgets, such as plotly, leaflet and DT

Source: https://rstudio.github.io/crosstalk/

Skeleton

Column

Code

---
title: "flexdashboard + plotly + crosstalk"
output: flexdashboard::flex_dashboard
---

```{r setup, include=FALSE}
library(plotly)
library(crosstalk)
lw <- read.csv("length-weight_data.csv")
shared_lw <- SharedData$new(lw)
```

Column {.tabset}
-------------------------------------

### Length-Weight relationship

```{r}
plot_ly(data = shared_lw) %>% 
    add_markers(x = ~length, y = ~weight, name = "Observed") %>% 
    add_lines(x = ~length, y = ~exp(fit), name = "Predicted")
```

### Residuals vs. fitted values

```{r}
plot_ly(data = shared_lw) %>% 
    add_markers(x = ~fit, y = ~res)
```

This will generate a simple flexdashboard with two interactive figures (duplicated to the right)

Quick start

1. Download code and data

2. Open skeleton.Rmd in Rstudio

3. Install packages: install.packages(c("flexdashboard", "plotly", "crosstalk"))

4. Knit file by typing Ctrl+Shift+K or use the button

Details

This skeleton is a verbatim copy of an R markdown file (`<a href="data:text/x-markdown;base64,LS0tDQp0aXRsZTogImZsZXhkYXNoYm9hcmQgKyBwbG90bHkgKyBjcm9zc3RhbGsiDQpvdXRwdXQ6IGZsZXhkYXNoYm9hcmQ6OmZsZXhfZGFzaGJvYXJkDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoY3Jvc3N0YWxrKQ0KbHcgPC0gcmVhZC5jc3YoImxlbmd0aC13ZWlnaHRfZGF0YS5jc3YiKQ0Kc2hhcmVkX2x3IDwtIFNoYXJlZERhdGEkbmV3KGx3KQ0KYGBgDQoNCkNvbHVtbiB7LnRhYnNldH0NCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMjIExlbmd0aC1XZWlnaHQgcmVsYXRpb25zaGlwDQoNCmBgYHtyfQ0KcGxvdF9seShkYXRhID0gc2hhcmVkX2x3KSAlPiUgDQogICAgYWRkX21hcmtlcnMoeCA9IH5sZW5ndGgsIHkgPSB+d2VpZ2h0LCBuYW1lID0gIk9ic2VydmVkIikgJT4lIA0KICAgIGFkZF9saW5lcyh4ID0gfmxlbmd0aCwgeSA9IH5leHAoZml0KSwgbmFtZSA9ICJQcmVkaWN0ZWQiKQ0KYGBgDQoNCiMjIyBSZXNpZHVhbHMgdnMuIGZpdHRlZCB2YWx1ZXMNCg0KYGBge3J9DQpwbG90X2x5KGRhdGEgPSBzaGFyZWRfbHcpICU+JSANCiAgICBhZGRfbWFya2Vycyh4ID0gfmZpdCwgeSA9IH5yZXMpDQpgYGANCg0K" download="skeleton.Rmd">skeleton.Rmd</a>`{=html}) set-up to produce a simple flexdashboard with interactive plotly visuals connected by crosstalk. Like most R markdown files, it includes three types of content:

  1. A YAML header surrounded by ----
  2. Text following markdown formatting
  3. R code chunks surrounded by ```

The YAML header includes the metadata for the file, such as the document title and output format:

---
title: "flexdashboard + plotly + crosstalk"
output: flexdashboard::flex_dashboard
---

While only a title and format was specified in the skeleton, many other options are available (e.g. author, date).

The next section is a chunk of R code:

```{r setup, include=FALSE} 
library(plotly)
library(crosstalk)
lw <- read.csv("length-weight_data.csv")
shared_lw <- SharedData$new(lw)
```

This is where the plotly and crosstalk packages are loaded along with some sample data (`<a href="data:text/csv;base64,InJlY29yZCIsInllYXIiLCJtb250aCIsImRheSIsImxlbmd0aCIsIndlaWdodCIsImZpdCIsInJlcyINCjEsMTk4MCw1LDIyLDQxLDU4MCw2LjM5OSwtMC4wMzYNCjIsMTk4MCw1LDIyLDY1LDIyMTAsNy44NTEsLTAuMTUNCjMsMTk4MCw1LDI0LDIwLDUwLDQuMTM5LC0wLjIyNg0KNCwxOTgwLDExLDIzLDM4LDYzMCw2LjE2LDAuMjg2DQo1LDE5ODEsNCw3LDgxLDUyMTAsOC41NDQsMC4wMTQNCjYsMTk4MSwxMSwyMSw4NSw2ODAwLDguNjk2LDAuMTI5DQo3LDE5ODIsMywxNCw0OCwxMDMwLDYuODk2LDAuMDQxDQo4LDE5ODIsMywyMyw0Miw2MzAsNi40NzUsLTAuMDMNCjksMTk4Miw1LDcsNTQsMTQ1MCw3LjI2NywwLjAxMg0KMTAsMTk4MiwxMSw5LDkwLDY4ODAsOC44NzYsLTAuMDQNCjExLDE5ODIsMTEsMjIsOTIsNzYzMCw4Ljk0NSwtMC4wMDUNCjEyLDE5ODMsMywxOSw4Niw1NDEwLDguNzMzLC0wLjEzNw0KMTMsMTk4MywzLDI1LDcxLDM4MTAsOC4xMjksMC4xMTYNCjE0LDE5ODMsNywxMiwxMjQsMTY4MDAsOS44ODUsLTAuMTU2DQoxNSwxOTgzLDcsMjcsNTMsMTI0MCw3LjIwOCwtMC4wODUNCjE2LDE5ODMsNywyNyw0NSw4NDAsNi42OTMsMC4wNDENCjE3LDE5ODMsOCwxLDk2LDcyODAsOS4wNzksLTAuMTg2DQoxOCwxOTgzLDEwLDI1LDIwLDYwLDQuMTM5LC0wLjA0NA0KMTksMTk4MywxMSw1LDM0LDQwMCw1LjgxLDAuMTgyDQoyMCwxOTgzLDEyLDMsMjMsMTAwLDQuNTc5LDAuMDI2DQoyMSwxOTg0LDUsMTksMTAzLDEwMzMwLDkuMzAxLC0wLjA1OA0KMjIsMTk4NCw4LDEzLDg1LDQ1NTAsOC42OTYsLTAuMjczDQoyMywxOTg0LDgsMjAsOTcsOTU4MCw5LjExMiwwLjA1Ng0KMjQsMTk4NCwxMSwyNiw4OCw1OTcwLDguODA1LC0wLjExMQ0KMjUsMTk4NSwxLDE2LDM0LDM1MCw1LjgxLDAuMDQ4DQoyNiwxOTg1LDMsMjEsNzEsMzMwMCw4LjEyOSwtMC4wMjcNCjI3LDE5ODUsMywyMyw0Nyw4MDAsNi44MywtMC4xNDUNCjI4LDE5ODUsMywyMywzOCw0MzAsNi4xNiwtMC4wOTYNCjI5LDE5ODUsMywyMyw1OCwxODAwLDcuNDkyLDAuMDA0DQozMCwxOTg1LDgsMjAsNTUsMTUzMCw3LjMyNSwwLjAwOA0KMzEsMTk4NSwxMCwyNSw0OCwxMDYwLDYuODk2LDAuMDcNCjMyLDE5ODUsMTAsMjYsNTEsMTM1MCw3LjA4NywwLjEyMQ0KMzMsMTk4NSwxMCwyNiw0OSwxMTEwLDYuOTYxLDAuMDUxDQozNCwxOTg1LDEwLDI5LDQwLDYyMCw2LjMyMiwwLjEwOA0KMzUsMTk4NSwxMCwzMCwxMDcsMTEzOTAsOS40MjEsLTAuMDgNCjM2LDE5ODYsMSwxOCw3OSw0NzUwLDguNDY1LDAuMDAxDQozNywxOTg2LDEsMTgsNTksMTg3MCw3LjU0NiwtMC4wMTINCjM4LDE5ODYsMiwxMiwzMywyODAsNS43MTYsLTAuMDgxDQozOSwxOTg2LDIsMTYsNzMsMzQzMCw4LjIxNiwtMC4wNzYNCjQwLDE5ODYsOCwyNCwzNywzNzAsNi4wNzYsLTAuMTYzDQo0MSwxOTg2LDgsMjQsMzcsMzgwLDYuMDc2LC0wLjEzNg0KNDIsMTk4NiwxMSw1LDYzLDIyMTAsNy43NTIsLTAuMDUyDQo0MywxOTg2LDExLDE3LDc1LDM5NDAsOC4zMDIsLTAuMDIzDQo0NCwxOTg2LDExLDI5LDMzLDI4MCw1LjcxNiwtMC4wODENCjQ1LDE5ODcsMiwxMiw1NSwxNTYwLDcuMzI1LDAuMDI4DQo0NiwxOTg3LDYsMjAsNTYsMTM4MCw3LjM4MSwtMC4xNTINCjQ3LDE5ODcsNiwyMCwyMyw5MCw0LjU3OSwtMC4wNzkNCjQ4LDE5ODcsOCwzLDkyLDY2MDAsOC45NDUsLTAuMTUNCjQ5LDE5ODcsOCw1LDMyLDI4MCw1LjYxOSwwLjAxNg0KNTAsMTk4Nyw4LDUsNjYsMjcyMCw3Ljg5OSwwLjAwOQ0KNTEsMTk4NywxMCwyMCwzNyw0MDAsNi4wNzYsLTAuMDg1DQo1MiwxOTg3LDExLDEsNjEsMjA5MCw3LjY1MSwtMC4wMDYNCjUzLDE5ODcsMTEsMzAsMzYsNDUwLDUuOTksMC4xMTkNCjU0LDE5ODgsMiwxNiw0Miw2NDAsNi40NzUsLTAuMDE0DQo1NSwxOTg4LDIsMjAsNzEsMjkxMCw4LjEyOSwtMC4xNTMNCjU2LDE5ODgsMTAsMjcsNDUsNzIwLDYuNjkzLC0wLjExMw0KNTcsMTk4OCwxMCwyNyw2NSwyMjAwLDcuODUxLC0wLjE1NQ0KNTgsMTk4OCwxMSwxLDEwNiwxMzA1MCw5LjM5MSwwLjA4NQ0KNTksMTk4OCwxMSw2LDcwLDMyMDAsOC4wODQsLTAuMDEzDQo2MCwxOTg4LDExLDcsMzAsMjUwLDUuNDE2LDAuMTA2DQo2MSwxOTg4LDExLDIxLDQzLDc4MCw2LjU0OSwwLjExDQo2MiwxOTg4LDExLDI1LDQ0LDg2MCw2LjYyMiwwLjEzNQ0KNjMsMTk4OCwxMiwzLDg4LDY3MzAsOC44MDUsMC4wMDkNCjY0LDE5ODksMiwyMiw0Miw2MTAsNi40NzUsLTAuMDYyDQo2NSwxOTg5LDExLDIsNDAsNTYwLDYuMzIyLDAuMDA2DQo2NiwxOTg5LDExLDMsNjksMzY5MCw4LjAzOSwwLjE3NA0KNjcsMTk4OSwxMSwxMiw2NSwzMTgwLDcuODUxLDAuMjE0DQo2OCwxOTg5LDExLDE1LDI5LDIwMCw1LjMwOSwtMC4wMQ0KNjksMTk4OSwxMSwyNiwxNyw0MCwzLjYyNywwLjA2Mg0KNzAsMTk4OSwxMiw3LDQzLDYzMCw2LjU0OSwtMC4xMDQNCjcxLDE5ODksMTIsOSwyNywxODAsNS4wODQsMC4xMDkNCjcyLDE5OTAsMiwxMSw0Myw2NDAsNi41NDksLTAuMDg4DQo3MywxOTkwLDIsMTksNjYsMjM1MCw3Ljg5OSwtMC4xMzcNCjc0LDE5OTAsMyw0LDUzLDEyNTAsNy4yMDgsLTAuMDc3DQo3NSwxOTkwLDUsMTksNzgsNDQ4MCw4LjQyNSwtMC4wMTgNCjc2LDE5OTAsNSwxOSwyOCwxNjAsNS4xOTgsLTAuMTIzDQo3NywxOTkwLDUsMjQsNzcsNDgzMCw4LjM4NSwwLjA5OA0KNzgsMTk5MCw1LDI2LDY4LDMxMDAsNy45OTMsMC4wNDYNCjc5LDE5OTAsNSwyOCwzMywzMDAsNS43MTYsLTAuMDEyDQo4MCwxOTkwLDYsMiw3Niw0MzIwLDguMzQzLDAuMDI4DQo4MSwxOTkwLDgsMTAsMzAsMjIwLDUuNDE2LC0wLjAyMg0KODIsMTk5MCwxMCwxOSw0NSw3ODAsNi42OTMsLTAuMDMzDQo4MywxOTkwLDExLDcsNTYsMTU4MCw3LjM4MSwtMC4wMTYNCjg0LDE5OTAsMTEsMTEsMjksMjEwLDUuMzA5LDAuMDM4DQo4NSwxOTkwLDExLDE3LDM1LDM4MCw1LjkwMSwwLjAzOQ0KODYsMTk5MCwxMSwxNywyNywxNzAsNS4wODQsMC4wNTINCjg3LDE5OTAsMTEsMjMsNzAsMzc5MCw4LjA4NCwwLjE1Ng0KODgsMTk5MCwxMSwyNSwxOCw0MCwzLjgwNywtMC4xMTgNCjg5LDE5OTAsMTEsMjUsNjksMjczMCw4LjAzOSwtMC4xMjcNCjkwLDE5OTAsMTEsMjgsMjksMjEwLDUuMzA5LDAuMDM4DQo5MSwxOTkwLDExLDI5LDI3LDE3MCw1LjA4NCwwLjA1Mg0KOTIsMTk5MCwxMSwyOSw0MSw2MTAsNi4zOTksMC4wMTQNCjkzLDE5OTAsMTEsMzAsNTUsMTY4MCw3LjMyNSwwLjEwMg0KOTQsMTk5MCwxMiwxLDcyLDM5MzAsOC4xNzMsMC4xMDMNCjk1LDE5OTAsMTIsNyw0Nyw5NzAsNi44MywwLjA0OA0KOTYsMTk5MCwxMiw3LDQzLDc3MCw2LjU0OSwwLjA5Nw0KOTcsMTk5MSwyLDgsMzIsMjcwLDUuNjE5LC0wLjAyDQo5OCwxOTkxLDIsMjIsNzAsMjczMCw4LjA4NCwtMC4xNzINCjk5LDE5OTEsMiwyMiw2NiwyNDcwLDcuODk5LC0wLjA4Nw0KMTAwLDE5OTEsMywxNiw0Miw1ODAsNi40NzUsLTAuMTEyDQoxMDEsMTk5MSwzLDE2LDQ3LDkwMCw2LjgzLC0wLjAyNw0KMTAyLDE5OTEsMywyNSw0Miw1NzAsNi40NzUsLTAuMTMNCjEwMywxOTkxLDMsMjUsNzIsMzEwMCw4LjE3MywtMC4xMzQNCjEwNCwxOTkxLDMsMjUsNDEsNTIwLDYuMzk5LC0wLjE0Ng0KMTA1LDE5OTEsMywyNSwzNyw0NDAsNi4wNzYsMC4wMTENCjEwNiwxOTkxLDUsMjAsMTksNTAsMy45NzcsLTAuMDY1DQoxMDcsMTk5MSw1LDIyLDM2LDM5MCw1Ljk5LC0wLjAyNA0KMTA4LDE5OTEsNSwyNCw1MSwxMDUwLDcuMDg3LC0wLjEzDQoxMDksMTk5MSw4LDYsMzQsMzMwLDUuODEsLTAuMDExDQoxMTAsMTk5MSwxMSwxMSw0Miw3NjAsNi40NzUsMC4xNTgNCjExMSwxOTkxLDExLDEyLDQxLDU5MCw2LjM5OSwtMC4wMTkNCjExMiwxOTkxLDExLDE2LDI2LDEzMCw0Ljk2NSwtMC4wOTcNCjExMywxOTkxLDExLDE2LDQ1LDY4MCw2LjY5MywtMC4xNzENCjExNCwxOTkxLDExLDE4LDQ5LDExMDAsNi45NjEsMC4wNDINCjExNSwxOTkxLDExLDE4LDQ0LDc5MCw2LjYyMiwwLjA1DQoxMTYsMTk5MSwxMSwyMCw0OSwxMDgwLDYuOTYxLDAuMDI0DQoxMTcsMTk5MSwxMSwyNiw0NSw4MjAsNi42OTMsMC4wMTcNCjExOCwxOTkxLDExLDI4LDQyLDYwMCw2LjQ3NSwtMC4wNzgNCjExOSwxOTkxLDEyLDExLDQ1LDc5MCw2LjY5MywtMC4wMjENCjEyMCwxOTkxLDEyLDEzLDU4LDE4NDAsNy40OTIsMC4wMjYNCjEyMSwxOTkyLDMsMSw1OCwxNjUwLDcuNDkyLC0wLjA4Mw0KMTIyLDE5OTIsNCwxNSwzNyw0MjAsNi4wNzYsLTAuMDM2DQoxMjMsMTk5Miw0LDIzLDM1LDM1MCw1LjkwMSwtMC4wNDMNCjEyNCwxOTkyLDUsMzEsNTIsMTE1MCw3LjE0OCwtMC4xMDENCjEyNSwxOTkyLDExLDcsNDUsOTcwLDYuNjkzLDAuMTg1DQoxMjYsMTk5MiwxMSw5LDQ5LDEyMjAsNi45NjEsMC4xNDYNCjEyNywxOTkyLDExLDEwLDYyLDI4NjAsNy43MDIsMC4yNTcNCjEyOCwxOTkyLDExLDExLDQwLDUzMCw2LjMyMiwtMC4wNDkNCjEyOSwxOTkyLDExLDI2LDQ3LDEwNTAsNi44MywwLjEyNw0KMTMwLDE5OTIsMTIsMyw1MCw5MDAsNy4wMjUsLTAuMjIyDQoxMzEsMTk5MywyLDIzLDMxLDI2MCw1LjUxOSwwLjA0Mg0KMTMyLDE5OTMsMiwyOCw1OCwxNzQwLDcuNDkyLC0wLjAzDQoxMzMsMTk5Myw2LDMsNDAsNDQwLDYuMzIyLC0wLjIzNQ0KMTM0LDE5OTMsNiw0LDQyLDUyMCw2LjQ3NSwtMC4yMjINCjEzNSwxOTkzLDYsNCw1NiwxMTAwLDcuMzgxLC0wLjM3OA0KMTM2LDE5OTMsOCwxMSw2MSwxODEwLDcuNjUxLC0wLjE1DQoxMzcsMTk5MywxMSw1LDM0LDI4MCw1LjgxLC0wLjE3NQ0KMTM4LDE5OTMsMTEsMjMsMzMsMzEwLDUuNzE2LDAuMDIxDQoxMzksMTk5MywxMiwxLDU0LDE2MjAsNy4yNjcsMC4xMjMNCjE0MCwxOTk0LDIsMjgsNDIsNTYwLDYuNDc1LC0wLjE0Nw0KMTQxLDE5OTQsMiwyOCw0MCw1NzAsNi4zMjIsMC4wMjQNCjE0MiwxOTk0LDMsMywzNCwzMjAsNS44MSwtMC4wNDENCjE0MywxOTk0LDUsMjksMjYsMTQwLDQuOTY1LC0wLjAyMw0KMTQ0LDE5OTQsNiw1LDQwLDUwMCw2LjMyMiwtMC4xMDcNCjE0NSwxOTk1LDEsMTEsMzksNjAwLDYuMjQyLDAuMTU1DQoxNDYsMTk5NSwyLDIsMjIsODAsNC40MzksLTAuMDU3DQoxNDcsMTk5NSw3LDE0LDQxLDYxMCw2LjM5OSwwLjAxNA0KMTQ4LDE5OTUsOCwxNSw1OCwxNjMwLDcuNDkyLC0wLjA5Ng0KMTQ5LDE5OTUsOCwyOSw2MywyMjYwLDcuNzUyLC0wLjAyOQ0KMTUwLDE5OTUsMTIsNSwzMCwyNzAsNS40MTYsMC4xODMNCjE1MSwxOTk1LDEyLDYsNDAsNjAsNi4zMjIsLTIuMjI3DQoxNTIsMTk5NSwxMiw2LDI3LDE3MCw1LjA4NCwwLjA1Mg0KMTUzLDE5OTUsMTIsMTYsMTUsMzAsMy4yMzIsMC4xNjkNCjE1NCwxOTk2LDYsOCw1MywxMzQwLDcuMjA4LC0wLjAwOA0KMTU1LDE5OTYsNiwyMCw0OCw5NjAsNi44OTYsLTAuMDI5DQoxNTYsMTk5Niw3LDE2LDYzLDI2NTAsNy43NTIsMC4xMw0KMTU3LDE5OTYsNywzMSw3Nyw0NzQwLDguMzg1LDAuMDc5DQoxNTgsMTk5Niw4LDYsNjIsMjg5MCw3LjcwMiwwLjI2Nw0KMTU5LDE5OTYsOCwxNCw1NywyMDUwLDcuNDM3LDAuMTg4DQoxNjAsMTk5Niw4LDIwLDY3LDMwOTAsNy45NDYsMC4wOQ0KMTYxLDE5OTYsOSwxOCw0MCw2NTAsNi4zMjIsMC4xNTUNCjE2MiwxOTk2LDksMTgsNDIsNzMwLDYuNDc1LDAuMTE4DQoxNjMsMTk5NiwxMCwzMSwyNSwxNDAsNC44NDEsMC4xDQoxNjQsMTk5NiwxMSw5LDQ3LDkzMCw2LjgzLDAuMDA2DQoxNjUsMTk5NiwxMSwxMCwzNyw0NDAsNi4wNzYsMC4wMTENCjE2NiwxOTk2LDExLDEwLDIwLDYwLDQuMTM5LC0wLjA0NA0KMTY3LDE5OTYsMTEsMTAsMTYsMzAsMy40MzYsLTAuMDM0DQoxNjgsMTk5NiwxMSwxMSwzMiwyODAsNS42MTksMC4wMTYNCjE2OSwxOTk2LDExLDE1LDM2LDM4MCw1Ljk5LC0wLjA1DQoxNzAsMTk5NiwxMSwxNSwyOCwyMjAsNS4xOTgsMC4xOTUNCjE3MSwxOTk2LDExLDE2LDI1LDEzMCw0Ljg0MSwwLjAyNg0KMTcyLDE5OTcsMSwyNSwzMywzMDAsNS43MTYsLTAuMDEyDQoxNzMsMTk5Nyw3LDEwLDU2LDE0NDAsNy4zODEsLTAuMTA5DQoxNzQsMTk5Nyw3LDIzLDU4LDIwNzAsNy40OTIsMC4xNDMNCjE3NSwxOTk3LDcsMjksMzMsNDkwLDUuNzE2LDAuNDc5DQoxNzYsMTk5Nyw4LDIxLDUwLDEwODAsNy4wMjUsLTAuMDQNCjE3NywxOTk3LDgsMjMsNjIsMjE3MCw3LjcwMiwtMC4wMg0KMTc4LDE5OTcsOCwyNyw2MywyNjYwLDcuNzUyLDAuMTM0DQoxNzksMTk5Nyw5LDgsNzMsMzUyMCw4LjIxNiwtMC4wNQ0KMTgwLDE5OTcsOSwyNyw2MywyNDcwLDcuNzUyLDAuMDYNCjE4MSwxOTk3LDEwLDcsOTEsNzY2MCw4LjkxMSwwLjAzMw0KMTgyLDE5OTcsMTAsNywzOCw0NjAsNi4xNiwtMC4wMjkNCjE4MywxOTk3LDExLDEwLDQ3LDg2MCw2LjgzLC0wLjA3Mw0KMTg0LDE5OTcsMTEsMTEsMzQsMzMwLDUuODEsLTAuMDExDQoxODUsMTk5NywxMSwxMiwzOSw2MDAsNi4yNDIsMC4xNTUNCjE4NiwxOTk3LDExLDE0LDQ4LDgzMCw2Ljg5NiwtMC4xNzUNCjE4NywxOTk3LDEyLDksMzgsNDgwLDYuMTYsMC4wMTQNCjE4OCwxOTk4LDYsMzAsNjQsMjAzMCw3LjgwMiwtMC4xODYNCjE4OSwxOTk4LDcsMjIsNDQsODEwLDYuNjIyLDAuMDc1DQoxOTAsMTk5OCw3LDI4LDczLDQyODAsOC4yMTYsMC4xNDUNCjE5MSwxOTk4LDgsMjYsNjksMzUzMCw4LjAzOSwwLjEzDQoxOTIsMTk5OCw4LDI3LDYzLDIzMDAsNy43NTIsLTAuMDEyDQoxOTMsMTk5OCwxMCwyMCwyMiw4MCw0LjQzOSwtMC4wNTcNCjE5NCwxOTk4LDEwLDIyLDM4LDUyMCw2LjE2LDAuMDk0DQoxOTUsMTk5OCwxMCwzMSw0Myw2NzAsNi41NDksLTAuMDQyDQoxOTYsMTk5OCwxMSw0LDUwLDEyMTAsNy4wMjUsMC4wNzQNCjE5NywxOTk4LDExLDUsMjIsMTAwLDQuNDM5LDAuMTY2DQoxOTgsMTk5OCwxMSwyNSw0Myw2NzAsNi41NDksLTAuMDQyDQoxOTksMTk5OSw2LDE2LDU1LDE1NDAsNy4zMjUsMC4wMTUNCjIwMCwxOTk5LDYsMTcsODUsNjE1MCw4LjY5NiwwLjAyOA0KMjAxLDE5OTksNiwyMCw2OSwzMTAwLDguMDM5LDANCjIwMiwxOTk5LDYsMjgsMzEsMjUwLDUuNTE5LDAuMDAzDQoyMDMsMTk5OSw2LDI4LDMyLDI5MCw1LjYxOSwwLjA1MQ0KMjA0LDE5OTksNiwyOCw2NywyMjgwLDcuOTQ2LC0wLjIxNA0KMjA1LDE5OTksNiwyOSw2MywyMTQwLDcuNzUyLC0wLjA4NA0KMjA2LDE5OTksNywxMyw1OSwyMjUwLDcuNTQ2LDAuMTczDQoyMDcsMTk5OSw3LDIyLDcxLDI2OTAsOC4xMjksLTAuMjMyDQoyMDgsMTk5OSwxMSwyMiwxNCwyMCwzLjAxNSwtMC4wMTkNCjIwOSwxOTk5LDExLDIzLDI5LDIwMCw1LjMwOSwtMC4wMQ0KMjEwLDE5OTksMTIsNyw0NCw3MjAsNi42MjIsLTAuMDQzDQoyMTEsMjAwMCw2LDksNDQsNjQwLDYuNjIyLC0wLjE2DQoyMTIsMjAwMCw2LDI3LDY0LDI1MTAsNy44MDIsMC4wMjYNCjIxMywyMDAwLDcsMTMsNDQsNjYwLDYuNjIyLC0wLjEzDQoyMTQsMjAwMCw4LDE1LDcwLDM1NjAsOC4wODQsMC4wOTMNCjIxNSwyMDAwLDgsMjIsNjEsMjE2MCw3LjY1MSwwLjAyNw0KMjE2LDIwMDAsOCwyNCw1NywxNzgwLDcuNDM3LDAuMDQ3DQoyMTcsMjAwMCw4LDI0LDU2LDIwNDAsNy4zODEsMC4yMzkNCjIxOCwyMDAwLDgsMzEsNjAsMjQ3MCw3LjU5OSwwLjIxMw0KMjE5LDIwMDAsMTEsMiw0NCw2OTAsNi42MjIsLTAuMDg1DQoyMjAsMjAwMCwxMSwxMiw0Nyw4MTAsNi44MywtMC4xMzMNCjIyMSwyMDAwLDExLDE5LDE5LDYwLDMuOTc3LDAuMTE3DQoyMjIsMjAwMCwxMSwyMiwyNCwxMzAsNC43MTMsMC4xNTUNCjIyMywyMDAwLDExLDIzLDYwLDE4MDAsNy41OTksLTAuMTAzDQoyMjQsMjAwMCwxMSwzMCw0MSw1NzAsNi4zOTksLTAuMDU0DQoyMjUsMjAwMCwxMiw2LDMxLDI1MCw1LjUxOSwwLjAwMw0KMjI2LDIwMDAsMTIsOSwxMiwxMCwyLjUzLC0wLjIyNw0KMjI3LDIwMDAsMTIsMTAsMjEsNjAsNC4yOTIsLTAuMTk4DQoyMjgsMjAwMSw2LDE4LDI5LDE5MCw1LjMwOSwtMC4wNjINCjIyOSwyMDAxLDYsMTksMjMsOTAsNC41NzksLTAuMDc5DQoyMzAsMjAwMSw3LDQsNDUsOTQwLDYuNjkzLDAuMTUzDQoyMzEsMjAwMSw3LDEwLDU3LDE4NzAsNy40MzcsMC4wOTYNCjIzMiwyMDAxLDcsMzEsNzksNDM1MCw4LjQ2NSwtMC4wODcNCjIzMywyMDAxLDgsMSw2MiwxOTEwLDcuNzAyLC0wLjE0Nw0KMjM0LDIwMDEsOSw1LDY3LDI2NTAsNy45NDYsLTAuMDY0DQoyMzUsMjAwMSwxMSwyNSwzNiwzNzAsNS45OSwtMC4wNzYNCjIzNiwyMDAxLDExLDI2LDQxLDYyMCw2LjM5OSwwLjAzDQoyMzcsMjAwMSwxMiwxLDMzLDM1MCw1LjcxNiwwLjE0Mg0KMjM4LDIwMDEsMTIsMSwzNyw0ODAsNi4wNzYsMC4wOTgNCjIzOSwyMDAxLDEyLDIsMzksNTIwLDYuMjQyLDAuMDEyDQoyNDAsMjAwMSwxMiw0LDQ3LDk2MCw2LjgzLDAuMDM3DQoyNDEsMjAwMSwxMiw2LDE4LDQwLDMuODA3LC0wLjExOA0KMjQyLDIwMDEsMTIsNywyOSwyMDAsNS4zMDksLTAuMDENCjI0MywyMDAxLDEyLDcsMzgsNDQwLDYuMTYsLTAuMDczDQoyNDQsMjAwMSwxMiw3LDUzLDExNjAsNy4yMDgsLTAuMTUyDQoyNDUsMjAwMSwxMiwxMSwzMiwyNjAsNS42MTksLTAuMDU4DQoyNDYsMjAwMSwxMiwxMywxNiwzMCwzLjQzNiwtMC4wMzQNCjI0NywyMDAyLDMsMjAsNzgsNDYzMCw4LjQyNSwwLjAxNQ0KMjQ4LDIwMDIsNSwyMyw2NiwyNTUwLDcuODk5LC0wLjA1NQ0KMjQ5LDIwMDIsNiw3LDQxLDU1MCw2LjM5OSwtMC4wOQ0KMjUwLDIwMDIsNiw3LDI4LDE2MCw1LjE5OCwtMC4xMjMNCjI1MSwyMDAyLDcsMzEsNjUsMjc4MCw3Ljg1MSwwLjA3OQ0KMjUyLDIwMDIsOCw2LDY4LDI5ODAsNy45OTMsMC4wMDcNCjI1MywyMDAyLDgsNyw3NSwzODgwLDguMzAyLC0wLjAzOA0KMjU0LDIwMDIsOCw3LDY2LDIxOTAsNy44OTksLTAuMjA3DQoyNTUsMjAwMiw4LDI3LDU4LDIxMjAsNy40OTIsMC4xNjcNCjI1NiwyMDAyLDgsMjgsNzAsMzA3MCw4LjA4NCwtMC4wNTUNCjI1NywyMDAyLDksMTEsNzYsNDUyMCw4LjM0MywwLjA3Mw0KMjU4LDIwMDIsMTAsMzAsNDcsOTYwLDYuODMsMC4wMzcNCjI1OSwyMDAyLDExLDIsNTcsMTc2MCw3LjQzNywwLjAzNg0KMjYwLDIwMDIsMTEsMTcsMTcsNDAsMy42MjcsMC4wNjINCjI2MSwyMDAyLDEyLDIsMzUsMzQwLDUuOTAxLC0wLjA3Mg0KMjYyLDIwMDIsMTIsMiwzOCw0ODAsNi4xNiwwLjAxNA0KMjYzLDIwMDMsMSw1LDM1LDQwMCw1LjkwMSwwLjA5DQoyNjQsMjAwMywxLDYsNTUsMTM5MCw3LjMyNSwtMC4wODgNCjI2NSwyMDAzLDEsNywzMywzMjAsNS43MTYsMC4wNTMNCjI2NiwyMDAzLDQsMTAsNzcsNDkxMCw4LjM4NSwwLjExNQ0KMjY3LDIwMDMsNCwxMCw2MSwyMDAwLDcuNjUxLC0wLjA1DQoyNjgsMjAwMyw1LDIsNjcsMjk1MCw3Ljk0NiwwLjA0Mw0KMjY5LDIwMDMsNiw4LDUxLDEwODAsNy4wODcsLTAuMTAyDQoyNzAsMjAwMyw3LDI0LDg2LDU2MTAsOC43MzMsLTAuMQ0KMjcxLDIwMDMsOCwyNyw2NCwyNTcwLDcuODAyLDAuMDUNCjI3MiwyMDAzLDgsMjksNjAsMjIwMCw3LjU5OSwwLjA5Nw0KMjczLDIwMDMsOSw5LDQ1LDg3MCw2LjY5MywwLjA3Ng0KMjc0LDIwMDMsOSw5LDQ1LDcyMCw2LjY5MywtMC4xMTMNCjI3NSwyMDAzLDksMTcsNjIsMjU1MCw3LjcwMiwwLjE0Mg0KMjc2LDIwMDMsMTEsMjcsNDYsODkwLDYuNzYyLDAuMDI5DQoyNzcsMjAwMywxMiw5LDM5LDUwMCw2LjI0MiwtMC4wMjcNCjI3OCwyMDAzLDEyLDExLDE4LDQwLDMuODA3LC0wLjExOA0KMjc5LDIwMDMsMTIsMTYsNDEsNjIwLDYuMzk5LDAuMDMNCjI4MCwyMDA0LDEsMTEsMTQsMjAsMy4wMTUsLTAuMDE5DQoyODEsMjAwNCwxLDEzLDM3LDQ0MCw2LjA3NiwwLjAxMQ0KMjgyLDIwMDQsMSwyNCwxNiwzMCwzLjQzNiwtMC4wMzQNCjI4MywyMDA0LDEsMjksNDAsNDgwLDYuMzIyLC0wLjE0OA0KMjg0LDIwMDQsNiwxMywxOSw1MCwzLjk3NywtMC4wNjUNCjI4NSwyMDA0LDYsMjIsNjEsMjQyMCw3LjY1MSwwLjE0MQ0KMjg2LDIwMDQsNywyOCw1OCwyMDAwLDcuNDkyLDAuMTA5DQoyODcsMjAwNCw4LDQsNjEsMjI1MCw3LjY1MSwwLjA2OA0KMjg4LDIwMDQsOCwxNyw1OSwyMzYwLDcuNTQ2LDAuMjIxDQoyODksMjAwNCwxMCwyOCwyNCwxNDAsNC43MTMsMC4yMjkNCjI5MCwyMDA0LDExLDExLDMzLDMyMCw1LjcxNiwwLjA1Mw0KMjkxLDIwMDQsMTEsMTcsNDcsMTA3MCw2LjgzLDAuMTQ2DQoyOTIsMjAwNCwxMiw3LDE3LDQwLDMuNjI3LDAuMDYyDQoyOTMsMjAwNCwxMiw5LDM2LDQ0MCw1Ljk5LDAuMDk3DQoyOTQsMjAwNCwxMiwxMiwxOSw1MCwzLjk3NywtMC4wNjUNCjI5NSwyMDA0LDEyLDEzLDM2LDQzMCw1Ljk5LDAuMDc0DQoyOTYsMjAwNSw2LDIzLDI0LDEyMCw0LjcxMywwLjA3NQ0KMjk3LDIwMDUsNiwyOCwyNiwxNjAsNC45NjUsMC4xMQ0KMjk4LDIwMDUsNywyLDYxLDE4ODAsNy42NTEsLTAuMTEyDQoyOTksMjAwNSw3LDQsNzEsMzQ2MCw4LjEyOSwwLjAyDQozMDAsMjAwNSw3LDIwLDM2LDUxMCw1Ljk5LDAuMjQ1DQozMDEsMjAwNSw3LDIwLDM3LDQ3MCw2LjA3NiwwLjA3Nw0KMzAyLDIwMDUsNywyNyw3NSwzNDEwLDguMzAyLC0wLjE2Nw0KMzAzLDIwMDUsMTEsMywzOCw1NjAsNi4xNiwwLjE2OA0KMzA0LDIwMDUsMTEsOSwyNiwxNTAsNC45NjUsMC4wNDYNCjMwNSwyMDA1LDExLDI0LDM1LDM4MCw1LjkwMSwwLjAzOQ0KMzA2LDIwMDUsMTEsMjcsNDMsNzgwLDYuNTQ5LDAuMTENCjMwNywyMDA1LDExLDI5LDI2LDE1MCw0Ljk2NSwwLjA0Ng0KMzA4LDIwMDUsMTIsMTQsMTUsMzAsMy4yMzIsMC4xNjkNCjMwOSwyMDA2LDEsOCw0Niw5MzAsNi43NjIsMC4wNzMNCjMxMCwyMDA2LDUsMjYsNDYsODAwLDYuNzYyLC0wLjA3Nw0KMzExLDIwMDYsNiwyMiwxMywxMCwyLjc4MiwtMC40NzkNCjMxMiwyMDA2LDYsMjIsMjcsMTgwLDUuMDg0LDAuMTA5DQozMTMsMjAwNiw3LDExLDY4LDI5MjAsNy45OTMsLTAuMDE0DQozMTQsMjAwNiw3LDIwLDU5LDIwODAsNy41NDYsMC4wOTQNCjMxNSwyMDA2LDgsMiw1NSwxODQwLDcuMzI1LDAuMTkzDQozMTYsMjAwNiw4LDcsNjAsMjA5MCw3LjU5OSwwLjA0Ng0KMzE3LDIwMDYsOCw5LDQ4LDk2MCw2Ljg5NiwtMC4wMjkNCjMxOCwyMDA2LDgsMjEsNTQsMTQ1MCw3LjI2NywwLjAxMg0KMzE5LDIwMDYsOSw2LDM4LDU3MCw2LjE2LDAuMTg1DQozMjAsMjAwNiw5LDEzLDQ5LDExNDAsNi45NjEsMC4wNzgNCjMyMSwyMDA2LDExLDYsMjksMjEwLDUuMzA5LDAuMDM4DQozMjIsMjAwNiwxMSw5LDQ0LDY2MCw2LjYyMiwtMC4xMw0KMzIzLDIwMDYsMTEsMTUsNTYsMTUxMCw3LjM4MSwtMC4wNjINCjMyNCwyMDA2LDExLDE3LDUwLDExNDAsNy4wMjUsMC4wMTQNCjMyNSwyMDA2LDEyLDMsMTUsMjAsMy4yMzIsLTAuMjM3DQozMjYsMjAwNiwxMiw5LDE1LDMwLDMuMjMyLDAuMTY5DQozMjcsMjAwNywzLDIsNTQsMTYwMCw3LjI2NywwLjExMQ0KMzI4LDIwMDcsNywxMyw1NiwxODUwLDcuMzgxLDAuMTQxDQozMjksMjAwNyw3LDEzLDU0LDE1OTAsNy4yNjcsMC4xMDUNCjMzMCwyMDA3LDcsMjMsNDUsNjgwLDYuNjkzLC0wLjE3MQ0KMzMxLDIwMDcsNywyMyw1NywxODcwLDcuNDM3LDAuMDk2DQozMzIsMjAwNywxMSwzLDE5LDUwLDMuOTc3LC0wLjA2NQ0KMzMzLDIwMDcsMTEsMTgsMjksMjMwLDUuMzA5LDAuMTI5DQozMzQsMjAwNywxMSwyMywyMCw3MCw0LjEzOSwwLjExDQozMzUsMjAwNywxMSwyOCw4MCw0OTEwLDguNTA1LC0wLjAwNg0KMzM2LDIwMDcsMTEsMzAsMTksNjAsMy45NzcsMC4xMTcNCjMzNywyMDA3LDExLDMwLDI1LDE0MCw0Ljg0MSwwLjENCjMzOCwyMDA3LDExLDMwLDIyLDkwLDQuNDM5LDAuMDYxDQozMzksMjAwNywxMiw4LDU0LDE0NDAsNy4yNjcsMC4wMDUNCjM0MCwyMDA3LDEyLDgsNDEsNjAwLDYuMzk5LC0wLjAwMw0KMzQxLDIwMDcsMTIsOCw0NywxMDMwLDYuODMsMC4xMDgNCjM0MiwyMDA3LDEyLDExLDUzLDE0MjAsNy4yMDgsMC4wNQ0KMzQzLDIwMDcsMTIsMTUsNjMsMjQzMCw3Ljc1MiwwLjA0Mw0KMzQ0LDIwMDcsMTIsMTYsNjQsMjc0MCw3LjgwMiwwLjExNA0KMzQ1LDIwMDcsMTIsMTYsMzcsNDQwLDYuMDc2LDAuMDExDQozNDYsMjAwOCwzLDEsMzIsMzAwLDUuNjE5LDAuMDg1DQozNDcsMjAwOCwzLDMsNTIsMTI2MCw3LjE0OCwtMC4wMDkNCjM0OCwyMDA4LDMsMyw0MCw2MDAsNi4zMjIsMC4wNzUNCjM0OSwyMDA4LDMsNiw0Miw2MzAsNi40NzUsLTAuMDMNCjM1MCwyMDA4LDYsNCwyNiwxNTAsNC45NjUsMC4wNDYNCjM1MSwyMDA4LDcsMiw1OCwxODIwLDcuNDkyLDAuMDE1DQozNTIsMjAwOCw3LDEwLDU4LDIwMzAsNy40OTIsMC4xMjQNCjM1MywyMDA4LDcsMTAsNTYsMTY1MCw3LjM4MSwwLjAyNw0KMzU0LDIwMDgsNywyOCw3OCw0NjAwLDguNDI1LDAuMDA5DQozNTUsMjAwOCw3LDI5LDY2LDI2NDAsNy44OTksLTAuMDINCjM1NiwyMDA4LDExLDExLDE3LDMwLDMuNjI3LC0wLjIyNQ0KMzU3LDIwMDgsMTEsMjEsMjUsMTQwLDQuODQxLDAuMQ0KMzU4LDIwMDgsMTEsMjYsNzEsMzQ3MCw4LjEyOSwwLjAyMw0KMzU5LDIwMDgsMTIsNywyMywxMTAsNC41NzksMC4xMjINCjM2MCwyMDA5LDcsMTAsNzAsMjY2MCw4LjA4NCwtMC4xOTgNCjM2MSwyMDA5LDcsMjEsNjIsMjQwMCw3LjcwMiwwLjA4MQ0KMzYyLDIwMDksNywyMSw3OCwzNzkwLDguNDI1LC0wLjE4NQ0KMzYzLDIwMDksMTEsMjYsMjAsNjAsNC4xMzksLTAuMDQ0DQozNjQsMjAwOSwxMiwxMiw4NCw1NzkwLDguNjU5LDAuMDA1DQozNjUsMjAwOSwxMiwxMiw3MiwzMTEwLDguMTczLC0wLjEzMQ0KMzY2LDIwMTAsNiwxMSwzOCw0NDAsNi4xNiwtMC4wNzMNCjM2NywyMDEwLDYsMTcsMjUsMTUwLDQuODQxLDAuMTY5DQozNjgsMjAxMCw2LDIyLDI5LDE5MCw1LjMwOSwtMC4wNjINCjM2OSwyMDEwLDYsMjMsMjYsMTQwLDQuOTY1LC0wLjAyMw0KMzcwLDIwMTAsNywxMyw2NywyMjkwLDcuOTQ2LC0wLjIxDQozNzEsMjAxMCw3LDI4LDU1LDE2MzAsNy4zMjUsMC4wNzINCjM3MiwyMDEwLDgsMiw3NywzNTcwLDguMzg1LC0wLjIwNA0KMzczLDIwMTAsMTEsNiw1MiwxMTgwLDcuMTQ4LC0wLjA3NQ0KMzc0LDIwMTAsMTEsMTgsMzEsMjkwLDUuNTE5LDAuMTUxDQozNzUsMjAxMCwxMSwyMSwxOSw2MCwzLjk3NywwLjExNw0KMzc2LDIwMTAsMTEsMjUsMjgsMTkwLDUuMTk4LDAuMDQ5DQozNzcsMjAxMCwxMSwyNiw2MywyMjEwLDcuNzUyLC0wLjA1Mg0KMzc4LDIwMTAsMTEsMjgsNTAsMTE0MCw3LjAyNSwwLjAxNA0KMzc5LDIwMTAsMTEsMjgsNTYsMTY0MCw3LjM4MSwwLjAyMQ0KMzgwLDIwMTAsMTEsMjgsMzIsMzMwLDUuNjE5LDAuMTgNCjM4MSwyMDEwLDEyLDUsMzAsMjIwLDUuNDE2LC0wLjAyMg0KMzgyLDIwMTAsMTIsNSw3MywzMzgwLDguMjE2LC0wLjA5MQ0KMzgzLDIwMTAsMTIsNSw2MywyNzYwLDcuNzUyLDAuMTcxDQozODQsMjAxMCwxMiwxNiw0MSw1NzAsNi4zOTksLTAuMDU0DQozODUsMjAxMCwxMiwxOSwxOCw1MCwzLjgwNywwLjEwNQ0KMzg2LDIwMTEsNiw4LDQ4LDg5MCw2Ljg5NiwtMC4xMDUNCjM4NywyMDExLDYsOSwzMCwyMzAsNS40MTYsMC4wMjINCjM4OCwyMDExLDYsMjAsNjIsMTk4MCw3LjcwMiwtMC4xMTENCjM4OSwyMDExLDYsMjEsNDcsOTYwLDYuODMsMC4wMzcNCjM5MCwyMDExLDYsMjIsNDYsODgwLDYuNzYyLDAuMDE4DQozOTEsMjAxMSw3LDEyLDYwLDIxMDAsNy41OTksMC4wNTENCjM5MiwyMDExLDcsMTQsNzgsNDI3MCw4LjQyNSwtMC4wNjYNCjM5MywyMDExLDcsMjcsNjUsMjUwMCw3Ljg1MSwtMC4wMjcNCjM5NCwyMDExLDgsMTgsNzEsMzE3MCw4LjEyOSwtMC4wNjgNCjM5NSwyMDExLDksMTMsNjEsMjI2MCw3LjY1MSwwLjA3Mg0KMzk2LDIwMTEsMTEsMTgsNjgsMzIyMCw3Ljk5MywwLjA4NA0KMzk3LDIwMTEsMTIsOCwyNywxNzAsNS4wODQsMC4wNTINCjM5OCwyMDExLDEyLDExLDcwLDMzNTAsOC4wODQsMC4wMzINCjM5OSwyMDEyLDYsOCw0Niw4MzAsNi43NjIsLTAuMDQNCjQwMCwyMDEyLDYsMTYsMjUsMTYwLDQuODQxLDAuMjM0DQo0MDEsMjAxMiw3LDExLDU1LDEyNjAsNy4zMjUsLTAuMTg2DQo0MDIsMjAxMiw3LDI0LDUyLDE3MjAsNy4xNDgsMC4zMDINCjQwMywyMDEyLDExLDUsNDQsODQwLDYuNjIyLDAuMTExDQo0MDQsMjAxMiwxMSw2LDM3LDQ2MCw2LjA3NiwwLjA1NQ0KNDA1LDIwMTIsMTEsNywyMCw2MCw0LjEzOSwtMC4wNDQNCjQwNiwyMDEyLDExLDE3LDM2LDQzMCw1Ljk5LDAuMDc0DQo0MDcsMjAxMiwxMSwxOSwzNyw1MzAsNi4wNzYsMC4xOTcNCjQwOCwyMDEyLDExLDIyLDQ4LDEwMDAsNi44OTYsMC4wMTINCjQwOSwyMDEyLDExLDI2LDUyLDEyNzAsNy4xNDgsLTAuMDAxDQo0MTAsMjAxMiwxMSwyOSw0Nyw5ODAsNi44MywwLjA1OA0KNDExLDIwMTIsMTIsMiw1MywxNDAwLDcuMjA4LDAuMDM2DQo0MTIsMjAxMiwxMiwzLDk1LDk3OTAsOS4wNDYsMC4xNDMNCjQxMywyMDEyLDEyLDUsMjMsOTAsNC41NzksLTAuMDc5DQo0MTQsMjAxMiwxMiwxNSw2NCwyNTAwLDcuODAyLDAuMDIyDQo0MTUsMjAxMiwxMiwyMCw2NywzMTEwLDcuOTQ2LDAuMDk2DQo0MTYsMjAxMyw2LDE2LDE5LDUwLDMuOTc3LC0wLjA2NQ0KNDE3LDIwMTMsNiwxNyw1OCwxODAwLDcuNDkyLDAuMDA0DQo0MTgsMjAxMyw2LDE5LDQ3LDkyMCw2LjgzLC0wLjAwNQ0KNDE5LDIwMTMsNiwyMCw5Miw5MTYwLDguOTQ1LDAuMTc3DQo0MjAsMjAxMyw3LDIzLDU3LDE5MTAsNy40MzcsMC4xMTgNCjQyMSwyMDEzLDcsMzAsODcsNTQ2MCw4Ljc2OSwtMC4xNjQNCjQyMiwyMDEzLDgsMTYsNzQsNDM4MCw4LjI1OSwwLjEyNQ0KNDIzLDIwMTMsOCwxOSw2MCwyMDEwLDcuNTk5LDAuMDA3DQo0MjQsMjAxMywxMCwyMyw1NCwxNDIwLDcuMjY3LC0wLjAwOQ0KNDI1LDIwMTMsMTAsMjYsNDIsNjIwLDYuNDc1LC0wLjA0Ng0KNDI2LDIwMTMsMTEsMSw1OCwxNzcwLDcuNDkyLC0wLjAxMw0KNDI3LDIwMTMsMTEsMTEsNzMsMjk1MCw4LjIxNiwtMC4yMjcNCjQyOCwyMDEzLDExLDE4LDU4LDE3NTAsNy40OTIsLTAuMDI1DQo0MjksMjAxMywxMSwxOSw1NSwxNjgwLDcuMzI1LDAuMTAyDQo0MzAsMjAxMywxMSwyNSwxOCw0MCwzLjgwNywtMC4xMTgNCjQzMSwyMDEzLDExLDI3LDcyLDM0NTAsOC4xNzMsLTAuMDI3DQo0MzIsMjAxMywxMSwyNyw0NCw3NTAsNi42MjIsLTAuMDAyDQo0MzMsMjAxNCw2LDksMTgsNDAsMy44MDcsLTAuMTE4DQo0MzQsMjAxNCw2LDE4LDMwLDIyMCw1LjQxNiwtMC4wMjINCjQzNSwyMDE0LDcsMTQsNjcsMzI5MCw3Ljk0NiwwLjE1Mg0KNDM2LDIwMTQsNywxNiw2NywyNzEwLDcuOTQ2LC0wLjA0Mg0KNDM3LDIwMTQsOCwxNyw3OCwzNDUwLDguNDI1LC0wLjI3OQ0KNDM4LDIwMTQsOCwyMCw2MywyMjgwLDcuNzUyLC0wLjAyMQ0KNDM5LDIwMTQsOSw5LDY0LDI0NTAsNy44MDIsMC4wMDINCjQ0MCwyMDE0LDEwLDMwLDUxLDEyNjAsNy4wODcsMC4wNTINCjQ0MSwyMDE0LDExLDE0LDUwLDExNzAsNy4wMjUsMC4wNA0KNDQyLDIwMTQsMTEsMTUsNTIsMTQ2MCw3LjE0OCwwLjEzOA0KNDQzLDIwMTQsMTEsMjEsMTYsMzAsMy40MzYsLTAuMDM0DQo0NDQsMjAxNCwxMSwyOCw2MiwxOTcwLDcuNzAyLC0wLjExNg0KNDQ1LDIwMTQsMTEsMjksNzgsNTczMCw4LjQyNSwwLjIyOA0KNDQ2LDIwMTQsMTIsNyw1MiwxMTYwLDcuMTQ4LC0wLjA5Mg0KNDQ3LDIwMTUsMSw5LDQzLDcyMCw2LjU0OSwwLjAzDQo0NDgsMjAxNSwxMCwxMCwzNiw0NDAsNS45OSwwLjA5Nw0KNDQ5LDIwMTUsMTAsMzAsMzYsNDIwLDUuOTksMC4wNQ0KNDUwLDIwMTUsMTEsMiw2NCwyMzcwLDcuODAyLC0wLjAzMQ0KNDUxLDIwMTUsMTEsNSwyNywxNTAsNS4wODQsLTAuMDczDQo0NTIsMjAxNSwxMSw2LDQ4LDEwMjAsNi44OTYsMC4wMzINCjQ1MywyMDE1LDExLDEzLDk1LDk4NTAsOS4wNDYsMC4xNDkNCjQ1NCwyMDE1LDExLDEzLDMwLDIyMCw1LjQxNiwtMC4wMjINCjQ1NSwyMDE1LDExLDE3LDU4LDE5ODAsNy40OTIsMC4wOTkNCjQ1NiwyMDE1LDExLDE4LDc0LDQzNzAsOC4yNTksMC4xMjMNCjQ1NywyMDE1LDExLDIxLDMzLDMwMCw1LjcxNiwtMC4wMTINCjQ1OCwyMDE1LDExLDIzLDQ0LDY2MCw2LjYyMiwtMC4xMw0KNDU5LDIwMTUsMTEsMjgsMzIsMjMwLDUuNjE5LC0wLjE4MQ0KNDYwLDIwMTUsMTEsMzAsNzMsNDQzMCw4LjIxNiwwLjE4DQo0NjEsMjAxNSwxMiw5LDIzLDEwMCw0LjU3OSwwLjAyNg0KNDYyLDIwMTUsMTIsMTAsNjcsMjU2MCw3Ljk0NiwtMC4wOTkNCjQ2MywyMDE2LDUsOSwxMiwxMCwyLjUzLC0wLjIyNw0KNDY0LDIwMTYsNSwxOSwyMSw4MCw0LjI5MiwwLjA5DQo0NjUsMjAxNiw2LDQsMTYsMzAsMy40MzYsLTAuMDM0DQo0NjYsMjAxNiw2LDEwLDY0LDIyNjAsNy44MDIsLTAuMDc5DQo0NjcsMjAxNiw2LDExLDI4LDE3MCw1LjE5OCwtMC4wNjINCjQ2OCwyMDE2LDEwLDI4LDQ5LDk5MCw2Ljk2MSwtMC4wNjMNCjQ2OSwyMDE2LDExLDE0LDMwLDI5MCw1LjQxNiwwLjI1NA0KNDcwLDIwMTYsMTEsMTUsMTYsMzAsMy40MzYsLTAuMDM0DQo0NzEsMjAxNiwxMSwxOCwzNyw0NTAsNi4wNzYsMC4wMzMNCjQ3MiwyMDE2LDExLDIxLDQ2LDgwMCw2Ljc2MiwtMC4wNzcNCjQ3MywyMDE2LDExLDI2LDMzLDMxMCw1LjcxNiwwLjAyMQ0KNDc0LDIwMTYsMTEsMzAsNzIsMzU1MCw4LjE3MywwLjAwMg0KNDc1LDIwMTYsMTIsMiwzMSwyMTAsNS41MTksLTAuMTcyDQo0NzYsMjAxNiwxMiw1LDU4LDE5MDAsNy40OTIsMC4wNTgNCjQ3NywyMDE2LDEyLDExLDM3LDQyMCw2LjA3NiwtMC4wMzYNCjQ3OCwyMDE2LDEyLDE0LDgwLDQwOTAsOC41MDUsLTAuMTg5DQo0NzksMjAxNywxMCwyNywzNiw0NTAsNS45OSwwLjExOQ0KNDgwLDIwMTcsMTEsMiwzOSw1NTAsNi4yNDIsMC4wNjgNCjQ4MSwyMDE3LDExLDMsMzgsNDQwLDYuMTYsLTAuMDczDQo0ODIsMjAxNywxMSw5LDUwLDExMDAsNy4wMjUsLTAuMDIxDQo0ODMsMjAxNywxMSwxMCw1NSwxODAwLDcuMzI1LDAuMTcxDQo0ODQsMjAxNywxMSwxMCw1MiwxMzIwLDcuMTQ4LDAuMDM3DQo0ODUsMjAxNywxMSwxMiwxOSw2MCwzLjk3NywwLjExNw0KNDg2LDIwMTcsMTEsMTQsNTIsMTUxMCw3LjE0OCwwLjE3Mg0KNDg3LDIwMTcsMTEsMTQsNjUsMjc5MCw3Ljg1MSwwLjA4Mw0KNDg4LDIwMTcsMTEsMTQsNDQsODEwLDYuNjIyLDAuMDc1DQo0ODksMjAxNywxMSwxOCw2MywyMTMwLDcuNzUyLC0wLjA4OQ0KNDkwLDIwMTcsMTEsMjUsMjgsMTcwLDUuMTk4LC0wLjA2Mg0KNDkxLDIwMTcsMTEsMjUsNDAsNTYwLDYuMzIyLDAuMDA2DQo0OTIsMjAxOCwxMCw3LDQyLDg4MCw2LjQ3NSwwLjMwNQ0KNDkzLDIwMTgsMTAsMjksNDQsNzIwLDYuNjIyLC0wLjA0Mw0KNDk0LDIwMTgsMTEsMSwyMiw4MCw0LjQzOSwtMC4wNTcNCjQ5NSwyMDE4LDExLDMsNjMsMjI5MCw3Ljc1MiwtMC4wMTYNCjQ5NiwyMDE4LDExLDEwLDI1LDEzMCw0Ljg0MSwwLjAyNg0KNDk3LDIwMTgsMTIsMSw2MiwxODcwLDcuNzAyLC0wLjE2OA0KNDk4LDIwMTgsMTIsMTEsNTEsMTIyMCw3LjA4NywwLjAyDQo0OTksMjAxOCwxMiwxNSw0Nyw5MTAsNi44MywtMC4wMTYNCjUwMCwyMDE4LDEyLDE1LDY5LDMxODAsOC4wMzksMC4wMjYNCg==" download="length-weight_data.csv">length-weight_data.csv</a>`{=html}). The sample data includes length and weight data (columns length and weight, respectively) along with fitted values and residuals from a length-weight regression (columns called fit and res, respectively). The SharedData function from crosstalk package is also used here to generate a data object that can be “shared” across independent plots.

Following this chunk of R code is a level 2 markdown header that tells flexdashboard to introduce a column break and place the subsequent components into separate tabs:

Column {.tabset}
-------------------------------------

Following this break, independent tabs are defined using three hashtags followed by an optional tab name (level 3 markdown header). This header can be followed by either markdown text or R code. Here, two tabs are generated with plotly plots using shared data from crosstalk:

### Length-Weight relationship

```{r} 
plot_ly(data = shared_lw) %>% 
    add_markers(x = ~length, y = ~weight, name = "Observed") %>% 
    add_lines(x = ~length, y = ~exp(fit), name = "Predicted")
```

### Residuals vs. fitted values

```{r} 
plot_ly(data = shared_lw) %>% 
    add_markers(x = ~fit, y = ~res)
```

The native syntax of plotly was inspired by the grammar of graphics and, as such, its general structure will be familiar to those who have used ggplot2. The package has also been structured to be pipe (%>%) and dplyr friendly, making the code more intuitive and efficient. Though the script ends with the residual vs. fitted plot, the dashboard can easily be extended to include other diagnostic plots, such as a histogram of the residuals.

Once this script is “Knit” (Ctrl+Shift+K in Rstudio), a stand-alone html document will be produced with the plots rendered into independent tabs (shown to the right). Clicking a specific point in one plot will highlight the corresponding point in the other plot. In short, flexdashboard sets up the structure of the document, plotly produces the interactive figures and crosstalk connects the plots held in independent tabs.

Of course, this is only a rudimentary overview of what is possible with flexdashboard, plotly and crosstalk. A wide range of layout options are possible using flexdashboard, plotly can produce more than just scatter and line plots and crosstalk can connect various widgets. See the links provided on the Background page for more details on each package. The hope here is that this skeleton serves as a starting point from which to build more elaborate dashboards tailored to specific needs.

Column

Length-Weight relationship

Residuals vs. fitted values

rmarkdown

Row

R markdown

The package rmarkdown enables the writing of markdown text and R code in the same document (extension .Rmd). Most R markdown files includes three types of content:

  1. A YAML header surrounded by ----
  2. Text following markdown formatting
  3. R code chunks surrounded by ```

Row

YAML

The first step in setting up an R markdown file is to define a YAML header. In the skeleton, it looks like this:

---
title: "flexdashboard + plotly + crosstalk"
output: flexdashboard::flex_dashboard
---

This is where the output type is defined along with other items such as title, author, date, etc. A flex_dashboard is requested here. There are are growing number of output types supported by R markdown (e.g. html_document, pdf_document, word_document).

Markdown

Next, write plain text using markdown syntax to describe how to format the text in the final document.

  • Plain text simply translates to Plain text in the default font of the output document.
  • Italics and bold are specified using asterisk and/or underscores:
    • *italic* or _italic_ \(\rightarrow\) italic
    • **bold** or __bold__ \(\rightarrow\) bold
    • **_bold-italic_** \(\rightarrow\) bold-italic
  • Equations can be specified using LaTeX syntax:
    • $W = \alpha L ^{\beta}$ \(\rightarrow\) \(W = \alpha L ^{\beta}\)
  • Ordered and unordered lists are generated using numbers and dashes or asterisk, respectively:
    • 1. ordered item 1 \(\rightarrow\) 1.   ordered item 1
    • - unordered item \(\rightarrow\) •   unordered item
  • Headers are define using hashtags:
    • ##### Header 5 \(\rightarrow\)
      Header 5
    • Note that markdown headers with three hashtags or less have specific formatting functions in flexdashboard

R

Finally, mix in R code by surrounding chunks of code using one backtick for inline code (e.g.`r 1+1` will print 2 in the output) or three backticks to run several lines of code and/or display a table or plot. The chunk below will print the top three rows of the cars data-set:

```{r} 
head_cars <- head(cars, 3)
head_cars
```

Resulting in the following output:

  speed dist
1     4    2
2     4   10
3     7    4

flexdashboard

Row

flexdashboard

The flexdashboard package can be used to render groups of related text, figures and tables into a dashboard. Using a combination of markdown syntax and R code (i.e. R markdown), this package facilitates a wide range of layout options and each component can include output from packages such as plotly, leaflet, ggplot2, and so on. The package also integrates nicely with shiny and crosstalk, providing options for increasing the interactivity of the dashboard. Some layout and component options are highlighted below.

Row

Layout

Individual charts are defined using markdown’s level 3 header (### Chart title) and they are, by default, stacked vertically within columns defined using markdown’s level 2 header (---------). The code below will create a flexdashboard with two stacked columns and three charts:

---
title: "Layout example 1"
output: flexdashboard::flex_dashboard
---

Column
-------------------------------------

### Chart 1


Column
-------------------------------------

### Chart 2


### Chart 3

The output from this example has been duplicated here.

Alternatively, charts can be organized by row by modifying the YAML header:

---
title: "Layout example 2"
output: 
  flexdashboard::flex_dashboard:
    orientation: rows
---

Row
-------------------------------------

### Chart 1


Row
-------------------------------------

### Chart 2


### Chart 3

The output from this example has been duplicated here.

Also note that multiple pages can be generated using markdown’s level 1 header:

---
title: "Layout example 1"
output: flexdashboard::flex_dashboard
---

Page 1
====================================

Column
-------------------------------------

### Chart 1


Page 2
====================================

Column
-------------------------------------

### Chart 2


### Chart 3

Components

The components of a dashboard can hold a wide range of outputs. The code below generates a mixture of tabular and graphical output. The table is generated following markdown syntax with inline R code and the interactive plot is generated using plotly.

---
title: "Components example"
output: flexdashboard::flex_dashboard
---

Column {data-width=300}
-------------------------------------

### Table  

Summary statistics of the `volcano` data-set

| Statistic     | Elevation                   |
|:------------- |:--------------------------- |
| Min           | `r min(volcano)`            | 
| Median        | `r median(volcano)`         |
| Mean          | `r round(mean(volcano))`    |
| Max           | `r max(volcano)`            |


Column {data-width=700}
-------------------------------------

### Plot

```{r} 
plotly::plot_ly(z = volcano, type = "surface")
```

The output from this example has been duplicated here. Note the use of the data-width attribute to make the table chart relatively narrow.

plotly

Column

plotly

There are two ways to produce interactive graphics using plotly:

  1. Using the function ggplotly to convert plots from ggplot to plotly objects
  2. Using the native syntax of the plotly package

Both options follow the layered grammar of graphics, which is a generic tool for concisely describing the components of a graphic, such as the:

  • Data and mappings (aesthetics)
  • Geometric objects (points, lines, polygons)
  • Scales (color, size, shape, axes)

Column

ggplotly

Using the ggplotly function, a user can construct a plot using ggplot2 and supply the plot object to ggplotly to convert it to an interactive plotly graphic:

library(ggplot2)
p <- ggplot(data = iris, 
            mapping = aes(x = Sepal.Length, 
                          y = Petal.Length, 
                          color = Species)) +
  geom_point() +
  scale_color_manual(values = viridis::viridis(3))
plotly::ggplotly(p)

Data and mapping

Here, the ggplot function is used to set-up the base layer of the plot as well as the aesthetics. That is, iris data are supplied to the function and specific columns in the iris data-set are mapped to x, y and color aesthetics.

Geometric objects

Next points are added using the geom_point function. Many other geometries can be used to visually represent the data, such as lines (geom_line), bars (geom_bar), text (geom_text).

Scales

Finally, colors were modified using scale_color_manual. While the colors are manually defined here, ggplot2 includes built in color scales such as scale_color_grey. Scales used for the x and y aesthetics can also be modified using functions such as scale_x_log10.

Output

Column

plot_ly

Using functions from the plotly package, plotly plots can be directly created using syntax similar to ggplot2:

library(plotly)
plot_ly(data = iris, 
        x = ~Sepal.Length, 
        y = ~Petal.Length, 
        color = ~Species,
        colors = viridis::viridis(3)) %>% 
  add_markers()

Data and mapping

The plot_ly function is analogous to the ggplot function from ggplot2 and, like ggplot, this function sets-up the base layer of the plot. Again, the iris data is supplied and specific columns are mapped to x, y and color aesthetics.

Geometric objects

Under plotly, geometries are added using functions with the add_ prefix rather that the geom_ prefix of used in ggplot2. Points are added here using add_markers and, like ggplot2, several other geometries can be specified, such as lines (add_lines), bars (add_bars), text (add_text).

Scales

Unlike ggplot2, scales are not modified using specific functions with a scale_ prefix, rather, scales are specified in the plot_ly function call itself or via the layout function. Here, colors are specified using the colors argument in the plot_ly function.

Output

crosstalk

Column

crosstalk

The crosstalk package enables HTML widgets, such as plotly and leaflet, to communicate with each other without shiny. As such, self-contained html files with similar behaviour to shiny applications can be built using crosstalk.

A first step to using crosstalk is to set-up a shared data-set using the SharedData function:

library(crosstalk)
sub_quakes <- subset(quakes, stations %in% c(10, 20, 50, 100))
shared_quakes <- SharedData$new(sub_quakes)

The quakes data is used for this example. As shown to the right using leaflet and plotly, HTML widgets using this shared data will be linked and selections in one plot will affect the other plot.

The crosstalk package also includes a series of functions for filtering the shared data (filter_checkbox, filter_slider and filter_select). When used in a flexdashboard, and other interactive contexts, the following lines of code will produce the check-box, slider and drop-down filters shown below.

filter_checkbox("stations", "Stations", shared_quakes, 
                ~stations, inline = TRUE)
filter_slider("depth", "Depth", shared_quakes, ~depth)
filter_select("mag", "Magnitude", shared_quakes, 
              ~cut(mag, breaks = seq(1, 10, 0.5), right = FALSE))

Column

leaflet

plotly