Create synchronized, interactive dashboards where one click updates multiple components
linkeR
makes it effortless to create linked views in Shiny applications. When users interact with one component (like clicking a map marker), all related components (tables, charts, other maps) automatically update to show corresponding information.
What linkeR Does
- Bidirectional Linking: Click a map marker → table row highlights. Click table row → map zooms and shows popup.
- One-Line Setup: Link multiple components with a single function call
- Custom Behaviors: Define exactly what happens when users click different components
- Multi-Component Support: Link maps, tables, charts, and more in complex dashboards
- Zero Boilerplate: No manual observer setup or event handling required
Why Use linkeR?
Before linkeR (Manual Approach)
# Complex manual setup for each component pair
observeEvent(input$map_marker_click, {
clicked_id <- input$map_marker_click$id
# Find corresponding table row
row_idx <- which(my_data()$id == clicked_id)
# Update table selection
dataTableProxy("my_table") %>% selectRows(row_idx)
# Update map view
leafletProxy("my_map") %>% setView(...)
# Update any other components...
# Repeat this for every component combination!
})
observeEvent(input$my_table_rows_selected, {
# More boilerplate code...
# Handle edge cases...
# Ensure consistency...
})
With linkeR (Simple Approach)
# One line links everything!
link_plots(
session,
my_map = my_data,
my_table = my_data,
shared_id_column = "id"
)
Installation
# Install from CRAN (when available)
install.packages("linkeR")
# Or install development version from GitHub
# install.packages("devtools")
devtools::install_github("JakeWags/linkeR")
Requirements
For linking to work, your setup needs:
- Shared ID Column: All datasets must have a common identifier column
-
Matching Component IDs:
- Leaflet: Use
layerId = ~your_id_column
- DT: Row numbers automatically map to data rows
- Leaflet: Use
-
Reactive Data: Wrap your data in
reactive()
# Good: Proper setup
my_data <- reactive({
data.frame(
id = 1:10, # ← Shared ID column
name = paste("Item", 1:10),
lat = runif(10), lng = runif(10)
)
})
output$my_map <- renderLeaflet({
leaflet(my_data()) %>%
addMarkers(layerId = ~id) # ← layerId matches shared_id_column
})
link_plots(session, my_map = my_data, shared_id_column = "id")
# Bad: Missing layerId
output$my_map <- renderLeaflet({
leaflet(my_data()) %>%
addMarkers() # ← No layerId = no linking!
})
Supported Components
Component | Status | Notes |
---|---|---|
Leaflet Maps | ✅ Full Support | Interactive maps with markers, circles, polygons |
DT DataTables | ✅ Full Support | Sortable, filterable tables |
Plotly Charts | 🔄 Partial | Requires manual event handling |
Custom Components | 🔄 Partial | Any Shiny component with click events, Requires manual event handling |
Base R Plots | 📋 Planned | Static plots with click detection |
Mapbox | 📋 Planned | Alternative mapping solution |