--- title: "6 - ggplot2, plotly, htmlwidgets, crosstalk" author: "Man" date: 2026-09-23 format: html toc: true --- # Setup Today we look at some ways to make our data slightly more interactive for the web without the full power of web development in R Shiny. First we load in some libraries. ```{r} #| warning: false library(dplyr) library(tidyr) library(ggplot2) library(reactable) library(plotly) library(crosstalk) ``` # ggplot2 `ggplot2` creates 2D graphs. **Directions** 1. State the data frame. Then add an "aesthetics" of which data frame columns to serve as x-, y-axis: :::{style="width: 90%; margin: 0 auto 1em auto; padding: 0.6em; background-color: #c4c4c4; border-radius: 2px;"} ``` ggplot(df, aes(x = col1, y = col2, color = ..., fill = ..., size = ..., shape = ...) + options below + more options below + etc. ) ``` ::: 2. Add graph types, like: - `geom_histogram()` - `geom_bar()` and `geom_col()` - `geom_dotplot()` - `geom_point()` - `geom_line()` - `geom_boxplot()` 3. Add etc. - Add labels `labs(title = ..., x = ..., y = ..., color = ...)` - Add theme: `theme_bw()`, `theme_dark()`, `theme_minimal()`, etc. ## Example Use the Billboard Songs database and the top positions of their songs, available at `https://manctsui.github.io/datasets/charts.csv`. Plot the number of weeks song is on the board vs their peak positions. (Idea: Keep only distinct songs.) ```{r} df <- read.csv("https://manctsui.github.io/datasets/charts.csv") |> distinct(song, artist, .keep_all = TRUE) plot <- ggplot(df, aes(weeks.on.board, peak.rank)) + geom_point() plot ``` # Plotly `plotly` creates 2D and 3D graphs with interactivity. Wrap a `ggplot` object with `ggplotly()` to get a `plotly` graph: ```{r} #| warning: false library(ggplot2) library(plotly) x <- c(1:100) random_y <- rnorm(100, mean = 0) data <- data.frame(x, random_y) fig <- ggplot(data, mapping = aes(x = x, y = random_y)) + geom_line() ggplotly(fig) ``` Or directly create graphs in `plotly`: ```{r} fig <- plot_ly(data, x = ~x, y = ~random_y, type = 'scatter', mode = 'lines') fig ``` Types to choose from: - `scatter` -- accounts for dotplots, scatterplots, line graphs, etc. - `scatter3d` - `bar` - `pie` - `choropleth` map of geographic regions shaded by intensity of data values - Sankey diagrams, etc. ## Example Repeat the `ggplot2` example purely in `plotly`: ```{r} plot2 <- plot_ly(df, x = ~weeks.on.board, y= ~peak.rank, type = "scatter", mode = 'markers') |> layout( title = "Billboard Songs: Total Weeks vs Peak Rank", xaxis = list(title = "Total Weeks on Board"), yaxis = list(title = "Peak Rank") ) plot2 ``` # Leaflet ```{r} library(leaflet) locations_df <- data.frame( name = c("Eiffel Tower", "Louvre Museum", "Notre-Dame"), lat = c(48.8584, 48.8606, 48.8530), lng = c(2.2945, 2.3376, 2.3499) ) # Plotting all 3 markers simultaneously leaflet(data = locations_df) |> addTiles() |> addMarkers( lng = ~lng, lat = ~lat, popup = ~name # Adds clickable text popups ) ``` # HTML Widgets `plotly` and `leaflet` are actually JavaScript libraries. The R package `htmlwidgets` allows developers write R bindings to access these JS libraries. This means you can [pick from many widgets](https://gallery.htmlwidgets.org/) to use in R without needing to use JS. # Crosstalk Crosstalk does *linked brushing*: selecting data points in one widget automatically selects the same data points in a shared widget. **Directions:** 1. Pick a column `df$col` of a data frame `df` that uniquely identifies each row: this column serves as a **key**. 2. Upgrade our data frame `df` to a `SharedData` object and store it as a variable ```sd <- SharedData$new(df, key = ~col)``` The `~` is used here because key expects a formula not a variable name as input. 3. Use this `SharedData` object `sd` as you would use a data frame within `ggplot2`, `plotly`, `DT`, `reactable`, `leaflet`, etc. Crosstalk also comes with the following inputs; some arguments are shown: - `filter_slider(id, label, sharedData, column, min, max)` - `filter_select(id, label, sharedData, group)` - `filter_checkbox(id, label, sharedData, group)` Here: - `id` is the HTML id of the input, so you can reference this input object. - `label` is the name of this input that shows up. - `sharedData` is your upgraded data frame - `group` and `column`: the formula or data frame column that is shared between widgets. ## Example Display songs by Ed Sheeran, Adele, and Taylor Swift from the Billboard Songs database as well as the top positions of their songs as a table. Include a filter checkbox that toggles based on the selected artists to restrict our table. ```{r} specific_artists <- read.csv("https://manctsui.github.io/datasets/charts.csv") |> filter(artist %in% c("Ed Sheeran", "Adele", "Taylor Swift")) |> distinct(song, artist, peak.rank) sd <- SharedData$new(specific_artists, key = ~song) filter_checkbox("artist_checkbox", "Artist", sd, ~artist) reactable(sd, defaultPageSize = 4) ``` ## Example, improved We can make the above look nicer by arranging the widgets into columns with crosstalk's `bscols` (Bootstrap columns) function. Read the documentations and an example of its use if you want to learn more. ```{r} bscols( filter_checkbox("artist_checkbox", "Artist", sd, ~artist), reactable(sd, defaultPageSize = 4), widths = c(4,8) ) ``` ## Caveats - Not all HTML widgets support crosstalk. - For full reactivity, use Shiny for R. ## Reference - [Documentation for crosstalk](https://www.rdocumentation.org/packages/crosstalk/versions/1.2.2) esp. `filter_slider`, `filter_select`, and `filter_checkbox` (under `filter_slider`). - [Tutorial](https://emilyriederer.github.io/demo-crosstalk/tutorial/tutorial-rmd.html) - [Examples](https://rstudio.github.io/crosstalk/using.html)