Title: Link Interactive Plots and Tables in 'shiny' Applications
Version: 0.1.2
Description: Build powerful, linked-view dashboards in 'shiny' applications. With a declarative, one-line setup, you can create bidirectional links between interactive components. When a user interacts with one element (e.g., clicking a map marker), all linked components (such as 'DT' tables or other charts) instantly update. Supports 'leaflet' maps, 'DT' tables, and spatial data via 'sf' objects out-of-the-box, with an extensible API for custom components.
License: MIT + file LICENSE
Encoding: UTF-8
RoxygenNote: 7.3.2
Imports: shiny (≥ 1.5.0), magrittr (≥ 2.0.0), later (≥ 1.0.0)
Suggests: leaflet, DT, sf, testthat (≥ 3.0.0), knitr, plotly, bslib, rmarkdown
Config/testthat/edition: 3
VignetteBuilder: knitr
URL: https://epiforesite.github.io/linkeR/, https://github.com/EpiForeSITE/linkeR/
BugReports: https://github.com/EpiForeSITE/linkeR/issues/
NeedsCompilation: no
Packaged: 2025-09-15 20:22:18 UTC; jake
Author: Jake Wagoner ORCID iD [aut, cre], Centers for Disease Control and Prevention's Center for Forecasting and Outbreak Analytics [fnd] (Cooperative agreement CDC-RFA-FT-23-0069)
Maintainer: Jake Wagoner <jakew@sci.utah.edu>
Repository: CRAN
Date/Publication: 2025-09-21 14:10:02 UTC

Apply Default Leaflet Behavior for Selection Events

Description

apply_default_leaflet_behavior is a helper function that provides consistent default behavior for leaflet maps when handling selection events. It manages popup display and map navigation based on the selection state.

Usage

apply_default_leaflet_behavior(map_proxy, selected_data, component_info)

Arguments

map_proxy

A leaflet map proxy object used to update the map

selected_data

A data frame or list containing the selected row/item data. If NULL, indicates deselection occurred.

component_info

A list containing component configuration information:

shared_id_column

Character. Name of the column containing unique identifiers

config

List containing:

lng_col

Character. Name of the longitude column

lat_col

Character. Name of the latitude column

highlight_zoom

Numeric. Zoom level to use when highlighting selection

Details

When selected_data is provided:

When selected_data is NULL (deselection):

Value

Returns the modified map proxy object with updated view and popups


Description

create_link_registry creates a registry system that manages linked interactions between multiple 'shiny' components, allowing them to share selection state and coordinate their behavior.

Usage

create_link_registry(session, on_selection_change = NULL)

Arguments

session

A 'shiny' session object, required for server-side reactivity

on_selection_change

Optional callback function that gets called when selection changes. Should accept parameters: selected_id, selected_data, source_component_id, and session

Details

The registry maintains a shared state across all registered components, automatically setting up observers to synchronize selections. When a selection changes in one component, all other registered components are updated to reflect the same selection.

Components are automatically cleaned up when re-registered to prevent memory leaks from orphaned observers.

Value

A link_registry object with the following methods:

register_component(session, component_id, type, data_reactive, shared_id_column, config)

Register a new component with the registry. Parameters:

  • session: 'shiny' session object for namespacing. Can be global session in non-modular apps.

  • component_id: Unique string identifier for the component

  • type: Component type (e.g., "table", "plot")

  • data_reactive: Reactive expression returning the component's data

  • shared_id_column: Name of the column used for linking selections

  • config: Optional list of component-specific configuration

clear_all()

Remove all registered components and reset shared state

set_selection(selected_id, source_component_id)

Programmatically update the selection state

get_selection()

Get current selection as list with selected_id and source

get_on_selection_change()

Return the on_selection_change callback function

get_components()

Get registry components info (for debugging)

get_shared_state()

Get current shared state (for debugging)

See Also

setup_component_observers() for component observer setup

Examples


# Create a mock session for the example
session <- shiny::MockShinySession$new()

# Create registry with optional callback
registry <- create_link_registry(
  session = session,
  on_selection_change = function(id, data, source, session) {
    message("Selection changed to ID: ", id, " from: ", source)
  }
)

# In a real app, you would register components like this:
# my_data <- reactive({ data.frame(id = 1:3, name = c("A", "B", "C")) })
# registry$register_component("table1", "table", my_data, "id")
# registry$register_component("plot1", "plot", my_data, "id")



Detect Component Type Based on Output ID Patterns

Description

detect_component_type is an internal function that attempts to automatically determine the type of 'shiny' output component based on common naming patterns in the component ID. This function uses simple heuristics to classify components as either "leaflet" (for maps) or "datatable" (for tables), with "datatable" as the default fallback.

Usage

detect_component_type(component_id, data_reactive)

Arguments

component_id

Character string. The ID of the output component to classify.

data_reactive

Reactive data object (currently unused in the function logic).

Details

The function uses case-insensitive pattern matching on the component ID:

Value

Character string indicating the detected component type:

Note

This is an internal function that provides basic auto-detection capabilities. For more precise control over component types, use the explicit register_* functions instead.


Description

link_plots provides a simple, one-line interface to link interactive components in a single-file or non-modular 'shiny' application. It automatically detects component types and sets up bidirectional linking.

Usage

link_plots(
  session,
  ...,
  shared_id_column,
  leaflet_lng_col = "longitude",
  leaflet_lat_col = "latitude",
  leaflet_click_handler = NULL,
  dt_click_handler = NULL,
  on_selection_change = NULL
)

Arguments

session

The 'shiny' session object

...

Named arguments where names are component output IDs and values are reactive data frames. Each data frame must contain the shared_id_column. For leaflet maps: can be sf objects (coordinates auto-extracted) or regular data frames with longitude/latitude columns.

shared_id_column

Character string naming the column that contains unique identifiers present in all linked components.

leaflet_lng_col

Character string naming the longitude column for leaflet maps. Defaults to "longitude". For sf objects, this will be the name of the created column.

leaflet_lat_col

Character string naming the latitude column for leaflet maps. Defaults to "latitude". For sf objects, this will be the name of the created column.

leaflet_click_handler

Optional function that handles leaflet marker clicks. This will be used for both direct clicks and when other components select this marker. Function should accept (map_proxy, selected_data, session).

dt_click_handler

Optional function that handles DT row selections. This will be used for both direct clicks and when other components select this row. Function should accept (dt_proxy, selected_data, session).

on_selection_change

Optional callback function that gets called when selection changes. Function should accept parameters: (selected_id, selected_data, source_component_id, session)

Details

This function is the fastest way to get started with linkeR and is ideal for straightforward dashboards.

For more complex applications that use 'shiny' Modules, you should use the more robust pattern of creating a central registry with create_link_registry() and passing it to your modules, where you will call register_leaflet() or register_dt() directly. This preserves module encapsulation and leads to more maintainable code. See the modularized_example for a complete example of this pattern.

Value

Invisibly returns the created registry object

Examples

# This example is for a single-file app.
# For modular apps, please see the "Using linkeR with Modules" vignette.
if (interactive()) {
  library(shiny)
  library(leaflet)
  library(DT)

  # Sample data
  sample_data <- data.frame(
    id = 1:10,
    name = paste("Location", 1:10),
    latitude = runif(10, 40.7, 40.8),
    longitude = runif(10, -111.95, -111.85),
    value = round(runif(10, 100, 1000))
  )

  ui <- fluidPage(
    titlePanel("linkeR Example"),
    fluidRow(
      column(6, leafletOutput("my_map")),
      column(6, DTOutput("my_table"))
    )
  )

  server <- function(input, output, session) {
    my_data <- reactive({
      sample_data
    })

    output$my_map <- renderLeaflet({
      leaflet(my_data()) %>%
        addTiles() %>%
        addMarkers(
          lng = ~longitude,
          lat = ~latitude,
          layerId = ~id,
          popup = ~name
        )
    })

    output$my_table <- renderDT({
      datatable(my_data()[, c("name", "value")], selection = "single")
    })

    link_plots(
      session,
      my_map = my_data,
      my_table = my_data,
      shared_id_column = "id"
    )
  }

  shinyApp(ui, server)
}

Package imports

Description

Package imports


Process SF Data for Leaflet Integration

Description

process_sf_data is a helper function to extract coordinates from an sf object or ensure lng/lat columns exist in a data frame.

Usage

process_sf_data(data, lng_col = "longitude", lat_col = "latitude")

Arguments

data

Data frame or sf object. If sf object, coordinates will be extracted.

lng_col

Character string. Name for the longitude column (default: "longitude")

lat_col

Character string. Name for the latitude column (default: "latitude")

Details

This function handles three scenarios:

For sf objects, the function:

Value

Data frame with explicit lng/lat columns, ready for leaflet integration

Examples

if (requireNamespace("sf", quietly = TRUE)) {
  # Create a sample sf object
  sf_data <- sf::st_as_sf(
    data.frame(
      id = 1:2,
      name = c("A", "B"),
      geom = c("POINT(-111.9 40.7)", "POINT(-111.8 40.6)")
    ),
    wkt = "geom",
    crs = 4326
  )

  # Process the sf object
  processed_data <- process_sf_data(sf_data)
  print(processed_data)
}


Register a DT DataTable Component

Description

register_dt registers a DT datatable for linking with other components.

Usage

register_dt(
  session,
  registry,
  dt_output_id,
  data_reactive,
  shared_id_column,
  click_handler = NULL
)

Arguments

session

'shiny' session object. The session from the module where the DT is used. This could be global session in non-modular apps.

registry

A link registry created by create_link_registry()

dt_output_id

Character string: the outputId of your DT::DTOutput

data_reactive

Reactive expression returning the data frame for the table

shared_id_column

Character string: name of the ID column

click_handler

Optional function: custom click handler for row selection, must have args (map_proxy, selected_data, session), overrides all default behavior

Value

NULL (invisible). This function is called for its side effects of registering the component.

Examples


  # Create a mock session for the example
  session <- shiny::MockShinySession$new()

  # Create a registry
  registry <- create_link_registry(session)

  # Sample reactive data
  my_data <- shiny::reactive({
    data.frame(
      id = 1:5,
      name = c("A", "B", "C", "D", "E"),
      value = 11:15
    )
  })

  # Register a DT component
  register_dt(session, registry, "my_table", my_data, "id")

  # Verify registration
  print(registry$get_components())


Register a Leaflet Component

Description

register_leaflet registers a Leaflet map for linking with other components.

Usage

register_leaflet(
  session,
  registry,
  leaflet_output_id,
  data_reactive,
  shared_id_column,
  lng_col = "longitude",
  lat_col = "latitude",
  highlight_zoom = 12,
  click_handler = NULL
)

Arguments

session

'shiny' session object. The session from the module where the DT is used. This could be global session in non-modular apps.

registry

A link registry created by create_link_registry()

leaflet_output_id

Character string: the outputId of your leafletOutput

data_reactive

Reactive expression returning the data frame for the map

shared_id_column

Character string: name of the ID column

lng_col

Character string: name of longitude column (default: "longitude")

lat_col

Character string: name of latitude column (default: "latitude")

highlight_zoom

Numeric: zoom level when highlighting (default: 12)

click_handler

Optional function: custom click handler for row selection, must have args (map_proxy, selected_data, session), overrides all default behavior

Value

No return value, called for side effects.

Examples


  # Create a mock session for the example
  session <- shiny::MockShinySession$new()

  # Create a registry
  registry <- create_link_registry(session)

  # Sample reactive data
  my_data <- shiny::reactive({
    data.frame(
      id = 1:5,
      name = c("A", "B", "C", "D", "E"),
      longitude = -111.9 + runif(5, -0.1, 0.1),
      latitude = 40.7 + runif(5, -0.1, 0.1)
    )
  })

  # Register a leaflet component
  register_leaflet(session, registry, "my_map", my_data, "id")

  # Verify registration
  print(registry$get_components())


Set up observers for different component types

Description

setup_component_observers is an internal function that creates and configures observers for different types of interactive components based on the specified component type. It acts as a dispatcher that calls the appropriate setup function for each supported component.

Usage

setup_component_observers(
  component_id,
  type,
  session,
  components,
  shared_state,
  on_selection_change,
  registry = NULL
)

Arguments

component_id

Character string. Unique identifier for the component.

type

Character string. The type of component to set up observers for. Currently supports "leaflet" and "datatable".

session

'shiny' session object. The current 'shiny' session.

components

List. Collection of all components in the application.

shared_state

Reactive values object. Shared state across components.

on_selection_change

Function. Callback function to execute when selection changes occur.

registry

Optional. Registry object for component management. Default is NULL.

Value

List of observer objects created for the specified component type. Throws Error if an unsupported component type is provided.


Setup DataTable Observers

Description

setup_datatable_observers Sets up reactive observers for a DataTable component to handle user interactions and state changes. This function establishes the necessary event handlers for selection changes and synchronizes the component with the shared application state.

Usage

setup_datatable_observers(
  component_id,
  session,
  components,
  shared_state,
  on_selection_change,
  registry = NULL
)

Arguments

component_id

Character string. Unique identifier for the DataTable component.

session

'shiny' session object. The current 'shiny' session for reactive context.

components

List. Collection of UI components in the application.

shared_state

Reactive values object. Shared state container for cross-component communication.

on_selection_change

Function. Callback function to execute when table selection changes.

registry

List or NULL. Optional registry for component management. Defaults to NULL.

Details

This function creates reactive observers that monitor DataTable interactions and update the shared state accordingly. It handles selection events and ensures proper synchronization between the DataTable component and other application components.

Value

NULL. This function is called for its side effects of setting up observers.


Setup Leaflet Map Observers

Description

setup_leaflet_observers creates two observers for handling Leaflet map interactions in a linked component system. The first observer handles direct marker clicks on the map, while the second observer responds to selection changes from other linked components.

Usage

setup_leaflet_observers(
  component_id,
  session,
  components,
  shared_state,
  on_selection_change,
  registry = NULL
)

Arguments

component_id

Character string. The unique identifier for the Leaflet component.

session

'shiny' session object for the current user session.

components

List containing component configuration data including data reactives and shared ID columns.

shared_state

Reactive values object containing selected_id and selection_source for coordinating selections across components.

on_selection_change

Function to call when selection changes (currently unused).

registry

Optional registry object with set_selection method for managing selections. If NULL, falls back to direct shared_state updates.

Details

The marker click observer:

The selection response observer:

Value

List containing two observer objects:

observer1

Handles marker click events on the map

observer2

Responds to selection changes from other components


Update DT Selection Based on Shared ID

Description

update_dt_selection Updates the selection state of a DataTable (DT) component when a shared ID is selected or deselected from another linked component. This function handles both custom click handlers and default selection behavior.

Usage

update_dt_selection(component_id, selected_id, session, components)

Arguments

component_id

Character string. The ID of the DT component to update.

selected_id

The shared ID value to select. If NULL, deselects all rows.

session

'shiny' session object for the current user session.

components

List containing component configuration information, including data reactives, shared ID columns, and optional custom click handlers.

Details

The function performs the following steps:

Value

NULL (invisible). Function is called for side effects only.

Custom Click Handlers

If a custom click handler is provided in the component configuration (component_info$config$click_handler), it will be called with the DT proxy, selected data (or NULL for deselection), and session. Otherwise, default row selection/deselection is performed.


Update Leaflet Map Selection

Description

update_leaflet_selection updates a Leaflet map component to reflect a new selection state. This function handles both selection and deselection events, applying either custom user-defined click handlers or default behaviors.

Usage

update_leaflet_selection(component_id, selected_id, session, components)

Arguments

component_id

Character string. The ID of the Leaflet map component to update.

selected_id

Character string or NULL. The ID of the selected item. If NULL, indicates deselection.

session

'shiny' session object. The current 'shiny' session.

components

List. A named list containing component information, where each element contains component configuration including data_reactive, shared_id_column, and config settings.

Details

The function performs the following operations:

Required columns in the component data:

Value

NULL (invisibly). The function is called for its side effects on the Leaflet map.

Note

If the leaflet package is not available, the function returns early without error. Missing required columns will generate a warning and cause early return.