linkeR: Effortless Linked Views for ‘shiny’ Applications

R-CMD-check Codecov test coverage CRAN status Lifecycle: experimental EpiForeSITE ForeSITE Group

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

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"
)

Key Benefits

Manual Approach linkeR Approach
50+ lines of observer code 1 function call
Easy to introduce bugs Tested and reliable
Hard to maintain Declarative and clear
Limited to 2 components Unlimited components
No built-in customization Rich customization options

Installation

# Install from CRAN (when available)
install.packages("linkeR")

# Or install development version from GitHub
# install.packages("devtools")
devtools::install_github("EpiForeSITE/linkeR")

Requirements

For linking to work, your setup needs:

  1. Shared ID Column: All datasets must have a common identifier column
  2. Matching Component IDs:
  3. 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

Contributing

Contributions are welcome and encouraged! Follow best practice for github contributions.

Development Setup

# Clone and setup
git clone https://github.com/EpiForeSITE/linkeR.git
cd linkeR

# Install dependencies
devtools::install_deps()

# Run tests
devtools::test()

# Check package
devtools::check()

License

This project is licensed under the MIT License - see the LICENSE file for details.