library(rtemis.draw)21 Export & serialization
Every drawing function returns an htmlwidget. This chapter covers where that widget can go: an IDE pane, a Quarto document, a Shiny app, a static file, or a JSON option you hand to something else entirely.
21.1 Sizing and identity
Chart widgets accept these sizing and output arguments:
width,height— CSS strings ("100%","32rem") or numbers of pixels. Their interpretation also depends on the host document or viewer. Check sizing in the target host, particularly when using fixed widths.element_id— an explicit DOM id for the container. Leave itNULLand htmlwidgets generates one; set it when something on the page needs to find the chart.filename— export a supported chart as well as returning the widget.
draw_scatter(
penguins$bill_len,
penguins$flipper_len,
width = 500,
height = 320
)21.2 Static files
save_drawing() exports statistical charts, complete draw_panels() figures, three-dimensional scatterplots, Sigma networks, and MapLibre choropleths to SVG. It requires a Node.js 18 or later node binary on PATH. The exported marks and text are vector graphics you can edit or scale for publication. PDF and PNG export are planned.
Inspect exported labels, layout, and layers at the intended size. Static output has no hover interaction and may use different font metrics from the browser.
f <- file.path(tempdir(), "penguins.svg")
save_drawing(draw_scatter(penguins$bill_len, penguins$flipper_len), f)width and height set the export size in pixels:
save_drawing(draw_pie(as.integer(table(penguins$species)), names(table(penguins$species))),
file.path(tempdir(), "species.svg"), width = 600, height = 600)Callbacks in tooltips, axis pointers, and toolbox controls are omitted. Other JavaScript callbacks are rejected because removing them could lose visible content. Built-in Gantt bars, dendrograms, and boxplot points use renderers shared by the browser and SVG exporter. A3 legend headings and annotations also export as vector text and shapes. Square-cell heatmaps retain equal cell dimensions in standalone SVGs and panel figures, with dendrograms aligned to the matrix.
Passing filename to a drawing function does the same thing in one step:
draw_scatter(penguins$bill_len, penguins$flipper_len, filename = "penguins.svg")The export uses the light theme by default. For a dark export, force the theme at draw time:
draw_scatter(penguins$bill_len, penguins$flipper_len,
theme = theme_dark(), filename = "penguins-dark.svg")Network exports use the same reproducible layout, node sizes, and edge colors as the interactive plot. Labels are fitted to the page and overlapping labels are omitted. Map exports retain the geographic boundaries, classification colors, and legend. Both export the initial configured view; zooming or panning in the browser does not change the R object.
For a complete example, follow the 150-researcher collaboration network and its SVG export.
21.3 The option as data
ECharts option objects convert to a plain list or JSON. Native series options can be passed to an ECharts instance in another language. Charts that use rtemis custom renderers also need those renderer definitions; JSON alone does not install them.
opt <- EChartsOption(
title = Title(text = "Body mass"),
x_axis = Axis(type = "category", data = names(table(penguins$species))),
y_axis = Axis(type = "value"),
series = BarSeries(data = as.integer(table(penguins$species)))
)
str(to_list(opt))List of 4
$ title :List of 1
..$ text: chr "Body mass"
$ xAxis :List of 2
..$ type: chr "category"
..$ data: chr [1:3] "Adelie" "Chinstrap" "Gentoo"
$ yAxis :List of 1
..$ type: chr "value"
$ series:List of 1
..$ :List of 2
.. ..$ data: int [1:3] 152 68 124
.. ..$ type: chr "bar"
cat(to_json(opt, pretty = TRUE)){
"title": {
"text": "Body mass"
},
"xAxis": {
"type": "category",
"data": ["Adelie", "Chinstrap", "Gentoo"]
},
"yAxis": {
"type": "value"
},
"series": [
{
"data": [152, 68, 124],
"type": "bar"
}
]
}
to_list() also works on component and style classes, dropping unset properties — ECharts treats a missing key as its default, so a null would mean something different:
to_list(ItemStyle(color = "#6CA3A0", opacity = 0.5))$color
[1] "#6CA3A0"
$opacity
[1] 0.5
Property names convert to ECharts’ camelCase on the way out:
to_list(Axis(type = "value", split_number = 4, boundary_gap = FALSE))$type
[1] "value"
$splitNumber
[1] 4
$boundaryGap
[1] FALSE
To go the other way — a chart described as a document, in rtemis’ own schema rather than ECharts’ — see Chart configs.
21.4 Quarto
Nothing to do: print the widget in an R chunk and it renders inline, as every chart on this site does. Charts follow the page’s light/dark toggle when theme is left at NULL.
21.5 Shiny
drawOutput() and renderDraw() are the standard htmlwidgets pair:
library(shiny)
library(rtemis.draw)
ui <- fluidPage(
selectInput("var", "Variable", c("bill_len", "bill_dep", "flipper_len", "body_mass")),
drawOutput("plot", height = "460px")
)
server <- function(input, output) {
output$plot <- renderDraw({
draw_density(penguins[[input$var]], group = penguins$species, xlab = input$var)
})
}
shinyApp(ui, server)For charts that redraw on every interaction, animation = FALSE is worth passing to draw(): animating a re-render of many points is expensive and buys nothing when the update is driven by an input.
draw(compile(cfg, data = df), animation = FALSE)