library(rtemis.draw)
Attaching package: 'rtemis.draw'
The following object is masked from 'package:graphics':
Axis
Attaching package: 'rtemis.draw'
The following object is masked from 'package:graphics':
Axis
Important Note that this vignette has been built using the light theme. The page theme toggle will work partly to switch the chart theme, but the result is not the same as using the dark theme directly. When working with an IDE like VS Code, if you don’t define a theme, the function will auto-detect your system setting and apply the appropriate theme. See Themes for the details.
draw_* functions| Function | Chart |
|---|---|
draw_scatter() |
Scatter plot, optionally with fitted lines and confidence bands |
draw_line() |
Line and area charts |
draw_bar() |
Bar charts, vertical or horizontal, grouped or stacked |
draw_boxplot() |
Box plots, one or many variables, optionally grouped |
draw_histogram() |
Histograms, optionally grouped |
draw_density() |
Kernel density plots, optionally grouped |
draw_pie() |
Pie and Nightingale/rose charts |
draw_heatmap() |
Matrix heatmaps with optional clustering and dendrograms |
draw_sankey() |
Sankey flow diagrams |
draw_gantt() |
Timeline / Gantt charts |
draw_spectrogram() |
Time-frequency heatmaps from a signal or a matrix |
They share a common set of trailing arguments — title, theme, width, height, element_id, filename — and, where the chart is categorical, palette; where it encodes a quantity in color, colormap.
We’ll use the built-in penguins dataset. Let’s take a look at the variables:
'data.frame': 344 obs. of 8 variables:
$ species : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
$ island : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
$ bill_len : num 39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
$ bill_dep : num 18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
$ flipper_len: int 181 186 195 NA 193 190 181 195 193 190 ...
$ body_mass : int 3750 3800 3250 NA 3450 3650 3625 4675 3475 4250 ...
$ sex : Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
$ year : int 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...
Input: Single numeric vector
Note:
NAs, prints a message, and excludes them from the plotYou can define a custom label either by passing a named list/data.frame or by using the labels argument:
2026-08-18 16:38:07 Removed 2 NA values [FUN]
2026-08-18 16:38:07 Removed 2 NA values [FUN]
Input can be a list of any number of numeric vectors:
2026-08-18 16:38:07 Removed 2 NA values [FUN]
2026-08-18 16:38:07 Removed 2 NA values [FUN]
or a data.frame:
2026-08-18 16:38:07 Removed 2 NA values [FUN]
2026-08-18 16:38:07 Removed 2 NA values [FUN]
2026-08-18 16:38:07 Removed 2 NA values from data [boxplot_option]
Use the breaks argument to control binning — it accepts any value accepted by graphics::hist(): a number of bins, a character algorithm name, or an explicit vector of break points:
2026-08-18 16:38:07 Removed 2 NA values from x [density_option]
2026-08-18 16:38:07 Removed 2 NA values from x [density_option]
2026-08-18 16:38:08 Removed 2 NA values from Body Mass [FUN]
Pass fit = "gam" (or "glm") to overlay a fitted line with a 95% confidence band:
Fit lines and confidence bands are drawn per group and share the group’s color. Clicking a legend entry toggles the scatter points, fit line, and band together:
Two arguments control the geometry of the plot rather than its content:
square makes the plotting box itself square — the box, excluding axis labels and margins.equal_axes gives one data unit the same size in pixels on both axes.Set together they also say something about the limits, since the only square box with equal scaling is one whose axes span the same interval: both axes are put on one common interval derived from all the values, or from whichever limit you gave. This is the true-versus-predicted and ROC case, where the identity line has to run at 45 degrees to be read correctly.
The box is solved in the browser, which is the only side that knows the container width, and re-solved on every resize — so it stays square as the page reflows. draw_line() takes the same two arguments; an identity line drawn with it lands at exactly 45 degrees:
Giving xlim and ylim as different intervals alongside both flags is an error rather than a silent override.
Pass a named list to y to draw one line per element:
Set rose_type = "radius" to encode value as radius instead of arc angle:
draw_sankey() takes a data frame of directed links with source, target, and value columns. Node names are derived from the unique values of source and target; no separate node list is needed.
source target value
1 Adelie female 73
2 Chinstrap female 34
3 Gentoo female 58
4 Adelie male 73
5 Chinstrap male 34
6 Gentoo male 61
Flows can chain through any number of columns — a node that is a target in one row and a source in another simply sits in the middle:
size_class <- ifelse(penguins$body_mass > 4200, "Large", "Small")
chain <- rbind(
as.data.frame(
table(source = penguins$species, target = penguins$sex),
responseName = "value"
),
as.data.frame(
table(source = penguins$sex, target = size_class),
responseName = "value"
)
)
chain <- chain[chain$value > 0, ]
draw_sankey(chain, node_align = "justify")orient = "vertical" flows top to bottom, and node_width, node_gap, and node_align tune the layout:
draw_heatmap() accepts any numeric matrix. For square matrices, square_cells is enabled automatically so every cell is perfectly square.
Set zlim = c(-1, 1) to fix the color scale to the full correlation range:
For symmetric matrices it is common to show only one triangle. Use triangle = "lower" to keep the lower triangle and diagonal, masking the upper triangle:
Set show_values = TRUE to print each correlation coefficient inside its cell. value_digits controls the number of decimal places:
cluster_rows and cluster_cols reorder the matrix using hclust(), grouping similar rows and columns together:
For rectangular matrices, set square_cells = FALSE. Here we compute the mean of each trait per species and z-score the columns so traits on different scales are directly comparable:
traits <- c("bill_len", "bill_dep", "flipper_len", "body_mass")
means <- sapply(
traits,
function(tr) tapply(penguins[[tr]], penguins$species, mean, na.rm = TRUE)
)
colnames(means) <- c("Bill Length", "Bill Depth", "Flipper Length", "Body Mass")
draw_heatmap(
scale(means),
square_cells = FALSE,
show_values = TRUE,
value_digits = 2,
title = "Mean Traits by Species (z-scored)"
)draw_spectrogram() renders an interactive time–frequency heatmap. Pass a raw numeric signal vector together with sample_rate; the function computes the STFT internally via signal::specgram(). Alternatively pass a pre-computed spectrogram matrix directly.
All examples below use synthetic signals so no external data is required.
A chirp sweeps linearly from a low to a high frequency. The spectrogram makes the sweep immediately visible as a diagonal ridge:
Three simultaneous sine waves appear as three horizontal bands — one per frequency:
Use freq_scale = "log" to expand the low-frequency region — useful when the signal of interest spans several octaves. freq_unit = "kHz" and time_unit = "ms" rescale the axis labels:
For signed data — such as an Event-Related Spectral Perturbation (ERSP) matrix from an EEG experiment — use colormap = "diverging". The midpoint color maps exactly to zero. Set db = FALSE because the values are already on a meaningful signed scale:
set.seed(1)
n_freq <- 60
n_time <- 120
freq <- seq(4, 80, length.out = n_freq) # 4 – 80 Hz
time <- seq(-0.5, 1.5, length.out = n_time) # −500 ms to +1500 ms
# Background: small random fluctuations
ersp <- matrix(rnorm(n_freq * n_time, sd = 0.4), nrow = n_freq)
# Alpha suppression (8–13 Hz, 200–800 ms post-stimulus)
alpha_f <- freq >= 8 & freq <= 13
alpha_t <- time >= 0.2 & time <= 0.8
ersp[alpha_f, alpha_t] <- ersp[alpha_f, alpha_t] - 2.5
# Gamma increase (40–60 Hz, 100–400 ms post-stimulus)
gamma_f <- freq >= 40 & freq <= 60
gamma_t <- time >= 0.1 & time <= 0.4
ersp[gamma_f, gamma_t] <- ersp[gamma_f, gamma_t] + 2
draw_spectrogram(
ersp,
frequency = freq,
time = time,
db = FALSE,
power = FALSE,
colormap = "diverging",
title = "Simulated ERSP"
)The seewave package includes several bird song recordings as Wave objects ready to pass to draw_spectrogram():
For EEG and physiological signals, PhysioNet (physionet.org) hosts thousands of freely downloadable recordings. The EDF/EDF+ format can be read into R with the edfReader package.
draw_gantt() draws one horizontal bar per task, positioned by start and end and grouped into rows by label. ECharts has no native Gantt series; this is implemented as a custom series.
The input is a data frame with label, start, and end columns. Repeated label values put several bars on the same row:
tasks <- data.frame(
label = c("read", "preprocess", "tune", "tune", "train", "evaluate"),
start = c(0, 140, 420, 420, 1500, 2100),
end = c(120, 400, 1480, 1180, 2050, 2300),
stage = c("io", "prep", "model", "model", "model", "eval"),
failed = c(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE)
)
draw_gantt(tasks, xlab = "ms")group names a column whose values color the bars and produce a legend, and border names a logical column whose TRUE rows get an outline without changing their fill — enough to flag failures while the fill still encodes the stage:
Set axis_type = "time" for timestamps. POSIXct and Date columns are converted to epoch milliseconds automatically:
start <- as.POSIXct("2026-08-18 09:00:00", tz = "UTC")
schedule <- data.frame(
label = c("ingest", "features", "model A", "model B", "report"),
start = start + c(0, 900, 2700, 2700, 6300) ,
end = start + c(840, 2600, 6200, 5400, 7200),
team = c("data", "data", "ml", "ml", "ops")
)
draw_gantt(schedule, group = "team", axis_type = "time")zoom = TRUE (the default) enables mouse-wheel zoom, drag-to-pan, and a top-right toolbox with box-zoom, undo, and reset; guides = TRUE shows an axis pointer that follows the mouse. tooltip names a column to use as the bar’s tooltip text, and bar_height and bar_radius set thickness and corner radius:
rtemis models carry an execution timeline of the same shape, which is plotted with this chart type; see the rtemis documentation for that.