Start with the hosted gallery to explore what each module can do: https://j-andrews7-VizModules.share.connect.posit.cloud/
You can also run the same gallery locally from this package. Each tab opens a module on an example dataset with its main features switched on, and the Figure Builder tab combines several modules into one multi-panel figure:
Each module’s own example app
(e.g. plotthis_BoxPlotApp()) opens on the same example as
its gallery tab.
VizModules ships three Agent Skills that hand an agent the package’s conventions up front, rather than having it grep the docs for them. Install them into your project with:
VizModules::use_vizmodules_skills(".") # .agents/skills/ (OpenAI Codex, GitHub Copilot)
VizModules::use_vizmodules_skills(".", client = "copilot") # .github/skills/ (GitHub Copilot)
VizModules::use_vizmodules_skills(".", client = "claude") # .claude/skills/ (Claude Code)vizmodules-app covers what this
vignette does: wiring modules into an app, defaults,
hide.inputs/hide.tabs, the Stats tab,
createModuleApp(), the data filter table, the figure
builder, and source-data export. It carries a generated inventory of
every module’s column-mapping keys, colour key, and tab names, which is
otherwise the most expensive thing for an agent to look up.vizmodules-custom-module covers
building a wrapper module on top of a base module; see
vignette("custom-modules", package = "VizModules").vizmodules-new-module covers authoring
a module inside this package; see
vignette("adding-a-new-module", package = "VizModules").Restart your agent session after installing so the new directory is picked up. The README has a plain-text prompt for tools that cannot read local skill files.
All modules follow the same pattern: *InputsUI() for
controls, *OutputUI() for the plot, and
*Server() for the logic. Here is a minimal scatter plot
example using the dittoViz_scatterPlot module:
library(VizModules)
# The same defaults go to the controls and the server, so Reset returns to them.
cars_defaults <- list(x.by = "wt", y.by = "mpg", color.by = "cyl")
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
dittoViz_scatterPlotInputsUI("cars", mtcars, defaults = cars_defaults)
),
mainPanel(dittoViz_scatterPlotOutputUI("cars"))
)
)
server <- function(input, output, session) {
dittoViz_scatterPlotServer("cars", data = reactive(mtcars), defaults = cars_defaults)
}
shinyApp(ui, server)defaults argument of *InputsUI() to pre-fill
inputs, and the same list to the module’s *Server() so its
Reset button returns to them. Names are the module’s input IDs, which
mostly match the underlying plot function’s arguments (e.g.,
defaults = list(color.by = "cyl", size = 3) for the scatter
plot).reactive() instead of a fixed value, so an input follows
your app’s state
(e.g. defaults = list(color.by = reactive(input$colour_col))).
See
vignette("defaults-and-hiding", package = "VizModules").hide.inputs in the
server call to remove controls while still initializing their values.
This is useful when your app sets certain parameters itself or wants to
hide control of various elements while still passing their initial
values.hide.tabs to remove
whole groups of controls (e.g., "Plotly" or
"Legend" in scatterPlot).server <- function(input, output, session) {
dittoViz_scatterPlotServer(
"cars",
data = reactive(mtcars),
hide.inputs = c("split.by", "shape.by"),
hide.tabs = c("Plotly")
)
}Hidden inputs and tabs still feed their values into the plot, so the module stays fully configured while exposing only what your users need.
createModuleApp()To enable simple, consistent testing of any module, we provide an app
factory function that returns a full standalone app with data import, a
filterable data table, and dataset switching for any module -
createModuleApp():
library(VizModules)
app <- createModuleApp(
inputs_ui_fn = plotthis_BarPlotInputsUI,
output_ui_fn = plotthis_BarPlotOutputUI,
server_fn = plotthis_BarPlotServer,
data_list = list("cars" = example_mtcars),
title = "My Bar Plot"
)
if (interactive()) runApp(app)All built-in *App() convenience functions
(e.g. plotthis_BarPlotApp(), linePlotApp())
are thin wrappers around createModuleApp() with sensible
default data. You can also pass custom wrapper module functions to
createModuleApp() for rapid prototyping.
We provide collect_source_data() to assemble a compact
record of the plotted data, stats, UI inputs, and the rendered plot, and
create_source_download_handler() to turn that record into a
downloadable .zip. collect_source_data()
requires a reactive plotly plot; the output summary can be optionally
enriched by both a stats reactive and a UI inputs reactive.
create_source_download_handler() also accepts a named list
of summaries (one per plot), which is how the Figure Builder bundles
every plot on its canvas into a single download.
The .zip also carries an SVG and a PNG of each plot.
Those are photographed in the browser, off the graph the user is looking
at, so they match it exactly – including everything applied after the
figure was built, such as reference lines, statistical brackets and
dragged annotations. A module whose output is not a plotly graph has
nothing to photograph and supplies its own instead, by putting a
vector_svg and/or raster_png function of
(width, height, res) on its summary list;
draw_to_svg() and draw_to_png() build one from
any grid or base drawing.
if (interactive()) {
library(shiny)
library(plotly)
ui <- fluidPage(
plotlyOutput("plot"),
downloadButton("download_summary", "Download Summary")
)
server <- function(input, output, session) {
# A reactive plotly plot
plot_reactive <- reactive({
plot_ly(mtcars, x = ~wt, y = ~mpg, type = "scatter", mode = "markers")
})
# Optional: a reactive returning a stats data.frame
stats_reactive <- reactive({
data.frame(
metric = c("mean_mpg", "sd_mpg"),
value = c(mean(mtcars$mpg), sd(mtcars$mpg))
)
})
# Optional: capture all UI inputs as a named list
AllInputs <- reactive({
reactiveValuesToList(input)
})
output$plot <- renderPlotly(plot_reactive())
# Assemble the summary, then wire up the download handler.
plot_summary_reactive <- reactive({
collect_source_data(
plot_reactive = plot_reactive,
stats_reactive = stats_reactive,
inputs_reactive = AllInputs()
)
})
output$download_summary <- create_source_download_handler(
data_list = plot_summary_reactive,
filename_base = "my_plot_summary"
)
}
shinyApp(ui, server)
}Modules wrap plotting functions from dittoViz, plotthis, and native plotting functions. To see which arguments are available in a module:
?dittoViz_scatterPlotInputsUI or
?plotthis_AreaPlotInputsUI. The Details
section notes which arguments from the underlying plot function are
wired through and any that are intentionally omitted.?dittoViz::scatterPlot, ?plotthis::AreaPlot,
etc.). Input names in defaults line up with those function
arguments when they are supported.If an argument is listed as missing or non-functional in the module docs, it has been intentionally hidden because it does not round-trip well in the interactive Plotly output or is simply unnecessary due to plotly functionality.