rustgd

Native plot, data frame, and HTML viewer windows for R sessions that live in a terminal or a lean editor.

rustgd alongside Zed Editor

What it is

rustgd gives a plain R session the three things a full IDE would normally hand you: a graphics window for plots, a spreadsheet-style window for data frames, and a web window for HTML widgets and Shiny apps. The viewers are native desktop windows written in Rust, launched directly from R, and bundled inside the package, so once it is installed there is nothing else to set up.

It is built for the way many people actually run R day to day: radian in a terminal, and/or an editor such as Zed or Neovim driving an R process that has no built-in panes. In those setups a plot() has nowhere to go, View() is missing or clumsy, and printing a leaflet map or a plotly chart throws you out to a browser tab. rustgd closes that gap.

Why it was made

RStudio and Positron ship with a Plots pane, a data viewer, and an HTML Viewer pane. Terminal and editor workflows do not. If you would rather work in radian and a modern editor than in a full IDE, you give those panes up, and the usual fallbacks (e.g., saving plots to disk, opening data in a pager, bouncing widgets through the browser) are a poor substitute for a window that simply appears when you draw something.

rustgd exists to get those windows back without adopting an IDE. The rendering and table handling are done in Rust rather than in R, which keeps the windows fast and the runtime footprint small.

The three viewers

Plots

Cycling through plots in the rustgd viewer

rustgd registers a real R graphics device. Every plot(), hist(), base-graphics build-up, or printed ggplot renders into a dedicated window. The window keeps a gallery of every plot you draw in the session, so you can page back and forth with the toolbar or the arrow keys, zoom and pan into a plot, and export the current one to PNG or SVG. It follows your system light or dark setting, and it re-renders on resize so a plot stays sharp at any window size rather than being stretched.

Data frames

mtcars in the rustgd frames window

View(df) opens a fast, scrollable table. Columns sort, resize, and filter, with a level checklist for factors, a contains box for text, and a min and max range for numeric columns; the row count updates as filters narrow the data. A Summary panel reports per-column statistics such as missing count, unique count, and a type-appropriate breakdown over what is currently shown. Every frame you view stays loaded, so paging back to an earlier one restores its sort, selection, and scroll position. The current view, filtered and in its current order, exports to Arrow, CSV, or Excel.

Both capitalized View() and lowercase view() open this window, including the view() that tibble exports, so the table appears whichever one you reach for. Cells are shown the way R stores them rather than the way Arrow happens to format them, so a value read off the table can be pasted straight into a filter: logicals read TRUE/FALSE, and a difftime reads as its plain numeric value in the column's own units (with the unit in the header). The CSV and Excel exports follow the same rule. Because View() and view() are ordinary package exports, they stay active for as long as rustgd is attached; detaching the package restores R's own View().

HTML and web content

A leaflet map in the rustgd web window

The web viewer takes over R's HTML viewer and Shiny launcher, so htmlwidgets (plotly, leaflet, dygraphs, and the like) and Shiny apps open in a native window instead of a browser tab. Each widget is copied into a per-session folder so the window does not depend on R's temporary files, and widgets accumulate into a gallery you can page through, export, or clear.

A widget rendered in the rustgd web window

For anything that already lives at a live address, a Shiny app, a local dashboard, or a dev server, rustgd_browse(url) points the same window straight at it.

How it works

Under the hood rustgd is an R package with a Rust core built using extendr. The plot device is a true R graphics device compiled into the package; it serializes each page to SVG and hands it to a separate viewer process through a per-session temporary directory. That same directory is how the window signals resizes back to R, which is what lets the device replay a plot at the new size instead of scaling a bitmap.

The data frame and web viewers are two more small native binaries. Both View() and the lowercase view() (the latter also exported by tibble) are exported functions that write your data as Apache Arrow and feed the table window, and R's viewer and shiny.launch.browser options are pointed at the web binary so widgets and apps route there automatically. All three binaries are compiled when the package builds and shipped inside it, so there is nothing extra to download or launch at runtime. The windows open lazily, the first time you actually draw a plot, view a frame, or show a widget.

Installation

From R-universe (recommended)

A prebuilt binary, no compiler required:

install.packages("rustgd",
  repos = c("https://alcocer-jj.r-universe.dev",
            "https://cloud.r-project.org"))

From GitHub (source)

This compiles on your machine, so it needs a Rust toolchain (cargo and rustc, easiest via rustup):

# install.packages("remotes")
remotes::install_github("alcocer-jj/rustgd")

rustgd requires R 4.2 or newer. Prebuilt binaries are served for macOS and Windows on the current R release and the previous one. On Linux, install from source; the windows use the system's standard desktop graphics and WebKit libraries.

rustgd does not run under WebAssembly or webR. The viewers are native desktop windows, so a browser-based R session has nothing to open.

Turning it on and off

Attaching the package makes the data-frame viewer live immediately, so View(df) and view(df) open the rustgd table with no further setup:

library(rustgd)

The plot device and the web viewer are opt-in, since turning them on replaces R's graphics device and HTML viewer for the session. Switch them on and off for the current session with:

rustgd_enable()
rustgd_disable()

To carry all three viewers into future sessions automatically, use use_rustgd(). It turns on the plot device and web viewer now and offers to add a one-line activation snippet to your ~/.Rprofile; the snippet attaches the package (so View() and view() come with it) and enables the plot and web viewers, restoring the full suite at startup. It asks first and writes only if you confirm, so nothing touches your startup file without your say-so:

use_rustgd()

unuse_rustgd() deactivates the session and, if that snippet is present, offers to remove it from your ~/.Rprofile:

unuse_rustgd()

Both prompts appear only in interactive sessions; Rscript, R CMD BATCH, knitr, and package checks never read from or write to your .Rprofile.

use_rustgd() takes a mode argument that affects only the plot window. The default, "lazy", registers the device so the window opens the first time you draw a plot, the same way base R's quartz and X11 behave. Pass "eager" to open a plot window straight away, before you plot anything:

use_rustgd(mode = "eager")

Because View() and view() are ordinary package exports, they remain active for as long as rustgd is attached. rustgd_disable() and unuse_rustgd() turn off the plot device and the web viewer but leave the table viewer in place; to restore R's own View(), detach the package with detach("package:rustgd").

And to open a live URL in the web window:

rustgd_browse("http://127.0.0.1:4321")

License

MIT. See LICENSE.