sideview: Explore and Join Many Tables on a Zoomable Canvas sideview hex logo

sideview puts many tables side by side on a pan-and-zoom canvas, so you can compare them, connect columns to build joins, check those joins before you run them, and take away reproducible tidyverse code. It runs as an RStudio gadget or as an htmlwidget you can save to HTML or embed in Quarto and R Markdown.

The sideview canvas: four tables side by side, with a minimap, toolbar and AI bar

Take the visual tour to see every feature in a screenshot.

Installation

Install from r-universe (binaries for Windows and macOS):

install.packages("sideview", repos = c("https://lauyeehow1986-hub.r-universe.dev", "https://cloud.r-project.org"))

Or install the development version from GitHub:

# install.packages("remotes")
remotes::install_github("lauyeehow1986-hub/sideview")

Key Features

Quick Start

library(sideview)

patients <- data.frame(
  patient_id = c("P01", "P02", "P03", "P04"),
  age        = c(45, 52, 38, 61),
  sex        = c("Male", "Female", "M", "Fem")
)
visits <- data.frame(
  patient_id  = c("P01", "P02", "P03", "P05"),
  systolic_bp = c(120, 140, 115, 130)
)

# 1. Open the canvas (RStudio dialog by default; also viewer = "pane" or "browser")
if (interactive()) {
  sideview(patients, visits)
}

# 2. Check a join before you run it
sv_join_diagnostics(patients, visits, by = "patient_id",
                    x_name = "patients", y_name = "visits")

# 3. Build a data dictionary across tables
sv_codebook(patients, visits)

# 4. Share the canvas as a standalone HTML file
save_sideview(sideview_widget(patients, visits), file = "study_overview.html")

To embed the canvas in Quarto or R Markdown, put sideview_widget(patients, visits, height = "650px") in a chunk.

In your own Shiny app

sideviewUI() and sideviewServer() put an R-backed canvas into any Shiny app, several per page. Sorting, filtering, lazy arrow/duckdb tables, the join check and the column inspector run in R, as in the gadget. The server adds, replaces and removes tables through a proxy and reads back what the user built:

library(shiny)
library(sideview)

ui <- fluidPage(
  actionButton("refresh", "Refresh labs"),
  sideviewUI("review", height = "560px"),
  verbatimTextOutput("code")
)
server <- function(input, output, session) {
  px <- sideviewServer("review", cards = list(visits = visits, labs = labs_now()))
  observeEvent(input$refresh, {
    px <- sideviewProxy("review")
    sv_replace_card(px, "labs", labs_now())
    sv_highlight(px, "labs", "lab_date")
  })
  output$code <- renderText(px$code())
}
shinyApp(ui, server)

A replace keeps the card where it is; steps that name a column the new table lacks are disabled, not deleted, and one toast says so. px$code(), px$pipeline(), px$state() and px$cards() are reactives. Insert Script, Run & Exit, Run in R and Run Console are off in a module, because any visitor to a deployed app could forge the code they would run. $code() is composed in the browser: treat it as untrusted text to show, save or review, and never eval() it unattended. A complete app with two canvases is in system.file("examples/proxy", package = "sideview").

sideview is a research and education tool for exploring and preparing data. It is not medical device software and is not intended for clinical decisions.