The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Linking Multiple Components

library(linkeR)
library(shiny)
library(leaflet)
library(DT)
library(plotly)

Linking Multiple Components

linkeR can link any number of interactive components together. This vignette shows how to create complex dashboards with maps, tables, charts, and other elements all responding to the same selections.

Three-Component Example

Here’s a dashboard with a map, table, and plotly chart all linked together:

ui <- fluidPage(
  titlePanel("Multi-Component Dashboard"),
  
  fluidRow(
    column(4,
      h4("Geographic View"),
      leafletOutput("map")
    ),
    column(4,
      h4("Data Table"),
      DTOutput("table")
    ),
    column(4,
      h4("Performance Chart"),
      plotlyOutput("chart")
    )
  ),
  
  fluidRow(
    column(12,
      h4("Selection Details"),
      verbatimTextOutput("selection_info")
    )
  )
)

server <- function(input, output, session) {
  
  # Sample business data
  business_data <- reactive({
    data.frame(
      business_id = paste0("BIZ_", 1:20),
      name = paste("Business", 1:20),
      latitude = runif(20, 40.7, 40.8),
      longitude = runif(20, -111.95, -111.85),
      revenue = runif(20, 100000, 1000000),
      employees = sample(10:100, 20, replace = TRUE),
      category = sample(c("Tech", "Retail", "Food"), 20, replace = TRUE)
    )
  })
  
  # Render map
  output$map <- renderLeaflet({
    leaflet(business_data()) %>%
      addTiles() %>%
      addCircleMarkers(
        lng = ~longitude,
        lat = ~latitude,
        layerId = ~business_id,
        radius = 5,
        popup = ~paste("Business:", name)
      )
  })
  
  # Render table
  output$table <- renderDT({
    data <- business_data()
    display_data <- data[, c("name", "category", "revenue", "employees")]
    
    datatable(
      display_data,
      selection = "single",
      rownames = FALSE
    ) %>%
      formatCurrency("revenue", currency = "$", digits = 0)
  })
  
  # Render chart
  output$chart <- renderPlotly({
    plot_ly(
      data = business_data(),
      x = ~employees,
      y = ~revenue,
      customdata = ~business_id,  # Critical: this enables plotly linking
      text = ~name,
      type = "scatter",
      mode = "markers",
      source = "business_chart"  # Source ID for plotly events
    ) %>%
      layout(
        title = "Revenue vs Employees",
        xaxis = list(title = "Employees"),
        yaxis = list(title = "Revenue")
      )
  })
  
  # Link the map and table (plotly requires special handling)
  registry <- link_plots(
    session,
    map = business_data,
    table = business_data,
    chart = business_data,
    shared_id_column = "business_id"
  )
  
  # Display selection info
  output$selection_info <- renderText({
    selection <- registry$get_selection()
    if (!is.null(selection$selected_id)) {
      data <- business_data()
      selected <- data[data$business_id == selection$selected_id, ]
      if (nrow(selected) > 0) {
        paste0(
          "Selected: ", selected$name, "\n",
          "Source: ", selection$source, "\n",
          "Revenue: $", format(selected$revenue, big.mark = ","), "\n",
          "Employees: ", selected$employees
        )
      }
    } else {
      "No selection"
    }
  })
}

Adding More Component Types

Summary Tables

You can link summary tables that show aggregated information:

# In your server function
output$category_summary <- renderDT({
  data <- business_data()
  
  summary_data <- data %>%
    group_by(category) %>%
    summarise(
      count = n(),
      avg_revenue = mean(revenue),
      total_employees = sum(employees),
      .groups = "drop"
    )
  
  datatable(
    summary_data,
    selection = "single",
    rownames = FALSE,
    options = list(pageLength = 5, searching = FALSE)
  ) %>%
    formatCurrency("avg_revenue", currency = "$", digits = 0)
})

# Link it by adding to your link_plots call
link_plots(
  session,
  map = business_data,
  table = business_data,
  summary = business_data,  # Same data, different view
  shared_id_column = "business_id"
)

Managing Complex State

For complex dashboards, you might want centralized state management:

server <- function(input, output, session) {
  
  # Centralized selection state
  current_selection <- reactiveVal(NULL)
  
  # Business data
  business_data <- reactive({ 
    data.frame(
      business_id = paste0("BIZ_", 1:20),
      name = paste("Business", 1:20),
      latitude = runif(20, 40.7, 40.8),
      longitude = runif(20, -111.95, -111.85),
      revenue = runif(20, 100000, 1000000),
      employees = sample(10:100, 20, replace = TRUE),
      category = sample(c("Tech", "Retail", "Food"), 20, replace = TRUE)
    )
   })
  
  # Set up linking with global callback
  registry <- link_plots(
    session,
    map = business_data,
    table = business_data,
    shared_id_column = "business_id",
    
    # Update centralized state
    on_selection_change = function(selected_id, selected_data, source_id, session) {
      current_selection(selected_data)
    }
  )
  
  # All outputs can react to current_selection()
  output$detail_panel <- renderUI({
    selected <- current_selection()
    if (!is.null(selected)) {
      # Rich detail panel
      fluidRow(
        column(6, 
          h4("Business Details"),
          p("Name:", selected$name),
          p("Category:", selected$category)
        ),
        column(6,
          h4("Performance"),
          p("Revenue:", scales::dollar(selected$revenue)),
          p("Employees:", selected$employees)
        )
      )
    } else {
      div("Select a business to view details")
    }
  })
  
  output$related_businesses <- renderDT({
    selected <- current_selection()
    if (!is.null(selected)) {
      # Show businesses in same category
      related <- business_data()[
        business_data()$category == selected$category & 
        business_data()$business_id != selected$business_id,
      ]
      
      datatable(
        related[, c("name", "revenue", "employees")],
        caption = paste("Other", selected$category, "businesses"),
        options = list(pageLength = 5)
      )
    }
  })
}

Performance Tips

  1. Limit Updates: Use req() to avoid unnecessary updates
  2. Debounce Fast Clicks: Use debounce() for rapid selection changes
  3. Lazy Loading: Only render expensive components when selected
  4. Efficient Data: Keep linked datasets reasonably sized

Troubleshooting Multiple Components

With these patterns, you can create rich, interconnected dashboards where every component enhances the user’s understanding of the data.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.