| Type: | Package |
| Title: | Interactive Overlays on 'shiny' Plots |
| Version: | 0.2.0 |
| Description: | Provides rectangular elements that can be dragged and resized over plots in 'shiny' apps. This may be useful in applications where users need to mark regions on the plot for further input or processing. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| URL: | https://github.com/nicholasdavies/overshiny,https://nicholasdavies.github.io/overshiny/ |
| BugReports: | https://github.com/nicholasdavies/overshiny/issues |
| RoxygenNote: | 7.3.2 |
| Imports: | cowplot, ggplot2, graphics, grDevices, grid, htmltools, shiny,shinyjs, shinyjqui, stringr |
| Suggests: | knitr, rmarkdown, testthat (≥ 3.0.0) |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| NeedsCompilation: | no |
| Packaged: | 2025-09-06 22:11:25 UTC; nick |
| Author: | Nick Davies [aut, cre, cph] |
| Maintainer: | Nick Davies <nicholas.davies@lshtm.ac.uk> |
| Repository: | CRAN |
| Date/Publication: | 2025-09-07 22:00:17 UTC |
Interactive overlays on Shiny plots
Description
overshiny provides draggable and resizable rectangular elements thatoverlay plots in Shiny apps. This may be useful in applications where usersneed to define regions on the plot for further input or processing.Currently, the overlays are only designed to move along the x axis of theplot.
Details
The package exports a setup helper (useOverlay()),UI components (overlayToken(),overlayPlotOutput()),a server-side controller (overlayServer()), and a function foraligning overlays to a ggplot2 or base plot (overlayBounds()).
Author(s)
Maintainer: Nick Daviesnicholas.davies@lshtm.ac.uk [copyright holder]
See Also
Useful links:
Report bugs athttps://github.com/nicholasdavies/overshiny/issues
Align overlays with a ggplot2 or base plot
Description
Sets the pixel and coordinate bounds of the overlay area based on aggplot2::ggplot() object or base R plot. This ensures that overlays arepositioned correctly in both visual and coordinate space.
Usage
overlayBounds(ov, plot, xlim = c(NA, NA), ylim = c(NA, NA), row = 1L, col = 1L)Arguments
ov | A |
plot | A |
xlim,ylim | Vectors defining the coordinate limits for overlays.Use |
row,col | Row and column of the facet panel (if applicable). This onlyworks with ggplot2 plots; base R plots with multiple panels are notsupported. |
Details
Call this function withinshiny::renderPlot(), before returning theggplot object (if using ggplot2) orNULL (if using base R plotting).
Value
The ggplot object (for ggplot2) orNULL (for base R plotting), tobe returned from theshiny::renderPlot() block.
See Also
overlayServer(), for a complete example.
Examples
server <- function(input, output) { ov <- overlayServer("my_plot", 1, 1) output$my_plot <- shiny::renderPlot({ plot(1:100, sin(1:100 * 0.1), type = "l") overlayBounds(ov, "base", xlim = c(1, 100)) }) # further server code here . . .}Create a plot output element with overlays
Description
Render ashiny::renderPlot() within an application page, with support foroverlays.
Usage
overlayPlotOutput(outputId, width, height)Arguments
outputId | The |
width,height | Image width and height. Must be a valid CSS unit, like |
Value
A plot output element that can be added to a UI definition.
See Also
overlayServer(), for a complete example.
Examples
ui <- shiny::fluidPage( overlayPlotOutput("my_plot", 640, 480) # further UI elements here . . .)Add interactive overlays to a Shiny plot
Description
This function sets up server-side infrastructure to support draggable andresizable overlays on a plot. This may be useful in applications where usersneed to define regions on the plot for further input or processing.Currently, the overlays are only designed to move along the x axis of theplot.
Usage
overlayServer( outputId, nrect, width = NULL, data = NULL, snap = NULL, heading = NULL, select = NULL, menu = NULL, colours = overlayColours, opacity = 0.25, icon = shiny::icon("gear"), stagger = 0.045, style = list(), debug = FALSE)Arguments
outputId | The ID of the plot output (as used in |
nrect | Number of overlay rectangles to support. |
width | Optional default overlay width in plot coordinates. If |
data | Named list of custom overlay-specific properties to be edited inthe overlay dropdown menu. |
snap | Function to "snap" overlay coordinates to a grid, or |
heading | Function to provide a heading for the overlay dropdown menus,or |
select | If you want to allow users to change the type (i.e. label) ofthe overlay from the overlay dropdown menu, set this to |
menu | Function to provide additional UI elements on the overlaydropdown menu. See details for how to specify the menu function. |
colours | A function to assign custom colours to the overlays. Shouldbe a function that takes a single integer (the number of overlays) andreturns colours in hexadecimal notation (e.g. "#FF0000"). Do not provideopacity here as a fourth channel; use the |
opacity | Numeric value (0 to 1) indicating overlay transparency. |
icon | A Shiny icon to show the dropdown menu. |
stagger | Vertical offset between stacked overlays, as a proportion ofheight. |
style | Named list of character vectors with additional CSS stylingattributes for the overlays. If an element is named "background-color"then this will override the |
debug | If |
Details
Call this function once from your server code to initialise a set of overlayrectangles for a specific plot. It creates reactive handlers for move,resize, and dropdown menu actions, and allows adding new overlays bydragging anoverlayToken() onto the plot. The function returns ashiny::reactiveValues() object which you should keep for further use; inthe examples and documentation, this object is typically calledov.
Value
Ashiny::reactiveValues() object with the following named fields:
n | Number of overlays (read-only). |
show | TRUE/FALSE; controls whether overlays are visible. |
active | Logical vector of lengthn; indicates which overlays are active. |
label | Character vector of labels shown at the top of each overlay. |
data | Custom data for each overlay, to be edited via the dropdown menu. |
editing | Index of the overlay currently being edited via the dropdown menu;NA if none (read-only). |
last | Index of the most recently added overlay (read-only). |
snap | Coordinate snapping function. |
heading | Heading function for the dropdown menu. |
select | Overlay label select options for the dropdown menu. |
menu | Function to provide additional UI elements for the dropdown menu. |
px,pw | Numeric vector; overlay x-position and width in pixels (see note). |
py,ph | Numeric vector; overlay y-position and height in pixels (read-only). |
cx0,cx1 | Numeric vector; overlay x-bounds in plot coordinates (see note). |
outputId | The output ID of the plot display area (read-only). |
bound_cx, bound_cw | x-position and width of the bounding area in plot coordinates (read-only). |
bound_px, bound_pw | x-position and width of the bounding area in pixels (read-only). |
bound_py, bound_ph | y-position and height of the bounding area in pixels (read-only). |
stagger | Amount of vertical staggering, as proportion of height. |
style | Named list of character vectors; additional styling for rectangular overlays. |
update_cx(i) | Function to updatecx0/cx1 frompx/pw for overlaysi (see note). |
update_px(i) | Function to updatepx/pw fromcx0/cx1 for overlaysi (see note). |
Note: Fields marked "read-only" above should not be changed. Other fields canbe changed in your reactive code and this will modify the overlays and theirproperties. The fieldspx andpw which specify the pixel coordinates ofeach overlay can be modified, but any modifications should be placed in ashiny::isolate() call, with a call toov$update_cx(i) at the end toupdatecx0 andcx1 and apply snapping. Similarly, the fieldscx0 andcx1 which specify the plot coordinates of each overlay can bemodified, but modifications should be placed in ashiny::isolate() callwith a call toov$update_px(i) at the end to updatepx andpwand apply snapping. Thei parameter to these functions can be left outto apply changes to all overlays, or you can pass in the indices of justthe overlay(s) to be updated.
snap parameter
If you provide your own coordinate snapping function (snap argument), itshould have the signaturefunction(ov, i) whereov is theshiny::reactiveValues() object defining the overlays and their settings,andi is the set of indices for the rectangles to be updated. When theposition of any of the overlays is changed, the snapping function will beapplied. In this function, you should make sure that allov$cx0[i] andov$cx1[i] are within the coordinate bounds defined by the plot, i.e.constrained byov$bound_cx andov$bound_cw, when the function returns.This means, for example, if you are "rounding down"ov$cx0[i] to somenearest multiple of a number, you should make sure it doesn't become lessthanov$bound_cx. Finally, the snapping function will get triggered whenthe x axis range of the plot changes, so it may be a good idea to provideone if the user might place an overlay onto the plot, but then change the xaxis range of the plot such that the overlay is no longer visible. You candetect this by verifying whether the overlay rectangles are "out of bounds"at the top of your snapping function. See the code forsnapGrid() forideas.
Overlay dropdown menu
Overlays have a little icon in the top-right corner (by default, a gear).When the user clicks on this icon, a dropdown menu appears that allows theuser to remove the overlay. You can also provide additional components forthis dropdown menu by using theheading,select, andmenu parameterstooverlayServer().
heading: This should be a function with the signaturefunction(ov, i)whereov is theshiny::reactiveValues() object defining the overlays andtheir settings, andi is the (single) index for the current overlay. Thefunction should return a character string that will be used as the headingon thedropdown menu. This can be used to e.g. report the precise start andend point of the overlay, which may be useful to your users. The built-infunctionsrangeHeading() anddateHeading() can be used for numericvalues and date values on the x-axis, respectively. Or you can useNULLfor no heading on the dropdown menu.
select: This can beTRUE to provide ashiny::selectInput() widgeton the dropdown menu that users can use to change the type (i.e. label) ofthe current overlay. Or you can provide a character vector to restrict thewidget to specific labels, or useNULL to omit this widget.
menu: This can be a function with the signaturefunction(ov, i)whereov is theshiny::reactiveValues() object defining the overlays andtheir settings, andi is the (single) index for the current overlay. Itshould return UI component(s) (if multiple components, wrapped in alistortagList) that will be inserted into the dropdown menu. If you give theinput widgets special IDs, the user can use those input widgets to directlymodify certain properties of the overlays:
inputId | Modifies |
*_label | The label of the overlay currently being edited. |
*_cx0 | Starting x-coordinate of overlay. |
*_cx1 | Ending x-coordinate of overlay. |
*_cx | X-position of overlay; this is likecx0, but also updatescx1 to keep the same width. |
*_cw | Width of overlay; this adjustscx1 so that the overlay has the given width. |
*_XYZ | The corresponding entry "XYZ" indata for the overlay being edited. |
Note: above,* stands for theoutputId argument tooverlayServer(). |
See examples for an illustration of this.
See Also
overlayPlotOutput(),overlayBounds()
Examples
ui <- shiny::fluidPage( overlayPlotOutput("my_plot", 640, 480), overlayToken("add", "Raise") # further UI elements here . . .)server <- function(input, output) { menu <- function(ov, i) { sliderInput("my_plot_amount", "Raise amount", value = ov$data$amount[i], min = 0, max = 1) } ov <- overlayServer("my_plot", 4, 1, data = list(amount = 0.2), snap = snapGrid(step = 0.1), heading = rangeHeading(digits = 3), menu = menu) output$my_plot <- shiny::renderPlot({ df <- data.frame(x = seq(0, 2 * pi, length.out = 200)) df$y <- (1 + sin(df$x)) / 2 for (i in which(ov$active)) { xi <- (df$x >= ov$cx0[i] & df$x <= ov$cx1[i]) df$y[xi] <- df$y[xi] + ov$data$amount[i] } plot(df, type = "l") overlayBounds(ov, "base") }) # further server code here . . .}if (interactive()) { shiny::shinyApp(ui, server)}Create an overlay token input control
Description
Create a token that can be dragged onto anoverlay plotto create a new overlay.
Usage
overlayToken(id, name, label = name)Arguments
id | A unique ID for the token (a character string without spaces). |
name | Text (or HTML) to be displayed on the token itself. |
label | Text label that will appear on the overlay. |
Details
Note that the DOM ID of the token will be converted to"overshiny_token_<id>". This transformed ID is important for internalinteraction logic (e.g. for use with JavaScript drag/drop handlers). Whenreferencing the token programmatically (e.g. in CSS selectors or customJavaScript), use the full prefixed ID (see examples).
Value
An overlay token input control that can be added to a UI definition.
See Also
overlayServer(), for a complete example.
Examples
ui <- shiny::fluidPage( useOverlay(), overlayToken("add", "Add new overlay", "Overlay"), # The token's HTML id will be "overshiny_token_add" shiny::tags$style(shiny::HTML("#overshiny_token_add { cursor: grab; }")))Headings for overlay dropdown menus
Description
Use a call to one of these functions as theheading parameter ofoverlayServer() to provide a heading on the overlay dropdown menureporting the start and end position of the overlay. For numbers, theheading fromrangeHeading() will be e.g. "1.5 - 3.5". For dates, theheading fromdateHeading() will be e.g. "2025-05-01 - 2025-06-01".
Usage
rangeHeading(..., sep = " - ")dateHeading(format, ..., sep = " - ")Arguments
... | Further arguments to be passed to |
sep | A separator that will be inserted between the start and endposition of the overlay. Use |
format | For |
Value
A heading function suitable to pass tooverlayServer() as theheading argument.
See Also
overlayServer(), for a complete example.
Examples
server <- function(input, output) { ov <- overlayServer("my_plot", 8, heading = dateHeading("%b %d")) # further server code here . . .}Adjust margins of a ggplot2 plot
Description
To avoid the overlay rectangles moving around when the plot margins change,you can use this function to set specific margins for your plot. You willprobably want to specify a large enough margin so that the axes and legendsdon't go out of the plot area.
Usage
remargin(g, t, r, b, l, unit = "npc")Arguments
g | A |
t,r,b,l | Top, right, bottom, and left margins to set. |
unit | Unit for the margins (see |
Details
Note that this only works withggplot2 plots. For base plots, you can setthe margins usingpar(plt = c(x1, x2, y1, y2)). Seegraphics::par() fordetails.
Value
Aggplot2 plot with margins adjusted.
Examples
plot1 = ggplot2::ggplot(data.frame(x = rnorm(10), y = rnorm(10))) + ggplot2::geom_point(ggplot2::aes(x, y))plot2 = remargin(plot1, 0.1, 0.1, 0.1, 0.1) # plot with 10% margins all aroundSnap overlays to a grid
Description
Use a call to this function as thesnap parameter ofoverlayServer() toenable a simple snap-to-grid behaviour for your overlay. It will ensure youroverlays stay within the bounds of the plot, and snap both position andwidth of each overlay to the specified grid.
Usage
snapGrid(anchor = 0, step = 1, min_width = NA, max_width = NA)Arguments
anchor | The location of any specific gridline. |
step | The space between gridlines. |
min_width | (optional) Minimum width of an overlay; default ( |
max_width | (optional) Maximum width of an overlay; default ( |
Details
Note that you do not pass justsnapGrid tooverlayServer(), but e.g.snapGrid() orsnapGrid(step = 0.1). The default values snap overlays towhole numbers.
Value
A snapping function suitable to pass tooverlayServer() as thesnap argument.
See Also
overlayServer(), for a complete example.
Examples
server <- function(input, output) { ov <- overlayServer("my_plot", 8, snap = snapGrid()) # further server code here . . .}Manually set up a Shiny app to use overshiny
Description
overshiny will set up automatically if you have anoverlayPlotOutput()anywhere in your Shiny UI, which you probably do if you are using thispackage. But if you don't, you can set upovershiny by manually puttinguseOverlay() somewhere in your Shiny app's UI.
Usage
useOverlay()Details
This also callsshinyjs::useShinyjs(), asovershiny depends onshinyjs.
Value
Returns an HTML dependency that sets up your Shiny app to useovershiny.
See Also
overlayServer(), for a complete example.
Examples
ui <- shiny::fluidPage( useOverlay() # only needed if no overlayPlotOutput() elements below # further UI elements here . . .)server <- function(input, output) { # server code here . . .}if (interactive()) { shiny::shinyApp(ui, server)}