overshiny
provides draggable and resizable rectangular
elements that overlay plots in Shiny apps. This may be useful in
applications where users need to define regions on the plot for further
input or processing. Currently, the overlays are only designed to move
along the x axis of the plot.
overshiny
is under active development. There are some
missing features.
Missing features:
You can install the development version of overshiny from GitHub with:
# install.packages("devtools")
::install_github("nicholasdavies/overshiny") devtools
This example shows the basic functionality of
overshiny
:
library(shiny)
library(ggplot2)
library(overshiny)
# --- User interface ---
<- fluidPage(
ui # Load overshiny
useOverlay(),
# Lighten the sidebar background
$head(tags$style(".well { background-color: white }")),
tags
titlePanel("Overlay demo"),
sidebarLayout(
sidebarPanel(
# Control whether overlays are displayed and whether they alter the plot
checkboxInput("show_overlays", "Show overlays", value = TRUE),
checkboxInput("enable_logic", "Enable overlay logic", value = TRUE),
$hr(),
tags
# Select date range for the plot
dateRangeInput("date_range", "Date range", start = "2025-01-01", end = "2025-12-31"),
$hr(),
tags
# Overlay controls: tokens that can be dragged onto the plot
h5("Drag tokens below onto the plot:"),
overlayToken("grow", "Grow"),
overlayToken("shrink", "Shrink")
),
mainPanel(
# Main plot with support for overlays
overlayPlotOutput("plot", width = "100%", height = 300)
)
)
)
# --- App logic ---
<- function(input, output, session)
server
{# --- OVERLAY SETUP ---
# Initialise 8 draggable/resizable overlays
<- overlayServer("plot", 8, width = 56) # 56 days = 8 weeks default width
ov
# Reactive values to store custom per-overlay settings
<- reactiveValues(
opt type = rep("Grow", 8), # type of overlay action
strength = rep(50, 8) # strength as a percentage
)
# Toggle overlay visibility based on checkbox
observe({
$show <- isTRUE(input$show_overlays)
ov
})
# --- OVERLAY DROPDOWN MENU ---
# Render dropdown menu when an overlay is being edited
$plot_menu <- renderUI({
output<- req(ov$editing) # Current overlay being edited
i tagList(
textOutput("dates"),
selectInput("type", NULL, choices = c("Grow", "Shrink"), selected = ov$label[i]),
sliderInput("strength", "Strength", min = 0, max = 100, value = opt$strength[i])
)
})
# Display date range for the currently edited overlay
$dates <- renderText({
output<- req(ov$editing)
i <- function(t) format(as.Date(round(t), origin = "1970-01-01"), "%b %d")
fmt paste(fmt(ov$cx0[i]), "–", fmt(ov$cx1[i]))
})
# Update stored strength when the slider changes
observeEvent(input$strength, {
<- req(ov$editing)
i $strength[i] <- input$strength
opt
})
# Update stored type and overlay label when dropdown changes
observeEvent(input$type, {
<- req(ov$editing)
i $type[i] <- input$type
opt$label[i] <- input$type
ov
})
# --- DATA PROCESSING BASED ON OVERLAY POSITION ---
# Reactive dataset: oscillating signal modified by active overlays
<- reactive({
data <- seq(input$date_range[1], input$date_range[2], by = "1 day")
date_seq <- 1 + 0.5 * sin(as.numeric(date_seq) / 58) # oscillating signal
y
# Modify signal according to active overlays if logic is enabled
if (isTRUE(input$enable_logic)) {
for (i in which(ov$active)) {
<- as.Date(round(ov$cx0[i]), origin = "1970-01-01")
start <- as.Date(round(ov$cx1[i]), origin = "1970-01-01")
end <- date_seq >= start & date_seq <= end
in_range <- opt$strength[i] / 100
factor <- y[in_range] * if (ov$label[i] == "Grow") (1 + factor) else (1 - factor)
y[in_range]
}
}
data.frame(date = date_seq, y = y)
})
# --- RENDERING OF DATA ---
# Render plot and align overlays to current axis limits
$plot <- renderPlot({
output<- ggplot(data()) +
plot geom_line(aes(x = date, y = y)) +
ylim(0, 3) +
labs(x = NULL, y = "Signal")
overlayBounds(ov, plot,
xlim = c(input$date_range),
ylim = c(0, NA))
})
}
# --- Run app ---
shinyApp(ui, server)