| Type: | Package |
| Title: | Multimodal Access and Interactive Data Representation |
| Version: | 0.5.0 |
| URL: | https://github.com/xability/r-maidr, https://r.maidr.ai/ |
| BugReports: | https://github.com/xability/r-maidr/issues |
| Description: | Provides accessible, interactive visualizations through the 'MAIDR' (Multimodal Access and Interactive Data Representation) system. Converts 'ggplot2' and Base R plots into accessible HTML/SVG formats with keyboard navigation, screen reader support, and 'sonification' capabilities. Supports bar charts (simple, grouped, stacked), pie charts, histograms, line plots, step plots, scatter plots, box plots, violin plots, candlestick (OHLC) charts, heat maps, density/smooth curves, faceted plots, multi-panel layouts (including patchwork), and multi-layered plot combinations. Also makes 'plotly', 'highcharter' and 'echarts4r' 'htmlwidgets' accessible by attaching the matching 'MAIDR' JavaScript adapter. Enables data exploration for users with visual impairments through multiple sensory modalities. For more details see the 'MAIDR' project https://maidr.ai/. |
| License: | GPL (≥ 3) |
| Encoding: | UTF-8 |
| Language: | en |
| Depends: | R (≥ 4.0.0) |
| Imports: | base64enc, curl, ggplot2, ggplotify, grid, htmltools, htmlwidgets, jsonlite, methods, shiny, stats, svglite (≥ 2.1.1), xml2, rlang, R6 |
| Suggests: | testthat (≥ 3.0.0), lintr, styler, goodpractice, cyclocomp, knitr, rmarkdown, quarto, patchwork, scales, tibble, tidyquant, quantmod, TTR, zoo, xts, pkgload, hexbin, vioplot, wordcloud, sm, gridGraphics, pROC, yardstick, plotly, highcharter, echarts4r |
| Config/testthat/edition: | 3 |
| VignetteBuilder: | knitr |
| Config/roxygen2/version: | 8.1.0 |
| NeedsCompilation: | no |
| Packaged: | 2026-09-29 02:29:16 UTC; jseo1005 |
| Author: | JooYoung Seo [aut, cph, cre], Niranjan Kalaiselvan [aut] |
| Maintainer: | JooYoung Seo <jseo1005@illinois.edu> |
| Repository: | CRAN |
| Date/Publication: | 2026-09-29 21:20:22 UTC |
maidr: Multimodal Access and Interactive Data Representation
Description
The 'maidr' package provides accessible, interactive visualizations through the MAIDR (Multimodal Access and Interactive Data Representation) system. It converts 'ggplot2' and Base R plots into accessible HTML/SVG formats with keyboard navigation, screen reader support, and sonification capabilities. This enables users with visual impairments to independently explore and understand data visualizations through multiple sensory modalities.
Main Functions
-
show: Display an interactive MAIDR plot in the browser or RStudio Viewer -
save_html: Save a plot as a standalone HTML file -
run_example: Run interactive example plots -
maidr_on: Enable automatic MAIDR interception in RMarkdown -
maidr_off: Disable automatic MAIDR interception -
render_maidr: Render MAIDR plots in Shiny applications -
maidr_output: Create MAIDR output container for Shiny UI
Supported Plot Types
The package supports a wide variety of plot types from both 'ggplot2' and Base R plotting systems:
ggplot2 plots:
Bar charts (simple, grouped, stacked) -
geom_bar(),geom_col()Pie charts -
geom_col()/geom_bar()withcoord_polar("y")Histograms -
geom_histogram()Scatter plots -
geom_point()Line plots -
geom_line()Step plots -
geom_step()Box plots -
geom_boxplot()Violin plots -
geom_violin()Heat maps -
geom_tile()Candlestick (OHLC) charts -
tidyquant::geom_candlestick()Density/smooth curves -
geom_density(),geom_smooth()Faceted plots -
facet_wrap(),facet_grid()Multi-panel layouts (via 'patchwork' package)
Multi-layered plot combinations
Base R plots:
Bar plots (simple, grouped, stacked) -
barplot()Pie charts -
pie()Histograms -
hist()Scatter and line plots -
plot(),points(),lines()Step plots -
plot(type = "s"),plot(type = "S")Box plots -
boxplot()Heat maps -
image(),heatmap()Contour plots -
contour()Candlestick (OHLC) charts -
quantmod::chartSeries()Multi-panel layouts -
par(mfrow),par(mfcol)
Experimental plot types: The types above are stable. The package also reads a longer list of charts as prototypes: none has been through a user study, and each may change without a deprecation period. In these docs an experimental type is marked [experimental] after its name; a type with no mark is stable. Among them:
ggplot2 area charts [experimental]
ggplot2 contour plots -
geom_contour()[experimental]ggplot2 error bars [experimental]
ggplot2 Gantt charts -
maidr_gantt()[experimental]ggplot2 hexbin plots [experimental]
ggplot2 ROC curves -
maidr_roc()[experimental]Base R correlograms [experimental]
Base R Q-Q plots [experimental]
Base R radar charts -
stars()[experimental]Base R mosaic plots [experimental]
Base R violin plots -
vioplot::vioplot()[experimental]Base R word clouds [experimental]
The full list is under "Experimental Plot Types" in the README.
Accessibility Features
-
Keyboard Navigation: Use arrow keys to explore data points
-
Screen Reader Support: ARIA labels and live regions for announcements
-
Sonification: Audio representation of data patterns
-
Text Summaries: Automatic statistical descriptions
-
Grid Navigation: Efficient exploration of scatter plots
Integration
The package integrates seamlessly with:
-
RStudio: Direct display in the Viewer pane
-
RMarkdown/Quarto: Automatic rendering with
maidr_on() -
Shiny: Interactive plots in Shiny apps via
render_maidr() -
Standalone HTML: Export plots for sharing with
save_html()
Getting Started
To create your first accessible plot:
library(maidr) library(ggplot2) # Create a ggplot2 plot p <- ggplot(mtcars, aes(x = factor(cyl), y = mpg)) + geom_boxplot() # Display as interactive MAIDR plot show(p) # Or save to HTML file save_html(p, file = "my_plot.html")
For Base R plots:
library(maidr) # Create a Base R plot barplot(table(mtcars$cyl)) # Display as interactive MAIDR plot show()
Learn More
Package website: https://r.maidr.ai/
MAIDR project: https://maidr.ai/
GitHub repository: https://github.com/xability/r-maidr
Get started:
vignette("getting-started", package = "maidr")Shiny integration:
vignette("shiny-integration", package = "maidr")
Author(s)
Maintainer: JooYoung Seo jseo1005@illinois.edu [copyright holder]
Authors:
JooYoung Seo jseo1005@illinois.edu [copyright holder]
Niranjan Kalaiselvan nk46@illinois.edu
See Also
Useful links:
Report bugs at https://github.com/xability/r-maidr/issues
Function Classification Maps
Description
Maps of function names to their classification levels
Usage
.base_r_function_classes
One rebuilt frame per layer, so a facet does not pay for it per panel
Description
process_facet_panel() runs once per panel, so a jittered layer asked for
its undisplaced positions once per panel too – and each of those rebuilds
the whole plot, every panel of it. Measured by counting
ggplot2::ggplot_build calls through a facet of P panels: 3, 5 and 9 calls
for P of 2, 4 and 8. One build is the original; the other P are the same
answer computed P times over, so the work is quadratic in the panel count
while the answer never varies – undisplaced_layer_data() depends only on
the plot and the layer index.
Usage
.jitter_cache
Details
Keyed on the layer itself rather than on the plot. ggplot2 Layer objects
are ggproto, ggproto objects are environments, and identical() on two
environments is a pointer comparison – so the lookup is O(1) and exact,
where hashing or deep-comparing the plot could cost as much as the rebuild
it saves. A layer belongs to one plot, so its identity settles the question.
One entry per layer index, each holding the layer it was computed from, and the whole cache emptied when a plot starts being processed.
All three parts are load-bearing. The index bounds the cache at the number
of layers a plot has and stops two jittered layers evicting each other once
per panel, which is the cost this exists to remove. The layer catches the
ordinary case of a second plot built from its own geom_jitter(). And the
reset catches the case the layer cannot: ggplot2 documents a layer as
reusable across plots, and +.gg appends the same ggproto object rather
than a clone, so
shared <- geom_jitter() p1 <- ggplot(df1, aes(g, score)) + shared p2 <- ggplot(df2, aes(g, score)) + shared
gives two plots that are identical() at that layer. Measured before the
reset went in: p2 was announced with every one of df1's values, and the
row-count check waved it through because the two frames were the same
length.
Base R Device-Scoped Storage
Description
This module provides device-scoped storage for Base R plot calls, enabling proper isolation between devices and preventing call accumulation.
Usage
.maidr_base_r_session
chartSeries TA Advisory Warning State
Description
Environment used to suppress repeat chartSeries TA advisory warnings
within a single session.
Usage
.maidr_chartseries_ta_warned
fourfoldplot() Decline Advisory State
Description
Environment holding the decline reasons already explained in this session, so the advisory below is not repeated for every call.
Usage
.maidr_fourfoldplot_declined
Details
A character vector rather than the single flag
.maidr_chartseries_ta_warned carries, because fourfoldplot() declines
for three different reasons and a session that draws a default-std chart
and then a 2x2xk one should hear both explanations rather than only the
first.
ggplot2 Print Method Interception
Description
Intercepts ggplot2's print method so that typing a ggplot object name at the console automatically renders it in the MAIDR interactive viewer.
Usage
.maidr_ggplot_state
Base R Function Patching System
Description
This module provides function patching capabilities for Base R plotting functions. It intercepts Base R plotting calls and records them for processing by the MAIDR system.
Usage
.maidr_patching_env
vioplot's default whisker reach, in interquartile ranges
Description
vioplot's default whisker reach, in interquartile ranges
Usage
.maidr_vioplot_default_range
Grobs vioplot draws, one of each per violin
Description
Measured by echoing a two-group call through gridGraphics::grid.echo():
Usage
.maidr_vioplot_grob_kinds
Details
graphics-plot-1-box-1 polygon n=4 <- the plot frame, NOT a violin graphics-plot-1-polygon-1 polygon n=200 <- violin body graphics-plot-1-lines-1 lines n=2 <- whisker, lower to upper graphics-plot-1-rect-1 rect n=1 <- the quartile box graphics-plot-1-points-1 points n=1 <- the median dot
The body carries exactly twice the evaluation points sm.density returns,
mirrored about the category position, which is what confirms the replayed
curve is the drawn one.
The patterns below are anchored, which is defensive rather than a fix for
anything observed. Measured, the two things it is tempting to credit it with
are not true: graphics-plot-11-polygon-1 is excluded by the - delimiter
whether the pattern is anchored or not, and graphics-plot-1-box-1 – the
panel frame, which is a polygon grob – never enters this search because
it is not named polygon. What the trailing $ genuinely excludes is a
longer name beginning the same way, such as -polygon-1-extra; gridSVG
emits none today, so this keeps a name it does not own from being collected
if that ever changes.
Wrap vioplot's entry point once its namespace is available
Description
vioplot is in Suggests, so if it loads after maidr its vioplot() has not
been wrapped yet and user calls would go unrecorded. Same shape as the
quantmod hook above, and registered beside it in .onLoad.
Usage
.maidr_vioplot_onload_hook(...)
wordcloud()'s own defaults, replicated so the reading matches the drawing
Description
Only the two that decide which terms are drawn. The rest — scale,
rot.per, colors — decide how they look, and a reading has nothing to
do with them.
Usage
.maidr_wordcloud_defaults
Wrap wordcloud's entry point once its namespace is available
Description
Same shape and same reason as the vioplot hook above: wordcloud is in
Suggests, so a call made after a late library(wordcloud) would otherwise
go unrecorded entirely.
Usage
.maidr_wordcloud_onload_hook(...)
Base R System Adapter
Description
Adapter for the Base R plotting system. This adapter uses function patching to intercept Base R plotting calls and detect plot types.
Format
An R6 class inheriting from SystemAdapter
Super class
SystemAdapter -> BaseRAdapter
Methods
Public methods
BaseRAdapter$new()
Initialize the Base R adapter
Usage
BaseRAdapter$new()
BaseRAdapter$formula_frame_missing()
Was a formula call recorded without the frame it drew from?
A formula reader takes its rows from the model frame kept at record
time. When that frame could not be built – a subset written as an
expression with nothing to evaluate it in, a data that no longer
resolves – the reader has nothing to announce, and a claimed layer
with nothing in it exports as an interactive chart that says nothing.
Declining the type sends the chart to the picture instead.
Usage
BaseRAdapter$formula_frame_missing(layer)
Arguments
layerThe recorded call entry
Returns
TRUE when the call carries a formula but no frame
BaseRAdapter$formula_call()
Was the call handed a formula?
Either written in the call, or – fmla <- y ~ x; plot(fmla) –
bound to a name the recorder resolved.
Usage
BaseRAdapter$formula_call(layer)
Arguments
layerThe recorded call entry
Returns
TRUE when the call carries a formula
BaseRAdapter$formula_scatter_readable()
Does a recorded formula plot() draw a numeric scatter?
plot.formula() draws a scatter only for a numeric response over one
numeric predictor; a factor predictor reaches plot.factor() and a
box plot, and a longer right-hand side is plot.default() over the
first term. Only the two-column numeric frame is read as points.
Usage
BaseRAdapter$formula_scatter_readable(layer)
Arguments
layerThe recorded call entry
Returns
TRUE when the frame is a numeric pair
BaseRAdapter$can_handle()
Check if this adapter can handle a plot object
Usage
BaseRAdapter$can_handle(plot_object)
Arguments
plot_objectThe plot object to check (should be NULL for Base R)
Returns
TRUE if Base R plotting is active, FALSE otherwise
BaseRAdapter$detect_layer_type()
Detect the type of a single layer from Base R plot calls
Usage
BaseRAdapter$detect_layer_type(layer, plot_object = NULL)
Arguments
layerThe plot call entry from our logger
plot_objectThe parent plot object (NULL for Base R)
Returns
String indicating the layer type (e.g., "bar", "dodged_bar", "stacked_bar", "smooth", "line", "point")
BaseRAdapter$is_dodged_barplot()
Check if a barplot call represents a dodged bar plot
Usage
BaseRAdapter$is_dodged_barplot(args)
Arguments
argsThe arguments from the barplot call
Returns
TRUE if this is a dodged bar plot, FALSE otherwise
BaseRAdapter$is_stacked_barplot()
Check if a barplot call represents a stacked bar plot
Usage
BaseRAdapter$is_stacked_barplot(args)
Arguments
argsThe arguments from the barplot call
Returns
TRUE if this is a stacked bar plot, FALSE otherwise
BaseRAdapter$is_normalized_barplot()
Check if a barplot call draws a 100% stacked bar
Base R has no position = "fill" to read: barplot() takes no
normalisation argument at all, and the idiomatic way to draw a 100%
stacked bar is to normalise the matrix first, as
barplot(prop.table(m, 2)). The only signal left is the drawn geometry.
So this reads what the chart shows rather than guessing what the author
meant, and the two are the same thing here: when every column sums to 1,
every bar is drawn to a common full height and each segment is that
category's share. A chart like that IS a 100% stacked bar whatever the
numbers were before they reached barplot().
Deliberately narrow. It does not also accept columns summing to 100, because a matrix of raw counts can total 100 by coincidence and nothing about the drawing would distinguish that from percentages. And it needs two or more rows, because a single series stacked against nothing is not a stack.
Usage
BaseRAdapter$is_normalized_barplot(args)
Arguments
argsThe arguments from the barplot call
Returns
TRUE if every column of the height matrix sums to 1
BaseRAdapter$create_orchestrator()
Create an orchestrator for this system (Base R)
Usage
BaseRAdapter$create_orchestrator(plot_object = NULL)
Arguments
plot_objectThe plot object to process (NULL for Base R)
Returns
PlotOrchestrator instance
BaseRAdapter$get_system_name()
Get the system name
Usage
BaseRAdapter$get_system_name()
Returns
System name string
BaseRAdapter$get_adapter()
Get a reference to this adapter (for use by orchestrator)
Usage
BaseRAdapter$get_adapter()
Returns
Self reference
BaseRAdapter$has_facets()
Check if plot has facets (Base R doesn't support facets)
Usage
BaseRAdapter$has_facets(plot_object = NULL)
Arguments
plot_objectThe plot object (ignored for Base R)
Returns
FALSE (Base R doesn't support facets)
BaseRAdapter$is_patchwork()
Check if plot is a patchwork plot (Base R doesn't support patchwork)
Usage
BaseRAdapter$is_patchwork(plot_object = NULL)
Arguments
plot_objectThe plot object (ignored for Base R)
Returns
FALSE (Base R doesn't support patchwork)
BaseRAdapter$get_plot_calls()
Get recorded plot calls for processing
Usage
BaseRAdapter$get_plot_calls(device_id = grDevices::dev.cur())
Arguments
device_idGraphics device ID (defaults to current device)
Returns
List of recorded plot calls
BaseRAdapter$clear_plot_calls()
Clear recorded plot calls (for cleanup)
Usage
BaseRAdapter$clear_plot_calls(device_id = grDevices::dev.cur())
Arguments
device_idGraphics device ID (defaults to current device)
BaseRAdapter$initialize_patching()
Initialize function patching
Usage
BaseRAdapter$initialize_patching()
Returns
NULL (invisible)
BaseRAdapter$restore_functions()
Restore original functions
Usage
BaseRAdapter$restore_functions()
Returns
NULL (invisible)
BaseRAdapter$clone()
The objects of this class are cloneable with this method.
Usage
BaseRAdapter$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Association Plot Layer Processor
Description
Processes Base R assocplot() layers – a Cohen–Friendly association
plot, which draws one tile per cell of a two-way table whose signed height
is that cell's Pearson residual, (observed - expected) / sqrt(expected).
Read as a heat layer, because a named grid of one number per cell is what
the chart states and row-then-column is how a reader navigates a
contingency table. Measured on assocplot(HairEyeColor[, , 1]), the rects
the drawing produces carry the residuals exactly:
Brown Blue Hazel Green
Black 2.780 -2.059 0.184 -1.408
Brown 0.391 -0.246 0.185 -0.465
Red -0.562 -0.658 0.532 1.485
Blond -3.273 3.271 -0.988 1.097
Nothing is inferred from the drawing: assocplot() is handed the table, so
the recorded call carries every number the trace wants. It returns NULL,
which is why the reading comes from the argument – the shape bxp()'s
reading took in #265.
Two things this deliberately does not do
The tile width is dropped. Each tile is drawn sqrt(expected) wide, so
the marginals are on the chart as a second encoding. A heat layer has no
width, and the residual is what an association plot exists to show – the
eye reads height and sign, and the width is why a cell's box is wider
rather than a value the reader is asked to compare. Announcing it in z
instead would replace the number the chart is about.
It is not a mosaic. mosaicplot() is read as one and the two look
alike, but a mosaic's tiles tile the space and carry proportions of a
whole. These float above and below a baseline and carry residuals, which
are signed and sum to nothing. Calling it a mosaic would tell a reader the
areas are shares of a total when they are a departure from an expectation.
Super class
LayerProcessor -> BaseRAssocplotLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRAssocplotLayerProcessor$process()
Process the association plot layer.
Usage
BaseRAssocplotLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused for Base R (kept for interface compatibility)
layoutUnused for Base R (kept for interface compatibility)
builtUnused for Base R (kept for interface compatibility)
gtGtable object used for selector generation (optional)
grob_idUnused for Base R
panel_idUnused for Base R
panel_ctxUnused for Base R
layer_infoInformation about the recorded plot call
Returns
List with data, selectors, type, title and axes
BaseRAssocplotLayerProcessor$needs_reordering()
Whether the plot data must be reordered before drawing; a Base R layer is read from the recorded call and never is
Usage
BaseRAssocplotLayerProcessor$needs_reordering()
Returns
FALSE
BaseRAssocplotLayerProcessor$extract_data()
Read the residual grid out of the recorded call.
The grid is the table transposed, and its rows reversed. That is
not a convention chosen here but the relation assocplot() has to its
argument, measured from the drawn rects: the first dimension runs
across the x axis and the second up the y axis, bottom to top. It is
the same relation image() has to its matrix, and the heatmap
processor transposes for the same reason.
A table with a zero margin has cells whose expected count is zero, and
a residual there is 0/0. assocplot() draws nothing for such a cell;
the grid has to keep a place for it, so it carries 0 – the departure
from an expectation of nothing being nothing.
Usage
BaseRAssocplotLayerProcessor$extract_data(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
List with points, x and y, empty when there is no table
BaseRAssocplotLayerProcessor$pearson_residuals()
The Pearson residual of every cell.
(observed - expected) / sqrt(expected), with the expected counts
taken from the margins the same way assocplot() takes them.
Usage
BaseRAssocplotLayerProcessor$pearson_residuals(table)
Arguments
tableA two-way table
Returns
A numeric matrix of the same shape
BaseRAssocplotLayerProcessor$recorded_table()
The two-way table the call was handed, when it is one.
Only a two-dimensional table is read. assocplot() itself accepts no
more – it stops on anything else – so this declines the same inputs
the function does.
Usage
BaseRAssocplotLayerProcessor$recorded_table(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
A 2-D table, or NULL
BaseRAssocplotLayerProcessor$extract_axis_titles()
Name the axes from the table's own dimension names.
assocplot() labels its axes with names(dimnames(x)) unless the
author overrides them, so those are the words a reader should be given.
z names what the numbers are rather than a dimension of the table:
the grid holds residuals, and a reader told "Eye" for the value would
be told a level name where a number is.
Usage
BaseRAssocplotLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
Canonical axes list
BaseRAssocplotLayerProcessor$extract_main_title()
The title the call was given, if any.
Usage
BaseRAssocplotLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
Character scalar, empty when the author wrote no title
BaseRAssocplotLayerProcessor$generate_selectors()
Address the tiles the chart drew.
assocplot() draws every cell into ONE rect grob – measured, a 4x4
table gives graphics-plot-N-rect-1 holding sixteen rects – so the
cells need no picking out of the drawing the way a gantt's bars do.
Usage
BaseRAssocplotLayerProcessor$generate_selectors( layer_info, gt = NULL, extracted_data = NULL )
Arguments
layer_infoInformation about the recorded plot call
gtGtable object (optional)
extracted_dataThe grid this layer emitted
Returns
List of selectors, one per cell
BaseRAssocplotLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRAssocplotLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Bar Plot Layer Processor
Description
Processes Base R bar plot layers based on recorded plot calls
Super class
LayerProcessor -> BaseRBarplotLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRBarplotLayerProcessor$process()
Process the layer: read its data, selectors, axis titles and main title from the recorded call
Usage
BaseRBarplotLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface
layoutUnused; present for the processor interface
builtUnused; present for the processor interface
gtGtable of the replayed drawing, searched for selectors (optional)
grob_idUnused; present for the processor interface
panel_idUnused; present for the processor interface
panel_ctxUnused; present for the processor interface
layer_infoLayer information with the recorded call
Returns
List describing the layer for the MAIDR payload
BaseRBarplotLayerProcessor$is_horizontal()
Check whether this barplot call used horiz = TRUE
Usage
BaseRBarplotLayerProcessor$is_horizontal(layer_info)
Arguments
layer_infoLayer information
Returns
Logical
BaseRBarplotLayerProcessor$needs_reordering()
Whether the plot data must be reordered before drawing; a Base R layer is read from the recorded call and never is
Usage
BaseRBarplotLayerProcessor$needs_reordering()
Returns
FALSE
BaseRBarplotLayerProcessor$extract_data()
One point per bar, read from the recorded height
Usage
BaseRBarplotLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of points
BaseRBarplotLayerProcessor$extract_axis_titles()
Extract the axis titles for this layer
barplot() writes no title of its own, so an author who wrote none
leaves both axes nameless. A bar chart always plots categories against
their measured heights, whether or not the heights arrived named, so
that is what the defaults say. horiz = TRUE puts the heights on the
visual x axis – the same swap extract_data() applies to the points.
Usage
BaseRBarplotLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information
Returns
Canonical axes list
BaseRBarplotLayerProcessor$extract_main_title()
The main title of the recorded call, or an empty string
Usage
BaseRBarplotLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Character string
BaseRBarplotLayerProcessor$generate_selectors()
Generate the CSS selectors that address this layer's drawn elements
Usage
BaseRBarplotLayerProcessor$generate_selectors(layer_info, gt = NULL)
Arguments
layer_infoLayer information with the recorded call
gtGtable of the replayed drawing (optional)
Returns
List of selectors
BaseRBarplotLayerProcessor$find_rect_grobs()
Recursively find rect grobs in the grob tree (like ggplot2 does)
Usage
BaseRBarplotLayerProcessor$find_rect_grobs(grob, call_index)
Arguments
grobThe grob tree to search
call_indexThe plot call index to match
Returns
Character vector of grob names
BaseRBarplotLayerProcessor$generate_selectors_from_grob()
Generate selectors from grob tree (like ggplot2 does)
Usage
BaseRBarplotLayerProcessor$generate_selectors_from_grob(grob, call_index)
Arguments
grobThe grob tree to search
call_indexThe plot call index
Returns
List of selectors
BaseRBarplotLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRBarplotLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Biplot Processor
Description
Reads biplot() as the two things it draws: the observations in principal
component space, and the variables' loadings on the same components.
It is a grid, and for a reason the other grids do not have. pairs(),
lag.plot() and termplot() are read as grids because they draw several
panels. A biplot draws its two halves on top of each other – but on
two different pairs of axes, which is the whole trick of the chart.
Measured, the two plot.xy calls run over different ranges, and the
quantities behind them are different sizes again:
scores PC1 range -1.716 .. 2.199 loadings PC1 range -0.962 .. -0.012
Announcing both against one axis pair would misstate every loading. So the two are given a cell each – one row, two columns – which is the only way the existing grammar can say "these have separate scales" without inventing a second axis on one layer.
It draws no points at all. Both plot.xy calls are type = "n";
every mark on the page is a label or an arrow. Measured on the export
of a ten-observation, four-variable fit:
graphics-plot-1-text-1 10 children the observations graphics-plot-2-text-1 4 children the variables graphics-plot-2-arrows-1 4 children the arrows
Both text grobs are addressable per datum, in data order, which is the
shape lag.plot()'s labelled panels already established – one g per
label rather than one use per symbol. The arrows are not emitted
separately: an arrow and its label name the same variable and sit at the
same place, so the label is the mark a reader is moved to.
The values are the caller's, not the drawing's. biplot() apportions
the two halves between the axes so that both fit one page – it divides
the scores by sdev * sqrt(n) and multiplies the loadings by it, so
neither set is drawn at its own scale. What a reader wants is the pair
that mean something: the scores, an observation's coordinate in
component space, and the loadings, a variable's weight on each
component. Those are announced. This is the same choice stars() makes,
where the radii on the page are shares of a column's range and the reading
hands over the readings instead.
Super classes
LayerProcessor -> BaseRPointLayerProcessor -> BaseRBiplotLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRPointLayerProcessor$extract_axis_titles()BaseRPointLayerProcessor$extract_base_r_axis_grid_info()BaseRPointLayerProcessor$extract_data()BaseRPointLayerProcessor$extract_main_title()BaseRPointLayerProcessor$formula_variables()BaseRPointLayerProcessor$generate_selectors()BaseRPointLayerProcessor$needs_reordering()BaseRPointLayerProcessor$resolve_coordinates()
BaseRBiplotLayerProcessor$process()
Emit the observations and the variables, a cell each
Usage
BaseRBiplotLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface.
layoutUnused; present for the processor interface.
builtUnused; present for the processor interface.
gtUnused; the selectors are built rather than searched for.
grob_idUnused; present for the processor interface.
panel_idUnused; present for the processor interface.
panel_ctxUnused; present for the processor interface.
layer_infoLayer information with the recorded call.
Returns
A multi-panel result, or NULL when nothing was read
BaseRBiplotLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRBiplotLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Boxplot Layer Processor
Description
Processes Base R boxplot layers by extracting statistical summaries and generating selectors for boxplot components.
Super class
LayerProcessor -> BaseRBoxplotLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRBoxplotLayerProcessor$process()
Process the layer: read its data, selectors, axis titles and main title from the recorded call
Usage
BaseRBoxplotLayerProcessor$process( plot, layout, built = NULL, gt = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface
layoutUnused; present for the processor interface
builtUnused; present for the processor interface
gtGtable of the replayed drawing, searched for selectors (optional)
layer_infoLayer information with the recorded call
Returns
List describing the layer for the MAIDR payload
BaseRBoxplotLayerProcessor$read_stats()
The five-number summaries the drawn boxes came from
A boxplot() call carries the observations, so the summaries have to
be recomputed from them – which boxplot(plot = FALSE) does, using
the same code path the drawing did, rather than a reimplementation of
it here. graphics::boxplot is named directly so the replay does not
go back through maidr's own wrapper and record a second call.
Overridable because bxp() is handed the summaries already computed
and draws exactly the same marks from them: everything below this
method – the outlier grouping, the polygon and segment indices, the
shift each box with no outliers puts on the ones after it – is the
same reading either way, and only where the summaries come from
differs (#262).
Usage
BaseRBoxplotLayerProcessor$read_stats(args)
Arguments
argsRecorded argument list
Returns
The boxplot.stats-shaped list, or NULL when it cannot be had
BaseRBoxplotLayerProcessor$extract_data()
One five-number summary per group, recomputed from the recorded observations
Usage
BaseRBoxplotLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of box summaries
BaseRBoxplotLayerProcessor$generate_selectors()
Selectors for each box's polygon, whiskers, median and outliers
Usage
BaseRBoxplotLayerProcessor$generate_selectors( layer_info, gt = NULL, extracted_data = NULL )
Arguments
layer_infoLayer information with the recorded call
gtGtable of the replayed drawing (optional)
extracted_dataThe data already extracted for this layer (optional)
Returns
List of selectors
BaseRBoxplotLayerProcessor$extract_axis_titles()
Extract the axis titles for this layer
boxplot() records no title unless the author wrote one, but the
formula method derives both from the formula itself and draws them, so
a y ~ g call already names its axes: the response on the value axis
and the grouping terms on the category axis. Everything else falls back
to what a box plot always shows – groups against their distributions.
horizontal = TRUE swaps which visual axis is which, exactly as
boxplot.formula()'s own defaults do.
Usage
BaseRBoxplotLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information
Returns
Canonical axes list
BaseRBoxplotLayerProcessor$extract_formula_labels()
Read the axis titles boxplot.formula() derives from its formula
boxplot.formula() builds them out of the model frame's column names:
the response column names the value axis and the remaining columns,
joined with " : ", name the category axis. Building the same model
frame reproduces the drawn titles for expressions (log(mpg) ~ cyl)
and for . alike, where deparsing the formula's terms would not.
Usage
BaseRBoxplotLayerProcessor$extract_formula_labels(args, frame = NULL)
Arguments
argsRecorded argument list
frameThe model frame kept by the recording (optional)
Returns
List with response and groups, or NULL when this call is
not the formula method or the model frame cannot be rebuilt
BaseRBoxplotLayerProcessor$extract_main_title()
The main title of the recorded call, or an empty string
Usage
BaseRBoxplotLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Character string
BaseRBoxplotLayerProcessor$determine_orientation()
Which way the boxes were drawn, from the recorded horizontal flag
Usage
BaseRBoxplotLayerProcessor$determine_orientation(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
"horz" or "vert"
BaseRBoxplotLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRBoxplotLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R bxp() Layer Processor
Description
Reads a graphics::bxp() call as the box plot it draws.
bxp() is the drawing half of boxplot(): boxplot.default() computes the
five-number summaries and then hands them to bxp(), which puts the boxes,
whiskers, medians and outliers on the page. Calling it directly is how a
caller draws boxes from summaries they already have – from
boxplot(plot = FALSE), from boxplot.stats(), or computed elsewhere
entirely – and it is one of the twelve calls #262 found drawing while the
save reported no plot at all.
What is the same, and what is not
The marks are identical. Drawn off-screen and echoed through
gridGraphics, bxp(z) and the boxplot() call that produced z emit
the same grob names in the same order – polygon-1, segments-1,
points-1, ... – because the same code drew them. Every selector
BaseRBoxplotLayerProcessor builds, including the index shift each box
with no outliers puts on the boxes after it, therefore addresses a bxp()
chart unchanged, and this class inherits all of it.
The one difference is where the summaries come from. boxplot() is handed
observations, so its processor replays boxplot(plot = FALSE) to recover
them; bxp() is handed the summaries themselves, in its first argument.
Replaying boxplot() on that would read the six-element list as six
groups of numbers and summarise them – so the only thing this class
overrides is read_stats().
Two things bxp() shares with boxplot() are shared including their
limits: horizontal = TRUE means the same thing to both, and at =
repositions boxes without reordering the drawing in either, so a
non-monotonic at reads in drawing order here exactly as it already does
for boxplot().
Super classes
LayerProcessor -> BaseRBoxplotLayerProcessor -> BaseRBxpLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRBoxplotLayerProcessor$determine_orientation()BaseRBoxplotLayerProcessor$extract_axis_titles()BaseRBoxplotLayerProcessor$extract_data()BaseRBoxplotLayerProcessor$extract_formula_labels()BaseRBoxplotLayerProcessor$extract_main_title()BaseRBoxplotLayerProcessor$generate_selectors()BaseRBoxplotLayerProcessor$process()
BaseRBxpLayerProcessor$read_stats()
The summaries bxp() was handed
bxp()'s first formal is z, and it draws nothing without a numeric
z$stats with five rows – so a recorded call that reached this
package has one. It is still checked rather than assumed: a shape that
does not answer leaves the layer empty and the figure falls back to the
picture it already was, where reaching past it would raise out of
process() with nothing to catch it.
The positional half looks for the first unnamed argument rather than
for slot 1. match_recorded_args() keeps the author's order and leaves
only the dispatch argument unnamed, wherever it was written, so
bxp(horizontal = TRUE, z) records z in slot 2 – a call R itself
accepts and draws. Reading slot 1 there hands TRUE to the check below
and leaves the layer empty. resolve_xy_args() resolves a positional
argument the same way, for the same reason. Raised in review of #265.
Usage
BaseRBxpLayerProcessor$read_stats(args)
Arguments
argsRecorded argument list
Returns
The boxplot.stats-shaped list, or NULL when it is not one
BaseRBxpLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRBxpLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Candlestick Layer Processor
Description
Processes Base R candlestick chart layers produced by
quantmod::chartSeries(x, type = "candlesticks").
Each xts row becomes a single navigable CandlestickPoint with
value, open, high, low, close, computed trend
(Bull / Bear / Neutral), volatility (high - low) and optional
volume (when quantmod::has.Vo() is TRUE).
Selectors are derived from the gridSVG export of the chartSeries
grob (captured via ggplotify::as.grob()). chartSeries draws candle
bodies via a single vectorized rect() call (each candle body is one
SVG <rect> child of graphics-plot-<N>-rect-*) and upper/lower
wicks via segments() calls (one SVG <polyline> per wick under
graphics-plot-<N>-segments-*).
Super class
LayerProcessor -> BaseRCandlestickLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRCandlestickLayerProcessor$process()
Process the layer: the candlestick layer, plus a volume bar layer when
addVo() was requested
Usage
BaseRCandlestickLayerProcessor$process( plot, layout, built = NULL, gt = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface
layoutUnused; present for the processor interface
builtUnused; present for the processor interface
gtGtable of the replayed drawing, searched for selectors (optional)
layer_infoLayer information with the recorded call
Returns
A candlestick layer, or a multi-layer list with the volume bars
BaseRCandlestickLayerProcessor$has_add_vo()
Detect whether the chartSeries call draws the addVo() volume panel, which it does by default
Usage
BaseRCandlestickLayerProcessor$has_add_vo(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Logical
BaseRCandlestickLayerProcessor$build_volume_layer()
Build a "bar" layer carrying volume data
Usage
BaseRCandlestickLayerProcessor$build_volume_layer(layer_info, gt, candle_data)
Arguments
layer_infoLayer information with the recorded call
gtGtable of the replayed drawing (optional)
candle_dataThe candlestick data already extracted
BaseRCandlestickLayerProcessor$generate_volume_selectors()
Generate selectors for the addVo() volume bar panel
chartSeries(TA = "addVo()") creates a second plotting window. In
the gridSVG export that maps to a second graphics-plot-<N> group
(typically N = 2). Returns a per-bar selector list so each volume
bar can be individually highlighted on navigation; matches the
bar layer contract used by the Base R barplot processor.
Usage
BaseRCandlestickLayerProcessor$generate_volume_selectors( layer_info, gt, n_bars )
Arguments
layer_infoLayer information with the recorded call
gtGtable of the replayed drawing (optional)
n_barsNumber of volume bars
Returns
List of selectors, one per volume bar
BaseRCandlestickLayerProcessor$extract_data()
Extract OHLC data points from the chartSeries call
Usage
BaseRCandlestickLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer info containing the recorded plot call
Returns
List of CandlestickPoint dicts
BaseRCandlestickLayerProcessor$generate_selectors()
Generate CSS selectors for the candlestick layer
Returns ONE CandlestickSelector object (matching the maidr JS
frontend contract in src/model/candlestick.ts::mapToSvgElements).
The returned object has these named character-vector keys:
-
bodylength-N vector, one per-candle body-rect selector -
wickHighlength-N vector, one per-candle upper-wick selector (omitted if only one segments group is present) -
wickLowlength-N vector, one per-candle lower-wick selector (omitted if only one segments group is present) -
wicklength-N vector, used as fallback when there is only one segments group (the frontend falls back towickwhenwickHigh/wickLoware absent).
gridSVG emits a child id <group-id>.1.<i> for each primitive in
a vectorized draw call. The frontend iterates each string array
(collectElements(arr)) and picks the i-th element via
getElementAt(*, i), so per-candle selectors are required for
single-candle highlighting on arrow-key navigation.
IMPORTANT: do NOT return an array of objects (e.g.
[[body, wick], ...]). The frontend's Array.isArray() branch
would then take selectors[0] (the first dict) and pass it to
querySelectorAll, yielding a JS SyntaxError: '[object Object]' is not a valid selector. The boxplot pattern of per-item dicts
does NOT apply here because each chart model has its own contract.
Usage
BaseRCandlestickLayerProcessor$generate_selectors( layer_info, gt = NULL, extracted_data = NULL )
Arguments
layer_infoLayer info (used for fallback plot index)
gtThe captured chartSeries grob (from ggplotify::as.grob)
extracted_dataPreviously extracted data (used for count)
Returns
Named list (single CandlestickSelector) or list() when
grobs cannot be located.
BaseRCandlestickLayerProcessor$extract_axis_titles()
The axis titles, defaulting to Date and Price
Usage
BaseRCandlestickLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Canonical axes list
BaseRCandlestickLayerProcessor$extract_main_title()
The main title of the recorded call, or an empty string
Usage
BaseRCandlestickLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Character string
BaseRCandlestickLayerProcessor$format_x_values()
Format a vector of x-axis index values to character
Usage
BaseRCandlestickLayerProcessor$format_x_values(idx)
Arguments
idxInteger x-axis positions
Returns
Character vector
BaseRCandlestickLayerProcessor$collect_grob_names()
Recursively collect all grob names in a grob tree
Usage
BaseRCandlestickLayerProcessor$collect_grob_names(g)
Arguments
gA grob
Returns
Character vector of grob names
BaseRCandlestickLayerProcessor$sort_ids()
Sort grob ids by trailing integer suffix
Usage
BaseRCandlestickLayerProcessor$sort_ids(ids)
Arguments
idsGrob ids
Returns
The ids in numeric order of their suffix
BaseRCandlestickLayerProcessor$find_grob_by_name()
Find the grob node whose name matches id
Usage
BaseRCandlestickLayerProcessor$find_grob_by_name(g, id)
Arguments
gA grob
idThe grob name to find
Returns
The grob, or NULL when no name matches
BaseRCandlestickLayerProcessor$grob_coord_count()
Count the number of primitive coordinates a grob carries
Usage
BaseRCandlestickLayerProcessor$grob_coord_count(g)
Arguments
gA grob
Returns
Integer
BaseRCandlestickLayerProcessor$pick_largest_child_group()
Pick the rect-id whose grob has the most coordinates
Usage
BaseRCandlestickLayerProcessor$pick_largest_child_group(gt, ids)
Arguments
gtGtable of the replayed drawing (optional)
idsGrob ids
BaseRCandlestickLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRCandlestickLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Conditional Density Plot Layer Processor
Description
Reads cdplot() as the 100% stacked area chart it draws.
A conditional density plot shows, for each value of a numeric x, how the
levels of a factor y divide up: the bands are stacked, they fill the
whole height, and their shares sum to 1 at every x. That is a normalized
stacked area, which Ggplot2AreaLayerProcessor already emits for
position = "fill", so a cdplot() is read as
stacked_normalized_area and the two adapters describe one chart the
same way – each series a list of {x, y, z} where y is the band's own
share and z names the level, and one selector per band.
Before this, cdplot() had no branch in detect_layer_type(), so the
switch fell through to "unknown" and the chart degraded to a static
image (#216, #251).
Where the curves come from
cdplot() has a plot argument, so it can be asked for what it drew
without drawing it again. It returns the boundaries between the bands:
nlevels(y) - 1 functions, each approxfun() over the density grid,
named for the level below the boundary.
rval <- cdplot(x, y, plot = FALSE) names(rval) # "c" "b" for a factor with levels a, b, c rval[[1]](50) # the cumulative share at x = 50
Stacking them the way cdplot() does – rbind(0, boundaries, 1), band
i running from row i to row i + 1 – gives the shares back. Measured
over three hundred random charts, every column's shares sum to 1 and no
band comes out negative, so the boundaries do not cross in the drawn
range.
graphics::cdplot by the qualified name, not the bare one: maidr patches
the name on the search path, and a bare call would record the replay as a
second chart. The same line BaseRSpineplotLayerProcessor draws.
Which x values were drawn
The returned functions interpolate over the density grid, which
stats::density() pads past the data by three bandwidths. cdplot()
throws that padding away before drawing:
y1 <- y1[, which(x1 >= min(x) & x1 <= max(x))] x1 <- x1[x1 >= min(x) & x1 <= max(x)]
so the announced grid is trimmed the same way – 372 of the 512 points on a measured chart. Announcing the untrimmed grid would put readings either side of the data at x values the chart has no marks at.
The grid itself is read off the first returned function rather than
recomputed: approxfun() keeps its knots, and environment(f)$x is the
grid cdplot() built. Recomputing density() here would have to guess
bw, n, from, to and weights back out of the recorded call, and
a guess that differed by one point would shift every reading.
What the replay proves
A cdplot() that returned rather than stopping has already established
most of what a reader here would otherwise have to check, because
cdplot() checks it first and stops. Each was measured:
-
yis a factor – "dependent variable should be a factor"; -
xis finite –stats::density()stops on a missing or infinite value; a formula names exactly two variables – "'formula' should specify exactly two variables";
the grid overlaps the data – a
from/tothat put it elsewhere stops with "need at least two non-NA values to interpolate";the factor has at least two levels – one stops with "subscript out of bounds".
The NULL checks that remain below are therefore not checking any of that. They are there so that a shape none of the above rules out cannot throw out of the pipeline, where declining to read leaves the static image the figure produces today. Where a check would only repeat one another check already makes, it is not written twice.
Super class
LayerProcessor -> BaseRCdplotLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRCdplotLayerProcessor$process()
Build the layer
Usage
BaseRCdplotLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plot, layout, built, gt, grob_id, panel_id, panel_ctxPipeline arguments
layer_infoThe recorded call
Returns
List with data, selectors, type, title and axes
BaseRCdplotLayerProcessor$extract_data()
One series per band, bottom to top
Bottom to top because that is the order cdplot() draws its
polygons in, and the selector list is positional against those
polygons.
Usage
BaseRCdplotLayerProcessor$extract_data(layer_info)
Arguments
layer_infoThe recorded call
Returns
A list of series, each a list of {x, y, z} points
BaseRCdplotLayerProcessor$drawn_bands()
The grid, the band names and their shares, or NULL
NULL rather than an empty list when the call cannot be read, so every caller degrades the same way: no data, no selectors, and the figure falls back to the static image it produces today.
Usage
BaseRCdplotLayerProcessor$drawn_bands(layer_info)
Arguments
layer_infoThe recorded call
Returns
A list of x, levels and shares (a bands-by-points
matrix), or NULL
BaseRCdplotLayerProcessor$replay()
Ask cdplot() what it drew, without drawing it
Usage
BaseRCdplotLayerProcessor$replay(args)
Arguments
argsThe recorded call's arguments
Returns
The list of boundary functions, or NULL
BaseRCdplotLayerProcessor$drawn_grid()
The x values the bands were drawn over
Usage
BaseRCdplotLayerProcessor$drawn_grid(boundaries, args)
Arguments
boundariesThe replayed boundary functions
argsThe recorded call's arguments
Returns
A numeric vector, or NULL
BaseRCdplotLayerProcessor$band_levels()
The band names, bottom to top
cdplot() names its boundaries for every level but the topmost, so
the one it does not name is the one level of the response that is
left. Derived that way rather than by reproducing the ylevels
argument's reordering, which is cdplot()'s to define.
Declines unless exactly one level is left over. That is the one
guard the step needs, and it does double duty: an ylevels naming a
strict subset of the factor's levels leaves two over – measured,
ylevels = c("a", "b") on a three-level factor – and unnamed
boundaries would leave every level over. Either way the reading
would be missing a band, and every selector after it would point at
its neighbour.
An empty level name is not declined. factor(x, levels = c("b", "")) is a level like any other, setdiff() matches it like any
other, and the chart draws a band for it – so it is announced with
the empty name the axis shows rather than dropped.
Usage
BaseRCdplotLayerProcessor$band_levels(boundaries, args)
Arguments
boundariesThe replayed boundary functions
argsThe recorded call's arguments
Returns
A character vector, or NULL
BaseRCdplotLayerProcessor$predictor()
The numeric variable on the x axis
Usage
BaseRCdplotLayerProcessor$predictor(args)
Arguments
argsThe recorded call's arguments
Returns
A numeric vector, or NULL
BaseRCdplotLayerProcessor$response()
The factor whose levels the bands are
Usage
BaseRCdplotLayerProcessor$response(args)
Arguments
argsThe recorded call's arguments
Returns
A factor, or NULL
BaseRCdplotLayerProcessor$variables()
The two variables the call was given, whichever form it took
cdplot() has two methods and they name their variables
differently: cdplot(x, y) and cdplot(y ~ x, data). The formula
method builds a model frame and takes the response from column one
and the predictor from column two, which is reproduced here because
the recorded call carries the formula rather than the frame.
Memoised. process() reaches this three times – through
response(), through predictor() and again for the axis names –
and on the formula path each ask would rebuild a model frame and
re-apply the subset. The same call BaseRSpineplotLayerProcessor
makes about its replayed table, for the same reason. Nothing
observable changes, which is why this is written down rather than
left to be rediscovered.
Usage
BaseRCdplotLayerProcessor$variables(args)
Arguments
argsThe recorded call's arguments
Returns
A list of x, y and names, or NULL
BaseRCdplotLayerProcessor$default_variables()
The variables of a cdplot(x, y) call
Usage
BaseRCdplotLayerProcessor$default_variables(args)
Arguments
argsThe recorded call's arguments
Returns
A list of x, y and names, or NULL
BaseRCdplotLayerProcessor$formula_variables()
The variables of a cdplot(y ~ x, data) call
subset is carried through, because cdplot.formula builds its
model frame with it and everything downstream is the subset's:
measured on cdplot(b ~ a, data = d, subset = a > 45), the chart
draws over 46.1 to 70.9 while the whole column runs from 25.5. Read
without the subset, the grid would be trimmed to the wider range and
a fifth of the announced points would sit left of the leftmost mark.
Usage
BaseRCdplotLayerProcessor$formula_variables(formula, data, subset = NULL)
Arguments
formulaThe recorded formula
dataThe recorded data, if any
subsetThe recorded subset, if any
Returns
A list of x, y and names, or NULL
BaseRCdplotLayerProcessor$extract_axis_titles()
Name the axes
The band's number is a share of the column, not a position on the
drawn y axis – which carries the level names, and is the fill
dimension shown positionally. So ylab names z and y says what
its numbers are, the same split BaseRMosaicLayerProcessor makes
for the same reason.
Usage
BaseRCdplotLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoThe recorded call
Returns
An axes payload
BaseRCdplotLayerProcessor$extract_main_title()
The chart's own title, where the call gave one
Usage
BaseRCdplotLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoThe recorded call
Returns
The title, or an empty string
BaseRCdplotLayerProcessor$generate_selectors()
Address each band by the polygon that drew it
cdplot() writes one polygon grob per band, in draw order, which
is the bottom-to-top order the series are in. The frame it draws
around the plot is a polygon too, but gridGraphics names it
-box-1 rather than -polygon-N, so the anchored pattern does not
collect it.
Withheld entirely when the counts disagree, for the reason every processor here gives: a partial list hands a band its neighbour's element, and a user cannot tell that apart from a correct one.
Usage
BaseRCdplotLayerProcessor$generate_selectors( layer_info, gt = NULL, n_series = 0L )
Arguments
layer_infoThe recorded call
gtThe grob tree
n_seriesHow many bands the data reports
Returns
A list of CSS selectors, one per band
BaseRCdplotLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRCdplotLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Contour Layer Processor
Description
Reads a base R contour() call as the contour it draws.
contour() had no processor. base_r_adapter mapped the call to the type
"contour" and the factory fell through to the generic processor, so the
layer shipped typed "unknown" – and the core's trace factory ends its
dispatch with throw new Error("Invalid trace type: …"), so the figure
bound interactively and then failed to construct. #214 stopped that by
typing the call "unknown" at the adapter, which degrades to a static
image; this replaces the picture with the reading (#218).
The curves come from grDevices::contourLines(), which is the same
computation contour() does and takes the same defaults, so nothing here
is a guess about what was drawn:
contour.default(x = seq(0, 1, length.out = nrow(z)),
y = seq(0, 1, length.out = ncol(z)),
z, nlevels = 10, levels = pretty(zlim, nlevels),
zlim = range(z, finite = TRUE))
The payload matches ggplot2_contour_layer_processor.R exactly – a list
of curves, each a list of {x, y, level} – so the two adapters describe
one chart the same way.
Super class
LayerProcessor -> BaseRContourLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRContourLayerProcessor$process()
Build the layer
Usage
BaseRContourLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plot, layout, built, gt, grob_id, panel_id, panel_ctxPipeline arguments
layer_infoThe recorded call
Returns
List with data, selectors, type, title and axes
BaseRContourLayerProcessor$read_curves()
Read the drawn curves off the recorded call
Hands back which curves were kept as well as the curves themselves.
gridGraphics draws from the same contourLines() output, so it
writes one grob per curve before any filtering here – and
comparing a filtered count against an unfiltered one would make the
two disagree, which generate_selectors answers by withholding the
whole layer's highlighting. Keeping the indices lets each announced
curve take the grob that drew it, whatever was dropped.
Usage
BaseRContourLayerProcessor$read_curves(layer_info)
Arguments
layer_infoThe recorded call
Returns
data (curves of {x, y, level}), kept (their indices among
what contourLines() returned) and total (how many that was)
BaseRContourLayerProcessor$extract_data()
The curves alone, for callers that want only the payload
Usage
BaseRContourLayerProcessor$extract_data(layer_info)
Arguments
layer_infoThe recorded call
Returns
A list of curves, each a list of {x, y, level} points
BaseRContourLayerProcessor$contour_grid()
The grid and levels the call drew, or NULL when it drew none
Resolved the way contour.default resolves it, rather than by a rule
of our own. Its arguments are (x, y, z, ...); a named argument
claims its slot and the unnamed ones fill what is left, in order.
Then, and only then:
if (missing(z) && !missing(x) && !is.list(x)) { z <- x; x <- NULL }
which is what makes contour(m) a contour of m rather than a
chart with m on the x axis.
Reproducing that matters because the wrapper records a partially
named call: measured, contour(c(10, 20, 30), c(100, 200, 300), z)
arrives as one unnamed argument plus y = and z =. A rule that
looked for the matrix and took the unnamed arguments before it
found z already named, never looked at the unnamed one, and
announced the caller's grid on the 0-1 default – every coordinate
wrong, and nothing raised.
Usage
BaseRContourLayerProcessor$contour_grid(args)
Arguments
argsThe recorded call's arguments
Returns
A list of x, y, z and levels, or NULL
BaseRContourLayerProcessor$default_nlevels()
How many levels the drawing function defaults to
contour.default defaults to 10 and filled.contour to 20, and the
number decides the whole announced set: pretty(zlim, nlevels). The
two are otherwise resolved identically, so the difference lives here
rather than in a second copy of contour_grid().
Usage
BaseRContourLayerProcessor$default_nlevels()
Returns
The default nlevels for this call
BaseRContourLayerProcessor$extract_axis_titles()
Name the two axes
Only x and y. The level is not an axis here: it travels on every
point of the curve it belongs to, which is where the frontend's
contour trace reads it from – the same choice
ggplot2_contour_layer_processor makes, so the two adapters
describe one chart alike.
No default label. contour() prints the deparsed argument when the
caller names nothing, and those names are gone by the time the
wrapper has recorded evaluated values – so a guessed noun would be
worse than none, and the axis is left to the renderer's generic.
Usage
BaseRContourLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoThe recorded call
Returns
An axes payload
BaseRContourLayerProcessor$extract_main_title()
The chart's own title, where the call gave one
Usage
BaseRContourLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoThe recorded call
Returns
The title, or an empty string
BaseRContourLayerProcessor$generate_selectors()
Address each curve by the element that drew it
gridGraphics writes one lines grob per curve, named
graphics-plot-<group>-contour-<i>-<i>, in the order
contourLines() returns them – checked vertex count by vertex
count, not assumed. A lines grob renders as a <polyline>.
Withheld entirely when the count does not match what was announced. The frontend drops a layer whose selector list disagrees with its series count, and a partial list would hand a curve its neighbour's element – the defect #145 and #204 are both about.
Usage
BaseRContourLayerProcessor$generate_selectors( layer_info, gt = NULL, kept = integer(0), total = 0 )
Arguments
layer_infoThe recorded call
gtThe grob tree
keptWhich of the drawn curves were announced
totalHow many curves were drawn
Returns
A list of CSS selectors, one per announced curve
BaseRContourLayerProcessor$find_contour_grobs()
Every contour grob this layer drew
Usage
BaseRContourLayerProcessor$find_contour_grobs(grob, group_index)
Arguments
grobThe grob tree
group_indexWhich plot on the device
Returns
A character vector of grob names
BaseRContourLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRContourLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Correlogram Layer Processor
Description
Processes the three correlogram entry points – acf(), pacf() and
ccf(). Each draws one vertical spike per lag, from the zero line to the
correlation at that lag, and joins nothing to anything.
Read as a lollipop layer, for the reason BaseRSpikeLayerProcessor
gives: a line would say the samples are joined and that the space between
two lags can be interpolated, which is the one relationship a correlogram
is drawn to deny. The spikes even export under the same grob name –
measured, plot(acf(v)) names them graphics-plot-1-spike-1 – so the
inherited selector search needs no override.
What this adds is where the numbers come from. The recorded call holds the
series, not the correlogram: measured, acf(v, lag.max = 5) records
one HIGH call whose args are the 60 observations and lag.max. So the
reading replays the call with plot = FALSE and takes $lag and $acf
off the result, which is the same shape BaseRSpineplotLayerProcessor
takes for a table it cannot read off the drawing either.
All three differ in what the lags are, and the replay answers that too rather than the reading assuming it. Measured on one 60-point series:
acf(v, lag.max = 5) lags 0 1 2 3 4 5 pacf(v, lag.max = 5) lags 1 2 3 4 5 ccf(v, w, lag.max = 3) lags -3 -2 -1 0 1 2 3
acf starts at lag 0, whose correlation is 1 by construction and which
the chart draws; pacf has no lag 0 at all; and a cross-correlation's
lags are signed, because "x leads y" and "y leads x" are different
statements. Announcing any of the three as another would misname every
spike on the chart.
Super classes
LayerProcessor -> BaseRLineLayerProcessor -> BaseRSpikeLayerProcessor -> BaseRCorrelogramLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRLineLayerProcessor$axis_extent()BaseRLineLayerProcessor$extract_abline_data()BaseRLineLayerProcessor$extract_multiline_data()BaseRLineLayerProcessor$extract_single_line_data()BaseRLineLayerProcessor$find_lines_grobs()BaseRLineLayerProcessor$generate_selectors()BaseRLineLayerProcessor$generate_selectors_from_grob()BaseRLineLayerProcessor$get_axis_labels()BaseRLineLayerProcessor$get_x_range_from_group()BaseRLineLayerProcessor$get_y_range_from_group()BaseRLineLayerProcessor$needs_reordering()BaseRSpikeLayerProcessor$selector_grob_type()
BaseRCorrelogramLayerProcessor$process()
Process the correlogram layer.
Usage
BaseRCorrelogramLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused for Base R (kept for interface compatibility)
layoutUnused for Base R (kept for interface compatibility)
builtUnused for Base R (kept for interface compatibility)
gtGtable object used for selector generation (optional)
grob_idUnused for Base R
panel_idUnused for Base R
panel_ctxUnused for Base R
layer_infoInformation about the recorded plot call
Returns
List with data, selectors, type, title and axes
BaseRCorrelogramLayerProcessor$extract_data()
Read one point per lag the correlogram draws.
The lag on the category axis and the correlation as the magnitude,
in the order they are drawn – which for ccf runs from the most
negative lag rightwards, so the announced order is the drawn one.
Usage
BaseRCorrelogramLayerProcessor$extract_data(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
List of x/y points, empty when the replay states nothing
BaseRCorrelogramLayerProcessor$extract_axis_titles()
Name the lag axis and the quantity drawn against it.
A correlogram writes its own axis labels, so there is nothing the
caller titled to read – and the inherited X/Y fallback would
name a lag after a coordinate. The value axis follows what the replay
says it computed: acf(type = "covariance") draws covariances, not
correlations, and calling them correlations would announce a
normalisation the chart never applied.
Usage
BaseRCorrelogramLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
Named list with x and y
BaseRCorrelogramLayerProcessor$extract_main_title()
Title the chart the way the drawing does.
plot.acf() writes "Series v" above an acf and "v & w" above a
ccf, and the replayed object carries those as $series and
$snames – but not usefully. Both are deparse(substitute(x)), and
the replay hands stats the recorded values rather than the name
the caller wrote, so measured they come back as the whole series
pasted in: Series c(-2.0715334064552, -0.117989125730012, ...).
That is worse than no title at all.
The name is in the recorded call expression instead, which is kept as
the source text of the call – measured, "acf(v, lag.max = 3)". It
is used only when the argument is a bare symbol: a caller who wrote
acf(rnorm(60)) named nothing, and titling the chart with the
expression that produced it would announce a call rather than a
series.
A caller's own main = wins, which is what the inherited reading
already answers.
Usage
BaseRCorrelogramLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
The title, or NULL when the caller named nothing
BaseRCorrelogramLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRCorrelogramLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Cumulative Periodogram Processor
Description
Reads cpgram() as the staircase it draws: the cumulative periodogram
against frequency, held across each interval and then jumping.
It is a step, not a line. cpgram() plots with type = "s", which
draws the horizontal segment first – MAIDR's "hv". A line would imply
the value slides between frequencies, which is not what a cumulative sum
does, and the export agrees: the grob is step-1, not lines-1.
It does NOT use spectrum()'s estimate. This is the trap the reading
exists to avoid. spectrum() defaults to taper = 0.1, detrend = TRUE, demean = FALSE and smooths; cpgram() computes its own periodogram –
taper, FFT, zero the first ordinate, then normalise the cumulative sum –
and the two disagree. Measured, the second step of the drawn curve is
0.0801 while spectrum()'s estimate gives 0.0817: close enough to look
right and wrong enough to announce wrong numbers. So the computation below
is cpgram()'s own, and it reproduces the traced plot.xy call exactly.
Super classes
LayerProcessor -> BaseRLineLayerProcessor -> BaseRCpgramLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRLineLayerProcessor$axis_extent()BaseRLineLayerProcessor$extract_abline_data()BaseRLineLayerProcessor$extract_axis_titles()BaseRLineLayerProcessor$extract_data()BaseRLineLayerProcessor$extract_main_title()BaseRLineLayerProcessor$extract_multiline_data()BaseRLineLayerProcessor$extract_single_line_data()BaseRLineLayerProcessor$find_lines_grobs()BaseRLineLayerProcessor$generate_selectors()BaseRLineLayerProcessor$generate_selectors_from_grob()BaseRLineLayerProcessor$get_axis_labels()BaseRLineLayerProcessor$get_x_range_from_group()BaseRLineLayerProcessor$get_y_range_from_group()BaseRLineLayerProcessor$needs_reordering()BaseRLineLayerProcessor$selector_grob_type()
BaseRCpgramLayerProcessor$process()
Emit the cumulative periodogram as a step
Usage
BaseRCpgramLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface.
layoutUnused; present for the processor interface.
builtUnused; present for the processor interface.
gtUnused; the selector is built rather than searched for.
grob_idUnused; present for the processor interface.
panel_idUnused; present for the processor interface.
panel_ctxUnused; present for the processor interface.
layer_infoLayer information with the recorded call.
Returns
A step layer, or NULL when nothing was read
BaseRCpgramLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRCpgramLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Dodged Bar Layer Processor
Description
Processes Base R dodged bar plot layers with proper ordering to match backend logic
Super class
LayerProcessor -> BaseRDodgedBarLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRDodgedBarLayerProcessor$process()
Process the layer: read its data, selectors, axis titles and main title from the recorded call
Usage
BaseRDodgedBarLayerProcessor$process( plot, layout, built = NULL, gt = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface
layoutUnused; present for the processor interface
builtUnused; present for the processor interface
gtGtable of the replayed drawing, searched for selectors (optional)
layer_infoLayer information with the recorded call
Returns
List describing the layer for the MAIDR payload
BaseRDodgedBarLayerProcessor$extract_data()
One series per row of the recorded height matrix
Usage
BaseRDodgedBarLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of series
BaseRDodgedBarLayerProcessor$generate_selectors()
The selector for the bars, scoped to this layer's plot group
Usage
BaseRDodgedBarLayerProcessor$generate_selectors(layer_info, gt = NULL)
Arguments
layer_infoLayer information with the recorded call
gtGtable of the replayed drawing (optional)
Returns
List of selectors
BaseRDodgedBarLayerProcessor$find_rect_grobs()
Find the rect grobs drawn by the recorded call at call_index
Usage
BaseRDodgedBarLayerProcessor$find_rect_grobs(grob, call_index)
Arguments
grobThe grob tree to search
call_indexIndex of the recorded plot group, which numbers the panel's grobs
Returns
Character vector of grob names
BaseRDodgedBarLayerProcessor$generate_selectors_from_grob()
Build this layer's selector from the grob tree
Usage
BaseRDodgedBarLayerProcessor$generate_selectors_from_grob(grob, call_index)
Arguments
grobThe grob tree to search
call_indexIndex of the recorded plot group, which numbers the panel's grobs
Returns
A selector string, or an empty string when no grob matches
BaseRDodgedBarLayerProcessor$extract_axis_titles()
Extract the axis titles for this layer
Same shape as the stacked processor: barplot(beside = TRUE) writes no
title, its points carry the column category on x and the bar height on
y, and the group each bar belongs to travels with the point as z rather
than as a named axis.
Usage
BaseRDodgedBarLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information
Returns
Canonical axes list
BaseRDodgedBarLayerProcessor$extract_main_title()
The main title of the recorded call, or an empty string
Usage
BaseRDodgedBarLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Character string
BaseRDodgedBarLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRDodgedBarLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Dot Chart Layer Processor
Description
Processes Base R dotchart() layers – a Cleveland dot plot: one value
per category, marked with a dot on a horizontal guide line, with the
categories running down the page.
Read as a dot layer, which the core builds on BarTrace: a bar chart's
reading with a different mark. The guide lines and the category labels are
frame rather than data – gridGraphics draws them as -abline-h- and
-mtext-left-, and only the dots carry a value.
orientation is "horz", which is not a detail: dotchart() puts the
categories on the vertical axis and the value along the horizontal one,
and the core reads a horz layer's magnitude from x and its category
from y. Without the key the layer defaults to vertical and reads the
category name where the magnitude belongs – no number to pitch, and the
announcement inverted (#184, #480).
The dots are emitted in the order dotchart() was handed them, which is
bottom-up on the drawn chart – base R puts the first element at the
bottom. That is the arrangement barplot(horiz = TRUE) already ships for
the same reason, so the two horizontal base R charts read from the same
end.
Selectors come from the points grob, which is the one thing a dotchart
shares with a scatter: graphics-plot-N-points-1 holds one <use> per
dot. So this inherits BaseRPointLayerProcessor and replaces what is
read out of the call rather than how the marks are addressed.
Super classes
LayerProcessor -> BaseRPointLayerProcessor -> BaseRDotchartLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRPointLayerProcessor$extract_axis_titles()BaseRPointLayerProcessor$extract_base_r_axis_grid_info()BaseRPointLayerProcessor$extract_main_title()BaseRPointLayerProcessor$formula_variables()BaseRPointLayerProcessor$generate_selectors()BaseRPointLayerProcessor$needs_reordering()BaseRPointLayerProcessor$resolve_coordinates()
BaseRDotchartLayerProcessor$process()
Process the dot chart layer.
Usage
BaseRDotchartLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused for Base R (kept for interface compatibility)
layoutUnused for Base R (kept for interface compatibility)
builtUnused for Base R (kept for interface compatibility)
gtGtable object used for selector generation (optional)
grob_idUnused for Base R
panel_idUnused for Base R
panel_ctxUnused for Base R
layer_infoInformation about the recorded plot call
Returns
List with data, selectors, type, title, axes and orientation
BaseRDotchartLayerProcessor$extract_data()
Read the dots out of the recorded dotchart() call.
dotchart(x, labels = NULL, ...) names its dots from labels when
the caller gives them and from names(x) otherwise, which is what the
chart draws down its left margin. A vector with neither is drawn
against blank labels, and is emitted here against its positions so a
reader still has something to navigate by.
x and y carry the magnitude and the category respectively, which
is the arrangement a horz layer means – see the class note.
Usage
BaseRDotchartLayerProcessor$extract_data(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
List of x/y points, empty when there is nothing to read
BaseRDotchartLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRDotchartLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Filled Contour Layer Processor
Description
Reads a base R filled.contour() call as the contour it draws.
filled.contour draws the same level curves contour() does and fills the
bands between them, so it is read the same way: one curve per level, from
grDevices::contourLines(), which is the computation the drawing itself
runs. One chart with two spellings gets one reading.
Two things differ from contour(), and only two:
The level default. contour.default takes nlevels = 10 and
filled.contour takes nlevels = 20, and the number decides the whole
announced set through pretty(zlim, nlevels). Everything else about
resolving the call – the (x, y, z, ...) slots, the
if (missing(z)) z <- x fallback, the list(x =, y =, z =) unpacking,
the zlim default – is identical in both, so this class overrides the
number and inherits the rest.
The chart cannot be highlighted, and the inherited code already knows
it. contour() writes one lines grob per curve, which is what
generate_selectors() pairs against. filled.contour writes one
polygon grob for the entire field, and gridSVG exports it as a flat run
of pieces. Measured on a 6x5 grid drawn at the 17 default levels:
grobs written graphics-plot-2-filled-contour-1 (one) SVG polygons graphics-plot-2-filled-contour-1.1.1 .. .1.160 curves announced 40
160 pieces against 40 curves, and against 17 levels: the polygons are the
grid's cells cut by the level crossings, not the bands and not the curves.
Nothing pairs, so nothing is emitted – the inherited
generate_selectors() finds no -contour-N-N grob, its count check fails,
and it withholds the list, which is the same answer it gives a contour()
whose grobs and curves disagree. A layer with no selectors is announced,
sonified and navigated; it is the visual highlight alone that is missing,
and that is the established degradation here (#89) rather than a reason to
ship a picture.
Note also that the field is drawn in the second plot region: the call
lays out a colour key as graphics-plot-1 and the field as
graphics-plot-2. Nothing here depends on that, because nothing here
addresses a grob, but a later attempt to highlight this chart will.
py-maidr declines the equivalent call. Its reason – recorded in
maidr/patch/contour.py – is that contourf hands back the filled paths
and "an outline of one runs along two different level curves", which is a
statement about deriving curves from what was drawn. It does not apply
here: R hands over contourLines(), so the curves announced are the level
curves themselves rather than an inference from the fill, and every one of
them is on the page as the boundary between two bands.
Super classes
LayerProcessor -> BaseRContourLayerProcessor -> BaseRFilledContourLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRContourLayerProcessor$contour_grid()BaseRContourLayerProcessor$extract_axis_titles()BaseRContourLayerProcessor$extract_data()BaseRContourLayerProcessor$extract_main_title()BaseRContourLayerProcessor$find_contour_grobs()BaseRContourLayerProcessor$generate_selectors()BaseRContourLayerProcessor$process()BaseRContourLayerProcessor$read_curves()
BaseRFilledContourLayerProcessor$default_nlevels()
How many levels filled.contour() defaults to
Twice contour()'s, and the only number that separates the two.
Usage
BaseRFilledContourLayerProcessor$default_nlevels()
Returns
20
BaseRFilledContourLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRFilledContourLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Fourfold Display Layer Processor
Description
Processes Base R fourfoldplot() layers drawn with
std = "ind.max" or std = "all.max" – a 2x2 contingency table drawn as
four quarter-circles, one per cell, sized so the wedge's AREA is
proportional to that cell's count.
Read as a heat layer, for the same reason assocplot() is: the drawing
is a 2x2 grid of one number per cell, and row-then-column is how a reader
navigates a contingency table. Measured on
fourfoldplot(as.table(matrix(c(10, 40, 90, 160), 2)), std = "ind.max"),
the radii and the counts they recover:
grob r quadrant r^2 * max(count) cell graphics-plot-1-polygon-1 0.250000 upper LEFT 10 [1, 1] graphics-plot-1-polygon-2 0.500000 lower LEFT 40 [2, 1] graphics-plot-1-polygon-3 0.750000 upper RIGHT 90 [1, 2] graphics-plot-1-polygon-4 1.000000 lower RIGHT 160 [2, 2]
exactly, so radius / sqrt(count) is one constant (0.0790569415 here, with a
relative spread of 1.755e-16). The table's FIRST dimension runs
vertically and its SECOND horizontally – the transpose of assocplot()'s
arrangement, and measured from the label grobs, which put
names(dimnames(x))[1] at the top and bottom of the drawing and
names(dimnames(x))[2] at the left and right.
Nothing is inferred from the drawing. fourfoldplot() is handed the table,
so the recorded call carries every number the trace wants; the grobs are
consulted only to decide whether the drawing on the page is the one the
recorded call describes.
What this deliberately does not do
It is not a mosaic and it is not a bar. A mosaic's tiles tile a
whole and carry proportions of it; these are four independent quarter-discs
separated by space (default 0.2) that tile nothing. A bar trace would
imply a value axis with a zero baseline and one categorical axis, while
measured the radii are on a square-root scale and the quadrants are laid
out in two dimensions.
The confidence arcs are dropped. Measured, a conf.level draws 8
unfilled arcs (polygon-5 .. polygon-12), arcs 4 + j and 8 + j being
the lower and upper bound of cell c(tab)[j]. A heat layer has nowhere
to carry an interval, so a reader is told the counts and not that the chart
also draws a band around each. Unlike qqplot's band this does not justify
declining: the arcs decorate numbers that ARE fully carried.
The odds ratio is never announced. There is no MAIDR trace for one
scalar. Under ind.max/all.max a reader gets four counts and can compute
it.
Where the two gates live, and what the second one cannot do
#268 asks that a chart whose geometry disagrees LOSE the reading rather
than get a wrong one. That is not achievable here and this does not pretend
it is. Verified against BaseRPlotOrchestrator$initialize(), which runs
detect_layers(), resolve_fallback_scope(), create_layer_processors()
and process_layers() at lines 122-125: the picture-versus-chart decision
is frozen by line 123, which reads private$.layers[[i]]$type through
unsupported_layer_flags(). That field is written only by the two
private$.layers[[layer_counter]] <- list(type = ...) assignments at lines
147 and 169, both from detect_layer_type(), and is never rewritten from a
processor result; line 124 does not even build a processor for a layer
already typed "unknown" (line 219). A processor that answered
type = "unknown" would ship that string with has_unsupported_layers()
still FALSE – the #214 failure BaseRProcessorFactory$get_supported_types()
records, where the figure binds and then fails to construct.
So the split is:
the argument gate is
fourfold_decline_reason(), called fromdetect_layer_type(), and it CAN lose the reading;the geometry gate is
radii_agree()below, and it can only returnlist()fromgenerate_selectors()– the numbers are still announced and nothing highlights. That is the shipped pie idiom: "a short list means these are not this pie's grobs. Filling the gap with a guessed id would silently highlight another panel's wedges."
What the geometry gate can and cannot see
Measured, and weaker than it looks:
It is exactly scale-invariant. A drawing of
tab * 3, or oftab * 1e6, checked againsttab's counts gives a relative deviation of1.755e-16and passes.radius / sqrt(count) == 1 / sqrt(max(tab))is an identity insidestdize(), so no table can falsify it and an upstream change to whatind.maxmeans would go uncaught at runtime. That exposure is carried by the live-drawing assertions intest-base-r-fourfoldplot.R, the same bet theqqplotbranch makes.It passes for a symmetric table drawn under the default
std. Measured,9, 4, 4, 9understd = "margins"gives a relative deviation of0.000e+00, and so does7, 7, 7, 7; algebraically, withn11 = n22 = aandn12 = n21 = b,u / a == (1 - u) / b == 1 / (a + b). It recovers off symmetry fast –9, 4, 4, 9.0001gives2.778e-06and fails at1e-8– but this is whystdis the first gate and the geometry only the second.
What it does catch is a grob tree that is not this call's: measured,
fourfoldplot(UCBAdmissions, std = "ind.max") draws 78 polygons, and an
asymmetric table's margins drawing checked against its own counts gives
7.616e-01.
Super class
LayerProcessor -> BaseRFourfoldLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRFourfoldLayerProcessor$process()
Process the fourfold display layer.
Usage
BaseRFourfoldLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused for Base R (kept for interface compatibility)
layoutUnused for Base R (kept for interface compatibility)
builtUnused for Base R (kept for interface compatibility)
gtGtable object used for selector generation (optional)
grob_idUnused for Base R
panel_idUnused for Base R
panel_ctxUnused for Base R
layer_infoInformation about the recorded plot call
Returns
List with data, selectors, type, title and axes
BaseRFourfoldLayerProcessor$needs_reordering()
Whether the plot data must be reordered before drawing; a Base R layer is read from the recorded call and never is
Usage
BaseRFourfoldLayerProcessor$needs_reordering()
Returns
FALSE
BaseRFourfoldLayerProcessor$recorded_table()
The 2x2 table of counts the call was handed, when it is one.
Guarded by fourfold_decline_reason(), the same predicate
detect_layer_type() asks, so dispatch and extraction cannot disagree
about which calls are readable.
Used for the COUNTS and the shape only. The level names and the axis
names come from drawn_dimnames() instead, which is not the same
thing – see there.
Usage
BaseRFourfoldLayerProcessor$recorded_table(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
A 2x2 table, or NULL
BaseRFourfoldLayerProcessor$drawn_dimnames()
The dimnames fourfoldplot() itself labels the chart with.
NOT dimnames(recorded_two_way_table(...)), and the difference is the
whole point. recorded_two_way_table() repairs dimnames through
as.table(); graphics::fourfoldplot repairs them from dimnames(x)
as handed, after reshaping a 2-D x to 2 x 2 x 1. Its own source:
if (length(dim(x)) == 2L)
x <- if (is.null(dimnames(x))) array(x, c(dim(x), 1L))
else array(x, c(dim(x), 1L), c(dimnames(x), list(NULL)))
dnx <- dimnames(x)
if (is.null(dnx)) dnx <- vector("list", 3L)
for (i in which(sapply(dnx, is.null))) dnx[[i]] <- LETTERS[seq_len(dim(x)[i])]
if (is.null(names(dnx))) i <- 1L:3L else i <- which(is.null(names(dnx)))
if (any(i)) names(dnx)[i] <- c("Row", "Col", "Strata")[i]
reproduced here rather than approximated. For an ftable the two
disagree completely: dimnames(ftable(tb)) is NULL, so the chart is
labelled Row: A, Col: A, Row: B, Col: B – measured off the
text grobs – while as.table(ftable(tb)) reconstructs
Treatment/Outcome and Drug/Placebo/Cured/Not. Reading the
levels off as.table() would announce six strings that appear nowhere
on the page, which is #268's own failure displaced from the numbers
onto the labels.
The which(is.null(names(dnx))) line is upstream's, quirk included:
is.null() returns one logical, so that expression is always
integer(0) and the Row/Col default fires only when
names(dimnames(x)) is entirely NULL. A PARTIALLY named dimnames is
therefore never repaired, and measured, names(dimnames(t)) <- c("Answer", "") makes the chart literally draw ": hi" and ": lo".
extract_axis_titles() substitutes "Col" there rather than announce
an empty label – deliberately better than the chart, and the one place
this reading is not identical to it. test-base-r-fourfoldplot.R pins
the chart's wrong answer as well as ours.
Usage
BaseRFourfoldLayerProcessor$drawn_dimnames(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
A length-3 named list of dimnames, or NULL
BaseRFourfoldLayerProcessor$extract_data()
Read the 2x2 grid of counts out of the recorded call.
Rows of the emitted grid are the table's FIRST dimension, top to
bottom, and its columns the SECOND, left to right – measured from the
drawing, where polygon-1 (cell [1, 1]) is the upper-left quadrant
and the top and bottom labels carry names(dimnames(x))[1]. That is
the transpose of what assocplot() does with the same argument, and
it is not a convention chosen here.
The level names come from drawn_dimnames(), so they are the strings
the chart puts beside each quadrant.
Usage
BaseRFourfoldLayerProcessor$extract_data(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
List with points, x and y, empty when there is no readable table
BaseRFourfoldLayerProcessor$levels_of()
The level names of one table dimension, as drawn.
drawn_dimnames() is NULL only when the recorded first argument has no
2-D dim() at all, which a readable call cannot have; the fallback is
there so a malformed layer_info in a test yields level names rather
than an error.
Usage
BaseRFourfoldLayerProcessor$levels_of(named, i, fallback)
Arguments
namedThe list
drawn_dimnames()returned, or NULLiWhich dimension, 1 or 2
fallbackLevel names to use when there are none drawn
Returns
A character vector of level names
BaseRFourfoldLayerProcessor$extract_axis_titles()
Name the axes the way the chart places the dimensions.
x is the SECOND dimension, because measured the columns run left to
right; y is the first, because the rows run top to bottom. z names
what the numbers are rather than a dimension of the table – a reader
told "Outcome" for the value would be given a level name where a number
is.
"Count" is the contingency-table convention and not a claim that the
values are whole numbers: measured, fourfoldplot() draws non-integer
cells happily (1.5, 2.5, 3.5, 4.5 gives radii
0.5774, 0.7454, 0.8819, 1.0000 and the ratio check passes).
No recorded_axis_label() call, unlike the assocplot processor.
Measured, names(formals(graphics::fourfoldplot)) is exactly
x, color, conf.level, std, margin, space, main, mfrow, mfcol – no
xlab, no ylab, no ... – and fourfoldplot(tab, xlab = "X")
stops with "unused argument". Reading a label that the function rejects
would be dead code asserting an argument that cannot exist.
Usage
BaseRFourfoldLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
Canonical axes list
BaseRFourfoldLayerProcessor$extract_main_title()
The title the call was given, if any.
Usage
BaseRFourfoldLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
Character scalar, empty when the author wrote no title
BaseRFourfoldLayerProcessor$wedge_names()
The four wedge grobs of one fourfold panel, or NULL.
Discriminated by polygon count and vertex count, NOT by gp$fill.
Fill looks like the exact discriminator and is not: measured,
fourfoldplot(tb, std = "ind.max", color = "steelblue") leaves two
quadrants with fill = NA, because fourfoldplot() does not validate
color's length and its draw calls index it as
color[1 + (d > 1)] / color[2 - (d > 1)]. A fill-keyed search finds
two wedges there and the layer would ship with no selectors at all, for
a chart that is perfectly readable.
What is measured to be stable:
one panel draws exactly 13 polygons (4 wedges, 8 confidence arcs, 1 frame) or exactly 5 when
conf.levelis0orFALSE. The arc count is 8 or 0 and never anything else –conf.levelproduces twofor (j in 1:4)loops guarded byis.numeric(conf.level), and every other value (1,-0.1,NA, a length-2 vector,NULL) is rejected byfourfoldplot()itself. Measured,kpanels draw13kor5k:UCBAdmissionsgives 78 and 30, so this count also refuses another figure's grob tree.the wedges are always the first four in
find_graphics_plot_grobs()order, becausedrawPie()runs before the rings and before the frame at everyconf.level;every quarter disc has 501 vertices (
drawPie(n = 500)plus the centre point) and the frame is the only 4-vertex polygon.
Usage
BaseRFourfoldLayerProcessor$wedge_names(gt, plot_index)
Arguments
gtGrob tree to search
plot_indexThe plot (panel) index the grob names carry
Returns
The four wedge grob names, or NULL when this is not one panel
BaseRFourfoldLayerProcessor$radii_agree()
Whether the wedges on the page are the counts in the call.
radius / sqrt(count) constant across the four quadrants, to a
relative spread of 1e-8. Measured headroom on the worst-conditioned
tables that fourfoldplot() will draw at all –
c(1e-9, 1, 1, 1) (2.220e-16), c(1, 2, 3, 1e18) (2.068e-16) and
the non-integer c(1.5, 2.5, 3.5, 4.5) (1.178e-16) – is eight
orders below the threshold, while an asymmetric table's margins
drawing checked against its counts gives 7.616e-01. (c(1, 1e15, 1, 1) is not in that list because radii_agree() is never asked about
it – not because it errors. Measured, fourfoldplot() returns
normally there with a "NaNs produced" warning and emits ZERO polygon
grobs under ind.max and all.max, so wedge_names() refuses it on
the polygon count first. Under the default margins the same table
does draw 13 polygons – radii 0.00017782794, 0.99999998, 0.99999998, 0.00017782794 – but no margins call reaches a
processor.)
A zero count makes radius / sqrt(count) 0/0, so those cells are
held to radius == 0 instead – measured, a zero cell still emits a
full 501-vertex polygon at the origin, so the grob is there and
addressable.
The check is vacuous when fewer than two cells are non-zero: one
non-zero cell makes the relative deviation identically 0 whatever the
radius is. Measured, 0, 0, 0, 160 under ind.max draws radii
0, 0, 0, 1 and would pass an unguarded check against any table with
the same three zeros. Two non-zero cells are required before the ratio
is treated as evidence, so such a chart announces its counts and
highlights nothing.
Usage
BaseRFourfoldLayerProcessor$radii_agree(gt, names, counts)
Arguments
gtGrob tree to search
namesThe four wedge grob names, in drawing order
countsThe four recorded counts, in
c(tab)order
Returns
TRUE when the drawing carries the recorded counts
BaseRFourfoldLayerProcessor$generate_selectors()
Address the quadrant the chart drew each count into.
Each quadrant is its own polygon grob, so each needs its own selector – the pie's situation, not the barplot's. Two orderings compose here, and they run in opposite directions:
-
The drawing is column-major. Table cell
[r, c]is polygon(c - 1) * 2 + r. Measured on the exported SVG offourfoldplot(tb, std = "ind.max")withc(tab) = 10, 40, 90, 160, the polygon centroids in screen coordinates (the root<g>carriestranslate(0, 360) scale(1, -1), so screenyis360 - y) arepolygon-1 (221, 158)upper LEFT,polygon-2 (190, 224)lower LEFT,polygon-3 (345, 114)upper RIGHT,polygon-4 (376, 268)lower RIGHT, and the count labels sit at10 (90, 55),40 (90, 305),90 (414, 55),160 (414, 305). So table row 1 is the TOP row on the page, which is the rowextract_data()emits first. -
The
heattrace reverses the numbers and not the selectors. In the bundledmaidr-4.8.0/maidr.jsthe constructor isthis.y=[...t.y].reverse(),this.heatmapValues=[...t.points].reverse(), whilemapToSvgElements()'s array-of-arrays branch walkse[i]index for index. Its bare-string branch immediately below DOES reverse (let a=t-1-e), which is what makes the asymmetry easy to miss. SohighlightValues[0]lines up withpoints' LAST row.
Grid row 1 is therefore the BOTTOM wedges:
[[polygon-2, polygon-4], [polygon-1, polygon-3]]. The wrong answer
is to emit it index-aligned with points, top row first – it reads
correctly and highlights the vertically mirrored quadrant on every
cell of every fourfold plot: row 0, col 0 then announces
Placebo / 40 while lighting the wedge drawn for Drug / 10.
test-base-r-fourfoldplot.R pins the bottom-first order against that.
image()/heatmap() is the precedent – measured on
image(matrix(1:6, 2)), points[[1]] is the top row while
selectors[[1]] is rect:nth-child(1), the lowest rect on the page –
and NEWS.md records fixing the same mirror there.
Returns list() when the drawing and the recorded call disagree. The
numbers are still announced – they are what the call was handed – and
nothing highlights, rather than a highlight landing on another panel's
quadrant.
Usage
BaseRFourfoldLayerProcessor$generate_selectors( layer_info, gt = NULL, extracted_data = NULL )
Arguments
layer_infoInformation about the recorded plot call
gtGrob tree to search
extracted_dataUnused; the counts are re-read from the call
Returns
A 2x2 nested list of selectors, or an empty list
BaseRFourfoldLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRFourfoldLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Heatmap Layer Processor
Description
Processes Base R heatmap layers using the heatmap() function
Super class
LayerProcessor -> BaseRHeatmapLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRHeatmapLayerProcessor$process()
Process the layer: read its data, selectors, axis titles and main title from the recorded call
Usage
BaseRHeatmapLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface
layoutUnused; present for the processor interface
builtUnused; present for the processor interface
gtGtable of the replayed drawing, searched for selectors (optional)
grob_idUnused; present for the processor interface
panel_idUnused; present for the processor interface
panel_ctxUnused; present for the processor interface
layer_infoLayer information with the recorded call
Returns
List describing the layer for the MAIDR payload
BaseRHeatmapLayerProcessor$extract_data()
One row per cell of the recorded matrix, in drawn order
Usage
BaseRHeatmapLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of rows
BaseRHeatmapLayerProcessor$compute_heatmap_ordering()
Reproduce the row/column ordering heatmap() draws with
Usage
BaseRHeatmapLayerProcessor$compute_heatmap_ordering(args)
Arguments
argsRecorded heatmap() arguments
Returns
List with rowInd/colInd, or NULL if unavailable
BaseRHeatmapLayerProcessor$generate_selectors()
Selectors for the image tiles, one per cell
Usage
BaseRHeatmapLayerProcessor$generate_selectors( layer_info, gt = NULL, extracted_data = NULL )
Arguments
layer_infoLayer information with the recorded call
gtGtable of the replayed drawing (optional)
extracted_dataThe data already extracted for this layer (optional)
Returns
List of selectors
BaseRHeatmapLayerProcessor$find_image_rect_grobs()
Find the image-rect grobs drawn by the plot group at group_index
Usage
BaseRHeatmapLayerProcessor$find_image_rect_grobs(grob, group_index)
Arguments
grobThe grob tree to search
group_indexIndex of the recorded plot group, which numbers the panel's grobs
Returns
Character vector of grob names
BaseRHeatmapLayerProcessor$generate_selectors_from_grob()
Build this layer's selector from the grob tree
Usage
BaseRHeatmapLayerProcessor$generate_selectors_from_grob( grob, group_index = NULL )
Arguments
grobThe grob tree to search
group_indexIndex of the recorded plot group, which numbers the panel's grobs
Returns
A selector string, or an empty string when no grob matches
BaseRHeatmapLayerProcessor$extract_axis_titles()
Extract the axis titles for this layer
heatmap() lays the matrix out one way round only – its columns run
along x and its rows up y – so those two words are facts about the
call. image() is not the same picture: it draws a coordinate grid,
and image(x, y, z) puts the caller's own coordinates on those axes,
so naming them after a matrix would be a guess. It gets no default.
Usage
BaseRHeatmapLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information
Returns
Canonical axes list
BaseRHeatmapLayerProcessor$extract_main_title()
The main title of the recorded call, or an empty string
Usage
BaseRHeatmapLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Character string
BaseRHeatmapLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRHeatmapLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Histogram Layer Processor
Description
Processes Base R histogram plot layers using verified data extraction and selector generation logic.
Super class
LayerProcessor -> BaseRHistogramLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRHistogramLayerProcessor$process()
Process the layer: read its data, selectors, axis titles and main title from the recorded call
Usage
BaseRHistogramLayerProcessor$process( plot, layout, built = NULL, gt = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface
layoutUnused; present for the processor interface
builtUnused; present for the processor interface
gtGtable of the replayed drawing, searched for selectors (optional)
layer_infoLayer information with the recorded call
Returns
List describing the layer for the MAIDR payload
BaseRHistogramLayerProcessor$extract_data()
One point per bin, from the histogram recomputed from the recorded call
Usage
BaseRHistogramLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of points
BaseRHistogramLayerProcessor$recompute_histogram()
Recompute the plotted histogram from the recorded call
Usage
BaseRHistogramLayerProcessor$recompute_histogram(args)
Arguments
argsRecorded argument list
Returns
A "histogram" object, or NULL when the call recorded no data
BaseRHistogramLayerProcessor$is_frequency()
Is this a frequency histogram rather than a density one?
The plotted y-axis shows counts only for frequency histograms; with freq = FALSE or probability = TRUE it shows densities. hist()'s own default is freq = TRUE only for equidistant breaks.
Usage
BaseRHistogramLayerProcessor$is_frequency(args, hist_obj = NULL)
Arguments
argsRecorded argument list
hist_objThe recomputed histogram, or NULL when there is none
Returns
Logical
BaseRHistogramLayerProcessor$generate_selectors()
The selector for the bins, scoped to this layer's plot group
Usage
BaseRHistogramLayerProcessor$generate_selectors(layer_info, gt = NULL)
Arguments
layer_infoLayer information with the recorded call
gtGtable of the replayed drawing (optional)
Returns
List of selectors
BaseRHistogramLayerProcessor$find_rect_grobs()
Find the rect grobs drawn by the recorded call at call_index
Usage
BaseRHistogramLayerProcessor$find_rect_grobs(grob, call_index)
Arguments
grobThe grob tree to search
call_indexIndex of the recorded plot group, which numbers the panel's grobs
Returns
Character vector of grob names
BaseRHistogramLayerProcessor$generate_selectors_from_grob()
Build this layer's selector from the grob tree
Usage
BaseRHistogramLayerProcessor$generate_selectors_from_grob( grob, call_index = NULL )
Arguments
grobThe grob tree to search
call_indexIndex of the recorded plot group, which numbers the panel's grobs
Returns
A selector string, or an empty string when no grob matches
BaseRHistogramLayerProcessor$extract_axis_titles()
Extract the axis titles for this layer
hist() derives both titles inside the call and so records neither:
the x title is deparse(substitute(x)), which is gone by the time the
evaluated arguments reach us, and the y title is "Frequency" or
"Density" depending on what the bars measure. The y default therefore
repeats hist()'s own choice – resolved by the same rule that decides
which values extract_data() emits, so the noun always names the number
being announced – while x says only what the axis certainly holds:
the bins.
Usage
BaseRHistogramLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information
Returns
Canonical axes list
BaseRHistogramLayerProcessor$frequency_label()
The title hist() itself would print above the counted axis
Usage
BaseRHistogramLayerProcessor$frequency_label(args)
Arguments
argsRecorded argument list
Returns
"Frequency" or "Density"
BaseRHistogramLayerProcessor$extract_main_title()
The main title of the recorded call, or an empty string
Usage
BaseRHistogramLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Character string
BaseRHistogramLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRHistogramLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Interaction Plot Layer Processor
Description
Reads interaction.plot() as the set of lines it draws: one series per
level of the trace factor, running across the levels of the x factor at
fun(response) for each cell.
stats::interaction.plot computes that grid itself and hands it straight
to matplot:
cells <- tapply(response, list(x.factor, trace.factor), fun) matplot(xvals, cells, ..., type = type, ...)
which is the shape BaseRLineLayerProcessor already reads for matplot –
one series per column, each point carrying its column name as z. So the
whole reading is recomputing cells and handing it over; nothing about
extracting a multi-series line is new here.
Recomputed rather than read back off the drawing, for the reason the correlograms recompute theirs (#276): a cell mean is not on the page in any form a grob carries, and the recorded arguments hold everything needed to get it exactly as the function did.
type is not consulted. It varies the marks – "l" draws lines, "p"
points, "b"/"o"/"c" both – but every variant draws the same cell
means in the same series, and reading a type = "p" chart as loose points
would lose the trace grouping that makes it an interaction plot.
Super classes
LayerProcessor -> BaseRLineLayerProcessor -> BaseRInteractionLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRLineLayerProcessor$axis_extent()BaseRLineLayerProcessor$extract_abline_data()BaseRLineLayerProcessor$extract_main_title()BaseRLineLayerProcessor$extract_multiline_data()BaseRLineLayerProcessor$extract_single_line_data()BaseRLineLayerProcessor$find_lines_grobs()BaseRLineLayerProcessor$generate_selectors()BaseRLineLayerProcessor$generate_selectors_from_grob()BaseRLineLayerProcessor$get_axis_labels()BaseRLineLayerProcessor$get_x_range_from_group()BaseRLineLayerProcessor$get_y_range_from_group()BaseRLineLayerProcessor$needs_reordering()BaseRLineLayerProcessor$process()BaseRLineLayerProcessor$selector_grob_type()
BaseRInteractionLayerProcessor$extract_data()
One series per trace level, read from the grid of cell means
Usage
BaseRInteractionLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of series
BaseRInteractionLayerProcessor$extract_axis_titles()
The three labels the drawing writes, each explicit argument first.
All three of interaction.plot's own defaults are
deparse1(substitute(...)) of an argument, so they name the
expression the caller wrote. The wrapper records evaluated values, by
which point substitute() is long gone – a factor's levels are not its
name – so the expressions come off the recorded call text instead, the
way the correlograms recover their series names (#276).
Usage
BaseRInteractionLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information for the recorded call
Returns
An axes list from build_axes()
BaseRInteractionLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRInteractionLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Lag Plot Processor
Description
Reads lag.plot() as the grid of scatters it draws: one panel per series
and lag, the series plotted against a shifted copy of itself.
A grid, not a layer. Like pairs(), this call lays out its own panels
and hands nothing to the device's layout calls, so the grid has to come
from the reading. It answers multi_panel = TRUE and places each layer at
its own cell.
What a panel pairs. Measured by tracing graphics::plot.xy through a
real call – the panel is plot(lag(X, k), X), and lag() shifts the time
base back, so the pair at time t is
x = X[t + k] the later reading, across y = X[t] the earlier one, up
over every t where both indices land inside the series. A negative lag
works out of the same expression and was measured too: set.lags = -1
gives x = X[1..n-1] against y = X[2..n], and set.lags = 0 gives the
series against itself.
The panels are numbered in draw order. The nested loop runs series
outermost and lag innermost, and par(mfrow) fills row by row – measured
against a grid.echo() export, a two-column matrix at lags = 2 writes
graphics-plot-1 through graphics-plot-4 for (a,1) (a,2) (b,1) (b,2).
So panel k sits at row (k - 1) %/% ncols + 1, column
(k - 1) %% ncols + 1.
A panel's marks are symbols or labels, and labels decides which.
lag.plot() writes the time index at each pair rather than a symbol when
labels is true, and labels defaults to do.lines, which defaults to
n <= 150 – so the default chart is the labelled one. Measured, the
four combinations give:
labels do.lines grobs in a panel FALSE FALSE points FALSE TRUE points, lines TRUE FALSE text TRUE TRUE text, brokenline
So do.lines only adds the joining line and labels alone decides the
mark, which is why the two are read separately rather than through the
default that ties them together.
Both marks can be outlined, and the export is what says so. Measured on a
real save_html() of a labelled call, the text grob comes out as one
group per pair, in data order:
<g id="graphics-plot-1-text-1.1"> <g id="graphics-plot-1-text-1.1.1" transform="translate(254.32, …)"> <g id="graphics-plot-1-text-1.1.2" transform="translate(221.70, …)">
which is the same shape a points grob has, with use elements replaced
by nested gs. So the selector differs only in the grob name and the
child it reaches for.
Super classes
LayerProcessor -> BaseRPointLayerProcessor -> BaseRLagLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRPointLayerProcessor$extract_axis_titles()BaseRPointLayerProcessor$extract_base_r_axis_grid_info()BaseRPointLayerProcessor$extract_data()BaseRPointLayerProcessor$extract_main_title()BaseRPointLayerProcessor$formula_variables()BaseRPointLayerProcessor$generate_selectors()BaseRPointLayerProcessor$needs_reordering()BaseRPointLayerProcessor$resolve_coordinates()
BaseRLagLayerProcessor$process()
Emit one point layer per drawn panel
Usage
BaseRLagLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface.
layoutUnused; present for the processor interface.
builtUnused; present for the processor interface.
gtUnused; the selectors are built rather than searched for.
grob_idUnused; present for the processor interface.
panel_idUnused; present for the processor interface.
panel_ctxUnused; present for the processor interface.
layer_infoLayer information with the recorded call.
Returns
A multi-panel result, or NULL when nothing was read
BaseRLagLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRLagLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Line Plot Layer Processor
Description
Processes Base R line plot layers based on recorded plot calls
Super class
LayerProcessor -> BaseRLineLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRLineLayerProcessor$process()
Process the layer: read its data, selectors, axis titles and main title from the recorded call
Usage
BaseRLineLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface
layoutUnused; present for the processor interface
builtUnused; present for the processor interface
gtGtable of the replayed drawing, searched for selectors (optional)
grob_idUnused; present for the processor interface
panel_idUnused; present for the processor interface
panel_ctxUnused; present for the processor interface
layer_infoLayer information with the recorded call
Returns
List describing the layer for the MAIDR payload
BaseRLineLayerProcessor$needs_reordering()
Whether the plot data must be reordered before drawing; a Base R layer is read from the recorded call and never is
Usage
BaseRLineLayerProcessor$needs_reordering()
Returns
FALSE
BaseRLineLayerProcessor$extract_data()
One series per line: a vector, each column of a matrix, a time series, or the
endpoints of abline()
Usage
BaseRLineLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of series
BaseRLineLayerProcessor$get_axis_labels()
Get custom axis labels from axis() LOW-level calls
Usage
BaseRLineLayerProcessor$get_axis_labels(layer_info, axis_side = 1)
Arguments
layer_infoLayer information containing group data
axis_sideWhich axis (1=bottom/x, 2=left/y, 3=top, 4=right)
Returns
Character vector of labels or NULL if not found
BaseRLineLayerProcessor$extract_single_line_data()
The points of one line, pairing each x with its y
Usage
BaseRLineLayerProcessor$extract_single_line_data(x, y, x_labels = NULL)
Arguments
xx positions
yy values
x_labelsCategory labels to announce in place of the x positions (optional)
Returns
List holding one series
BaseRLineLayerProcessor$extract_multiline_data()
One series per column of y_matrix, named after the columns
Usage
BaseRLineLayerProcessor$extract_multiline_data(x, y_matrix, x_labels = NULL)
Arguments
xx positions
y_matrixOne column of y values per series
x_labelsCategory labels to announce in place of the x positions (optional)
Returns
List of series
BaseRLineLayerProcessor$extract_axis_titles()
The axis titles, taken from the HIGH-level call for an overlay such as
abline()
Usage
BaseRLineLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Canonical axes list
BaseRLineLayerProcessor$extract_abline_data()
The endpoints of an abline() call across the axis the HIGH-level call set up
Usage
BaseRLineLayerProcessor$extract_abline_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List holding one two-point series, or empty
BaseRLineLayerProcessor$get_x_range_from_group()
The x extent of the group's HIGH-level call, as the axis was drawn
Usage
BaseRLineLayerProcessor$get_x_range_from_group(group)
Arguments
groupThe recorded plot group holding the HIGH-level call
Returns
Numeric vector of two, or NULL
BaseRLineLayerProcessor$get_y_range_from_group()
The y extent of the group's HIGH-level call, as the axis was drawn
Usage
BaseRLineLayerProcessor$get_y_range_from_group(group)
Arguments
groupThe recorded plot group holding the HIGH-level call
Returns
Numeric vector of two, or NULL
BaseRLineLayerProcessor$axis_extent()
The extent of an axis the way plot.default() sets it: an explicit
xlim/ylim, or the finite data extended by 4 % each way, which is
what abline() draws its clipped line across.
Usage
BaseRLineLayerProcessor$axis_extent(limits, data)
Arguments
limitsAn explicit
xlim/ylim, or NULLdataThe plotted values on that axis
Returns
Numeric vector of two, or NULL when nothing finite was plotted
BaseRLineLayerProcessor$extract_main_title()
The main title, taken from the HIGH-level call for abline()
Usage
BaseRLineLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Character string
BaseRLineLayerProcessor$generate_selectors()
One selector per polyline, in series order
Usage
BaseRLineLayerProcessor$generate_selectors(layer_info, gt = NULL)
Arguments
layer_infoLayer information with the recorded call
gtGtable of the replayed drawing (optional)
Returns
List of selectors
BaseRLineLayerProcessor$find_lines_grobs()
Find every grob of the given family drawn by the plot group at group_index
Usage
BaseRLineLayerProcessor$find_lines_grobs( grob, group_index, grob_type = "lines" )
Arguments
grobThe grob tree to search
group_indexIndex of the recorded plot group, which numbers the panel's grobs
grob_typeThe grob family to match: "lines", "abline", "segments", "spike" or "step"
Returns
Character vector of grob names
BaseRLineLayerProcessor$selector_grob_type()
Which family of grob names this layer's selectors are drawn from: "abline", "lines", "segments", "spike" or "step". Overridden by subclasses whose geometry lands under a different grob name (see BaseRStepLayerProcessor).
Usage
BaseRLineLayerProcessor$selector_grob_type(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
"abline" or "lines"
BaseRLineLayerProcessor$generate_selectors_from_grob()
One selector per matching polyline, sorted by the grob number
Usage
BaseRLineLayerProcessor$generate_selectors_from_grob( grob, group_index, layer_info )
Arguments
grobThe grob tree to search
group_indexIndex of the recorded plot group, which numbers the panel's grobs
layer_infoLayer information with the recorded call
Returns
List of selectors
BaseRLineLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRLineLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Mosaic Plot Layer Processor
Description
Processes Base R mosaicplot() layers – a two-way contingency table
drawn as tiles, where a column's width encodes that category's share
of all observations and a tile's height its conditional proportion within
the column.
Read as a mosaic layer, which exists for exactly this shape. Read as a
stacked_bar it would lose the width entirely, and the width is half the
table: the conditional proportions would arrive without the group sizes
they were computed from, so a category of six observations and one of six
hundred would read identically.
Nothing here is inferred from the drawing. mosaicplot() is handed the
table itself, so the recorded call carries every number the trace wants –
the counts, the margins they imply, and the level names from dimnames().
Super class
LayerProcessor -> BaseRMosaicLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRMosaicLayerProcessor$process()
Process the mosaic layer.
Usage
BaseRMosaicLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused for Base R (kept for interface compatibility)
layoutUnused for Base R (kept for interface compatibility)
builtUnused for Base R (kept for interface compatibility)
gtGtable object used for selector generation (optional)
grob_idUnused for Base R
panel_idUnused for Base R
panel_ctxUnused for Base R
layer_infoInformation about the recorded plot call
Returns
List with data, selectors, type, title and axes
BaseRMosaicLayerProcessor$needs_reordering()
Whether the plot data must be reordered before drawing; a Base R layer is read from the recorded call and never is
Usage
BaseRMosaicLayerProcessor$needs_reordering()
Returns
FALSE
BaseRMosaicLayerProcessor$extract_data()
Read the table out of the recorded mosaicplot() call.
The emitted shape is the segmented one the stacked bar processor
already produces – data[[fill]][[category]] – because the core
builds MosaicTrace on SegmentedTrace and navigates it
category-then-series exactly as a stack. mosaicplot() splits along
the first dimension into columns and each column along the second, so
the first dimension is the category and the second the fill.
Each cell carries four numbers rather than one:
-
y, the cell's conditional proportion within its column – the tile's height, and what a stack's value would be; -
width, the column's share of all observations – carried on every cell of the column, because the grammar's unit is the point and a flat list has nowhere else to put it; -
count, the cell's own count. A mosaic is drawn from counts and they are the numbers a reader would quote back; -
z, the fill level's name.
A column that observed nothing has no conditional proportions to
report – dividing would give NaN for every cell – so its cells
carry a proportion of 0 alongside their true count of 0. That is what
the chart draws: a column of zero width and no tiles.
Usage
BaseRMosaicLayerProcessor$extract_data(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
Nested list of points, empty when there is no table to read
BaseRMosaicLayerProcessor$recorded_table()
The two-way table the call was handed, when it is one.
Only a two-dimensional table is read. mosaicplot() accepts three and
more, splitting recursively, and a mosaic layer has one category
axis and one fill – so a deeper table has nowhere to put its later
dimensions and is declined rather than flattened into a
cross-classification the chart does not claim.
Usage
BaseRMosaicLayerProcessor$recorded_table(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
A 2-D table, or NULL
BaseRMosaicLayerProcessor$extract_axis_titles()
Name the axes from the table's own dimension names.
mosaicplot() labels its axes with names(dimnames(x)) unless the
author overrides them – "Hair" and "Eye" for HairEyeColor[, , 1] –
so those are the two words a reader should be given for the two
dimensions.
Which grammar axis each lands on is not the chart's own arrangement.
The second dimension is what mosaicplot() draws up the y axis, but a
segmented layer's y holds the magnitude and its z the fill, so
the second dimension is named on z and y says what its numbers
are. ylab follows the dimension it names rather than the axis it
shares a letter with, for the same reason.
Usage
BaseRMosaicLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
Canonical axes list
BaseRMosaicLayerProcessor$extract_main_title()
The title the call was given, if any.
mosaicplot() writes a default main of its own from the deparsed
data expression, but the recorded call carries only what the author
passed, and a title invented from a variable name is not something a
reader can act on.
Usage
BaseRMosaicLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
Character scalar, empty when the author wrote no title
BaseRMosaicLayerProcessor$generate_selectors()
Address the tiles the chart drew.
Measured on a rendered mosaicplot(HairEyeColor[, , 1]): gridGraphics
draws one -polygon-N grob per cell and nothing else as a polygon –
16 grobs for a 4x4 table, with no frame among them. Their geometry
says the order: polygon-1 to -4 share the leftmost column's x
extent, -5 to -8 the next one's, and within a column the grob
number runs down the fill levels in the table's own order. So the tile
for row f of column c is the (c - 1) * fills + fth grob.
The grobs are found rather than named by formula, and a short list is declined: a guessed id resolves to nothing at best and to another panel's tiles at worst, and a mosaic with no highlight still reads – the outcome #145 established for a layer with nothing to point at.
Usage
BaseRMosaicLayerProcessor$generate_selectors(layer_info, gt = NULL)
Arguments
layer_infoInformation about the recorded plot call
gtGtable object to search
Returns
List of selectors, one per cell, or empty when unresolvable
BaseRMosaicLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRMosaicLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Scatterplot Matrix Processor
Description
Reads pairs() as the grid of scatters it draws: one panel per ordered
pair of columns, the column across plotted against the column down.
A grid, not a layer. Every other base R processor answers with one
layer, or several layers in one cell. A scatterplot matrix is n x n
panels, which is the figure's shape rather than a layer's, so this one
answers with multi_panel = TRUE and places each layer at its own cell.
That is the shape the same chart already gets elsewhere: sns.pairplot in
py-maidr, and a plotly splom since xability/py-maidr#667.
The grid cannot come from the recording. Measured, pairs() sets its
own par(mfrow) internally and restores it, so nothing lands in the
device's layout calls – get_layout_calls() answers zero – and
detect_panel_configuration() sees a single panel (#272). The grid is the
reading's own, derived from the number of columns.
The panels are numbered column-major. Measured against a real
grid.echo() export of a three-column matrix, gridGraphics writes nine
graphics-plot-N groups – one per cell, diagonal included – and pairing
them with a panel that recorded what it was handed gives
k cell drawn 1 (1,1) text the variable's name 2 (2,1) points x = column 1, y = column 2 3 (3,1) points x = column 1, y = column 3 4 (1,2) points x = column 2, y = column 1 5 (2,2) text 6 (3,2) points x = column 2, y = column 3 7 (1,3) points x = column 3, y = column 1 8 (2,3) points x = column 3, y = column 2 9 (3,3) text
– that is k = (col - 1) * n + row, and the panel at (row, col) plots
column col horizontally against column row vertically.
The diagonal has no layer. A diagonal cell draws the variable's name
and nothing else, which the orchestrator already has an answer for: a cell
with no layers becomes a valid empty subplot. Giving it a histogram instead
would announce a chart pairs() does not draw – its default diag.panel
draws nothing at all.
Super classes
LayerProcessor -> BaseRPointLayerProcessor -> BaseRPairsLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRPointLayerProcessor$extract_axis_titles()BaseRPointLayerProcessor$extract_base_r_axis_grid_info()BaseRPointLayerProcessor$extract_data()BaseRPointLayerProcessor$extract_main_title()BaseRPointLayerProcessor$formula_variables()BaseRPointLayerProcessor$generate_selectors()BaseRPointLayerProcessor$needs_reordering()BaseRPointLayerProcessor$resolve_coordinates()
BaseRPairsLayerProcessor$process()
Emit one point layer per off-diagonal panel
Usage
BaseRPairsLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface.
layoutUnused; present for the processor interface.
builtUnused; present for the processor interface.
gtUnused; the selectors are built rather than searched for.
grob_idUnused; present for the processor interface.
panel_idUnused; present for the processor interface.
panel_ctxUnused; present for the processor interface.
layer_infoLayer information with the recorded call.
Returns
A multi-panel result, or NULL when nothing was read
BaseRPairsLayerProcessor$extract_columns()
The columns pairs() drew, with the names it wrote
Read from the recorded call rather than re-derived. A formula call is resolved from the frame the recording kept (#254) rather than from the formula, whose variables may since have been rebound; the ordinary spelling hands over a data frame or a matrix, which is recorded by value and needs nothing.
An unnamed matrix is labelled the way pairs.default labels it –
measured against a real export, the diagonals of a two-column unnamed
matrix read "var 1" and "var 2".
A column that is not numeric is not a case to handle: pairs() itself
stops with "non-numeric argument to 'pairs'" before anything is
recorded.
Usage
BaseRPairsLayerProcessor$extract_columns(layer_info)
Arguments
layer_infoLayer information with the recorded call.
Returns
A named list of numeric vectors, empty when nothing resolves
BaseRPairsLayerProcessor$column_names()
The names pairs() writes down its diagonal
Usage
BaseRPairsLayerProcessor$column_names(handed, count)
Arguments
handedThe recorded data frame or matrix.
countHow many columns it has.
Returns
One name per column
BaseRPairsLayerProcessor$panel_layer()
One panel's points, axes and selector
A pair with a missing coordinate is dropped rather than announced.
Measured, pairs() hands its panel the raw columns including NA,
and points() then draws nothing for that pair – so announcing it
would offer a sample the chart does not draw (#170).
Usage
BaseRPairsLayerProcessor$panel_layer(columns, row, col, title)
Arguments
columnsThe named columns.
rowWhich column runs up the panel.
colWhich column runs across it.
titleThe figure's own title.
Returns
A layer, or NULL when the panel drew no points
BaseRPairsLayerProcessor$panel_selectors()
The marks one panel was drawn into
Built rather than searched for, from the column-major numbering in the
class docs. find_graphics_plot_grob() answers with the first points
grob of the plot, and a scatterplot matrix draws one per cell, so a
search would give every panel the first cell's marks.
Numbered from one because a call that declares its own grid is the only
thing on the page: pairs() takes over the device's layout, and the
orchestrator reads a grid from a single call only.
Usage
BaseRPairsLayerProcessor$panel_selectors(row, col, count)
Arguments
rowWhich column runs up the panel.
colWhich column runs across it.
countHow many columns there are.
Returns
A one-element list of selectors
BaseRPairsLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRPairsLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Patch Architecture
Description
Modular system for patching Base R plotting functions with chain of responsibility pattern
Methods
Public methods
BaseRPatcher$can_patch()
Abstract: whether this patcher applies to the call
Usage
BaseRPatcher$can_patch(function_name, args)
Arguments
function_nameName of the plotting function
argsRecorded argument list
Returns
Logical
BaseRPatcher$apply_patch()
Abstract: the argument list with this patcher's change applied
Usage
BaseRPatcher$apply_patch(function_name, args)
Arguments
function_nameName of the plotting function
argsRecorded argument list
Returns
Argument list
BaseRPatcher$get_name()
Get the patcher name for debugging
Usage
BaseRPatcher$get_name()
BaseRPatcher$clone()
The objects of this class are cloneable with this method.
Usage
BaseRPatcher$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Pie Chart Layer Processor
Description
Processes Base R pie() layers based on recorded plot calls. A pie layer is
1-D and flat: one point per slice, carrying the slice label as x and the
slice magnitude as y. Percentages are derived by the frontend from those
magnitudes, so none are emitted here.
Super class
LayerProcessor -> BaseRPieLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRPieLayerProcessor$process()
Process the pie layer
Usage
BaseRPieLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused for Base R (NULL)
layoutLayout information
builtUnused for Base R (NULL)
gtGrob tree used for selector generation
grob_idUnused for Base R
panel_idUnused for Base R
panel_ctxUnused for Base R
layer_infoLayer information (contains the recorded plot call)
Returns
List with data, selectors, type, title and axes
BaseRPieLayerProcessor$extract_dial()
Where the ring begins and which way it runs
The frontend walks a pie clockwise – Right steps to the next slice the
way a clock hand goes, the audio pans each slice to where it sits and
p names its clock position – all from where the layer says the first
slice begins, measured in degrees clockwise from 12 o'clock. pie()
draws the other way round by default: clockwise = FALSE, from
init.angle degrees counterclockwise from 3 o'clock, so its
default of 0 is the frontend's 90 and a clockwise = TRUE pie's
default of 90 is the frontend's 0. The direction is declared so the
frontend can turn the walk round; the wedges stay in recorded-call
order, which is what the selectors are index-aligned to.
Both keys are left out at the frontend's own defaults – a clockwise ring from the top – which is also what every layer declared before the keys existed.
Usage
BaseRPieLayerProcessor$extract_dial(layer_info)
Arguments
layer_infoLayer information
Returns
Named list holding startAngle and/or direction, possibly
empty
BaseRPieLayerProcessor$needs_reordering()
Pie slices are emitted in drawing order (see extract_data)
Usage
BaseRPieLayerProcessor$needs_reordering()
Returns
FALSE
BaseRPieLayerProcessor$extract_data()
Extract one point per slice from the recorded call
Usage
BaseRPieLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information
Returns
Flat list of list(x = <label>, y = <value>) points
BaseRPieLayerProcessor$resolve_slice_labels()
Resolve the per-slice labels the way pie() does
labels defaults to names(x), and falls back to the slice position
when the input is unnamed. pie(labels = NA) draws neither label nor
leader line, but the wedges are still there and still navigable, so
those slices are announced by position rather than as "NA".
Usage
BaseRPieLayerProcessor$resolve_slice_labels(values, args)
Arguments
valuesThe recorded
xargument (names still attached)argsRecorded argument list from the pie() call
Returns
Character vector with one label per slice
BaseRPieLayerProcessor$generate_selectors()
Generate one selector per wedge, index-aligned to the data
Usage
BaseRPieLayerProcessor$generate_selectors( layer_info, gt = NULL, extracted_data = NULL )
Arguments
layer_infoLayer information
gtGrob tree to search
extracted_dataPoints from
extract_data(), used for the count
Returns
List of CSS selector strings, one per slice
BaseRPieLayerProcessor$extract_axis_titles()
Extract the axis titles for this layer
x names what the slice labels mean, y what their magnitudes measure.
pie() records neither unless the author wrote one, and a pie always
holds labelled categories against their magnitudes, so the defaults
say that much rather than leaving the axes nameless.
Usage
BaseRPieLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information
Returns
Canonical axes list
BaseRPieLayerProcessor$extract_main_title()
Extract the main title for this layer
Usage
BaseRPieLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information
Returns
Character scalar
BaseRPieLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRPieLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Plot Orchestrator Class
Description
This class orchestrates the detection and processing of multiple layers in Base R plots. It analyzes each recorded plot call individually and combines the results into a comprehensive interactive plot.
Methods
Public methods
BaseRPlotOrchestrator$new()
Create an orchestrator for the calls recorded on a device
Usage
BaseRPlotOrchestrator$new(device_id = grDevices::dev.cur())
Arguments
device_idGraphics device ID
BaseRPlotOrchestrator$detect_layers()
Turn each recorded plot group into layer entries: one for its HIGH-level call and one per LOW-level overlay
Usage
BaseRPlotOrchestrator$detect_layers()
BaseRPlotOrchestrator$analyze_single_layer()
Describe one recorded call as a layer entry with its detected type
Usage
BaseRPlotOrchestrator$analyze_single_layer( plot_call, layer_index, group = NULL )
Arguments
plot_callThe recorded call
layer_indexIndex of the layer
groupThe recorded plot group holding the HIGH-level call
Returns
Layer information list
BaseRPlotOrchestrator$create_layer_processors()
Create a processor for every layer of a known type
Usage
BaseRPlotOrchestrator$create_layer_processors()
BaseRPlotOrchestrator$create_layer_processor()
Create the processor for one layer
Usage
BaseRPlotOrchestrator$create_layer_processor(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
A layer processor, or NULL for an unknown type
BaseRPlotOrchestrator$create_unified_layer_processor()
Unified layer processor creation - used by all plot types
Usage
BaseRPlotOrchestrator$create_unified_layer_processor(layer_info)
Arguments
layer_infoLayer information
Returns
Layer processor instance
BaseRPlotOrchestrator$process_layers()
Run every layer processor and combine the results
Usage
BaseRPlotOrchestrator$process_layers()
BaseRPlotOrchestrator$extract_format_config_from_axis_calls()
Extract Format Configuration from axis() Calls
Scans logged axis() calls for format config stored by the axis wrapper. The wrapper stores .maidr_format_config when labels is a scales:: function.
Usage
BaseRPlotOrchestrator$extract_format_config_from_axis_calls()
Returns
A list with x and/or y format configurations, or NULL
BaseRPlotOrchestrator$extract_layout()
Read the figure-level title, subtitle and axis labels from the recorded HIGH-level calls
Usage
BaseRPlotOrchestrator$extract_layout()
Returns
List
BaseRPlotOrchestrator$combine_layer_results()
Combine the per-layer results into the subplot grid
Usage
BaseRPlotOrchestrator$combine_layer_results(layer_results)
Arguments
layer_resultsList of per-layer results, one per processor
BaseRPlotOrchestrator$generate_maidr_data()
Assemble the MAIDR data object for the figure
Usage
BaseRPlotOrchestrator$generate_maidr_data()
Returns
List with an id and the subplots
BaseRPlotOrchestrator$get_layout()
The figure-level layout read by extract_layout()
Usage
BaseRPlotOrchestrator$get_layout()
Returns
List
BaseRPlotOrchestrator$get_combined_data()
The combined per-layer data
Usage
BaseRPlotOrchestrator$get_combined_data()
Returns
List
BaseRPlotOrchestrator$get_layer_processors()
The processors created for the layers
Usage
BaseRPlotOrchestrator$get_layer_processors()
Returns
List
BaseRPlotOrchestrator$get_layers()
The detected layer entries
Usage
BaseRPlotOrchestrator$get_layers()
Returns
List
BaseRPlotOrchestrator$get_plot_calls()
The recorded plot calls
Usage
BaseRPlotOrchestrator$get_plot_calls()
Returns
List
BaseRPlotOrchestrator$get_gtable()
The gtable of the replayed drawing, built once and cached
Usage
BaseRPlotOrchestrator$get_gtable()
Returns
A gtable, or NULL when nothing was recorded
BaseRPlotOrchestrator$get_grob_for_layer()
The grob a layer's processor searches for its selectors
Usage
BaseRPlotOrchestrator$get_grob_for_layer(layer_index)
Arguments
layer_indexIndex of the layer
Returns
A grob, or NULL
BaseRPlotOrchestrator$unsupported_layer_flags()
Flag each detected layer maidr cannot process
Decorations carry no data of their own; leaving them out of the interactive output loses nothing. Data-bearing LOW-level overlays (polygon, rect, segments, ...) with no processor would silently disappear from the accessible output, so they count as unsupported.
Usage
BaseRPlotOrchestrator$unsupported_layer_flags()
Returns
Logical vector, one entry per detected layer
BaseRPlotOrchestrator$has_unsupported_layers()
Check if any HIGH-level layers are unsupported (unknown type)
Usage
BaseRPlotOrchestrator$has_unsupported_layers()
Returns
Logical indicating if there are unsupported layers
BaseRPlotOrchestrator$unsupported_group_indices()
Plot groups holding a layer maidr cannot process
Usage
BaseRPlotOrchestrator$unsupported_group_indices()
Returns
Integer vector of plot-group indices, in ascending order
BaseRPlotOrchestrator$resolve_fallback_scope()
Work out how far an unsupported layer reaches
An unsupported LOW-level overlay sits on top of a chart maidr does understand, so it only makes the panel that owns it undescribable. In a multi-panel figure the other panels are drawn from their own calls and stay fully accessible, so the fallback is scoped to the affected panels. It widens to the whole figure when there is nothing left to scope to: a single-panel figure, a figure whose every visible panel is affected, an unsupported call that belongs to no panel of the exported page, or an unsupported HIGH-level call.
Usage
BaseRPlotOrchestrator$resolve_fallback_scope()
Returns
Invisible NULL; the scope is cached on the orchestrator
BaseRPlotOrchestrator$is_group_scoped_out()
Check whether a plot group is scoped out of the payload
Usage
BaseRPlotOrchestrator$is_group_scoped_out(group_index)
Arguments
group_indexPlot-group index to test
Returns
TRUE when the group's panel falls back on its own
BaseRPlotOrchestrator$fallback_panels()
Panels rendered without accessible data
Usage
BaseRPlotOrchestrator$fallback_panels()
Returns
Integer vector of 1-based panel numbers, empty when the whole figure renders normally or falls back as a whole
BaseRPlotOrchestrator$should_fallback()
Determine if the plot should fall back to image rendering
Usage
BaseRPlotOrchestrator$should_fallback()
Returns
Logical indicating if fallback should be used
BaseRPlotOrchestrator$clone()
The objects of this class are cloneable with this method.
Usage
BaseRPlotOrchestrator$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Point/Scatter Plot Layer Processor
Description
Processes Base R scatter plot layers based on recorded plot calls
Super class
LayerProcessor -> BaseRPointLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRPointLayerProcessor$process()
Process the layer: read its data, selectors, axis titles and main title from the recorded call
Usage
BaseRPointLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface
layoutUnused; present for the processor interface
builtUnused; present for the processor interface
gtGtable of the replayed drawing, searched for selectors (optional)
grob_idUnused; present for the processor interface
panel_idUnused; present for the processor interface
panel_ctxUnused; present for the processor interface
layer_infoLayer information with the recorded call
Returns
List describing the layer for the MAIDR payload
BaseRPointLayerProcessor$needs_reordering()
Whether the plot data must be reordered before drawing; a Base R layer is read from the recorded call and never is
Usage
BaseRPointLayerProcessor$needs_reordering()
Returns
FALSE
BaseRPointLayerProcessor$extract_data()
One point per observation, from the recorded x and y or from the formula's model frame
Usage
BaseRPointLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of points
BaseRPointLayerProcessor$resolve_coordinates()
The x and y a recorded call plots, resolved as plot() resolves them.
plot(y ~ x, data = d) carries a formula rather than two vectors, and
its coordinates are the two columns of the model frame the recording
kept (#254). Read from resolve_xy_args() alone, the formula is a
language object and the layer came out with no points at all – an
interactive chart with nothing in it.
Usage
BaseRPointLayerProcessor$resolve_coordinates(plot_call)
Arguments
plot_callThe recorded call
Returns
A list with x and y, either of which may be NULL
BaseRPointLayerProcessor$formula_variables()
The two numeric variables of a recorded formula call, or NULL.
Only a numeric pair is a scatter: plot(y ~ f) on a factor draws a
box plot through plot.factor(), and a frame with more than one
predictor draws something else again. Both are left as they were.
Usage
BaseRPointLayerProcessor$formula_variables(plot_call)
Arguments
plot_callThe recorded call
Returns
A list with x, y, x_name, y_name, or NULL
BaseRPointLayerProcessor$extract_axis_titles()
Extract axis information from Base R plot call
Returns per-axis objects with an optional label and optional grid navigation fields (min, max, tickStep). Grid fields are derived from xlim/ylim args or data range, and tick intervals via pretty(). Every field is included only when extraction succeeds, and an axis that ends up with none of them is left out of the payload entirely.
Usage
BaseRPointLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information with recorded plot call
Returns
Canonical axes list
BaseRPointLayerProcessor$extract_base_r_axis_grid_info()
Extract grid navigation info for a Base R axis
Computes min, max from xlim/ylim or data range, and tickStep from pretty() tick positions. Returns NULL if extraction fails.
Usage
BaseRPointLayerProcessor$extract_base_r_axis_grid_info(data, lim = NULL)
Arguments
dataNumeric vector of data values
limOptional axis limits (xlim or ylim)
Returns
List with min, max, tickStep or NULL
BaseRPointLayerProcessor$extract_main_title()
The main title of the recorded call, or an empty string
Usage
BaseRPointLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Character string
BaseRPointLayerProcessor$generate_selectors()
The selector for the points, scoped to this layer's plot group
Usage
BaseRPointLayerProcessor$generate_selectors(layer_info, gt = NULL)
Arguments
layer_infoLayer information with the recorded call
gtGtable of the replayed drawing (optional)
Returns
List of selectors
BaseRPointLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRPointLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Processor Factory
Description
Factory for creating Base R-specific processors. This factory creates processors for Base R plot types based on recorded plot calls.
Format
An R6 class inheriting from ProcessorFactory
Super class
ProcessorFactory -> BaseRProcessorFactory
Methods
Public methods
Inherited methods
BaseRProcessorFactory$new()
Initialize the Base R processor factory
Usage
BaseRProcessorFactory$new()
BaseRProcessorFactory$create_processor()
Create a processor for a specific plot type
Usage
BaseRProcessorFactory$create_processor(plot_type, layer_info)
Arguments
plot_typeThe type of plot (e.g., "bar", "line", "point")
layer_infoInformation about the layer (contains plot call and metadata)
Returns
Processor instance for the specified plot type
BaseRProcessorFactory$get_supported_types()
Get list of supported plot types
Usage
BaseRProcessorFactory$get_supported_types()
Returns
Character vector of supported plot types
BaseRProcessorFactory$get_system_name()
Get the system name
Usage
BaseRProcessorFactory$get_system_name()
Returns
System name string
BaseRProcessorFactory$is_processor_available()
Check if a specific processor class is available
Usage
BaseRProcessorFactory$is_processor_available(processor_class_name)
Arguments
processor_class_nameName of the processor class
Returns
TRUE if available, FALSE otherwise
BaseRProcessorFactory$get_available_processors()
Get available processor classes
Enumerated from create_processor() rather than listed here, so the
answer cannot drift away from what the factory actually dispatches to
(#200).
Usage
BaseRProcessorFactory$get_available_processors()
Returns
Character vector of available processor class names
BaseRProcessorFactory$try_create_processor()
Create a processor with error handling
Usage
BaseRProcessorFactory$try_create_processor(plot_type, layer_info)
Arguments
plot_typeThe type of plot
layer_infoThe layer information
Returns
Processor instance or NULL if creation fails
BaseRProcessorFactory$clone()
The objects of this class are cloneable with this method.
Usage
BaseRProcessorFactory$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Q-Q Plot Layer Processor
Description
Reads qqnorm() and qqplot() as the scatter of quantile pairs they
draw.
A Q-Q plot is a scatter, and BaseRPointLayerProcessor already knows how
to emit one – the selector, the title and the grid all carry over
unchanged, and qqnorm() exports its marks under
graphics-plot-N-points-1, the same grob the point processor looks for.
What does not carry over is the data.
The base R processors read a call's recorded arguments, not the drawn
grob, and a Q-Q plot's arguments are not its coordinates. qqnorm(y) is
handed one sample and draws it against theoretical quantiles it computes;
qqplot(x, y) is handed two samples of possibly different lengths and
draws one interpolated pair per point of the shorter. Read as an ordinary
scatter, both would announce numbers the chart does not draw – for
qqnorm the raw sample on an axis of standard deviations, which is the
one reading a Q-Q plot most needs not to have, because the whole point of
the chart is the comparison between the two.
So the coordinates are not re-derived here. stats computes them and
both functions will hand them over without drawing: plot.it = FALSE
returns exactly the pairs the plotted call would have drawn. Forwarding
the recorded arguments rather than picking them apart is what makes the
awkward cases free. Measured on eight values against five:
qqnorm(x, plot.it = FALSE)$x theoretical quantiles, in the
caller's order, not sorted
qqnorm(x, datax = TRUE, ...) the same pair, swapped
qqplot(x, y, plot.it = FALSE) both length 5; x interpolated to the
shorter sample's quantiles
datax is the clearest of them: it swaps which axis holds the sample,
and forwarding it means nothing here has to know that.
The pairs come back in the order the call drew them, which is the order
the points grob lays its marks down in, so the selector list keeps
pairing positionally. Nothing is sorted.
Super classes
LayerProcessor -> BaseRPointLayerProcessor -> BaseRQqLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRPointLayerProcessor$extract_base_r_axis_grid_info()BaseRPointLayerProcessor$formula_variables()BaseRPointLayerProcessor$generate_selectors()BaseRPointLayerProcessor$needs_reordering()BaseRPointLayerProcessor$process()BaseRPointLayerProcessor$resolve_coordinates()
BaseRQqLayerProcessor$extract_data()
Extract the quantile pairs the call drew
Usage
BaseRQqLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of points, each a list of x and y
BaseRQqLayerProcessor$quantile_pairs()
Ask stats for the pairs the call drew
Returns NULL when the computation raises or does not come back as a usable pair of equal-length numeric vectors, which leaves the layer empty and the chart on the fallback rather than shipping half of it.
Usage
BaseRQqLayerProcessor$quantile_pairs(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List with x and y, or NULL
BaseRQqLayerProcessor$extract_axis_titles()
Axis labels and grid for a Q-Q plot
qqnorm() writes "Theoretical Quantiles" against "Sample Quantiles"
whenever the caller does not, and datax = TRUE swaps them along with
the axes – both are constants in the function's own signature, so
they are the labels the chart really carries rather than a guess.
qqplot() has no such defaults: its are deparse1(substitute(x)),
the caller's expression, which is gone by the time the wrapper has
recorded evaluated values. So a qqplot() the caller did not label is
left unlabelled for the renderer's generic, on the same reasoning the
point processor already states – a guessed noun is worse than none.
The grid is computed from the drawn pairs, not from the recorded
arguments: those are the samples, and on qqnorm one of the two axes
is not a sample at all.
Usage
BaseRQqLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Canonical axes list
BaseRQqLayerProcessor$default_axis_labels()
The labels the call writes when the caller does not
Usage
BaseRQqLayerProcessor$default_axis_labels(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List with x and y, either a string or NULL
BaseRQqLayerProcessor$extract_main_title()
The title the call writes when the caller does not
qqnorm()'s main defaults to "Normal Q-Q Plot" and it is drawn, so
announcing it is reporting the chart rather than inventing a name for
it. qqplot() has no default title and gets none.
Usage
BaseRQqLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
The title string
BaseRQqLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRQqLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Q-Q Reference Line Layer Processor
Description
Reads qqline() as the reference line it draws.
qqnorm() and qqplot() became readable in #251, and qqline() – how
nearly every Q-Q plot in the wild is finished – was listed in LOW with
no reading at all, purely so a chart carrying one would decline rather
than come out as a scatter with a drawn mark silently missing from it.
That was the lower of the two claims; this is the reading (#252).
Why it is recorded at all
stats::qqline() ends in abline(int, slope, ...), and that call is
reached from inside the stats namespace, where maidr's search-path
wrapper never sees it. Measured: before qqline was listed, qqnorm(x); qqline(x) recorded exactly one call and the reference line left no trace.
Where the endpoints come from
Not from the drawn grob and not re-derived. stats::qqline's body is four
lines, and the line it draws is the one through two points:
y <- quantile(y, probs, names = FALSE, type = qtype, na.rm = TRUE) x <- distribution(probs)
with probs defaulting to c(0.25, 0.75) and distribution to qnorm.
This class asks stats for the same two anchors, from the call's own
arguments, so a qqline() written with a non-default probs, qtype or
distribution is read from what it was given rather than from the
defaults. datax = TRUE swaps which of the two the slope is taken over,
and qqline() takes its own copy of that argument rather than inheriting
the plot's – so a qqline(datax = TRUE) over a qqnorm(datax = FALSE)
is expressible, and is read from the qqline call.
Why the x range is not the parent's
BaseRLineLayerProcessor$extract_abline_data() takes its x range from
get_x_range_from_group(), which reads the group's HIGH call's first
argument as the x data. On a qqnorm group that argument is the
sample, not the theoretical quantiles the chart puts on x – so
inheriting it would stretch the line across the wrong interval, which is
the class of mistake the Q-Q reading exists to avoid. The range comes from
the drawn pairs instead, which BaseRQqLayerProcessor already
computes from stats' own output.
Highlighting needs nothing new: qqnorm(x); qqline(x) and
plot(x, y); abline(0, 1) export the same grob,
graphics-plot-1-abline-ab-1, so the parent's abline selector reaches it
unchanged.
Super classes
LayerProcessor -> BaseRLineLayerProcessor -> BaseRQqlineLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRLineLayerProcessor$axis_extent()BaseRLineLayerProcessor$extract_abline_data()BaseRLineLayerProcessor$extract_axis_titles()BaseRLineLayerProcessor$extract_main_title()BaseRLineLayerProcessor$extract_multiline_data()BaseRLineLayerProcessor$extract_single_line_data()BaseRLineLayerProcessor$find_lines_grobs()BaseRLineLayerProcessor$generate_selectors()BaseRLineLayerProcessor$generate_selectors_from_grob()BaseRLineLayerProcessor$get_axis_labels()BaseRLineLayerProcessor$get_x_range_from_group()BaseRLineLayerProcessor$get_y_range_from_group()BaseRLineLayerProcessor$needs_reordering()BaseRLineLayerProcessor$process()
BaseRQqlineLayerProcessor$extract_data()
Extract the two endpoints the reference line is drawn between
Usage
BaseRQqlineLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of one series, each point a list of x and y
BaseRQqlineLayerProcessor$reference_line()
The intercept and slope stats::qqline computes
Reproduces the four lines of stats::qqline's own body against the
recorded arguments, defaults included. Returns NULL when the call did
not carry a sample this can read, or when the anchors come back
degenerate – two equal quantiles give a slope of Inf or NaN, and
a line through them is not a line the chart drew.
Usage
BaseRQqlineLayerProcessor$reference_line(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List with intercept and slope, or NULL
BaseRQqlineLayerProcessor$qq_x_range()
The x interval the chart drew, taken from the Q-Q pairs
The group's HIGH call is the qqnorm() or qqplot() this line sits
on, and its recorded first argument is a sample rather than either
drawn coordinate. So the range is read off the pairs stats computes,
which is what the chart put on the x axis.
Usage
BaseRQqlineLayerProcessor$qq_x_range(layer_info)
Arguments
layer_infoLayer information carrying the group
Returns
Numeric of length two, or NULL
BaseRQqlineLayerProcessor$selector_grob_type()
Which grob family this layer's selectors are drawn from
qqline() ends in abline(), so the mark it leaves is an abline's:
qqnorm(x); qqline(x) and plot(x, y); abline(0, 1) export the same
graphics-plot-1-abline-ab-1. The parent keys this off the recorded
function name, which here is qqline rather than abline, so without
the override the selector would look under lines and find nothing –
announcing the line correctly and highlighting nothing, which is the
shape of defect #145 was about.
Usage
BaseRQqlineLayerProcessor$selector_grob_type(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
The grob family name
BaseRQqlineLayerProcessor$named_or_first()
A named argument, or the first positional one
Usage
BaseRQqlineLayerProcessor$named_or_first(args, name)
Arguments
argsThe recorded arguments
nameThe formal's name
Returns
The value, or NULL
BaseRQqlineLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRQqlineLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Smooth/Density Layer Processor
Description
Processes Base R smooth curves including:
Density plots: plot(density()) or lines(density())
Loess smooth: lines(loess.smooth()) or lines(predict(loess))
Smooth splines: lines(smooth.spline())
Super class
LayerProcessor -> BaseRSmoothLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRSmoothLayerProcessor$process()
Process the layer: read its data, selectors, axis titles and main title from the recorded call
Usage
BaseRSmoothLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface
layoutUnused; present for the processor interface
builtUnused; present for the processor interface
gtGtable of the replayed drawing, searched for selectors (optional)
grob_idUnused; present for the processor interface
panel_idUnused; present for the processor interface
panel_ctxUnused; present for the processor interface
layer_infoLayer information with the recorded call
Returns
List describing the layer for the MAIDR payload
BaseRSmoothLayerProcessor$extract_data()
One point per fitted value of the smooth, density or curve
Usage
BaseRSmoothLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of points
BaseRSmoothLayerProcessor$generate_selectors()
The selector for the curve's polyline
Usage
BaseRSmoothLayerProcessor$generate_selectors(layer_info, gt = NULL)
Arguments
layer_infoLayer information with the recorded call
gtGtable of the replayed drawing (optional)
Returns
List of selectors
BaseRSmoothLayerProcessor$find_polyline_grobs()
Find the lines container grob for this layer
Usage
BaseRSmoothLayerProcessor$find_polyline_grobs(grob, call_index = NULL)
Arguments
grobThe grob tree to search
call_indexIndex of the recorded plot group, which numbers the panel's grobs
Returns
Grob name, or NULL
BaseRSmoothLayerProcessor$generate_selectors_from_grob()
Build this layer's selector from the grob tree
Usage
BaseRSmoothLayerProcessor$generate_selectors_from_grob(grob, call_index = NULL)
Arguments
grobThe grob tree to search
call_indexIndex of the recorded plot group, which numbers the panel's grobs
Returns
A selector string, or an empty string when no grob matches
BaseRSmoothLayerProcessor$extract_axis_titles()
Extract the axis titles for this layer
The x axis holds whatever variable was smoothed, which the recorded
arguments no longer name, so it carries no default. The y axis does
when the curve came from density(): that estimate is a density, and
plot.density() prints exactly that word.
Usage
BaseRSmoothLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information
Returns
Canonical axes list
BaseRSmoothLayerProcessor$extract_main_title()
The main title of the recorded call, or an empty string
Usage
BaseRSmoothLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Character string
BaseRSmoothLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRSmoothLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Spectral Density Processor
Description
Reads spectrum() as the line it draws: the estimated spectral density
against frequency.
The values are the raw spec, not its logarithm. plot.spec draws on
a log y axis by default, but it puts the log on the axis and hands
plot.xy the untransformed values – traced, the first call's y equals
spectrum(v, plot = FALSE)$spec exactly. So the numbers a reader hears are
the numbers the chart is scaled from, and taking a logarithm here would
announce a series the caller never computed.
The caller's arguments are forwarded. spans, taper, detrend and
the rest change the estimate, so recomputing with defaults would announce a
different curve from the one drawn. The recorded call's arguments are
passed through with plot = FALSE added.
Super classes
LayerProcessor -> BaseRLineLayerProcessor -> BaseRSpectrumLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRLineLayerProcessor$axis_extent()BaseRLineLayerProcessor$extract_abline_data()BaseRLineLayerProcessor$extract_axis_titles()BaseRLineLayerProcessor$extract_data()BaseRLineLayerProcessor$extract_main_title()BaseRLineLayerProcessor$extract_multiline_data()BaseRLineLayerProcessor$extract_single_line_data()BaseRLineLayerProcessor$find_lines_grobs()BaseRLineLayerProcessor$generate_selectors()BaseRLineLayerProcessor$generate_selectors_from_grob()BaseRLineLayerProcessor$get_axis_labels()BaseRLineLayerProcessor$get_x_range_from_group()BaseRLineLayerProcessor$get_y_range_from_group()BaseRLineLayerProcessor$needs_reordering()BaseRLineLayerProcessor$selector_grob_type()
BaseRSpectrumLayerProcessor$process()
Emit the spectral density as a line
Usage
BaseRSpectrumLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface.
layoutUnused; present for the processor interface.
builtUnused; present for the processor interface.
gtUnused; the selector is built rather than searched for.
grob_idUnused; present for the processor interface.
panel_idUnused; present for the processor interface.
panel_ctxUnused; present for the processor interface.
layer_infoLayer information with the recorded call.
Returns
A line layer, or NULL when nothing was read
BaseRSpectrumLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRSpectrumLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Spike Plot Layer Processor
Description
Processes Base R spike layers – plot(x, y, type = "h") and the
lines() equivalent. type = "h" draws a vertical line from the baseline
to each value and joins nothing to anything: the samples stand side by
side rather than in a series.
Read as a lollipop layer, which the core builds on BarTrace: one value
per position, with no claim about the space between two of them. The
marker head a lollipop conventionally carries is the only difference from
what base R draws here, and it is not something a reader hears.
Announced as a line before this existed, which is the reading a spike
chart most needs not to have – a line says the samples are joined and
that the space between them can be interpolated, and that is the one
relationship the chart is drawn to deny (#239).
Data extraction, axis titles and the main title are a line layer's, so
this inherits BaseRLineLayerProcessor; what it adds is the layer type,
the flat point list a bar-shaped trace wants, and the grob family the
spikes are actually named after.
Super classes
LayerProcessor -> BaseRLineLayerProcessor -> BaseRSpikeLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRLineLayerProcessor$axis_extent()BaseRLineLayerProcessor$extract_abline_data()BaseRLineLayerProcessor$extract_axis_titles()BaseRLineLayerProcessor$extract_main_title()BaseRLineLayerProcessor$extract_multiline_data()BaseRLineLayerProcessor$extract_single_line_data()BaseRLineLayerProcessor$find_lines_grobs()BaseRLineLayerProcessor$generate_selectors()BaseRLineLayerProcessor$generate_selectors_from_grob()BaseRLineLayerProcessor$get_axis_labels()BaseRLineLayerProcessor$get_x_range_from_group()BaseRLineLayerProcessor$get_y_range_from_group()BaseRLineLayerProcessor$needs_reordering()
BaseRSpikeLayerProcessor$process()
Process the spike layer.
Usage
BaseRSpikeLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused for Base R (kept for interface compatibility)
layoutUnused for Base R (kept for interface compatibility)
builtUnused for Base R (kept for interface compatibility)
gtGtable object used for selector generation (optional)
grob_idUnused for Base R
panel_idUnused for Base R
panel_ctxUnused for Base R
layer_infoInformation about the recorded plot call
Returns
List with data, selectors, type, title and axes
BaseRSpikeLayerProcessor$extract_data()
Read the spikes as one flat list of points.
A line layer's data is a list of series, because several lines can
share one layer. A lollipop is read as a bar is, and a bar layer's
data is one point per position – so the single series the inherited
extraction produces is unwrapped here rather than shipped one level
too deep, where the frontend would read the whole chart as a single
point.
Only the first series is taken. plot(type = "h") and
lines(type = "h") each draw exactly one, and matplot – the call
that draws several – has its own dispatch that never reaches here.
Usage
BaseRSpikeLayerProcessor$extract_data(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
List of x/y points, empty when there is nothing to read
BaseRSpikeLayerProcessor$selector_grob_type()
Draw a spike layer's selectors from the spike grobs.
gridGraphics names a grob after what drew it, so spikes land under
graphics-plot-N-spike-M – never under the -lines- name the
inherited search looks for. Measured on plot(1:6, y, type = "h"),
one polyline per spike sits under that grob, in data order:
<polyline id="graphics-plot-1-spike-1.1.1" points="74.4,... "/> <polyline id="graphics-plot-1-spike-1.1.2" points="151.2,..."/> ...
so the one selector this yields resolves to one element per point, which is what a bar-shaped trace pairs with its data.
Usage
BaseRSpikeLayerProcessor$selector_grob_type(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
"spike"
BaseRSpikeLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRSpikeLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Spine Plot Layer Processor
Description
Reads spineplot() as the two-way contingency table it draws.
A spine plot is a mosaic of one categorical axis against another: one
column per level of x, its width that level's share of all
observations, split vertically by y's conditional proportions inside it.
That is the shape BaseRMosaicLayerProcessor was written for in #247 –
"the column widths encode data too" – so a spine plot is read as a
mosaic layer, and this class changes only the two things that differ.
Where the table comes from. mosaicplot() is handed its table, so the
recorded call carries it. spineplot() is handed the two variables and
builds the table itself, and it has no plot argument to be asked for
the table without drawing – cdplot() has one, spineplot() does not.
But it returns what it drew:
spineplot(table(f, g)) # g # f no yes # low 11 12 # mid 7 14 # high 12 4
so the call is replayed on a throwaway device and the return value taken.
graphics::spineplot by the qualified name, not the bare one: maidr
patches the name on the search path, and the bare call would record the
replay as a second chart. Reproducing the binning by hand instead would be
a re-derivation – spineplot cuts a numeric x by its own rule – and
the point of every reading in this package is that the library is asked
rather than imitated.
Where the tiles are. mosaicplot() writes one polygon grob per
cell. spineplot() writes one rect grob for the whole panel, and
gridSVG exports it as one <rect> element per tile. Measured on a 3x2
table:
graphics-plot-1-rect-1.1.1 x 59.04 w 152.86 h 118.71 graphics-plot-1-rect-1.1.2 x 59.04 w 152.86 h 108.81 graphics-plot-1-rect-1.1.3 x 219.88 w 139.57 h 151.68 graphics-plot-1-rect-1.1.4 x 219.88 w 139.57 h 75.84 graphics-plot-1-rect-1.1.5 x 367.42 w 106.34 h 56.88 graphics-plot-1-rect-1.1.6 x 367.42 w 106.34 h 170.64
Six elements for six cells, sharing an x within a column, and the widths
152.86 : 139.57 : 106.34 in the marginals' own ratio 23 : 21 : 16. The
order is column-major, and within a column the last fill level is drawn
first: the heights pair 118.71 : 108.81 with 12 : 11, which is yes
above no. That is the opposite of the mosaic's ascending order, which is
why the index is computed here rather than inherited.
A zero cell still draws. The hazard this shape invites is the one
xability/maidr#1002 found elsewhere: a count of zero skipped rather than
drawn, shifting every later tile's index by one. Measured on a table with
a genuine zero in it, spineplot draws the tile anyway with height="0",
so the positional pairing holds. There is a test for exactly that.
Super classes
LayerProcessor -> BaseRMosaicLayerProcessor -> BaseRSpineplotLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRMosaicLayerProcessor$extract_axis_titles()BaseRMosaicLayerProcessor$extract_data()BaseRMosaicLayerProcessor$extract_main_title()BaseRMosaicLayerProcessor$needs_reordering()BaseRMosaicLayerProcessor$process()
BaseRSpineplotLayerProcessor$recorded_table()
The table spineplot() drew, by replaying the call
Memoised, because process() asks for it three times – once for
the data, once for the axis names and once for the selectors – and
each ask would otherwise open a device and draw the chart again.
Usage
BaseRSpineplotLayerProcessor$recorded_table(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
A 2-D table, or NULL when the call cannot be replayed
BaseRSpineplotLayerProcessor$generate_selectors()
Address the tile each cell was drawn into
One rect grob holds the whole panel, so the tiles are its
sub-elements rather than grobs of their own and are addressed by
their exported ids. The grob is found rather than named by
formula, and a panel that does not hold exactly one is declined: a
guessed id resolves to nothing at best and to another panel's tiles
at worst, and a spine plot with no highlight still reads (#145).
The index runs column-major with the fill levels descending inside a column, which is the order measured off the drawing and recorded in the class note. The emitted list is in the payload's own order – all categories of the first fill, then the second – so the two line up.
Usage
BaseRSpineplotLayerProcessor$generate_selectors(layer_info, gt = NULL)
Arguments
layer_infoInformation about the recorded plot call
gtGtable object to search
Returns
List of selectors, one per cell, or empty when unresolvable
BaseRSpineplotLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRSpineplotLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Stacked Bar Layer Processor
Description
Processes Base R stacked bar plot layers intercepted via the patching
system. Assumes sorting by x (columns) and then z (rows) has already been
applied by the SortingPatcher.
Super class
LayerProcessor -> BaseRStackedBarLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRStackedBarLayerProcessor$process()
Process the layer: read its data, selectors, axis titles and main title from the recorded call
Usage
BaseRStackedBarLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface
layoutUnused; present for the processor interface
builtUnused; present for the processor interface
gtGtable of the replayed drawing, searched for selectors (optional)
grob_idUnused; present for the processor interface
panel_idUnused; present for the processor interface
panel_ctxUnused; present for the processor interface
layer_infoLayer information with the recorded call
Returns
List describing the layer for the MAIDR payload
BaseRStackedBarLayerProcessor$needs_reordering()
Whether the plot data must be reordered before drawing; a Base R layer is read from the recorded call and never is
Usage
BaseRStackedBarLayerProcessor$needs_reordering()
Returns
FALSE
BaseRStackedBarLayerProcessor$extract_data()
One series per row of the recorded height matrix
Usage
BaseRStackedBarLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
List of series
BaseRStackedBarLayerProcessor$extract_axis_titles()
Extract the axis titles for this layer
A stacked barplot() records no title unless the author wrote one, and
its points always carry the column category on x and the segment height
on y, so the defaults name those two. The stack's own dimension is
already announced per point as z; nothing in the call names the
variable those groups came from, so no z title is claimed.
Usage
BaseRStackedBarLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information
Returns
Canonical axes list
BaseRStackedBarLayerProcessor$extract_main_title()
The main title of the recorded call, or an empty string
Usage
BaseRStackedBarLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Character string
BaseRStackedBarLayerProcessor$generate_selectors()
The selector for the segments, scoped to this layer's plot group
Usage
BaseRStackedBarLayerProcessor$generate_selectors( layer_info, gt = NULL, extracted_data = NULL )
Arguments
layer_infoLayer information with the recorded call
gtGtable of the replayed drawing (optional)
extracted_dataThe data already extracted for this layer (optional)
Returns
List of selectors
BaseRStackedBarLayerProcessor$find_rect_groups()
Find every rect group drawn by the plot group at call_index
Usage
BaseRStackedBarLayerProcessor$find_rect_groups(grob, call_index)
Arguments
grobThe grob tree to search
call_indexIndex of the recorded plot group, which numbers the panel's grobs
Returns
Character vector of grob names
BaseRStackedBarLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRStackedBarLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Star Plot Processor
Description
Reads stars() as the radar it draws: one closed outline per observation,
with a spoke for each variable.
It is a multi-line layer. MAIDR's radar trace is navigated as one –
"each spoke a column and each series a row" – so the whole reading is
handing over the matrix with its axes the other way round from the way
stars() takes it. stars(m) draws a glyph per row, so the rows are
the series and the columns are the spokes, and
BaseRLineLayerProcessor's extract_multiline_data() wants series in
columns. Hence the transpose, which is the only rearranging here.
The values are the caller's, not the drawing's. stars() scales every
column to [0, 1] before drawing, so the radii on the page are shares of
each column's range rather than the readings themselves. Announcing those
would tell a reader that observation 1 scores 0 on a variable it merely
has the smallest value of. The recorded matrix carries what the caller
measured, and that is what a reader is told.
It is read without an outline, deliberately. The marks are there and
the pairing is known – measured by giving each observation its own
col.stars and reading every polygon's fill, observation k owns
polygons 2k - 1 and 2k, both filled its colour, plus a segments-k
carrying one segment per variable:
polygon-1 #111199 polygon-2 #111199 segments-1 observation 1 polygon-3 #229922 polygon-4 #229922 segments-2 observation 2 ...
What is not established is the selector those grobs export to. A
selector is only worth emitting once it has been resolved against a real
export, and a real export cannot be had until the chart stops falling back
to a picture – which is what this reading is for. So the outline is left
for a follow-up that can measure it, rather than guessed from the grob
names. Reading without one is what gauge already does upstream when the
marks and the cursor cannot be paired with confidence.
Super classes
LayerProcessor -> BaseRLineLayerProcessor -> BaseRStarsLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRLineLayerProcessor$axis_extent()BaseRLineLayerProcessor$extract_abline_data()BaseRLineLayerProcessor$extract_axis_titles()BaseRLineLayerProcessor$extract_data()BaseRLineLayerProcessor$extract_main_title()BaseRLineLayerProcessor$extract_multiline_data()BaseRLineLayerProcessor$extract_single_line_data()BaseRLineLayerProcessor$find_lines_grobs()BaseRLineLayerProcessor$generate_selectors()BaseRLineLayerProcessor$generate_selectors_from_grob()BaseRLineLayerProcessor$get_axis_labels()BaseRLineLayerProcessor$get_x_range_from_group()BaseRLineLayerProcessor$get_y_range_from_group()BaseRLineLayerProcessor$needs_reordering()BaseRLineLayerProcessor$selector_grob_type()
BaseRStarsLayerProcessor$process()
Emit one radar series per observation
Usage
BaseRStarsLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface.
layoutUnused; present for the processor interface.
builtUnused; present for the processor interface.
gtUnused; this reading emits no selectors.
grob_idUnused; present for the processor interface.
panel_idUnused; present for the processor interface.
panel_ctxUnused; present for the processor interface.
layer_infoLayer information with the recorded call.
Returns
A radar layer, or NULL when nothing was read
BaseRStarsLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRStarsLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Step Plot Layer Processor
Description
Processes Base R stairstep layers – plot(x, y, type = "s"),
plot(x, y, type = "S") and the lines() equivalents. A step chart is
piecewise constant: the value is held across an interval and then jumps,
rather than being interpolated between samples the way a line implies.
Data extraction, axis titles, the main title and polyline selector
generation are identical to a line layer, so this class inherits
BaseRLineLayerProcessor and adds only the step-specific reporting: the
layer type and the stepDirection convention the call requested.
One data point is emitted per data sample, never one per stairstep vertex – the MAIDR frontend maps the rendered polyline's corner vertices back onto the samples itself.
Super classes
LayerProcessor -> BaseRLineLayerProcessor -> BaseRStepLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRLineLayerProcessor$axis_extent()BaseRLineLayerProcessor$extract_abline_data()BaseRLineLayerProcessor$extract_axis_titles()BaseRLineLayerProcessor$extract_data()BaseRLineLayerProcessor$extract_main_title()BaseRLineLayerProcessor$extract_multiline_data()BaseRLineLayerProcessor$extract_single_line_data()BaseRLineLayerProcessor$find_lines_grobs()BaseRLineLayerProcessor$generate_selectors()BaseRLineLayerProcessor$generate_selectors_from_grob()BaseRLineLayerProcessor$get_axis_labels()BaseRLineLayerProcessor$get_x_range_from_group()BaseRLineLayerProcessor$get_y_range_from_group()BaseRLineLayerProcessor$needs_reordering()
BaseRStepLayerProcessor$process()
Process the step layer.
Usage
BaseRStepLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused for Base R (kept for interface compatibility)
layoutUnused for Base R (kept for interface compatibility)
builtUnused for Base R (kept for interface compatibility)
gtGtable object used for selector generation (optional)
grob_idUnused for Base R
panel_idUnused for Base R
panel_ctxUnused for Base R
layer_infoInformation about the recorded plot call
Returns
List with data, selectors, type, title, axes and stepDirection
BaseRStepLayerProcessor$extract_step_direction()
Read the step convention the recorded call requested.
type = "s" draws the horizontal segment first (MAIDR's "hv") and
type = "S" draws the vertical segment first ("vh"). The two are not
interchangeable, so an unrecognised or absent type yields NULL and
the caller omits stepDirection rather than guessing.
Usage
BaseRStepLayerProcessor$extract_step_direction(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
"hv", "vh", or NULL
BaseRStepLayerProcessor$selector_grob_type()
Draw a step layer's selectors from the stairstep grobs.
gridGraphics names a grob after the type letter that drew it, so a
stairstep lands under graphics-plot-N-step-M (type = "s") or
graphics-plot-N-Step-M (type = "S") – never under the -lines-
name the inherited line search looks for. Without this override a Base
R step layer emits zero selectors, and the frontend's
selectors.length === series count precondition then drops the
layer's highlighting entirely.
Usage
BaseRStepLayerProcessor$selector_grob_type(layer_info)
Arguments
layer_infoInformation about the recorded plot call
Returns
"step"
BaseRStepLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRStepLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Strip Chart Layer Processor
Description
Reads stripchart() as the one-dimensional scatter it draws: every
observation as its own mark, laid along a value axis at its group's
position.
One layer per group. That is the shape of the reading and it is forced by the drawing rather than chosen for tidiness: measured on two groups, gridGraphics exports
graphics-plot-1-points-1 graphics-plot-1-points-2
– one points grob per group – and find_graphics_plot_grob() answers
with the first match, so a single layer would announce every observation
and highlight only the first group's. It is also the reading the same chart
already gets in py-maidr, whose stripplot and swarmplot split into one
named layer per category.
The groups are not re-derived. stripchart forms them in two places
and both are read rather than reimplemented:
stripchart.default groups <- if (is.list(x)) x
else if (is.numeric(x)) list(x)
stripchart.formula split(mf[[response]], mf[-response])
after stats::model.frame
so a list keeps its own names, a bare vector is one unnamed group, and a
formula is split by split() itself.
A formula with no data = is read too, which is worth stating because
the opposite is the obvious guess. A formula carries the environment it was
written in, and the recorded call holds the formula, so that environment is
still reachable when the chart is read; model.frame() resolves the
variables from it exactly as stripchart.formula did when it drew them.
Measured on stripchart(len ~ supp) with the variables local to a
function, global, and in a closure whose call had returned – all three
read back the drawn groups and values. This is also what
BaseRBoxplotLayerProcessor already does with its data = args[["data"]].
What that inherits is the hazard of a late lookup: rebinding len between
the drawing and the rendering makes the payload announce the new values.
Measured, and filed as #254 – it belongs to every recorded formula in this
package rather than to this processor, and refusing the ordinary spelling
to dodge it would trade a chart that reads exactly for a picture.
The position stays a number. ScatterPoint.x is typed number in the
grammar and ScatterTrace does arithmetic on it, so the group's name
travels beside its position in yLabel – or xLabel on a vertical chart
– exactly as the ggplot2 point processor does since #178.
method = "jitter" is not a reading problem here, and that is worth
saying because it is one for geom_jitter() (#174). A stripchart jitters
along the group axis only; the value axis is untouched, so every number
announced is the observation itself. What is displaced is the position
whose name is already carried as a label.
Super classes
LayerProcessor -> BaseRPointLayerProcessor -> BaseRStripchartLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRPointLayerProcessor$extract_base_r_axis_grid_info()BaseRPointLayerProcessor$extract_data()BaseRPointLayerProcessor$extract_main_title()BaseRPointLayerProcessor$formula_variables()BaseRPointLayerProcessor$generate_selectors()BaseRPointLayerProcessor$needs_reordering()BaseRPointLayerProcessor$resolve_coordinates()
BaseRStripchartLayerProcessor$process()
Emit one point layer per drawn group
Usage
BaseRStripchartLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface.
layoutUnused; present for the processor interface.
builtUnused; present for the processor interface.
gtThe grob tree, for the selectors.
grob_idUnused; present for the processor interface.
panel_idUnused; present for the processor interface.
panel_ctxUnused; present for the processor interface.
layer_infoLayer information with the recorded call.
Returns
A multi-layer result, or NULL when nothing was read
BaseRStripchartLayerProcessor$extract_groups()
The groups stripchart() itself would form
Read from the recorded call rather than re-derived, per the two spellings in the class docs. Returns an empty list for anything this cannot resolve exactly, which leaves the chart on the static fallback.
Usage
BaseRStripchartLayerProcessor$extract_groups(layer_info)
Arguments
layer_infoLayer information with the recorded call.
Returns
A named list of numeric vectors, one per group
BaseRStripchartLayerProcessor$draws_horizontally()
Which visual axis the observations run along
stripchart() draws horizontally unless told otherwise, which is the
opposite of boxplot()'s default and worth reading from the call
rather than assuming.
Usage
BaseRStripchartLayerProcessor$draws_horizontally(layer_info)
Arguments
layer_infoLayer information with the recorded call.
Returns
TRUE when the values run left to right
BaseRStripchartLayerProcessor$extract_axis_titles()
Name the value axis and the group axis
Overrides the inherited scatter helper, which reads the recorded x
as a pair of coordinates and so gets a stripchart wrong in both
directions at once. Measured on
stripchart(c(3.1, 4.2, 5.0, 2.2, 6.9)), that helper hands the bare
vector to xy.coords(), which reads it as y and indexes x over 1:5:
announced x 1 .. 5 y 2 .. 7 drawn x 2.2 .. 6.9 y one group, at 1
– the value range offered on the group axis, and a bare index on the
value axis. A stripchart is one categorical axis against one measured
axis, the same shape boxplot() and barplot() draw, so it is named
the same way and by the same helper; vertical = TRUE swaps which
visual axis holds which, exactly as horizontal = TRUE does there.
No range is emitted for either axis. The group axis has none to give – its positions are names – and the value axis is left to the renderer's own generic, which is where every other grouped base R chart leaves it.
Usage
BaseRStripchartLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information with the recorded call.
Returns
Canonical axes list
BaseRStripchartLayerProcessor$split_by_formula()
Split a formula's response by its grouping columns
stripchart.formula does exactly this, through stats::model.frame
and split, so both are called rather than imitated. data is passed
through exactly as recorded – a data frame, a plain list, or NULL –
because model.frame() accepts all three, and NULL is its own default
for "resolve from the formula's environment", which is what the
drawing did. Coercing it first bought nothing: measured,
as.data.frame(NULL) and NULL produce the same split. This is the
spelling BaseRBoxplotLayerProcessor already uses.
A one-sided formula needs no guard of its own. stripchart(~ len)
does not draw at all – stripchart.formula stops with "formula
missing or incorrect" – so it cannot be recorded, and reached
directly it gives response == 0, whose frame[[0]] the tryCatch
below already turns into the decline.
Usage
BaseRStripchartLayerProcessor$split_by_formula(formula, data, frame = NULL)
Arguments
formulaThe recorded formula.
dataThe recorded
dataargument, or NULL.frameThe model frame kept when the call was recorded, or NULL for a call recorded before that existed.
Returns
A named list of numeric vectors, or NULL
BaseRStripchartLayerProcessor$group_names()
The names stripchart() writes down the group axis
group.names first, then the list's own names, then the positions –
the order stripchart.default resolves them in. A group.names of
the wrong length is ignored here because it is ignored there.
Usage
BaseRStripchartLayerProcessor$group_names(args, groups)
Arguments
argsThe recorded argument list.
groupsThe groups already formed.
Returns
One name per group
BaseRStripchartLayerProcessor$group_positions()
Where along the group axis each group was drawn
at when the caller gave one of the right length, and 1:n
otherwise, which is what stripchart.default falls back to.
Usage
BaseRStripchartLayerProcessor$group_positions(layer_info, count)
Arguments
layer_infoLayer information with the recorded call.
countHow many groups there are.
Returns
One numeric position per group
BaseRStripchartLayerProcessor$group_points()
One group's observations, as points
The value goes on the value axis and the position on the group axis,
and the group's name travels beside the position as a label rather
than in place of it – ScatterPoint.x is typed number and
ScatterTrace does arithmetic on it (#178).
Usage
BaseRStripchartLayerProcessor$group_points(values, label, position, horizontal)
Arguments
valuesThe group's observations.
labelThe group's name.
positionWhere the group sits on its axis.
horizontalTRUE when the values run left to right.
Returns
A list of points
BaseRStripchartLayerProcessor$group_selectors()
The marks one group was drawn into
Built rather than searched for. find_graphics_plot_grob() answers
with the first points grob of the plot, and a stripchart draws one
per group, so a search would give every layer the first group's marks.
The names are graphics-plot-{plot}-points-{group}, measured against a
real gridSVG export, and every emitted selector was then resolved in
Chromium against a rendering of a three-group chart: 5, 4 and 2
elements, one per observation.
Usage
BaseRStripchartLayerProcessor$group_selectors(layer_info, index)
Arguments
layer_infoLayer information with the recorded call.
indexWhich group this is, from 1.
Returns
A one-element list of selectors
BaseRStripchartLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRStripchartLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Seasonal Subseries Layer Processor
Description
Reads monthplot() as the set of lines it draws: one series per cycle
position – month, quarter, whatever the frequency makes it – running over
that position's own subseries.
stats::monthplot.default draws exactly that, one lines() call per
position:
for (i in 1L:f) {
sub <- phase == i
lines((y[sub] - min(y)) * scale - 0.45 + i, x[sub], type = type, ...)
}
The x coordinate there is a slot offset, not a reading: every subseries is
squeezed into its own 0.9-wide band so twelve of them fit side by side on
one axis. What the offset is computed from is times, and that is the
reading – the cycle each observation falls in. So each series comes out as
its own subseries over times, carrying its position's label as z, which
is the shape BaseRLineLayerProcessor already reads for matplot.
Recomputed from the recorded arguments rather than read back off the drawing, for the reason the correlograms recompute theirs (#276): the slot offsets are on the page and the times are not, and the offsets are the half that carries no meaning.
What is not read
base draws one horizontal segment per position at base(x[phase == i])
– the position's mean, by default – and those segments are not emitted.
There is no shape in the grammar for a per-series reference level, and a
series of its own would be wrong: the twelve means run across the cycle
positions, while every series here runs across the cycles, so putting
them in one layer would put two x domains in it. Left to a maintainer with
the grammar to change.
type does not change the reading, for the reason interaction.plot's does
not change its own (#278): "l" and "h" draw the same subseries with
different marks, and reading the spikes as loose values would lose the
grouping that makes the chart a subseries plot.
It does change where the marks are, though. "h" is not handed to
lines() the way a type usually is – monthplot branches and calls
segments() instead – so the grobs land under -segments- and the
inherited search for -lines- finds nothing. A layer with no selectors is
dropped by the frontend's selectors.length === series count precondition,
so the chart would read correctly and highlight nothing at all. See
selector_grob_type() and generate_selectors() below.
A monthly series whose labels this reads rather than the caller writes is
named with month.abb rather than with monthplot's own initials – see
the note beside ts_labels() for why the initials do not survive being
announced.
Super classes
LayerProcessor -> BaseRLineLayerProcessor -> BaseRSubseriesLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRLineLayerProcessor$axis_extent()BaseRLineLayerProcessor$extract_abline_data()BaseRLineLayerProcessor$extract_main_title()BaseRLineLayerProcessor$extract_multiline_data()BaseRLineLayerProcessor$extract_single_line_data()BaseRLineLayerProcessor$find_lines_grobs()BaseRLineLayerProcessor$generate_selectors_from_grob()BaseRLineLayerProcessor$get_axis_labels()BaseRLineLayerProcessor$get_x_range_from_group()BaseRLineLayerProcessor$get_y_range_from_group()BaseRLineLayerProcessor$needs_reordering()BaseRLineLayerProcessor$process()
BaseRSubseriesLayerProcessor$extract_data()
One series per cycle position, over that position's own subseries.
Built point by point rather than through
extract_multiline_data(), which takes a matrix and so would need the
short positions padded. A series of 48 monthly observations gives every
month four cycles and pads nothing; 50 gives January and February five
and the other ten four, and the padding would put two points on the
chart that monthplot never drew.
Usage
BaseRSubseriesLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information for the recorded call
Returns
A list of series, each a list of x/y/z points
BaseRSubseriesLayerProcessor$extract_axis_titles()
The labels the drawing writes.
monthplot's own ylab default is deparse1(substitute(x)), so it
names the expression the caller wrote. The wrapper records evaluated
values, by which point substitute() is gone, so the expression comes
off the recorded call text instead, the way the correlograms recover
their series names (#276).
There is no default for xlab: monthplot blanks it unless the caller
passes one, because the axis it writes carries the cycle labels and not
a quantity. An unset label is left unset rather than invented.
Usage
BaseRSubseriesLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoLayer information for the recorded call
Returns
An axes list from build_axes()
BaseRSubseriesLayerProcessor$generate_selectors()
The selectors, with the base line's grob left out of them.
monthplot draws the base reference segments in one segments()
call before the loop, so on a type = "h" chart the first
-segments- grob is the twelve means and the rest are the twelve
subseries. Handed over as they are, every series would be outlined on
the position before it.
A count that is not exactly one more than the series drops the selectors rather than guessing which grob is which: outlining the wrong spikes is worse than outlining none.
base = NULL would remove the extra grob, and cannot arrive here:
monthplot(x, type = "h", base = NULL) raises object 'means' not found inside stats – measured – because the "h" branch reads a
means the base guard never computed. A call that raised is never
recorded.
Usage
BaseRSubseriesLayerProcessor$generate_selectors(layer_info, gt = NULL)
Arguments
layer_infoLayer information for the recorded call
gtThe gtable the drawing was exported to
Returns
A list of CSS selectors, one per series
BaseRSubseriesLayerProcessor$selector_grob_type()
Which family of grob names this layer's selectors come from.
-segments- when the spikes were drawn, -lines- otherwise. Public
because the parent's is: generate_selectors_from_grob() reaches it
through self$, which finds nothing private.
Usage
BaseRSubseriesLayerProcessor$selector_grob_type(layer_info)
Arguments
layer_infoLayer information for the recorded call
Returns
"segments" or "lines"
BaseRSubseriesLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRSubseriesLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Term Plot Processor
Description
Reads termplot() as the partial-effect curves it draws: one panel per
term, the term's contribution to the fit plotted against its own carrier.
A grid, not a layer. Like pairs() and lag.plot(), one termplot()
call draws several panels, and the orchestrator's ordinary multipanel path
cannot split them: combine_layer_results() maps a layer to a cell by its
group index, and one recorded call is one group, so every curve would
land in the same cell. So this answers multi_panel = TRUE and places each
curve at its own cell.
The panels are pages, not terms. termplot() sets no layout of its
own – unlike pairs(), which calls par(mfrow) itself – so the caller's
par(mfrow) decides how many terms share a page, and R starts a new page
when it runs out of cells. Only the last page is exported. Measured on a
three-term lm:
no mfrow (k = 1) graphics-plot-1 1 panel mfrow c(1,2) (k = 2) graphics-plot-1 1 panel mfrow c(1,3) (k = 3) graphics-plot-1 .. -3 3 panels mfrow c(2,2) (k = 4) graphics-plot-1 .. -3 3 panels
So with n terms and k cells the page carries the last
((n - 1) %% k) + 1 of them, which is the rule
compute_panel_slots() already applies to whole plot groups – the same
arithmetic, one level down. A reading that announced all n terms would
name curves that are not on the page.
The par call is recorded as LAYOUT rather than as a layer, so it does not
reach the processor with the rest of the call. It is read off the device
the call was recorded on, through the same detect_panel_configuration()
the orchestrator uses, so the two cannot disagree about the grid.
What a panel draws. The curve is the term's fitted contribution,
predict(model, type = "terms")[, term], against that term's carrier from
the model frame, in increasing carrier order – which is the order
termplot() sorts them into before drawing. With
partial.resid = TRUE it adds the partial residuals,
contribution + residuals(model), as points beside the curve; measured,
that is a second grob in the same panel:
termplot(fit) panel k: lines-1 termplot(fit, partial.resid = T) panel k: lines-1 and points-1
The points are left for a follow-up rather than emitted as a second layer:
they are a different reading of the same panel, and the curve is the thing
termplot() exists to draw.
A factor term is declined. termplot() draws it as a step function
over the levels, which is neither this line nor a bar, and reading it as a
line would announce a slope between levels that have no order. It is left
out of the grid rather than given a wrong shape.
Super classes
LayerProcessor -> BaseRLineLayerProcessor -> BaseRTermplotLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()BaseRLineLayerProcessor$axis_extent()BaseRLineLayerProcessor$extract_abline_data()BaseRLineLayerProcessor$extract_axis_titles()BaseRLineLayerProcessor$extract_data()BaseRLineLayerProcessor$extract_main_title()BaseRLineLayerProcessor$extract_multiline_data()BaseRLineLayerProcessor$extract_single_line_data()BaseRLineLayerProcessor$find_lines_grobs()BaseRLineLayerProcessor$generate_selectors()BaseRLineLayerProcessor$generate_selectors_from_grob()BaseRLineLayerProcessor$get_axis_labels()BaseRLineLayerProcessor$get_x_range_from_group()BaseRLineLayerProcessor$get_y_range_from_group()BaseRLineLayerProcessor$needs_reordering()BaseRLineLayerProcessor$selector_grob_type()
BaseRTermplotLayerProcessor$process()
Emit one line layer per drawn panel
Usage
BaseRTermplotLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface.
layoutUnused; present for the processor interface.
builtUnused; present for the processor interface.
gtUnused; the selectors are built rather than searched for.
grob_idUnused; present for the processor interface.
panel_idUnused; present for the processor interface.
panel_ctxUnused; present for the processor interface.
layer_infoLayer information with the recorded call.
Returns
A multi-panel result, or NULL when nothing was read
BaseRTermplotLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRTermplotLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Unknown Layer Processor
Description
Processes unknown Base R layer types as a fallback
Super class
LayerProcessor -> BaseRUnknownLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRUnknownLayerProcessor$process()
Describe a layer nothing is known about
Usage
BaseRUnknownLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface
layoutUnused; present for the processor interface
builtUnused; present for the processor interface
gtGtable of the replayed drawing, searched for selectors (optional)
grob_idUnused; present for the processor interface
panel_idUnused; present for the processor interface
panel_ctxUnused; present for the processor interface
layer_infoLayer information with the recorded call
Returns
List with no data and no selectors
BaseRUnknownLayerProcessor$needs_reordering()
Whether the plot data must be reordered before drawing; a Base R layer is read from the recorded call and never is
Usage
BaseRUnknownLayerProcessor$needs_reordering()
Returns
FALSE
BaseRUnknownLayerProcessor$extract_data()
Nothing: an unknown layer has no data to announce
Usage
BaseRUnknownLayerProcessor$extract_data(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Empty list
BaseRUnknownLayerProcessor$generate_selectors()
Nothing: an unknown layer has no elements to address
Usage
BaseRUnknownLayerProcessor$generate_selectors(layer_info)
Arguments
layer_infoLayer information with the recorded call
Returns
Empty list
BaseRUnknownLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRUnknownLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Base R Violin Layer Processor
Description
Reads a vioplot::vioplot() call as the violin_box + violin_kde layer
pair, matching what the ggplot2 adapter produces for geom_violin(). Which
plotting system a user chose should not decide whether their chart is
accessible.
vioplot() returns its box summary but not the density curve it drew, so
both are recovered by replaying the call vioplot makes internally — see
compute_vioplot_stats(), which records why that is a transcription rather
than an approximation.
Super class
LayerProcessor -> BaseRViolinLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_data()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$generate_selectors()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
BaseRViolinLayerProcessor$process()
Read a recorded vioplot() call as two maidr layers
Usage
BaseRViolinLayerProcessor$process( plot, layout, built = NULL, gt = NULL, layer_info = NULL )
Arguments
plotUnused; present for the processor interface.
layoutUnused; present for the processor interface.
builtUnused; present for the processor interface.
gtThe grob tree of the rendered plot.
layer_infoThe recorded plot call and its metadata.
Returns
A multi-layer result, or NULL when nothing can be read.
BaseRViolinLayerProcessor$extract_violins()
The recorded call's violins, each with its statistics
Usage
BaseRViolinLayerProcessor$extract_violins(layer_info)
Arguments
layer_infoThe recorded plot call and its metadata.
Returns
A list of list(label =, stats =), one per drawn violin.
BaseRViolinLayerProcessor$build_box_data()
One box summary per violin
Usage
BaseRViolinLayerProcessor$build_box_data(violins)
Arguments
violinsAs returned by
extract_violins().
Returns
A list of box points.
BaseRViolinLayerProcessor$build_kde_data()
One density curve per violin
Usage
BaseRViolinLayerProcessor$build_kde_data(violins)
Arguments
violinsAs returned by
extract_violins().
Returns
A list of point lists, one per violin.
BaseRViolinLayerProcessor$build_kde_selectors()
Selectors addressing each violin's outline
Usage
BaseRViolinLayerProcessor$build_kde_selectors(violins, gt, plot_index)
Arguments
violinsAs returned by
extract_violins().gtThe grob tree.
plot_indexWhich recorded plot these grobs belong to.
Returns
A list of selector strings, or an empty list.
BaseRViolinLayerProcessor$build_box_selectors()
BoxSelector objects addressing each violin's box parts
vioplot draws the whisker, the quartile box and the median as separate grobs, so unlike a plotly violin – where the whole box is one path and every section has to share it – each section can point at what it actually is.
Usage
BaseRViolinLayerProcessor$build_box_selectors(violins, gt, plot_index)
Arguments
violinsAs returned by
extract_violins().gtThe grob tree.
plot_indexWhich recorded plot these grobs belong to.
Returns
A list of BoxSelector lists, or an empty list.
BaseRViolinLayerProcessor$grob_ids()
Grob names of one kind, in drawing order
Usage
BaseRViolinLayerProcessor$grob_ids(gt, plot_index, kind)
Arguments
gtThe grob tree.
plot_indexWhich recorded plot these grobs belong to.
kindOne of the kinds in
.maidr_vioplot_grob_kinds.
Returns
A character vector of grob names.
BaseRViolinLayerProcessor$plot_index()
Which recorded plot this layer belongs to
Usage
BaseRViolinLayerProcessor$plot_index(layer_info)
Arguments
layer_infoThe recorded plot call and its metadata.
Returns
An integer index.
BaseRViolinLayerProcessor$extract_axis_titles()
Axis titles for the violin's two axes
Usage
BaseRViolinLayerProcessor$extract_axis_titles(layer_info)
Arguments
layer_infoThe recorded plot call and its metadata.
Returns
An axes list.
BaseRViolinLayerProcessor$extract_main_title()
The plot's main title
Usage
BaseRViolinLayerProcessor$extract_main_title(layer_info)
Arguments
layer_infoThe recorded plot call and its metadata.
Returns
A character scalar.
BaseRViolinLayerProcessor$determine_orientation()
Whether the violins run up the page or across it
Usage
BaseRViolinLayerProcessor$determine_orientation(layer_info)
Arguments
layer_infoThe recorded plot call and its metadata.
Returns
"vert" or "horz".
BaseRViolinLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
BaseRViolinLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
The std choices graphics::fourfoldplot() offers
Description
Written out rather than read from formals(graphics::fourfoldplot)$std,
which is an unevaluated call of length 4 (measured: class() is
"call", and formals(...)$std[[1]] is the symbol c) and would have to
be eval()ed on every dispatch. That the literal still matches upstream is
asserted against the real formals() in
tests/testthat/test-base-r-fourfoldplot.R, the answer the qqplot
branch gives to the same exposure.
Usage
FOURFOLD_STD_CHOICES
A path geom that admits a threshold aesthetic
Description
ggplot2::GeomPath with one optional aesthetic added, so that a
threshold mapped to a maidr_roc() layer survives ggplot_build() as a
column of the built data rather than being dropped with Ignoring unknown aesthetics. Nothing about the drawing changes; the aesthetic reaches no
grob.
Usage
GeomRoc
Format
A ggproto object inheriting from ggplot2::GeomPath
ggplot2 System Adapter
Description
Adapter for the ggplot2 plotting system. This adapter wraps the existing ggplot2 functionality to work with the new extensible architecture.
Format
An R6 class inheriting from SystemAdapter
Super class
SystemAdapter -> Ggplot2Adapter
Methods
Public methods
Ggplot2Adapter$new()
Initialize the ggplot2 adapter
Usage
Ggplot2Adapter$new()
Ggplot2Adapter$can_handle()
Check if this adapter can handle a plot object
Usage
Ggplot2Adapter$can_handle(plot_object)
Arguments
plot_objectThe plot object to check
Returns
TRUE if this adapter can handle the object, FALSE otherwise
Ggplot2Adapter$detect_layer_type()
Detect the type of a single layer
Usage
Ggplot2Adapter$detect_layer_type(layer, plot_object)
Arguments
layerThe ggplot2 layer object to analyze
plot_objectThe parent plot object (for context)
Returns
String indicating the layer type (e.g., "bar", "line", "point")
Ggplot2Adapter$is_pie_coord()
Check if a bar layer is drawn as pie wedges
coord_radial() produces a CoordRadial that does NOT inherit
CoordPolar, so both class names have to be tested. theta decides
what the angle encodes: only theta = "y" maps a bar's height
onto the angle, which is a pie. theta = "x" keeps the height on
the radius, which is a coxcomb/rose - still a bar chart, just bent.
The coordinate system alone is not enough: a polar bar layer is a pie
only when it draws ONE ring. geom_col(aes(x = category)) under
coord_polar("y") draws one concentric ring per x category - a
bullseye - and a pie payload has no room for that second dimension, so
such a layer keeps the bar classification it has always had.
Usage
Ggplot2Adapter$is_pie_coord(plot_object, layer = NULL)
Arguments
plot_objectThe ggplot2 plot object
layerThe layer being classified, or NULL for the plot's first
Returns
TRUE when the layer is drawn as a pie, FALSE otherwise
Ggplot2Adapter$draws_single_ring()
Check if a layer occupies a single position on x
The ring count has to come off the BUILT data: a mapping expression
cannot say how many levels it has, and by build time ggplot2 has
already resolved every constant form - the literal "", a
one-level factor, a column holding one repeated value - to the same
single x position. Each facet panel is its own pie, so constancy is
asked of each panel separately. A build that fails answers FALSE,
leaving the layer classified the way it was before pie support.
Usage
Ggplot2Adapter$draws_single_ring(plot_object, layer = NULL)
Arguments
plot_objectThe ggplot2 plot object
layerThe layer being classified, or NULL for the plot's first
Returns
TRUE when no panel holds more than one x position
Ggplot2Adapter$find_layer_index()
Locate a layer among its plot's layers
Usage
Ggplot2Adapter$find_layer_index(plot_object, layer = NULL)
Arguments
plot_objectThe ggplot2 plot object
layerThe layer to locate, or NULL for the plot's first
Returns
Integer index into the plot's layers, or NULL when absent
Ggplot2Adapter$create_orchestrator()
Create an orchestrator for this system (ggplot2)
Usage
Ggplot2Adapter$create_orchestrator(plot_object)
Arguments
plot_objectThe ggplot2 plot object to process
Returns
PlotOrchestrator instance
Ggplot2Adapter$get_system_name()
Get the system name
Usage
Ggplot2Adapter$get_system_name()
Returns
System name string
Ggplot2Adapter$get_adapter()
Get a reference to this adapter (for use by orchestrator)
Usage
Ggplot2Adapter$get_adapter()
Returns
Self reference
Ggplot2Adapter$has_facets()
Check if plot has facets
Usage
Ggplot2Adapter$has_facets(plot_object)
Arguments
plot_objectThe ggplot2 plot object
Returns
TRUE if plot has facets, FALSE otherwise
Ggplot2Adapter$is_patchwork()
Check if plot is a patchwork plot
Usage
Ggplot2Adapter$is_patchwork(plot_object)
Arguments
plot_objectThe ggplot2 plot object
Returns
TRUE if plot is patchwork, FALSE otherwise
Ggplot2Adapter$ribbon_is_area()
Whether a ribbon fills from a baseline rather than spanning two curves.
geom_ribbon(aes(ymin = 0, ymax = y)) is an area chart: the magnitude
is the height of the fill, measured from a baseline the reader can
assume. geom_ribbon(aes(ymin = lo, ymax = hi)) draws the gap, and
its content is the distance between two edges rather than the height of
either – read as an area it would announce hi as a magnitude and drop
lo entirely.
The same distinction the Python binding draws for fill_between(), and
drawn the same way: only an identically-zero lower edge is an area.
Reads the built data rather than the mapping, because ymin may be a
constant, a column, or a computed aesthetic, and only the built frame
has resolved which. A layer that cannot be built is treated as a band,
which is the reading that loses nothing: an area announced as an
interval still carries both edges.
Usage
Ggplot2Adapter$ribbon_is_area(layer, plot_object)
Arguments
layerThe ggplot2 layer
plot_objectThe parent plot object
Returns
TRUE when the ribbon is an area chart
Ggplot2Adapter$segments_span_lanes()
Check whether a segment layer draws intervals in lanes
Asked of the built data for the reason ribbon_is_area() is: a
mapping expression cannot say whether the two ends of a segment agree,
and by build time ggplot2 has resolved every spelling of the lane – a
factor, a character column, a repeated constant – to the position it
drew at.
The whole layer is asked at once rather than each row, which is the
rule xability/maidr#1100 settled for the same reading: one
geom_segment() call can hold spans and edges together, and
reading three spans out of four segments would announce a gantt quietly
missing a quarter of its chart.
Usage
Ggplot2Adapter$segments_span_lanes(layer, plot_object)
Arguments
layerThe layer being classified
plot_objectThe ggplot2 plot object
Returns
TRUE when the layer's segments lay intervals in lanes
Ggplot2Adapter$rect_spans_lanes()
Check whether a declared rect layer draws intervals in lanes
Asked through the same predicate the processor will use, so the two
cannot disagree about what a schedule is: rect_gantt_frame()
renames the declared layer's bounds into the four columns
segment_lane_axis() already reads, and the landed test decides.
The degenerate case comes free rather than needing a rule of its own.
Measured: a declared layer whose rectangles are all zero-width
normalises to level on both axes, segment_lane_axis() returns
NULL, and the layer is refused instead of being announced as a schedule
of zero-length work – which is the rule this file already applies to
geom_segment().
Nothing else is asked of the rectangles. A guard on their shape is the
structural rule the eight-chart table above the GeomRect branch
of detect_layer_type() falsified, and a veto on a layer the
author explicitly declared is near-useless anyway: measured, a declared
monotone waterfall partitions on y and would pass one.
Usage
Ggplot2Adapter$rect_spans_lanes(layer, plot_object)
Arguments
layerThe layer being classified
plot_objectThe ggplot2 plot object
Returns
TRUE when the layer's rectangles lay intervals in lanes
Ggplot2Adapter$unread_layer_type()
The answer for a layer no branch above claimed
"unknown" is what makes has_unsupported_layers() true and
drops the whole plot to a static image. That is right for a layer
carrying marks nothing describes: a filled geom_polygon() is
drawn, and a reader told the chart was complete would be told wrong.
It is not right for a layer that drew nothing. Then there is no mark,
so there is nothing the reader is missing, and the chart pays
everything to protect them from an absence. Measured with
save_html() on thirty points:
geom_point() interactive 50,406 bytes geom_point() + geom_point(data = d[0, ]) interactive 51,313 bytes geom_point() + geom_polygon(data = d[0, ]) base64 image 27,368 bytes geom_point() + geom_polygon() base64 image 31,848 bytes
Rows two and three are the same chart in every way a reader could tell – thirty points and a layer of nothing – and only one of them was interactive, because its empty layer happened to be of a kind this function names. Row four is the case the fallback exists for, and it keeps falling back.
The case this turns up in is not contrived: a missing Suggests
package. geom_quantile() without quantreg warns, computes
no rows and draws nothing; ggplot2 carries on and r-maidr turned the
whole figure into a picture, with no second warning connecting the two
(#227).
A plot made only of such layers still falls back, for the reason #176
gives: has_unsupported_layers() is true when every layer
is "skip" as well, so "nothing unsupported" cannot quietly come
to mean "nothing at all".
Nothing here decides which geoms are readable. A geom_polygon()
with data in it is still "unknown" and still costs its chart
exactly what it costs today.
Usage
Ggplot2Adapter$unread_layer_type(layer, plot_object)
Arguments
layerThe layer being classified
plot_objectThe ggplot2 plot object
Returns
"skip" when the layer drew no rows, "unknown"
otherwise
Ggplot2Adapter$layer_drew_nothing()
Whether a layer put no mark on the page at all
A layer's rows can vanish in its input, in a filter, in an aggregate
over no groups, or – the case #227 was found through – in a stat that
could not run because a Suggests package is absent. All four
arrive here identically: ggplot_build() reports zero rows for
that layer while ggplot2 warns, draws the rest of the chart and carries
on.
Asked by unread_layer_type(), which turns it into "skip"
rather than "unknown", and by the quantile branch of
detect_layer_type(), which uses it to keep from claiming a
curve that was never drawn (#229). Kept as its own method for that
second caller: a rule two branches ask is a rule, not a fall-through.
Declines whenever the build cannot answer – it raised, or gave this layer no frame. Absent is not empty: a build that said nothing about what a layer drew must not have that read as "it drew nothing", which would wave a mark through as harmless.
Usage
Ggplot2Adapter$layer_drew_nothing(layer, plot_object)
Arguments
layerThe layer being asked about
plot_objectThe ggplot2 plot object
Returns
TRUE when the layer built no rows
Ggplot2Adapter$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2Adapter$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
ggplot2 Area Layer Processor
Description
Processes geom_area() into MAIDR's area, stacked_area and
stacked_normalized_area layers.
Before this processor existed these layers fell through to
Ggplot2UnknownLayerProcessor, so an area chart carried no data at all.
Why not read it as a line
In a stacked area chart the band's top edge is a cumulative total while the band's height is the series' own value. A line layer announces one number per point with nothing to say which of those two it is, so the type exists to keep them apart: MAIDR's area trace announces the series' value and reports the running total beside it.
The two traps in ggplot2's built data
y is not the value. ggplot2 stacks by computing absolute band edges,
so ymin/ymax are the cumulative positions and y is the top edge. The
series' own value is ymax - ymin, and MAIDR sums the series itself to
reach the total. Emitting y would hand it a cumulative number to
accumulate again, announcing totals that grow with the number of series
rather than with the data.
Most of the rows are not data. geom_area() defaults to
stat = "align", which inserts interpolation vertices so the bands stack
cleanly and closes each polygon on the baseline. A four-point, two-series
chart produces twenty-four rows:
x y ymin ymax group align_padding 1999.997 0.000 0.000 0.000 1 TRUE 2000.000 5.000 2.000 5.000 1 FALSE 2000.003 5.009 2.003 5.009 1 FALSE <- not a data point 2000.997 7.991 2.997 7.991 1 FALSE <- not a data point
Read whole, a chart of four years announces twelve points per series,
including a reading of 5.009 at "year 2000.003" – a value the data does
not hold at an x the chart does not have. align_padding does not
identify them: it marks only the two baseline-closing vertices.
The rows that are data are those whose x the layer's own data carries,
which is verified to give the same answer as stat = "identity".
Super classes
LayerProcessor -> Ggplot2LineLayerProcessor -> Ggplot2AreaLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()Ggplot2LineLayerProcessor$attach_discrete_y_names()Ggplot2LineLayerProcessor$attach_group_axis()Ggplot2LineLayerProcessor$attach_level_labels()Ggplot2LineLayerProcessor$build_level_lookup()Ggplot2LineLayerProcessor$curve_selectors()Ggplot2LineLayerProcessor$extract_data()Ggplot2LineLayerProcessor$extract_layer_axes()Ggplot2LineLayerProcessor$extract_multiline_data()Ggplot2LineLayerProcessor$extract_single_line_data()Ggplot2LineLayerProcessor$find_main_polyline_grob()Ggplot2LineLayerProcessor$format_x_value()Ggplot2LineLayerProcessor$generate_multiline_selectors()Ggplot2LineLayerProcessor$generate_single_line_selector()Ggplot2LineLayerProcessor$get_group_column()Ggplot2LineLayerProcessor$get_layer()Ggplot2LineLayerProcessor$get_x_transformation()Ggplot2LineLayerProcessor$has_series_groups()Ggplot2LineLayerProcessor$line_layer_position()Ggplot2LineLayerProcessor$needs_reordering()Ggplot2LineLayerProcessor$normalize_point_values()Ggplot2LineLayerProcessor$panel_axis_labels()Ggplot2LineLayerProcessor$polyline_curve_count()Ggplot2LineLayerProcessor$recover_x_values()Ggplot2LineLayerProcessor$resolve_group_mapping()Ggplot2LineLayerProcessor$series_count()Ggplot2LineLayerProcessor$transform_x_values()
Ggplot2AreaLayerProcessor$process()
Process the area layer.
Usage
Ggplot2AreaLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selectors (optional)
Returns
List with data, axes and type
Ggplot2AreaLayerProcessor$generate_selectors()
One selector per band, so navigation highlights a band.
geom_area draws each series as its own geom_ribbon.gTree holding a
filled GRID.polygon, which is the granularity the consumer wants:
AreaTrace extends the line trace, whose multi-series highlight needs
one selector per series and discards a list whose length disagrees.
The polygon rather than the outline polyline each ribbon also draws: the band is the mark a reader is being pointed at, and outlining it would highlight a hairline around the shape instead of the shape.
The existing curve machinery does not transfer.
Ggplot2LineLayerProcessor$curve_selectors() counts curves inside one
auto-named polyline grob, and layer_polyline_grobs() deliberately
skips geom-named gTrees to avoid miscounting – an area layer being
exactly the shape that helper excludes.
Emits nothing rather than a short or mispaired list, for the reason every processor here gives: the caller can tell an empty selector list apart from a wrong one, and a user cannot.
Usage
Ggplot2AreaLayerProcessor$generate_selectors( plot, gt = NULL, panel_ctx = NULL, n_series = 0L )
Arguments
plotThe ggplot2 object
gtGtable object
panel_ctxPanel context for panel-scoped selector generation
n_seriesHow many bands the data reports
Returns
A list of selectors, one per band, or an empty list
Ggplot2AreaLayerProcessor$band_polygon_names()
Names of the band polygon grobs inside a grob, in draw order, which is series order.
Matches the auto-generated GRID.polygon.N name exactly rather than by
prefix, so a theme element's own polygon – named after the element,
not after grid's counter – cannot be collected as a band. Anchoring
both ends is what keeps this from widening the way a grepl on a bare
prefix would.
Usage
Ggplot2AreaLayerProcessor$band_polygon_names(grob)
Arguments
grobA grob to walk
Returns
Character vector of grob names
Ggplot2AreaLayerProcessor$resolve_area_type()
Decide which of the three area types this layer is.
position = "fill" rescales every column to a common height, so a
band's height is its share of that column and every column totals 1 by
construction. Reading that as a plain stacked area would announce the
shares as if they were values and imply the columns have equal totals,
which is the one thing a filled chart is drawn to deny – the same
distinction stacked_normalized_bar draws for bars.
A single series has nothing stacked on it whatever its position, so it is a plain area: announcing a running total equal to the value at every point would be noise.
Usage
Ggplot2AreaLayerProcessor$resolve_area_type(plot, series)
Arguments
plotThe ggplot2 object
seriesThe emitted series
Returns
One of "area", "stacked_area", "stacked_normalized_area"
Ggplot2AreaLayerProcessor$extract_series()
Build the MAIDR series for this layer.
Emits each series' own value rather than the cumulative band top, because MAIDR's area trace sums the series to reach the running total and announces the two separately.
Usage
Ggplot2AreaLayerProcessor$extract_series(built, layer_data, panel_id = NULL)
Arguments
builtBuilt plot data
layer_dataThis layer's computed rows
panel_idPanel ID for faceted plots (optional)
Returns
A list of series, each a list of MAIDR points
Ggplot2AreaLayerProcessor$drop_alignment_vertices()
Keep only the rows the chart was given.
StatAlign inserts interpolation vertices and baseline-closing
vertices, neither of which is an observation. The rows that are data are
those whose x appears in the layer's own data; that filter is verified
to give the same rows stat = "identity" produces.
A layer whose x values cannot be recovered keeps every row rather than losing the chart – a noisy reading being better than none – which is why this returns the input unchanged rather than empty when the lookup fails.
Usage
Ggplot2AreaLayerProcessor$drop_alignment_vertices(built, layer_data)
Arguments
builtBuilt plot data
layer_dataThis layer's computed rows
Returns
The data-bearing rows
Ggplot2AreaLayerProcessor$source_x_values()
Read the x values the layer was given, before any stat.
Reports a discrete axis as such rather than guessing its positions: those are assigned by the scale, and reconstructing them from the data column would drift the moment a factor level appeared in one and not the other. The caller has an exact rule for that case.
"Discrete" and "could not be read" are answered differently, because
the caller must do different things with them. The integer rule that is
exact for a discrete axis would silently drop the fractional rows of a
continuous one, and an x mapped through an expression – aes(x = year / 2), say – resolves to no column and lands here while still being
continuous. Collapsing the two into one NULL is how that axis loses
half its data to a rule that was never about it.
Usage
Ggplot2AreaLayerProcessor$source_x_values(built)
Arguments
builtBuilt plot data
Returns
list(kind = "discrete"), list(kind = "numeric", values =),
or NULL when the axis could not be read at all
Ggplot2AreaLayerProcessor$band_height()
The band's own height at one row.
Falls back to y when the edges are absent, since an unstacked layer
whose baseline is the axis draws a band of exactly that height.
Usage
Ggplot2AreaLayerProcessor$band_height(rows, i)
Arguments
rowsThe rows of one series
iWhich row
Returns
The series' value at that row
Ggplot2AreaLayerProcessor$resolve_series_labels()
Name each series after its fill level.
Usage
Ggplot2AreaLayerProcessor$resolve_series_labels(built, rows, panel_id = NULL)
Arguments
builtBuilt plot data
rowsThis layer's data-bearing rows
panel_idPanel ID for faceted plots (optional)
Returns
A named list of group key to label
Ggplot2AreaLayerProcessor$fill_levels()
The fill levels, in the order ggplot2 numbered the groups.
Usage
Ggplot2AreaLayerProcessor$fill_levels(built)
Arguments
builtBuilt plot data
Returns
A character vector of levels, possibly empty
Ggplot2AreaLayerProcessor$attach_fill_axis()
Add the legend title as the z axis, when there is one.
Usage
Ggplot2AreaLayerProcessor$attach_fill_axis(plot, built, axes, panel_id = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data
axesThe axes assembled so far
panel_idPanel ID for faceted plots (optional)
Returns
The axes, with z added when a fill legend exists
Ggplot2AreaLayerProcessor$mapped_column()
Name the source column an aesthetic is mapped to.
aes(x = factor(year)) maps a call rather than a bare name, and the
column the data actually holds is its argument – so the call is
unwrapped rather than labelled, which would give "factor(year)" and
match nothing.
Usage
Ggplot2AreaLayerProcessor$mapped_column(quo)
Arguments
quoThe mapped quosure, or NULL
Returns
The column name, or NULL when there is no mapping
Ggplot2AreaLayerProcessor$scalar()
Convert one coordinate to a JSON-safe scalar.
Usage
Ggplot2AreaLayerProcessor$scalar(value)
Arguments
valueA coordinate read off the built data
Returns
A number, or a string when the coordinate is not numeric
Ggplot2AreaLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2AreaLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Bar Layer Processor
Description
Processes bar plot layers with complete logic included
Super class
LayerProcessor -> Ggplot2BarLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2BarLayerProcessor$process()
Process the layer: read its bars, selectors and orientation from the built plot
Usage
Ggplot2BarLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List describing the layer for the MAIDR payload
Ggplot2BarLayerProcessor$is_flipped()
Is this layer's category axis y rather than x?
ggplot(df, aes(y = g, x = n)) + geom_col() is the ordinary spelling of
a horizontal bar chart, and ggplot_build() marks it flipped_aes and
swaps which computed column holds what. Everything below reads x as
the category and y as the measure, so on a flipped layer it picked up
exactly the wrong pair: apple/banana/cherry at 30/70/50 came out as
category "30" with value 1, category "50" with value 3 and
category "70" with value 2 – the labels gone, the values replaced
by factor codes, and the rows resorted by the measure (#162).
coord_flip() is not this. It rotates the coordinate system and leaves
flipped_aes alone, so its data layout is genuinely unflipped, and it
is reported vert today. That question spans every processor.
Should it ever be answered here, the key and the point layout have to
move together: "horz" and the vertical x = category, y = measure
pairing is precisely the combination #184 was about, and a
coord_flip() chart currently reads correctly only because both halves
are left in their vertical form. That is what swap_point_axes()
being driven from this same answer is for.
Usage
Ggplot2BarLayerProcessor$is_flipped(plot, built = NULL)
Arguments
plotThe ggplot2 object.
builtIts
ggplot_build()result, when the caller has one.
Returns
TRUE when the category runs up the y axis.
Ggplot2BarLayerProcessor$unflip_mapping()
Exchange a plot's x and y aesthetics
Returns a copy: the mapping is only read to recover the category's column name, and the caller's plot is still wanted unswapped for selectors and axis labels.
The layer is copied too. A ggplot2 layer is a ggproto object, which
is an environment, so assigning into plot$layers[[i]]$mapping
wrote through to the caller's plot: after one read a horizontal
geom_col(aes(y = g, x = n)) was a vertical chart, for the render
and for the user. The swapped mapping goes on a child object that
inherits everything else from the layer, so the layer itself is
never written.
Usage
Ggplot2BarLayerProcessor$unflip_mapping(plot)
Arguments
plotThe ggplot2 object.
Returns
A copy whose plot-level and layer-level x/y mappings are swapped.
Ggplot2BarLayerProcessor$needs_reordering()
Whether the plot data must be reordered before drawing, so the emitted order matches the drawn rects
Usage
Ggplot2BarLayerProcessor$needs_reordering()
Returns
TRUE
Ggplot2BarLayerProcessor$reorder_layer_data()
Reorder the plot data by category so the emitted rows match the drawn rects
Usage
Ggplot2BarLayerProcessor$reorder_layer_data(data, plot)
Arguments
dataThe data frame ggplot2 will draw from
plotThe ggplot2 object
Returns
The reordered data frame
Ggplot2BarLayerProcessor$extract_data()
One point per bar, read from the built plot
Usage
Ggplot2BarLayerProcessor$extract_data(plot, built = NULL, panel_id = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
Returns
List of points
Ggplot2BarLayerProcessor$format_x_value()
Format an x-axis value as character.
Date / POSIXct / POSIXlt values are formatted via format() so that a
Date column emits ISO date strings ("2024-01-02") rather than the
default scale-tick labels ("Jan 02"). All other types use
as.character(). Mirrors Ggplot2CandlestickProcessor$format_x_value()
so candle and bar layers from the same Date column align string-wise.
Usage
Ggplot2BarLayerProcessor$format_x_value(x)
Arguments
xThe value to format
Returns
Character vector
Ggplot2BarLayerProcessor$panel_x_is_discrete()
Does this panel draw x on a discrete scale?
Only a discrete scale numbers its built positions 1..n, which is what makes indexing the break labels with them legitimate.
Usage
Ggplot2BarLayerProcessor$panel_x_is_discrete(panel_params, x_pos, panel_labels)
Arguments
panel_paramsThis panel's entry from
built$layout$panel_paramsx_posBuilt x positions for this panel
panel_labelsThis panel's x break labels, or NULL
Returns
TRUE for a discrete x scale
Ggplot2BarLayerProcessor$map_discrete_x()
Label discrete built positions with this panel's breaks.
Usage
Ggplot2BarLayerProcessor$map_discrete_x(x_pos, panel_labels)
Arguments
x_posBuilt x positions for this panel
panel_labelsThis panel's x break labels, or NULL
Returns
Character vector of x labels
Ggplot2BarLayerProcessor$map_continuous_x()
Recover user-facing x values for a non-discrete scale.
Built positions on a continuous, Date or datetime scale already are
the values, but a Date arrives as a day count. Matching them back to
the mapped column restores the original typing so format_x_value()
can emit "2024-01-02" rather than "19724". Mirrors the same recovery
in Ggplot2LineLayerProcessor.
Usage
Ggplot2BarLayerProcessor$map_continuous_x(x_pos, plot, layer_index)
Arguments
x_posBuilt x positions for this panel
plotThe ggplot object
layer_indexIndex of this layer within the plot
Returns
Character vector of x labels
Ggplot2BarLayerProcessor$generate_selectors()
Selectors for the layer's rects
Usage
Ggplot2BarLayerProcessor$generate_selectors( plot, gt = NULL, grob_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List of selectors
Ggplot2BarLayerProcessor$own_rect_names()
The rect grob names under this layer's own slot, or under the whole panel
A panel holds one geom_rect.rect grob per bar layer, so a plot
that overlays two geom_col()s – a total behind a highlighted
part is the usual reason – has two, and a search over the panel
returns both to each layer. Its selectors then address every bar in
the panel: the frontend finds twice the marks it has points for and
highlights nothing, on both layers. So the search is scoped to the
layer's own slot (see find_layer_slot_grob()): whatever the
geom drew there, a bare rect grob or a tree wrapping one, and nothing
when it drew no rects here at all. The panel-wide search remains only
for a panel whose layout the slot cannot be read from.
Usage
Ggplot2BarLayerProcessor$own_rect_names(panel_grob, find_rect_names)
Arguments
panel_grobThe panel grob
find_rect_namesFunction collecting every rect grob name under a grob
Returns
Character vector of rect grob names
Ggplot2BarLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2BarLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Boxplot Layer Processor
Description
Processes boxplot layers (geom_boxplot) to extract statistical data and generate selectors for individual boxplot components in the SVG structure.
Super class
LayerProcessor -> Ggplot2BoxplotLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2BoxplotLayerProcessor$get_built()
Get (and cache) the built plot data
ggplot_build() is expensive; extract_data, generate_selectors, determine_orientation, and map_categories_to_names all need it, so build at most once per processor instance.
Usage
Ggplot2BoxplotLayerProcessor$get_built(plot, built = NULL)
Arguments
plotThe ggplot2 object
builtOptionally a pre-built plot to adopt
Returns
Built plot data
Ggplot2BoxplotLayerProcessor$process()
Process the boxplot layer
Usage
Ggplot2BoxplotLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selectors (optional)
Returns
List with data and selectors
Ggplot2BoxplotLayerProcessor$extract_data()
Extract data from boxplot layer
Usage
Ggplot2BoxplotLayerProcessor$extract_data(plot, built = NULL, panel_id = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idOptional facet panel to restrict extraction to
Returns
List with boxplot statistics for each category
Ggplot2BoxplotLayerProcessor$generate_selectors()
Generate selectors for boxplot elements
Usage
Ggplot2BoxplotLayerProcessor$generate_selectors( plot, gt = NULL, panel_ctx = NULL, panel_id = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
panel_ctxPanel context for panel-scoped selection (optional)
panel_idOptional facet panel to restrict outlier counts to
Returns
List of selectors for each boxplot
Ggplot2BoxplotLayerProcessor$determine_orientation()
Determine if the boxplot is horizontal or vertical
Usage
Ggplot2BoxplotLayerProcessor$determine_orientation(plot)
Arguments
plotThe ggplot2 object
Returns
"horz" or "vert"
Ggplot2BoxplotLayerProcessor$map_categories_to_names()
Map numeric category codes to actual category names Uses panel_params axis labels from ggplot_build to map codes to labels
Usage
Ggplot2BoxplotLayerProcessor$map_categories_to_names( boxplot_data, plot, panel_id = NULL )
Arguments
boxplot_dataList of boxplot statistics
plotThe ggplot2 object
panel_idOptional facet panel whose scale supplies the labels
Returns
Updated boxplot data with proper category names
Ggplot2BoxplotLayerProcessor$find_panel_grob()
Find the panel grob this layer draws into
Usage
Ggplot2BoxplotLayerProcessor$find_panel_grob(gt, panel_ctx = NULL)
Arguments
gtThe gtable to search
panel_ctxPanel context for patchwork leaves and facets; NULL for a single plot, where the panel is the cell literally named "panel"
Returns
The panel grob or NULL
Ggplot2BoxplotLayerProcessor$find_children_by_type()
Find children by type pattern
Usage
Ggplot2BoxplotLayerProcessor$find_children_by_type(grob, type_pattern)
Arguments
grobThe grob to search
type_patternPattern to match
Returns
List of matching children
Ggplot2BoxplotLayerProcessor$find_outlier_container()
Find the outlier container within a boxplot
Usage
Ggplot2BoxplotLayerProcessor$find_outlier_container(gt, boxplot_id)
Arguments
gtThe gtable object
boxplot_idThe boxplot container ID
Returns
The outlier container ID or NULL
Ggplot2BoxplotLayerProcessor$find_box_container()
Find the box container within a boxplot
Usage
Ggplot2BoxplotLayerProcessor$find_box_container(gt, boxplot_id)
Arguments
gtThe gtable object
boxplot_idThe boxplot container ID
Returns
The box container ID or NULL
Ggplot2BoxplotLayerProcessor$find_whisker_container()
Find the whisker container within a boxplot
Usage
Ggplot2BoxplotLayerProcessor$find_whisker_container(gt, boxplot_id)
Arguments
gtThe gtable object
boxplot_idThe boxplot container ID
Returns
The whisker container ID or NULL
Ggplot2BoxplotLayerProcessor$find_median_container()
Find the median container within a boxplot
Usage
Ggplot2BoxplotLayerProcessor$find_median_container(gt, boxplot_id)
Arguments
gtThe gtable object
boxplot_idThe boxplot container ID
Returns
The median container ID or NULL
Ggplot2BoxplotLayerProcessor$find_child_by_pattern()
Find a child element by pattern within a container
Usage
Ggplot2BoxplotLayerProcessor$find_child_by_pattern(gt, container_id, pattern)
Arguments
gtThe gtable object
container_idThe container ID to search within
patternPattern to match
Returns
The matching child ID or NULL
Ggplot2BoxplotLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2BoxplotLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Candlestick Layer Processor
Description
Processes candlestick chart layers produced by tidyquant::geom_candlestick().
tidyquant's geom_candlestick() expands into TWO ggplot layers:
A
GeomLinerangeBC(BC = barchart) layer drawing the high-low wicks.A
GeomRectCS(CS = candlestick) layer drawing the open-close bodies.
The adapter tags the wick layer as "skip" so the orchestrator does not
create a separate maidr layer for it. This processor handles only the
second (body) layer, but reads back into the wick layer's grobs to
produce wick CSS selectors.
Output type: "candlestick". Each data point is a CandlestickPoint
with value, open, high, low, close, optional volume,
computed trend (Bull / Bear / Neutral) and volatility (high - low).
Selectors are emitted as a single CandlestickSelector object whose
body and wick fields are arrays of per-candle CSS selectors using
:nth-of-type against the rect/line elements of the gridSVG-exported
tidyquant grobs.
Super class
LayerProcessor -> Ggplot2CandlestickProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2CandlestickProcessor$process()
Process the candlestick layer
Usage
Ggplot2CandlestickProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotggplot2 object
layoutLayout information
builtBuilt plot data
gtGtable object
grob_idGrob ID (faceting; not yet supported for candlestick)
panel_idPanel id (patchwork; accepted for signature parity)
panel_ctxPanel context (faceting; not yet supported)
Returns
Maidr candlestick layer list
Ggplot2CandlestickProcessor$extract_data()
Extract OHLC data points from the plot
Usage
Ggplot2CandlestickProcessor$extract_data(plot, built = NULL)
Arguments
plotggplot2 object
builtBuilt plot data
Returns
List of CandlestickPoint dicts
Ggplot2CandlestickProcessor$generate_selectors()
Generate candlestick CSS selectors
Returns a single CandlestickSelector object with body and wick
as single CSS group selectors (one per element kind, not per candle).
The maidr JS layer uses these to grab all candle elements at once and
then auto-derives open/close from body rect edges based on trend.
Usage
Ggplot2CandlestickProcessor$generate_selectors( plot, gt = NULL, grob_id = NULL, panel_ctx = NULL )
Arguments
plotggplot2 object
gtGtable object
grob_idGrob ID (faceting)
panel_ctxPanel context (faceting)
Returns
Named list with body and (optionally) wick single-string
selectors, or empty list if grobs cannot be located.
Ggplot2CandlestickProcessor$extract_layer_axes()
Extract axes labels for candlestick layer
Candlestick layer mappings are typically NULL (top-level mapping
carries x/open/high/low/close). The base implementation only inspects
layer_mapping$x and layer_mapping$y, which yields blank labels.
Here we additionally fall back to plot$mapping$x and synthesize a
"Price" y-label since OHLC has no single y mapping.
Usage
Ggplot2CandlestickProcessor$extract_layer_axes(plot, layout)
Arguments
plotggplot2 object
layoutLayout information
Returns
list(x = list(label = ...), y = list(label = ...))
Ggplot2CandlestickProcessor$resolve_col()
Resolve a mapping quosure to a column name in data
Usage
Ggplot2CandlestickProcessor$resolve_col(mapping_expr, data)
Arguments
mapping_exprA mapping quosure
dataThe data frame to resolve the column in
Returns
The column name, or NULL when the mapping names no column of data
Ggplot2CandlestickProcessor$format_x_value()
Format an x-axis value as character
Usage
Ggplot2CandlestickProcessor$format_x_value(x)
Arguments
xThe value to format
Returns
Character vector
Ggplot2CandlestickProcessor$get_effective_mapping()
Get the effective mapping (layer mapping merged on top)
Usage
Ggplot2CandlestickProcessor$get_effective_mapping(plot)
Arguments
plotThe ggplot2 object
Ggplot2CandlestickProcessor$get_original_data()
Get original data for the layer (falls back to plot$data)
Usage
Ggplot2CandlestickProcessor$get_original_data(plot)
Arguments
plotThe ggplot2 object
Ggplot2CandlestickProcessor$count_candles()
Count candles from the original data
Usage
Ggplot2CandlestickProcessor$count_candles(plot)
Arguments
plotThe ggplot2 object
Returns
Integer, 0 when there is no data
Ggplot2CandlestickProcessor$find_panel_grob()
Find the panel grob this layer draws into
Usage
Ggplot2CandlestickProcessor$find_panel_grob(gt, panel_ctx = NULL)
Arguments
gtGtable object
panel_ctxPanel context for patchwork leaves and facets; NULL for a single plot, where the panel is the cell literally named "panel"
Returns
The panel gTree, or NULL when it cannot be resolved
Ggplot2CandlestickProcessor$find_first_child_name()
Find the first descendant whose name matches pattern
Usage
Ggplot2CandlestickProcessor$find_first_child_name(grob, pattern)
Arguments
grobThe grob tree to search
patternRegular expression the grob name must match
Returns
The matching grob name, or NULL
Ggplot2CandlestickProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2CandlestickProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Contour Layer Processor
Description
Processes contour layers (geom_contour, geom_density_2d).
A contour is the one chart of its family whose value is a number rather
than a colour: ggplot2 computes level per row, so both halves of the
reading invert exactly and nothing is recovered from a fill. That is what
separates it from the same chart in a renderer that keeps its magnitude
only in a continuous colour, which is why xability/maidr#1084 left
Observable Plot's contour unread.
The filled forms are not this chart. geom_contour_filled() and
geom_density_2d_filled() draw the bands between levels, and say so in
the frame: their level is a factor of intervals rather than a number.
Announcing one of those outlines as a level's own curve would be right for
half of its points.
Super class
LayerProcessor -> Ggplot2ContourLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_data()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2ContourLayerProcessor$process()
Process the contour layer
Usage
Ggplot2ContourLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for patchwork leaves and facets
Returns
List with data, selectors and axes
Ggplot2ContourLayerProcessor$extract_axes()
Name the two axes
Only x and y. The level is not an axis here: it travels on every point of the curve it belongs to, and the frontend's contour trace announces it from there under its own heading rather than from a third axis label.
Usage
Ggplot2ContourLayerProcessor$extract_axes(plot, built = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
Returns
An axes payload with x and y
Ggplot2ContourLayerProcessor$generate_selectors()
Address each drawn curve by its own element
GeomContour draws every curve in one polylineGrob, and gridSVG
exports that as one <polyline> per piece with an id of the form
<grob>.1.<n> – measured, a two-level field with two peaks gives
GRID.polyline.1.1.1 through .4. So a curve is addressed by its
position among the pieces, which is what contour_curves() returns.
The grob carries grid's automatic name rather than one derived from
the geom, so it is found the way a line layer's is – by position
among the auto-named polylines of the panel. That is the whole reason
polyline_layer_position() had to learn about this type: a contour
drawn beside a geom_line() sits in the same candidate list, and a
count that skipped it would give both layers the other's curves.
Usage
Ggplot2ContourLayerProcessor$generate_selectors( gt = NULL, plot = NULL, panel_ctx = NULL, order = integer(0) )
Arguments
gtGtable object
plotThe ggplot2 object, used to build a gtable when none is given
panel_ctxPanel context for patchwork leaves and facets
orderThe piece behind each emitted curve
Returns
A list of CSS selectors, one per curve
Ggplot2ContourLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2ContourLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Dodged Bar Layer Processor
Description
Processes dodged bar plot layers with complete logic included
Super class
LayerProcessor -> Ggplot2DodgedBarLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2DodgedBarLayerProcessor$process()
Process the layer: read its series, selectors and DOM mapping from the built plot
Usage
Ggplot2DodgedBarLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List describing the layer for the MAIDR payload
Ggplot2DodgedBarLayerProcessor$needs_reordering()
Whether the plot data must be reordered before drawing, so the emitted order matches the drawn rects
Usage
Ggplot2DodgedBarLayerProcessor$needs_reordering()
Returns
TRUE
Ggplot2DodgedBarLayerProcessor$resolve_aes_values()
Resolve this layer's x/y/fill aesthetics to VALUES.
rlang::as_label() produces a display string, which doubles as a
column name only for bare-column mappings. Evaluating the quosure
against the data also covers expression aesthetics such as
aes(fill = factor(cyl)), which are idiomatic ggplot2 and which
the column-name treatment turned into data[["factor(cyl)"]],
i.e. NULL.
Usage
Ggplot2DodgedBarLayerProcessor$resolve_aes_values(plot, data)
Arguments
plotA ggplot2 object
dataData frame the aesthetics are evaluated against
Returns
List with x, y and fill vectors (any may be NULL)
Ggplot2DodgedBarLayerProcessor$reorder_layer_data()
Reorder the plot data by x and fill so each column's rects are drawn in the order the frontend walks them
Usage
Ggplot2DodgedBarLayerProcessor$reorder_layer_data(data, plot)
Arguments
dataThe data frame ggplot2 will draw from
plotThe ggplot2 object
Returns
The reordered data frame
Ggplot2DodgedBarLayerProcessor$extract_data()
One series per fill level, as a rectangular grid with a 0 for every missing
bar
Usage
Ggplot2DodgedBarLayerProcessor$extract_data( plot, built = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List of series
Ggplot2DodgedBarLayerProcessor$generate_selectors()
One flat selector matching every rect in the layer, which is the contract the frontend expects (see the note above)
Usage
Ggplot2DodgedBarLayerProcessor$generate_selectors( plot, gt = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List holding one selector
Ggplot2DodgedBarLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2DodgedBarLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Dot Plot Layer Processor
Description
Processes Wilkinson dot plots (geom_dotplot).
The layer emits type hist, because that is the chart: a stack of
dots is a bar, and the bin and its count are what a reader navigates. The
y axis a dot plot draws is not one – ggplot2's own documentation says the
values on it are meaningless – so the count goes on it here.
Highlighting is not offered, and that is a real limit rather than an
oversight. GeomDotplot draws the whole chart as one
dotstackGrob, which gridSVG exports as one <circle> per
observation: a bin of three dots has three elements and no element of
its own, while the frontend's bar traces resolve exactly one element per
announced value. So the bins are announced, sonified and brailled, and
nothing lights up – which is the highlight-only blind spot
xability/maidr#814 names, and strictly better than the static image this
chart was before (#201). geom_histogram() draws the same
distribution with a rect per bin and highlights.
Super class
LayerProcessor -> Ggplot2DotplotLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$generate_selectors()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2DotplotLayerProcessor$process()
Process the dot plot layer
Usage
Ggplot2DotplotLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for patchwork leaves and facets
Returns
List with type, data, orientation, selectors and axes
Ggplot2DotplotLayerProcessor$bins_run_up_the_y_axis()
Which axis the values were binned along
Read from the layer's own binaxis parameter, which is what
decides it: geom_dotplot(binaxis = "y") is the form drawn
beside a categorical x, and its bins run up the y axis. Defaulted to
"x" to match ggplot2's own default rather than guessed at from
the data.
Usage
Ggplot2DotplotLayerProcessor$bins_run_up_the_y_axis(plot)
Arguments
plotThe ggplot2 object
Returns
TRUE when the bins run up the y axis
Ggplot2DotplotLayerProcessor$extract_data()
Read the bins out of the built data
Emitted in the shape Ggplot2HistogramLayerProcessor emits, so
the frontend's histogram trace reads it unchanged: the bin's centre
and count as x/y, and the bin's own bounds as
xMin/xMax. A bar rises from zero, so yMin is 0
and yMax is the count.
Both are swapped for a layer binned up the y axis, matching what
orientation = "horz" tells the frontend to expect.
Usage
Ggplot2DotplotLayerProcessor$extract_data( plot, built = NULL, panel_id = NULL, horizontal = FALSE )
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
horizontalWhether the bins run up the y axis
Returns
A list of bins, ascending
Ggplot2DotplotLayerProcessor$extract_axes()
Name the two axes
The bin axis keeps the variable's name through the package's shared
labs()-then-mapping chain. The other one is named "count"
here rather than read from the plot: ggplot2 labels a dot plot's
count axis "count" while drawing values on it that its own
documentation calls meaningless, and reading that label back would
pair a real count with whatever the caller renamed the fiction to.
Usage
Ggplot2DotplotLayerProcessor$extract_axes( plot, built = NULL, horizontal = FALSE )
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
horizontalWhether the bins run up the y axis
Returns
An axes payload with x and y
Ggplot2DotplotLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2DotplotLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
ggplot2 Error Bar Layer Processor
Description
Processes ggplot2's uncertainty geoms – geom_errorbar(),
geom_errorbarh(), geom_linerange(), geom_pointrange() and
geom_crossbar() – into MAIDR's error_bar layer.
Uncertainty is usually the finding rather than the decoration: whether two
group means differ is answered by whether their intervals overlap. Until
this processor existed every one of these geoms fell through to
Ggplot2UnknownLayerProcessor, so the interval was dropped and that
comparison was unavailable to a MAIDR reader.
Reading the right pair of bounds
The trap this class exists to avoid is that ggplot2's built data carries
both pairs for most of these geoms, and only one of them is the
interval. A vertical geom_errorbar() computes:
x y ymin ymax xmin xmax flipped_aes 1 4.2 3.8 4.6 0.55 1.45 FALSE
ymin/ymax are the interval; xmin/xmax are the cap width – how
wide the little crossbars are drawn, which is a styling parameter and not
data at all. Reading the wrong pair yields a chart describing the cap
geometry, which is both wrong and plausible-looking.
Which pair is the interval is decided by the layer's orientation, and ggplot2 records that in two different ways depending on the geom:
-
geom_errorbar(orientation = "y")and friends set aflipped_aescolumn toTRUEin the built data. -
geom_errorbarh()has noflipped_aescolumn at all – it is horizontal by construction.
Both are handled, because a layer that read only flipped_aes would treat
every geom_errorbarh() as vertical and emit the cap heights as the
interval.
Super classes
LayerProcessor -> Ggplot2PointLayerProcessor -> Ggplot2ErrorbarLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()Ggplot2PointLayerProcessor$extract_axes_labels()Ggplot2PointLayerProcessor$extract_axis_grid_info()Ggplot2PointLayerProcessor$extract_data()Ggplot2PointLayerProcessor$find_children_by_type()Ggplot2PointLayerProcessor$find_panel_grob()
Ggplot2ErrorbarLayerProcessor$process()
Process the error bar layer.
Usage
Ggplot2ErrorbarLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selectors (optional)
Returns
List with data, selectors, axes, type and orientation
Ggplot2ErrorbarLayerProcessor$attach_group_axis()
Name the series axis after the legend the chart shows.
Guarded on the split rather than on the payload's shape, because
data_has_series_groups() reads data[[1]][[1]]$z and an ungrouped
layer's data[[1]] is a point, whose first element is an atomic
category name. The grouped shape is the only one that has a z axis to
name, so asking the split is both safer and the actual question.
Usage
Ggplot2ErrorbarLayerProcessor$attach_group_axis( plot, built, data, groups, panel_id = NULL )
Arguments
plotThe ggplot2 object
builtBuilt plot data
dataThe extracted layer data
groupsThe layer's series split, or NULL
panel_idPanel ID for faceted plots (optional)
Returns
The axes list, with z added when the layer is grouped
Ggplot2ErrorbarLayerProcessor$resolve_interval_groups()
Split the layer's rows into the series the chart draws.
A dodged interval chart puts one whip per group at every category, and
without the split every category is announced twice with nothing saying
which reading belongs to which group – so the comparison the figure
exists to support, whether two groups' intervals overlap, is the one
thing unavailable (#183). MAIDR's grammar gained the grouped shape,
ErrorBarPoint[][] with a z per point, in xability/maidr#942.
The group each row belongs to cannot be read out of the built data:
ggplot_build() replaces the grouping column with an integer group
id, and on a discrete x that id is the interaction of x and the
grouping aesthetic – 6 ids for 3 categories and 2 groups, measured –
so it names a cell rather than a series. The aesthetic's own values are
replaced too, by the palette colour they mapped to. The user's frame is
what still holds the names, and it is only usable while it still has a
row per built row: ggplot2 drops rows it cannot draw, and a padded
lookup would name every series NA. The same guard
Ggplot2StackedBarProcessor applies for the same reason.
A layer with its own data is read from that frame rather than the
plot's, matching ggplot2's own precedence.
Usage
Ggplot2ErrorbarLayerProcessor$resolve_interval_groups( plot, layer_data, built, panel_id = NULL )
Arguments
plotThe ggplot2 object
layer_dataThis layer's computed rows
builtBuilt plot data
panel_idPanel ID for faceted plots (optional)
Returns
A list of positions (each row's series, as an index into
levels), levels (the series, in the order ggplot2 draws them) and
order (the row indices in series order), or NULL when the layer
draws a single undivided series
Ggplot2ErrorbarLayerProcessor$group_values_agree()
Check the frame's values against what the layer drew.
Row counts agreeing is not the same as rows corresponding. A stat that happens to emit as many rows as the frame has would pass the count test while pairing a reading with somebody else's group name – the worst failure available here, since every value stays correct and only the label is a lie.
What can be checked is that the pairing is consistent: ggplot2 keeps
the grouping aesthetic in the built data as the value it mapped to (a
palette colour, a linetype), and a correct pairing gives every row
sharing that drawn value the same name. A shuffled one almost never
does. Falls back to the built group id when the aesthetic itself is
not in the built data, which is what an explicit aes(group = ...)
leaves behind.
Usage
Ggplot2ErrorbarLayerProcessor$group_values_agree(layer_data, aes_names, values)
Arguments
layer_dataThis layer's computed rows
aes_namesThe winning aesthetic's spelling variants
valuesThe frame's grouping values, one per row
Returns
TRUE when every drawn value carries a single name
Ggplot2ErrorbarLayerProcessor$layer_built_rows()
This layer's built rows, every panel of them.
Usage
Ggplot2ErrorbarLayerProcessor$layer_built_rows(built)
Arguments
builtBuilt plot data
Returns
A data frame, or NULL when the layer index does not resolve
Ggplot2ErrorbarLayerProcessor$panel_row_indices()
Which of the layer's built rows this panel's rows are.
Mirrors get_layer_built_data(), including its fallback: a panel id
that selects nothing leaves the whole layer in place, so the indices
have to as well. Answers NULL when the two do not line up, which is
the signal to decline the split rather than pair rows at random.
Usage
Ggplot2ErrorbarLayerProcessor$panel_row_indices(full, rows, panel_id = NULL)
Arguments
fullThe layer's built rows, every panel of them
rowsHow many rows this panel contributed
panel_idPanel ID for faceted plots (optional)
Returns
Integer indices into full, or NULL
Ggplot2ErrorbarLayerProcessor$interval_group_frame()
The frame still carrying the grouping column's own values.
Usage
Ggplot2ErrorbarLayerProcessor$interval_group_frame(plot, rows)
Arguments
plotThe ggplot2 object
rowsHow many rows the layer computed
Returns
A data frame with one row per built row, or NULL
Ggplot2ErrorbarLayerProcessor$is_horizontal_layer()
Decide whether the interval runs along x rather than y.
Reads flipped_aes when the built data carries it, and falls back to
the geom class for geom_errorbarh(), which is horizontal by
construction and therefore has no such column to read.
Usage
Ggplot2ErrorbarLayerProcessor$is_horizontal_layer(plot, layer_data)
Arguments
plotThe ggplot2 object
layer_dataThis layer's computed rows
Returns
TRUE when the interval spans the x axis
Ggplot2ErrorbarLayerProcessor$draws_one_shape_for_every_sample()
Whether this layer draws its whole interval as one shape.
True for a ribbon, which fills a single polygon across every x. Every
other geom this processor serves draws one shape per sample – a
segments grob per geom_linerange() row, a polygon per
geom_crossbar() box – which is what makes a per-sample selector
possible at all.
class(...)[1], matching the adapter's own ribbon test: GeomArea
inherits GeomRibbon and is not routed here, but an inherits() check
would still be the wrong shape of question to ask.
Usage
Ggplot2ErrorbarLayerProcessor$draws_one_shape_for_every_sample(plot)
Arguments
plotThe ggplot2 object
Returns
TRUE when the layer's interval is one undivided shape
Ggplot2ErrorbarLayerProcessor$generate_selectors()
Address the drawn interval, one SVG element per sample.
ErrorBarTrace.mapToSvgElements resolves the selectors and requires
the flattened result to be exactly as long as the emitted data; any
other length is discarded and the layer highlights nothing (#145). So
the job here is one element per sample, in the order the data was
emitted – not one per bound, and not the container.
The five geoms do not draw alike, and the differences are not
cosmetic. Verified against real gridSVG::grid.export() output on
ggplot2 3.4.4:
-
geom_linerange()– asegmentsgrob named after the geom; one<polyline>per sample. -
geom_pointrange()– a gTree holding that samesegmentsgrob and apointsgrob. The whisker is the one that spans the interval, so it is the one addressed. -
geom_crossbar()– a gTree holding apolygongrob (the box) and asegmentsgrob (the middle line). The box is the sample. -
geom_errorbar()/geom_errorbarh()– an unnamedpolyline,GRID.polyline.N, carrying no geom prefix at all, and drawing three elements per sample: a cap, the whisker, the other cap.
Both of those last two facts are why this could not reuse the
inherited generate_selectors(): it matches geom_point.points by
name, which reaches none of these, and a name-prefix search reaches
geom_errorbar() least of all.
Usage
Ggplot2ErrorbarLayerProcessor$generate_selectors( plot, gt = NULL, grob_id = NULL, panel_ctx = NULL, sample_count = NULL, order = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
grob_idGrob ID for faceted plots (unused; the drawn grob is resolved from the panel, which is what the unnamed polyline needs)
panel_ctxPanel context for panel-scoped selectors (optional) A grouped layer needs one selector per sample instead of one stride over all of them, because MAIDR flattens its series before pairing them against the resolved elements: the payload runs series by series while the chart draws row by row, and one stride can only ever produce the drawn order. The per-sample form addresses each mark by the id gridSVG gave it, not by position, so resolving one cannot disturb the rest – a positional list would, since resolving a selector inserts a hidden clone beside the match and shifts every later
nth-child(xability/maidr#1004).sample_countHow many points this layer emitted
orderThe row indices in series order, or NULL when the layer draws a single undivided series
Returns
A list of CSS selectors, or an empty list
Ggplot2ErrorbarLayerProcessor$interval_sample_selectors()
Address one drawn mark per sample, in series order.
gridSVG gives every exported element its own id, built from the grob's
name: <grob>.1.<i> where a sample is drawn as one element, and
<grob>.1.<i>a, <i>b, <i>c where geom_errorbar() draws its cap,
whisker and other cap. Measured on ggplot2 3.4.4 across all four
geoms this processor serves. The whisker is the middle one, which is
the same element the stride form's nth-child(3n+2) picks – so a
grouped chart and an ungrouped one outline the same mark.
Restricted to the two shapes interval_selector() handles, for the
same reason: an unverified element count would name a mark by an id
pattern nothing has been checked against.
Usage
Ggplot2ErrorbarLayerProcessor$interval_sample_selectors( grob_name, per_sample, order )
Arguments
grob_nameName of the grob whose children are the samples
per_sampleHow many elements the grob draws per sample
orderThe row indices in series order
Returns
A list of CSS selectors, one per sample, or an empty list
Ggplot2ErrorbarLayerProcessor$find_interval_grob()
Find the grob whose children are the samples.
Usage
Ggplot2ErrorbarLayerProcessor$find_interval_grob(plot, gt, panel_ctx = NULL)
Arguments
plotThe ggplot2 object
gtGtable object
panel_ctxPanel context for panel-scoped selectors (optional)
Returns
The grob one of whose child elements is drawn per sample, or NULL when it cannot be resolved
Ggplot2ErrorbarLayerProcessor$find_unnamed_interval_grob()
Resolve the drawn grob of a layer ggplot2 left unnamed.
geom_errorbar() and geom_errorbarh() draw a bare
GRID.polyline.N, so there is no name to match on and
find_layer_grob_tree() returns NULL for them. Position is the
remaining handle: ggplot2 lays a panel out as the grill, a leading
zeroGrob, one child per layer in layer order, a trailing
zeroGrob and the border. A layer that draws nothing still takes its
slot as a zeroGrob, so the correspondence survives an empty layer
beside this one.
The leading blank is found by class rather than by an absent name: a
zeroGrob is named, and its name is the four characters "NULL".
It is deliberately narrow. The result has to be a polyline for a
geom that is known to draw one, because a positional hit on the wrong
layer would highlight another layer's marks – worse than the missing
highlight this fixes, since a reader can hear nothing but cannot hear
wrongness.
Usage
Ggplot2ErrorbarLayerProcessor$find_unnamed_interval_grob( plot, gt, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
gtGtable object
panel_ctxPanel context for panel-scoped selectors (optional)
Returns
The layer's polyline grob, or NULL
Ggplot2ErrorbarLayerProcessor$interval_grob_shape()
Count the samples a grob draws, and the elements each takes.
Usage
Ggplot2ErrorbarLayerProcessor$interval_grob_shape(grob)
Arguments
grobThe grob resolved for this layer
Returns
A list of samples and per_sample, or NULL when the grob is
not one of the shapes this has been verified against
Ggplot2ErrorbarLayerProcessor$grob_point_groups()
Split a grob's points into one index vector per sample.
Usage
Ggplot2ErrorbarLayerProcessor$grob_point_groups(grob)
Arguments
grobA
polygonorpolylinegrob
Returns
A list of index vectors in drawing order, or NULL
Ggplot2ErrorbarLayerProcessor$drawn_run_count()
Count the elements one sample of a grob is drawn as.
grid breaks a polyline at a missing point, and geom_errorbar() uses
that: its eight points per sample are cap, NA, whisker, NA, cap, so
the export carries three elements for the one bar. A run needs two
points to be a line at all, and a shorter one draws nothing.
Usage
Ggplot2ErrorbarLayerProcessor$drawn_run_count(grob, index)
Arguments
grobA
polygonorpolylinegrobindexThe point indices belonging to one sample
Returns
How many elements that sample is drawn as
Ggplot2ErrorbarLayerProcessor$interval_selector()
Build the CSS selector for one element per sample.
gridSVG wraps each grob in a <g> named after it with a .1 suffix
and writes its elements inside in drawing order, so the samples are
addressable as a stride through that group's children.
Only the two strides that have been checked against an export are
emitted: one element per sample, and the three a geom_errorbar()
draws, of which the middle one is the whisker spanning the interval –
the cap either side of it says nothing a reader is navigating to. Any
other stride returns NULL and the layer goes back to highlighting
nothing, which is the honest answer for a shape nobody has looked at.
Usage
Ggplot2ErrorbarLayerProcessor$interval_selector(grob_name, per_sample)
Arguments
grob_nameThe drawn grob's name
per_sampleHow many elements each sample is drawn as
Returns
A CSS selector, or NULL
Ggplot2ErrorbarLayerProcessor$extract_interval_data()
Build the MAIDR points for this layer.
The emitted shape names the category x and the magnitude y in both
orientations, with the bounds in yMin/yMax, and lets orientation
say which is on screen where. That is the shape MAIDR's ErrorBarTrace
consumes: it reads the magnitude as y/yMin/yMax with no
orientation branch, so emitting screen-aligned keys would leave a
horizontal chart with no interval at all.
A row missing its bounds still emits its estimate. A one-sided interval is a real chart, and dropping the point for want of its other half would lose the estimate too.
A grouped layer emits one series per group instead, each point
carrying its group's name as z – the shape every other grouped
layer in this package already emits, and the one MAIDR's ErrorBarTrace
reads as a series of series.
Usage
Ggplot2ErrorbarLayerProcessor$extract_interval_data( built, layer_data, is_horizontal, panel_id = NULL, groups = NULL )
Arguments
builtBuilt plot data
layer_dataThis layer's computed rows
is_horizontalWhether the interval spans the x axis
panel_idPanel ID for faceted plots (optional)
groupsThe layer's series split, or NULL for a single series
Returns
A list of MAIDR interval points, or a list of such lists when the layer is grouped
Ggplot2ErrorbarLayerProcessor$resolve_estimates()
Resolve the estimate each interval is centred on.
The estimate aesthetic is optional on these geoms, and leaving it
out is idiomatic rather than exotic:
geom_errorbar(aes(x, ymin, ymax)) layered over a geom_col() is the
standard way to draw a bar chart with error bars, and it builds with no
y column at all. geom_linerange() is the same. Requiring the column
dropped every such layer silently – no interval, no estimate, no error.
When it is absent the chart genuinely draws no estimate, only a span, so
the centre of that span is used. That is a property of the drawn bar
rather than a claim about an unobserved estimate, and it is what keeps
the bounds – which are the real data here – reachable at all. It is
NOT the mean for an asymmetric interval, and nothing here pretends it
is: a layer that carries y always uses the value the chart drew.
Usage
Ggplot2ErrorbarLayerProcessor$resolve_estimates( layer_data, value_col, min_col, max_col )
Arguments
layer_dataThis layer's computed rows
value_colThe estimate column for this orientation
min_colThe lower bound column for this orientation
max_colThe upper bound column for this orientation
Returns
A numeric vector of estimates, or NULL when neither the estimate nor a pair of bounds is present
Ggplot2ErrorbarLayerProcessor$resolve_category_labels()
Recover the names behind a discrete category axis.
ggplot2 maps a discrete axis onto integer positions before it computes
the layer, so the built data carries 1, 2, 3 where the chart draws
control, high dose, low dose. Announcing the positions would name
something the reader cannot find anywhere on the chart – and the
positions are assigned in the scale's order, not the data's, so they do
not even read as row numbers.
The labels come from the panel's scale rather than from the data frame, which is what makes the position an index into them.
Usage
Ggplot2ErrorbarLayerProcessor$resolve_category_labels( built, layer_data, category_col, panel_id = NULL )
Arguments
builtBuilt plot data
layer_dataThis layer's computed rows
category_colWhich built column carries the category
panel_idPanel ID for faceted plots (optional)
Returns
A list of labels – strings for a discrete axis, numbers for a continuous one
Ggplot2ErrorbarLayerProcessor$category_axis_labels()
Read the break labels of the category axis, when discrete.
Usage
Ggplot2ErrorbarLayerProcessor$category_axis_labels( built, category_col, panel_id = NULL )
Arguments
builtBuilt plot data
category_colWhich built column carries the category
panel_idPanel ID for faceted plots (optional)
Returns
A character vector of labels, or NULL on a continuous axis
Ggplot2ErrorbarLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2ErrorbarLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Gantt Layer Processor
Description
Processes geom_segment() layers that draw intervals in lanes, and
maidr_gantt() layers whose author declared that their rectangles do.
A segment with the two ends of a span on one axis and a lane on the other
is how ggplot2 draws a schedule, a range plot and a high-low chart.
ggplot_build computes both ends and the lane exactly, so nothing is
inverted from a pixel: the four columns x, xend, y and
yend are the interval and the lane the caller wrote.
geom_curve() computes the same four columns and reads the same way.
Its vectorised curve grob is split into one curve per row by
split_vectorised_curve_grobs() before export (#195), which is what
the per-interval selectors address. See the adapter's own note.
A declared rectangle layer has none of those four columns – it builds
xmin, xmax, ymin and ymax – so
rect_gantt_frame() renames its bounds into them before anything
here runs. That is the whole of the rect path: the lanes, the ordering,
the orientation and the axes are then this class answering one question
rather than two implementations of it, and the processed layer comes back
identical() to the geom_segment() spelling of the same
schedule in everything but the grob its selectors name. Only the lane
names need their own route, because a rectangle layer's lane axis is
continuous and lane_names() reads levels off a discrete one.
Super class
LayerProcessor -> Ggplot2GanttLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_data()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2GanttLayerProcessor$process()
Process the gantt layer
Usage
Ggplot2GanttLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for patchwork leaves and facets
Returns
List with data, selectors, axes and orientation
Ggplot2GanttLayerProcessor$lane_names()
Name the lanes, in the order the scale lays them out
Read off the panel's own view of the scale rather than off the
source column: the built data records a discrete lane as the position
ggplot2 gave it (1, 2, 3), and the panel's limits are the levels in
the same order, so the two line up by index. That is also what makes
an undrawn level visible – scale_y_discrete(drop = FALSE) keeps it
in the limits, and it is a lane holding nothing.
NULL for a continuous lane axis, which has no names to give.
Usage
Ggplot2GanttLayerProcessor$lane_names(built, lane_axis, panel_id = NULL)
Arguments
builtBuilt plot data
lane_axis"y", "x", or NULL
panel_idPanel ID for faceted plots (optional)
Returns
Character vector of lane names, or NULL
Ggplot2GanttLayerProcessor$declared_lane_axis()
Which axis this layer's author said the lanes run up
Read off the layer rather than inferred, because inference is not
available: measured, both axes partition for the target schedule and
for one whose tasks all take the same time, so structure can neither
confirm nor contradict what the author meant. "y" when nothing
was declared, which is what a geom_segment() gantt drawn the
ordinary way also reads as.
Usage
Ggplot2GanttLayerProcessor$declared_lane_axis(plot)
Arguments
plotThe ggplot2 object
Returns
"y" or "x"
Ggplot2GanttLayerProcessor$name_rect_lanes()
Name a rectangle gantt's lanes from the ticks inside them
lane_names() above cannot serve, and the reason is measured:
it requires view$is_discrete(), and a rectangle layer written
with the author's own numeric ymin/ymax trains a
continuous scale – measured, is_discrete() is FALSE and
limits is the range 0.6, 3.4 rather than a list of
levels. The lanes are there; the scale just has no names to lend them.
So a lane is named by the single explicit tick drawn inside it, and by its position otherwise – the rule xability/py-maidr#533 settled. Two guards come with it and both are that issue's: a band holding more than one tick is named by none of them, and a band holding none is named by its position.
Read off built$layout$panel_params, never
layer_scales(): measured on the default scale the panel's
view gives breaks NA, 1, 2, 3, NA while layer_scales()
gives NA, 1, 1.5, 2, 2.5, 3, NA – two ticks per band, which
defeats the one-tick rule in exactly the case the rule exists for.
The NA padding is dropped.
Usage
Ggplot2GanttLayerProcessor$name_rect_lanes( grouped, built, built_data, lane_axis, panel_id = NULL )
Arguments
groupedThe lanes as
segment_lanes()grouped thembuiltBuilt plot data
built_dataThe normalised frame, carrying the bounds and the lane
lane_axis"y", "x", or NULL
panel_idPanel ID for faceted plots (optional)
Returns
grouped with its named lanes renamed
Ggplot2GanttLayerProcessor$lane_ticks()
The lane axis's drawn ticks, with the padding dropped
panel_params is keyed by the axis the chart draws, not the
axis the data lives on, and coord_flip() swaps the two. So the
panel is asked for the drawn counterpart of lane_axis rather
than for lane_axis itself.
Indexing by lane_axis reads the span axis under a flip, and
the wrong answer is worth writing down because it is two different
wrong answers. Measured on ggplot2 3.4.4, the example schedule with
coord_flip() added: with the time axis given its own named
breaks the lanes came back Jan, Feb, Mar – names the chart
draws along the other axis – and with the ordinary numeric time
breaks 0, 5, 10, 15 every label failed
label_names_its_lane() and the lanes silently lost their names
altogether, on a chart drawing design, build, test. Both are
pinned in tests/testthat/test-gantt-rect.R.
The breaks travel with the labels, so they stay comparable with the
bands: measured under the flip, panel_params[[1]]$x gives
breaks 1, 2, 3 against bands 0.6-1.4, 1.6-2.4
and 2.6-3.4, which are data-space ymin/ymax.
class()[1] is "CoordFlip" here – measured – but the
test is inherits(), because it is asking whether the coord
flips rather than which coord it is.
lane_names() above indexes by lane_axis too and is
deliberately left alone: it requires view$is_discrete(), a
rectangle layer's numeric bounds always train a continuous lane axis,
and so it cannot reach a rect gantt at all. Measured, the
geom_segment() spelling of the same flipped chart comes back
with no lanes rather than with borrowed ones, which is the
reading it has today and not this issue's to change.
Usage
Ggplot2GanttLayerProcessor$lane_ticks(built, lane_axis, panel_id = NULL)
Arguments
builtBuilt plot data
lane_axis"y", "x", or NULL
panel_idPanel ID for faceted plots (optional)
Returns
A list of breaks and labels, or NULL
Ggplot2GanttLayerProcessor$extract_axes()
Name the two axes
Usage
Ggplot2GanttLayerProcessor$extract_axes(plot, built = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
Returns
An axes payload with x and y
Ggplot2GanttLayerProcessor$generate_selectors()
Address each drawn interval by its own element
GeomSegment draws every interval in one segmentsGrob,
and gridSVG exports that as one element per segment carrying an id of
the form <grob>.1.<n> – measured, a four-interval chart gives
GRID.segments.38.1.1 through .4, in built-data order.
So an interval is addressed by the built row it came from, and the
list follows the regrouping rather than the document.
Flat rather than nested, because the frontend slices it per lane using the lane lengths it already has – and withdraws highlighting outright unless the resolved count matches the interval count exactly. A partial list is therefore worse than none, so an empty list is returned when the grob cannot be found rather than a guess at its name.
Usage
Ggplot2GanttLayerProcessor$generate_selectors( gt = NULL, plot = NULL, panel_ctx = NULL, order = integer(0) )
Arguments
gtGtable object
plotThe ggplot2 object, used to build a gtable when none is given
panel_ctxPanel context for patchwork leaves and facets
orderThe built-data row behind each interval, in emission order
Returns
A list of CSS selectors, one per interval
Ggplot2GanttLayerProcessor$target_geom_class()
The class of the geom this layer was drawn with
Both the grob to look for and the shape of its exported element ids follow from it, so it is asked once and answered from the plot rather than inferred from what happens to be in the panel.
Usage
Ggplot2GanttLayerProcessor$target_geom_class(plot)
Arguments
plotThe ggplot2 object
Returns
The geom's class name, or NULL when the layer cannot be found
Ggplot2GanttLayerProcessor$segments_grob_class()
Which grid grob class a segment-family geom draws
Usage
Ggplot2GanttLayerProcessor$segments_grob_class(geom)
Arguments
geomThe layer's geom object
Details
geom_curve() draws a curve grob and everything else in
the family – geom_segment(), and geom_spoke() which is
a GeomSegment subclass – draws segments. Asked of the
geom rather than assumed from the layer type, because it decides both
which grobs find_segments_name() gathers and which layers it
counts itself among, and those two have to be the same population.
Returns
"curve" or "segments"
Ggplot2GanttLayerProcessor$find_segments_name()
Find the name of the grob holding this layer's segments
The base class's find_layer_grob_tree() cannot serve here, and
the reason is worth recording: it matches a grob whose name begins
with the geom's own prefix, and ggplot2 does not give a segment layer
one. The grob arrives with grid's automatic name – measured,
GRID.segments.38 – so there is no geom_segment. to
match and the lookup returns NULL, which is a layer that announces
every interval and highlights none of them.
The disambiguation rule is the same one that helper applies, keyed on
the grob's class instead: the nth segment layer of the plot draws
the nth segments grob of the panel. Two geom_segment() layers
would otherwise both resolve to the first one's elements, and the
second would highlight the first's intervals while announcing its own.
The number in that automatic name is grid's global counter and is not stable between sessions, which is exactly why it is read off the gtable being exported rather than reconstructed.
Usage
Ggplot2GanttLayerProcessor$find_segments_name(plot, gt, panel_ctx = NULL)
Arguments
plotThe ggplot2 object
gtGtable object
panel_ctxPanel context for patchwork leaves and facets
Returns
The grob name, or NULL when it cannot be resolved
Ggplot2GanttLayerProcessor$find_rect_name()
Find the name of the grob holding a rect layer's bars
The opposite way round from find_segments_name(), and for a
measured reason: a rectangle layer is given a geom-prefixed grob
name, and the grob class is useless because the theme draws rects
too. Collecting every rect-class grob of a lone rect chart
gave, in tree order,
plot.background..rect.33 panel.background..rect.6 geom_rect.rect.2
so position 1 is the plot background and the reader would have the
whole page highlighted for their first task. The name prefix
^geom_rect\. matches the drawn bars and none of the theme's
rects.
Every number in a grob name here is grid's global counter, which
find_segments_name() above already records as not stable
between sessions – the same chart measured second in a session
numbers higher. What was measured is the tree order and the rect
counts; each listing below is from its own fresh session.
The counter is the other half. ggplot2 names a drawn grob after the
geom whose draw_panel() made it, and GeomRect$
draw_panel() hard-codes geom_rect, so geom_tile(),
geom_bar() and geom_col() all emit
geom_rect.rect.* grobs while geom_grob_prefix() calls
them geom_tile/geom_bar/geom_col. Measured,
geom_col(5 bars) + geom_rect(4 rects) draws two of them –
geom_rect.rect.2 holding the 5 bars and
geom_rect.rect.4 holding the 4 bands – and the base class's
find_layer_grob_tree() hands the rect layer the first, the
column chart's bars. Counting the target among
inherits(geom, "GeomRect") layers makes the counted
population the drawn population and resolves it to the second;
measured the same for geom_tile(9) + geom_rect(4), which
draws 9 then 4 under the same two names.
inherits() rather than a written-out list of class names, so
that a rect subclass this package has never heard of is counted as
what it draws. Measured, GeomTile, GeomBar and
GeomCol all inherit GeomRect; GeomRaster does
not, and draws GRID.rastergrob.* rather than a rect, so the
two populations agree on it as well. GeomRectCS, the
candlestick body, inherits it too – measured against tidyquant
1.0.12, where inherits(GeomRectCS, "GeomRect") is TRUE and
class(GeomRectCS)[1] is "GeomRectCS".
Scoped to this lookup. The same miscount reaches any bar, heat or
candlestick layer sharing a panel with another rect-drawn geom
through find_layer_grob_tree(); that is a defect this change
did not introduce and does not widen.
Usage
Ggplot2GanttLayerProcessor$find_rect_name( plot, gt, panel_ctx = NULL, target = NULL )
Arguments
plotThe ggplot2 object
gtGtable object
panel_ctxPanel context for patchwork leaves and facets
targetThis layer's index among the plot's layers
Returns
The grob name, or NULL when it cannot be resolved
Ggplot2GanttLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2GanttLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Heatmap Layer Processor
Description
Processes heatmap layers (geom_tile) with generic data and grob reordering
Super class
LayerProcessor -> Ggplot2HeatmapLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2HeatmapLayerProcessor$process()
Process the layer: read its tiles, selectors and axis names from the built plot
Usage
Ggplot2HeatmapLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List describing the layer for the MAIDR payload
Ggplot2HeatmapLayerProcessor$needs_reordering()
Whether the plot data must be reordered before drawing, so the emitted order matches the drawn tiles
Usage
Ggplot2HeatmapLayerProcessor$needs_reordering()
Returns
TRUE
Ggplot2HeatmapLayerProcessor$binned_selector_grid()
One selector per drawn bin of a binned grid, NA for an empty one
ggplot2 draws the bins in the order the built data lists them, so the
k-th rect under the layer's group is the k-th built row; cells holds
that row number per cell, in the emitted row order.
Usage
Ggplot2HeatmapLayerProcessor$binned_selector_grid(selector, cells)
Arguments
selectorThe layer's
<group> > rectselectorcellsPer-row lists of built row numbers,
NAwhere no bin was drawn
Returns
A per-cell selector grid
Ggplot2HeatmapLayerProcessor$reorder_layer_data()
Reorder the plot data row-wise so the emitted cells match the drawn tiles
Usage
Ggplot2HeatmapLayerProcessor$reorder_layer_data(data, plot)
Arguments
dataThe data frame ggplot2 will draw from
plotThe ggplot2 object
Returns
The reordered data frame
Ggplot2HeatmapLayerProcessor$is_binned_layer()
Report whether this layer's grid was computed by a stat.
geom_bin_2d() is GeomTile + StatBin2d, so it arrives here
classified as a heatmap – correctly, since a rectangular bin grid
is one. What differs is where the grid comes from: a geom_tile()
heatmap is handed one in plot$data, and a binned one has its
computed for it.
Matched on the stat rather than on the presence of a count
column, because a tidy heatmap whose value column happens to be
named count is not a binned layer and must not take that path.
Reached through get_own_layer(), which already answers "is there
a layer at my index?" – a second bounds check here would be a
second place for the answer to change.
Usage
Ggplot2HeatmapLayerProcessor$is_binned_layer(plot)
Arguments
plotThe ggplot object
Returns
TRUE when the layer's stat computes a 2D bin grid
Ggplot2HeatmapLayerProcessor$extract_binned_data()
Read a computed 2D bin grid out of the built data.
The built data is the grid: one row per drawn tile, carrying the bin's count and its edges. Only the bins that hold something are present, so the full rectangle is rebuilt from the distinct positions and the empty cells left missing rather than scored zero – an empty bin genuinely counted nothing, but the frontend reads a zero as "no rect here" for highlighting, and every cell of a heatmap has one.
Axis labels are the bin's coordinate range, not its index: "a count of 4" means nothing without "between -2.2 and -1.1", and the range is what a sighted reader gets from the axis (#136).
Usage
Ggplot2HeatmapLayerProcessor$extract_binned_data(built_data)
Arguments
built_dataThis layer's computed data, already panel-filtered
Returns
The same shape extract_data returns for a tidy heatmap
Ggplot2HeatmapLayerProcessor$format_bin_edge()
Render one bin edge as a short, readable number.
Bin edges are floating point and print at full precision by default – "-1.1076174999999999 to 1.1076180000000001e-07" is an announcement nobody can hold in their head. Rounded to a few significant figures, and trimmed, so the label reads as a coordinate rather than as a machine number.
Usage
Ggplot2HeatmapLayerProcessor$format_bin_edge(value)
Arguments
valueA single numeric bin edge or centre
Returns
A length-1 character string
Ggplot2HeatmapLayerProcessor$bin_labels()
Label each bin by the range it covers.
xmin/xmax are computed alongside the count, so the range costs
nothing to report and is the only thing that makes the count
meaningful. Falls back to the bin centre when the edges are absent,
which is still a coordinate rather than an index.
Usage
Ggplot2HeatmapLayerProcessor$bin_labels(built_data, positions, axis)
Arguments
built_dataThis layer's computed data
positionsThe distinct bin centres, sorted
axis"x"or"y"
Returns
Character labels, one per position, in the same order
Ggplot2HeatmapLayerProcessor$extract_data()
One row per tile plus the fill label, read from the built plot
Usage
Ggplot2HeatmapLayerProcessor$extract_data(plot, built = NULL, panel_id = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
Returns
List
Ggplot2HeatmapLayerProcessor$generate_selectors()
Selectors for the tiles, scoped to the panel
Usage
Ggplot2HeatmapLayerProcessor$generate_selectors( plot, gt = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List of selectors
Ggplot2HeatmapLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2HeatmapLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Hexbin Layer Processor
Description
Processes hexagonal binning layers (geom_hex, stat_binhex).
A hexbin is the standard answer to an overplotted scatter: bin the points
into hexagons and encode the count as fill. Read as a lattice of counted
cells that is a heatmap, and the navigation, braille and pitch all
transfer – but the rows are staggered, so it is a layer type of its own
rather than a heatmap with different cells. See hexbin_lattice() for
what that costs.
Super class
LayerProcessor -> Ggplot2HexbinLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2HexbinLayerProcessor$process()
Process the hexbin layer
Usage
Ggplot2HexbinLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for patchwork leaves and facets
Returns
List with data, selectors and axes
Ggplot2HexbinLayerProcessor$extract_data()
Read the drawn lattice out of the built data
The built data is the lattice: one row per drawn hexagon, carrying its centre and its count. Nothing is reconstructed from the source columns, which are the raw observations and say nothing about where the stat placed the bins.
Usage
Ggplot2HexbinLayerProcessor$extract_data(plot, built = NULL, panel_id = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
Returns
The list hexbin_lattice() returns
Ggplot2HexbinLayerProcessor$extract_axes()
Name the three axes
The colour axis is the count of points that fell in the bin, which is
what stat_binhex() computes and what the fill encodes. Named
here rather than read from the legend title, which says "count" for
the default and would say after_stat(density) for a chart that
is still counting into the same cells.
x and y go through positional_axis_label(), which is the
package's shared "labs() override, then the layer's own
mapping, then the plot's" chain, falling back to the aesthetic name
rather than to nothing.
Usage
Ggplot2HexbinLayerProcessor$extract_axes(plot, built = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
Returns
An axes payload with x, y and z
Ggplot2HexbinLayerProcessor$generate_selectors()
Address each drawn hexagon by its own element
gridSVG exports the layer's single multi-polygon grob as one
<polygon> per hexagon, in built-data order, each carrying an id
of the form <grob>.1.<n>. So a bin is addressed by the built
row it came from, and the emitted list follows the regrouping rather
than the document.
The frontend withdraws highlighting outright unless the resolved element count matches the bin count exactly, so a partial list is worse than none – an empty list is returned when the grob cannot be found rather than a guess at its name.
Usage
Ggplot2HexbinLayerProcessor$generate_selectors( gt = NULL, plot = NULL, panel_ctx = NULL, order = integer(0) )
Arguments
gtGtable object
plotThe ggplot2 object, used to build a gtable when none is given
panel_ctxPanel context for patchwork leaves and facets
orderThe built-data row behind each bin, in emission order
Returns
A list of CSS selectors, one per bin
Ggplot2HexbinLayerProcessor$find_hex_polygon_name()
Find the name of the grob holding the hexagons
GeomHex draws every hexagon in one polygonGrob, so there
is a single name to find rather than one per bin. Searched depth-first
because the layer's grobs sit inside a gTree of their own – and the
caller passes that tree rather than the panel, so a first match is
this layer's rather than some other hexbin's.
Usage
Ggplot2HexbinLayerProcessor$find_hex_polygon_name(grob)
Arguments
grobThe layer's grob tree to search
Returns
The grob name, or NULL when the layer drew nothing
Ggplot2HexbinLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2HexbinLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Histogram Layer Processor
Description
Processes histogram plot layers with complete logic included
Super class
LayerProcessor -> Ggplot2HistogramLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2HistogramLayerProcessor$process()
Process the layer: read its bins, selectors and orientation from the built plot
Usage
Ggplot2HistogramLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List describing the layer for the MAIDR payload
Ggplot2HistogramLayerProcessor$determine_orientation()
Which axis this histogram's bins run along
ggplot_build() fills a flipped layer's ymin/ymax with the bin
bounds and its x with the count, and extract_data above passes both
through as they come – so the emitted data is already transposed
correctly. What was missing is this key saying so.
Without it the frontend defaults to vertical and reads the bin range
from xMin/xMax, which on a flipped layer hold the count bounds. A
geom_histogram() drawn with aes(y = v) was announced with a bin
range of "0 to 5" – counts – where the data runs -2.42 to -1.10, and
with every bin centre offered as a value. Every number real, every one
on the wrong axis, and nothing erroring (#163).
Read from flipped_aes, which ggplot2 sets on the built layer, the way
the boxplot and violin processors already do. coord_flip() is a
different question and deliberately not answered here: it leaves
flipped_aes alone and rotates only the coordinate system, so the data
layout this key describes is genuinely unflipped. Treating it as
horizontal would swap a pair that is already the right way round.
Usage
Ggplot2HistogramLayerProcessor$determine_orientation(plot, built = NULL)
Arguments
plotThe ggplot2 object.
builtIts
ggplot_build()result, when the caller already has one.
Returns
"horz" or "vert".
Ggplot2HistogramLayerProcessor$extract_data()
One point per bin, read from this layer's own built data
Usage
Ggplot2HistogramLayerProcessor$extract_data( plot, built = NULL, panel_id = NULL )
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
Returns
List of points
Ggplot2HistogramLayerProcessor$generate_selectors()
Selectors for the bins, scoped to the panel
Usage
Ggplot2HistogramLayerProcessor$generate_selectors( plot, gt = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List of selectors
Ggplot2HistogramLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2HistogramLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Final Line Layer Processor - Uses Actual SVG Structure
Description
Processes line plot layers using the actual gridSVG structure discovered:
Lines: GRID.polyline.61.1.1, GRID.polyline.61.1.2, GRID.polyline.61.1.3
Points: geom_point.points.63.1.1 through geom_point.points.63.1.24 (grouped by series)
Super class
LayerProcessor -> Ggplot2LineLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2LineLayerProcessor$process()
Process the line layer with actual SVG structure
Usage
Ggplot2LineLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List with data and selectors
Ggplot2LineLayerProcessor$attach_group_axis()
Add the legend title as the z axis label for a multi-series line layer.
Shared with the smooth layer processor via
attach_series_group_axis(); see R/series_group_utils.R.
Usage
Ggplot2LineLayerProcessor$attach_group_axis(plot, built, data, axes)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
dataThe extracted layer data
axesAxes built so far
Returns
The axes list, with z added when the layer is grouped
Ggplot2LineLayerProcessor$has_series_groups()
Report whether extracted data is split into named series.
Usage
Ggplot2LineLayerProcessor$has_series_groups(data)
Arguments
dataThe extracted layer data
Returns
TRUE when there is more than one series and points carry z
Ggplot2LineLayerProcessor$resolve_group_mapping()
Resolve the aesthetic that splits this layer into series.
A line has no fill, so only the colour aesthetic is probed.
Usage
Ggplot2LineLayerProcessor$resolve_group_mapping(plot)
Arguments
plotThe ggplot2 object
Returns
list with aes (aesthetic spelling variants, or NULL when
nothing is mapped) and column (the mapped column name, or
"group" as a fallback)
Ggplot2LineLayerProcessor$extract_layer_axes()
Extract axes labels for line layers, with a special case for
moving-average geoms (e.g. tidyquant::geom_ma).
By default the parent LayerProcessor$extract_layer_axes() reads the
y-label from the layer's aesthetic mapping. For a moving-average
overlay typically written as geom_ma(aes(y = close), ma_fun = SMA, ...),
this yields the literal input-column name "close", which is misleading:
the value being plotted (and announced during navigation) is the moving
average of close, not close itself. We detect GeomMA (the class of
tidyquant's geom_ma layer) and override the y-label accordingly. Plain
geom_line / geom_smooth overlays are untouched.
Usage
Ggplot2LineLayerProcessor$extract_layer_axes(plot, layout)
Arguments
plotThe ggplot2 object
layoutLayout information
Returns
list(x = list(label = ...), y = list(label = ...))
Ggplot2LineLayerProcessor$extract_data()
Extract data from line layer (single or multiline)
Usage
Ggplot2LineLayerProcessor$extract_data(plot, built = NULL, panel_id = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
Returns
List of arrays, each containing series data points
Ggplot2LineLayerProcessor$attach_discrete_y_names()
Give every point the name of its discrete y level.
A factor y aesthetic reaches the payload as ggplot2's internal level
code, so without this a reader hears "5" where the axis says "Awake".
y deliberately stays numeric – it drives sonification, braille and
the min/max range – and the name rides alongside as label.
A continuous y is returned untouched, so no label is emitted and the
frontend announces the number, which is the right reading there.
Usage
Ggplot2LineLayerProcessor$attach_discrete_y_names( series_data, plot, built, panel_id = NULL )
Arguments
series_dataList of series produced by the extractors above
plotThe ggplot2 object
builtBuilt plot data
panel_idPanel ID for faceted plots (optional)
Returns
The series list, labelled when y is discrete
Ggplot2LineLayerProcessor$normalize_point_values()
Coerce every point's y to a plain number.
A discrete y aesthetic – the ordinal level of a hypnogram, and the
reason this processor exists – makes ggplot_build() return y as a
mapped_discrete vector. That class carries no asJSON method, so
emitting it verbatim aborts payload serialisation with
"No method asJSON S3 class: mapped_discrete". Stripping the class here
keeps y a bare number, which is what the wire contract asks for and
what drives sonification, braille and the min/max range.
Usage
Ggplot2LineLayerProcessor$normalize_point_values(series_data)
Arguments
series_dataList of series produced by the line extractor
Returns
The series list with numeric y values
Ggplot2LineLayerProcessor$panel_axis_labels()
Read one panel's own axis labels.
The labels ggplot2 drew on a panel's axis, which is what a sighted
reader sees, and which both discrete recoveries below start from: the
y level names in build_level_lookup(), and the x values in
recover_x_values(). Both need the same three things to hold before
the labels can be trusted – present, non-empty, no NA – so the
check lives here rather than being spelled out at each call site.
The tryCatch is not incidental: get_labels() is one of the
accessors whose spelling has moved between ggplot2 versions, the same
reason get_x_transformation() exists. Guarding it in one place leaves
the next version bump one site to fix instead of two that can drift.
Indexes with [[axis]] rather than $x / $y: $ on a list falls
back to partial matching, so a panel_params without an x but with
an x.range would silently hand back the range. Exact matching returns
NULL there, which is the honest answer.
Usage
Ggplot2LineLayerProcessor$panel_axis_labels(built, panel_index, axis)
Arguments
builtBuilt plot data
panel_indexIndex into
built$layout$panel_paramsaxisEither
"x"or"y"
Returns
Character vector of labels, or NULL when the panel has no such scale or its labels are unusable
Ggplot2LineLayerProcessor$build_level_lookup()
Build a numeric-level to level-name lookup for the y aesthetic.
For a factor (or character) y aesthetic, ggplot_build() replaces the
level with its numeric position, so built$data$y is a level code
and the name has to be recovered from somewhere else.
It is recovered from the panel's own y scale – the very labels ggplot2 draws on the axis – which makes the announcement agree with what a sighted reader sees, and sidesteps two traps:
-
Row order is not a join key.
GeomLine$setup_data()sorts the built data by (PANEL, group, x) – that sort is the documented difference betweengeom_line()andgeom_path()– while the caller's column keeps its own order, so pairing them row by row attaches the wrong name to the wrong code. -
Unused levels are dropped. A discrete scale defaults to
drop = TRUE, so a factor declaring five levels of which two are drawn is coded 1..2, not by position inlevels(). Reading names off the factor would name code 2 after the second declared level rather than the second drawn one.
Returns NULL for a plain continuous y, in which case no label is
emitted and the frontend announces the numeric value.
Usage
Ggplot2LineLayerProcessor$build_level_lookup(plot, built, panel_id = NULL)
Arguments
plotThe ggplot2 object (unused; kept for call-site symmetry)
builtBuilt plot data
panel_idPanel ID for faceted plots (optional) – each panel carries its own scale under
scales = "free_y"
Returns
Named character vector keyed by the built y value, or NULL
Ggplot2LineLayerProcessor$attach_level_labels()
Attach the ordinal level name to every point of every series. Points whose y has no entry in the lookup are left untouched, so the frontend falls back to the numeric announcement for them.
Usage
Ggplot2LineLayerProcessor$attach_level_labels(series_data, lookup)
Arguments
series_dataList of series produced by the line extractor
lookupNamed character vector keyed by the built y value
Returns
The series list with label attached where known
Ggplot2LineLayerProcessor$get_layer()
The ggplot2 layer this processor is responsible for.
Usage
Ggplot2LineLayerProcessor$get_layer(plot)
Arguments
plotThe ggplot2 object
Returns
The layer, or NULL when the index does not resolve
Ggplot2LineLayerProcessor$get_x_transformation()
The transformation a panel's x scale applies to positions.
ggplot_build() stores x positions in transformed space, so under
scale_x_log10() the data value 100 is recorded as 2. Recovering
the value the axis actually shows needs the scale's own transformation.
ggplot2 >= 3.5 exposes it through get_transformation(); earlier
versions keep it in the scale's trans field.
Usage
Ggplot2LineLayerProcessor$get_x_transformation(built, panel_index)
Arguments
builtBuilt plot data
panel_indexIndex into
built$layout$panel_params
Returns
A scales transform object, or NULL when none is available
Ggplot2LineLayerProcessor$transform_x_values()
Project raw x values into the space ggplot_build()
stores positions in.
Going forwards (raw -> transformed) rather than inverting the built positions keeps the comparison exact: it repeats the very computation ggplot2 performed, so no floating-point drift is introduced. Values the transformation cannot represent (a non-positive number under a log scale, say) become NA and simply fail to match.
Usage
Ggplot2LineLayerProcessor$transform_x_values(values, transformation)
Arguments
valuesRaw values taken from the plot's data
transformationTransform object from
get_x_transformation(), or NULL
Returns
Numeric vector the same length as values
Ggplot2LineLayerProcessor$format_x_value()
Format an x-axis value for the payload.
A plain number stays a number, so a line over a numeric column carries
the same x a geom_point() over it does. Date / POSIXct / POSIXlt
values are formatted via format() so that a Date column emits ISO
date strings (e.g. "2024-01-02") rather than the underlying numeric
days-since-epoch representation produced by ggplot_build(), which
keeps them aligned string-wise with
Ggplot2BarLayerProcessor$format_x_value(). Anything else – a
category label – is a string. See line_x_value().
Usage
Ggplot2LineLayerProcessor$format_x_value(x)
Arguments
xThe value to format
Returns
A number, or a string
Ggplot2LineLayerProcessor$extract_multiline_data()
Extract data for multiple line series
Usage
Ggplot2LineLayerProcessor$extract_multiline_data( layer_data, plot, recovered_x = NULL )
Arguments
layer_dataThe built layer data
plotThe original ggplot2 object
recovered_xx values recovered from the built column by
recover_x_values(), aligned tolayer_data's rows. NULL leaves the built value in place.
Returns
List of arrays, each containing series data
Ggplot2LineLayerProcessor$extract_single_line_data()
Extract data for single line (backward compatibility)
Usage
Ggplot2LineLayerProcessor$extract_single_line_data( layer_data, plot = NULL, recovered_x = NULL )
Arguments
layer_dataThe built layer data
plotThe original ggplot2 object. Unread since x recovery moved upstream; kept for signature parity with
extract_multiline_data()and for existing call sites.recovered_xx values recovered from the built column by
recover_x_values(), aligned tolayer_data's rows. NULL leaves the built value in place.
Returns
List containing single series data
Ggplot2LineLayerProcessor$recover_x_values()
The x values to announce, recovered from the BUILT column.
ggplot_build() stores x in the scale's own space – a level code for
a discrete scale, days-since-epoch for a Date – so something has to
turn it back into what the axis shows. The obvious route, reading the
caller's column, cannot be indexed by the built row number:
GeomLine$setup_data() sorts the built data by (PANEL, group, x),
which is the documented difference between geom_line() and
geom_path(), while the caller's column keeps its own order. Pairing
the two by position hands every point another point's x.
Recovering from the built value instead is order-proof by construction, and per scale type it needs:
discrete – the panel's own x labels, indexed by the level code, the same source
build_level_lookup()uses for a discrete ytransformed (Date, POSIXct, log) – the transformation's inverse
plain numeric – nothing; the built value already IS the value
Usage
Ggplot2LineLayerProcessor$recover_x_values(layer_data, built, panel_id = NULL)
Arguments
layer_dataThe built layer data for this layer
builtBuilt plot data
panel_idPanel ID for faceted plots (optional)
Returns
A vector aligned to layer_data's rows, or NULL to leave the
built value alone
Ggplot2LineLayerProcessor$get_group_column()
Get the grouping column name from plot mappings
Usage
Ggplot2LineLayerProcessor$get_group_column(plot)
Arguments
plotThe ggplot2 object
Returns
Name of the grouping column
Ggplot2LineLayerProcessor$generate_selectors()
One selector per series this line layer draws.
The panel-wide polyline list conflates two different things: a
grouped geom_line() draws ALL of its curves as ONE
polylineGrob whose id splits it (gridSVG then emits
GRID.polyline.N.1.1, .1.2, ... per curve), while a
second polyline-producing layer such as geom_smooth() adds
further grobs of its own. Indexing that flat list by this layer's
position among line layers therefore returned one selector for a
three-curve layer as soon as a smooth sat beside it, and the
frontend's multiline trace refuses a selector list whose length does
not equal the series count – so the layer lost highlighting
entirely rather than mis-aiming it.
This resolves THIS layer's own grob first and then enumerates the curves inside it, emitting one selector per curve. When the curves cannot be lined up with the series, no selector is emitted: a caller can tell an absent selector apart from a wrong one, a user cannot.
Usage
Ggplot2LineLayerProcessor$generate_selectors( plot, gt = NULL, grob_id = NULL, panel_ctx = NULL, built = NULL, n_series = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation
builtBuilt plot data (optional)
n_seriesNumber of series
extract_data()produced, or NULL to derive it from the built layer data
Returns
List of selectors for each series
Ggplot2LineLayerProcessor$series_count()
Number of series this layer draws in the given panel.
Never throws: selector generation has to degrade gracefully for
inputs extract_data() would reject.
Usage
Ggplot2LineLayerProcessor$series_count(plot, built = NULL, panel_ctx = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_ctxPanel context for panel-scoped selector generation
Returns
Number of series, at least 1
Ggplot2LineLayerProcessor$curve_selectors()
Selectors for the curves inside this layer's own grob.
Usage
Ggplot2LineLayerProcessor$curve_selectors(plot, panel_grob, n_series)
Arguments
plotThe ggplot2 object
panel_grobThe panel's grob tree
n_seriesNumber of series the layer produced
Returns
List of selectors, or NULL when the grob does not line up with the series
Ggplot2LineLayerProcessor$polyline_curve_count()
Number of separate curves a polyline grob draws.
polylineGrob() splits one grob into several drawn lines via
id / id.lengths; gridSVG renders each as its own SVG
element suffixed .1.<k>.
Usage
Ggplot2LineLayerProcessor$polyline_curve_count(grob)
Arguments
grobA polyline grob
Returns
Integer count, at least 1
Ggplot2LineLayerProcessor$generate_multiline_selectors()
Generate selectors for multiline plots using actual structure
Usage
Ggplot2LineLayerProcessor$generate_multiline_selectors(base_id, num_series)
Arguments
base_idThe base ID from the grob (e.g., "61")
num_seriesNumber of series
Returns
List of selectors
Ggplot2LineLayerProcessor$generate_single_line_selector()
Generate selector for single line plot
Usage
Ggplot2LineLayerProcessor$generate_single_line_selector(base_id)
Arguments
base_idThe base ID from the grob
Returns
List with single selector
Ggplot2LineLayerProcessor$line_layer_position()
Position of this layer among the polyline-producing layers.
Delegates to polyline_layer_position(), which counts every layer type
that renders an auto-named polyline: "line", "step" and "contour".
layer_polyline_grobs() skips only the layers that name their grob tree
after their geom, and none of these three do. GeomContour defines no
draw_panel() of its own and so draws through GeomPath's – a bare
polylineGrob – while GeomStep stairsteps its data and then calls
the same method; either sits in that candidate list exactly as a
geom_line() does. Counting only "line" layers would therefore index
the wrong polyline for every layer of a plot that combines them.
Usage
Ggplot2LineLayerProcessor$line_layer_position(plot)
Arguments
plotThe ggplot2 object
Returns
The 1-based position, or NULL if registry-based detection fails
Ggplot2LineLayerProcessor$find_main_polyline_grob()
Find the main polyline grob (GRID.polyline.XX)
Usage
Ggplot2LineLayerProcessor$find_main_polyline_grob(gt)
Arguments
gtThe gtable to search
Returns
The main polyline grob or NULL
Ggplot2LineLayerProcessor$needs_reordering()
Check if layer needs reordering
Usage
Ggplot2LineLayerProcessor$needs_reordering()
Returns
FALSE (line plots typically don't need reordering)
Ggplot2LineLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2LineLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Pie Layer Processor
Description
Processes the ggplot2 idiom for a pie chart: a geom_col() /
geom_bar() layer drawn in polar coordinates with theta mapped to y,
so the stack's segments become wedges. The payload is 1-D and flat – one
point per wedge, x the slice label and y its magnitude. The
percentage MAIDR announces is derived from those values by the frontend, so
this layer deliberately does not emit one.
Multi-ring "bullseye" polar bars are out of scope. geom_col() with a
non-constant x under coord_polar("y") draws one concentric ring per
x category, and a flat list of wedges cannot carry that second dimension –
wedges from different rings would collapse onto the same label. Those
layers never reach this processor: Ggplot2Adapter$is_pie_coord()
declines them, and they stay bar / stacked / dodged as before.
Super class
LayerProcessor -> Ggplot2PieLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2PieLayerProcessor$process()
Process the pie layer
Usage
Ggplot2PieLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selectors (optional)
Returns
List with data, selectors, title, axes and type
Ggplot2PieLayerProcessor$extract_dial()
Where the ring begins and which way the emitted wedges run
The frontend walks a pie clockwise – Right steps to the next slice the
way a clock hand goes, the audio pans each slice to where it sits and
p names its clock position – all from where the layer says the first
slice begins, in degrees clockwise from 12 o'clock. The layer says two
things about the wedges it emits: where the ring begins and which way
round the dial the emitted order runs.
Where the ring begins, and which way the coord runs round it, are read
off the coord by pie_coord_ring(): coord_polar() keeps a
start applied in its direction, coord_radial() an
arc already turned round by its reverse. Either maps the
whole theta scale onto the arc, so a full ring ends where it began and
the same edge serves whichever way the wedges are walked. A partial
coord_radial() arc, or its default theta expansion, draws less
than the full circle; the frontend's pie has no key for that, so the
ring's nominal edge is declared and the wedges are read as filling it.
Which way the emitted order runs is NOT simply the coord's direction.
position_stack() stacks the first group on top by default, so
the built rows – and the wedges, and the selectors index-aligned to
them – run from the top of the stack down: the first emitted wedge is
the one that ENDS the ring, and the order goes back against the coord's
direction, and position_stack(reverse = TRUE) builds them the
other way up. So the direction is read off the built rows themselves:
emitted order running down the stack is the coord's direction
reversed, running up it is the coord's direction.
Both keys are left out at the frontend's own defaults – a clockwise ring from the top – which is also what every layer declared before the keys existed.
Usage
Ggplot2PieLayerProcessor$extract_dial(plot, built, panel_id = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data
panel_idOptional facet panel to restrict extraction to
Returns
Named list holding startAngle and/or direction, possibly
empty
Ggplot2PieLayerProcessor$extract_data()
Extract one point per wedge
The magnitude is the segment's own extent, not the stacked y:
ymax - ymin is what the wedge actually subtends, and it is the
one expression that works for both geom_col() (stat identity)
and geom_bar() (stat count).
The extent is unsigned, though, and a negative datum is stacked
below the baseline: ggplot2 builds v = -40 as
ymin = -40, ymax = 0, so the extent is 40 and the sign is gone.
Reporting that would announce a slice the author entered as -40 as
40, and compute its share against a total that swallowed it –
confidently wrong, and indistinguishable from real data.
So the sign is restored from which side of the baseline the segment sits on. The renderer treats a negative slice as a gap, announcing it as missing rather than letting it corrupt every other slice's percentage; laundering it here would leave that defence nothing to catch. Whether a producer should reject such a value outright is a separate question – see xability/maidr#771 – but no answer to it is served by destroying the sign first.
Usage
Ggplot2PieLayerProcessor$extract_data(plot, built = NULL, panel_id = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idOptional facet panel to restrict extraction to
Returns
List of list(x, y) points, one per wedge
Ggplot2PieLayerProcessor$panel_built_data()
Rows of this layer's built data, optionally one panel's
Usage
Ggplot2PieLayerProcessor$panel_built_data(built, panel_id = NULL)
Arguments
builtBuilt plot data
panel_idOptional facet panel to restrict the rows to
Returns
data.frame of built rows for this layer
Ggplot2PieLayerProcessor$resolve_slice_mapping()
Resolve the aesthetic whose categories name the wedges
Fill is probed before x because the idiomatic pie maps x to the literal
"" and carries the categories on fill. A layer whose built rows
do not each sit in their own group is not split by any aesthetic (every
row shares group -1 or 1), so no aesthetic names its wedges.
Usage
Ggplot2PieLayerProcessor$resolve_slice_mapping(plot, built_data)
Arguments
plotThe ggplot2 object
built_dataThis layer's built rows
Returns
list with aes (aesthetic name, or NULL) and
column (the mapped column name)
Ggplot2PieLayerProcessor$resolve_slice_labels()
Name each wedge after the category it draws
ggplot_build() has already replaced the grouping column with
integer group ids, assigned in the sorted order of that column's
values – the same order the scale reports its labels in. Indexing the
labels BY the id, rather than by position among the ids present, is
what stops a facet panel that is missing a category from shifting every
remaining wedge's label by one. Wedges the scale cannot name fall back
to their position.
Usage
Ggplot2PieLayerProcessor$resolve_slice_labels(plot, built, built_data)
Arguments
plotThe ggplot2 object
builtBuilt plot data
built_dataThis layer's built rows
Returns
Character vector, one label per wedge
Ggplot2PieLayerProcessor$slice_categories()
Categories of the aesthetic that splits the wedges
The scale is asked first, because a mapping written as an expression –
aes(fill = factor(cyl)) – has no column to read. A discrete
POSITION scale keeps its labels in panel_params instead, and
coord_polar() publishes none of those under x, so the mapped
column is the fallback. Both list the categories in the same sorted
order the group ids were assigned in.
Usage
Ggplot2PieLayerProcessor$slice_categories(plot, built, slice)
Arguments
plotThe ggplot2 object
builtBuilt plot data
sliceSlice mapping from
resolve_slice_mapping()
Returns
Character vector of categories, or NULL when neither source has any
Ggplot2PieLayerProcessor$scale_labels()
Break labels of the scale backing an aesthetic
Usage
Ggplot2PieLayerProcessor$scale_labels(built, aes_name)
Arguments
builtBuilt plot data
aes_nameAesthetic whose scale to read
Returns
Character vector of labels, or NULL when the scale has none
Ggplot2PieLayerProcessor$extract_pie_axes()
Build the canonical axes for a pie layer
x names what the wedge labels mean and y what their
magnitudes measure. Since the labels come off the slice aesthetic, its
legend title is the x label – resolved the same way the stacked bar
layer resolves its z label. The y label is taken from the layout, which
reads the BUILT plot's labels and so already carries a stat-derived
name such as "count".
Usage
Ggplot2PieLayerProcessor$extract_pie_axes(plot, layout, built, panel_id = NULL)
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data
panel_idOptional facet panel to restrict extraction to
Returns
Canonical axes list with x and y
Ggplot2PieLayerProcessor$generate_selectors()
Generate the wedge selector for this layer
In polar coordinates the whole layer is ONE polygonGrob named
geom_rect.polygon.<N> whose sub-polygons are grouped by
id – not the geom_rect.rect.<N> a cartesian bar layer
draws. gridSVG exports it as <g id="geom_rect.polygon.<N>.1">
with one <polygon> child per wedge, emitted in built-row order,
so a single descendant selector resolves to the N elements in slice
order.
Usage
Ggplot2PieLayerProcessor$generate_selectors(plot, gt = NULL, panel_ctx = NULL)
Arguments
plotThe ggplot2 object
gtGtable object (optional)
panel_ctxPanel context for panel-scoped selectors (optional)
Returns
List holding one selector, or an empty list
Ggplot2PieLayerProcessor$layer_slot_grob()
The grob slot belonging to this layer
ggplot2 lays a panel out as the grill, a leading zeroGrob,
one child per layer in layer order, a trailing
zeroGrob and the axis tree. So the slot is the handle: layer
k owns the kth child after the leading blank, whether or
not it drew anything.
It matters because a panel can hold more than one polar
geom_rect layer – two geom_col()s under
coord_polar() is an ordinary way to draw a ring over a pie –
and a search that takes the first container hands every layer the first
layer's wedges. Those selectors resolve, and the payload looks healthy,
and the outline is on the wrong marks.
LayerProcessor$find_layer_grob_tree() cannot be reused for this:
it matches on the geom's own class, and a geom_col() layer is
GeomCol while the grob it draws is named after
geom_rect. Counting containers instead of slots does not work
either – a geom_text() label layer occupies a slot and draws no
container, so the counts stop lining up and both rings of an annotated
pie lose their selectors.
Usage
Ggplot2PieLayerProcessor$layer_slot_grob(panel)
Arguments
panelThe panel grob, or NULL
Returns
This layer's grob, or NULL when the slot cannot be established
Ggplot2PieLayerProcessor$sole_wedge_container()
The one wedge container in a tree, when there is exactly one
The fallback for when the slot lookup cannot resolve – a panel shape
with no leading blank, or a caller handing over a gtable rather than a
panel. Correct whenever the search finds a single container, which is
every chart that is only a pie; ambiguous otherwise, and ambiguous
means no selector for the reason generate_selectors() gives.
Usage
Ggplot2PieLayerProcessor$sole_wedge_container(roots)
Arguments
rootsGrobs to search
Returns
Grob name, or NULL
Ggplot2PieLayerProcessor$collect_polygon_grobs()
Every wedge container in a grob tree, in drawing order
One entry per layer that drew wedges. A match is not descended into: the container is the whole layer's wedges, and its children are the individual ones.
Usage
Ggplot2PieLayerProcessor$collect_polygon_grobs(grob)
Arguments
grobGrob to search
Returns
Character vector of grob names, possibly empty
Ggplot2PieLayerProcessor$find_own_polygon_grob()
Whether this grob is itself a wedge container
ggplot2 does not draw a polar bar layer the same way across versions,
and the difference is not cosmetic. Verified against real
gridSVG::grid.export() output:
One
geom_rect.polygon.<N>grob holding every wedge, grouped by id. This is what the lookup was written for.A
geom_rect.gTree.<N>holding onegeom_polygon.polygon.<N>grob per wedge. On ggplot2 3.4.4 this is what a pie draws, and nothing namedgeom_rect.polygonexists anywhere in the tree – so the lookup found nothing,generate_selectors()returned an empty list, and a pie highlighted nothing at all (#151).
Either way the answer is a container whose <polygon> descendants
are the wedges in slice order, so the caller's descendant selector
resolves against both without knowing which it got.
The polar grill draws a polygon of its own under
coord_radial(), named GRID.polygon.<N>; neither branch
carries a name that matches it. The gTree branch also requires a
polygon to be there: a geom_rect layer that drew none has
nothing to point at.
Usage
Ggplot2PieLayerProcessor$find_own_polygon_grob(grob)
Arguments
grobGrob to test
Returns
Grob name, or NULL
Ggplot2PieLayerProcessor$holds_polygon()
Whether a grob tree draws at least one polygon.
Usage
Ggplot2PieLayerProcessor$holds_polygon(grob)
Arguments
grobGrob to search
Returns
TRUE when the tree holds a polygon grob
Ggplot2PieLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2PieLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Plot Orchestrator Class
Description
This class orchestrates the detection and processing of multiple layers in a ggplot2 object. It analyzes each layer individually and combines the results into a comprehensive interactive plot.
Methods
Public methods
Ggplot2PlotOrchestrator$new()
Create an orchestrator for a ggplot2 object
Usage
Ggplot2PlotOrchestrator$new(plot)
Arguments
plotThe ggplot2 object
Ggplot2PlotOrchestrator$detect_layers()
Turn each layer of the plot into a layer entry with its detected type
Usage
Ggplot2PlotOrchestrator$detect_layers()
Ggplot2PlotOrchestrator$skip_layers_that_drew_nothing()
Retag every layer that drew no rows as "skip".
A layer can be typed perfectly well and still have nothing in it – a
data = filtered to nothing, a stat that dropped every row, a
facet arrangement in which one layer's data is empty, a Suggests
package absent so the stat could not run. It then reaches the schema
as a layer a reader can walk into and find nothing in. Measured on ten
points, the second layer drawn from d[0, ]:
geom_point() point(0) an empty layer of points geom_col() bar(0) an empty layer of bars geom_line() line(1x0) one series, holding nothing geom_smooth() smooth(1x0) one series, holding nothing
Asked here rather than in detect_layer_type() because emptiness
is not a fact about what kind of chart a layer is, and because the
classifier runs per layer: one ggplot_build() for the whole
pass costs a chart ~37 ms once, where asking per layer would multiply
it. "skip" rather than a fourth answer, because that is the tag
the rest of the orchestrator already understands – including the #176
guard, so a chart whose only layer is empty falls back to an image
rather than announcing itself as interactive with nothing in it.
A build that cannot answer changes nothing. That is the same posture
layer_drew_nothing() takes: a plot that will not build is a
bigger problem than this, and it is about to be met by whatever else
needs the build.
Usage
Ggplot2PlotOrchestrator$skip_layers_that_drew_nothing()
Returns
NULL, invisibly. Rewrites private$.layers in place.
Ggplot2PlotOrchestrator$analyze_single_layer()
Describe one ggplot2 layer as a layer entry with its detected type
Usage
Ggplot2PlotOrchestrator$analyze_single_layer(layer, layer_index)
Arguments
layerA ggplot2 layer object
layer_indexIndex of the layer
Returns
Layer information list
Ggplot2PlotOrchestrator$determine_layer_type()
The layer type the adapter detects for one layer of the plot
Usage
Ggplot2PlotOrchestrator$determine_layer_type(plot, layer_index)
Arguments
plotThe ggplot2 object
layer_indexIndex of the layer
Returns
Character string
Ggplot2PlotOrchestrator$create_layer_processors()
Create a processor for every layer of a known type
Usage
Ggplot2PlotOrchestrator$create_layer_processors()
Ggplot2PlotOrchestrator$create_layer_processor()
Create the processor for one layer
Usage
Ggplot2PlotOrchestrator$create_layer_processor(layer_info)
Arguments
layer_infoLayer information
Returns
A layer processor, or NULL for an unknown type
Ggplot2PlotOrchestrator$create_unified_layer_processor()
Unified layer processor creation - used by all plot types
Usage
Ggplot2PlotOrchestrator$create_unified_layer_processor(layer_info)
Arguments
layer_infoLayer information
Returns
Layer processor instance
Ggplot2PlotOrchestrator$process_layers()
Run every layer processor and combine the results
Usage
Ggplot2PlotOrchestrator$process_layers()
Ggplot2PlotOrchestrator$extract_layout()
Read the figure-level title, subtitle, caption and axis labels from the built plot
Usage
Ggplot2PlotOrchestrator$extract_layout(built = NULL)
Arguments
builtBuilt plot data (optional)
Returns
List
Ggplot2PlotOrchestrator$combine_layer_results()
Combine the per-layer results into the subplot grid
Usage
Ggplot2PlotOrchestrator$combine_layer_results(layer_results)
Arguments
layer_resultsList of per-layer results, one per processor
Ggplot2PlotOrchestrator$generate_maidr_data()
Assemble the MAIDR data object for the figure
Usage
Ggplot2PlotOrchestrator$generate_maidr_data()
Returns
List with an id and the subplots
Ggplot2PlotOrchestrator$get_gtable()
The gtable the plot was drawn to
Usage
Ggplot2PlotOrchestrator$get_gtable()
Returns
A gtable, or NULL before the layers are processed
Ggplot2PlotOrchestrator$get_layout()
The figure-level layout read by extract_layout()
Usage
Ggplot2PlotOrchestrator$get_layout()
Returns
List
Ggplot2PlotOrchestrator$get_combined_data()
The combined per-layer data
Usage
Ggplot2PlotOrchestrator$get_combined_data()
Returns
List
Ggplot2PlotOrchestrator$get_layer_processors()
The processors created for the layers
Usage
Ggplot2PlotOrchestrator$get_layer_processors()
Returns
List
Ggplot2PlotOrchestrator$get_layers()
The detected layer entries
Usage
Ggplot2PlotOrchestrator$get_layers()
Returns
List
Ggplot2PlotOrchestrator$is_patchwork_plot()
Check if the plot is a patchwork composition
Usage
Ggplot2PlotOrchestrator$is_patchwork_plot()
Returns
Logical indicating if the plot is a patchwork plot
Ggplot2PlotOrchestrator$is_faceted_plot()
Check if the plot is faceted
Usage
Ggplot2PlotOrchestrator$is_faceted_plot()
Returns
Logical indicating if the plot is faceted
Ggplot2PlotOrchestrator$process_faceted_plot()
Process a faceted plot using utility functions
Usage
Ggplot2PlotOrchestrator$process_faceted_plot()
Returns
NULL (sets internal state)
Ggplot2PlotOrchestrator$process_patchwork_plot()
Process a patchwork multipanel plot using utility functions
Usage
Ggplot2PlotOrchestrator$process_patchwork_plot()
Returns
NULL (sets internal state)
Ggplot2PlotOrchestrator$has_unsupported_layers()
Check if any layers are unsupported (unknown type)
Usage
Ggplot2PlotOrchestrator$has_unsupported_layers()
Returns
Logical indicating if there are unsupported layers
Ggplot2PlotOrchestrator$should_fallback()
Determine if the plot should fall back to image rendering
Usage
Ggplot2PlotOrchestrator$should_fallback()
Returns
Logical indicating if fallback should be used
Ggplot2PlotOrchestrator$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2PlotOrchestrator$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Point Layer Processor
Description
Processes scatter plot layers (geom_point) to extract point data and generate selectors for individual points in the SVG structure.
Super class
LayerProcessor -> Ggplot2PointLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2PointLayerProcessor$process()
Process the point layer
Usage
Ggplot2PointLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List with data and selectors
Ggplot2PointLayerProcessor$extract_axes_labels()
Extract axis information from the plot
Returns per-axis objects with label and optional grid navigation fields (min, max, tickStep). Grid fields are only included when they can be successfully extracted from the built plot scales.
Usage
Ggplot2PointLayerProcessor$extract_axes_labels( plot, built = NULL, panel_id = NULL )
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
Returns
List with x and y per-axis objects
Ggplot2PointLayerProcessor$extract_axis_grid_info()
Extract grid navigation info (min, max, tickStep) for a single axis
Delegates to axis_grid_info(), which is where the reading now
lives: the rug processor needs the same answer for the axis its ticks
stand on, and one grid rule read two ways is how the two would drift.
Kept as a method so this class's own callers are unchanged.
Usage
Ggplot2PointLayerProcessor$extract_axis_grid_info( built, axis = "x", panel_id = NULL )
Arguments
builtBuilt plot data
axisCharacter, either "x" or "y"
panel_idPanel index for faceted plots (optional, defaults to 1)
Returns
List with min, max, tickStep or NULL if extraction fails
Ggplot2PointLayerProcessor$extract_data()
Extract data from point layer
Usage
Ggplot2PointLayerProcessor$extract_data(plot, built = NULL, panel_id = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
Returns
List with points array and color information
Ggplot2PointLayerProcessor$generate_selectors()
Generate selectors for point elements
Usage
Ggplot2PointLayerProcessor$generate_selectors( plot, gt = NULL, grob_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List of selectors
Ggplot2PointLayerProcessor$find_panel_grob()
Find the panel grob this layer draws into
Usage
Ggplot2PointLayerProcessor$find_panel_grob(gt, panel_ctx = NULL)
Arguments
gtThe gtable to search
panel_ctxPanel context for patchwork leaves and facets; NULL for a single plot, where the panel is the cell literally named "panel"
Returns
The panel grob or NULL
Ggplot2PointLayerProcessor$find_children_by_type()
Find children by type pattern
Usage
Ggplot2PointLayerProcessor$find_children_by_type(grob, type_pattern)
Arguments
grobThe grob to search
type_patternPattern to match
Returns
List of matching children
Ggplot2PointLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2PointLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Polygon Layer Processor
Description
Reads geom_polygon() as the closed path it draws.
A polygon is geom_path() with its ends joined and its interior filled.
GeomPath has been dispatched to "line" since before this file existed,
so reading a polygon the same way decides nothing new about what a series
of vertices means – it makes two spellings of one mark behave alike, the
argument GeomSpoke was routed through GeomSegment on (#225).
What it was costing until then is the whole chart. "unknown" is what
makes has_unsupported_layers() true and drops the plot to a static
image (#176). Measured on ggplot2 3.4.4, thirty points, save_html():
geom_point() interactive SVG 52,708 bytes geom_point() + geom_polygon() base64 image 30,913 bytes geom_polygon() alone base64 image 18,353 bytes
Skipping it instead was declined in #225 and the reason is worth keeping
here: every geom skipped today carries no observations – geom_blank()
draws nothing, a reference line is a constant, a text label repeats a
value already in the payload – so skipping loses a reader nothing they
could have navigated. A polygon's vertices are rows the author supplied.
Skipping one that is the data would drop it silently, which is worse than
the honest picture, because the reader is not told anything is missing.
The closing vertex is not emitted
Four rows draw a quadrilateral with four corners and five edges. The
fifth edge is the closure, and it adds no observation – which is
ggplot2's own reading as well: GeomPolygon$draw_panel() hands grid the
munched rows unchanged under a linear coord, and the drawn element holds
exactly as many points as the layer has rows. Straight off the exported
SVG for x = c(1, 3, 3, 1), y = c(1, 1, 3, 3):
<polygon points="49.84,53.12 171.93,53.12 171.93,265.22 49.84,265.22"/>
So a series and its drawn shape are the same length, in the same order, and a reader who navigates to the end has been told every vertex once.
Addressing
Unlike a line, a polygon layer names its grob after its geom, so it needs
no draw-order search of anonymous GRID.polyline.N grobs. gridSVG turns
one grob into one element per group, which is the granularity the
multi-series trace wants:
<g id="geom_polygon.polygon.57.1"> <polygon id="geom_polygon.polygon.57.1.1"/> <- group 1 <polygon id="geom_polygon.polygon.57.1.2"/> <- group 2
aes(subgroup =) – a shape with a hole in it – is drawn as a
pathgrob rather than a polygon, and gridSVG still emits one <path>
per pathId, which is still the group. Measured on two groups of two
subgroups: geom_polygon.pathgrob.42.1.1 and ...1.2, each holding both
of its rings in one d. So both spellings address the same way and only
the element differs, which is why the search below matches either.
Super classes
LayerProcessor -> Ggplot2LineLayerProcessor -> Ggplot2PolygonLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()Ggplot2LineLayerProcessor$attach_discrete_y_names()Ggplot2LineLayerProcessor$attach_level_labels()Ggplot2LineLayerProcessor$build_level_lookup()Ggplot2LineLayerProcessor$extract_data()Ggplot2LineLayerProcessor$extract_layer_axes()Ggplot2LineLayerProcessor$extract_multiline_data()Ggplot2LineLayerProcessor$extract_single_line_data()Ggplot2LineLayerProcessor$find_main_polyline_grob()Ggplot2LineLayerProcessor$format_x_value()Ggplot2LineLayerProcessor$generate_multiline_selectors()Ggplot2LineLayerProcessor$generate_selectors()Ggplot2LineLayerProcessor$generate_single_line_selector()Ggplot2LineLayerProcessor$get_group_column()Ggplot2LineLayerProcessor$get_layer()Ggplot2LineLayerProcessor$get_x_transformation()Ggplot2LineLayerProcessor$has_series_groups()Ggplot2LineLayerProcessor$line_layer_position()Ggplot2LineLayerProcessor$needs_reordering()Ggplot2LineLayerProcessor$normalize_point_values()Ggplot2LineLayerProcessor$panel_axis_labels()Ggplot2LineLayerProcessor$polyline_curve_count()Ggplot2LineLayerProcessor$recover_x_values()Ggplot2LineLayerProcessor$series_count()Ggplot2LineLayerProcessor$transform_x_values()
Ggplot2PolygonLayerProcessor$process()
Process the polygon layer as a closed path
The reading is the line processor's: one series per group, in the
built data's row order, named from whatever aesthetic splits the
layer. Only the type and the selectors are this class's own.
Usage
Ggplot2PolygonLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for patchwork leaves and facets
Returns
List with data, selectors, title, axes and type
Ggplot2PolygonLayerProcessor$resolve_group_mapping()
Resolve the aesthetic that splits this layer into series
A line probes colour alone, because a line has no fill. A polygon
has both, and fill is the one it is usually split by – so fill
is probed first, then the outline colour, then group itself.
group is the addition, and it is worth its line. A polygon is drawn
one shape per group, and aes(group = g) with nothing else mapped is
the plainest way to write two shapes – it is how ggplot2's own
documentation writes them. Without it both series fall back to
"Series 1" and "Series 2" while the chart's own data says "a" and
"b". ggplot2 records the column under labels$group exactly as it
records a legend title, so the z label comes out as "g" and a reader
hears "g is a" rather than "Group is Series 1".
Usage
Ggplot2PolygonLayerProcessor$resolve_group_mapping(plot)
Arguments
plotThe ggplot2 object
Returns
list with aes (aesthetic spelling variants, or NULL when
nothing is mapped) and column (the mapped column name, or
"group" as a fallback)
Ggplot2PolygonLayerProcessor$attach_group_axis()
Add the grouping column's name as the z axis label
Usage
Ggplot2PolygonLayerProcessor$attach_group_axis(plot, built, data, axes)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
dataThe extracted layer data
axesAxes built so far
Returns
The axes list, with z added when the layer is grouped
Ggplot2PolygonLayerProcessor$group_aes()
The aesthetics a polygon layer can be split by, in order
Usage
Ggplot2PolygonLayerProcessor$group_aes()
Returns
List of aesthetic-name vectors, each holding the spelling variants of one aesthetic
Ggplot2PolygonLayerProcessor$curve_selectors()
Selectors for this layer's polygons, one per series
Declines when the drawn shape count and the emitted series count
disagree, which is what the line processor does and for the same
reason: the frontend's multiline trace drops the whole layer's
highlight unless selectors.length === data.length, so a mismatched
list would outline the wrong shape rather than none.
Usage
Ggplot2PolygonLayerProcessor$curve_selectors(plot, panel_grob, n_series)
Arguments
plotThe ggplot2 object
panel_grobThe panel's grob tree
n_seriesNumber of series the layer emitted
Returns
List of CSS selectors, or NULL
Ggplot2PolygonLayerProcessor$polygon_shape_count()
How many shapes one polygon grob draws
id separates a polygon grob's locations into shapes; a pathgrob
uses id for its subgroups and pathId for the group, so the group
is what has to be counted there – a two-group, two-subgroup layer
carries id = 1,1,1,1,2,2,2,2,1,... and pathId = 1,1,1,1,1,1,1,1,2,...,
and reading id would answer two for a chart drawing two paths of
two rings each only by coincidence.
There is no "it has no ids" case to answer for.
GeomPolygon$draw_panel() always passes one – id = munched$group
for a polygon, pathId = munched$group for a path – so a grob
without one is not one of these, and length(unique(NULL)) answering
zero declines it, which is the right answer for a grob this should
not be addressing.
Usage
Ggplot2PolygonLayerProcessor$polygon_shape_count(grob)
Arguments
grobA
polygonorpathgrobgrob
Returns
The number of shapes drawn
Ggplot2PolygonLayerProcessor$find_layer_polygon_grob()
The polygon grob ggplot2 drew for THIS layer
Usage
Ggplot2PolygonLayerProcessor$find_layer_polygon_grob( plot, panel_grob, target = NULL )
Arguments
plotThe ggplot2 object
panel_grobThe panel's grob tree
targetIndex of the layer to find; defaults to this one's
Returns
The matching grob, or NULL
Ggplot2PolygonLayerProcessor$layer_polygon_grobs()
Panel polygons that a polygon layer could have drawn
The skip list is not defensive. geom_boxplot() draws each box's
crossbar through GeomPolygon, so a boxplot contributes grobs named
exactly like a polygon layer's own – and they are drawn first.
Measured on three boxes beside one polygon:
geom_boxplot.gTree.30 geom_boxplot.gTree.10 -> geom_crossbar.gTree.9 -> geom_polygon.polygon.7 geom_boxplot.gTree.20 -> geom_crossbar.gTree.19 -> geom_polygon.polygon.17 geom_boxplot.gTree.28 -> geom_crossbar.gTree.27 -> geom_polygon.polygon.25 geom_polygon.polygon.32 <- the layer's own
Taking the first match would outline a box. Every one of those sits
inside a tree named after the geom that owns it, so refusing to
descend into another layer's tree leaves exactly the layer's own –
which is how layer_polyline_grobs() scopes the same search for the
geoms that draw anonymous polylines.
Usage
Ggplot2PolygonLayerProcessor$layer_polygon_grobs( plot, panel_grob, target = NULL )
Arguments
plotThe ggplot2 object
panel_grobThe panel's grob tree
targetIndex of the layer whose polygons are wanted
Returns
List of grobs in draw order
Ggplot2PolygonLayerProcessor$polygon_layer_position()
This layer's position among the plot's polygon layers
Two geom_polygon() calls draw two grobs in layer order, so the
second layer wants the second match.
Usage
Ggplot2PolygonLayerProcessor$polygon_layer_position(plot, target)
Arguments
plotThe ggplot2 object
targetIndex of the layer of interest
Returns
The 1-based position, or NULL when the layer is not one
Ggplot2PolygonLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2PolygonLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
ggplot2 Processor Factory
Description
Factory for creating ggplot2-specific processors. This factory uses the existing ggplot2 layer processors and wraps them in the new unified interface.
Format
An R6 class inheriting from ProcessorFactory
Super class
ProcessorFactory -> Ggplot2ProcessorFactory
Methods
Public methods
Inherited methods
Ggplot2ProcessorFactory$new()
Initialize the ggplot2 processor factory
Usage
Ggplot2ProcessorFactory$new()
Ggplot2ProcessorFactory$create_processor()
Create a processor for a specific plot type
Usage
Ggplot2ProcessorFactory$create_processor(plot_type, layer_info)
Arguments
plot_typeThe type of plot (e.g., "bar", "line", "point")
layer_infoInformation about the layer (contains plot object and metadata)
Returns
Processor instance for the specified plot type
Ggplot2ProcessorFactory$get_supported_types()
Get list of supported plot types
Usage
Ggplot2ProcessorFactory$get_supported_types()
Returns
Character vector of supported plot types
Ggplot2ProcessorFactory$get_system_name()
Get the system name
Usage
Ggplot2ProcessorFactory$get_system_name()
Returns
System name string
Ggplot2ProcessorFactory$is_processor_available()
Check if a specific processor class is available
Usage
Ggplot2ProcessorFactory$is_processor_available(processor_class_name)
Arguments
processor_class_nameName of the processor class
Returns
TRUE if available, FALSE otherwise
Ggplot2ProcessorFactory$get_available_processors()
Get available processor classes
Enumerated from create_processor() rather than listed here, so the
answer cannot drift away from what the factory actually dispatches to
(#200).
Usage
Ggplot2ProcessorFactory$get_available_processors()
Returns
Character vector of available processor class names
Ggplot2ProcessorFactory$try_create_processor()
Create a processor with error handling
Usage
Ggplot2ProcessorFactory$try_create_processor(plot_type, plot_object)
Arguments
plot_typeThe type of plot
plot_objectThe plot object
Returns
Processor instance or NULL if creation fails
Ggplot2ProcessorFactory$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2ProcessorFactory$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
ROC Curve Layer Processor
Description
Reads a receiver operating characteristic curve – a classifier's true
positive rate against its false positive rate, one point per decision
threshold, one curve per classifier – as the roc trace.
Structurally a multi-series line, so the line processor does the work: the series split, the x recovery through the scale, the selectors per drawn polyline. What this adds is what the trace reads that a line does not.
-
The rates are numbers. The line processor formats x for announcement, which turns a rate into a string; the core's ROC trace measures the area under the curve and each point's height above the chance diagonal from
x, so it is handed back as a number. -
xis the false positive rate.pROC::ggroc()mapsspecificityon a reversed axis, which draws the same picture as1 - specificityon an ordinary one and reads as the opposite: every point would be measured below the diagonal it sits above. The rate is inverted and the axis named for what is announced. -
Thresholds and areas travel with the points. A
maidr_roc()layer'sthresholdaesthetic survives the build as a column, and itsaucargument names the areas; each is attached to the points of the series it belongs to, the threshold per point and the area on the first point of its curve, which is where the core reads it.
Emitted with type = "roc", which the core has read since maidr 4.9.0.
Super classes
LayerProcessor -> Ggplot2LineLayerProcessor -> Ggplot2RocLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()Ggplot2LineLayerProcessor$attach_discrete_y_names()Ggplot2LineLayerProcessor$attach_group_axis()Ggplot2LineLayerProcessor$attach_level_labels()Ggplot2LineLayerProcessor$build_level_lookup()Ggplot2LineLayerProcessor$curve_selectors()Ggplot2LineLayerProcessor$extract_data()Ggplot2LineLayerProcessor$extract_layer_axes()Ggplot2LineLayerProcessor$extract_multiline_data()Ggplot2LineLayerProcessor$extract_single_line_data()Ggplot2LineLayerProcessor$find_main_polyline_grob()Ggplot2LineLayerProcessor$format_x_value()Ggplot2LineLayerProcessor$generate_multiline_selectors()Ggplot2LineLayerProcessor$generate_selectors()Ggplot2LineLayerProcessor$generate_single_line_selector()Ggplot2LineLayerProcessor$get_group_column()Ggplot2LineLayerProcessor$get_layer()Ggplot2LineLayerProcessor$get_x_transformation()Ggplot2LineLayerProcessor$has_series_groups()Ggplot2LineLayerProcessor$line_layer_position()Ggplot2LineLayerProcessor$needs_reordering()Ggplot2LineLayerProcessor$normalize_point_values()Ggplot2LineLayerProcessor$panel_axis_labels()Ggplot2LineLayerProcessor$polyline_curve_count()Ggplot2LineLayerProcessor$recover_x_values()Ggplot2LineLayerProcessor$resolve_group_mapping()Ggplot2LineLayerProcessor$series_count()Ggplot2LineLayerProcessor$transform_x_values()
Ggplot2RocLayerProcessor$process()
Process the ROC layer
Usage
Ggplot2RocLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selectors (optional)
Returns
List with data, selectors, title, axes and type
Ggplot2RocLayerProcessor$as_rates()
Hand the rates back as numbers, inverting x when asked
The line processor stringifies x on the way out, because a line's x
may be a date or a category. A rate is neither, and the core does
arithmetic on it.
Usage
Ggplot2RocLayerProcessor$as_rates(data, inverted = FALSE)
Arguments
dataThe series list the line processor emitted
invertedWhether
xis specificity, to be read as1 - x
Returns
The series list with numeric rates
Ggplot2RocLayerProcessor$attach_thresholds()
Attach each point's decision threshold, when the layer carries one
A threshold column survives the build only for a maidr_roc()
layer, whose geom names the aesthetic. The line processor drops the
rows whose y is NA and splits the rest by group in the group's own
order, so the same filter and split here put the thresholds back
beside the points they were scored at. A series whose count disagrees
– a row the line processor dropped for a reason other than NA y –
gets no thresholds rather than the wrong ones.
Usage
Ggplot2RocLayerProcessor$attach_thresholds(data, built, panel_id = NULL)
Arguments
dataThe series list
builtBuilt plot data
panel_idPanel ID for faceted plots (optional)
Returns
The series list, with threshold on each point that has one
Ggplot2RocLayerProcessor$attach_areas()
Attach the declared area to the first point of each curve
maidr_roc(auc = ) names one area per curve. A named vector is
matched to the series by their names; an unnamed one is taken in
series order when it has one entry per series. Anything else is left
out rather than guessed, and the core measures the area from the
points instead.
Usage
Ggplot2RocLayerProcessor$attach_areas(data, layer)
Arguments
dataThe series list
layerThe layer being read
Returns
The series list, with auc on each curve's first point
Ggplot2RocLayerProcessor$rows_read()
The built rows the line processor emitted points for
The same panel filter and NA-y filter extract_data() applies, so
that a column read off these rows lines up with the emitted points.
Usage
Ggplot2RocLayerProcessor$rows_read(built, panel_id = NULL)
Arguments
builtBuilt plot data
panel_idPanel ID for faceted plots (optional)
Returns
The rows, or NULL when the layer built none
Ggplot2RocLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2RocLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Rug Layer Processor
Description
Reads geom_rug() as the observations it marks.
A rug draws one short tick per row against the edge of the panel. What it
states is the raw data – which is exactly what the density curve or
histogram it usually accompanies does not. Until #222 the layer reached
Ggplot2UnknownLayerProcessor: a rug-only chart emitted one empty layer
and a rug beside a scatter added an empty one a reader could land on and
find nothing in.
Read as points, which is the reading py-maidr settled on for
seaborn.rugplot (xability/py-maidr#250). length is one number for the
whole layer, so a tick's length is decoration and only its position is
data – the same argument the event-plot reading makes about its ticks. The
coordinate across the tick is emitted as a constant rather than as the
tick's own base, because that base is a fraction of the panel and would
read as data at whatever scale the other axis happens to use.
One layer per axis
geom_rug() defaults to sides = "bl", so on a chart with both aesthetics
mapped it marks both – and the built data carries both columns. So this
emits up to two layers: the x observations and the y observations.
Not one per drawn grob. sides = "trbl" draws the same x observations at
top and bottom, and emitting that twice would have a reader navigate the
same numbers under two names. Measured on four rows:
sides="b" GRID.segments.1 : x (n=4) sides="l" GRID.segments.41 : y (n=4) sides="bl" GRID.segments.78 : x (n=4) GRID.segments.79 : y (n=4) sides="trbl" .116: x .117: x .118: y .119: y
A side is drawn only where the matching aesthetic exists – sides = "bl"
with only aes(x = v) gives one grob – so the layers follow the built
data's columns rather than a parse of the sides string.
Super class
LayerProcessor -> Ggplot2RugLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_data()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2RugLayerProcessor$process()
Process the rug layer
Usage
Ggplot2RugLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for patchwork leaves and facets
Returns
A single layer, or a multi_layer result carrying two
Ggplot2RugLayerProcessor$layer_rows()
This layer's rows of the built data
Not LayerProcessor$get_layer_built_data(), and the difference is
the point rather than an oversight. That method falls back to all
panels' rows when the panel-scoped subset comes back empty, and a rug
is a chart where an empty subset is real: a facet_grid() cell that
no row falls in draws no ticks. Measured on a grid with two populated
cells of two ticks each –
panel 1 -> layer_rows: 2 get_layer_built_data: 2 panel 2 -> layer_rows: 0 get_layer_built_data: 4 panel 3 -> layer_rows: 0 get_layer_built_data: 4 panel 4 -> layer_rows: 2 get_layer_built_data: 2
– so the inherited helper would have the two empty panels each
announce all four observations, drawn in the other two. An empty
subset is returned as it is, and process() reads it as the "no
layer" it is.
Written down because the two look interchangeable and are not:
swapping this for the inherited helper is a one-line simplification
that reintroduces the bug silently.
test-ggplot2-rug.R pins the panel that draws nothing.
Usage
Ggplot2RugLayerProcessor$layer_rows(built, panel_id = NULL)
Arguments
builtBuilt plot data
panel_idPanel ID for faceted plots (optional)
Returns
A data frame, or NULL
Ggplot2RugLayerProcessor$marked_axes()
Which axes this rug actually marks
Both halves are needed, and measuring showed why. The built data's
columns are not enough on their own: geom_rug(sides = "b") on
aes(v, w) carries a y column and draws no left rug, and reading
the columns alone emitted a y layer for observations the chart never
marked – a whole layer invented out of an aesthetic that was mapped
for the scatter underneath.
sides is not enough either, in the other direction: it defaults to
"bl" on every rug, and one drawn over aes(x = v) alone has no y
to mark. So a side counts only where both agree, which is exactly
what the drawing does – measured, sides = "bl" gives two grobs
with both aesthetics mapped and one with only x.
Usage
Ggplot2RugLayerProcessor$marked_axes(rows, layer)
Arguments
rowsThis layer's rows of the built data
layerThis layer, for its
sides
Returns
A character vector, a subset of c("x", "y"), in that order
Ggplot2RugLayerProcessor$axis_layer()
One axis' observations as a point layer
Usage
Ggplot2RugLayerProcessor$axis_layer( plot, layout, rows, axis, gt, panel_ctx, built = NULL, panel_id = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
rowsThis layer's rows of the built data
axis"x"or"y"gtGtable object
panel_ctxPanel context for patchwork leaves and facets
builtBuilt plot data, for the axis bounds
panel_idPanel ID for faceted plots (optional)
Returns
A layer list
Ggplot2RugLayerProcessor$axis_labels()
Name the axes, calling the strip the ticks sit in what it is
The axis carrying the observations keeps the chart's own label. The
one across the ticks is renamed even where the caller labelled it: a
rug under a density curve has a real "density" label on that axis,
and every entry this layer emits sits at 0 rather than at any
density.
Both carry bounds as well, and that is what makes the layer reachable
in grid mode – the only mode where a point layer renders braille at
all. Measured against maidr's ScatterTrace: with the labels alone
the braille state comes back empty, and a rug is then the one chart
with no braille surface reachable by any keystroke. With them, four
observations at 1, 2, 3 and 9 over a 0-10 axis give
values [[2, 1, 0, 1]] – the observation count per cell, which is
the clustering a rug is drawn to show and the one thing its audio
cannot carry, every tick sitting at the same place on the axis pitch
is mapped from (xability/maidr#1132).
The observation axis takes the chart's own bounds, through the same
axis_grid_info() the point processor reads, and is declined on the
same grounds. The axis across the ticks is supplied whole as 0 to 1
in one step: a rug is one row deep by construction, and a finer step
buys a second row of zeroes – measured, tickStep 0.5 gives
[[2, 1, 0, 1], [0, 0, 0, 0]].
Additive only: grid mode is entered deliberately, and the ordinary reading is untouched.
Usage
Ggplot2RugLayerProcessor$axis_labels( layout, axis, built = NULL, panel_id = NULL )
Arguments
layoutLayout information
axis"x"or"y"builtBuilt plot data, for the observation axis' bounds
panel_idPanel ID for faceted plots (optional)
Returns
An axes list
Ggplot2RugLayerProcessor$generate_selectors()
Address each tick by the element it was drawn as
geom_rug() draws one segmentsGrob per side, and gridSVG exports
that as one element per segment carrying an id of the form
<grob>.1.<n> – the shape #194 measured for geom_segment(), whose
GRID.segments.38.1.1 through .4 follow built-data order.
The grob cannot be found by name: ggplot2 gives a rug layer no geom
prefix, so it arrives as grid's automatic GRID.segments.N, whose
number is a global counter and not stable between sessions. It is
located by class and by position instead, and read off the gtable
being exported rather than reconstructed.
Where a rug draws one axis twice – sides = "tb", or "trbl" –
the first grob for that axis is addressed. The two are copies of one
observation, so highlighting one of them is partial; highlighting
neither is worse, and #145 settled that a selector list which does not
match the point count is withdrawn wholesale rather than applied in
part. An empty list is returned when the grob cannot be resolved, for
that same reason: a guess at its name is worse than no highlighting.
Usage
Ggplot2RugLayerProcessor$generate_selectors( plot, gt, axis, count, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
gtGtable object
axis"x"or"y"countHow many ticks this layer emits
panel_ctxPanel context for patchwork leaves and facets
Returns
A list of CSS selectors, one per tick
Ggplot2RugLayerProcessor$find_segments_name()
The grob holding this layer's ticks for one axis
geom_rug() wraps its grobs in a gTree of its own – measured, a
sides = "bl" rug gives GRID.gTree.3 holding GRID.segments.1 and
GRID.segments.2, and two rug layers give two such trees in layer
order. So one layer's grobs arrive as a block already, and there is
nothing to slice.
That wrapping is also what tells a rug from its neighbours.
geom_segment() draws a bare segments grob directly under the
panel:
rug + segment GRID.segments.117 <- the segment layer
GRID.gTree.120
GRID.segments.118 <- the rug, x
GRID.segments.119 <- the rug, y
So a candidate is a directly-held gTree with grid's automatic name
whose children are every one a segments grob, and the nth of those
belongs to the nth rug layer. Matching on the name is necessary as
well as the class: a layer ggplot2 does name arrives with its geom's
prefix, and one of those is not a rug whatever it holds.
Which axis a grob stands on it answers itself: a tick standing on x
is held constant in y, so y0 is a single recycled value while
x0 carries one entry per observation. The same property py-maidr's
read_rug uses, and it needs no reference to sides.
Where a rug draws one axis twice – sides = "tb", or "trbl" –
the first grob for that axis wins. The two are copies of one
observation, so highlighting one of them is partial; highlighting
neither is worse, and #145 settled that a selector list which does not
match the point count is withdrawn wholesale rather than in part.
Usage
Ggplot2RugLayerProcessor$find_segments_name(plot, gt, axis, panel_ctx = NULL)
Arguments
plotThe ggplot2 object
gtGtable object
axis"x"or"y"panel_ctxPanel context for patchwork leaves and facets
Returns
The grob name, or NULL when it cannot be resolved
Ggplot2RugLayerProcessor$position_among_rugs()
This layer's place among the plot's rug layers
Counted among its own kind, so a second geom_rug() reaches its own
grobs rather than the first one's – the rule
Ggplot2GanttLayerProcessor$find_segments_name() applies, for the
same reason.
Usage
Ggplot2RugLayerProcessor$position_among_rugs(plot)
Arguments
plotThe ggplot2 object
Returns
The 1-based position, or NULL when the layer cannot be found
Ggplot2RugLayerProcessor$rug_trees()
The panel's rug wrappers, in drawing order
Usage
Ggplot2RugLayerProcessor$rug_trees(gt, panel_ctx = NULL)
Arguments
gtGtable object
panel_ctxPanel context for patchwork leaves and facets
Returns
A list of gTrees
Ggplot2RugLayerProcessor$wraps_a_rug()
Whether a grob is one rug layer's wrapper
Usage
Ggplot2RugLayerProcessor$wraps_a_rug(node)
Arguments
nodeA grob
Details
The name test is a guard rather than a live branch, and is kept as
one deliberately. Measured across every geom that draws segments –
boxplot, violin, errorbar, crossbar, pointrange, linerange, step, a
reference line – none produces a gTree whose children are all
segments, so today the class test alone decides and dropping the name
test changes no reading. test-ggplot2-rug.R pins that measurement,
so the ggplot2 release that ends it turns a test red rather than
leaving this silently load-bearing.
Returns
TRUE when it is a GRID.gTree of nothing but segments
Ggplot2RugLayerProcessor$axis_of()
Which axis one segments grob's ticks stand on
Usage
Ggplot2RugLayerProcessor$axis_of(grob)
Arguments
grobA
segmentsgrob
Returns
"x", "y", or NA when it says neither
Ggplot2RugLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2RugLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Smooth Layer Processor
Description
Processes smooth plot layers with complete logic included
Super class
LayerProcessor -> Ggplot2SmoothLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2SmoothLayerProcessor$process()
Process the layer: read its curves, selectors and axes from the built plot
Usage
Ggplot2SmoothLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List describing the layer for the MAIDR payload
Ggplot2SmoothLayerProcessor$layer_computes_interval()
Whether this layer's ymin/ymax are an
interval at all.
Asked of the stat, never of the columns, because the columns lie.
This processor serves StatSmooth and StatDensity alike,
and both emit ymin/ymax while meaning different things:
StatSmooth computes the confidence bounds around the fit, but
StatDensity sets ymin = 0 and ymax = density –
the extent of the fill, not an uncertainty. Measured on a three-group
geom_density(): all 1536 rows carry finite bounds running from
zero to the curve.
Reading those as an interval would announce every density curve as having a confidence band from zero, which is a claim about the data rather than a missing feature – the worse of the two failures, and the one this guard exists to prevent.
Usage
Ggplot2SmoothLayerProcessor$layer_computes_interval(plot)
Arguments
plotThe ggplot2 object
Returns
TRUE when the layer's stat computes an interval
Ggplot2SmoothLayerProcessor$group_aes()
Grouping aesthetics that split this layer into curves.
geom_smooth() and geom_density() both render a fill, so
aes(fill = g) splits them into one curve per group just as
aes(colour = g) does. The line processor probes colour only,
because a line has no fill and reading one from an unrelated layer's
mapping would invent a legend the plot never draws.
Ggplot2Adapter types a layer as smooth for
GeomSmooth or for any layer whose stat is StatDensity.
A default geom_area() uses StatAlign and so never
arrives here, but geom_area(stat = "density") does, and splits
per group like the others.
Usage
Ggplot2SmoothLayerProcessor$group_aes()
Returns
List of aesthetic-name vectors, in precedence order
Ggplot2SmoothLayerProcessor$attach_group_axis()
Add the legend title as the z axis label when the layer is split into per-group curves.
Shared with the line layer processor via
attach_series_group_axis(); see R/series_group_utils.R.
Usage
Ggplot2SmoothLayerProcessor$attach_group_axis(plot, built, data, axes)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
dataThe extracted layer data
axesAxes built so far
Returns
The axes list, with z added when the layer is grouped
Ggplot2SmoothLayerProcessor$resolve_target_layer()
Resolve which layer of the plot this processor describes.
Prefers this processor's OWN layer: picking the first line-like layer would extract another layer's data in multi-layer plots (e.g. geom_line + geom_smooth).
Usage
Ggplot2SmoothLayerProcessor$resolve_target_layer(plot)
Arguments
plotThe ggplot2 object
Returns
Index into plot$layers
Ggplot2SmoothLayerProcessor$layer_built_data()
Built data for this layer, restricted to one facet panel.
Usage
Ggplot2SmoothLayerProcessor$layer_built_data( plot, built = NULL, panel_id = NULL )
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
Returns
A data frame of built rows
Ggplot2SmoothLayerProcessor$series_group_ids()
Distinct group ids when the layer draws more than one curve.
Usage
Ggplot2SmoothLayerProcessor$series_group_ids(built_data)
Arguments
built_dataBuilt rows for this layer
Returns
Sorted group ids, or an empty vector for a single-curve layer
Ggplot2SmoothLayerProcessor$extract_data()
Extract one series per drawn curve.
ggplot2 draws a mapped smooth as one curve per group, so the payload has to be split the same way: concatenating the groups into a single series would walk a reader off the end of one curve into the start of the next with nothing announced in between.
Usage
Ggplot2SmoothLayerProcessor$extract_data(plot, built = NULL, panel_id = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
Returns
List of series, each a list of points
Ggplot2SmoothLayerProcessor$curve_points()
Turn built rows into MAIDR points.
Usage
Ggplot2SmoothLayerProcessor$curve_points(rows, z = NULL)
Arguments
rowsBuilt rows for one curve
zSeries name, or NULL for a single-curve layer
Returns
List of points
Ggplot2SmoothLayerProcessor$attach_interval()
Keep this layer's ymin/ymax only when they
are an uncertainty, and put them in the space the reader is shown.
The columns are dropped rather than ignored, so curve_points()
can key on their presence instead of re-asking the stat per sample.
Usage
Ggplot2SmoothLayerProcessor$attach_interval( built_data, plot, built = NULL, panel_id = NULL )
Arguments
built_dataThis layer's built rows
plotThe ggplot2 object
builtBuilt plot data
panel_idPanel ID for faceted plots (optional)
Returns
built_data, with the interval untransformed or removed
Ggplot2SmoothLayerProcessor$generate_selectors()
The selector for the polyline this layer drew, or none when it cannot be found (see the note above)
Usage
Ggplot2SmoothLayerProcessor$generate_selectors( plot, gt = NULL, panel_ctx = NULL, built = NULL, panel_id = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
Returns
List of selectors
Ggplot2SmoothLayerProcessor$own_curve_grob()
The polyline grob ggplot2 drew for THIS layer's curve.
A curve layer leaves its grob in one of two shapes, and which one decides how it can be found again:
-
geom_smooth()andgeom_density()wrap theirs in a tree named after the geom (geom_smooth.gTree.N), so the layer's own polylines are exactly the ones inside it. The last is the fitted line: ggplot2 draws the confidence band first, and within one layer that ordering does hold. -
geom_function()draws a bare polyline –GeomFunctioninheritsGeomPath$draw_panel()and gets no tree of its own – so it is indistinguishable by name from ageom_line()'s, and only its draw-order position among the other bare polylines identifies it. That is the questionfind_layer_polyline_grob()already answers for the line and contour processors.
Usage
Ggplot2SmoothLayerProcessor$own_curve_grob(plot, gt, panel_ctx = NULL)
Arguments
plotThe ggplot2 object
gtGtable object
panel_ctxPanel context for panel-scoped selector generation
Returns
The grob, or NULL when this layer's curve cannot be identified
Ggplot2SmoothLayerProcessor$series_group_count()
Number of curves this layer draws in the given panel.
Never throws: selector generation has to degrade to the single-curve
path for inputs extract_data() would reject.
Usage
Ggplot2SmoothLayerProcessor$series_group_count( plot, built = NULL, panel_id = NULL )
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
Returns
Number of groups, or 0 when the layer draws a single curve
Ggplot2SmoothLayerProcessor$grouped_curve_selectors()
One selector per curve for a layer split into groups.
ggplot2 draws a grouped smooth one group at a time, so the layer's grob
tree holds an equal run of children per group: a bare polyline for
se = FALSE, a ribbon gTree followed by a polyline for
se = TRUE, and a ribbon gTree alone for geom_density().
Chunking the children by group and taking the last polyline in each
chunk applies the same "the curve is the last polyline drawn" rule the
single-curve path uses, once per group instead of once per layer.
Usage
Ggplot2SmoothLayerProcessor$grouped_curve_selectors( plot, gt, panel_ctx, n_series )
Arguments
plotThe ggplot2 object
gtGtable object
panel_ctxPanel context for panel-scoped selector generation
n_seriesNumber of curves the layer draws
Returns
List of selectors, or NULL when the grob tree does not line up
Ggplot2SmoothLayerProcessor$polyline_grob_names()
Names of the curve polyline grobs inside a grob, in draw
order. Panel grid lines are excluded: they are named after the theme
element (panel.grid.major.x..polyline.N), not GRID.polyline.N.
Usage
Ggplot2SmoothLayerProcessor$polyline_grob_names(grob)
Arguments
grobA grob to walk
Returns
Character vector of grob names
Ggplot2SmoothLayerProcessor$find_layer_grob_tree()
Find the grob tree ggplot2 drew for this layer.
Defers to the base walk and supplies the one thing this processor does
differently: which layer to look for. resolve_target_layer() may
answer a layer other than this processor's own, which is why the target
cannot simply be the layer index the base class would use.
Usage
Ggplot2SmoothLayerProcessor$find_layer_grob_tree( plot, gt, panel_ctx = NULL, target = NULL )
Arguments
plotThe ggplot2 object
gtGtable object
panel_ctxPanel context for panel-scoped selector generation
targetIndex of the layer to find; resolved when absent
Returns
The matching grob, or NULL
Ggplot2SmoothLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2SmoothLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Stacked Bar Layer Processor
Description
Processes stacked bar plot layers with complete logic included
Super class
LayerProcessor -> Ggplot2StackedBarProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2StackedBarProcessor$process()
Process the layer: read its series, selectors and the fill legend title from the built plot
Usage
Ggplot2StackedBarProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List describing the layer for the MAIDR payload
Ggplot2StackedBarProcessor$needs_reordering()
Whether the plot data must be reordered before drawing, so the emitted order matches the drawn rects
Usage
Ggplot2StackedBarProcessor$needs_reordering()
Returns
TRUE
Ggplot2StackedBarProcessor$reorder_layer_data()
Reorder the plot data by category and fill so the emitted rows match the drawn rects
Usage
Ggplot2StackedBarProcessor$reorder_layer_data(data, plot)
Arguments
dataThe data frame ggplot2 will draw from
plotThe ggplot2 object
Returns
The reordered data frame
Ggplot2StackedBarProcessor$extract_plot_columns()
The column names the plot maps to x, y and fill
Usage
Ggplot2StackedBarProcessor$extract_plot_columns(plot)
Arguments
plotThe ggplot2 object
Returns
List with category_col, value_col and fill_col
Ggplot2StackedBarProcessor$extract_data()
One series per fill level, restricted to the panel's rows under faceting
Usage
Ggplot2StackedBarProcessor$extract_data( plot, built = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List of series
Ggplot2StackedBarProcessor$generate_selectors()
One flat selector matching every rect in the layer, which is the contract the frontend expects (see the note above)
Usage
Ggplot2StackedBarProcessor$generate_selectors( plot, gt = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List holding one selector
Ggplot2StackedBarProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2StackedBarProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
ggplot2 Step Layer Processor
Description
Processes geom_step() layers. A step chart is piecewise constant: the
value is held across an interval and then jumps, rather than being
interpolated between samples the way a line implies. The canonical case is
a hypnogram – an ordinal sleep stage (Awake / REM / N1 / N2 / N3) against
time.
Everything about extracting x/y and locating the rendered polyline is the
same as for a line, so this class inherits Ggplot2LineLayerProcessor and
adds only what a step layer has that a line layer does not:
-
stepDirection– thehv/vh/midconvention the layer was drawn with, emitted as a sibling ofaxesanddataon the layer. a per-point
label– the name of the ordinal level, so the frontend announces "REM" rather than the numeric level code that encodes it.ystays numeric because it drives sonification, braille and the min/max range.
One data point is emitted per data sample, never one per stairstep
vertex. ggplot2 expands the stairsteps inside GeomStep$draw_panel(), so
the rendered polyline carries 2n - 1 vertices (hv / vh) or 2n
(mid) for n samples; the MAIDR frontend's StepTrace maps those
vertices back onto the samples. Emitting vertex-level data to "match" the
polyline would double every level and misreport transitions and run
lengths.
Super classes
LayerProcessor -> Ggplot2LineLayerProcessor -> Ggplot2StepLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()Ggplot2LineLayerProcessor$attach_discrete_y_names()Ggplot2LineLayerProcessor$attach_group_axis()Ggplot2LineLayerProcessor$attach_level_labels()Ggplot2LineLayerProcessor$build_level_lookup()Ggplot2LineLayerProcessor$curve_selectors()Ggplot2LineLayerProcessor$extract_data()Ggplot2LineLayerProcessor$extract_layer_axes()Ggplot2LineLayerProcessor$extract_multiline_data()Ggplot2LineLayerProcessor$extract_single_line_data()Ggplot2LineLayerProcessor$find_main_polyline_grob()Ggplot2LineLayerProcessor$format_x_value()Ggplot2LineLayerProcessor$generate_multiline_selectors()Ggplot2LineLayerProcessor$generate_selectors()Ggplot2LineLayerProcessor$generate_single_line_selector()Ggplot2LineLayerProcessor$get_group_column()Ggplot2LineLayerProcessor$get_layer()Ggplot2LineLayerProcessor$get_x_transformation()Ggplot2LineLayerProcessor$has_series_groups()Ggplot2LineLayerProcessor$line_layer_position()Ggplot2LineLayerProcessor$needs_reordering()Ggplot2LineLayerProcessor$normalize_point_values()Ggplot2LineLayerProcessor$panel_axis_labels()Ggplot2LineLayerProcessor$polyline_curve_count()Ggplot2LineLayerProcessor$recover_x_values()Ggplot2LineLayerProcessor$resolve_group_mapping()Ggplot2LineLayerProcessor$series_count()Ggplot2LineLayerProcessor$transform_x_values()
Ggplot2StepLayerProcessor$process()
Process the step layer.
Usage
Ggplot2StepLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selectors (optional)
Returns
List with data, selectors, title, axes, type and stepDirection
Ggplot2StepLayerProcessor$in_drawn_order()
Put this layer's built rows into the order they are drawn in, dropping any row that is not a point.
Both halves come from one fact: GeomStep does not draw the rows
it is handed. GeomStep$draw_panel() calls
ggplot2:::stairstep(), whose first act is
data[order(data$x), ] – so the drawn staircase is the
sorted rows, whatever order the stat returned them in. Sorting
here recovers what is on screen rather than imposing a new order, and
an already-sorted layer – which is every geom_step() written by
hand – is unchanged.
StatEcdf is why this is needed at all. It returns its rows in
input order and pads them with -Inf / Inf for the two
ends of the staircase. Measured on n = 20: 22 rows, two of them
infinite, unsorted. Those two rows are not observations – there is no
x to announce for them – and an infinity in the payload is worse than
a dropped point in both bindings: jsonlite writes it as the
string "-Inf", and json.dumps on the Python side
writes a bare -Infinity that JSON.parse rejects outright
(xability/py-maidr#427).
Ordered within PANEL and group, not globally, because
draw_panel() is called once per panel per group – a grouped
ECDF is several staircases, and a global sort would interleave them
into one series that walks backwards at every seam.
The filter asks about x alone, and deliberately. A row with a
real x and a missing y is a different thing – it has a position and no
reading – and the line processor this class inherits already decides
those, for its own reason: it keeps the rows ggplot2 draws through,
dropping leading and trailing NA-y rows and announcing an interior one
as missing (line_drawn_span()). Repeating that here would be a second
filter with a second rationale over the same rows. Raised in review on
#169; the Python binding draws the same x-only line, and for the same
reason (xability/py-maidr#430).
Left alone when x is not numeric: the finiteness test is meaningless
there and is.finite() on a character vector is FALSE
throughout, which would delete every row.
Usage
Ggplot2StepLayerProcessor$in_drawn_order(built)
Arguments
builtBuilt plot data
Returns
built, with this layer's frame reordered and filtered
Ggplot2StepLayerProcessor$extract_step_direction()
Read the step convention this layer was drawn with.
geom_step(direction = ) is a formal of GeomStep$draw_panel(), so
ggplot2 files it under layer$geom_params$direction rather than
layer$aes_params or the layer's mapping. The three accepted values
("hv", "vh", "mid") are exactly MAIDR's, so they pass through
unchanged. "hv" is both ggplot2's and MAIDR's default.
Usage
Ggplot2StepLayerProcessor$extract_step_direction(plot)
Arguments
plotThe ggplot2 object
Returns
One of "hv", "vh", "mid" (defaulting to "hv"), or NULL when the layer cannot be located at all.
Ggplot2StepLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2StepLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Unknown Layer Processor
Description
Handles unsupported layer types gracefully by returning empty data
Super class
LayerProcessor -> Ggplot2UnknownLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$augment_plot()LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_augmentation()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2UnknownLayerProcessor$process()
Describe a layer nothing is known about
Usage
Ggplot2UnknownLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List with no data and no selectors
Ggplot2UnknownLayerProcessor$extract_data()
Nothing: an unknown layer has no data to announce
Usage
Ggplot2UnknownLayerProcessor$extract_data(plot, built = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
Returns
Empty list
Ggplot2UnknownLayerProcessor$generate_selectors()
Nothing: an unknown layer has no elements to address
Usage
Ggplot2UnknownLayerProcessor$generate_selectors( plot, gt = NULL, grob_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
Empty list
Ggplot2UnknownLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2UnknownLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Violin Layer Processor
Description
Processes violin layers (geom_violin) to extract density curve (KDE) data
and box-summary statistics, producing two maidr layers: violin_kde and
violin_box.
The processor injects a thin geom_boxplot(width = 0.1) into the plot
before rendering so that the SVG contains visible box elements whose
CSS selectors can drive the violin_box highlight in the maidr frontend.
Super class
LayerProcessor -> Ggplot2ViolinLayerProcessor
Methods
Public methods
Inherited methods
LayerProcessor$extract_layer_axes()LayerProcessor$find_layer_grob_tree()LayerProcessor$find_layer_polyline_grob()LayerProcessor$get_last_result()LayerProcessor$get_layer_built_data()LayerProcessor$get_layer_index()LayerProcessor$get_own_layer()LayerProcessor$initialize()LayerProcessor$is_flipped_layer()LayerProcessor$is_horizontal_call()LayerProcessor$layer_polyline_grobs()LayerProcessor$needs_reordering()LayerProcessor$other_geom_grob_prefixes()LayerProcessor$reorder_layer_data()LayerProcessor$resolve_panel_index()LayerProcessor$set_last_result()LayerProcessor$swap_point_axes()LayerProcessor$unflip_columns()LayerProcessor$unflip_panel_params()
Ggplot2ViolinLayerProcessor$needs_augmentation()
Violin needs to inject a boxplot layer
Usage
Ggplot2ViolinLayerProcessor$needs_augmentation()
Ggplot2ViolinLayerProcessor$augment_plot()
Inject geom_boxplot into the plot for visual box + selectors
Usage
Ggplot2ViolinLayerProcessor$augment_plot(plot)
Arguments
plotggplot2 object
Returns
Augmented ggplot2 object with boxplot layer added
Ggplot2ViolinLayerProcessor$process()
Process the violin layer
Returns a list with multi_layer = TRUE and two maidr layers:
violin_box (with BoxSelector objects) and violin_kde.
Usage
Ggplot2ViolinLayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object (already augmented with boxplot)
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_idPanel ID for faceted plots (optional)
panel_ctxPanel context for faceted plots (optional)
Returns
List with multi_layer flag and layers, or NULL for facet panels
Ggplot2ViolinLayerProcessor$extract_box_data()
Extract box-summary statistics per violin group
Computes min, Q1, median, Q3, max from the original data (since geom_violin only stores the KDE curve, not quartiles).
Usage
Ggplot2ViolinLayerProcessor$extract_box_data(plot, built)
Arguments
plotThe ggplot2 object
builtBuilt plot data
Returns
List of BoxPoint objects (one per violin)
Ggplot2ViolinLayerProcessor$extract_kde_data()
Extract KDE density-curve data per violin group
Uses ggplot2's built violin data (violinwidth, x, y, width columns)
to compute left/right violin edges, applies RDP simplification to
~30 points per violin, and includes the width field needed by the
maidr frontend. The svg_x/svg_y coordinates are injected later
by create_enhanced_svg() after the grid device is drawn.
Usage
Ggplot2ViolinLayerProcessor$extract_kde_data(plot, built, max_kde_points = 30L)
Arguments
plotThe ggplot2 object
builtBuilt plot data
max_kde_pointsMaximum number of output points per violin (default 30)
Returns
List of lists (ViolinKdePoint[][])
Ggplot2ViolinLayerProcessor$simplify_violin_kde()
Simplify a single violin's KDE curve using RDP
Uses ggplot2's built violin data columns (y, violinwidth, x, width) to compute the left/right edges, then applies RDP simplification.
Usage
Ggplot2ViolinLayerProcessor$simplify_violin_kde( rows, cat_label, is_horizontal, max_points = 30L )
Arguments
rowsdata.frame of built violin data for one group
cat_labelCharacter label for this violin category
is_horizontalLogical, TRUE for horizontal violins
max_pointsMaximum number of output points
Returns
List of ViolinKdePoint dicts with data_left_x/data_right_x/data_y
Ggplot2ViolinLayerProcessor$extract_data()
Not used directly - required by base class interface
Usage
Ggplot2ViolinLayerProcessor$extract_data(plot, built = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
Ggplot2ViolinLayerProcessor$generate_selectors()
Generate CSS selectors for violin polygons (for violin_kde layer)
Usage
Ggplot2ViolinLayerProcessor$generate_selectors( plot, gt = NULL, grob_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
gtGtable object
grob_idGrob ID (for faceted plots)
panel_ctxPanel context (for faceted plots)
Returns
List of CSS selector strings (one per violin)
Ggplot2ViolinLayerProcessor$generate_box_selectors()
Generate BoxSelector objects for the injected boxplot grobs
Walks the gtable to find geom_boxplot grobs and produces a BoxSelector list (one per violin) with CSS selectors for min, iq, q2, max, lowerOutliers, upperOutliers.
Usage
Ggplot2ViolinLayerProcessor$generate_box_selectors( plot, gt, built, panel_ctx = NULL )
Arguments
plotThe ggplot2 object (augmented with boxplot)
gtGtable object
builtBuilt plot data
panel_ctxPanel context (for patchwork leaves)
Returns
List of BoxSelector objects
Ggplot2ViolinLayerProcessor$determine_orientation()
Determine orientation from built data
Usage
Ggplot2ViolinLayerProcessor$determine_orientation(built)
Arguments
builtBuilt plot data (optional)
Ggplot2ViolinLayerProcessor$get_effective_mapping()
The violin layer's mapping merged with the plot's
Built in ggplot2's own order – the layer's own aesthetics first, then
whatever only the plot maps – because the order is not cosmetic.
ggplot2 numbers group from the interaction of a layer's discrete
columns taken in the order the mapping produced them, so a mapping
assembled the other way round gives the injected box different group
ids than the violin, and every lookup keyed on group then crosses
the two layers.
Usage
Ggplot2ViolinLayerProcessor$get_effective_mapping(plot)
Arguments
plotThe ggplot2 object
Returns
Named list of quosures, one per mapped aesthetic
Ggplot2ViolinLayerProcessor$discrete_axis_labels()
Break labels of whichever panel axis holds the categories
The categorical axis is the discrete one, which is not always the axis
the data is keyed on: coord_flip() leaves the data x-major while
moving the category labels to the y axis, so reading the axis off
flipped_aes alone returns the value axis' breaks and every violin is
labelled with a number.
Usage
Ggplot2ViolinLayerProcessor$discrete_axis_labels(built)
Arguments
builtBuilt plot data
Returns
Character vector of labels, or NULL when neither axis is discrete (a continuous category axis carries its value directly)
Ggplot2ViolinLayerProcessor$fill_levels_by_colour()
Map each mapped fill colour back to the level it came from
Dodging splits one category into several violins that differ only by fill, and they all round to the same category position. Without the level, they are announced under one repeated name and cannot be told apart.
Usage
Ggplot2ViolinLayerProcessor$fill_levels_by_colour(built)
Arguments
builtBuilt plot data
Returns
Named character vector (colour -> level), or NULL when the plot has no fill scale
Ggplot2ViolinLayerProcessor$group_labels()
Announceable label for each drawn violin
Usage
Ggplot2ViolinLayerProcessor$group_labels( built, layer_data, groups, is_horizontal )
Arguments
builtBuilt plot data
layer_dataBuilt data for the violin layer
groupsThe layer's group ids, in emission order
is_horizontalWhether the value axis is x
Returns
Character vector of labels, one per group
Ggplot2ViolinLayerProcessor$boxplot_stats()
Box statistics ggplot2 itself computed for each group
The processor injects a geom_boxplot() so the SVG has box elements to
highlight; that layer's stat_boxplot output is also the authoritative
source for the numbers to announce. Reading it keyed by group avoids
re-deriving quartiles from the original data via a rounded axis
position and a string match on the break label – a round trip that
silently mislabels dodged violins and finds nothing at all under
coord_flip().
Usage
Ggplot2ViolinLayerProcessor$boxplot_stats(plot, built)
Arguments
plotThe ggplot2 object
builtBuilt plot data
Returns
data.frame of the boxplot layer's built data, or NULL
Ggplot2ViolinLayerProcessor$find_boxplot_layer_index()
Find the boxplot layer index in the augmented plot
Usage
Ggplot2ViolinLayerProcessor$find_boxplot_layer_index(plot)
Arguments
plotThe ggplot2 object
Returns
Integer index of the boxplot layer, or NULL
Ggplot2ViolinLayerProcessor$find_panel_grob()
Find the panel grob this layer draws into
Usage
Ggplot2ViolinLayerProcessor$find_panel_grob(gt, panel_ctx = NULL)
Arguments
gtGtable object
panel_ctxPanel context for patchwork leaves; NULL for a single plot, where the panel is the cell literally named "panel"
Returns
The panel gTree, or NULL when it cannot be resolved
Ggplot2ViolinLayerProcessor$find_grob_ids()
Recursively find all grob IDs matching a pattern
Usage
Ggplot2ViolinLayerProcessor$find_grob_ids(grob, pattern)
Arguments
grobGrob tree to search
patternRegular expression matched against grob names
Returns
Character vector of unique matching grob names
Ggplot2ViolinLayerProcessor$find_direct_children()
Find direct children of a named parent matching a pattern
Usage
Ggplot2ViolinLayerProcessor$find_direct_children(grob, parent_id, pattern)
Arguments
grobGrob tree to search
parent_idName of the parent grob
patternRegular expression matched against child names
Returns
Character vector of matching child names
Ggplot2ViolinLayerProcessor$find_grob_by_id()
Find a grob by its name (recursive)
Usage
Ggplot2ViolinLayerProcessor$find_grob_by_id(grob, target_id)
Arguments
grobGrob tree to search
target_idName of the grob to find
Returns
The matching grob, or NULL
Ggplot2ViolinLayerProcessor$find_desc_by_pattern()
Find the first descendant matching a pattern under a named parent
Usage
Ggplot2ViolinLayerProcessor$find_desc_by_pattern(grob, parent_id, pattern)
Arguments
grobGrob tree to search
parent_idName of the parent grob
patternRegular expression matched against descendant names
Returns
The first matching name, or NULL
Ggplot2ViolinLayerProcessor$find_all_desc_by_pattern()
Find all descendants matching a pattern under a named parent
Usage
Ggplot2ViolinLayerProcessor$find_all_desc_by_pattern(grob, parent_id, pattern)
Arguments
grobGrob tree to search
parent_idName of the parent grob
patternRegular expression matched against descendant names
Returns
Character vector of matching descendant names
Ggplot2ViolinLayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
Ggplot2ViolinLayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
The aesthetics that split an uncertainty layer into series
Description
Probed in order, and each entry holds the spelling variants of ONE
aesthetic, which is the contract resolve_series_group_mapping()
documents. colour first because it is what a dodged interval chart is
almost always split by; group last, because an author who writes
aes(group = g) and nothing else has still said what the series are.
Usage
INTERVAL_GROUP_AES
Position classes that displace a point from where its data puts it
Description
PositionJitterdodge does not inherit from PositionJitter – both
descend straight from Position – so it has to be named rather than
caught by inheritance. Its dodge is removed along with its jitter, which is
correct for the same reason: the offset that separates hue groups is drawn
geometry, and the group itself is carried as an aesthetic, so nothing is
lost by putting the point back on its category.
Usage
JITTER_POSITION_CLASSES
Abstract Layer Processor Interface
Description
This is the abstract base class for all layer processors. It defines the interface that all layer processors must implement.
Public fields
layer_infoInformation about the layer
Methods
Public methods
LayerProcessor$new()
Initialize the layer processor
Usage
LayerProcessor$new(layer_info)
Arguments
layer_infoInformation about the layer
LayerProcessor$process()
Process the layer (MUST be implemented by subclasses)
Usage
LayerProcessor$process( plot, layout, built = NULL, gt = NULL, grob_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
layoutLayout information
builtBuilt plot data (optional)
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List with data and selectors
LayerProcessor$extract_data()
Extract data from the layer (MUST be implemented by subclasses)
Usage
LayerProcessor$extract_data(plot, built = NULL)
Arguments
plotThe ggplot2 object
builtBuilt plot data (optional)
Returns
Extracted data
LayerProcessor$generate_selectors()
Generate selectors for the layer (MUST be implemented by subclasses)
Usage
LayerProcessor$generate_selectors( plot, gt = NULL, grob_id = NULL, panel_ctx = NULL )
Arguments
plotThe ggplot2 object
gtGtable object (optional)
grob_idGrob ID for faceted plots (optional)
panel_ctxPanel context for panel-scoped selector generation (optional)
Returns
List of selectors
LayerProcessor$get_layer_built_data()
Read this layer's rows out of the built plot.
Scoped to one panel when asked. A faceted plot puts every panel's rows in one frame, so a layer that took all of them would describe the whole facet grid as one series.
Usage
LayerProcessor$get_layer_built_data(built, panel_id = NULL)
Arguments
builtBuilt plot data
panel_idPanel ID for faceted plots (optional)
Returns
A data frame of computed aesthetics, or NULL
LayerProcessor$resolve_panel_index()
Resolve which entry of built$layout$panel_params
describes a facet panel.
Panel parameters are stored in the row order of
built$layout$layout, so panel n is entry n. An
unfaceted plot (or an unusable id) resolves to the only panel there is.
Shared: the line processor asked this first and the gantt processor asks it to name its lanes, and two readings disagreeing about which panel they are describing is not a difference worth having.
Usage
LayerProcessor$resolve_panel_index(built, panel_id = NULL)
Arguments
builtBuilt plot data
panel_idPanel id for faceted plots (optional)
Returns
Integer index guaranteed to be in range
LayerProcessor$get_own_layer()
Resolve the plot layer this processor was built for.
Every processor knows its index and several need the layer itself –
for its geom, its position or its own data – so the lookup lives
here rather than being copied into each. Answers NULL rather than
erroring when the index does not resolve, since a caller that cannot
find its layer has a reading to fall back on and no crash to justify.
Usage
LayerProcessor$get_own_layer(plot)
Arguments
plotThe ggplot2 object
Returns
The layer, or NULL when the index does not resolve
LayerProcessor$find_layer_grob_tree()
Find the grob tree ggplot2 drew for this layer.
ggplot2 names a layer's grob after its geom
(geom_smooth.gTree.5), so the tree is located by that prefix
and, when the plot repeats the geom, by this layer's position among
the layers sharing it. Scoping to the layer's own tree is what keeps a
sibling layer's grobs out of whatever the caller counts inside it.
Lives here rather than on one processor because two now need it and
the walk is the same walk – the argument that moved
get_own_layer() and get_layer_built_data() here before
it. What differs between callers is only which layer they are looking
for, and that is the target argument; the smooth processor
passes a resolved index because it may describe a layer other than its
own, and everything else takes the default.
Usage
LayerProcessor$find_layer_grob_tree(plot, gt, panel_ctx = NULL, target = NULL)
Arguments
plotThe ggplot2 object
gtGtable object
panel_ctxPanel context for panel-scoped selector generation
targetIndex of the layer to find; defaults to this one's
Returns
The matching grob, or NULL
LayerProcessor$find_layer_polyline_grob()
The polyline grob ggplot2 drew for THIS layer.
Shared rather than owned by the line processor: GeomPath, GeomStep
and GeomContour all draw through a bare polylineGrob and so all
land in the same auto-named candidate list, which is exactly why one
answer to "which of them is mine" has to serve all three.
Usage
LayerProcessor$find_layer_polyline_grob(plot, panel_grob, target = NULL)
Arguments
plotThe ggplot2 object
panel_grobThe panel's grob tree
targetIndex of the layer to find; defaults to this one's
Returns
The matching grob, or NULL
LayerProcessor$layer_polyline_grobs()
Panel polylines that a line layer could have drawn.
GeomPath$draw_panel() returns a bare polylineGrob, so a
line layer's grob carries grid's auto-generated
GRID.polyline.N name with no geom prefix to match on – only
its draw-order position identifies it. Layers that DO name their grob
tree after their geom (geom_smooth.gTree.N) are skipped whole
via geom_grob_prefix(), the same helper the smooth processor
uses to scope itself to its own tree; without that, the smooth's
three curves are counted as line-layer polylines and shift every
position by three. Panel grid lines are named after the theme element
(panel.grid.major.x..polyline.N) and so never match.
Usage
LayerProcessor$layer_polyline_grobs(plot, panel_grob, target = NULL)
Arguments
plotThe ggplot2 object
panel_grobThe panel's grob tree
targetIndex of the layer whose polylines are wanted
Returns
List of grobs in draw order
LayerProcessor$other_geom_grob_prefixes()
Grob-name prefixes belonging to the plot's OTHER geoms.
This layer's own prefix is excluded so that a second layer sharing
the geom (two geom_line() calls) is still walked.
Usage
LayerProcessor$other_geom_grob_prefixes(plot, target = NULL)
Arguments
plotThe ggplot2 object
targetIndex of the layer whose prefix is the own one
Returns
Character vector of prefixes, possibly empty
LayerProcessor$needs_reordering()
Check if this layer needs reordering (OPTIONAL - default: FALSE)
Usage
LayerProcessor$needs_reordering()
Returns
Logical indicating if reordering is needed
LayerProcessor$reorder_layer_data()
Reorder layer data (OPTIONAL - default: no-op)
Usage
LayerProcessor$reorder_layer_data(data, plot)
Arguments
datadata.frame effective for this layer
plotfull ggplot object (for mappings)
Returns
Reordered data
LayerProcessor$augment_plot()
Augment the plot before building (OPTIONAL - default: no-op)
Called by the orchestrator before ggplot_build/ggplotGrob. Allows a processor to inject additional geom layers (e.g., a boxplot inside a violin) so they appear in the SVG and can be targeted by selectors.
Usage
LayerProcessor$augment_plot(plot)
Arguments
plotThe ggplot2 object to augment
Returns
The (possibly augmented) ggplot2 object
LayerProcessor$needs_augmentation()
Check if this processor needs to augment the plot
Usage
LayerProcessor$needs_augmentation()
Returns
Logical
LayerProcessor$get_layer_index()
Get layer index
Usage
LayerProcessor$get_layer_index()
Returns
Layer index
LayerProcessor$is_flipped_layer()
Is this layer drawn with its category axis running up y?
ggplot(df, aes(y = g, x = n)) + geom_col() is the ordinary spelling of
a horizontal bar chart. ggplot_build() marks such a layer
flipped_aes and swaps which computed column holds what, so a
processor that reads x as the category and y as the measure picks up
exactly the wrong pair unless it asks first (#162, #184, #186).
Lives here rather than on one processor because three of them need the same answer, and because a processor that never asks it goes wrong silently: both columns hold plausible values.
coord_flip() is a different thing and answers FALSE here. It
rotates the coordinate system and leaves flipped_aes alone, so the
data layout is genuinely unflipped.
Usage
LayerProcessor$is_flipped_layer(built = NULL)
Arguments
builtA
ggplot_build()result, orNULLwhen the caller has none – in which case the layer is treated as unflipped, since there is nothing to read the flag from.
Returns
TRUE when the category runs up the y axis.
LayerProcessor$unflip_columns()
Exchange a built layer's paired x and y columns
Swapping the pairs up front lets every branch downstream stay written against one arrangement rather than each learning to ask which way round it is – and a branch that forgot to ask would go wrong silently, since both columns hold plausible numbers.
Usage
LayerProcessor$unflip_columns(built_data)
Arguments
built_dataOne layer's built data.
Returns
The same frame with its x and y pairs exchanged.
LayerProcessor$is_horizontal_call()
Was this base R call drawn with horiz = TRUE?
The base R counterpart of is_flipped_layer(): barplot() takes
the orientation as an argument rather than marking the built layer, so
the answer is read back off the captured call.
Usage
LayerProcessor$is_horizontal_call(layer_info = NULL)
Arguments
layer_infoThe captured layer information, or
NULL.
Returns
TRUE when the bars run across the page.
LayerProcessor$unflip_panel_params()
Exchange a panel's x and y scales
So the break labels a processor reads come from the axis the categories
are actually drawn on. Both the scale objects and the flattened
x.labels/y.labels of older ggplot2 are swapped, since readers fall
back from one to the other.
Usage
LayerProcessor$unflip_panel_params(panel_params)
Arguments
panel_paramsOne entry of
built$layout$panel_params.
Returns
The same list with its x and y entries exchanged.
LayerProcessor$swap_point_axes()
Put a horizontal layer's category and measure in the fields the bar grammar reads them from.
Processors emit x = category, y = measure, which is the vertical
arrangement. A horizontal bar is read the other way round: MAIDR takes
x as the magnitude and y as the category when orientation is
"horz", so the pair has to be exchanged on the way out. Left
unexchanged, the core looks for a number and finds a category name –
no magnitude to pitch, and an announcement that pairs the category axis
with the measure and the measure axis with the category name (#184).
Only the bar family wants this, which is why it is a step a processor
opts into rather than something the orchestrator applies to every
horizontal layer. An error bar keeps its category in x at both
orientations and lets orientation swap only which axis labels the
reading is announced against; a box carries quantiles and has no axis
assignment to exchange at all.
Usage
LayerProcessor$swap_point_axes(data_points)
Arguments
data_pointsPoints in
x = category, y = measureform. A nested list – one series per element, as a grouped bar layer emits – is handled as well as a flat one.
Returns
The same points with x and y exchanged.
LayerProcessor$set_last_result()
Store the last processed result (used by orchestrator)
Usage
LayerProcessor$set_last_result(result)
Arguments
resultThe result to store
LayerProcessor$get_last_result()
Get the last processed result
Usage
LayerProcessor$get_last_result()
Returns
The last result
LayerProcessor$extract_layer_axes()
Extract axes labels for this specific layer
Returns axes in the canonical per-axis object schema:
list(x = list(label = "..."), y = list(label = "...")).
Bare strings, top-level format/min/max/tickStep/
fill/level, and any non-{x,y,z} keys are NOT permitted.
Usage
LayerProcessor$extract_layer_axes(plot, layout)
Arguments
plotThe ggplot object
layoutGlobal layout with fallback axes
Returns
Named list with x and y AxisConfig objects
LayerProcessor$clone()
The objects of this class are cloneable with this method.
Usage
LayerProcessor$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
How long a cached internet probe stays trusted, in seconds
Description
Five minutes: long enough that knitting a document with dozens of plots still probes at most once or twice, short enough that connectivity that changed under a long-lived session is picked up while the user is still looking at it.
Usage
MAIDR_INTERNET_CACHE_TTL
MAIDR JavaScript library version bundled with this package
Description
MAIDR JavaScript library version bundled with this package
Usage
MAIDR_VERSION
Plot System Registry
Description
Central registry for managing different plotting systems and their adapters. This registry allows dynamic registration and discovery of plotting systems and their associated adapters and processor factories.
Format
An R6 class
Methods
Public methods
PlotSystemRegistry$register_system()
Registered plotting systems
System adapters
Processor factories
Register a new plotting system
Usage
PlotSystemRegistry$register_system(system_name, adapter, processor_factory)
Arguments
system_nameName of the plotting system (e.g., "ggplot2", "base_r")
adapterAdapter instance for this system
processor_factoryProcessor factory instance for this system
PlotSystemRegistry$detect_system()
Detect which system can handle a plot object
Usage
PlotSystemRegistry$detect_system(plot_object)
Arguments
plot_objectThe plot object to check
Returns
System name if found, NULL otherwise
PlotSystemRegistry$get_adapter()
Get the adapter for a specific system
Usage
PlotSystemRegistry$get_adapter(system_name)
Arguments
system_nameName of the system
Returns
Adapter instance
PlotSystemRegistry$get_processor_factory()
Get the processor factory for a specific system
Usage
PlotSystemRegistry$get_processor_factory(system_name)
Arguments
system_nameName of the system
Returns
Processor factory instance
PlotSystemRegistry$get_adapter_for_plot()
Get the adapter for a plot object (auto-detect system)
Usage
PlotSystemRegistry$get_adapter_for_plot(plot_object)
Arguments
plot_objectThe plot object
Returns
Adapter instance
PlotSystemRegistry$get_processor_factory_for_plot()
Get the processor factory for a plot object (auto-detect system)
Usage
PlotSystemRegistry$get_processor_factory_for_plot(plot_object)
Arguments
plot_objectThe plot object
Returns
Processor factory instance
PlotSystemRegistry$list_systems()
List all registered systems
Usage
PlotSystemRegistry$list_systems()
Returns
Character vector of registered system names
PlotSystemRegistry$is_system_registered()
Check if a system is registered
Usage
PlotSystemRegistry$is_system_registered(system_name)
Arguments
system_nameName of the system
Returns
TRUE if registered, FALSE otherwise
PlotSystemRegistry$unregister_system()
Unregister a system
Usage
PlotSystemRegistry$unregister_system(system_name)
Arguments
system_nameName of the system to unregister
PlotSystemRegistry$clone()
The objects of this class are cloneable with this method.
Usage
PlotSystemRegistry$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
Processor Factory Base Class
Description
Abstract base class for creating processors specific to different plotting systems. Each plotting system should have its own factory implementation that creates the appropriate processors for different plot types.
Format
An R6 class
Methods
Public methods
ProcessorFactory$create_processor()
Abstract method to create a processor for a specific plot type
Usage
ProcessorFactory$create_processor(plot_type, plot_object)
Arguments
plot_typeThe type of plot (e.g., "bar", "line", "point")
plot_objectThe plot object to process
Returns
Processor instance for the specified plot type
ProcessorFactory$get_supported_types()
Abstract method to get list of supported plot types
Usage
ProcessorFactory$get_supported_types()
Returns
Character vector of supported plot types
ProcessorFactory$supports_plot_type()
Check if a plot type is supported by this factory
Usage
ProcessorFactory$supports_plot_type(plot_type)
Arguments
plot_typeThe plot type to check
Returns
TRUE if supported, FALSE otherwise
ProcessorFactory$get_system_name()
Get system name (should be overridden by subclasses)
Usage
ProcessorFactory$get_system_name()
Returns
System name string
ProcessorFactory$clone()
The objects of this class are cloneable with this method.
Usage
ProcessorFactory$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
What the axis across a rug's ticks is called
Description
Every entry a rug layer emits sits at the same place on that axis, so whatever the panel calls it measures nothing here. Named rather than left blank, and named the same thing py-maidr names it, so the two bindings announce one chart the same way.
Usage
RUG_AXIS_LABEL
Layer types whose frontend model reads selectors as ONE selector for
every mark
Description
In maidr.js 4.x the shape of selectors is a contract, not a
convenience. A plain string is handed to document.querySelectorAll()
and the matches are aligned to the layer's points in document order. An
ARRAY means something else for these types: one selector per data point
for bar and hist (src/model/bar.ts), a per-series grid for the
segmented bars and mosaic (src/model/segmented.ts), and nothing at all
for point and pie, whose models read layer.selectors as string
(src/model/scatter.ts, src/model/pie.ts). dot and lollipop are
built by the bar model; heat reads a string or a per-cell grid
(src/model/heatmap.ts). maidr.js 3.x read a one-element array as the
string it held, which is why every processor here that returns
list(selector) was fine until the bundle moved to 4.0 (#316).
Usage
SINGLE_SELECTOR_LAYER_TYPES
Details
Types NOT listed keep whatever shape their processor built, because their
models want the array: one selector per series for line, smooth,
step, area, roc and violin_kde, one per level for contour, one
per box for box and violin_box, one per tick for a rug, and error_bar,
gantt, word_cloud and candlestick accept either.
System Adapter Base Class
Description
Abstract base class for adapting different plotting systems to the unified maidr interface. Each plotting system (ggplot2, base R, lattice, etc.) should have its own adapter implementation.
Format
An R6 class
Public fields
system_nameName of the plotting system
Methods
Public methods
SystemAdapter$new()
Initialize the adapter
Usage
SystemAdapter$new(system_name)
Arguments
system_nameName of the plotting system
SystemAdapter$can_handle()
Abstract method to check if this adapter can handle a plot object
Usage
SystemAdapter$can_handle(plot_object)
Arguments
plot_objectThe plot object to check
Returns
TRUE if this adapter can handle the object, FALSE otherwise
SystemAdapter$create_orchestrator()
Abstract method to create an orchestrator for this system
Usage
SystemAdapter$create_orchestrator(plot_object)
Arguments
plot_objectThe plot object to process
Returns
Orchestrator instance specific to this system
SystemAdapter$clone()
The objects of this class are cloneable with this method.
Usage
SystemAdapter$clone(deep = FALSE)
Arguments
deepWhether to make a deep clone.
The Suggests packages whose plotting entry point maidr wraps
Description
Named by package, valued by the function. Each is wrapped into maidr's
own namespace when the package loads (the onLoad hooks below), so a
bare call reaches the wrapper only while package:maidr sits ahead of
the package on the search path. Attached after maidr, the package masks
the wrapper and its calls go unrecorded; see package_masks_maidr().
Usage
WRAPPED_SUGGESTS
Convert Accuracy to Decimal Places
Description
Converts the scales package accuracy parameter to a decimal count.
For example, accuracy = 0.01 becomes decimals = 2.
Usage
accuracy_to_decimals(accuracy)
Arguments
accuracy |
The accuracy value (e.g., 0.01 for 2 decimal places) |
Value
Integer number of decimal places
Add maidr-data to SVG using proper XML manipulation
Description
Add maidr-data to SVG using proper XML manipulation
Usage
add_maidr_data_to_svg(svg_content, maidr_data)
Arguments
svg_content |
Character vector of SVG lines |
maidr_data |
The maidr-data structure |
Value
Modified SVG content
Reposition chartSeries date-range bracket header to prevent clipping
Description
quantmod::chartSeries() renders a bracketed date-range header
(e.g. "[2024-01-12/2024-01-15]") via base R title() with par(adj=1).
For short timeseries the text width exceeds the available right margin
and the closing bracket is clipped at the SVG viewBox edge. This is
upstream quantmod issue #129 (open since 2016, no fix). See
chartSeries.chob.R lines 205-209 for the hardcoded placement.
Usage
adjust_chartseries_bracket(svg_content, maidr_data)
Arguments
svg_content |
Character vector of SVG lines |
maidr_data |
The maidr-data structure (read-only; used to detect candlestick layers) |
Details
Earlier we tried CSS overflow: visible, but that re-exposes
chartSeries' intentionally negative-y volume <rect>s which rely on
the SVG root's default overflow: hidden for clipping. Further canvas
enlargement is impractical: the header is anchored at ~91% of canvas
width regardless of total width, so even 24-inch canvases would still
leave the header riding the right edge.
This helper performs surgical SVG post-processing on the exported
gridSVG output: it locates the bracket text element by content pattern,
switches its text-anchor to end, and snaps its x coordinate to
95% of the viewBox width. The text then right-aligns within the
viewBox regardless of header length.
Safety: this is a no-op when maidr_data contains no candlestick
layers (ggplot candlestick / non-candlestick plots), when xml2 is
unavailable, when the SVG fails to parse, when the viewBox cannot be
read, or when no element matches the bracket pattern.
Value
Modified SVG content (character vector). If any guard fails,
returns svg_content unchanged.
Document-level implementation of adjust_chartseries_bracket()
Description
Mutates svg_doc in place.
Usage
adjust_chartseries_bracket_doc(svg_doc)
Arguments
svg_doc |
Parsed SVG document (xml2) |
Value
TRUE if the document was modified
Say, as a package is attached, that it now masks a maidr wrapper
Description
Run from the attach hooks below. By then the package sits ahead of maidr
on the search path, so this is the moment to tell the user that bare
calls to its entry point will no longer be recorded. Silent when the
package does not mask, and under maidr.startup_message = FALSE.
Usage
announce_masking(package)
Arguments
package |
Name of the package, as in WRAPPED_SUGGESTS. |
Apply modular patches to barplot arguments
Description
Apply modular patches to barplot arguments
Usage
apply_barplot_patches(args)
Arguments
args |
List of arguments passed to barplot |
Value
Modified arguments with applied patches
Apply sorting logic to barplot arguments for consistent visual ordering
Description
Apply sorting logic to barplot arguments for consistent visual ordering
Usage
apply_barplot_sorting(args)
Arguments
args |
List of arguments passed to barplot |
Value
Modified arguments with sorted matrix data
Normalize a single axis value into AxisConfig shape
Description
Accepts legacy or partial inputs (bare string label, already-wrapped list, or NULL) and returns either NULL (when nothing to emit) or a named list conforming to the AxisConfig schema.
Usage
as_axis_config(value)
Arguments
value |
Raw axis input (string, list, or NULL) |
Value
A named list (AxisConfig) or NULL
Return a withVisible() result with the visibility it recorded
Description
The wrappers used to return everything invisibly, so par("mar") printed
nothing once maidr was attached and hist(x, plot = FALSE) had to be
wrapped in print() to be seen.
Usage
as_drawn(result)
Arguments
result |
A list from |
Value
The value, invisibly when the original call made it so
Attach a format object to a specific axis
Description
Mutates a single axis's format field. Creates the axis slot
(with label = default_label) if it does not exist. No-ops when
format_obj is NULL.
Usage
attach_axis_format(axes, which, format_obj, default_label = NULL)
Arguments
axes |
Canonical axes list |
which |
Axis key: one of |
format_obj |
AxisFormat list (or NULL) |
default_label |
Label to use if the axis slot is being created. NULL (the default) creates the slot without one, so attaching a format to an axis whose processor had no title to give does not put an empty label back in front of the renderer's generic. |
Value
The mutated axes list
Add the legend title as the z axis label for a grouped layer
Description
A grouped layer emits a per-series z value (the group's name), and
MAIDR announces it as "<z label> is <z value>". Without a z label the
frontend falls back to the generic word "Group", losing the legend title the
plot actually shows. Single-series layers emit no z value at all, so they
get no z label either.
Usage
attach_series_group_axis(
axes,
plot,
built,
data,
layer_index = NULL,
aes_groups = list(c("colour", "color"))
)
Arguments
axes |
Axes built so far |
plot |
The ggplot2 object |
built |
Built plot data (optional) |
data |
The extracted layer data |
layer_index |
Index of the layer being described |
aes_groups |
Grouping aesthetics to probe, as documented on
|
Value
The axes list, with z added when the layer is grouped
Apply processor plot augmentation to a single leaf ggplot
Description
Some processors need extra geoms in the rendered SVG to hang selectors on
– violin injects a thin geom_boxplot() so the box-summary layer has
something to highlight. The single-plot path does this in
Ggplot2PlotOrchestrator$process_layers(); leaves of a patchwork need the
same treatment before the composition is rendered.
Usage
augment_leaf_plot(leaf_plot)
Arguments
leaf_plot |
A ggplot object |
Value
The augmented ggplot (the input unchanged when nothing augments)
Augment every leaf of a patchwork composition
Description
Mirrors extract_patchwork_leaves()'s traversal so the augmented tree has
the same leaf order. The result must be used for BOTH
patchwork::patchworkGrob() and process_patchwork_plot_data(): grob names
come from a global counter, so selectors computed against one build cannot
resolve against another.
Usage
augment_patchwork_leaves(node)
Arguments
node |
Patchwork node or ggplot object |
Value
The same structure with each leaf augmented
Canonical Axes Schema Helpers
Description
Utilities for constructing and validating the canonical per-axis
axes object emitted by the MAIDR payload. Only x, y,
and z keys are permitted at the top level of axes; each maps
to an AxisConfig list with optional label (string),
min, max, tickStep (numbers), and format (an
AxisFormat list). The legacy flat form (bare string labels and
top-level format/min/max/tickStep/fill/level) has been removed with no
deprecation path.
Grid navigation bounds for one axis
Description
min, max and tickStep for the axis named, read off the built plot's
panel parameters, or NULL when any of the three cannot be determined –
which leaves the axis with its label and no grid, the graceful degradation
#158 settled on.
Usage
axis_grid_info(built, axis = "x", panel_id = NULL)
Arguments
built |
Built plot data |
axis |
Character, either "x" or "y" |
panel_id |
Panel index for faceted plots (optional, defaults to 1) |
Details
Lifted out of Ggplot2PointLayerProcessor, which still calls it, when the
rug processor came to need the same answer for the axis its ticks stand on
(#222). Two readings of one grid rule is how the two would drift.
Value
List with min, max, tickStep, or NULL
Functions maidr masks on attach
Description
library(maidr) puts maidr's own copies of the Base R plotting functions
ahead of the originals on the search path, and R says so with its "The
following objects are masked" notice. Each copy is a wrapper: it records
the call so that show() and save_html() can render an accessible
chart, then calls the original and returns what the original returns.
With interception off (maidr_off(), or options(maidr.base_r = FALSE))
the wrappers pass straight through.
Usage
barplot(...)
plot(...)
hist(...)
boxplot(...)
image(...)
heatmap(...)
contour(...)
matplot(...)
curve(...)
dotchart(...)
stripchart(...)
stem(...)
pie(...)
mosaicplot(...)
assocplot(...)
pairs(...)
coplot(...)
persp(...)
sunflowerplot(...)
fourfoldplot(...)
spineplot(...)
cdplot(...)
qqnorm(...)
qqplot(...)
qqline(...)
filled.contour(...)
acf(...)
pacf(...)
ccf(...)
cpgram(...)
spectrum(...)
monthplot(...)
termplot(...)
lag.plot(...)
biplot(...)
interaction.plot(...)
bxp(...)
stars(...)
vioplot(...)
wordcloud(...)
chartSeries(...)
lines(...)
points(...)
text(...)
mtext(...)
abline(...)
segments(...)
arrows(...)
polygon(...)
rect(...)
symbols(...)
legend(...)
axis(side, at = NULL, labels = TRUE, ...)
title(...)
grid(...)
par(...)
layout(...)
## S3 method for class 'screen'
split(...)
Arguments
... |
Arguments passed to the original graphics function. |
side, at, labels |
|
Details
What is masked
From graphics: the high-level plotting functions barplot(), plot(),
hist(), boxplot(), image(), contour(), matplot(), curve(),
dotchart(), stripchart(), stem(), pie(), mosaicplot(),
assocplot(), pairs(), coplot(), persp(), sunflowerplot(),
fourfoldplot(), spineplot(), cdplot(), filled.contour(), bxp()
and stars(); the low-level additions lines(), points(), text(),
mtext(), abline(), segments(), arrows(), polygon(), rect(),
symbols(), legend(), axis(), title() and grid(); and the layout
functions par(), layout() and split.screen().
From stats: heatmap(), qqnorm(), qqplot(), qqline(), acf(),
pacf(), ccf(), cpgram(), spectrum(), monthplot(), termplot(),
lag.plot(), biplot() and interaction.plot().
plot() is also masked from base, where its generic has lived since
R 4.0, and show() from methods: the S4 display generic, which maidr's
show() hands back any object that is not a plot.
vioplot::vioplot(), wordcloud::wordcloud() and
quantmod::chartSeries() are wrapped as well, once their package is
loaded.
show() and methods::show()
maidr's show() takes a ggplot2 object or, with no argument, the last
recorded Base R chart. Anything else it is given goes to
methods::show(), so show(x) on an S4 object prints as it did before
maidr was attached. In a script or a package, where what is masked
depends on what else is attached, call maidr::show() and
methods::show() by name.
Attach order for vioplot, wordcloud and quantmod
These three are wrapped into maidr's namespace when their package loads,
so a bare call reaches the wrapper only while package:maidr sits ahead
of the package on the search path. Attach them before maidr:
library(vioplot) library(maidr)
Attached after it, the package masks the wrapper, a bare vioplot(),
wordcloud() or chartSeries() draws without being recorded, and
show() reports that no Base R plot was detected. maidr says so at the
moment the package is attached and again in that error. The other way
round it is maidr::vioplot(), maidr::wordcloud() or
maidr::chartSeries(), called explicitly.
Calling an original directly
The wrappers add nothing to the drawing and return what the original
returns, so there is rarely a reason to go around them. graphics::barplot()
does, and draws a chart maidr does not record.
Value
Same as the original Base R function (invisibly when applicable).
See Also
show() and save_html(); maidr_on() and maidr_off() for
turning interception on and off; ?"maidr-options".
Base R Axis-Title Defaults
Description
Base R's high-level plotting functions derive their axis titles inside the
call (hist() names the y axis "Frequency", boxplot.formula() reads both
titles off the formula) instead of recording them, and barplot() and
pie() draw no title at all. Either way the recorded call carries no
xlab=/ylab=, so a processor that only reads those arguments announces a
nameless axis.
Details
What a chart can honestly put there is a property of the chart type rather than of the data, so the shapes shared by several processors are resolved here once.
Canonical axes for a categorical Base R chart
Description
barplot(), boxplot() and pie() all plot one categorical axis against
one measured axis, and none of them writes a title unless the author does.
Naming those axes for what they hold – "Category" against "Value" – says
what the numbers mean, where the renderer's positional "X"/"Y" fallback
only says where they sit, and it claims nothing beyond the shape of the
call. py-maidr's pie chart defaults to the same two words.
Usage
base_r_categorical_axes(args, horizontal = FALSE)
Arguments
args |
Recorded argument list, or NULL |
horizontal |
TRUE when the chart draws its value axis horizontally, which swaps which visual axis holds the categories |
Value
Canonical axes list
Map a Base R type argument onto a MAIDR step direction
Description
type = "s" draws the horizontal segment first, which is MAIDR's "hv";
type = "S" draws the vertical segment first, which is "vh". Any other
value returns NULL so the caller can omit stepDirection rather than
assert a convention the call never asked for.
Usage
base_r_step_direction(plot_type)
Arguments
plot_type |
The |
Value
"hv", "vh", or NULL.
Box-family emission order
Description
Which end of a horizontal box or violin chart a reader starts at is not something the input schema states, so the two MAIDR bindings disagreed about it: r-maidr emitted its categories bottom to top and py-maidr top to bottom, and the same chart was navigated from opposite ends depending on which one drew it (#187).
Build a canonical axes object
Description
Convenience constructor for a per-axis axes list. Drops NULL and empty axes, so a caller that can say nothing about an axis simply omits the key and leaves the generic to the renderer.
Usage
build_axes(x = NULL, y = NULL, z = NULL)
Arguments
x |
Label string or AxisConfig list for the x axis (or NULL) |
y |
Label string or AxisConfig list for the y axis (or NULL) |
z |
Label string or AxisConfig list for the z axis (or NULL) |
Value
A canonical axes list with only non-NULL axes set. Named even when
empty, so it serializes as the JSON object {} rather than as [].
Build a single AxisConfig
Description
Drops the fields that are absent, so an axis only carries what its caller
could establish. Returns a named empty list when nothing could be: passed
to build_axes(), that drops the axis key entirely.
Usage
build_axis_config(label = NULL, min = NULL, max = NULL, tickStep = NULL)
Arguments
label |
Axis label, or NULL |
min |
Axis minimum, or NULL |
max |
Axis maximum, or NULL |
tickStep |
Distance between ticks, or NULL |
Value
A named list (AxisConfig), possibly empty
Build Format Config from Detected Type and Parameters
Description
Build Format Config from Detected Type and Parameters
Usage
build_format_config(format_type, prefix, suffix, accuracy, digits)
Arguments
format_type |
Detected format type |
prefix |
Prefix from closure |
suffix |
Suffix from closure |
accuracy |
Accuracy from closure |
digits |
Digits from closure |
Value
Format configuration list
Build the Interactive SVG, or Answer NULL When It Cannot Be Built
Description
should_fallback() answers whether the recorded layers are ones maidr can
read. It cannot answer whether the plot can be exported, because that is
the exporter's question and the exporter is not consulted until the export
runs. When maidr exported through gridSVG, two base R charts failed there
on plots that pass the gate – matplot() with "non-numeric argument to
binary operator" and symbols() with gridSVG's own "We shouldn't be here!"
assertion, both raised inside grid.export() rather than by anything this
package computes. The svglite export draws both, but an export can still
throw.
Usage
build_interactive_svg(orchestrator, ...)
Arguments
orchestrator |
The orchestrator for the plot being rendered. |
... |
Passed through to |
Details
Left to propagate, those kill the save outright: the caller gets neither the interactive chart nor the static image, and an error naming a package they never called. The lower claim the package makes about a recorded plot is that it is at worst a picture (#216), and an export that throws is no more a reason to break that than a layer it cannot classify.
The whole build is guarded rather than the export alone. From the caller's side the gtable, the data and the SVG are one step – producing the interactive chart – and which of the three threw does not change what they should be given instead.
maidr_set_fallback(enabled = FALSE) is the caller asking for the failure
rather than the picture, so the error is re-raised untouched there.
Value
The SVG content, or NULL when the build failed and fallback is
enabled.
Assemble the exported document
Description
Assemble the exported document
Usage
build_svg_document(walk, svg, w, h)
Arguments
walk |
The walk state. |
svg |
svglite's page. |
w, h |
Page size in px. |
Value
Character vector of SVG lines.
Delegate to the stored original knitr plot hook
Description
Falls back to knitr's markdown hook only when no original was stored.
Usage
call_original_plot_hook(x, options)
Arguments
x |
The plot file path from knitr |
options |
Chunk options |
Value
The hook's output
Cancel a pending auto-show callback
Description
Removes by NAME rather than by the index addTaskCallback() returned:
that index is a position in R's callback list, and any other package
adding or removing a callback in the meantime shifts it. Removing a
stale index silently deletes an unrelated package's callback.
Usage
cancel_auto_show()
The name at one position, or NULL
Description
A point drawn off an integer is still in that integer's category.
position_dodge shifts a point sideways to make room for a sibling series
and position_jitter scatters it, and both displacements stay within the
category's own slot – so the tick it was moved from is the category it is
in, not a category it is being falsely assigned to. Measured on a dodged
scatter over two groups, x arrives as 0.875, 1.125, 1.875, 2.125, and an
exact match names none of the 24 points.
Usage
category_at(position, labels)
Arguments
position |
A drawn coordinate |
labels |
The map from |
Details
Rounding is what recovers them, which is the answer the Python binding
reached for the same situation: "a point drawn off one is a group a dodge
shifted aside to make room for its neighbour – still that group, and still
named by the tick it was moved from."
Bounded at half a tick, which is what keeps it honest. ggplot2 keeps both
displacements inside the slot – a dodge divides the category's width, and
position_jitter's default reaches 40% of the resolution – so anything
further out is not a displaced member of that category and is left unnamed.
The is_discrete() gate above does the rest: on a continuous axis there are
no names to round onto, so a measurement cannot be renamed after whichever
tick it happens to fall nearest.
Value
The name, or NULL when there is none
The technical-analysis indicators a recorded chartSeries() call draws
Description
quantmod::chartSeries() draws the indicators named by its TA
argument, which defaults to "addVo()", and splits a single string on
TAsep (";" by default), so TA = "addVo();addSMA()" draws two. An
explicit TA = NULL, FALSE, NA or "" draws none.
Usage
chartseries_ta_calls(args)
Arguments
args |
The recorded arguments of the chartSeries() call |
Value
A character vector of indicator calls, such as "addVo()";
character(0) when none is drawn, or NA when TA is not a
character vector (an evaluated indicator object), which cannot be read.
Classify a Base R Function
Description
Determines the classification level of a Base R plotting function.
Usage
classify_function(function_name)
Arguments
function_name |
Name of the function to classify |
Value
Character string: "HIGH", "LOW", "LAYOUT", or "UNKNOWN"
Clean MAIDR internal arguments from args list
Description
Removes internal arguments (starting with .maidr_) from an args list before passing to original functions during replay.
Usage
clean_maidr_args(args)
Arguments
args |
List of arguments |
Value
Cleaned args list without .maidr_* entries
Clear All Device Storage
Description
Clears storage for all devices.
Usage
clear_all_device_storage()
Value
NULL (invisible)
Clear Device Storage
Description
Clears all stored plot calls for a specific device.
Usage
clear_device_storage(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
NULL (invisible)
Clear recorded plot calls
Description
Clear recorded plot calls
Usage
clear_plot_calls(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID (defaults to current device) |
Value
NULL (invisible)
Clip chartSeries' lower-panel rects to their plot region
Description
quantmod::chartSeries() draws its volume panel (addVo()) as bars from
zero, in a panel whose y range starts near the smallest volume, and leaves
R to clip them to the plot region, as base graphics do by default. The
tree gridGraphics::grid.echo() rebuilds from that drawing places those
bars in graphics-plot-<N>, which does not clip, rather than in the
graphics-plot-<N>-clip viewport it builds beside it, so every bar ran on
past the panel's lower border into the date labels.
Usage
clip_chartseries_panel_rects(grob)
Arguments
grob |
A grob, gTree, gList, or gtable (or NULL) |
Details
Each rect of a panel below the first is moved into that panel's -clip
viewport, when the tree has one. The rect keeps its name, so its element
id, and the selectors built from it, are unchanged; only the viewport
groups around it are named after the clipping viewport, and the export
clips them as R clipped the drawing. The price panel is left alone: its
candles lie within its range.
Value
The same tree with lower-panel rects in their clipping viewport
Close and clean up the MAIDR temp device
Description
Close and clean up the MAIDR temp device
Usage
close_maidr_temp_device()
Value
NULL (invisible)
Collapse multiple "line" layer entries in a single panel into one multi-series line layer entry. Other layers are left untouched.
Description
The first line layer's id, title, and axes are preserved; data and selectors are concatenated across all line layers.
Usage
collapse_lines_to_multiseries(panel)
Arguments
panel |
A processed panel list with $id and $layers |
Value
Panel with line layers merged
Collect all candlestick layers in a maidr_data structure
Description
Collect all candlestick layers in a maidr_data structure
Usage
collect_candlestick_layers(maidr_data)
Every grob name in a tree, depth first
Description
Shared with the box plot processor's own walk, which looks for the same
graphics-plot-N-kind-M names in the same tree shape.
Usage
collect_grob_names(g)
Arguments
g |
A grob, gList, gTree or gtable. |
Value
A character vector of names.
Collect every panel cell of a gtable, descending into nested gtables
Description
Nested layouts like (p1 | p2) / p3 place the inner row's panels inside a
CHILD gtable ("patchwork-table-N"), so scanning only the top-level layout
drops them. Panels are collected in DISCOVERY order, which follows
patchwork's plot-addition order and therefore matches
extract_patchwork_leaves().
Usage
collect_gtable_panels(
gt,
t_path = integer(0),
l_path = integer(0),
vp_prefix = character(0),
wrapper = NULL
)
Arguments
gt |
Gtable object |
t_path |
Accumulated top positions of the enclosing cells |
l_path |
Accumulated left positions of the enclosing cells |
vp_prefix |
Accumulated viewport names of the enclosing cells |
Details
Each entry also carries the grid viewport path needed to navigate to that
panel after the gtable has been drawn. gtable names a cell's viewport
<name>.<t>-<r>-<b>-<l> and wraps a nested gtable's children in a
"layout" viewport, so the path down to a nested panel is
c("<child>.t-r-b-l", "layout", "<panel>.t-r-b-l"). Panel names are NOT
unique across a nested composition (both halves of a 2x2 contain a
"panel-1"), which is why callers address panels by position in this list
rather than by name.
Value
List of panel entries (name, grob, t, l, t_key, l_key, vp_path)
The full paths of the viewports a grob tree defines
Description
The full paths of the viewports a grob tree defines
Usage
collect_viewport_paths(grob)
Arguments
grob |
A grob, gTree, gList, or gtable |
Value
Character vector of "a::b::c" paths, from every childrenvp
Combine data from multiple layers in facet processing
Description
Combine data from multiple layers in facet processing
Usage
combine_facet_layer_data(layer_results)
Arguments
layer_results |
List of layer processing results |
Value
Combined data
Combine selectors from multiple layers in facet processing
Description
Combine selectors from multiple layers in facet processing
Usage
combine_facet_layer_selectors(layer_results)
Arguments
layer_results |
List of layer processing results |
Value
Combined selectors
Compute Panel Slot for Each Plot Group
Description
Maps plot groups to panel slots (1-based, in drawing order) for a multi-panel configuration:
Groups drawn BEFORE the layout call are not part of the grid (the next high-level plot starts a fresh page), so they get NA.
When more groups than panels were drawn, R flows onto a new page; only the final (visible) page is exported, so groups on earlier pages get NA.
Usage
compute_panel_slots(plot_groups, panel_config)
Arguments
plot_groups |
List of plot groups from group_device_calls() |
panel_config |
Panel configuration from detect_panel_configuration() |
Value
Integer vector (one entry per group): panel slot or NA
Compute one violin's statistics the way vioplot does
Description
Compute one violin's statistics the way vioplot does
Usage
compute_vioplot_stats(data, h = NULL, range = .maidr_vioplot_default_range)
Arguments
data |
Numeric vector for one violin. |
h |
Bandwidth, when the caller passed one. |
range |
Whisker reach in interquartile ranges, as vioplot's |
Value
A list with min, q1, median, q3, max, positions,
density and bandwidth, or NULL when there is nothing to describe.
Group a contour layer's rows into the curves it drew
Description
A contour draws a scalar field as curves of constant value, and
ggplot_build() has already done the hard half: level is a number on
every row, and piece separates the curves. A field with two peaks crosses
a level twice and arrives as two pieces, so nothing has to be split apart
here – which is the one place this reading is easier than the matplotlib
one, where both islands come back in a single compound path
(xability/py-maidr#540).
Usage
contour_curves(built_data)
Arguments
built_data |
A layer's computed data, carrying |
Details
Pieces are emitted in ascending piece, which is ascending level and then
draw order within a level, and the returned order is that sequence of
piece identifiers – what the selectors are built from, so the highlight
follows the grouping rather than relying on the document happening to agree.
Value
A list with data (one curve per piece, each a list of x, y
and level) and order (the piece behind each emitted curve)
How many gtable panels one patchwork leaf occupies
Description
One for an ordinary leaf; one per facet cell for a faceted one; none for a
leaf patchwork has wrapped. Used to walk find_patchwork_panels() in step
with the leaf list – a leaf that contributes no panel must not consume
one, or every leaf after it is described over somebody else's panel.
Usage
count_leaf_panels(leaf_plot)
Arguments
leaf_plot |
A leaf of a patchwork composition |
Value
Integer count, 0 for a wrapped leaf
Create enhanced wrapper for axis to capture scales:: format config
Description
This wrapper intercepts axis() calls and checks if the labels argument is a scales:: label function (closure). If so, it extracts the format configuration before applying the function to get the actual labels.
Usage
create_axis_wrapper(original_function)
Arguments
original_function |
Original axis function |
Value
Enhanced wrapped function
Create enhanced wrapper for barplot with sorting logic
Description
Create enhanced wrapper for barplot with sorting logic
Usage
create_barplot_wrapper(original_function)
Arguments
original_function |
Original barplot function |
Value
Enhanced wrapped function
Create enhanced SVG with maidr data
Description
Create enhanced SVG with maidr data
Usage
create_enhanced_svg(gt, maidr_data, ...)
Arguments
gt |
A gtable object |
maidr_data |
The maidr-data structure |
... |
Additional arguments |
Value
Character vector of SVG content
Create Fallback HTML Content
Description
Creates HTML content with the fallback image, styled to fit in iframes.
Usage
create_fallback_html(
plot = NULL,
shiny = FALSE,
format = get_fallback_format(),
width = 7,
height = 5
)
Arguments
plot |
A ggplot2 object or NULL for Base R plots |
shiny |
If TRUE, returns just the image tag for Shiny/knitr use |
format |
Image format. Defaults to the |
width |
Image width in inches |
height |
Image height in inches |
Value
HTML content string or htmltools object
Create iframe HTML tag for fallback static image
Description
Creates an iframe element whose srcdoc carries a static image.
Used when plots contain unsupported layers and fall back to PNG rendering.
Unlike create_maidr_iframe, this does not include MAIDR.js dependencies.
Usage
create_fallback_iframe(
html_content,
width = "100%",
height = "450px",
plot_id = NULL
)
Arguments
html_content |
Character string of HTML content (with img tag) |
width |
Width of the iframe (default: "100%") |
height |
Height of the iframe (default: "450px") |
plot_id |
Unique identifier for the plot |
Value
Character string of iframe HTML
Create Fallback Image for Unsupported Plots
Description
Renders a plot as a standard PNG image when MAIDR cannot process it. This is used as a fallback for unsupported plot types or layers.
Usage
create_fallback_image(
plot = NULL,
format = "png",
width = 7,
height = 5,
res = 150
)
Arguments
plot |
A ggplot2 object or NULL for Base R plots |
format |
Image format: "png" (default), "svg", or "jpeg" |
width |
Image width in inches (default: 7) |
height |
Image height in inches (default: 5) |
res |
Resolution in DPI for PNG/JPEG (default: 150) |
Value
Base64-encoded image data URI string
Create a function wrapper
Description
Create a function wrapper
Usage
create_function_wrapper(function_name, original_function)
Arguments
function_name |
Name of the function |
original_function |
Original function to wrap |
Value
Wrapped function
Create HTML document with dependencies
Description
Create HTML document with dependencies
Usage
create_html_document(svg_content, use_cdn = NULL)
Arguments
svg_content |
Character vector of SVG content |
use_cdn |
Logical. If |
Value
An htmltools HTML document object
Create inline image HTML for non-iframe rendering
Description
Creates a simple img tag for fallback/non-HTML output. Used when we don't need iframe isolation (unsupported plots in HTML, or any plot in PDF/EPUB output).
Usage
create_inline_image(plot = NULL, width = "100%", height = "auto")
Arguments
plot |
A ggplot object or NULL for Base R |
width |
Width for the image container |
height |
Height for the image container |
Value
Character string of HTML with img tag
Wrap a chart in its iframe for a knitted document
Description
Online, the frame loads maidr.js from the CDN, and the document is given
its own copy of the bundle (maidr_page_bundle_dependency()) for the frame
to fall back on. The frame's document sits in a srcdoc attribute, where
R Markdown's self_contained and Quarto's embed-resources cannot reach
its <script src>; the copy is what they embed instead, once per document
however many charts it has, so a self-contained document's charts work
offline. Offline at render time, each frame carries the bundle inline, as
before.
Usage
create_knitr_iframe(content)
Arguments
content |
The chart's SVG content, from |
Value
Character string of iframe HTML
Create HTML document with maidr enhancements using the orchestrator
Description
Create HTML document with maidr enhancements using the orchestrator
Usage
create_maidr_html(
plot,
use_cdn = NULL,
shiny = FALSE,
orchestrator = NULL,
...
)
Arguments
plot |
A ggplot2 object |
use_cdn |
Logical. If |
shiny |
If TRUE, returns just the SVG content instead of full HTML document |
orchestrator |
Optional pre-created orchestrator to reuse (avoids double creation) |
... |
Additional arguments passed to internal functions |
Value
An htmltools HTML document object or SVG content
Create iframe HTML tag for isolated MAIDR plot
Description
Creates an iframe element whose srcdoc carries the complete MAIDR plot.
This isolates each plot in its own document/JavaScript context while leaving
it same-origin with the page, which is what Web Bluetooth and Web Serial —
and so the tactile display — require.
Usage
create_maidr_iframe(
svg_content,
width = "100%",
height = "450px",
plot_id = NULL,
use_cdn = NULL,
page_fallback = FALSE
)
Arguments
svg_content |
Character vector of SVG content with maidr-data attribute |
width |
Width of the iframe (default: "100%") |
height |
Height of the iframe (default: "450px") |
plot_id |
Unique identifier for the plot |
use_cdn |
Logical. If |
page_fallback |
Logical. Passed to |
Value
Character string of iframe HTML
Create MAIDR Widget for knitr (Internal)
Description
Internal function to create a MAIDR widget from either ggplot or Base R plots.
Usage
create_maidr_widget_internal(plot = NULL)
Arguments
plot |
A ggplot object or NULL for Base R |
Value
An htmlwidget object
Create a wrapper for functions taking unevaluated expressions
Description
Used for functions like curve() whose arguments must stay lazy. The recorded args are the unevaluated call expressions together with the caller environment, so replay evaluates them exactly as the user's call did.
Usage
create_nse_wrapper(function_name, original_function)
Arguments
function_name |
Name of the function |
original_function |
Original function to wrap |
Value
Wrapped function
Create self-contained HTML for iframe embedding
Description
Generates a complete standalone HTML document with MAIDR.js that can be embedded in an iframe for isolation. Each iframe gets its own JavaScript context, avoiding MAIDR.js singleton pattern issues with multiple plots.
Usage
create_standalone_html(svg_content, use_cdn = NULL, page_fallback = FALSE)
Arguments
svg_content |
Character vector of SVG content with maidr-data attribute |
use_cdn |
Logical. If |
page_fallback |
Logical. When the CDN is used, fall back to the copy of
the bundle the embedding page carries if the CDN load fails. Set by the
knitr paths, which add that copy to the document with
|
Value
Character string of complete HTML document
Reproduce the axis labels curve() derives for itself
Description
curve() computes its default labels internally and does not return them:
the x label is xname ("x" unless the caller overrides it) and the y
label is the deparsed expression, with a bare function name rewritten as
fname(xname). Reading them off the recorded call keeps the announced
axes matching the drawn ones; without them a visibly labelled plot would
be announced with two empty axis titles.
Usage
curve_default_labels(recorded_args)
Arguments
recorded_args |
Recorded (unevaluated) argument list of the call |
Details
An explicit xlab/ylab in the call wins over these defaults; the line
processor applies that precedence.
Value
List with x and y label strings
Keep the points curve() itself evaluated
Description
curve() returns, invisibly, the exact x/y vectors it just drew. Keeping them means the accessible data is read back from the user's own call – evaluated once, at the moment it was made, in the frame that made it.
Usage
curve_recorded_values(recorded_args, result)
Arguments
recorded_args |
Recorded (unevaluated) argument list of the call |
result |
The value curve() returned |
Details
The alternative – re-deriving the points when the figure is emitted –
means running user code a second time, later, in a rebuilt frame. That
is the failure mode #59 fixed for for loops, where every panel
replayed the last iteration's bindings; snapshot_call_env() narrows the
window but cannot close it, and the recorded call alone is not enough
anyway: from/to arrive unevaluated too (to = 2 * pi is recorded as
a call), so emit time would have to redo curve()'s own seq/log/xname
handling on top of evaluating the expression. Reading back what was
drawn is neither. The SVG still comes from replaying the call, so a
deliberately non-deterministic expression can draw a second, different
curve – that is true of every recorded call and is not made worse here.
The values are stored under a .maidr_ name, so clean_maidr_args()
drops them before the call is replayed.
Value
A list with x, y and labels, or NULL when the returned
value is not a usable pair of coordinate vectors
Report whether extracted layer data is split into named series
Description
Report whether extracted layer data is split into named series
Usage
data_has_series_groups(data)
Arguments
data |
The extracted layer data (a list of series) |
Value
TRUE when there is more than one series and points carry z
Detect Multi-panel Configuration
Description
Analyzes layout calls to determine multi-panel configuration.
Usage
detect_panel_configuration(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
Panel configuration list or NULL
Detect Format Type from scales Closure Parameters
Description
Detect Format Type from scales Closure Parameters
Usage
detect_scales_format_type(prefix, suffix, digits, scale, accuracy)
Arguments
prefix |
Prefix string from closure |
suffix |
Suffix string from closure |
digits |
Digits parameter (only in label_scientific) |
scale |
Scale parameter |
accuracy |
Accuracy parameter |
Value
Format type string or NULL
Positions to category names for one axis of one panel
Description
Positions to category names for one axis of one panel
Usage
discrete_axis_labels(built, axis = "x", panel_id = NULL)
Arguments
built |
The built ggplot2 object |
axis |
|
panel_id |
The panel to read, defaulting to the first |
Value
A named character vector keyed by position (as character), or
NULL when the axis is continuous. Empty names are dropped, so a scale
with a blank label yields the number rather than a blank announcement.
Distinct values of an aesthetic, in the order ggplot2 draws them
Description
A factor follows its own level order, minus the levels nothing was drawn for; anything else sorts in its own type's order. Sorting the values AS TEXT reorders the columns twice over: against a factor whose levels are not alphabetical, and against a number, where it puts 10 before 2.
Usage
discrete_level_order(values)
Arguments
values |
A vector of aesthetic values |
Details
The missing category comes last, which is where ggplot2 puts it for a character column, a numeric one and an ordinary factor alike.
Value
Character vector of the observed levels, in drawn order, with
NA_character_ last when the aesthetic has a missing value
Resolve the definition R dispatched a recorded call to
Description
hist is the motivating case from #98: the generic is hist(x, ...), so
matching against it leaves a positional breaks inside the dots. The
method carries the formals that matter, and picking it by the first
argument's class is the same choice UseMethod() made when the call ran.
Usage
dispatched_definition(function_name, definition, args)
Arguments
function_name |
Name of the recorded function |
definition |
The original (unwrapped) function that was called |
args |
Recorded argument list of evaluated values |
Value
A function to match against, or NULL when none can be resolved
The processor classes a factory's create_processor() dispatches to
Description
Read off the method rather than kept beside it. The list a factory used to return was written out by hand and consulted by nothing, so it drifted freely: by the time #200 was filed it was missing four of the twenty ggplot2 processors and one of the fourteen base R ones, and nothing in the package or its tests could tell. A second list is a second thing to keep true; asking the dispatch itself is one thing that cannot disagree with itself.
Usage
dispatched_processor_classes(generator, prefix)
Arguments
generator |
The factory's |
prefix |
The class-name prefix its processors share. |
Details
deparse(body(...)) is used rather than reading R/, because an installed
package has no R/ to read – the sources are gone by then and only the
parsed function survives.
Value
Character vector of class names, in the order first dispatched.
Display HTML document directly
Description
Display HTML document directly
Usage
display_html(html_doc)
Arguments
html_doc |
An htmltools HTML document object |
Display HTML file in browser
Description
Display HTML file in browser
Usage
display_html_file(file)
Arguments
file |
HTML file path |
Collapse a dot stack into the bins it counts
Description
A Wilkinson dot plot is a histogram drawn one dot per observation: the
values are binned, and each bin's dots are stacked so the stack's height
is the bin's count. ggplot_build() says so directly – it returns
one row per observation carrying that observation's bin centre, the bin
width, and the bin's count – so the histogram is read off rather than
reconstructed:
Usage
dotplot_bins(built_data, horizontal = FALSE)
Arguments
built_data |
A layer's computed data, carrying the bin centre on
|
horizontal |
|
Details
y x binwidth count countidx 1 0 1 1 3 1 2 0 1 1 3 2 3 0 1 1 3 3 4 0 2 1 2 1
Three rows for the bin at 1, each saying count = 3. Collapsing on
the centre gives four bins of 3, 2, 1 and 4.
The count is taken from the count column rather than by counting
rows. Measured, the two agree everywhere ggplot2 will build a dot plot –
aes(weight = w) expands a bin to one row per weighted unit, and a
fractional weight is refused outright ("weight must be nonnegative
integers") – so this is not a correction, it is a preference for the
stat's own answer over a count of the rows that happen to represent it.
Bin bounds come from the centre and the width rather than from
xmin/xmax, which name the bin only in one of the two
orientations: measured, binaxis = "y" puts the panel's whole range
in ymin/ymax and the dot's own width in
xmin/xmax, so neither pair is the bin there.
Value
A list of bins, each with centre, half and
count, ascending; empty when the layer drew nothing readable
Drop selectors entries that carry no selector
Description
A layer that resolved no highlight target must say so by OMITTING the key,
never by sending an empty list. The frontend hands layer.selectors
straight to document.querySelectorAll(), and an empty array stringifies
to "", which is a SyntaxError – thrown inside the trace constructor,
so the whole figure fails to initialise: no announcement, no sonification,
no braille, no keyboard entry, on a chart that still looks fine. An absent
key is falsy and takes the frontend's own "no selectors" path instead.
Usage
drop_empty_selectors(node)
Arguments
node |
A maidr-data node (list, or a leaf) |
Details
Applied here rather than in each processor because every payload passes
through this one point, and list() is the honest return value for a
processor whose grob lookup found nothing.
Value
The node with empty selectors entries removed
Embed volume y-values from a bar layer into the candlestick layer's data.
Description
Strategy:
If both layers have the same number of points, embed positionally. This is the canonical case: patchwork stacks two panels driven by the same date column, so the i-th candle and the i-th bar refer to the same trading day even if the bar layer's x is formatted differently from the candle's
value.Otherwise, fall back to string-matching the candle's
valuefield against the bar layer'sxfield.
Usage
embed_volume_into_candle_data(candle_layer, bar_layer)
Ensure a device is open before plotting (suppress default window)
Description
Ensure a device is open before plotting (suppress default window)
Usage
ensure_maidr_device()
Value
The current device ID after ensuring one is open
Escape a document so it can travel in an HTML attribute
Description
The result is pure ASCII: quotes, angle brackets and ampersands become
entities, and every character outside ASCII becomes a numeric character
reference (한). The browser decodes those while it parses the
attribute, so the frame's document holds the original characters, and
nothing between here and the page has a byte left to garble.
Usage
escape_for_attribute(html)
Arguments
html |
Character string holding a complete HTML document |
Details
That last part is the point. The escaped document goes on through knitr's
output, an htmlwidget's JSON and pandoc, and under a C locale – a
container, a CI runner, plenty of servers – more than one of those treats
an unmarked string as native-encoded and rewrites each non-ASCII byte as
the text <e2>, <80>, <a6>. Leaving the bytes unmarked, which is what
this did before, kept them intact only as far as this function: the ellipsis
in the inlined maidr.js arrived in the page as <e2><80><a6>, the script
no longer parsed, and a chart rendered offline was a plain picture. ASCII
has no encoding to get wrong.
Byte-wise, and deliberately not htmltools::htmlEscape(), which works in
characters and so garbles the same way under a C locale. useBytes = TRUE
keeps the substitutions off the encoding: every byte they replace is ASCII
and every byte of a multi-byte UTF-8 sequence is not, so none can land
inside one. Ampersands go first, or the ones the later replacements
introduce would be escaped a second time; the character references come
last for the same reason.
A string marked latin1 is converted to UTF-8 first; an unmarked one is
taken to be UTF-8, which is what the SVG serialisation and the bundle
produce, because enc2utf8() on it would assume the native encoding and
garble it under a C locale. Unmarked bytes that are not valid UTF-8 are
left as they are, since there is no telling what they spell.
Quotes and angle brackets are enough for a double-quoted attribute: an apostrophe cannot end one, and a newline inside one is legal and preserved, so both are left alone.
Value
The same document, escaped for use as an attribute value
Export the grid scene on the current (svglite) device
Description
Must be called with the chart already drawn on a device opened by
open_svg_device(). Closes that device.
Usage
export_svg_scene(svg_string, width, height)
Arguments
svg_string |
The function |
width, height |
Page size in inches. |
Value
Character vector of SVG lines.
Extract Format Configuration for a Single Axis
Description
Extracts formatting configuration by inspecting the closure environment of scales label functions (e.g., scales::label_dollar, scales::label_percent).
Usage
extract_axis_format(built, axis = "x")
Arguments
built |
A built ggplot2 object |
axis |
Either "x" or "y" |
Value
Format configuration list or NULL
Extract a label from a possibly-wrapped axis value
Description
Accepts a bare string, an AxisConfig list with a label field, or
NULL. Returns a character scalar.
Usage
extract_axis_label(value, default = "")
Arguments
value |
Raw axis input |
default |
Default label when no value is present |
Value
Character scalar label
Extract the body <g> id from a candlestick body selector
Description
Input form: "#geom_rect\.rect\.57\.1 rect" Output: "geom_rect.rect.57.1"
Usage
extract_body_grob_id(body_selector)
Extract Format Configuration from Built Plot
Description
Extracts MAIDR format configuration from the scale objects in a built
ggplot2 plot. This looks for the maidr_format attribute attached
by the maidr label functions.
Usage
extract_format_config(built)
Arguments
built |
A built ggplot2 object from |
Value
A list with x and/or y format configurations,
or NULL if no format config is found
Extract Format Configuration from scales Package Closure
Description
Inspects the closure environment of a scales label function to extract formatting parameters. This allows users to use scales:: functions directly without needing maidr:: wrappers.
Usage
extract_from_scales_closure(label_func)
Arguments
label_func |
A label function (e.g., from scales::label_dollar) |
Value
Format configuration list or NULL
Extract layout from a single leaf ggplot
Description
Mirrors the single-plot path in Ggplot2PlotOrchestrator: labels are
read from the BUILT plot first. ggplot2 v4 resolves derived labels only
while building – the stat-computed "count" of geom_bar(), and the
mapped column names – so an unbuilt labels holds nothing but the
explicit labs() overrides.
Usage
extract_leaf_plot_layout(leaf_plot, leaf_built = NULL)
Arguments
leaf_plot |
The ggplot object |
leaf_built |
The leaf's built plot, or NULL when it is unavailable |
Value
Layout with title and axes
Recursively extract leaf ggplots in patchwork addition order
Description
The order matches panel discovery order in find_patchwork_panels()
(patches first, then the plot carried by the patchwork object itself),
which is how leaves are paired with panels.
Usage
extract_patchwork_leaves(node)
Arguments
node |
Patchwork node or ggplot object |
Value
List of leaf ggplot objects
Extract the trailing numeric index used to scope grouped open/close element ids. For an id like "geom_rect.rect.57.1", returns "57".
Description
Extract the trailing numeric index used to scope grouped open/close element ids. For an id like "geom_rect.rect.57.1", returns "57".
Usage
extract_rect_index_from_id(grob_id)
Split a vioplot call's arguments into one sample per violin
Description
vioplot() takes its groups the way boxplot() does: as separate vectors
(vioplot(a, b, c)), as a single list or data frame, or as a formula. Only
the first two are read here; a formula call is left for the caller to
decline, because resolving it needs the environment the call was made in and
reconstructing that would be guesswork.
Usage
extract_vioplot_samples(args)
Arguments
args |
The recorded call's arguments. |
Value
A named list of numeric vectors, one per violin, or an empty list.
Rows of a layer's own data that belong to one facet panel
Description
The obvious values == group is wrong the moment the facet column holds
an NA: == answers NA for that row, and [ turns an NA index into
a fabricated all-NA row. One missing facet value therefore injects junk
rows into EVERY panel's subset, not only the panel the NA belongs to.
Usage
facet_group_rows(values, group)
Arguments
values |
The facet column of the layer's data |
group |
The panel's own facet group, possibly |
Details
NA is a panel, not an absence. ggplot2 lays out a real panel for it and
draws "NA" on its strip, so the matching rows have to be selected for that
panel rather than dropped everywhere. %in% handles the ordinary levels
(it scores an NA value as FALSE instead of NA), and is.na() picks
out the NA panel's own rows. A facet column that literally contains the
string "NA" stays distinct from a missing value: as.character() leaves
the former as "NA" and the latter as NA_character_.
Value
A logical vector, one element per row, never NA
Find children matching a type pattern
Description
Find children matching a type pattern
Usage
find_children_by_type(parent_grob, pattern)
Arguments
parent_grob |
The parent grob to search |
pattern |
The pattern to match in grob names |
Value
Vector of matching child names
Find grob by element type pattern
Description
Searches recursively through a grob tree to find a grob whose name matches
the pattern: graphics-plot-<number>-<element_type>-<number>
Usage
find_graphics_plot_grob(grob, element_type, plot_index = NULL)
Arguments
grob |
The grob tree to search (typically from ggplotify::as.grob()) |
element_type |
The element type to search for (e.g., "rect", "lines", "points") |
plot_index |
Optional plot index to match (for multipanel layouts) |
Value
The name of the first matching grob, or NULL if not found
Every grob of one plot drawn by a given element type
Description
find_graphics_plot_grob() answers with the first match, which is what a
chart drawing its whole layer into one grob wants. A chart drawing one grob
per datum – a pie's wedges, a mosaic's tiles – needs all of them, in the
order gridGraphics numbered them.
Usage
find_graphics_plot_grobs(grob, element_type, plot_index)
Arguments
grob |
The grob tree to search |
element_type |
The element type, e.g. |
plot_index |
The plot (panel) index to match |
Details
Sorted by the trailing grob number rather than by tree order or
lexicographically: density = shading interleaves a segments grob between
a pie's wedges so tree order is not contiguous, and a lexicographic sort
would put -polygon-10 before -polygon-2.
Value
Character vector of grob names, ascending by grob number
Resolve the panel grob a layer belongs to
Description
Without a panel context this keeps the single-plot behaviour: the cell
literally named "panel". With one, the panel is addressed by
panel_ctx$panel_index into collect_gtable_panels(), whose order matches
find_patchwork_panels(). Name matching is only a fallback because
patchwork reuses panel names across nesting levels.
Usage
find_gtable_panel_grob(gt, panel_ctx = NULL)
Arguments
gt |
Gtable object |
panel_ctx |
Panel context (panel_index, panel_name, ...), or NULL |
Value
The panel gTree, or NULL when it cannot be resolved
The grob a ggplot2 layer drew, found by its slot in the panel
Description
ggplot2 lays a panel out as grill, a zeroGrob, then one grob
per layer in layer order, then the panel's border – so this layer's grob
is the one index places after that first blank. A search by grob
name cannot tell two layers of the same geom apart: two geom_col()s
in a panel are both geom_rect.rect.N, and a search that collects
every match hands each layer the other's bars as well as its own.
Usage
find_layer_slot_grob(panel, index)
Arguments
panel |
The panel grob, or NULL |
index |
The layer's index in the plot, or NULL |
Details
LayerProcessor$find_layer_grob_tree() matches on the geom's own
class, and a geom_col() layer is GeomCol while the grob it
draws is named after geom_rect, so it does not serve here. Counting
containers instead of slots does not either – a geom_text() layer
occupies a slot and draws no container, so the counts stop lining up.
Value
The grob in the layer's slot, or NULL when the slot cannot be established
Find the original function in loaded namespaces
Description
Find the original function in loaded namespaces
Usage
find_original_function(function_name)
Arguments
function_name |
Name of the function to find |
Value
Original function or NULL if not found
Discover panels via gtable layout rows named ^panel-<num> or ^panel-<row>-<col>
Returns a data.frame with panel_index, name, t, l, row, col
Description
Discover panels via gtable layout rows named ^panel-<num> or ^panel-<row>-<col>
Returns a data.frame with panel_index, name, t, l, row, col
Usage
find_patchwork_panels(gtable)
Arguments
gtable |
Gtable object |
Value
Data frame with panel information
Collapse a layer's selector list into the one string its type is read as
Description
Every processor builds selectors with list() or lapply(), so even a
single CSS selector reaches jsonlite::toJSON() as a list of one, and
auto_unbox = TRUE cannot unbox a list: the payload says
"selectors": ["#geom_rect\\.rect\\.2\\.1 rect"]. maidr.js 4.x reads that
array as one selector per data point, resolves it to one element for
seven bars, and declines the whole layer – navigation and speech keep
working while nothing on the chart ever changes colour (#316). Measured
in headless Chromium against the bundled 4.9.0: ggplot2 bar, point,
histogram, dodged, stacked and pie, and Base R barplot(), hist(),
plot() and pie(), all announced their values and drew no highlight;
rewriting only the JSON to a string restored every one of them.
Usage
flatten_single_selectors(node)
Arguments
node |
A maidr-data node (list, or a leaf) |
Details
For a layer whose type is in SINGLE_SELECTOR_LAYER_TYPES, a flat
character vector or list of strings becomes one string. Several entries
are joined with ", ": a selector list, which querySelectorAll()
resolves in document order – the same order the layer's points are in,
since a processor that names several containers (Base R pie() draws
one polygon grob per wedge) walks them in drawing order. Nested lists (a
per-cell grid), named objects (BoxSelector) and anything not made of
strings are left exactly as they are, and so is every other layer type.
Applied where drop_empty_selectors() is, and for the same reason:
every payload passes through this one point, the processors are honest
about what they found, and the shape the frontend reads is decided once,
against the bundle actually shipped, where a future bundle bump has one
place to look.
Value
The node with single-selector layers carrying a string
Move a rect's anchor so its extent can be stated positively
Description
Only rects anchored at the low edge are touched. A centred or high-anchored rect with a negative extent covers a different span, and moving its anchor would move the rectangle rather than restate it – so those are left as they are, warning and all, rather than silently redrawn somewhere else.
Usage
flip_negative_extent(position, extent, anchor)
Arguments
position |
The rect's |
extent |
The rect's |
anchor |
Where the rect is anchored on this axis, from
|
Value
List with the restated position and extent
Format Extraction Utilities
Description
Utility functions for extracting and converting axis format configuration from ggplot2 scale objects to MAIDR format specifications.
Describe a Panel-scoped Fallback
Description
Builds the warning text used when only some panels of a multi-panel figure lose their accessible data. Naming the panels matters: the rest of the figure still sonifies and navigates, so the user needs to know which panel went quiet rather than assuming the whole figure did.
Usage
format_panel_fallback_warning(panels)
Arguments
panels |
Integer vector of 1-based panel numbers, in drawing order |
Value
A single warning string
Sum a table over the variables a formula names
Description
The branch mosaicplot.formula() takes when data is already a table:
the formula selects which margins to keep, and ~ . keeps all of them.
Usage
formula_margin_table(formula, data)
Arguments
formula |
The recorded formula |
data |
The recorded table |
Value
A table, or NULL
The table mosaicplot.formula() would build from a recorded formula call
Description
mosaicplot(~ Hair + Eye, data = df) is a common calling style, and the
table it draws is recoverable rather than invented – so it is built the
way mosaicplot.formula() builds it, by the same two branches, rather
than by a rule of our own that would agree with it only sometimes.
Usage
formula_two_way_table(args)
Arguments
args |
Recorded argument list, or NULL |
Details
Which branch, and why it matters
Read from graphics:::mosaicplot.formula rather than assumed. A data
that is a table (or has more than two dimensions) is summed over the
formula's terms; anything else goes through model.frame() and is
counted by row:
if (inherits(edata, "ftable") || inherits(edata, "table") ||
length(dim(edata)) > 2) {
data <- marginSums(as.table(data), varnames)
mosaicplot(data, ...)
} else {
mf <- eval(model.frame(formula, data, subset, na.action))
mosaicplot(table(mf), ...)
}
The distinction is not cosmetic, and #248 proposed the other reading. A
data frame of pre-counted cells – as.data.frame(HairEyeColor[, , 1]),
sixteen rows and a Freq column – is counted by row like any other, so
the chart draws sixteen equal cells:
table(model.frame(~ Hair + Eye, df)) xtabs(Freq ~ Hair + Eye, df)
Brown Blue Hazel Green Brown Blue Hazel Green
Black 1 1 1 1 Black 32 11 10 3
Brown 1 1 1 1 Brown 53 50 25 15
Red 1 1 1 1 Red 10 10 7 7
Blond 1 1 1 1 Blond 3 30 5 8
The left table is what mosaicplot() draws; the right is the one it would
draw if handed HairEyeColor[, , 1] directly. Reading the right one would
announce numbers the chart does not show, which is the one thing this
processor exists not to do. There is no Freq convention to match:
mosaicplot.formula() has none.
What is declined
A recorded subset. mosaicplot.formula() passes it into
model.frame(), so honouring it means reproducing an argument whose
recorded form is not the expression model.frame() is given – and
ignoring it would read rows the chart left out. Declined rather than
guessed, which leaves the figure exactly the picture it is today.
A recorded na.action is not passed through, and does not need to be:
table() drops a missing level whatever reached it, so the three actions
a caller can name all draw the same chart. Measured on a frame with an NA
in each column, na.omit, na.pass and na.exclude gave one table:
b
a p q
x 2 1
y 1 0
stats::na.omit is named here anyway, because that is what
mosaicplot.formula() defaults to and matching it costs nothing.
Value
A table, or NULL when the call is not a readable formula call
Which measured refusal a fourfoldplot() call runs into, if any
Description
Returns NULL when the call is read, and otherwise the reason
warn_fourfoldplot_declined() explains. Kept beside is_two_way_table()
and called from the processor as well as from dispatch, so the two cannot
disagree about which calls are readable.
Usage
fourfold_decline_reason(args)
Arguments
args |
The arguments recorded from the |
Details
The three gates, in the order they are asked:
-
std. Only"ind.max"and"all.max"are read. Measured onc(tab) = 10, 40, 90, 160,std = "ind.max"draws radii0.25, 0.50, 0.75, 1.00andr^2 * max(count)recovers10, 40, 90, 160exactly, so the wedge AREA is the count. Under the default"margins"the same table draws0.632456, 0.774597, 0.774597, 0.632456–r1 == r4,r2 == r3, four radii carrying one number. -
Shape. Exactly two dimensions, both of extent 2. Written as
length(dims) == 2L && all(dims == 2L)and NOT asidentical(dims, c(2L, 2L)), becausedim()may carry the dimension names andidentical()compares them – so the exact-comparison spelling can decline a table for a reason that has nothing to do with what the chart draws. Measured,dim(as.table(ftable(tb)))isc(Treatment = 2L, Outcome = 2L)on R 4.3.3 and unnamed on R 4.6.1, so which tables that spelling would have dropped varies by R version. The spelling used here does not vary, which is the point of it: whether the names survive is not a fact about the chart. -
Values.
is.numeric()rather thanas.numeric(): measured, a logical 2x2 printsTRUE/FALSEon the page as its count labels whileas.numeric()would have announced1/0underz = "Count". Finite, non-negative and summing above zero, because the all-zero table makesstdize()returnNaNfour times and grid emits ZERO polygon grobs for it – measured,npoly = 0.all(counts >= 0)is load-bearing, not defensive, and the obvious reading of it is wrong. AnNAcount does stopfourfoldplot()under everystd, with "missing value where TRUE/FALSE needed", so it never arrives. A NEGATIVE count stops only under the DEFAULTstd = "margins", with that same message. Measured onc(-1, 2, 3, 4),std = "ind.max"andstd = "all.max"both return normally with a "NaNs produced" warning andnpoly = 0– and those are exactly the two values that get past gate 1. So a negative count reaches this gate whenever it is drawable at all, its counts are finite and sum to 8, and this clause is the one that declines it.test-base-r-fourfoldplot.Rpins both halves.
A 2x2xk array fails gate 2 twice over, and is asked about first only so
the advisory can say "strata" rather than "not a 2x2 table":
recorded_two_way_table() returns NULL for any input with three
dimensions anyway. That includes 2x2x1, which draws exactly what the
matrix spelling draws – a conservative, measured loss.
Value
NULL when the counts are readable, otherwise "std", "strata"
or "table".
Whether a fourfoldplot() call draws the table rather than its odds ratio
Description
The dispatch-side wrapper over fourfold_decline_reason(), in the shape
is_two_way_table() has over recorded_two_way_table().
Usage
fourfold_reads_counts(args)
Arguments
args |
The arguments recorded from the |
Value
TRUE when the four quadrants are the four counts.
Resolve a recorded std the way fourfoldplot() itself resolves it
Description
graphics::fourfoldplot runs std <- match.arg(std), so partial spellings
are legal calls that draw the counts. Measured on R 4.3.3, every one of
these is admitted:
Usage
fourfold_std(args)
Arguments
args |
The arguments recorded from the |
Details
<absent> -> margins "margins" -> margins "m" -> margins
"ma" -> margins "ind.max" -> ind.max "ind" -> ind.max
"i" -> ind.max "in" -> ind.max "all.max" -> all.max
"all" -> all.max "a" -> all.max
c("margins", "ind.max", "all.max") -> margins
So identical(args[["std"]], "ind.max") would silently decline five legal
spellings. The one existing exact-comparison idiom in this package,
base_r_subseries_layer_processor.R's spikes(), is complete only because
monthplot's type choices are the single characters "l" and "h",
where partial matching cannot produce a non-choice string. std's choices
are multi-character, so the same idiom is incomplete here.
Anything match.arg() rejects resolves to "margins", which declines:
measured, "IND.MAX", "x", NA_character_, character(0) and
c("ind.max", "margins") all error inside match.arg(), and
fourfoldplot() itself raises the identical error first, so none of them
is reachable from a drawn chart. The tryCatch is there so that a reader
never stop()s and takes the whole figure with it – the reason
recorded_flag() gives for the same shape.
A non-character std is refused before match.arg() rather than coerced.
Measured, fourfoldplot(tb, std = 1L), std = TRUE and
std = factor("ind.max") all stop with "'arg' must be NULL or a character
vector"; as.character(factor("ind.max")) would have been accepted here
and would have read a call that upstream refuses to draw.
args[["std"]], not args$std: $ partial-matches a list, the collision
recorded in recorded_main_title().
Value
One of "margins", "ind.max" or "all.max".
Generate robust CSS selector from grob name
Description
Creates a CSS selector that targets SVG elements by their ID pattern, without relying on panel structure or hardcoded values.
Usage
generate_robust_css_selector(grob_name, svg_element)
Arguments
grob_name |
The name of the grob (e.g., "graphics-plot-1-rect-1") |
svg_element |
The SVG element type to target (e.g., "rect", "polyline") |
Value
A robust CSS selector string, or NULL if grob_name is invalid
Generate robust selector for any element type
Description
Creates a robust CSS selector that works regardless of panel structure. This is the main function that layer processors should use.
Usage
generate_robust_selector(
grob,
element_type,
svg_element,
plot_index = NULL,
max_elements = NULL
)
Arguments
grob |
The grob tree to analyze |
element_type |
The element type to search for (e.g., "rect", "lines") |
svg_element |
The SVG element to target (e.g., "rect", "polyline") |
plot_index |
Optional plot index for multipanel layouts |
max_elements |
Optional limit on number of elements to target |
Value
A robust CSS selector string, or NULL if element not found
Generate a unique ID for MAIDR plots
Description
Creates a unique identifier combining timestamp and counter to ensure uniqueness even when multiple plots are created within the same second.
Usage
generate_unique_id()
Value
Character string with unique ID
Grob-name prefix ggplot2 gives a geom's layer grob
Description
ggplot2 names a layer's grob after the snake-cased class of its geom, so
GeomSmooth draws geom_smooth.gTree.<n> and GeomDensity
draws geom_density.gTree.<n>.
Usage
geom_grob_prefix(geom)
Arguments
geom |
A ggproto Geom object |
Value
Character scalar prefix
Get Flat List of All Patchable Functions
Description
Returns a flat vector of all functions to patch.
Usage
get_all_function_names()
Value
Character vector of all patchable function names
Get All Patchable Functions
Description
Returns a list of all functions that should be patched, organized by class.
Usage
get_all_patchable_functions()
Value
List with HIGH, LOW, and LAYOUT function vectors
Get All Plot Groups
Description
Retrieves all plot groups for a device.
Usage
get_all_plot_groups(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
List of plot groups
Get Current Plot Index
Description
Returns the current active plot index for a device.
Usage
get_current_plot_index(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
Current plot index (integer)
Get Plot Calls from Device Storage
Description
Retrieves all plot calls for a specific device.
Usage
get_device_calls(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
List of plot call entries
Filter Device Calls by Classification
Description
Retrieves plot calls of a specific classification level.
Usage
get_device_calls_by_class(
device_id = grDevices::dev.cur(),
class_level = "HIGH"
)
Arguments
device_id |
Graphics device ID |
class_level |
Classification level: "HIGH", "LOW", "LAYOUT" |
Value
List of filtered plot call entries
Get or Initialize Device State
Description
Retrieves the state object for a specific graphics device.
Usage
get_device_state(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
Device state list
Get or Initialize Device Storage
Description
Retrieves storage for a specific graphics device, creating it if needed.
Usage
get_device_storage(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID (from grDevices::dev.cur()) |
Value
Device storage list
Get Device Storage Summary
Description
Returns summary information about device storage (for debugging).
Usage
get_device_storage_summary()
Value
List with device storage statistics
Get facet group information for a panel
Description
Get facet group information for a panel
Usage
get_facet_groups(panel_info, built)
Arguments
panel_info |
Panel information from layout |
built |
Built plot data |
Value
List of facet group information
Get Fallback Image Format
Description
Get Fallback Image Format
Usage
get_fallback_format()
Value
Character string of the format to use
Get All Functions of a Specific Class
Description
Returns all function names for a given classification level.
Usage
get_functions_by_class(class_level)
Arguments
class_level |
Classification level: "HIGH", "LOW", or "LAYOUT" |
Value
Character vector of function names
Get the global plot system registry
Description
Get the global plot system registry
Usage
get_global_registry()
Value
PlotSystemRegistry instance
Get Group Count
Description
Returns the number of plot groups for a device.
Usage
get_group_count(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
Number of groups (integer)
Get HIGH-level Calls
Description
Get HIGH-level Calls
Usage
get_high_level_calls(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
List of HIGH-level plot calls
Get LAYOUT Calls
Description
Get LAYOUT Calls
Usage
get_layout_calls(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
List of LAYOUT-level plot calls
Get LOW-level Calls
Description
Get LOW-level Calls
Usage
get_low_level_calls(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
List of LOW-level plot calls
Get original (unwrapped) function by name
Description
Get original (unwrapped) function by name
Usage
get_original_function(function_name)
Arguments
function_name |
Name of the function |
Value
The original function
Get Panel Configuration
Description
Returns the panel configuration for a device.
Usage
get_panel_config(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
Panel configuration list
Get recorded plot calls
Description
Get recorded plot calls
Usage
get_plot_calls(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID (defaults to current device) |
Value
List of recorded plot calls
Get Plot Group by Index
Description
Retrieves a specific plot group.
Usage
get_plot_group(device_id = grDevices::dev.cur(), group_index)
Arguments
device_id |
Graphics device ID |
group_index |
Index of the group to retrieve |
Value
Plot group list or NULL if not found
Group Device Calls into Plot Units
Description
Groups all calls from a device into logical plot units. Each group contains one HIGH-level call and its associated LOW-level calls.
Usage
group_device_calls(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
List of plot groups, each containing HIGH and LOW calls
Check if Device Has Calls
Description
Checks whether a specific device has any recorded plot calls.
Usage
has_device_calls(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
TRUE if device has calls, FALSE otherwise
Whether the density half of a violin can be computed at all
Description
sm is in vioplot's Depends, so it is attached wherever a violin can have
been drawn: in any normal installation this cannot fail, and the branch is
unreachable. Kept as a guard rather than an assumption only so a broken or
partial installation surfaces as no violin layer rather than a bare "there
is no package called 'sm'" thrown from inside a rendering path.
Usage
has_sm_package()
Value
TRUE when sm can be loaded.
Does This heatmap() Call Apply revC?
Description
heatmap() normally puts reordered row 1 at the bottom of the y axis, but
its revC argument flips the drawing so row 1 lands at the top. revC is
not part of the ordering heatmap() returns, and it defaults to
identical(Colv, "Rowv") – which is TRUE for every symm = TRUE call,
since Colv itself defaults to "Rowv" there.
Usage
heatmap_applies_revc(args)
Arguments
args |
Recorded heatmap() arguments |
Value
TRUE when revC applies, i.e. the drawn rows read top-down
Resolve a heatmap()'s Caller-Supplied Axis Labels
Description
heatmap() gives an explicit labRow=/labCol= priority over the
matrix's own dimnames, and subscripts it by the same ordering it applies to
the data: labRow[rowInd] %||% rownames(x) %||% (1L:nr)[rowInd]. Reading
the labels off the reordered matrix therefore announced the dimnames – or,
for an unnamed matrix, bare indices – while the axis showed the caller's
strings.
Usage
heatmap_caller_labels(labels, ordering)
Arguments
labels |
The recorded |
ordering |
The matching |
Details
A short or NA-carrying vector is passed through rather than rejected:
labRow[rowInd] yields NA for the positions it cannot fill, and grid
draws that as the glyphs "NA", so mirroring it keeps the announcement equal
to the picture. Subscripting is also what holds the result to one label per
row: a caller who supplies too many gets the surplus dropped, exactly as
heatmap() drops it.
Value
Character vector in drawn order, or NULL when the caller supplied no labels for this axis
Group hexagonal bins into lattice rows
Description
A hex lattice staggers alternate rows by half a cell, which is what lets the hexagons tessellate. Read as a grid of counted cells it is a heatmap, but the stagger means a bin's column index is not its position – bin 3 of one row and bin 3 of the next sit at different x – so the frontend announces centres rather than indices and this returns the rows rather than a rectangle.
Usage
hexbin_lattice(built_data)
Arguments
built_data |
A layer's computed data, carrying |
Details
Rows ascend in y, because the frontend's UPWARD steps to the next row index, the same convention the heatmap follows. Within a row bins ascend in x.
Rows are ragged and are left that way. stat_binhex() emits only the
bins that hold something, so the lattice is genuinely uneven; padding it
would put cells on the chart that were never drawn.
The returned order is the point of the function. It is the built-data
row behind each emitted bin, in emission order, and the selectors are built
from it – so the highlight follows the regrouping instead of relying on the
DOM happening to be in the same order. stat_binhex() does emit its
rows bottom-first today, which means that reliance would pass; it would also
be undetectable the moment it stopped, since a hexbin announces centres and
has no index to contradict.
Value
A list with data (rows of bins, each a list of x,
y and count) and order (the built-data row behind
each bin, in emission order)
Initialize Base R function patching
Description
This function sets up the function patching system by wrapping Base R plotting functions (HIGH, LOW, and LAYOUT levels). It should be called before any Base R plotting commands.
Usage
initialize_base_r_patching(include_low = TRUE, include_layout = TRUE)
Arguments
include_low |
Include LOW-level functions (lines, points, etc.) |
include_layout |
Include LAYOUT functions (par, layout, etc.) |
Details
Wrappers are installed once into the package namespace during .onLoad (when the namespace is still open). Subsequent calls just activate the patching flag; wrappers check this flag to decide whether to record calls or simply pass through to the original function.
Value
NULL (invisible)
Base R System Initialization
Description
Initialize and register the Base R system with the global registry. This function sets up the Base R adapter and processor factory.
Usage
initialize_base_r_system()
Value
NULL (invisible)
ggplot2 System Initialization
Description
Initialize and register the ggplot2 system with the global registry. This function sets up the ggplot2 adapter and processor factory.
Usage
initialize_ggplot2_system()
Value
NULL (invisible)
Initialize MAIDR default options
Description
Sets default values for MAIDR options during package load. Does not override options already set by the user (e.g. in .Rprofile).
Usage
initialize_maidr_options()
Inject candlestick open/close virtual line elements into the SVG
Description
tidyquant's geom_candlestick() draws each candle's body as a single
<rect>. Upstream maidr JS auto-derives open and close highlight
positions from the rect's bounding-box edges, but its heuristic assumes
a natural SVG y-axis (y increasing downward). gridSVG exports content
inside a translate(0, h) scale(1, -1) group, so y is flipped. The
upstream heuristic therefore swaps open and close on every candle.
Usage
inject_candlestick_open_close(svg_content, maidr_data)
Arguments
svg_content |
Character vector of SVG lines |
maidr_data |
The maidr-data structure (read-only; used to look up
per-candle |
Details
We sidestep the heuristic by emitting two sibling <g> containers (one
for opens, one for closes), each holding N invisible <line> elements
positioned at the correct edge of the corresponding body rect (computed
from the per-candle trend). The candlestick processor emits explicit
selectors.open / selectors.close referencing these groups, so JS
uses our placed elements directly and skips its own derivation.
Value
Modified SVG content (character vector). If parsing fails or no
candlestick layers are present, returns svg_content unchanged.
Document-level implementation of inject_candlestick_open_close()
Description
Mutates svg_doc in place (xml2 documents are references).
Usage
inject_candlestick_open_close_doc(svg_doc, maidr_data)
Arguments
svg_doc |
Parsed SVG document (xml2) |
maidr_data |
The maidr-data structure |
Value
TRUE if the document was modified
Inject svg_x/svg_y coordinates into violin_kde layer data
Description
After grid.draw(gt) has been called on a PDF device, this function
navigates to the panel viewport, maps data coordinates to SVG points,
and injects svg_x/svg_y into each ViolinKdePoint. Temporary
metadata fields (.panel_x_range, .panel_y_range, .is_horizontal,
.panel_index, .panel_name, data_left_x, data_right_x, data_y) are
stripped from the output.
Usage
inject_violin_kde_svg_coords(gt, maidr_data)
Arguments
gt |
The gtable object (used to find the panel viewport paths) |
maidr_data |
The maidr-data structure (modified in place) |
Details
Each violin_kde layer is mapped through the viewport of the panel it was
extracted from, so a violin inside a patchwork gets its own panel's
coordinates rather than the first panel's. Nested compositions repeat panel
names across levels, so the layer's .panel_index (its position in
collect_gtable_panels(), which matches find_patchwork_panels()) is the
primary key and the name is only a fallback.
Value
Updated maidr_data with svg_x/svg_y injected
Check if Base R interception is enabled
Description
Check if Base R interception is enabled
Usage
is_base_r_enabled()
Value
TRUE if Base R interception is active
Whether an indicator call is quantmod's volume panel, addVo()
Description
Whether an indicator call is quantmod's volume panel, addVo()
Usage
is_chartseries_volume_ta(calls)
Arguments
calls |
Indicator calls from |
Value
A logical vector, FALSE for NA
Check if Fallback is Enabled
Description
Check if Fallback is Enabled
Usage
is_fallback_enabled()
Value
Logical indicating if fallback rendering is enabled
Check if Fallback Warning is Enabled
Description
Check if Fallback Warning is Enabled
Usage
is_fallback_warning_enabled()
Value
Logical indicating if warnings should be shown
Whether one record matches the run's fields and types exactly
Description
Whether one record matches the run's fields and types exactly
Usage
is_flat_record(record, fields, types)
Arguments
record |
A candidate record |
fields |
The run's field names, in order |
types |
The run's field types, in order |
Value
TRUE when every field is one attribute-free value of its type
Is a recorded argument a formula, evaluated or not?
Description
A value recorded on the ordinary path is a formula object; on the NSE
path the same argument is the unevaluated call to ~, which inherits()
does not recognise.
Usage
is_formula_argument(value)
Arguments
value |
A recorded argument |
Value
TRUE for either spelling
Check if ggplot2 interception is enabled
Description
Check if ggplot2 interception is enabled
Usage
is_ggplot2_enabled()
Value
TRUE if ggplot2 interception is active
Whether a dotchart() call draws more than one group
Description
dotchart() draws a group per matrix column, or per level of groups,
with a header in the left margin and every dot in one shared grob. The
grouping is what the chart is drawn to show and there is nothing in a
flat dot layer to carry it, so such a call is declined rather than
flattened.
Usage
is_grouped_dotchart(args)
Arguments
args |
The arguments recorded from the |
Value
TRUE when the call draws groups, otherwise FALSE.
Check if Function is HIGH-level
Description
Check if Function is HIGH-level
Usage
is_high_level_function(function_name)
Arguments
function_name |
Name of the function |
Value
TRUE if HIGH-level, FALSE otherwise
Check if current knitr output format is HTML
Description
Detects whether the current RMarkdown document is being rendered to HTML format (html_document, bookdown, etc.) vs non-HTML formats (pdf, epub, etc.)
Usage
is_html_output()
Value
TRUE if rendering to HTML, FALSE otherwise
Check Internal Guard Flag
Description
Checks if we're currently in internal code (to prevent recursive tracing).
Usage
is_internal_call()
Value
TRUE if internal guard is set, FALSE otherwise
Check if Function is LAYOUT-level
Description
Check if Function is LAYOUT-level
Usage
is_layout_function(function_name)
Arguments
function_name |
Name of the function |
Value
TRUE if LAYOUT-level, FALSE otherwise
Check if Function is LOW-level
Description
Check if Function is LOW-level
Usage
is_low_level_function(function_name)
Arguments
function_name |
Name of the function |
Value
TRUE if LOW-level, FALSE otherwise
Check if MAIDR interception is globally enabled
Description
Check if MAIDR interception is globally enabled
Usage
is_maidr_enabled()
Value
TRUE if the master switch is on
Check if MAIDR RMarkdown Mode is Enabled
Description
Check if MAIDR RMarkdown Mode is Enabled
Usage
is_maidr_on()
Value
Logical indicating if MAIDR mode is active
Check if the current device is the MAIDR temp device
Description
Check if the current device is the MAIDR temp device
Usage
is_maidr_temp_device()
Value
TRUE if current device is the temp device
Check if Multi-panel Layout is Active
Description
Check if Multi-panel Layout is Active
Usage
is_multipanel_active(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
TRUE if multi-panel layout is active, FALSE otherwise
Check Whether a Panel Configuration Describes a Multi-panel Grid
Description
Check Whether a Panel Configuration Describes a Multi-panel Grid
Usage
is_multipanel_config(panel_config)
Arguments
panel_config |
Panel configuration from detect_panel_configuration() |
Value
TRUE for a multi-panel (mfrow/mfcol/layout) grid
Check if patching is active
Description
Check if patching is active
Usage
is_patching_active()
Value
TRUE if patching is active, FALSE otherwise
Check if Base R patching is currently active
Description
Wrappers are installed once during .onLoad and remain in the namespace. This flag controls whether they record calls or act as pass-through.
Usage
is_patching_enabled()
Value
TRUE if patching is active
Whether a list is a run of flat, uniformly typed records
Description
The first record sets the field names and types every other record must match exactly.
Usage
is_record_run(node)
Arguments
node |
A non-empty list |
Value
TRUE when records_as_frames() may convert node
Whether the first record's fields can become data frame columns
Description
Each field becomes one column, so the names must be unique and non-empty and every type one that a column can hold a scalar of.
Usage
is_record_schema(fields, types)
Arguments
fields |
The first record's names |
types |
The first record's field types |
Value
TRUE for unique, non-empty names over scalar-capable types
Whether a Base R type argument draws spikes
Description
type = "h" draws a vertical line from the baseline to each value –
"histogram-like" in plot()'s own wording – and joins nothing to
anything. Read as a lollipop layer, which the core builds on BarTrace:
one value per position, with no claim about the space between two of them.
Usage
is_spike_plot_type(plot_type)
Arguments
plot_type |
The |
Details
Case-sensitive, like the step test beside it: plot() has no "H".
Value
TRUE when plot_type is "h", otherwise FALSE.
Does a Base R type argument request a stairstep?
Description
graphics::plot() and graphics::lines() draw stairsteps for
type = "s" (horizontal segment first) and type = "S" (vertical segment
first). The comparison is case-sensitive because those two letters mean
different things.
Usage
is_step_plot_type(plot_type)
Arguments
plot_type |
The |
Value
TRUE when plot_type is "s" or "S", otherwise FALSE.
Whether a mosaicplot() call was handed a two-way table
Description
A mosaic layer has one category axis and one fill, so it can carry a
two-dimensional table and no more. mosaicplot() accepts deeper ones and
splits them recursively.
Usage
is_two_way_table(args)
Arguments
args |
The arguments recorded from the |
Details
The table itself is resolved by recorded_two_way_table(), which the
processor also reads, so dispatch and extraction cannot disagree about
which calls are readable.
Value
TRUE when the call's table has exactly two dimensions.
Is this panel a volume-only bar panel (single bar layer, no other layers)?
Description
Is this panel a volume-only bar panel (single bar layer, no other layers)?
Usage
is_volume_only_bar_panel(panel)
Has patchwork wrapped this leaf?
Description
inset_element(), free() and wrap_elements() each prepend their own
class and place the plot in a gtable cell whose name is not a plain
"panel-N", so panel discovery never sees it. Test for the wrapper rather
than naming them, so one added later behaves the same.
Usage
is_wrapped_leaf(leaf_plot)
Arguments
leaf_plot |
A leaf of a patchwork composition |
Value
Logical
Look up a layer's rebuilt frame
Description
Look up a layer's rebuilt frame
Usage
jitter_cache_get(layer, layer_index)
Arguments
layer |
The ggplot2 |
layer_index |
Index of that layer within its plot. |
Value
The cached data frame, or NULL on a miss.
Remember a layer's rebuilt frame
Description
Remember a layer's rebuilt frame
Usage
jitter_cache_set(layer, layer_index, data)
Arguments
layer |
The ggplot2 |
layer_index |
Index of that layer within its plot. |
data |
The rebuilt data frame, or |
Value
Invisibly NULL.
One string from a flat list of selectors, or the input untouched
Description
One string from a flat list of selectors, or the input untouched
Usage
join_selector_list(selectors)
Arguments
selectors |
A layer's |
Value
A single string when selectors is a flat, unnamed collection of
non-empty strings; otherwise selectors as given
Custom knit_print Method for density Objects
Description
Suppresses the default printing of density return values in RMarkdown. The density() function is not patched (it's in stats, not graphics), so we need this method to suppress its output.
Usage
knit_print.density(x, options = list(), ...)
Arguments
x |
A density object (from density()) |
options |
Chunk options from knitr |
... |
Additional arguments (ignored) |
Value
An invisible empty string
Custom knit_print Method for ggplot Objects
Description
Converts ggplot objects to MAIDR widgets for accessible rendering in RMarkdown. Uses iframe-based isolation to ensure each plot has its own MAIDR.js context. Automatically falls back to image rendering for unsupported plot types or non-HTML output formats (PDF, EPUB).
Usage
knit_print.ggplot(x, options = list(), ...)
Arguments
x |
A ggplot object |
options |
Chunk options from knitr |
... |
Additional arguments (ignored) |
Value
A knit_asis object containing the iframe HTML or inline image
Custom knit_print Method for histogram Objects
Description
Suppresses the default printing of histogram return values in RMarkdown. The plot is already rendered via the plot hook; this prevents the histogram object structure from being printed as text output.
Usage
knit_print.histogram(x, options = list(), ...)
Arguments
x |
A histogram object (from hist()) |
options |
Chunk options from knitr |
... |
Additional arguments (ignored) |
Value
An invisible empty string
Whether an axis label names a lane or just writes its own coordinate out
Description
A continuous axis has labels too – "1", "0.5", "1,000" – but those are
formatted renderings of the numbers rather than names for them, which is
the distinction discrete_axis_labels() already draws for a discrete
scale and xability/py-maidr#533 settled for lanes: an explicit tick names
the lane it sits in, and the axis's own coordinates do not.
Usage
label_names_its_lane(label, break_value)
Arguments
label |
One axis label |
break_value |
The break the label was drawn at |
Details
So the test is "is this label a rendering of its own number", not "is there a label". Measured on ggplot2 3.4.4, bands at 0.6-1.4, 1.6-2.4, 2.6-3.4:
default scale 1, 2, 3 -> position
breaks = 1:3, labels = c("design", ...) design, build, test -> name
breaks = 1:3, labels = c("1", "2", "3") 1, 2, 3 -> position
breaks = 1:3 1, 2, 3 -> position
breaks = seq(0, 4, 0.5) 0.5, 1.0, 1.5, ... -> position
An author who writes labels = c("1", "2", "3") is deliberately
naming lanes "1", "2" and "3" and gets positions instead. That is the trade
py-maidr made, and it is the safe direction: a lane called "2" says less
than a lane called by the position 2 it sits at.
The strip is what keeps scales::comma, scales::dollar and a
padded label from reading as names – measured, "1,000" at the
break 1000 and "$1" at 1 both come back FALSE. It does not save
scales::percent, which renders the break 1 as "100%":
measured, that reads as a name and a lane is called "100%" rather
than 1.
The cost is a cosmetic mis-name inside a schedule the author already
declared, not a false claim, so it is recorded rather than chased.
Value
TRUE when the label is a name rather than the break written out
The name of the lane at one position on the lane axis
Description
A discrete scale lays its levels out at 1, 2, 3 and so on, so the name is
the level at that index. A continuous lane axis has no names and the
position itself is what a reader is told – GanttPoint$x takes a number
or a string for exactly this reason.
Usage
lane_name(slot, lane_names = NULL)
Arguments
slot |
One or more positions on the lane axis |
lane_names |
The lane names in drawn order, or NULL |
Value
The lane names, or the positions unchanged
Which axis a declared schedule runs its lanes up
Description
maidr_gantt(lane_axis = ) is an argument rather than an inference,
and this reads it back. "y" when the author said nothing, which is
the ordinary horizontal schedule: lanes stacked up y, spans running along
x. Also "y" when only the constructor survived – the lane axis
cannot be recovered from a call whose argument may be a variable – which
matches the default the author most likely took.
Usage
layer_declared_lane_axis(layer)
Arguments
layer |
A ggplot2 layer object |
Value
"y" or "x"
Does a layer's curve land in the panel's auto-named polyline population?
Description
layer_polyline_grobs() keeps every polyline that no geom-named tree
claims, so the population it returns is "layers that draw a BARE polyline"
– which is not the same set as "layers typed line". geom_function() is
typed smooth and draws one anyway: GeomFunction inherits
GeomPath$draw_panel(), which returns a polylineGrob with nothing named
around it, while GeomSmooth and GeomDensity wrap theirs in
geom_smooth.gTree / geom_density.gTree and are skipped whole.
Usage
layer_draws_bare_polyline(layer, type)
Arguments
layer |
A ggplot2 layer. |
type |
The layer type the adapter detected for it. |
Details
Counting only the line-ish types therefore counted a population one
smaller than the one being indexed, and a geom_function() drawn before
a geom_line() handed the line the function's curve to highlight (#204).
Both charts read correctly the whole time, which is the highlight-only
shape xability/maidr#814 names.
Value
TRUE when the layer draws a bare, auto-named polyline.
Whether a layer was drawn by annotate() rather than by a geom
Description
annotate() is ggplot2's word for decoration: a highlighted region, a
label, an arrow pointing at something. Whatever geom it happens to use, the
function is the author saying "this is not data".
Usage
layer_is_annotation(layer)
Arguments
layer |
A ggplot2 layer object |
Details
ggplot2 records which function built each layer, so this is exact rather
than a guess about geometry. Measured on ggplot2 3.4.4, layer$constructor
holds the matched call and its head is the function name:
geom_rect(aes(...)) -> geom_rect
annotate("rect", xmin = 2, xmax = 3, ...) -> annotate
annotate("text", x = 2, y = 3, ...) -> annotate
It survives disguise, which is what makes it better than the shape-based
rules considered in #197. annotate() sets inherit.aes = FALSE
and show.legend = FALSE, so those two look like a signature – but a
geom_rect() written with both still reports geom_rect, and a
rule keyed on them would call that user's data decoration.
Deliberately not a rule about what an annotation may draw. The whole point
of asking the constructor is that the answer does not depend on the mark:
annotate("segment") is an arrow, not a schedule, and a geometry test
would have to claim or refuse it on its coordinates.
A layer with no constructor – a ggplot2 that stopped recording it,
or a layer built by hand – answers FALSE and keeps whatever reading it had.
Value
TRUE when annotate() built the layer
Whether a layer's author declared it a schedule
Description
maidr_gantt() is maidr's word for "these rectangles are intervals in
lanes", the way annotate() is ggplot2's word for "this is
decoration". A rectangle layer carries no evidence of which it is – the
eight-chart table above the GeomRect branch in
detect_layer_type() is the measurement that closed every structural
rule – so the function the author called is the answer rather than
evidence towards it.
Usage
layer_is_declared_gantt(layer)
Arguments
layer |
A ggplot2 layer object |
Details
Two carriers are read, field first, because they fail in opposite directions. Measured on ggplot2 3.4.4:
maidr_gantt(m) head=maidr_gantt field=gantt
maidr::maidr_gantt(m) head=::/maidr/maidr_gantt field=gantt
one-deep user wrapper head=maidr_gantt field=gantt
two-deep user wrapper head=maidr_gantt field=gantt
do.call(maidr_gantt, list(m)) head=<coerce error> field=gantt
geom_rect(m) head=geom_rect field=NULL
annotate("rect", ...) head=annotate field=NULL
do.call() leaves the closure itself at constructor[[1]],
where as.character() raises "cannot coerce type 'closure' to vector
of type 'character'" – the identical hole layer_is_annotation()
has for do.call(annotate, ...) – and the field answers there. The
constructor answers for a ggplot2 that re-instantiated the layer through
ggproto() and dropped a field it did not know. Both are wrapped, so
a layer that answers neither is refused rather than raising.
Membership rather than equality on the head, for the reason
layer_is_annotation() gives: maidr::maidr_gantt(...) heads
as c("::", "maidr", "maidr_gantt").
Value
TRUE when maidr_gantt() built the layer
Whether a layer's points were displaced from their data positions
Description
Whether a layer's points were displaced from their data positions
Usage
layer_is_jittered(layer)
Arguments
layer |
A ggplot2 |
Value
TRUE when the layer carries a jittering position adjustment.
Whether a line layer maps the ROC's own vocabulary
Description
A ROC curve drawn as geom_line() or geom_path() carries no evidence of
what it means except its column names, and two producers name them after
the rates themselves: pROC::ggroc() maps specificity or
1-specificity against sensitivity, and ggplot2::autoplot() of a
yardstick::roc_curve() maps 1 - specificity against sensitivity.
Those names are the claim, and nothing else is read as one – a line of
fpr against tpr under any other column names is declared with
maidr_roc() instead, because a rule loose enough to catch it would catch
charts that are not ROC curves.
Usage
layer_maps_roc_rates(layer, plot_object)
Arguments
layer |
A ggplot2 layer |
plot_object |
The plot the layer belongs to |
Value
TRUE when the layer's x and y are specificity and sensitivity
Which of a plot's layers drew no rows
Description
The one place the emptiness rule lives, so the orchestrator and the
patchwork leaf path cannot disagree about it. A leaf inside a
patchwork composition is classified by
ggplot2_patchwork_utils.R rather than by
Ggplot2PlotOrchestrator$detect_layers(), so a rule written only in
the orchestrator would have left every composed chart ghosting (#232).
Usage
layers_that_drew_nothing(plot)
Arguments
plot |
A ggplot object. |
Details
One ggplot_build() per plot, not per layer. That is what makes this
affordable at all: the same question asked inside
detect_layer_type() would multiply the build by the layer count,
which is why #231 applied it to one geom only.
A build that cannot answer reports nothing empty. A plot that will not build is a bigger problem than this one, and it is about to be met by whatever else needs the build.
Value
Integer indices into plot$layers, possibly empty.
Key aesthetic values so a missing one stays distinct from the string "NA"
Description
paste() stringifies NA to "NA", which collapses a missing value onto a
level that is literally those two characters – so a grid keyed that way
cannot tell the two apart, and a duplicate test built on it does not see
the collision. Every present value is prefixed with "=", so the missing
key is one nothing else can produce.
Usage
level_keys(values)
Arguments
values |
A vector of aesthetic values |
Details
The missing key is a non-empty string on purpose. "" would read as the
obvious sentinel and is a trap: R lets "" %in% names(x) answer TRUE and
then throws "subscript out of bounds" on x[[""]], because empty is how a
name-less element is spelled. A lookup guarded by %in% – which is how
both bar processors read their cells – would pass the guard and abort.
Value
Character vector of keys, one per value, never NA
The text ggplot2 draws for one level
Description
The missing level reads as the two characters "NA", which is what is printed on its axis tick and in its legend key, so the announcement names the same category a sighted reader is looking at. A level that is literally the string "NA" reads the same way and is a different level: two categories, two ticks, both saying "NA", which is what ggplot2 draws.
Usage
level_label(level)
Arguments
level |
One level from |
Value
A length-1 character string, never NA
Find the environment a name is bound in
Description
Walks the enclosing chain from env the way R's own lookup does,
stopping once the global environment has been checked: names that resolve
beyond it live in attached packages, which no plotting loop rebinds.
Usage
locate_binding_env(name, env)
Arguments
name |
Name to look up |
env |
Environment to start from |
Value
The environment holding name, or NULL when unbound
Log Plot Call to Device Storage
Description
Records a plot call in the device-specific storage.
Usage
log_plot_call_to_device(
function_name,
call_expr,
args,
device_id = grDevices::dev.cur(),
call_env = NULL
)
Arguments
function_name |
Name of the plotting function |
call_expr |
The call expression |
args |
List of function arguments |
device_id |
Graphics device ID |
call_env |
Optional environment for replaying unevaluated (NSE)
arguments recorded in |
Value
NULL (invisible)
MAIDR Package Options
Description
Configure MAIDR interception and display behavior using R's options system.
Available Options
maidr.auto_showLogical. Master switch for all MAIDR interception. When FALSE, all plotting functions behave as standard R. Default: TRUE.
maidr.base_rLogical. Enable Base R plot interception. When TRUE, Base R plots are captured and displayed in the MAIDR viewer. Default: TRUE.
maidr.ggplot2Logical. Enable ggplot2 auto-display. When TRUE, ggplot2 objects are automatically rendered in the MAIDR viewer instead of the standard graphics device. Default: TRUE.
maidr.startup_messageLogical. Show startup message when package is loaded. Default: TRUE.
maidr.dotpad_sdk_urlCharacter. URL of a copy of the DotPad tactile-display SDK module (
DotPadSDK-3.0.3.js) that you serve yourself. maidr.js does not bundle the SDK, whose braille engine is a 14 MB liblouis build; unless told otherwise it imports the vendor's copy from jsDelivr the first time a DotPad is connected, from a document rendered withuse_cdn = FALSEas much as any other. Set this to keep that path off the network too. Falls back to the environment variableMAIDR_DOTPAD_SDK_URL. Default: unset.maidr.dotpad_asset_base_urlCharacter. URL of the directory holding the SDK's braille engine (
liblouis.js,.wasm,.data), needed only when it is not thelib/folder beside the module. Falls back to the environment variableMAIDR_DOTPAD_ASSET_BASE_URL. Default: unset.maidr.dotpad_sdk_dirCharacter. Directory where
maidr_download_dotpad_sdk()writes the SDK and whereshow()andsave_html()look for it when a document is rendered withuse_cdn = FALSE. Falls back to the environment variableMAIDR_DOTPAD_SDK_DIR, then to a per-user cache directory. Default: unset.maidr.cdn_versionCharacter. Which MAIDR.js the CDN paths load: a version such as
"4.9.0"(a leadingvis accepted),"bundled"for the version bundled with this package (maidr:::MAIDR_VERSION), or"latest"for jsDelivr's@latesttag. Either tag skips the version lookup described below. Anything else warns once and is ignored. Falls back to the environment variableMAIDR_CDN_VERSION. Default: unset, which loads the latest published version.maidr.cdn_timeoutNumeric. Seconds allowed for the whole CDN version lookup, clamped to between 0.1 and 30. Falls back to the environment variable
MAIDR_CDN_TIMEOUT. Default: 3.maidr.locale_base_urlCharacter, or
FALSE. Where maidr.js fetches a language other than English from, in the documents that load the bundled maidr.js (see the section on languages below): a directory URL to serve the locale packs yourself, or""orFALSEto declare nothing, which keeps such a document off the network and in English. A URL set here is declared in CDN documents too. Falls back to the environment variableMAIDR_LOCALE_BASE_URL. Default: unset, which declares the packs of the bundled version on jsDelivr.
Setting Options
Options can be set in your .Rprofile to persist across sessions:
# Disable ggplot2 interception by default options(maidr.ggplot2 = FALSE) # Disable all interception options(maidr.auto_show = FALSE) # Suppress startup message options(maidr.startup_message = FALSE) # Serve the DotPad SDK from your own server instead of jsDelivr options( maidr.dotpad_sdk_url = "https://example.org/vendor/DotPadSDK-3.0.3.js", maidr.dotpad_asset_base_url = "https://example.org/vendor/lib/" ) # Serve MAIDR's language packs yourself, or never fetch one (English only) options(maidr.locale_base_url = "https://example.org/maidr/") options(maidr.locale_base_url = FALSE)
DotPad SDK and offline documents
The two maidr.dotpad_*_url options are written into every document
this package produces (show(), save_html(), the htmlwidget,
knitr and Shiny) as the globals window.MAIDR_DOTPAD_SDK_URL and
window.MAIDR_DOTPAD_ASSET_BASE_URL, ahead of maidr.js, which
reads them when a DotPad is connected. Nothing is written when neither is
set. Without them a DotPad needs network access to jsDelivr on first
connect, even from a use_cdn = FALSE document; the rest of the
document works offline either way.
The other way to keep a DotPad off the network is to download the SDK
once with maidr_download_dotpad_sdk(): show() and
save_html() then copy it into lib/dotpad-sdk-<version>/ beside
every use_cdn = FALSE document and declare the globals with that
relative path. A configured URL wins over a downloaded copy. The widget,
knitr and Shiny paths render their charts in srcdoc frames, where a
relative path has nothing to resolve against, so they use only the URL
options.
Languages other than English
MAIDR.js reads a chart in English on its own, and in Korean, Japanese,
Chinese, Spanish, German, French, Italian or Hindi from a locale pack,
locale-<code>.js, that it fetches from beside itself when the
reader's language is chosen or detected. A document that loads MAIDR.js
from the CDN finds the packs there. This package does not bundle them –
they would add 0.8 MB to an installed package already over CRAN's size
guideline – so every document that loads the bundled MAIDR.js, from
lib/ or inlined, declares window.maidrLocaleBaseUrl ahead of
it: the packs of the bundled version on jsDelivr, unless
maidr.locale_base_url names another place or none. English needs no
network; another language is fetched when the reader is online and stays
English when they are not. A page that declares
window.maidrLocaleBaseUrl itself keeps its own.
Which MAIDR.js the CDN serves
Documents that load MAIDR.js from the jsDelivr CDN – show() and
save_html() with use_cdn = TRUE, and the widget, knitr and
Shiny paths when they find the machine online – load the latest
published MAIDR.js, as the Python binding does. Documents rendered with
use_cdn = FALSE load the copy bundled with this package, and reach
the network only for the two things described above: a DotPad's SDK and
a language other than English.
The first CDN document in an R session asks which version is the latest:
jsDelivr's data API
(https://data.jsdelivr.com/v1/packages/npm/maidr/resolved?specifier=latest),
then the npm registry
(https://registry.npmjs.org/-/package/maidr/dist-tags) if that
fails, within maidr.cdn_timeout seconds for the two together. The
answer is kept for the rest of the session, and the document names that
version, which never changes under the reader. When neither answers –
offline, blocked, timed out – that too is kept, no error is raised, and
the document names the version bundled with this package, the copy
use_cdn = FALSE would serve, as the Python binding does. So does
an answer older than the bundled version. The mutable maidr@latest
tag, which jsDelivr caches for up to a week, is used only when
maidr.cdn_version = "latest" asks for it.
Pin a version when a document has to load the same MAIDR.js wherever and whenever it is opened, or to keep the one this package was tested with:
# The version bundled with this package, no lookup options(maidr.cdn_version = "bundled") # A particular release options(maidr.cdn_version = "4.9.0") # Or from the shell, for every session # MAIDR_CDN_VERSION=bundled Rscript render.R
The dependency carrying a MAIDR chart-library adapter
Description
The adapters are UMD bundles published beside maidr.js – highcharts.js
defines window.maidrHighcharts, echarts.js defines
window.maidrECharts – and are bundled in the same directory, so the
local and CDN copies are always the same release as the core they run
against. Only the adapter's own file is declared (all_files = FALSE): the
directory also holds the multi-megabyte core, which the maidr
dependency already copies.
Usage
maidr_adapter_dependency(adapter, use_cdn = FALSE)
Arguments
adapter |
|
use_cdn |
Logical, as in |
Value
A single htmltools::htmlDependency()
Check a configured CDN lookup budget and clamp it
Description
Check a configured CDN lookup budget and clamp it
Usage
maidr_bound_cdn_timeout(value, source)
Arguments
value |
The setting as given |
source |
What the setting is called, for the warning |
Value
A number of seconds in [0.1, 30]
Deparse a setting for a message, bounded in length
Description
Deparse a setting for a message, bounded in length
Usage
maidr_cdn_deparse(value)
Arguments
value |
Any R value |
Value
A single string of at most 80 characters
Script that loads maidr.js from the CDN, falling back to the page's copy
Description
Goes into a chart frame's srcdoc in place of a plain CDN <script>. When
the CDN load fails – offline, blocked – it looks in the parent document
for the copy maidr_page_bundle_dependency() put there. A srcdoc frame
shares its parent's origin, so it can read it.
Usage
maidr_cdn_loader_script(cdn_js_url)
Arguments
cdn_js_url |
URL of maidr.js on the CDN |
Details
The copy arrives in one of two shapes, and both are handled: a src (the
_files folder, or a data: URL) or inline text, which is what pandoc
turns a script into when it embeds it. maidr.js initialises itself when it
runs, so nothing is called once it has loaded. KaTeX, which it fetches only
when an AI response carries maths, is pointed at the page's copy through
window.maidrMathStylesheetUrl, or added as a <style> when inline.
Value
Character string holding a <script> element
Fetch one resolver endpoint
Description
The only function in this package that makes the version lookup's request, so tests replace it and never reach the network.
Usage
maidr_cdn_resolver_request(url, timeout)
Arguments
url |
Endpoint URL |
timeout |
Seconds allowed for the whole transfer |
Value
The response body as a string; an error on any failure
The time budget for the CDN version lookup, in seconds
Description
The maidr.cdn_timeout option, then the MAIDR_CDN_TIMEOUT environment
variable, then 3 seconds. A value that is not a positive number warns once
and the default applies – 0 does not mean "skip the lookup"; that is
maidr.cdn_version = "latest" or "bundled". A value outside 0.1 to 30
seconds warns once and is clamped: below the floor every lookup would time
out, and above the ceiling a value meant as milliseconds would hang a
render.
Usage
maidr_cdn_timeout()
Value
A number of seconds in [0.1, 30]
Get the MAIDR CDN base URL
Description
The jsDelivr directory holding the maidr.js that CDN documents load. The
version in it comes from maidr_cdn_version(): the latest published
maidr.js, resolved once per session, unless a setting pins it.
Usage
maidr_cdn_url()
Details
No integrity (SRI) attribute goes with it. A hash can only be written
for bytes known in advance, which here means the bundled version; the CDN
paths now load whatever version is current, whose hash this package cannot
know. The bundled copy needs none: it is shipped with the package, not
fetched from a third party.
Value
CDN URL string, without a trailing slash
The maidr.js version CDN documents load
Description
In order: the maidr.cdn_version option, the MAIDR_CDN_VERSION
environment variable, then the latest published version, looked up once
per session by maidr_resolve_cdn_version().
Usage
maidr_cdn_version()
Details
When the lookup fails – offline, blocked, timed out, or an answer that is
not a version – this returns the bundled version, MAIDR_VERSION, as
py-maidr does (xability/py-maidr#295). The alternative, jsDelivr's
@latest tag, is a mutable alias that jsDelivr serves with a cache
lifetime of up to seven days, so degrading to it would let a browser
replay a week-old build in exactly the case the lookup exists to cover.
The bundled version is a real published release, its URL is immutable,
and it is the copy use_cdn = FALSE would have served anyway. What it
costs is that a network hiccup leaves the session on a possibly older
release. @latest is still emitted when it is asked for by name, with
options(maidr.cdn_version = "latest").
A resolver answer older than the bundled version is refused the same way
(see maidr_is_older_than_bundled()): nothing obliges a resolver, or
whatever sits between it and this session, to answer with the current
release, and the bundled version is the one known to have shipped with
this package.
Value
A single string: a semantic version, or "latest" when that tag
was pinned
The CDN version a setting pins, if any
Description
Reads the maidr.cdn_version option, then the MAIDR_CDN_VERSION
environment variable; an unset or blank option falls through to the
variable. A value that is not a usable pin warns once and is ignored, so
the latest version is looked up as though nothing were set: a mistyped
version says "I want a particular release", not "stay off the network",
and the latest is closer to that than failing the render would be.
Usage
maidr_cdn_version_pin()
Value
A semantic version, "latest", or NULL when nothing usable is
set
Warn once per session for a given key
Description
A bad setting is read on every render, and one warning is enough.
Usage
maidr_cdn_warn_once(key, message)
Arguments
key |
What identifies this warning |
message |
The warning |
Value
NULL, invisibly
Compare two pre-release identifiers by semver precedence
Description
Numeric identifiers compare numerically and sort below alphanumeric ones; alphanumeric ones compare in ASCII order, whatever the locale's collation.
Usage
maidr_compare_identifier(x, y)
Arguments
x, y |
Single identifiers |
Value
-1, 0 or 1
Compare two pre-release identifier runs by semver precedence
Description
Compare two pre-release identifier runs by semver precedence
Usage
maidr_compare_prerelease(a, b)
Arguments
a, b |
Character vectors of dot-separated identifiers |
Value
-1, 0 or 1
Where maidr.js loads the DotPad SDK from
Description
maidr.js does not bundle the DotPad tactile-display SDK: its braille engine
is a 14 MB liblouis build that every document would carry for the few
readers who own the device. So the first time a reader connects a DotPad,
maidr.js imports the SDK from the vendor's published copy on jsDelivr,
pinned to a commit. That is the one path an offline document
(use_cdn = FALSE) still takes to the network. The document renders,
sonifies and brailles without it; only connecting a DotPad needs it, unless
the page names its own copy of the SDK, or one was downloaded with
maidr_download_dotpad_sdk() for save_html() to carry.
Usage
maidr_dotpad_config()
Details
maidr.js reads two globals off the page before it loads:
window.MAIDR_DOTPAD_SDK_URL, the SDK ES module, and
window.MAIDR_DOTPAD_ASSET_BASE_URL, the directory holding the braille
engine's liblouis.js, .wasm and .data files (by default the lib/
folder beside the module). This reads the R-side settings for them: the
options maidr.dotpad_sdk_url and maidr.dotpad_asset_base_url, falling
back to the environment variables MAIDR_DOTPAD_SDK_URL and
MAIDR_DOTPAD_ASSET_BASE_URL, which carry the same names as the globals.
An empty value counts as unset.
Value
A list with sdk_url and asset_base_url, each a single string
or NULL when unset.
See Also
The DotPad SDK globals as an htmltools dependency
Description
For the paths that assemble their document from dependencies rather than
a template: show(), save_html() and the knitr widget. The globals ride
in the dependency's head, and the dependency is listed ahead of the
maidr one so the head lands before the bundle's <script>.
Usage
maidr_dotpad_config_dependency(config = maidr_dotpad_config())
Arguments
config |
The settings, as returned by |
Value
An htmltools::htmlDependency(), or NULL when nothing is
configured
<script> tag that declares the DotPad SDK globals
Description
Emitted ahead of maidr.js wherever this package loads the bundle, so
maidr.js finds the globals already set when it reads them. Nothing is
emitted when neither setting is configured: maidr.js then falls back to
the vendor's copy on jsDelivr, as documented in maidr-options.
Usage
maidr_dotpad_config_script(config = maidr_dotpad_config())
Arguments
config |
The settings, as returned by |
Value
A character string: the tag, or "" when nothing is configured
Download one file of the SDK
Description
A seam for the tests, which replace it rather than reach the network.
Usage
maidr_dotpad_download_file(url, destfile)
Arguments
url |
Where the file is |
destfile |
Where to write it |
Details
Bounded rather than left to hang: a connection that takes more than half a minute to open, or that delivers under a kilobyte a second for a full minute, fails like any other error. A slow link still gets the 14 MB engine; a stalled one does not hold the session for good.
Value
destfile, invisibly
Why a file is not the one the manifest describes, or NULL
Description
Size first, because it is the failure with a story: the corrupt
liblouis.data that motivated the pin was 7,685 bytes short, and a size
says so where a digest only says "different".
Usage
maidr_dotpad_file_mismatch(path, expected)
Arguments
path |
The file on disk |
expected |
One row of the manifest's |
Details
Then the digests base R can compute: MD5 always, and SHA-256 too from
R 4.5, which added tools::sha256sum(). The manifest carries both so the
stronger check is used wherever it is available without adding a
dependency for the older R this package supports.
Value
A string naming the difference, or NULL when there is none
The local SDK dependency, when a document going offline should carry one
Description
Applies only to use_cdn = FALSE: that is the document whose reader has no
network, and the one whose lib/ folder already travels with it. A session
that names its own copy by URL keeps that – either URL option, set alone
or together, wins – and one that never downloaded the SDK gets exactly
what it did before.
Usage
maidr_dotpad_local_dependency(use_cdn = NULL)
Arguments
use_cdn |
The document's |
Details
Either option, not only the module's. Both this dependency and the URL
one write the same globals, and the later head wins in the browser, so
a document carrying both with only the engine's URL configured would load
the module from lib/ and the engine from that URL: the offline copy's
worst half, and the network dependency use_cdn = FALSE exists to remove.
Value
An htmltools::htmlDependency(), or NULL
Is a manifest's file path one that stays put?
Description
Each path is joined onto the download directory to decide where a fetched
file is written, so a manifest could otherwise name ../../.. and write
wherever it liked. Nothing user-authored reaches this today – the
manifest is committed and only a maintainer regenerates it – but the
download is the one place this package writes files it did not name, and
a check costs nothing.
Usage
maidr_dotpad_path_is_safe(path)
Arguments
path |
One key of the manifest's |
Value
TRUE when the path is relative and stays inside its directory.
Parse the shipped DotPad SDK manifest
Description
Split from maidr_dotpad_sdk_manifest() so the read happens once and the
parsing is testable on its own. Every field is checked, because the file
is not authored here: fetch-maidr-bundle.sh copies whatever
dist/dotpad-sdk.json the pinned maidr.js release ships. A field that
changed shape upstream is named as a bad manifest rather than surfacing
later as a vapply type error.
Usage
maidr_dotpad_read_manifest(path = NULL)
Arguments
path |
Where to read from. Defaults to the installed |
Value
The manifest, in the shape maidr_dotpad_sdk_manifest() returns.
Whether a directory holds a complete copy of the SDK
Description
Complete means every file in the manifest is present at its recorded
size. The digests are checked when the copy is made, not on every
render, so this costs a handful of file.info() calls.
Usage
maidr_dotpad_sdk_available(dir = maidr_dotpad_sdk_dir())
Arguments
dir |
Where to look |
Value
TRUE or FALSE
A downloaded SDK as an htmltools dependency
Description
For the documents show() and save_html() write. htmltools copies the
directory into <libdir>/dotpad-sdk-<version>/ when the document is saved, and
the dependency's head declares the two globals with that relative path,
so the saved page finds its copy wherever the folder is moved to, as long
as the two move together. libdir is what htmltools::save_html() is
called with; its default is what this package uses.
Usage
maidr_dotpad_sdk_dependency(dir = maidr_dotpad_sdk_dir(), libdir = "lib")
Arguments
dir |
A complete copy, as |
libdir |
The |
Value
An htmltools::htmlDependency()
Where a downloaded copy of the DotPad SDK lives
Description
The option maidr.dotpad_sdk_dir, then the environment variable
MAIDR_DOTPAD_SDK_DIR, then a per-user cache directory from
tools::R_user_dir() (~/.cache/R/maidr/dotpad-sdk/<version> on Linux,
where the version is the manifest's, 3.0.3 today).
Nothing is created by asking.
Usage
maidr_dotpad_sdk_dir()
Value
A single path
The DotPad SDK maidr.js is pinned to
Description
maidr.js loads the SDK from one commit of a repository on jsDelivr, and
this is that pin, with the size and digests of every file a copy consists
of. It is read from inst/dotpad-sdk.json, a copy of the
dist/dotpad-sdk.json the maidr npm package ships as the single source of
truth for its own pin. .github/scripts/fetch-maidr-bundle.sh refreshes
the file with the bundle, so the two cannot drift once the bundled
maidr.js is one that ships it. The maidr.js this package bundles (see
MAIDR_VERSION) predates the file and still falls back to earlier commits
of the vendor's repository when nothing on the page names a copy. That
fallback is exactly what a downloaded copy or a configured URL replaces,
so what a document loads is this pin either way; the bundle catches up at
its next refresh (tools/update-maidr-assets.R).
Usage
maidr_dotpad_sdk_manifest()
Details
The files are served from xability/dotpad-sdk-guide, a mirror of the
vendor's dotincorp/dotpad-sdk-guide. The vendor publishes SDK 3.0.3
only as a zip archive, which jsDelivr cannot serve a file out of, so the
mirror carries the extracted files, byte-verified against the archive;
the manifest's upstream entry records the vendor commit, the archive
path and its SHA-256.
The pin matters beyond immutability. Earlier commits of the vendor's
repository carry a corrupt liblouis.data: its .gitattributes said
* text=auto and the file is braille-table text with no NUL byte in it,
so git rewrote its line endings on commit. It is an Emscripten package
addressed by absolute byte offsets, so every table after the first dropped
byte was read from the wrong place and the braille line silently fell back
to grade 1. The pinned files carry the intact bytes.
The liblouis build is LGPL-2.1-or-later. Its licence text and the sources of the WebAssembly wrapper are listed because the vendor's README asks anyone who redistributes the SDK to keep them beside the runtime files, which is the LGPL's relinking requirement.
Read once per session: every render path asks for the manifest several times over, and the answer cannot change while the package is loaded.
Value
A list: version, repository, commit, base_url, module,
asset_dir, and files, a data frame with one row per file (path,
bytes, md5, sha256).
Read one DotPad setting from an option, then an environment variable
Description
Read one DotPad setting from an option, then an environment variable
Usage
maidr_dotpad_setting(option, envvar)
Arguments
option |
Name of the R option |
envvar |
Name of the environment variable consulted when the option is unset or empty |
Value
A single non-empty string, or NULL
Download the DotPad SDK for use offline
Description
maidr.js drives a DotPad tactile display
through the vendor's SDK, which it does not bundle: the braille engine
inside it is a 14 MB liblouis build, and every document would carry it for
the few readers who own the device. By default maidr.js imports the
vendor's published copy from jsDelivr, pinned to a commit, the first time
a DotPad is connected – the one path an offline document
(use_cdn = FALSE) still takes to the network.
Usage
maidr_download_dotpad_sdk(
dir = maidr_dotpad_sdk_dir(),
force = FALSE,
quiet = FALSE
)
Arguments
dir |
Where to write. Defaults to the option |
force |
Refetch files that are already present and correct. |
quiet |
Say nothing about what was fetched. |
Details
This fetches that pinned copy once – the module, the liblouis build, and
the LGPL licence text and wrapper sources the vendor asks redistributors to
keep beside it – verifying every file against its recorded size and
digests (MD5, and SHA-256 on R 4.5 or later), and writes a manifest.json
beside them naming the commit they came from.
From then on show() and save_html() copy it into lib/dotpad-sdk-<version>/
next to every use_cdn = FALSE document and tell maidr.js where it is, so
a reader connects a DotPad without the network. A file already present and
correct is left alone, so a second call costs nothing.
A page served from somewhere else – an intranet host, or a knitr document,
whose charts live in srcdoc frames with no base URL for a relative path
to resolve against – names its copy by URL instead, through the options
maidr.dotpad_sdk_url and maidr.dotpad_asset_base_url; see
maidr-options. A configured URL wins over a downloaded copy.
Value
The directory, invisibly.
See Also
maidr-options for naming a copy by URL
Examples
## Not run:
maidr_download_dotpad_sdk() # about 14 MB, once
save_html(p, "chart.html", use_cdn = FALSE) # carries the SDK in lib/
## End(Not run)
Ask the resolvers which maidr.js version latest is
Description
Tries jsDelivr's data API, then the npm registry, within one shared time
budget: each request gets whatever the budget has left, and curl enforces
it as a limit on the whole transfer, name resolution included. Never
raises and never warns – a failed lookup must not fail a render – so
every failure, whether the network, an HTTP status, or an answer that is
not JSON or not a version, is NULL.
Usage
maidr_fetch_latest_cdn_version(budget)
Arguments
budget |
Seconds for the whole lookup |
Value
A semantic version, or NULL
Declare that a rectangle layer draws a schedule
Description
maidr_gantt() is ggplot2::geom_rect() with one thing added: the author
saying that these rectangles are intervals in lanes. A declared layer is
read as a gantt – lanes named, intervals announced, every bar
highlightable – where the same rectangles drawn with geom_rect() are
left unread and cost the whole chart its interactivity.
Nothing about the picture changes. The declaration is carried on the layer
object, not in the aesthetics, so the same xmin/xmax/ymin/ymax the
author would have written to geom_rect() produce the same chart: measured
on ggplot2 3.4.4, the built data is identical() to the bare
geom_rect() layer's and the panel's x.range and y.range are identical
too. Swapping geom_rect( for maidr_gantt( moves nothing on the page.
The gantt layer type [experimental] is one of the experimental plot
types: it has not been through a user study, and its reading may change
without a deprecation period. See "Experimental Plot Types" in the README.
Usage
maidr_gantt(
mapping = NULL,
data = NULL,
position = "identity",
...,
lane_axis = c("y", "x"),
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE
)
Arguments
mapping |
Aesthetics, as for |
data |
The layer's data, as for |
position |
Position adjustment, as for |
... |
Other arguments passed to the layer, as for
|
lane_axis |
Which axis the lanes run up: |
na.rm |
If |
show.legend |
Whether this layer is included in the legends. |
inherit.aes |
If |
Value
A ggplot2 layer, to be added to a plot with +.
Why the author is asked
A rectangle layer carries no evidence of what it means. Five structural
rules were measured against eight charts on ggplot2 3.4.4, and the best of
them – bands partition on the lane axis, more than one band, more than one
distinct span, minus a complete-lattice veto – scored 6 of 8 and still
claimed a heatmap with one cell missing and a two-region highlight. The
table is recorded above the reading itself, in
R/ggplot2_adapter.R. A monotone waterfall and a one-task-per-lane
schedule are the same rectangles, so there is nothing in the geometry to
separate; asking the author is the only unfalsified rule.
The consequence is that this is trusted. maidr_gantt() over heatmap
coordinates announces a heatmap as a schedule, and the package believes it,
because any guard strong enough to catch that is the rule the measurements
above ruled out.
What it costs not to declare
An undeclared geom_rect() layer reads as "unknown", which drops the
whole plot to a static image with the "Plot contains unsupported elements"
warning. That is unchanged by this function, deliberately: every chart
already written keeps exactly the reading it has today.
Lane names
With numeric ymin/ymax the lane axis is continuous and has no level
names to borrow, so a lane is named by the single explicit tick drawn
inside it – scale_y_continuous(breaks = 1:3, labels = c("design", "build", "test")) – and by its position on the axis otherwise. A tick
whose label is a rendering of its own number is a coordinate rather than a
name: measured on the default scale the panel's labels are NA, 1, 2, 3, NA, each one its own break written out, and a lane called "2" says less
than a lane called by the position 2 it sits at.
See Also
save_html() and show() for rendering the declared chart
Examples
if (requireNamespace("ggplot2", quietly = TRUE)) {
tasks <- data.frame(
lane = c(1, 2, 3, 2),
start = c(0, 3, 8, 12),
end = c(3, 8, 11, 15)
)
schedule <- ggplot2::ggplot(tasks) +
maidr_gantt(ggplot2::aes(
xmin = start, xmax = end,
ymin = lane - 0.4, ymax = lane + 0.4
)) +
ggplot2::scale_y_continuous(
breaks = 1:3,
labels = c("design", "build", "test")
) +
ggplot2::labs(x = "week", y = "task")
# The same rectangles written with `geom_rect()` draw the same chart and
# are left unread, which costs the plot its interactivity.
if (interactive()) {
show(schedule)
}
}
Get Current MAIDR Fallback Settings
Description
Retrieves the current fallback configuration for MAIDR.
Usage
maidr_get_fallback()
Value
A list with the current fallback settings:
-
enabled: Logical indicating if fallback is enabled -
format: Character string of the image format -
warning: Logical indicating if warnings are shown
See Also
maidr_set_fallback() to configure settings
Examples
# Get current settings
settings <- maidr_get_fallback()
print(settings)
Register JS dependencies for maidr
Description
Creates the HTML dependency for the MAIDR JavaScript bundle.
Behavior is controlled by the use_cdn parameter:
If
TRUE: Use CDN (requires internet): the latest published maidr.js, asmaidr_cdn_url()resolves it, unlessmaidr.cdn_versionpins oneIf
FALSE(default): Use local bundled files (works offline; a reader whose language is not English fetches that language's pack when online, see below)If
NULL: Same asFALSE- use local bundled files
Usage
maidr_html_dependencies(use_cdn = NULL)
Arguments
use_cdn |
Logical. If |
Details
We default to local bundled assets for deterministic rendering. Previously
we auto-detected via curl::has_internet(); when internet was available
the CDN path was selected, which combined with a (now-fixed) malformed
nested-<html> HTML scaffold caused base R chart SVGs to render squished
in the upper-left of the viewport. Local assets match the ggplot path that
has always rendered correctly. Users who want CDN can still pass
use_cdn = TRUE explicitly.
When a DotPad SDK location is configured (see maidr-options), a
maidr-dotpad-config dependency precedes the maidr one: its head
declares the window.MAIDR_DOTPAD_* globals, and listing it first is what
puts them ahead of the bundle's <script> in the rendered document.
A document that loads the bundled copy also gets a maidr-locale-config
dependency ahead of the bundle. maidr.js fetches any language but English
as a locale pack from beside itself, and this package does not bundle the
packs, so its head declares window.maidrLocaleBaseUrl: the packs of the
bundled version on jsDelivr, unless the session names another place or
none (see maidr_locale_base_url() and maidr-options).
No stylesheet is declared. MAIDR styles its interface at runtime, and
since maidr 3.75.1 the published maidr.css is a placeholder with no
rules in it. The one stylesheet that does carry rules, maidr-math.css
(KaTeX, for LaTeX in AI chat responses), is fetched by maidr.js itself,
resolved against the URL it was loaded from – the CDN directory, or the
lib/ folder htmltools copies the bundle into.
Value
A list of htmlDependency objects: the maidr bundle, preceded by
maidr-dotpad-config when a DotPad SDK location is configured and by
maidr-locale-config when a locale pack location is declared
Make a plotly, highcharter or echarts4r htmlwidget accessible
Description
Attaches MAIDR to an interactive chart drawn by another R package, so a screen reader user can explore it with the keyboard, hear it as sonification, and read it as text and braille. The chart is read by the MAIDR JavaScript adapter for the library that draws it, once it has been drawn in the browser; nothing about it is recomputed in R.
Usage
maidr_htmlwidget(widget, use_cdn = FALSE)
Arguments
widget |
An htmlwidget created by plotly, highcharter or echarts4r. |
use_cdn |
Logical. Where the MAIDR scripts are loaded from:
|
Details
Supported widgets:
-
plotly:
plotly::plot_ly()andplotly::ggplotly(). MAIDR's core detects a Plotly chart on the page by itself, so no adapter is added. -
highcharter:
highcharter::highchart(),highcharter::hchart()and the stock, map and gantt variants. -
echarts4r:
echarts4r::e_charts(). The chart is switched to ECharts' SVG renderer, since MAIDR highlights the mark being read by finding it among the drawn SVG elements, and the default canvas renderer draws none.
Which chart types each library supports is decided by its MAIDR adapter; see https://maidr.ai/ for the lists. A chart the adapter cannot read is left as it was drawn, with a warning in the browser console.
The widget keeps working everywhere an htmlwidget does: the RStudio
viewer, htmlwidgets::saveWidget(), R Markdown and Quarto documents,
and Shiny (plotly::renderPlotly(),
highcharter::renderHighchart(), echarts4r::renderEcharts4r()),
where the chart is read again each time the server re-renders it.
Applying it twice returns the widget unchanged.
Value
The widget, with MAIDR attached. Print it, return it from a Shiny render function, or save it as you would the original.
Examples
if (requireNamespace("plotly", quietly = TRUE)) {
w <- plotly::plot_ly(
x = c("Mon", "Tue", "Wed"), y = c(20, 14, 23), type = "bar"
)
w <- maidr_htmlwidget(w)
}
## Not run:
# Pipe-friendly
library(echarts4r)
mtcars |>
e_charts(wt) |>
e_scatter(mpg) |>
maidr_htmlwidget()
## End(Not run)
Which MAIDR adapter reads a widget
Description
Which MAIDR adapter reads a widget
Usage
maidr_htmlwidget_adapter(widget)
Arguments
widget |
The object passed to |
Value
"plotly", "highcharts" or "echarts".
Parent-side listener for the messages a MAIDR iframe posts
Description
Handles two messages, both keyed to the frame that sent them by matching
contentWindow against the message's source:
Usage
maidr_iframe_host_script()
Details
-
maidr-iframe-heightresizes the frame to its content. -
maidr:frame-focus-escapemoves focus out of the frame and into this document, when the reader shift-tabs off the chart and the browser has nowhere in this page to send them. Keyboard events do not cross a frame boundary, so while the reader is inside the chart the page around it hears nothing; if Shift+Tab then leaves the document altogether for the browser's own UI, the page cannot be driven from the keyboard at all. On a reveal.js slide that is exactly what happens — the deck renders no controls of its own, so a chart is the first thing on the page — and no key reaches the deck. The frame asks for the handoff rather than performing it, which keeps working whether or not it can reach this document: it could not when the chart was embedded through adata:URL, and a message costs nothing now thatsrcdocmeans it could.
Focus goes to the tab stop before the frame where this page has a reachable
one, which is what the browser would have done. Where it has none, focus
lands on the element holding the frame — a reveal.js slide is a
<section>, so on a slide deck that is the slide itself.
Reachability is checked rather than assumed: reveal.js leaves the slides on either side of the current one rendered, so a chart on the previous slide is a tab stop in document order even though it is marked hidden.
So is the handoff itself. Asking an element to take focus is not the same as
it taking focus — focus() on an element with no rendered box is a silent
no-op, and Shiny wraps every output in a display: contents div — so the
outcome is read back and the ancestors are walked until one actually holds
it. An element is asked as it stands before being given tabindex="-1", so
a tab stop this page already owns is never taken out of the tab order, and a
tabindex added to one that still refuses is removed again.
Registered at most once per document (guarded by a window flag), no matter how many iframes embed it.
Value
Character string with a script tag
Get <style>/<script> tags with the bundled assets inlined
Description
Reads the bundled maidr.js/maidr-math.css once per session and caches the assembled tags.
Usage
maidr_inline_asset_tags()
Details
KaTeX is inlined rather than left to maidr.js to fetch, because these
tags go into a standalone document whose script is inline: it has no URL
of its own, so the runtime has nothing to resolve the stylesheet against.
Value
A named list with css_tag and js_tag strings
Check internet availability, with a time-boxed cache
Description
curl::has_internet() can block for seconds on offline machines, so the result is cached rather than probed per plot. The cache is time-boxed to MAIDR_INTERNET_CACHE_TTL seconds so a stale answer self-heals: a transient failure does not pin the rest of the session to inlining the multi-megabyte bundle, and a session that goes offline after a successful probe stops emitting documents that point at a CDN it can no longer reach.
Usage
maidr_internet_available()
Value
TRUE if internet appears available
Is a resolved version older than the bundled one?
Description
Semantic version precedence, as py-maidr's _is_older_than_bundled
applies it: MAJOR.MINOR.PATCH compared numerically with
numeric_version(); on a tie, a pre-release sorts below the release it
precedes (4.9.0-rc.1 < 4.9.0), and two pre-releases compare
identifier by identifier, numeric ones numerically and below alphanumeric
ones, alphanumeric ones in ASCII order, a shorter run below a longer one
it begins. Build metadata (+build.5) carries no precedence and is
ignored.
Usage
maidr_is_older_than_bundled(resolved, bundled = MAIDR_VERSION)
Arguments
resolved |
The version the resolver answered with |
bundled |
The version bundled with this package |
Details
A version that cannot be compared is not called older: the resolver's answer, already checked to be a semantic version, stays in place.
Value
TRUE when resolved sorts below bundled
Is a string a semantic version?
Description
Is a string a semantic version?
Usage
maidr_is_semver(x)
Arguments
x |
Value to test |
Value
TRUE for a single string of at most 128 characters in semantic
version form, otherwise FALSE
Encode a string as a JavaScript literal safe inside a <script> element
Description
JSON is a subset of JavaScript, so jsonlite does the quoting. It leaves
/ alone, though, and an HTML parser ends the surrounding <script> at
the first </ it sees whatever the JavaScript around it says, so that
sequence is escaped too.
Usage
maidr_js_string_literal(x)
Arguments
x |
A single string |
Value
The quoted literal
Get paths to local MAIDR assets
Description
Returns the file paths to the locally bundled MAIDR JavaScript and KaTeX
stylesheet. The stylesheet is maidr-math.css, with its base64 web fonts
stripped by .github/scripts/fetch-maidr-bundle.sh to keep the installed
package under CRAN's size limit; KaTeX's layout rules are intact and only
the glyphs fall back to system fonts.
Usage
maidr_local_assets()
Value
A named list with 'js' and 'math_css' file paths
Where maidr.js should fetch its locale packs from
Description
Reads the maidr.locale_base_url option, then the MAIDR_LOCALE_BASE_URL
environment variable (see maidr-options). A place either of them names is
declared in every document. "" or FALSE declares nothing. Left unset,
a document that loads the bundled maidr.js gets the packs of the bundled
version on jsDelivr, and one that loads maidr.js from the CDN gets nothing,
since its packs sit beside that copy.
Usage
maidr_locale_base_url(use_cdn = FALSE)
Arguments
use_cdn |
Whether the document loads maidr.js from the CDN |
Value
A directory URL, or NULL when nothing is to be declared
The locale pack location as an htmltools dependency
Description
For the paths that assemble their document from dependencies: show(),
save_html(), the htmlwidget and knitr. htmltools writes a dependency's
head after its scripts, so the location rides in a dependency of its own,
listed ahead of the maidr one, as maidr_dotpad_config_dependency() does.
Usage
maidr_locale_config_dependency(use_cdn = FALSE)
Arguments
use_cdn |
Whether the document loads maidr.js from the CDN |
Value
An htmltools::htmlDependency(), or NULL when nothing is to be
declared
The locale pack location as a <script> element
Description
For the documents assembled from a template. It keeps a location the page already declared, so an author's own tag wins whichever comes first.
Usage
maidr_locale_config_script(url = maidr_locale_base_url())
Arguments
url |
As returned by |
Value
The element, or "" when url is NULL
Turn a CDN version setting into the version a URL names
Description
Turn a CDN version setting into the version a URL names
Usage
maidr_normalize_cdn_pin(value, source)
Arguments
value |
The setting as given |
source |
What the setting is called, for the warning |
Value
A semantic version, "latest", or NULL (with a warning, once per
distinct value) when value is not usable
Disable MAIDR Plot Interception
Description
Disables automatic MAIDR rendering and restores normal plot behavior. After calling this, Base R plots display in the standard graphics window and ggplot2 objects render with the default ggplot2 method.
Usage
maidr_off()
Value
Invisible TRUE on success
See Also
maidr_on() to enable MAIDR rendering
Enable MAIDR Plot Interception
Description
Turns on the accessible rendering of ggplot2 and Base R plots, and installs the knitr hooks that an R Markdown or Quarto document needs.
Usage
maidr_on()
Details
Interception is on by default after library(maidr): printing a ggplot2
object opens it in the MAIDR viewer, and Base R plotting calls are
recorded until show() is called. Calling maidr_on() yourself is needed
in two places: after maidr_off(), to start again, and once in the setup
chunk of an R Markdown or Quarto document, where it registers the
knit_print methods and the plot hook that turn every plot the document
draws into an accessible chart. library(maidr) alone installs neither.
Value
Invisible TRUE on success
See Also
maidr_off() to disable MAIDR rendering
Examples
library(maidr)
# Enable interception (on by default after library(maidr))
maidr_on()
# Now all plots render as accessible MAIDR widgets
library(ggplot2)
ggplot(mtcars, aes(x = factor(cyl))) +
geom_bar()
barplot(table(mtcars$cyl))
MAIDR Output Container for Shiny UI
Description
Creates a Shiny output container for MAIDR widgets using htmlwidgets. This provides automatic dependency injection and robust JavaScript initialization.
Usage
maidr_output(output_id, width = "100%", height = "400px")
Arguments
output_id |
The output variable to read the plot from |
width |
The width of the plot container (default: "100percent") |
height |
The height of the plot container (default: "400px") |
Value
A Shiny widget output function for use in UI
Examples
if (interactive()) {
library(shiny)
ui <- fluidPage(maidr_output("myplot"))
}
The bundle a knitted document carries for its charts
Description
The knitr paths put each chart in a srcdoc iframe whose <script> loads
maidr.js from the CDN. That document lives in an attribute, where neither
pandoc's --embed-resources (R Markdown's self_contained, Quarto's
embed-resources) nor anything else that rewrites a page's resources can
see it, so a self-contained document still needed the network to make its
charts accessible, and offline they were plain pictures.
Usage
maidr_page_bundle_dependency()
Details
This dependency gives the document one copy of the bundle that the tooling
does see: linked from the _files folder, or embedded into the page when
the document is self-contained. Its scripts are of a type no browser runs,
so the page itself is left alone; a chart frame whose CDN load fails reads
the copy from its parent instead (see maidr_cdn_loader_script()).
Value
A single htmltools::htmlDependency()
Read the version out of a resolver's answer
Description
Read the version out of a resolver's answer
Usage
maidr_parse_resolver_response(body, field)
Arguments
body |
The response body, JSON |
field |
The top-level field that holds the version |
Value
A semantic version, or NULL when the answer holds none
knitr Plot Hook for Base R Plots
Description
Intercepts Base R plot output and converts to MAIDR iframe. Uses iframe-based isolation to ensure each plot has its own MAIDR.js context. Automatically falls back to image rendering for unsupported plot types or non-HTML output formats (PDF, EPUB). This replaces knitr's default plot hook when maidr_on() is called.
Usage
maidr_plot_hook(x, options)
Arguments
x |
The plot file path from knitr |
options |
Chunk options |
Value
HTML string for the plot
MAIDR's custom print method for ggplot objects
Description
When MAIDR interception is enabled, this renders ggplot objects in the MAIDR interactive viewer. For unsupported plots, it falls back to the original ggplot2 rendering.
Usage
maidr_print_ggplot(x, newpage = is.null(vp), vp = NULL, ...)
Arguments
x |
A ggplot object |
newpage |
Draw on a new page? |
vp |
Viewport to draw in |
... |
Additional arguments passed to the print method |
Value
Invisible ggplot object
Forget the looked-up CDN version and the warnings already given
Description
For tests, and for a long-lived session that wants to pick up a release published since its first render.
Usage
maidr_reset_cdn_cache()
Value
NULL, invisibly
The latest published maidr.js version, looked up once per session
Description
The first call asks the resolvers (see maidr_fetch_latest_cdn_version())
and caches the answer, a failure included, so a machine that cannot reach
them pays the time budget once rather than on every render. Reset with
maidr_reset_cdn_cache().
Usage
maidr_resolve_cdn_version()
Value
A semantic version, or NULL when the lookup failed
Responsive page CSS dependency for MAIDR HTML output
Description
Returns an htmltools::htmlDependency() whose head payload injects a
viewport meta tag, a minimal CSS reset, and rules that make the embedded
SVG fill (or proportionally fit) the browser viewport. This is purely a
presentational layer; the SVG content, selectors, viewBox, and embedded
maidr-data attribute are untouched and the maidr JS frontend behaves
identically. We use a dependency (rather than an inline <style> tag in
the body) so the meta and style land in the document <head> produced by
htmltools::save_html().
Usage
maidr_responsive_dependency()
Value
A single htmltools::htmlDependency() object
Declare that a path layer draws a ROC curve
Description
maidr_roc() is ggplot2::geom_path() with two things added: the author
saying that the path is a receiver operating characteristic curve, and a
threshold aesthetic for the decision threshold each point was scored
at. A declared layer is read as a roc – each point announced as its
false and true positive rates, its threshold and its height above the
chance diagonal, the area under each curve and the best operating point
in the description – where the same path drawn with geom_path() or
geom_line() reads as a line, which says the rates and nothing a ROC
curve is drawn to say.
Nothing about the picture changes: the geom draws exactly what
geom_path() draws, and threshold reaches no mark.
The roc layer type [experimental] is one of the experimental plot
types: it has not been through a user study, and its reading may change
without a deprecation period. See "Experimental Plot Types" in the README.
Usage
maidr_roc(
mapping = NULL,
data = NULL,
position = "identity",
...,
auc = NULL,
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE
)
Arguments
mapping |
Aesthetics, as for |
data |
The layer's data, as for |
position |
Position adjustment, as for |
... |
Other arguments passed to the layer, as for
|
auc |
The area under each curve as the author computed it – with
|
na.rm |
If |
show.legend |
Whether this layer is included in the legends. |
inherit.aes |
If |
Value
A ggplot2 layer, to be added to a plot with +.
What is asked of the data
x is the false positive rate and y the true positive rate, both
fractions of one, in the order the curve is to be walked – from (0, 0)
up, as sklearn.metrics.roc_curve() returns them, or from (1, 1) down, as
pROC::coords() does; the area is measured over the points sorted by x
either way. Several classifiers on one chart are several groups, split by
colour, linetype or group as a multi-series line is, and each is
announced by its group's name.
Curves maidr reads without a declaration
Two idioms name their axes after the ROC's own vocabulary, and are read
as ROC curves as they stand: pROC::ggroc(), whose geom_line() maps
specificity (or 1-specificity with legacy.axes = TRUE) against
sensitivity, and ggplot2::autoplot() of a yardstick::roc_curve(),
whose geom_path() maps 1 - specificity against sensitivity. Where
x is specificity itself – pROC's default, drawn on a reversed axis –
the announced rate is 1 - specificity and the axis is named so, because
the height above chance is measured against the false positive rate and a
rate read off a reversed axis would put every point on the wrong side of
the diagonal. Neither idiom carries thresholds or the area into the plot,
so the area is measured from the points and no threshold is announced;
maidr_roc() is how an author supplies both.
Until the bundled maidr.js carries the trace
The roc trace shipped in maidr.js 4.9.0. While the copy this package
bundles is older (see maidr:::MAIDR_VERSION), a declared or detected
curve is read as a line, so that every chart keeps rendering; the
reading switches to roc with the next bundle update and no change to
the chart.
What it costs not to declare
A geom_line() of rates under any other column names keeps the line
reading it has today, deliberately: every chart already written keeps
exactly the reading it has.
See Also
maidr_gantt(), the other per-layer declaration; save_html()
and show() for rendering the declared chart
Examples
if (requireNamespace("ggplot2", quietly = TRUE)) {
curve <- data.frame(
fpr = c(0, 0.05, 0.1, 0.2, 0.35, 0.6, 1),
tpr = c(0, 0.55, 0.75, 0.86, 0.93, 0.98, 1),
cutoff = c(1, 0.8, 0.6, 0.45, 0.3, 0.15, 0)
)
roc <- ggplot2::ggplot(curve) +
maidr_roc(ggplot2::aes(x = fpr, y = tpr, threshold = cutoff)) +
ggplot2::geom_abline(linetype = "dashed") +
ggplot2::labs(x = "False positive rate", y = "True positive rate")
# The same path written with `geom_path()` draws the same chart and is
# read as a line: the rates, and none of what a ROC curve is read for.
if (interactive()) {
show(roc)
}
}
Configure MAIDR Fallback Behavior
Description
Configure how MAIDR handles unsupported plot types or layers. When fallback is enabled, unsupported plots are rendered as static images instead of failing or returning empty data.
Usage
maidr_set_fallback(enabled = NULL, format = NULL, warning = NULL)
Arguments
enabled |
Logical. If TRUE, unsupported plots fall back to image rendering. If FALSE, unsupported layers return empty data. If NULL (default), the current setting is kept. |
format |
Character. Image format for fallback: "png", "svg", or "jpeg". If NULL (default), the current setting is kept. |
warning |
Logical. If TRUE, shows a warning message when falling back to image rendering. If NULL (default), the current setting is kept. |
Value
Invisibly returns a list of the previous settings.
See Also
maidr_get_fallback() to retrieve current settings
Examples
# Save current settings and restore on exit
old_settings <- maidr_get_fallback()
on.exit(maidr_set_fallback(
enabled = old_settings$enabled,
format = old_settings$format,
warning = old_settings$warning
))
# Disable fallback (unsupported plots will have empty data)
maidr_set_fallback(enabled = FALSE)
# Use SVG format for fallback images
maidr_set_fallback(format = "svg")
# Disable warning messages
maidr_set_fallback(warning = FALSE)
# Configure multiple options
maidr_set_fallback(enabled = TRUE, format = "png", warning = TRUE)
Create MAIDR htmlwidget
Description
Internal function that creates an interactive MAIDR widget from a ggplot object. This is called internally by render_maidr() and should not be called directly. Use maidr_output() and render_maidr() for Shiny integration instead.
Usage
maidr_widget(
plot,
use_cdn = NULL,
width = NULL,
height = NULL,
element_id = NULL,
...
)
Arguments
plot |
A ggplot object, or NULL to auto-detect recorded Base R plots |
use_cdn |
Logical. Controls where MAIDR.js is loaded from, matching
This differs from |
width |
The width of the widget in pixels or CSS units (default: NULL for auto-sizing) |
height |
The height of the widget in pixels or CSS units (default: NULL for auto-sizing) |
element_id |
A unique identifier for the widget (default: NULL for auto-generated) |
... |
Additional arguments passed to create_maidr_html() |
Details
Uses iframe-based isolation to ensure MAIDR.js initializes properly. Each widget gets its own isolated JavaScript context where MAIDR.js can discover and initialize the SVG with maidr-data attribute.
Value
An htmlwidget object that can be displayed in RStudio, Shiny, or saved as HTML
MAIDR Widget Output for Shiny UI (Internal Alternative)
Description
Internal alternative Shiny UI function. This provides the same functionality as maidr_output() but is no longer recommended for direct use. Use maidr_output() and render_maidr() instead for better consistency.
Usage
maidr_widget_output(output_id, width = "100%", height = "400px")
Arguments
output_id |
The output variable to read the widget from |
width |
The width of the widget (default: "100percent") |
height |
The height of the widget (default: "400px") |
Value
A Shiny widget output function for use in UI
Map visual panel position to DOM panel name
Description
This function handles the mismatch between visual layout order (row-major) and DOM element generation order (column-major) in gridSVG.
Usage
map_visual_to_dom_panel(panel_info, gtable)
Arguments
panel_info |
Panel information from layout |
gtable |
Gtable object |
Details
Visual layout (row-major): 1 2 3 4
DOM order (column-major): 1 3 2 4
Value
Gtable panel name or NULL if not found
Advice shown when an attached package masks one of maidr's wrappers
Description
Shared by .onAttach, the attach hooks and the "No Base R plots
detected" errors so the wording stays in one place.
Usage
mask_advice(package)
Arguments
package |
Name of the package, as in WRAPPED_SUGGESTS. |
Value
A single advice string.
Name a recorded call's arguments the way R matched them
Description
A wrapper declared function(...) sees only the names the user typed, so
hist(x, 20) records an unnamed 20 and every processor asking for
args[["breaks"]] comes up empty. Running the recorded arguments through
match.call() against the definition R actually dispatched to restores
the names R itself assigned, once, for every processor.
Usage
match_recorded_args(function_name, definition, args)
Arguments
function_name |
Name of the recorded function |
definition |
The original (unwrapped) function that was called |
args |
Recorded argument list of evaluated values |
Details
Two properties are preserved deliberately:
-
Order.
match.call()reorders arguments into formal order; the recorded list keeps the user's order and only gains names. Replay doesdo.call(), which honours names regardless of position, whileapply_barplot_sorting()and friends still find the height in slot 1. -
The dispatch argument stays exactly as written. S3 dispatch happens on the first argument of the generic, and methods are free to rename it:
plot.formula()calls itformula, notx. Naming a positional first argument would therefore break replay in one direction or the other (plot(x = mpg ~ wt)never reachesplot.formula(), andplot(formula = ...)never satisfies the generic). Leaving it untouched makes the replayed call dispatch byte-identically to the user's.
Value
args with the names R matched, in the recorded order
Post-process a 2D subplot grid: if the layout is candlestick over volume-only bar (2 rows x 1 col, sharing an x-axis), collapse to a single 1x1 subplot whose layers are candlestick (+ embedded volume), bar, and optional line (multi-series MAs).
Description
Post-process a 2D subplot grid: if the layout is candlestick over volume-only bar (2 rows x 1 col, sharing an x-axis), collapse to a single 1x1 subplot whose layers are candlestick (+ embedded volume), bar, and optional line (multi-series MAs).
Usage
merge_candlestick_volume_panels(grid)
Combine a list of single-line layer entries into one multi-series line entry.
Description
Each input line layer's data is a list-of-series (typically length-1 for
a single GeomLine/GeomMA). We concatenate all series across all layers.
Usage
merge_line_layers(line_layers)
Details
Selector handling: each input layer now resolves to its OWN polyline grob
and emits one selector per curve it drew, so the inputs no longer overlap.
The dedupe-and-trim below is kept as a backstop, not as the mechanism: it
used to be load-bearing, because the generator discovered all polyline
grobs in the panel and handed every one of N line layers the same length-N
set. What still has to hold after merging is the frontend precondition
selectors.length === data.length, one selector per merged series, which
is why the trim below stays. There is deliberately no pad: a short
list fails that precondition and the frontend drops the layer's highlight
rather than aiming it at the wrong curve.
Evaluate an expression, muffling the retry's promise-restart warning
Description
When a call fails part-way through forcing an argument, that argument's promise is left interrupted. Forcing it again - which both the retry and the argument recording do - makes R warn "restarting interrupted promise evaluation". It is an artifact of retrying, not anything the user's call did, so it is muffled; every other warning passes through untouched.
Usage
muffle_promise_restart(expr)
Arguments
expr |
Expression to evaluate (lazily, inside the handler) |
Value
The value of expr
Message for show()/save_html()/maidr_widget() with nothing recorded
Description
Names every masking case that applies: the bare "create a plot first" wording is actively misleading there, because the user did draw a chart - it just went to the other package unrecorded.
Usage
no_base_r_plots_message()
Value
The error message string.
Replace every non-ASCII character with a numeric character reference
Description
Found and replaced as bytes. The same work done in characters, with a
UTF-8 perl regex, takes seconds on a document carrying the 1.8 MB
bundle, where this takes milliseconds: in bytes, a run of non-ASCII is a
run of bytes from 0x80 up, and nothing has to count characters to find it.
Usage
non_ascii_to_references(x)
Arguments
x |
A single string whose bytes are UTF-8, marked or not |
Value
x in ASCII, or unchanged when it is already ASCII or its bytes
are not valid UTF-8
Restate a rect grob's negative heights and widths as positive ones
Description
gridSVG::grid.export() warns "number of items to replace is not a
multiple of replacement length" on any rect grob drawn with a negative
height or width, and the warning reaches save_html(), where a plot that
warns falls back to a picture.
Usage
normalise_negative_rects(grob)
Arguments
grob |
A grob, gTree, gList, or gtable (or NULL) |
Details
Measured on a bare rectGrob() with nothing else to it: four rects with
positive heights export silently, and the same four with two heights
negated warn. So this is an upstream gridSVG defect rather than anything
about a particular chart – but it is reached by an ordinary one.
assocplot() draws every tile from a baseline with just = c("left", "bottom") and a signed height, so a cell below expectation is a negative
height by construction (#266); every association plot would warn.
A rect at (y, h) with h < 0 covers the same pixels as one at
(y + h, |h|), so the drawing is unchanged – only the arithmetic gridSVG
does with it. The same holds for x and a negative width.
The svglite export draws negative extents correctly; the repair is kept because it changes nothing drawn.
Value
The same tree with every rect's extent stated positively
Handle HIGH-level Call
Description
Updates state when a HIGH-level plotting function is called.
Usage
on_high_level_call(device_id = grDevices::dev.cur(), call_index)
Arguments
device_id |
Graphics device ID |
call_index |
Index of the call in the calls list |
Value
NULL (invisible)
Handle LAYOUT Call
Description
Updates state when a layout function (par, layout) is called.
Usage
on_layout_call(device_id = grDevices::dev.cur(), function_name, args)
Arguments
device_id |
Graphics device ID |
function_name |
Name of layout function |
args |
Function arguments |
Value
NULL (invisible)
Open a temporary device to suppress default graphics window
Description
Called by wrappers when no device is open to prevent R from opening the default interactive graphics device.
Usage
open_maidr_temp_device()
Value
The device ID of the temp device
Open the svglite page a chart is drawn on
Description
Open the svglite page a chart is drawn on
Usage
open_svg_device(width, height)
Arguments
width, height |
Page size in inches. |
Value
A function returning the page's SVG once the device is closed.
Organize subplots into 2D grid structure
Description
Organize subplots into 2D grid structure
Usage
organize_facet_grid(subplots, panel_layout)
Arguments
subplots |
List of processed subplot data |
panel_layout |
Panel layout information |
Value
2D grid structure
Is a package attached ahead of maidr on the search path?
Description
library(quantmod) after library(maidr) puts package:quantmod in
front of package:maidr, so an unqualified chartSeries() binds to
quantmod's own function and maidr's recording wrapper is never entered.
library(vioplot) and library(wordcloud) after maidr do the same to
vioplot() and wordcloud(): the "No Base R plots detected" error that
follows a bare call to either was measured with maidr 0.5.0 (#320).
Usage
package_masks_maidr(package)
Arguments
package |
Name of the package, as in WRAPPED_SUGGESTS. |
Details
maidr deliberately does not reach into another package's namespace to
win this race: overwriting a foreign package's binding would also
redirect the package's internal calls through maidr's ...-forwarding
wrapper, which for quantmod corrupts the match.call(expand.dots = TRUE)
it relies on. maidr reports the condition instead.
Value
TRUE when both packages are attached and package comes first.
The wrapped Suggests packages attached ahead of maidr right now
Description
The wrapped Suggests packages attached ahead of maidr right now
Usage
packages_masking_maidr()
Value
Package names, in WRAPPED_SUGGESTS order; empty when none masks.
Does a panel contain a layer of the given type?
Description
Does a panel contain a layer of the given type?
Usage
panel_has_layer_of_type(panel, type)
Arguments
panel |
A processed patchwork panel (with |
type |
Layer type string ("candlestick", "bar", "line", ...) |
Value
Logical
Return the (first) layer in panel whose type matches type
Description
Return the (first) layer in panel whose type matches type
Usage
panel_layer_of_type(panel, type)
Convert a Panel Slot Number to its (row, column) Grid Positions
Description
A layout() matrix may name the same panel in several cells; R draws that
panel once, spanning all of them. Returning every matching cell (in reading
order) lets the caller advertise the panel in each cell it actually covers,
so a spanned region is not mistaken for empty space. An mfrow/mfcol
grid cannot span, so it always yields exactly one cell.
Usage
panel_slot_positions(slot, panel_config)
Arguments
slot |
Panel slot number (1-based) |
panel_config |
Panel configuration from detect_panel_configuration() |
Value
List of integer vectors c(row, col); empty list if the slot occupies no cell
The transformation applied to one axis of a built plot
Description
The transformation applied to one axis of a built plot
Usage
panel_transformation(built, axis = "x", panel_id = NULL)
Arguments
built |
Built plot from |
axis |
|
panel_id |
Panel index for faceted plots, or NULL for the first |
Value
The transformation object, or NULL when there is none to undo
The arguments a periodogram call was made with
Description
Both entry points take the series as their first formal with nothing ahead
of it, and a recorded call keeps evaluated arguments, so the series is the
value itself. A call whose series is not numeric is declined rather than
coerced: the arguments of a call that stopped are recorded all the same,
and coercing would announce a curve computed from NAs.
Usage
periodogram_args(layer_info)
Arguments
layer_info |
Layer information with the recorded call. |
Value
The recorded arguments, or NULL when there is no series to read
One point per frequency
Description
One point per frequency
Usage
periodogram_points(x, y)
Arguments
x |
Frequencies, in the order they were drawn. |
y |
The value at each. |
Value
A list of list(x =, y =) points, empty when nothing lines up
The grob a periodogram's curve was drawn as, in its own panel
Description
gridGraphics numbers panels in draw order, so under par(mfrow = ) the
second chart's curve is graphics-plot-2-lines-1. The panel index is the
one the orchestrator assigned the layer; a layer without one is the first
panel.
Usage
periodogram_selector(layer_info, grob)
Arguments
layer_info |
Layer information carrying |
grob |
The grob name gridGraphics wrote: |
Value
A CSS selector for the curve's g element
Perpendicular distance from points to a line segment
Description
Perpendicular distance from points to a line segment
Usage
perpendicular_distance(points, start, end)
Arguments
points |
Nx2 numeric matrix of (x, y) points |
start |
Numeric vector of length 2 (line start) |
end |
Numeric vector of length 2 (line end) |
Value
Numeric vector of perpendicular distances
Address one grob that a chart draws a datum into as a polygon
Description
A pie's wedges and a mosaic's tiles are each their own grob, so each needs
its own selector – unlike a barplot(), whose bars all live inside one
rect grob. gridSVG appends .1 to the grob name and wraps the shape in a
group of that id, and the . has to be escaped for CSS.
Usage
polygon_cell_selector(grob_name)
Arguments
grob_name |
A grob name, as |
Value
A CSS selector for that grob's polygon
Position (1-based) of a layer among the polyline-producing layers of a plot
Description
layer_polyline_grobs() returns every polyline in the panel that no
geom-named grob tree claims, so the index used to pick one out has to be
counted over the same population.
geom_line() / geom_path() / tidyquant::geom_ma() (detected as
"line"), geom_step() (detected as "step") and geom_contour() /
geom_density_2d() (detected as "contour") each render one auto-named
polyline grob per layer, so all three types count. Counting only "line"
layers would index the wrong polyline for every layer of a plot that
combines them – and both charts would read correctly while outlining each
other's curves, which is the highlight-only failure xability/maidr#814
names.
Usage
polyline_layer_position(plot, layer_index)
Arguments
plot |
The ggplot2 object. |
layer_index |
Index of the layer of interest in |
Value
The 1-based position, or NULL when the layer produces no polyline or registry-based detection fails.
Every auto-named polyline inside a grob, in draw order
Description
Scoped to the grob handed in, so a caller that has already established which tree belongs to its layer cannot pick up a sibling layer's curve.
Usage
polylines_within(grob)
Arguments
grob |
A grob to walk. |
Value
List of polyline grobs, in the order they are drawn.
Resolve the printed label for a positional axis
Description
The name ggplot2 prints beside the x or y axis, which is the name a
reader needs in order to know what the numbers are. A labs()
override wins, then the layer's own mapping, then the plot's – the same
chain resolve_legend_label() walks for a legend title, because it
is the same chain ggplot2 walks.
Usage
positional_axis_label(plot, built = NULL, aes_name = "x", layer_index = NULL)
Arguments
plot |
The ggplot object |
built |
Built plot from |
aes_name |
|
layer_index |
Index of the layer whose mapping takes precedence, or NULL to consult only the plot-level mapping |
Details
The difference from the legend case is only what to do when none of them answers. A legend that has no title should have none; a positional axis always has one printed on the chart, so the aesthetic name is emitted rather than nothing. That is a poor label, but it is a label, and the alternative is a number announced with no name at all.
resolve_legend_label()'s documented caution – that labs()
records a title even for an unmapped aesthetic, so only ask about one the
layer is grouped by – does not apply here. A layer with no x or y mapping
has no positions to announce and does not reach a processor that would
ask.
Value
Character scalar, never NULL
Convert Currency Prefix to ISO 4217 Code
Description
Maps common currency symbols to their ISO 4217 codes for use in JavaScript's Intl.NumberFormat.
Usage
prefix_to_currency_code(prefix)
Arguments
prefix |
Currency symbol (e.g., "$", the Euro sign, the Pound sign) |
Value
ISO 4217 currency code (e.g., "USD", "EUR", "GBP")
Print a ggplot with the original (non-MAIDR) print method
Description
Print a ggplot with the original (non-MAIDR) print method
Usage
print_ggplot_natively(x)
Arguments
x |
A ggplot object |
Value
NULL (invisible)
Process a single facet panel
Description
Process a single facet panel
Usage
process_facet_panel(
plot,
panel_info,
panel_data,
facet_groups,
gtable_panel_name,
built,
layout,
gtable,
format_config = NULL
)
Arguments
plot |
The original plot |
panel_info |
Panel information |
panel_data |
Panel-specific data |
facet_groups |
Facet group information |
gtable_panel_name |
Gtable panel name |
built |
Built plot data |
layout |
Layout information |
gtable |
Gtable object |
format_config |
Optional format configuration from maidr label functions |
Value
Processed panel data
Process a faceted plot and return organized subplot data
Description
Process a faceted plot and return organized subplot data
Usage
process_faceted_plot_data(plot, layout, built, gtable, format_config = NULL)
Arguments
plot |
The faceted ggplot2 object |
layout |
Layout information |
built |
Built plot data |
gtable |
Gtable object |
format_config |
Optional format configuration from maidr label functions |
Value
List with organized subplot data in 2D grid format
Process a single patchwork panel
Description
Process a single patchwork panel
Usage
process_patchwork_panel(
leaf_plot,
panel_name,
panel_index,
row,
col,
layout,
gtable,
n_original_layers = NULL
)
Arguments
leaf_plot |
The leaf ggplot object |
panel_name |
Panel name from gtable |
panel_index |
Panel index |
row |
Panel row |
col |
Panel column |
layout |
Layout information |
gtable |
Gtable object |
n_original_layers |
Number of layers the user actually wrote. Defaults
to every layer of |
Value
Processed panel data
Process a patchwork plot and return organized subplot data
Description
Process a patchwork plot and return organized subplot data
Usage
process_patchwork_plot_data(plot, layout, gtable, original_plot = NULL)
Arguments
plot |
The patchwork plot object, with leaves already augmented |
layout |
Layout information |
gtable |
Gtable object |
original_plot |
The un-augmented composition. Supplied so each leaf is processed for the layers the user wrote rather than for the extra geoms a processor injected to render its selectors. |
Value
List with organized subplot data in 2D grid format
Whether a name refers to a processor class this package ships
Description
The check used to be exists(name, mode = "function"), and a processor is
an R6 generator rather than a function, so it matched nothing –
is.function(Ggplot2BarLayerProcessor) is FALSE and
class(...) is "R6ClassGenerator". Every entry a factory offered was
filtered out by it, so both factories reported an empty registry for every
processor they ship (#200).
Usage
processor_class_exists(processor_class_name)
Arguments
processor_class_name |
Name of the processor class. |
Value
TRUE when the name is an R6 generator that is reachable.
Advice shown when quantmod masks maidr's chartSeries() wrapper
Description
mask_advice() for quantmod.
Usage
quantmod_mask_advice()
Value
A single advice string.
Is quantmod attached ahead of maidr on the search path?
Description
package_masks_maidr() for quantmod, the first package this was noticed
with (#97).
Usage
quantmod_masks_maidr()
Value
TRUE when both packages are attached and quantmod comes first.
Convert R Date Format to Intl.DateTimeFormat Options
Description
Converts R strftime format strings to JavaScript Intl.DateTimeFormat options.
Usage
r_date_format_to_intl_options(format)
Arguments
format |
R date format string (e.g., "%Y-%m-%d") |
Value
List of Intl.DateTimeFormat options
Convert R Date Format to JavaScript Function
Description
Creates a JavaScript function string that formats dates according to an R strftime format string. Used for complex date formats that cannot be represented by Intl.DateTimeFormat options alone.
Usage
r_date_format_to_js_function(format, tz = "UTC")
Arguments
format |
R date format string |
tz |
Timezone |
Value
JavaScript function body string
Ramer-Douglas-Peucker algorithm for 2D polylines
Description
Iterative stack-based implementation to avoid R recursion limits.
Usage
rdp(points, epsilon)
Arguments
points |
Nx2 numeric matrix of ordered (x, y) points |
epsilon |
Maximum allowed perpendicular distance. Larger values yield fewer retained points. |
Value
Logical vector of length N (TRUE = keep this point)
Keep the title chartSeries() would have given the call it was made from
Description
Without a name, quantmod::chartSeries() titles the chart with the
expression its x was written as (as.character(match.call()["x"])), so
chartSeries(AAPL) is titled "AAPL". The call is replayed later with the
recorded value in place of that expression, and the title became the
series' numbers printed end to end. The name is taken from the call as
written, the way quantmod takes it, and recorded as an explicit name.
Usage
record_chartseries_name(args, call_expr)
Arguments
args |
The recorded arguments of the chartSeries() call |
call_expr |
The call as written |
Value
args, with name added when the caller gave none
Resolve one axis title from a recorded Base R call
Description
The author's own xlab=/ylab= always wins. An empty string counts as
unsupplied: Base R draws no title for it, so falling through to the chart
type's default announces more than the blank would, and the renderer would
otherwise substitute its generic "X"/"Y" anyway. This is how the
candlestick processor has always read these arguments.
Usage
recorded_axis_label(args, name, default = NULL)
Arguments
args |
Recorded argument list, or NULL |
name |
Argument to read: |
default |
What this chart type can honestly say when the author said nothing. Pass NULL when it can say nothing: an absent label leaves the generic to the renderer, which is where that decision belongs. |
Value
Character scalar, or default
The height a recorded barplot() call draws
Description
barplot() reads its data from height, which is its first formal. The
recorder names positional dots but leaves the dispatch argument as the
caller wrote it, so height arrives unnamed when it was passed by
position and named when it was not – and barplot(beside = TRUE, height = m) put beside in the first slot, where every reader used to look.
Usage
recorded_barplot_height(args)
Arguments
args |
Recorded argument list |
Value
The height vector or matrix, or NULL
Read a recorded logical argument the way its drawing function does
Description
Every base R reader asked isTRUE() of a recorded flag, and the base R
drawing functions ask if (x). The two agree on TRUE, on FALSE and on
absent, and disagree on every other truthy value R accepts in an if –
so a chart written stripchart(x, vertical = 1) was drawn vertically and
announced horizontally, with the values on the group axis and the group
positions on the value axis, silently, on a chart that renders as an
interactive one rather than as a fallback (#256).
Usage
recorded_flag(args, name, default = FALSE)
Arguments
args |
Recorded argument list |
name |
The formal's name |
default |
What an absent, |
Details
Measured, by reading each drawing function's own body:
| function | asks |
barplot.default | if (beside), (logx && horiz) |
bxp | if (horizontal) |
hist.default | if (freq1) |
stripchart.default | if (vertical) |
qqnorm.default, qqline | if (datax) |
vioplot.default | `if (horizontal |
All seven ask R's own truthiness, so all seven are read through this.
NA and an uncoercible value give the caller's default rather than an
error: if (NA) stops in R, but a reader that stops takes the whole
figure with it, and a chart read under its default is better than no chart
at all. A value of any length but one does the same, since if on one of
those errors too.
Value
TRUE or FALSE
The formula a recorded call carries, resolved
Description
The formula is the formula argument, the x argument, or the first
positional one, whichever is found first. On the NSE path it arrives as
the unevaluated call to ~, or – fmla <- y ~ x; plot(fmla, ...) – as
the name it was bound to, and either is resolved in the snapshot the
call was recorded with. Only a name or a ~ call is evaluated: an
arbitrary expression in the data slot (plot(rnorm(10))) is not a
formula and is not run again to find out.
Usage
recorded_formula(args, call_env = NULL)
Arguments
args |
Recorded argument list |
call_env |
The environment snapshot a deferred call was recorded with, or NULL when every argument is a plain value. |
Value
The formula object, or NULL when the call carries none
Resolve a recorded formula into the frame the chart was drawn from
Description
Base R calls are recorded and read later, at show()/save_html() time,
and for every argument but one that is harmless: the wrapper records
evaluated values, so a vector recorded is a vector and rebinding the
name it came from afterwards changes nothing.
Usage
recorded_formula_frame(
args,
call_env = NULL,
formula = recorded_formula(args, call_env)
)
Arguments
args |
Recorded argument list |
call_env |
The environment snapshot a deferred call was recorded with, or NULL when every argument is a plain value. |
formula |
The formula the call carries, as |
Details
A formula is the exception. It is a reference rather than a value – it
carries the environment it was written in – and a processor that calls
stats::model.frame() on it at render time resolves the variables
then. Measured (#254):
len <- c(1, 2, 3, 10, 11, 12); supp <- rep(c("OJ", "VC"), each = 3)
stripchart(len ~ supp) # draws 1,2,3 under OJ
len <- c(99, 98, 97, 96, 95, 94) # the user carries on working
supp <- rep(c("XX", "YY"), each = 3)
save_html(file = f) # announced 99,98,97 under XX
Every value and both group names belonged to bindings made after the drawing, and it was silent: the figure rendered as an interactive chart rather than as a fallback, so nothing said the numbers had moved.
So the frame is built here, while the call is being recorded and the
bindings are still the ones the chart was drawn from. stripchart.formula
and boxplot.formula build the same stats::model.frame(formula, data)
as they draw, so this is the frame they used rather than a reconstruction
of it.
Fixed at the recording layer rather than per processor because anything that reads a formula later inherits the same defect.
Value
The model frame, or NULL when the call carries no formula or the frame cannot be built – in which case the reader falls back to resolving it itself, exactly as before.
The main title a recorded call wrote, as text
Description
main = expression(alpha^2) is an ordinary way to put a Greek letter on a
chart, and a dozen readers passed the recorded value straight into the
layer's title. jsonlite::toJSON() has no method for an expression, so
the whole save failed on a title. A title that is not text is announced
as empty rather than failing the chart it sits on; the drawing keeps it.
Usage
recorded_main_title(args)
Arguments
args |
Recorded argument list |
Details
Exact-name lookup, since args$main would partial-match nothing today but
is the same shape as the args$x / xlab collision that emptied
monthplot() (#292).
Value
Character scalar, empty when there is no usable title
The two-way contingency table a recorded call was handed, when it is one
Description
mosaicplot() is given the table itself, so the recorded call carries
every number a mosaic layer wants – the counts, the margins they imply,
and the level names from dimnames(). Nothing is inferred from the
drawing.
Usage
recorded_two_way_table(args)
Arguments
args |
Recorded argument list, or NULL |
Details
Only a two-dimensional table is returned. mosaicplot() accepts three and
more, splitting recursively, and a mosaic layer has one category axis and
one fill – so a deeper table has nowhere to put its later dimensions and
is declined rather than flattened into a cross-classification the chart
does not claim. A table with unnamed margins is declined too: the levels
are what a reader navigates by, and positions are not levels.
mosaicplot()'s other calling style hands it a formula and a data
argument instead, and mosaicplot.formula() builds the table from the two.
That is recovered by formula_two_way_table() rather than declined, for
the reason the direct call is read at all: the table is the one the chart
draws, arrived at by the same code, not a plausible reconstruction (#248).
Shared by the adapter's dispatch and the processor's extraction so the two cannot disagree about which calls are readable.
Value
A 2-D table with named margins, or NULL
Hand jsonlite each run of flat records as a data frame
Description
A layer's data is usually one small named list per point, and
jsonlite::toJSON() serializes a list element by element through S4
dispatch: 10,000 points took 2 s of a 5 s ggplot2 render, more than the
SVG export. A data frame with the same columns is serialized row-wise in
one vectorised pass and yields byte-identical JSON under the options
set_maidr_data_attr() uses (auto_unbox, na = "null", digits = NA),
in about a hundredth of the time.
Usage
records_as_frames(node)
Arguments
node |
A maidr-data node (list, or a leaf) |
Details
Only a run that is certain to serialize identically is converted: an
unnamed list of named lists that all have the same field names in the
same order, each field one attribute-free logical, integer, double or
character value of the same type in every record. Anything else – a
nested value, a ragged or mixed-type field, a factor or date, a
zero-length value (which serializes as [], not null) – is left as a
list and recursed into, so the output never changes, only its cost.
Value
The node with record runs replaced by data frames
Where a rect grob is anchored on one axis, as a fraction
Description
A rectGrob() keeps its justification in just and leaves hjust /
vjust NULL unless the caller wrote them, so neither field alone answers
the question. just may be a keyword, a number, or a length-two vector of
either; absent, grid's own default is "centre".
Usage
rect_anchor(grob, axis)
Arguments
grob |
A rect grob |
axis |
|
Details
Anything unrecognised answers 0.5, the default – an anchor this cannot read is one it should not move.
Value
The anchor as a fraction: 0 is the low edge, 1 the high one
Address one tile of a grob that draws a whole panel of them
Description
gridSVG exports a rect grob holding several rectangles as one group of
<rect> elements, each with its own id: <grob>.1.<n>, counted from one
in draw order. A spine plot's panel is the case that needs it.
Usage
rect_cell_selector(grob_name, drawn_at)
Arguments
grob_name |
The grob holding the tiles |
drawn_at |
Which tile, counted in draw order from one |
Value
A CSS selector matching exactly that tile
Read a rectangle layer's bounds as the spans and lanes they draw
Description
A declared maidr_gantt() layer builds xmin, xmax,
ymin and ymax, and none of the four columns
segment_lane_axis() is keyed on. Measured, today's processor fed a
rect frame unchanged answers data lanes: 0 | lanes: NULL |
selectors: 0 – a confident empty schedule, which is a false claim of a
different kind from the one #197 is about. So the frame is renamed into the
segment spelling here and every landed function downstream runs unchanged.
Usage
rect_gantt_frame(built_data, lane_axis = "y")
Arguments
built_data |
A layer's computed data, carrying |
lane_axis |
|
Details
The lane is the band's midpoint rather than either edge, so a lane sits
where a reader sees it and a band drawn upside down (ymin > ymax)
lands in the same place. The span keeps both bounds; segment_lanes()
already sorts a span written backwards.
Measured on the repository's own four-interval schedule (ymin =
0.6, 1.6, 2.6, 1.6), the normalised frame gives segment_lane_axis()
= "y", lane sizes 1, 2, 1 and emission order 1, 2, 4, 3;
the processed layer's data, lanes, orientation and
axes come back identical() to the geom_segment()
spelling of the same schedule, and only the grob the selectors name
differs.
The degenerate guard falls out of the renaming rather than being a rule:
rectangles of zero width normalise to level on both axes, which
segment_lane_axis() already refuses.
Value
The frame with x, xend, y and yend
added, or NULL when it is not a rectangle layer's frame
Register MAIDR's custom print.ggplot method
Description
Stores the original ggplot2 print method and registers MAIDR's version.
Called during .onLoad().
Usage
register_ggplot2_print_method()
Render MAIDR Plot in Shiny Server
Description
Creates a Shiny render function for MAIDR widgets using htmlwidgets. This provides automatic dependency injection and robust JavaScript initialization.
Usage
render_maidr(expr, env = parent.frame(), quoted = FALSE)
Arguments
expr |
An expression that draws a plot. Either a ggplot object, or
Base R plotting calls – their return values differ
( |
env |
The environment in which to evaluate expr |
quoted |
Is expr a quoted expression |
Value
A Shiny render function for use in server
Examples
if (interactive()) {
library(shiny)
library(ggplot2)
server <- function(input, output) {
output$myplot <- render_maidr({
ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
geom_bar(stat = "identity")
})
}
}
Render MAIDR Widget in Shiny Server (Internal Alternative)
Description
Internal alternative Shiny server function. This provides the same functionality as render_maidr() but is no longer recommended for direct use. Use maidr_output() and render_maidr() instead for better consistency.
Usage
render_maidr_widget(expr, env = parent.frame(), quoted = FALSE)
Arguments
expr |
An expression that returns a ggplot object |
env |
The environment in which to evaluate expr |
quoted |
Is expr a quoted expression |
Value
A Shiny render function for use in server
Reorder one leaf's data by every layer processor that asks for it
Description
Reorder one leaf's data by every layer processor that asks for it
Usage
reorder_leaf_plot(leaf_plot)
Arguments
leaf_plot |
A ggplot object |
Value
The plot, its data reordered
Put every leaf's data in the order its processors will read the drawing in
Description
The single-plot and facet paths both reorder the plot data before drawing
(Ggplot2PlotOrchestrator$process_layers()), because a segmented
bar's DOM order is whatever order its rows arrive in and the processor
declares one order – category by category, fills descending – to the
frontend. A patchwork leaf was drawn from its rows as given, so its
declared order matched the drawing only when the rows happened to be
sorted that way, and a dodged leaf in a composition outlined another
cell's bar for the value announced (#316). Walks the composition the way
augment_patchwork_leaves() does.
Usage
reorder_patchwork_leaves(node)
Arguments
node |
A patchwork, a ggplot, or anything else (returned as is) |
Value
The node with each leaf's data reordered
Repair NA text-grob justification so gridSVG can export the tree
Description
gridGraphics::grid.echo() translates some base graphics text into grid
text grobs that leave vjust (and, in principle, hjust) as NA and defer
to the grob's just field instead. gridSVG 1.7.7 passes the raw value to
gridSVG:::justTovjust(), which branches on it directly and fails with
"missing value where TRUE/FALSE needed", aborting gridSVG::grid.export()
from devGrob.text. graphics::pie() is the case that bites: it labels
every wedge, so before this repair no base R pie chart could be exported at
all – pie(..., labels = NA), which draws no text, exported fine, which is
what pins the failure on these grobs. barplot() and friends are
unaffected because their text grobs already carry a numeric justification.
Usage
repair_na_text_justification(grob)
Arguments
grob |
A grob, gTree, gList, or gtable (or NULL) |
Details
Only NA components of text grobs are rewritten, so a grob that already has
a usable justification passes through untouched. 0.5 is exactly what grid
resolves NA to for the just = "centre" these grobs declare, so the drawn
output is byte-identical.
This was an upstream gridSVG/gridGraphics incompatibility rather than anything maidr introduced. The svglite export leaves justification to grid and does not need it; it is kept because it changes nothing grid draws and costs one pass over the tree.
Value
The same tree with NA hjust/vjust on text grobs set to 0.5
Replay Base R Plot from Device Storage
Description
Re-executes the recorded Base R plot calls to render the plot.
Usage
replay_base_r_plot(device_id)
Arguments
device_id |
The device ID to get calls from |
Replay a recorded plot call with the original (unwrapped) function
Description
Strips maidr-internal arguments and re-executes the call. When the
recorded args contain unevaluated expressions (from non-standard
evaluation, e.g. curve(sin(x)) or plot(y ~ x, subset = g == 1)),
the call is rebuilt and evaluated in the environment captured at record
time so those expressions resolve exactly as they did originally.
Usage
replay_plot_call(function_name, args, call_env = NULL)
Arguments
function_name |
Name of the recorded function |
args |
Recorded argument list (values and/or expressions) |
call_env |
Environment captured when NSE arguments could not be forced at record time, or NULL when all args are plain values |
Value
The result of the replayed call (invisibly)
Replay Base R plot to native graphics device
Description
For unsupported plots, close the temp device and replay the plot calls to the native graphics device.
Usage
replay_to_native_device(device_id = grDevices::dev.cur())
Arguments
device_id |
The device ID to get plot calls from |
Value
NULL (invisible)
Reset Device State
Description
Resets the state for a device (called when storage is cleared).
Usage
reset_device_state(device_id = grDevices::dev.cur())
Arguments
device_id |
Graphics device ID |
Value
NULL (invisible)
Reset the global registry (mainly for testing)
Description
Reset the global registry (mainly for testing)
Usage
reset_global_registry()
Forget every rebuilt frame
Description
Called when a plot starts being processed, so an entry can only ever be
answered to the run that computed it. See Ggplot2PlotOrchestrator$initialize
for why a layer alone cannot identify a plot.
Usage
reset_jitter_cache()
Value
Invisibly NULL.
Resolve the legend title for a grouping aesthetic
Description
Returns the title ggplot2 prints above the legend for a grouping
aesthetic, which is what the MAIDR payload emits as the z axis label.
A labs() override wins (ggplot2 stores it on the built plot's
labels, normalising color to colour); otherwise the
mapped expression is used, with the layer's own mapping taking precedence
over the plot-level one. Returns NULL when the aesthetic carries neither.
Usage
resolve_legend_label(
plot,
built = NULL,
aes_names = "fill",
layer_index = NULL
)
Arguments
plot |
The ggplot object |
built |
Built plot from |
aes_names |
Aesthetic names to try, in order. Pass spelling variants
of one aesthetic (for example |
layer_index |
Index of the layer whose mapping takes precedence, or NULL to consult only the plot-level mapping |
Details
Callers are responsible for only asking about an aesthetic the layer is
actually grouped by: labs() records a title even for an unmapped
aesthetic, so an unguarded lookup would invent a legend that the plot does
not draw.
Value
Character scalar, or NULL when the aesthetic has no title
A recorded argument as a value
Description
A recorded argument as a value
Usage
resolve_recorded_value(value, call_env = NULL)
Arguments
value |
A recorded argument, a plain value or an expression |
call_env |
The snapshot to evaluate an expression in, or NULL |
Value
The value, or NULL when an expression has nowhere to be evaluated or fails there
Resolve the aesthetic that splits a layer into series
Description
Mirrors ggplot2's precedence: the layer's own mapping wins over the
plot-level one. ggplot2 normalises color to colour, but both
spellings are probed defensively.
Usage
resolve_series_group_mapping(
plot,
layer_index = NULL,
aes_groups = list(c("colour", "color"))
)
Arguments
plot |
The ggplot2 object |
layer_index |
Index of the layer whose mapping takes precedence, or NULL to consult only the plot-level mapping |
aes_groups |
List of aesthetic-name vectors, probed in order. Each
element must hold spelling variants of ONE aesthetic (for example
|
Value
list with aes (the winning spelling variants, or NULL when
nothing is mapped) and column (the mapped column name, or
"group" as a fallback)
Name each series after the category its built group id stands for
Description
ggplot_build() replaces the grouping column with integer group ids,
so the user-facing name has to be recovered from the plot's own data. The
ids are assigned in the sorted order of the grouping column's values, which
is the order this function relies on. Falls back to "Series <id>" when the
mapped column is not present on the plot data (for example an expression
such as aes(colour = paste(a, b))).
Usage
resolve_series_group_names(plot, group_ids, column = "group")
Arguments
plot |
The ggplot2 object |
group_ids |
The layer's built |
column |
Name of the mapped grouping column |
Value
Character vector, one name per distinct group id in ascending order
Resolve x/y data arguments from a recorded call's argument list
Description
Mirrors how plot()/points()/lines() match their arguments: named x/y
win, then the first two UNNAMED arguments in order. Blind positional
access (args[[2]]) would grab graphical parameters instead
(plot(x, type = "l") -> y = "l") or error for single-argument calls
(plot(v), lines(v)).
Usage
resolve_xy_args(args)
Arguments
args |
Recorded argument list |
Value
List with x and y (either may be NULL)
Restore the original print.ggplot method
Description
Restore the original print.ggplot method
Usage
restore_ggplot2_print_method()
Restore original functions
Description
Deactivates patching by flipping the active flag. Wrappers remain in the namespace but act as pass-through (calling the original function directly). This avoids modifying the locked namespace or the search path.
Usage
restore_original_functions()
Value
NULL (invisible)
Retry a failed plot call from the caller's own frame
Description
The formula methods resolve non-standard arguments relative to
parent.frame(): plot.formula() evaluates subset = there, and
boxplot.formula() reaches into the caller's .... A wrapper puts its
own frame in that position, so calls that work in plain R fail through
maidr:
Usage
retry_call_in_caller_frame(
original_function,
recorded_call,
caller_env,
original_error
)
Arguments
original_function |
The unwrapped plotting function |
recorded_call |
|
caller_env |
The wrapper's calling frame |
original_error |
The error condition the direct call raised |
Details
plot(y ~ x, data = d, subset = g == 1) # object 'g' not found boxplot(y ~ g, data = d, subset = x > 5) # ..3 used in an incorrect context
Rebuilding the call and evaluating it in the caller's frame gives those methods the frame they expect. This runs only after the direct call has already failed, so working calls keep the single-evaluation fast path and a genuinely invalid call still reports its original error.
Known trade-off: on this retry path an argument can be evaluated more than once. The failed first attempt already forced some promises, the rebuilt call evaluates the argument expressions afresh, and the argument recording that follows forces the interrupted promise again. An argument carrying a side effect therefore runs it more than once here. The alternative is the pre-existing behaviour, where the whole call simply errored, so the retry is the better trade – but it is a trade.
Value
Result of the retried call
Turn a horizontal box-family layer round for the frontend
Description
BoxTrace, ViolinBoxTrace and ViolinTrace each reverse a horizontal
layer on the way in – "reverse points to match visual order (lower-left
start)", as src/model/box.ts puts it. The reversal is unconditional, so
the producer has to hand them the opposite order for the result to come
out lower-left first, and a layer emitted in its own natural bottom-to-top
order is read from the top down instead.
Usage
reverse_horizontal_box_layer(layer)
Arguments
layer |
A layer list carrying |
Details
Both halves move together. The frontend reverses the resolved highlight
alongside the points (BoxTrace explicitly, ViolinTrace by reversing the
selectors before it resolves them), so a layer that reversed only its data
would trade a correct outline for a wrong one.
Only the emission order changes. Each entry keeps its own category name and
its own statistics, and orientation still says which axis the values are
drawn along.
Worth stating what this does not settle: the frontend's reversal may exist because py-maidr reverses, in which case the cleaner fix is to drop it there and let every producer emit in its own natural order. That is a three-repository change and a released-behaviour change for py-maidr readers, so it is left to the maintainer. Until then the two bindings agree, which is the part a reader can feel.
Value
The layer, with both halves reversed when it is horizontal
The x and y a layer draws, its own mapping first and the plot's beneath
Description
The x and y a layer draws, its own mapping first and the plot's beneath
Usage
roc_layer_rates(layer, plot_object)
Arguments
layer |
A ggplot2 layer |
plot_object |
The plot the layer belongs to |
Value
list(x = , y = ) of normalised names, either NULL when unmapped
The name an aesthetic is mapped to, as the ROC vocabulary would spell it
Description
rlang::as_label() renders aes(x = specificity) as specificity,
aes(x = 1 - specificity) as 1 - specificity, and the .data[["1-specificity"]]
that pROC::ggroc() writes as .data[["1-specificity"]]. Stripping the
pronoun and the whitespace makes the three spellings of one rate compare
equal.
Usage
roc_mapped_name(mapping, aesthetic)
Arguments
mapping |
An aesthetic mapping, or NULL |
aesthetic |
Which aesthetic to read |
Value
The normalised name, or NULL when nothing is mapped
Whether the bundled maidr.js can build a roc trace
Description
The roc trace first shipped in maidr.js 4.9.0. Emitted to an older
bundle it is not declined but fatal: the core's factory throws on a
trace type it does not know, so the page renders nothing (#214). Until
MAIDR_VERSION reaches 4.9.0 a ROC curve therefore keeps the line
reading it had – pROC::ggroc() and yardstick's autoplot() in
particular, which are detected without any change on the author's side
and must not lose a chart they rendered yesterday. The moment the bundle
moves, the reading switches with no other change.
Usage
roc_trace_available()
Value
TRUE when the pinned bundle carries the trace
Whether a ROC layer's x is specificity, to be announced as 1 - x
Description
Whether a ROC layer's x is specificity, to be announced as 1 - x
Usage
roc_x_is_specificity(layer, plot_object)
Arguments
layer |
A ggplot2 layer |
plot_object |
The plot the layer belongs to |
Value
TRUE only for a detected layer whose x is specificity itself
Run MAIDR Example Plots
Description
Launches example plots demonstrating MAIDR's accessible visualization
capabilities. Each example creates an interactive plot using show().
Usage
run_example(example = NULL, type = c("ggplot2", "base_r"))
Arguments
example |
Character string specifying which example to run. If |
type |
Character string specifying the plot system to use.
Either |
Details
Available examples include various plot types such as bar charts, histograms, scatter plots, line plots, boxplots, heatmaps, and more.
Each example script creates a plot and calls show() to display it
in your default web browser with full MAIDR accessibility features
including keyboard navigation and screen reader support.
Value
Invisibly returns NULL. Called for its side effect of displaying
an interactive plot in the browser or listing available examples.
See Also
show() for displaying plots, save_html() for saving to file
Examples
# List all available examples
run_example()
if (interactive()) {
# Run ggplot2 bar chart example
run_example("bar")
# Run Base R histogram example
run_example("histogram", type = "base_r")
}
Save Interactive Plot as HTML File
Description
Save a ggplot2 or Base R plot as an HTML file with interactive MAIDR accessibility features.
Usage
save_html(plot = NULL, file = "plot.html", use_cdn = NULL, ...)
Arguments
plot |
A ggplot2 object or NULL for Base R auto-detection |
file |
File path where to save the HTML file (e.g., "plot.html") |
use_cdn |
Logical. Controls where MAIDR.js is loaded from:
|
... |
Additional arguments passed to internal functions |
Details
By default the MAIDR.js library is written to a lib/ folder beside
file, and the two have to be shared together: zip the folder that
holds both, or copy both. An .html sent on its own loads no
MAIDR.js and shows a plain, inaccessible chart. use_cdn = TRUE
writes one self-contained file instead, which needs internet access
whenever it is viewed and loads the latest published MAIDR.js from
jsDelivr rather than the copy bundled with this package.
Value
The file path where the HTML was saved (invisibly)
Examples
# ggplot2 bar chart
library(ggplot2)
p <- ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
geom_bar(stat = "identity")
maidr::save_html(p, tempfile(fileext = ".html"))
# ggplot2 violin plot
p_violin <- ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
geom_violin(fill = "lightblue", alpha = 0.7) +
labs(title = "MPG by Cylinders", x = "Cylinders", y = "MPG")
maidr::save_html(p_violin, tempfile(fileext = ".html"))
# Base R example (requires interactive session for function patching)
if (interactive()) {
barplot(c(10, 20, 30), names.arg = c("A", "B", "C"))
maidr::save_html(file = tempfile(fileext = ".html"))
}
Save HTML document to file
Description
Save HTML document to file
Usage
save_html_document(html_doc, file)
Arguments
html_doc |
An htmltools HTML document object |
file |
Output file path |
Read a ggplot2 scale's transformation
Description
ggplot2 3.5 renamed the accessor; the field it reads is the same one. Returns NULL when the scale carries no transformation at all, which is the case for a discrete scale.
Usage
scale_transformation(scale)
Arguments
scale |
A panel scale from |
Value
The transformation object, or NULL
Schedule auto-show after the current top-level expression completes
Description
Uses R's task callback mechanism. When a HIGH-level plot function is called,
this schedules show() to run after the expression finishes. If another
HIGH-level function is called in the same expression, the previous callback
is replaced (only one auto-show fires per expression).
Usage
schedule_auto_show()
Which axis a layer's segments lay their lanes on
Description
A segment whose two ends share a coordinate is a span along the other axis, at one position on this one – an interval in a lane, which is a gantt. A segment whose ends share nothing is an edge in a node-link diagram: it has no lane to sit in and no interval to announce.
Usage
segment_lane_axis(built_data)
Arguments
built_data |
A layer's computed data, carrying |
Details
The question is asked of the whole layer rather than of each row, which
is the rule xability/maidr#1100 settled for the same reading in the
Observable adapter. One geom_segment() call can hold spans and edges
together, and reading three spans out of four segments would announce a
gantt quietly missing a quarter of its chart.
A layer whose segments are level on both axes is every span reduced to a point. That is not a schedule with milestones in it – a milestone sits in a lane beside intervals that have length – so it is refused rather than announced as a chart of zero-length work.
Value
"y" when the lanes run up the y axis and the spans along x,
"x" for the mirror image, or NULL when the layer is not a gantt
Group a layer's segments into the lanes they were drawn in
Description
Group a layer's segments into the lanes they were drawn in
Usage
segment_lanes(built_data, lane_axis, lane_names = NULL)
Arguments
built_data |
A layer's computed data, one row per drawn segment |
lane_axis |
|
lane_names |
The lane names in drawn order, or NULL on a continuous
lane axis. Position |
Value
A list with data (lanes, each a list of x/start/end
intervals), lanes (the names of every lane in drawn order, or NULL) and
order (the built-data row behind each interval, in emission order)
Series-Group Helpers
Description
A layer whose grouping aesthetic is mapped (for example
aes(colour = g)) draws one curve per group. MAIDR describes that as
one series per group, each point carrying the group's name as z, and
names those values with the legend title as the z axis label. These helpers
are shared by the ggplot2 line and smooth layer processors so that a grouped
geom_line() and a grouped geom_smooth() are described the same
way.
Set Internal Guard Flag
Description
Guards against recursive tracing by setting an internal flag.
Usage
set_internal_guard(value)
Arguments
value |
TRUE to set guard, FALSE to clear |
Value
NULL (invisible)
Serialize maidr_data and set it as the SVG root's maidr-data attribute
Description
Mutates svg_doc in place.
Usage
set_maidr_data_attr(svg_doc, maidr_data)
Arguments
svg_doc |
Parsed SVG document (xml2) |
maidr_data |
The maidr-data structure |
Value
NULL (invisible)
Write a height back into a recorded barplot() call
Description
The counterpart of recorded_barplot_height(): the value goes back into
the slot it was read from, named or positional.
Usage
set_recorded_barplot_height(args, height)
Arguments
args |
Recorded argument list |
height |
The replacement height |
Value
The argument list with height replaced
Display Interactive MAIDR Plot
Description
Display a ggplot2 or Base R plot as an interactive, accessible visualization using the MAIDR (Multimodal Access and Interactive Data Representation) system.
Usage
show(plot = NULL, use_cdn = NULL, shiny = FALSE, as_widget = FALSE, ...)
Arguments
plot |
A ggplot2 object or NULL for Base R auto-detection |
use_cdn |
Logical. Controls where MAIDR.js is loaded from:
|
shiny |
If TRUE, returns just the SVG content instead of full HTML document |
as_widget |
If TRUE, returns an htmlwidget object instead of opening in browser |
... |
Additional arguments passed to internal functions |
Details
Attaching maidr masks methods::show(). An object that is not a
plot maidr renders – an S4 object, a vector, a data frame – is handed to
methods::show(), so it prints as it did before maidr was attached.
In a script or a package, call maidr::show() and
methods::show() by name; ?"base-r-wrappers" lists
everything else attaching maidr masks.
Value
Invisible NULL. The plot is displayed in RStudio Viewer or browser as a side effect.
Examples
# ggplot2 bar chart
library(ggplot2)
p <- ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
geom_bar(stat = "identity")
maidr::show(p)
# ggplot2 violin plot
p_violin <- ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
geom_violin(fill = "lightblue", alpha = 0.7) +
labs(title = "MPG by Cylinders", x = "Cylinders", y = "MPG")
maidr::show(p_violin)
# Base R example (requires interactive session for function patching)
if (interactive()) {
barplot(c(10, 20, 30), names.arg = c("A", "B", "C"))
maidr::show()
}
Adaptively simplify a 2D curve to a target number of points
Description
Uses binary search on epsilon to find the smallest tolerance that
yields at most target retained points.
Usage
simplify_curve(points, target, min_epsilon = 0, max_iterations = 50L)
Arguments
points |
Nx2 numeric matrix of ordered (x, y) points |
target |
Desired maximum number of retained points |
min_epsilon |
Lower bound for epsilon search (default 0) |
max_iterations |
Maximum binary-search iterations (default 50) |
Value
Logical vector of length N (TRUE = keep this point)
Whether the smooth processor can read a layer drawn with this geom
Description
The list this processor works from, stated once so that the classifier can
consult it. Ggplot2Adapter$detect_layer_type() decides a layer is a
"smooth" partly on its stat – StatFunction and
StatDensity both claim one – and a stat can name a geom this list
does not. When it did, resolve_target_layer() rejected the layer's
own index, found nothing in the fallback search and stop()ped:
Usage
smooth_reads_geom(geom)
Arguments
geom |
A layer's geom |
Details
stat_function(fun = sin, geom = "point") Error: No smooth curve layers found in plot stat_function(fun = sin, geom = "step") Error: No smooth curve layers found in plot stat_function(fun = sin) interactive
Not a fallback to a picture – an error out of save_html(), so the
caller's script stopped, and which geom the author passed decided whether
the call returned at all (#230). A decline is a reading decision; an
exception is a broken call.
inherits() rather than class(geom)[1] here, unlike the
dispatch: this asks whether the processor can read the artist,
which a subclass of a readable geom can. GeomFunction and
GeomQuantile are named all the same, because both are
GeomPath subclasses and a plain geom_path() is typed
"line" and never arrives here – widening to the parent would
claim nothing extra and would blur what this list is for, the geoms that
draw a computed curve (#202, #229).
Value
TRUE when this processor can read a layer drawn with it
Snapshot the bindings a recorded NSE call will need at replay time
Description
Recorded expressions are re-evaluated when the figure is rendered, long
after the caller has moved on – and R reuses ONE frame for every
iteration of a for loop. Storing that frame therefore makes every
iteration replay with the LAST iteration's values:
Usage
snapshot_call_env(args, caller_env)
Arguments
args |
Recorded argument list holding the unevaluated expressions |
caller_env |
The frame the recorded call was made from |
Details
par(mfrow = c(1, 2))
for (g in c("a", "b")) plot(y ~ x, data = d, subset = grp == g)
Both panels drew grp == "b", silently and without an error. Copying the
whole frame would fix that but brings its own problems (large objects,
active bindings, unforced promises, frames that are shared and mutated),
so only the names the recorded expressions actually mention are copied,
into a CHILD of the caller's frame. Everything else – including anything
reached through the enclosing scopes – still resolves exactly as before,
and the copies are references, so R's copy-on-write keeps them free.
Active bindings are deliberately left behind: reading one is a side effect, and re-reading it at replay time is the whole point of declaring it active. Names that cannot be read are skipped for the same reason – the fall-through to the caller's frame preserves today's behaviour.
Value
An environment whose parent is caller_env
Name a replayed spineplot(x, y)'s axes the way the caller's call did
Description
spineplot.default() titles its axes deparse1(substitute(x)) and
deparse1(substitute(y)) when no xlab/ylab is given. Replayed through
do.call() on the recorded values, the substitute is the data itself,
and a reader was told the axis was called c(1, 2, 3, ...) for as many
characters as the vector took to write. The names the caller wrote are in
the recorded call text, so they are matched against the default method's
formals and passed as the titles. A table or a formula names its own
axes and is left alone.
Usage
spineplot_written_axis_names(args, call_expr)
Arguments
args |
Recorded argument list |
call_expr |
The recorded call, deparsed |
Value
args, with xlab/ylab filled in where the call named them
One curve grob per row of a vectorised one
Description
Recycling is by position, which is grid's own rule for a gpar shorter than the positions it styles, so a layer given one colour for four rows keeps that colour on all four rather than losing three of them.
Usage
split_one_curve(curve)
Arguments
curve |
A |
Details
A single-row curve is returned untouched: it already satisfies gridSVG, and wrapping it would change the element id its selector is built from.
Value
A gTree of one curve per row, or the grob itself when it has one row
Split a vectorised curve grob into one curve per row
Description
geom_curve() draws every row of its layer as a single curve grob whose
positions and whose gp are vectors – measured on ggplot2 3.4.4, a
four-row layer arrives as GRID.curve.1 with x1, y1, x2, y2 and
gp$col, gp$fill, gp$lwd, gp$lty all of length 4. gridSVG's
svgStyleAttributes() rejects that outright –
"All SVG style attribute values must have length 1" – so
gridSVG::grid.export() aborts on the whole plot and no curve chart could
be read at all (#195).
Usage
split_vectorised_curve_grobs(grob)
Arguments
grob |
A grob, gTree, gList, or gtable (or NULL) |
Details
A segments grob is equally vectorised and exports fine, because gridSVG
has a method that splits it into one element per segment. There is no such
method for curve, so the split is done here instead: each row becomes its
own curve grob carrying its own slice of the gpar, gathered under a gTree
keeping the original's name. The drawing is unchanged – every row is drawn
with exactly the styling it had – and the export gains one element per
row, which is what a gantt's selectors address.
Slicing rather than scalarising is the point. Taking gp[[1]] would also
satisfy gridSVG and is visibly wrong: measured on a layer coloured by a
third column, the four rows export as rgb(248,118,109), rgb(0,186,56),
rgb(97,156,255) and rgb(0,186,56), so collapsing to the first would
paint the whole layer red.
This was an upstream gridSVG gap rather than anything maidr introduced. The svglite export draws a vectorised curve as it is, but the split stays: the element per row it gives is what a gantt's selectors address.
Value
The same tree with every multi-row curve grob split row-wise
Strip the bottom axis line and tick marks from chartSeries candlestick SVG
Description
quantmod::chartSeries() emits a bottom date axis (axis line, tick marks, and "Jan 12 2024" labels). The axis line and tick marks are drawn slightly off-center from the candles (chartSeries places ticks at evenly-spaced positions that do not always coincide with the candle centers), which reads as a visual misalignment. This helper removes the axis line and tick marks but preserves the date labels themselves so the chart still communicates which date each candle represents visually. Per-row date info is also encoded in the maidr-data JSON for the screen reader.
Usage
strip_chartseries_date_axis(svg_content, maidr_data)
Arguments
svg_content |
Character vector of SVG lines |
maidr_data |
The maidr-data structure (read-only; used to detect candlestick layers) |
Details
The relevant groups have IDs of the form
graphics-plot-N-bottom-axis-(line|ticks)-...; we match by
substring with contains(@id, 'bottom-axis-(line|ticks)-') and
explicitly leave bottom-axis-labels- untouched.
Safety: no-op when maidr_data contains no candlestick layers
(ggplot candlestick / non-candlestick plots use different SVG IDs
and are unaffected), when xml2 is unavailable, when SVG parsing
fails, or when no matching groups are found.
Value
Modified SVG content (character vector). If any guard
fails, returns svg_content unchanged.
Document-level implementation of strip_chartseries_date_axis()
Description
Mutates svg_doc in place.
Usage
strip_chartseries_date_axis_doc(svg_doc)
Arguments
svg_doc |
Parsed SVG document (xml2) |
Value
TRUE if the document was modified
Strip the right y-axis line and ticks from chartSeries candlestick SVG
Description
quantmod::chartSeries() draws a right-hand y-axis (axis(4)) with a
vertical axis line, tick marks, and numeric price labels (e.g.
101..106). In the tree gridGraphics::grid.echo() rebuilds from it, the
line and the ticks land inside the plot region, well left of its right
border, reading like a stray "axis through the middle" of the chart,
while the labels stay where R draws them. This helper removes the
right-axis-line-* and right-axis-ticks-* groups; the price labels
are preserved so the chart still communicates the y-axis scale visually.
Usage
strip_chartseries_right_axis(svg_content, maidr_data)
Arguments
svg_content |
Character vector of SVG lines |
maidr_data |
The maidr-data structure (read-only; used to detect candlestick layers) |
Details
The matched groups have IDs of the form
graphics-plot-N-right-axis-line-... and
graphics-plot-N-right-axis-ticks-..., matched by substring.
Safety: no-op when maidr_data contains no candlestick layers
(ggplot candlestick / non-candlestick plots use different SVG IDs
and are unaffected), when xml2 is unavailable, when SVG parsing
fails, or when no matching groups are found.
Value
Modified SVG content (character vector). If any guard
fails, returns svg_content unchanged.
Document-level implementation of strip_chartseries_right_axis()
Description
Mutates svg_doc in place.
Usage
strip_chartseries_right_axis_doc(svg_doc)
Arguments
svg_doc |
Parsed SVG document (xml2) |
Value
TRUE if the document was modified
Strip internal violin_kde metadata without coordinate injection
Description
Removes the temporary fields (.panel_x_range, .panel_y_range,
.is_horizontal, .panel_index, .panel_name, data_left_x,
data_right_x, data_y) that must never appear in the serialized
maidr-data JSON. Called unconditionally after coordinate injection, so a
layer whose panel viewport could not be navigated still comes out clean.
Usage
strip_violin_kde_metadata(maidr_data)
Arguments
maidr_data |
The maidr-data structure |
Value
Cleaned maidr_data
Rewrite svglite shapes into the exported document's shapes
Description
Rewrite svglite shapes into the exported document's shapes
Usage
svg_convert_shapes(
lines,
ids,
clips,
h,
as_path = logical(length(lines)),
own = rep(NA_character_, length(lines)),
blank = logical(length(lines))
)
Arguments
lines |
svglite element lines. |
ids |
Element ids (NA for none). |
clips |
Clip-path ids (NA for none). |
h |
Page height in px. |
as_path |
Shapes of a path grob, written as |
own |
Each shape's own gpar names (see |
blank |
Shapes drawn with a blank line type. |
Value
Character vector of rewritten element lines.
Draw one grob in the walk's context, under its ancestors' gpar
Description
Draw one grob in the walk's context, under its ancestors' gpar
Usage
svg_draw(g, st)
Close the pending batch, drawing its marker when shapes follow
Description
Close the pending batch, drawing its marker when shapes follow
Usage
svg_flush(st, draw = TRUE)
Families svglite resolved R's generic font families to
Description
Cached per session: svglite writes the concrete family it measured with ("Liberation Sans"), which a reader's browser may not have. Each is written back as the generic stack gridSVG used, ending in a CSS generic.
Usage
svg_font_aliases()
gridSVG's element id: <name>.<k>, <k> one more than the name's uses
Description
gridSVG's element id: <name>.<k>, <k> one more than the name's uses
Usage
svg_get_id(name, st)
Presentation attributes for a group, as gridSVG gave them
Description
gridSVG wrote a group's own gpar as attributes its shapes inherit, and a
shape's own gpar on the shape. Shapes here keep that split (see
svg_convert_shapes()), so the groups carry their share: each setting the
group's gpar names, at the value the drawing inherits there. Alpha is
folded into the opacities rather than written as opacity, the way the
device folds it into every shape.
Usage
svg_gp_attrs(eff, set)
Arguments
eff |
The effective gpar at the group. |
set |
Names of the gpar settings the group itself makes. |
Value
A string of attributes with a leading space, or "".
Which of an arrowed line's shapes are its pieces
Description
The device writes each piece of a line and then that piece's arrow heads, so pieces and heads interleave. A shape is the next expected piece when it is a line with that piece's point count starting at its first point (to svglite's two decimals); everything else is a head.
Usage
svg_match_pieces(lines, pieces)
Arguments
lines |
svglite lines for the element's shapes, in order. |
pieces |
Data frame of expected pieces ( |
Value
Logical vector: the shape is a piece.
Parse svglite's page into shapes, markers and clip regions
Description
Parse svglite's page into shapes, markers and clip regions
Usage
svg_parse_svglite(svg)
svglite's style declarations as presentation attributes
Description
svglite resolves every setting a shape draws with. gridSVG wrote on a shape only what the shape's own gpar set and let the rest come from its groups, and that split is visible to maidr.js: a highlight clone of a group repaints the shapes inside it only where they inherit. So a shape keeps just the attributes its own gpar accounts for (NA: all of them), with the value svglite resolved, which is the value it was drawn with.
Usage
svg_style_attrs(
style,
text,
own = rep(NA_character_, length(style)),
line = logical(length(style))
)
Arguments
style |
Character vector of |
text |
Logical vector: the element is text. |
own |
Comma-separated names of each shape's own gpar settings, NA for a shape drawn outside any grob. |
line |
Logical vector: the element is an open line, which gridSVG always wrote unfilled. |
Value
Character vector of attribute strings, each with a leading space.
Stop on svglite output the rewrite cannot vouch for
Description
The rewrite reads svglite's text output, one element per line, and attributes each shape to the grob drawn before it. A later svglite that wrote otherwise would not fail on its own: its shapes would be numbered onto the wrong grobs, and a reader would be announced one mark while another is outlined. So anything the rewrite does not recognise stops the export, and the chart falls back to a static image with a warning naming this, instead of shipping selectors that point at the wrong marks.
Usage
svg_unreadable(what)
Arguments
what |
What was found. |
The x offset of an SVG translate() transform
Description
The x offset of an SVG translate() transform
Usage
translate_x(transform)
Arguments
transform |
The |
Value
The first translate()'s x, or 0 when there is none
Put a layer's built points back where its data puts them
Description
Put a layer's built points back where its data puts them
Usage
undisplace_layer(plot, layer_data, layer_index)
Arguments
plot |
The ggplot2 object. |
layer_data |
The layer's built data, as read from |
layer_index |
Index of the layer within the plot. |
Value
layer_data with x and y restored when the layer was jittered
and the rebuild lined up, and unchanged otherwise.
The positions a layer's points would have without its jitter
Description
Rebuilds plot with the one layer's position adjustment replaced by
position_identity() and returns that layer's built data.
Usage
undisplaced_layer_data(plot, layer_index)
Arguments
plot |
The ggplot2 object. |
layer_index |
Index of the layer to undisplace. |
Details
The replacement is a fresh ggproto child rather than an assignment to the
layer's own position field. ggplot2 Layer objects are ggproto and have
reference semantics, so plot$layers[[i]]$position <- ... would alter
the caller's plot – the object they still hold and may draw again. A child
shadows the field instead, leaving the parent untouched; asserted in the
tests rather than left as a claim.
Value
A data frame of the layer's undisplaced built data, or NULL when
the rebuild fails or does not line up row for row with the original.
Put built positions back into the space the reader sees
Description
ggplot2 applies a scale transformation before the stat runs, so
ggplot_build()'s data is in transformed space. Read straight
through, a scale_x_log10() chart announces log10 coordinates under
the original axis label: a scatter of prices from $5.50 to $9,403 reads as
0.744 to 3.973 under "Price (USD)" (#158).
Usage
untransform_positions(values, built, axis = "x", panel_id = NULL)
Arguments
values |
Positions read from the built data |
built |
Built plot from |
axis |
|
panel_id |
Panel index for faceted plots, or NULL for the first |
Details
Nothing is missing from such a chart and nothing errors. The structure is right, the point count is right, the label is right, and the numbers are false – with no signal a reader could catch, since "these look small" is not checkable without the chart you cannot see.
coord_trans() needs no special case and deliberately gets none. It
transforms at draw time, after the stat, so its built data is already in
data space and its scale reports identity – the same
comparison that skips an untransformed chart skips it too. Testing for
"is there a log axis" would have inverted it wrongly.
Applied at the point a value is emitted rather than to the frame as a
whole, and that placement is load-bearing: scale_*_reverse()
negates, so a frame inverted before a sort would order rows opposite to
the way they were drawn, and selectors indexed by that order would land on
the wrong element. Ordering follows the drawn scale; only the announced
number is put back.
Value
The values in data space, unchanged when there is nothing to undo
Update Device State
Description
Updates the state for a specific graphics device.
Usage
update_device_state(device_id = grDevices::dev.cur(), state)
Arguments
device_id |
Graphics device ID |
state |
Updated state list |
Value
NULL (invisible)
Is a set of resolved coordinates usable for an axis grid?
Description
grDevices::xy.coords() coerces whatever it is given, so categorical
coordinates come back as all-NA numerics rather than as an error. Those
are worse than the raw input: range() on them yields infinities and a
warning, where the raw character vector is simply rejected as non-numeric.
Usage
usable_xy_coords(coords)
Arguments
coords |
Value returned by |
Value
TRUE when both axes carry at least one finite value
Validate a canonical axes object (strict)
Description
Enforces the canonical schema. On any violation, throws an error with a descriptive message.
Usage
validate_axes(axes, context = "")
Arguments
axes |
Axes list to validate (or NULL) |
context |
Optional string describing the call site (for errors) |
Details
Rules:
-
axesmust be NULL or a list. Keys must be a subset of
{"x","y","z"}.Each axis value must be a list (AxisConfig), never a string/ number/array.
No
format,min,max,tickStep,fill, orlevelat the top level ofaxes.-
min,max,tickStep(when present inside an axis) must be numeric scalars.
Value
Invisibly returns axes if valid
Build the anchored grob-name pattern for one kind
Description
Build the anchored grob-name pattern for one kind
Usage
vioplot_grob_pattern(plot_index, kind)
Turn a grob name into the selector gridSVG exports it under
Description
gridSVG appends .1 to each grob id, and the existing base R processors
address elements with the [id^=...] prefix form.
Usage
vioplot_grob_selector(element, id)
Walk a grabbed scene, redrawing it with batch markers
Description
Walk a grabbed scene, redrawing it with batch markers
Usage
walk_svg_scene(scene, one_at_a_time = FALSE)
Arguments
scene |
The gTree |
one_at_a_time |
Draw rect and circle grobs one element at a time. |
Value
The walk state (events per marker, symbol use).
Emit a one-time warning when quantmod::chartSeries() is called with a
technical-analysis indicator other than the volume panel (e.g.
TA = "addSMA()").
Description
maidr reads the candlesticks and the volume panel addVo() draws, but
no other indicator, so it falls back to native (non-accessible)
rendering for these calls and surfaces a one-time advisory pointing
users to the ggplot2 + tidyquant + patchwork alternative, which maidr's
ggplot2 path reads in full.
Usage
warn_chartseries_ta_unsupported()
Value
Invisibly NULL.
Say why a fourfoldplot() call is falling back to a picture
Description
The generic "Plot contains unsupported elements" the fallback already
emits is true and uninformative: it does not tell an author that the same
chart with std = "ind.max" would have been read. This says which of the
three measured refusals applied.
Usage
warn_fourfoldplot_declined(reason)
Arguments
reason |
One of |
Details
The three reasons, all measured on R 4.3.3:
-
"std"– the caller'sstdresolved to"margins", which isgraphics::fourfoldplot's own default. Under it the four radii aresqrt(c(u, 1 - u, 1 - u, u))withu = sqrt(or) / (1 + sqrt(or)): one number, the odds ratio, drawn four times. Measured, a table and the same table times three give bit-identical radii, so counts announced there would name numbers the chart did not draw. -
"strata"– a 2x2xk array.fourfoldplot()draws k panels into one figure region with repeatedplot.window()calls rather thanpar(mfrow), so measured onUCBAdmissionsall 78 polygon grobs are namedgraphics-plot-1-*and no helper here slices them per panel. The MESSAGE names the third dimension rather than the k panels, because "k panels share one region" is false for the one array shape that has no strata to confuse: measured,array(c(10, 40, 90, 160), c(2, 2, 1))underind.maxdraws a single panel of exactly 13 polygon grobs – the countwedge_names()accepts – and is declined anyway, becauserecorded_two_way_table()refuses three dimensions. Telling that author about panels they do not have would send them looking for the wrong thing; the matrix spelling is the fix and the message says so. -
"table"– a two-way argument that is not a 2x2 table of finite non-negative numbers summing above zero. Measured, the all-zero table draws ZERO polygon grobs, and a logical matrix printsTRUE/FALSEon the page whileas.numeric()would announce1/0.
Once per reason per session, not once per plot: detect_layer_type() is
called up to five times for one accepted layer
(base_r_plot_orchestrator.R lines 145, 163, 195, 499, 653) and once per
declined one, so an unguarded warning would repeat. The cost is that an
author who draws two default-std charts hears the explanation once –
the same trade warn_chartseries_ta_unsupported() makes above.
The message deliberately avoids the substring "unsupported elements":
tests/testthat/test-base-r-unrecorded-calls.R greps for exactly that to
decide whether the fallback warning arrived, and a second warning
carrying it would make that assertion pass for the wrong reason.
Value
Invisibly NULL.
Warn About Panels That Lost Their Accessible Data
Description
Emitted from the single place every render path funnels through, so a figure is described once no matter which entry point produced it.
Usage
warn_panel_fallback(orchestrator)
Arguments
orchestrator |
The orchestrator about to render the figure |
Value
Invisibly NULL
Wrap a single function
Description
This is only called during .onLoad when the namespace is still open. The wrapper checks is_patching_enabled() at runtime to decide whether to record calls or pass through.
Usage
wrap_function(function_name)
Arguments
function_name |
Name of the function to wrap |
Value
TRUE if successful, FALSE otherwise
Wrap S3 generic functions (lines and points)
Description
Special handling for S3 generics that can't be traced normally. Only called once during .onLoad when namespace is still open.
Usage
wrap_s3_generics()