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 |
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:
|
Details
When selected_data
is provided:
Creates a popup with "Selected" header and ID information
Sets map view to the selected location coordinates
Applies the configured highlight zoom level
When selected_data
is NULL (deselection):
Removes all existing popups from the map
Value
Returns the modified map proxy object with updated view and popups
Create a Link Registry for 'shiny' Component Coordination
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:
IDs containing "map" or "leaflet" are classified as "leaflet"
IDs containing "table" or "dt" are classified as "datatable"
All other IDs default to "datatable" with a warning message
Value
Character string indicating the detected component type:
"leaflet" - for IDs containing "map" or "leaflet"
"datatable" - for IDs containing "table" or "dt", or as default
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.
Simple Plot Linking Function for Non-Modular 'shiny' Apps
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:
SF objects: Extracts coordinates using sf::st_coordinates() and creates lng/lat columns
Regular data frames with existing lng/lat columns: Returns unchanged
Regular data frames without lng/lat columns: Issues warning and returns unchanged
For sf objects, the function:
Extracts point coordinates from the geometry column
Adds coordinates as new columns with the specified names
Preserves the original geometry column for advanced spatial operations
Returns an sf object with both geometry and coordinate columns
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 |
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 |
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:
Extracts clicked marker ID from the click event
Retrieves corresponding data row from the component's data
Clears existing popups and applies click behavior (custom or default)
Updates selection state through registry or direct shared_state modification
The selection response observer:
Only responds to selections from other components (not self-selections)
Updates the map visualization to reflect the new selection
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:
Validates that the DT package is available
Retrieves current data from the component's reactive data source
Validates that the shared ID column exists in the data
Creates a DT proxy for programmatic table manipulation
Finds the matching row based on the shared ID
Executes either custom click handler or default selection behavior
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:
Validates that the leaflet package is available
Checks that required columns (shared_id_column, lng_col, lat_col) exist in the data
Clears existing popups on the map
For selections: finds the selected data row and applies either custom click handler or default behavior
For deselections: delegates to custom handler or performs default cleanup
Required columns in the component data:
-
shared_id_column
: Column containing unique identifiers for map features -
lng_col
: Column containing longitude coordinates -
lat_col
: Column containing latitude coordinates
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.