vizRd is a zero-code R package and Shiny app for turning a project folder of tabular data into shareable visualizations. Put data in data/, add an optional vizrd.yml, and launch the app without editing package code.
Online documentation is intended to live at https://davidzenz.github.io/vizRd/.
What it does
- Launches Shiny visualizations from a project folder.
- Preserves template dashboards for
iso3/time/metric/value data. - Adds a generic explorer for arbitrary
.csvand.rdstabular data. - Builds embeddable URLs and supports compact iframe mode with package-local resize messaging.
- Provides share URLs, reproducible JSON snapshots, copyable iframe snippets, and a browseable gallery route for project datasets.
- Keeps the v1.2 area work on ggplot2 + ggiraph so existing hover, click detail, export, embed, visible chart hints/detail copy, and CRAN-friendly package behavior stay on the proven renderer stack.
Quick start
Install the package locally from the repository root:
install.packages(".", repos = NULL, type = "source")Inspect the packaged example project:
library(vizRd)
example_path <- system.file("extdata", "example_project", package = "vizRd")
vizRd::list_datasets(example_path)Launch it when working interactively:
if (interactive()) {
vizRd::run_app(path = example_path)
}For your own project, create a folder with data/ and optional vizrd.yml, then run:
if (interactive()) {
vizRd::run_app(path = "path/to/project")
}Template dashboards
Template dashboards are for structured indicator-style data. A template dataset uses these columns by default:
iso3 | year or date | variable | value
Template mode powers map, bars, line, scatter, and area views. Optional metadata can supply labels and titles through attr(df, "var_labels"), attr(df, "app_title"), variable_label, or dataset_title.
The packaged example keeps configured template datasets such as excises and marlboro in inst/extdata/example_project/data/.
Area views support absolute stacked values and area_mode = "percent" for 100% stacked mode when the displayed values are complete, finite, non-negative, and have a positive total in every time period. Invalid percent states fall back to absolute values with compact guardrail copy instead of normalizing misleading data. High-cardinality area data use deterministic Top-N plus Other aggregation, and area_series isolates displayed series after that contract so named series and the generated Other group can be shared or embedded without reranking the data.
Detailed renderer and area evidence is maintained in the maintainer article Renderer and Area Release Evidence (vignettes/renderer-area-release-evidence.Rmd); the README keeps only the user workflow summary.
Generic explorer
Generic explorer mode is for arbitrary tabular data. Drop a .csv or .rds file into data/ and vizRd infers column roles such as numeric, categorical, date/time, logical, text, or unknown. The app opens with an overview first, then enables eligible analytic chart families such as scatter, count, time series, aggregate, boxplot, and missingness.
The packaged example includes generic_sales.csv, a small CSV that is not template-shaped and is auto-discovered as explorer data.
Sharing, snapshots, and gallery
Every active state exposes Actions for sharing and reproducibility. Share URL is a read-only URL for the current template dashboard or generic explorer selection. Download snapshot writes JSON metadata with package version, dataset identity, selected controls, filters, warnings, timestamp, and share state.
Build share URLs directly from R:
vizRd::build_share_url(
base_url = "https://example.org/vizrd/",
dataset = "generic_sales",
chart = "scatter",
numeric = "units",
numeric2 = "revenue"
)Template area states can be shared the same way with build_share_url(). geos narrows the candidate series before Top-N plus Other aggregation; area_series records the displayed series after aggregation and can include the generated Other label.
vizRd::build_share_url(
base_url = "https://example.org/vizrd/",
dataset = "excises",
view = "area",
metric = "total_excise_duty_eur_1_000",
geos = c("AUT", "DEU", "FRA"),
area_mode = "absolute"
)
vizRd::build_share_url(
base_url = "https://example.org/vizrd/",
dataset = "excises",
view = "area",
metric = "total_excise_duty_eur_1_000",
area_mode = "percent",
area_series = c("AUT", "Other")
)Open ?gallery=1 on a running vizRd app to browse available datasets and copy ready-to-open share URLs or iframe snippets:
https://example.org/vizrd/?gallery=1
The packaged example project also serves /vizrd-project/share-uat.html on a running app. It provides preset template, generic, embed, stale-dataset, and stale-column share URLs for manual copy/paste checks.
Project structure
A minimal project looks like this:
my-project/
data/
metrics.rds
generic_sales.csv
vizrd.yml
www/
notes.pdf
vizrd.yml is optional for simple auto-discovered data, but useful for app titles, explicit dataset ordering, embedding defaults, basemap configuration, and export settings. See vignettes/project-structure.Rmd for the full layout.
Embedding with iframes
Use embed=1 to hide full-app chrome for iframe use while keeping required chart controls:
<iframe
id="vizrd-frame"
src="https://example.org/vizrd/?dataset=excises&view=area&metric=total_excise_duty_eur_1_000&geos=AUT%2CDEU&embed=1"
width="100%"
style="border:0; min-height:520px;"
loading="lazy"
></iframe>vizRd serves its child resize bridge from vizrd/vendor/open-iframe-resizer-core.js. The bridge emits vizrd:resize messages to the host page. A same-origin host can use:
<script>
window.addEventListener("message", function(event) {
var frame = document.getElementById("vizrd-frame");
if (!frame || event.source !== frame.contentWindow) {
return;
}
var data = event.data || {};
if (data.type === "vizrd:resize" && Number.isFinite(data.height)) {
frame.style.height = Math.min(10000, Math.max(320, data.height)) + "px";
}
});
</script>For cross-origin hosts, add a strict event.origin check. See vignettes/embedding.Rmd for same-origin iframe, cross-origin iframe, fixed-height fallback, and troubleshooting recipes.
Build embed URLs from R:
vizRd::build_embed_url(
base_url = "https://example.org/vizrd/",
dataset = "excises",
view = "area",
metric = "total_excise_duty_eur_1_000",
geos = c("AUT", "DEU", "FRA"),
area_mode = "percent",
area_series = c("AUT", "Other"),
embed = TRUE
)Or build the complete iframe snippet, including the host-side resize listener:
vizRd::build_iframe_snippet(
src = vizRd::build_share_url(
base_url = "https://example.org/vizrd/",
dataset = "generic_sales",
chart = "overview"
)
)Development checks
Maintainer release ladder
Run these commands from the repository root. rtk Rscript -e 'renv::status()' inspects dependency drift without editing files. Use rtk Rscript -e 'renv::restore(prompt = TRUE)' only when intentionally reconciling the project library with renv.lock.
rtk Rscript -e 'renv::status()'
rtk Rscript -e 'renv::restore(prompt = TRUE)'
rtk Rscript -e 'install.packages(".", repos = NULL, type = "source")'
rtk Rscript -e 'devtools::load_all()'Run focused, package-aware checks before broad checks. The devtools::test(filter = "runtime-adapters") command is the package-aware focused runtime-adapter command; raw testthat::test_file() is reserved here for static docs and E2E helper checks that do not need package internals.
rtk Rscript -e 'testthat::test_file("tests/testthat/test-docs-release.R")'
rtk Rscript -e 'devtools::test(filter = "runtime-adapters")'
rtk Rscript -e 'testthat::test_file("tests/testthat/test-e2e-helper.R")'
rtk Rscript -e 'devtools::test()'Browser E2E checks remain local and opt-in only. Run them only with both NOT_CRAN=true and VIZRD_E2E=true; ordinary package checks should skip browser startup when those variables or optional browser tools are unavailable.
Regenerate documentation, build a temporary pkgdown site, inspect the source tarball, and run the local as-CRAN check:
rtk Rscript -e 'devtools::document()'
rtk Rscript -e 'dir <- tempfile("vizrd-pkgdown-"); dir.create(dir); pkgdown::build_site(pkg = ".", override = list(destination = dir), preview = FALSE, new_process = FALSE, install = TRUE, quiet = FALSE)'
rtk Rscript -e 'tarball <- pkgbuild::build(".", dest_path = tempdir(), vignettes = TRUE, manual = FALSE); files <- utils::untar(tarball, list = TRUE); stopifnot(!any(grepl("^(vizRd/)?(\\.planning|\\.github|docs|renv|cran-comments\\.md|AGENTS\\.md|GEMINI\\.md)", files))); cat(tarball, "\n")'
rtk Rscript -e 'tarball <- pkgbuild::build(".", dest_path = tempdir(), vignettes = TRUE, manual = FALSE); Sys.setenv(`_R_CHECK_FORCE_SUGGESTS_` = "false"); rcmdcheck::rcmdcheck(tarball, args = "--as-cran", error_on = "never", check_dir = tempdir())'Optional dependency capability matrix
| Capability | Packages | Check | Missing behavior | Validation |
|---|---|---|---|---|
| Template maps | sf | requireNamespace("sf", quietly = TRUE) |
Map capability unavailable; missing {sf} must not count as true map coverage. | rtk Rscript -e 'devtools::test(filter = "runtime-adapters")' |
| Browser E2E | shinytest2, chromote, Chrome/Chromium |
NOT_CRAN=true VIZRD_E2E=true plus chromote::find_chrome()
|
Explicit skip before browser startup in ordinary checks. | rtk Rscript -e 'testthat::test_file("tests/testthat/test-e2e-helper.R")' |
| Export readiness | ragg, cowplot, magick, png | requireNamespace(..., quietly = TRUE) |
PNG/PDF handlers are Phase 21; missing packages should produce disabled-state or fallback messages, not check failures. | static docs tests in Phase 20; handler tests in Phase 21 |