Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
f3f6bc4
Add CRAN-SUBMISSION to .Rbuildignore and versioning policy to CLAUDE.md
mortonanalytics Mar 27, 2026
78eb3f6
Add sparkline mode for compact table-cell charts (v1.2)
mortonanalytics Mar 28, 2026
0645eff
Merge pull request #27 from mortonanalytics/feature/sparkline-mode
mortonanalytics Mar 28, 2026
3be5506
Add dark mode / theme system with auto-detection (v1.2)
mortonanalytics Mar 28, 2026
78123f3
Merge pull request #28 from mortonanalytics/feature/theme-system
mortonanalytics Mar 28, 2026
c614a19
Add export enhancements: SVG download, clipboard, CSS var resolution …
mortonanalytics Mar 28, 2026
f1a3808
Merge pull request #29 from mortonanalytics/feature/export-enhancements
mortonanalytics Mar 28, 2026
cb7f9b6
Add small multiples / faceting with CSS grid layout (v1.2)
mortonanalytics Mar 29, 2026
14a2d57
Merge pull request #30 from mortonanalytics/feature/small-multiples
mortonanalytics Mar 29, 2026
b6be35a
Add lollipop and dumbbell chart types (v1.2)
mortonanalytics Mar 29, 2026
cb8897e
Merge pull request #31 from mortonanalytics/feature/lollipop-dumbbell
mortonanalytics Mar 29, 2026
d2081e7
Add waffle, beeswarm, and bump chart types (v1.2)
mortonanalytics Mar 29, 2026
0b8477a
Merge pull request #32 from mortonanalytics/feature/waffle-beeswarm-bump
mortonanalytics Mar 29, 2026
dc2774a
Add SVG accessibility: ARIA roles, keyboard nav, data table (v1.2)
mortonanalytics Mar 29, 2026
781ad80
Merge pull request #33 from mortonanalytics/feature/svg-accessibility
mortonanalytics Mar 29, 2026
1a467fa
Add survival curves, distribution fitting, and layer opacity (Phase 4…
mortonanalytics Mar 29, 2026
aae9c8f
Merge pull request #34 from mortonanalytics/feature/session1-stats
mortonanalytics Mar 29, 2026
276210c
Add plotly migration guide vignette
mortonanalytics Mar 29, 2026
bad295f
Merge pull request #35 from mortonanalytics/feature/plotly-migration-…
mortonanalytics Mar 29, 2026
cac4709
Add linked brushing and group-by auto-series (Phase 4 Session 2)
mortonanalytics Mar 29, 2026
99c68c7
Merge pull request #36 from mortonanalytics/feature/session2-adoption
mortonanalytics Mar 29, 2026
23e2cb6
Add theme gallery with 12 named presets (Phase 4 Session 3)
mortonanalytics Mar 29, 2026
ea6fd94
Merge pull request #37 from mortonanalytics/feature/session3-polish
mortonanalytics Mar 29, 2026
75b8e89
Add radar, funnel, and parallel coordinates chart types (Phase 4 Sess…
mortonanalytics Mar 29, 2026
350f605
Merge pull request #38 from mortonanalytics/feature/session4-charts
mortonanalytics Mar 29, 2026
1f59b01
Update gallery app with all v1.2 features
mortonanalytics Mar 29, 2026
20e751b
Merge pull request #39 from mortonanalytics/feature/gallery-update
mortonanalytics Mar 29, 2026
7d1af0c
Fix gallery app visual issues from review
mortonanalytics Mar 29, 2026
be732a3
Merge pull request #40 from mortonanalytics/fix/gallery-visual-issues
mortonanalytics Mar 29, 2026
b9b19ed
Fix renderer bugs found during visual review
mortonanalytics Mar 29, 2026
2ff29b6
Merge pull request #41 from mortonanalytics/fix/renderer-bugs
mortonanalytics Mar 29, 2026
69fae17
Fix distribution fit x-axis scale: add xExtentFields to scaleHints
mortonanalytics Mar 29, 2026
bbb2df9
Merge pull request #42 from mortonanalytics/fix/distfit-scale
mortonanalytics Mar 29, 2026
b270ba9
Fix Shiny dropdown reactivity: destroy and recreate chart on re-render
mortonanalytics Mar 29, 2026
19f79be
Merge pull request #43 from mortonanalytics/fix/shiny-rerender
mortonanalytics Mar 29, 2026
0effb45
Fix theme presets not visually applying
mortonanalytics Mar 29, 2026
bdc5767
Merge pull request #44 from mortonanalytics/fix/theme-visual
mortonanalytics Mar 29, 2026
2e1a09d
Add contract tests for export enhancements
mortonanalytics Mar 31, 2026
5cb4834
Add contract tests for export enhancements (13 tests, all red)
mortonanalytics Mar 31, 2026
a3d3439
Vendor jsPDF 2.5.2 for lazy-loaded PDF export
mortonanalytics Mar 31, 2026
563c2bc
Expand CSS var list to 15 entries
mortonanalytics Mar 31, 2026
692200a
Add legend injection to clipboard exports
mortonanalytics Mar 31, 2026
32e3ede
Add copy submenu + feedback CSS
mortonanalytics Mar 31, 2026
7851779
co-code T1: Expand CSS var list to 15 entries
mortonanalytics Mar 31, 2026
6541055
co-code T3: Add legend injection to clipboard exports
mortonanalytics Mar 31, 2026
241abbd
co-code T5: Add copy submenu + feedback CSS
mortonanalytics Mar 31, 2026
8773265
Add clipboard button with copy submenu to toolbar
mortonanalytics Mar 31, 2026
24ad7c6
Add behavioral tests for resolve-css-vars
mortonanalytics Mar 31, 2026
56ea2b2
Create load-jspdf.js lazy loader
mortonanalytics Mar 31, 2026
0e0416c
co-code T4: Add clipboard button with copy submenu
mortonanalytics Mar 31, 2026
d8cb68d
co-code T2: Add behavioral tests for resolve-css-vars
mortonanalytics Mar 31, 2026
0493abd
co-code T7: Create load-jspdf.js lazy loader
mortonanalytics Mar 31, 2026
9ad1e15
Legend UI redesign: T1+T3+T4 — icons, CSS, buttonDiv cleanup
mortonanalytics Mar 31, 2026
2334c49
Legend UI redesign: T2 — panel restructure
mortonanalytics Mar 31, 2026
ff3a537
Legend UI redesign: T5+T6 — test updates
mortonanalytics Mar 31, 2026
1fbb79e
Legend UI redesign: T7 — bundle rebuild
mortonanalytics Mar 31, 2026
4b2d020
Fix ordinal legend panel staleness after toggle/reset
mortonanalytics Mar 31, 2026
08366dd
Add PDF export, clipboard copy, and fix export button defaults
mortonanalytics Mar 31, 2026
077fcdb
Add Export Demo tab to gallery app
mortonanalytics Mar 31, 2026
bc00a7a
Merge legend redesign + export enhancements into develop
mortonanalytics Mar 31, 2026
9edfbd8
Bump vite to 7.3.2 to fix three security vulnerabilities
mortonanalytics Apr 8, 2026
00b90ad
Fix SVG/PDF exports and dark-mode CSS var resolution
mortonanalytics Apr 17, 2026
468e2a9
Split clipboard action into Copy as PNG and Copy as SVG
mortonanalytics Apr 18, 2026
e19fa1e
Add linked cursor: synchronized hover crosshair across linked charts
mortonanalytics Apr 18, 2026
b7c2d89
Fix linked cursor crosshair appearing outside plot area
mortonanalytics Apr 19, 2026
a66eab9
Declare dplyr in Suggests to quiet R CMD check warnings
mortonanalytics Apr 19, 2026
6bd02ca
Add calendarHeatmap chart type
mortonanalytics Apr 19, 2026
66ed9c4
Add bslib sizing policy and expand crosstalk to 4 more chart types
mortonanalytics Apr 19, 2026
64730e0
Bump brace-expansion to resolve moderate audit advisory
mortonanalytics Apr 19, 2026
ce334df
Add AGENTS.md and cross-repo engine-bump-notify workflow
mortonanalytics Apr 19, 2026
4884cb9
Add smoke screenshots and exclude dev artifacts from CRAN tarball
mortonanalytics Apr 19, 2026
d8cefaf
Add workflow_dispatch trigger to engine-bump-notify
mortonanalytics Apr 19, 2026
9038304
Switch engine-bump-notify to REST (gh api) for fine-grained PAT support
mortonanalytics Apr 19, 2026
9c5082d
Use curl (not gh api) to create tracking issue
mortonanalytics Apr 19, 2026
889b672
Add token diagnostic to engine-bump-notify
mortonanalytics Apr 19, 2026
cad153d
Remove token diagnostic from engine-bump-notify
mortonanalytics Apr 19, 2026
523d79a
Merge remote-tracking branch 'origin/main' into develop
mortonanalytics Apr 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@
^design$
^md$
^review-home\.png$
^calendar-smoke\.png$
^linked-cursor-smoke\.png$
^linked-cursor-fixed\.png$
^AGENTS\.md$
^screenshots-review$
^scripts$
^inst/test_rmarkdown
^inst/appTester$
^CRAN-SUBMISSION$
7 changes: 7 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,10 @@
- **Website presence:** Demo gallery + package docs live at morton-analytics.com/myio/ (reverse-proxied from droplet). 17 chart types with interactive previews.
- **Market context:** Proof point for Morton's "open-source analytics" positioning. Demonstrates the builder identity — we don't just consult, we ship tools.
- **Related:** See `../morton-analytics-web/market-research/brand-strategy.md` for how myIO fits the content strategy

## Versioning & Compatibility

- myIO follows **strict semver**. Breaking changes are permitted only at major version bumps and should be minimized even then.
- All minor and patch releases (e.g., v1.2.0) **must** be fully backward compatible.
- Deprecations follow a **~2-year sunset**: introduce a deprecation warning in version N, remove no sooner than 2 years later at the next major version.
- See `docs/versioning-policy.md` for full policy details.
6 changes: 5 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ Suggests:
rmarkdown,
pkgdown,
shiny,
crosstalk (>= 1.2.0)
crosstalk (>= 1.2.0),
dplyr,
DT,
reactable,
htmltools
Config/testthat/edition: 3
VignetteBuilder: knitr
Imports:
Expand Down
5 changes: 5 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export(addIoLayer)
export(defineCategoricalAxis)
export(dragPoints)
export(flipAxis)
export(linkCharts)
export(myIO)
export(myIOOutput)
export(myIO_last_error)
Expand All @@ -13,7 +14,11 @@ export(setAxisFormat)
export(setAxisLimits)
export(setBrush)
export(setColorScheme)
export(setExportOptions)
export(setFacet)
export(setLayerOpacity)
export(setLinked)
export(setLinkedCursor)
export(setMargin)
export(setReferenceLines)
export(setSlider)
Expand Down
132 changes: 132 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,135 @@
# myIO 1.2.0 (development)

## Crosstalk: expanded chart-type coverage

* `setLinked()` now links `waffle`, `beeswarm`, `lollipop`, and `dumbbell`
layers in addition to the previously supported `point`, `bar`, `groupedBar`,
`histogram`, and `hexbin`. Selection dims non-matching elements; filter
hides them. Aggregate chart types (`boxplot`, `violin`, `qq`, `regression`,
`density`, `ridgeline`, `survfit`, `comparison`) remain outside crosstalk
in v1.2.
* New vignette `crosstalk-linking` demonstrates linking myIO with
`DT::datatable()` and `reactable::reactable()`, with code listings for
plotly and leaflet.

## bslib and Quarto Dashboards integration

* `myIO()` widgets now declare a sizing policy with `browser.fill = TRUE`
and are tagged as `html-fill-item` via `htmltools::bindFillRole()`, so
they fill container height inside `bslib::card()`, Quarto Dashboard
`{.fill}` cards, and flexdashboard layouts. Rendering in plain RMarkdown
and Shiny at the default 400px height is unchanged.
* Widget resize is now guarded against zero-dimension containers that can
appear briefly during fill-layout transitions.

## Calendar heatmap

* New `calendarHeatmap` chart type — GitHub-contributions-style grid of daily
cells over a single calendar year. Usage:
`addIoLayer(type = "calendarHeatmap", data, mapping = list(date = "day", value = "x"))`.
Supports Sunday or Monday week starts via `options$weekStart`, continuous
color legend, and linked-cursor sync across two linked calendars. Multi-year
data is rejected in v1.2; multi-year layouts are planned for v1.3. New CSS
variables: `--chart-calendar-cell-gap`, `--chart-calendar-cell-stroke`,
`--chart-calendar-empty-fill`.

## Theme gallery

* 12 named theme presets: `setTheme(preset = "midnight")`. Available presets:
midnight, ocean, forest, sunset, monochrome, neon, corporate, academic,
nature, minimal, retro, warm. Plus light/dark via mode parameter.

## Linked brushing

* `linkCharts(chart1, chart2, on = "column")` enables cross-chart selection.
Brush in one chart highlights matching rows in linked charts. Works in Shiny
and static HTML. Aggregation-to-source-row key resolution for summary views.

## Linked cursor

* `linkCharts()` and `setLinked()` gain a `cursor = TRUE` argument that draws a
synchronized vertical crosshair on every linked chart when the user hovers
any chart in the group. Supports point, bar, line, area, groupedBar, hexbin,
and histogram layers (donut and treemap are excluded — no x-axis to sync on).
Off by default; enable per-link or retrofit with `setLinkedCursor()` on a
pre-linked widget. New `--chart-cursor-rule-color`/`-width`/`-dasharray` CSS
variables theme the crosshair.

## Group-by auto-series

* Pass a `dplyr::group_by()` tibble to `addIoLayer()` and it auto-creates one
layer per group with colors from the Okabe-Ito palette. Soft dplyr dependency.

## Survival curves (Kaplan-Meier)

* `addIoLayer(type = "survfit", mapping = list(time = "time", status = "status"))`
computes Kaplan-Meier estimator with Greenwood CI using base R only (no
`survival` package dependency). Composite expands to step-curve line, CI band,
and censored-observation markers. Group stratification supported.

## Distribution fitting overlay

* `addIoLayer(type = "histogram_fit", mapping = list(value = "x"), options = list(family = "normal"))`
fits normal, lognormal, or exponential distributions via MLE. Composite
renders histogram + fitted density curve + optional parameter annotation.

## Layer opacity control

* `setLayerOpacity(label, opacity)` sets per-layer opacity (0-1). Critical for
CI bands overlaying scatter data.

## SVG accessibility

* ARIA roles (`graphics-document`, `graphics-object`, `graphics-symbol`) applied
to SVG chart structure for screen reader navigation.
* Keyboard navigation: arrow keys traverse layers and data points, with live
region announcements (150ms debounce).
* Hidden data table fallback for screen reader access to raw data (capped at
500 rows).
* Focus ring styling and screen-reader-only utility class.

## New chart types

* `lollipop` — vertical stem with circle head, supports `mean` and `summary`
transforms. Compatible with categorical x-axis charts.
* `dumbbell` — connected dots showing a range between `low_y` and `high_y`.
* `waffle` — 10x10 grid of colored squares representing proportions. Standalone.
* `beeswarm` — dodge-positioned points to avoid overlap. Inline dodge algorithm.
* `bump` — smooth S-curves showing rank/value changes over time with grouped lines.
* `radar` — spider/radar chart with radial axes and polygon data fill.
* `funnel` — narrowing horizontal bars for conversion pipeline data.
* `parallel` — parallel coordinates for multivariate exploration.
All new types support themed colors and standard tooltip formatting.

## Small multiples / faceting

* `setFacet(var, ncol, scales)` splits charts into a CSS grid of panels, one per
unique value of the faceting variable. Supports fixed and free scale modes,
auto-layout with configurable minimum panel width, and responsive breakpoints.

## Export enhancements

* `setExportOptions()` controls which export buttons appear in the toolbar
(PNG, SVG, clipboard, CSV). New SVG download button and clipboard copy
(SVG + PNG) via the Clipboard API.
* CSS custom properties resolved in exported SVGs for correct dark-mode colors.

## Dark mode / theme system

* `setTheme(mode = "dark")` applies a WCAG AA-verified dark palette across all
chart elements. Also supports `"light"` and `"auto"` (detects OS preference
and Quarto/Bootstrap `data-bs-theme`).
* Backward compatible: existing `setTheme(bg = "#fff")` calls still work.
* New `overrides` parameter for fine-grained CSS custom property control.
* High-contrast and reduced-motion CSS media query support.

## Sparkline mode

* `myIO(sparkline = TRUE)` renders a compact, axes-free chart suitable for
embedding in table cells (reactable, DT, gt). Strips legend, axes, reference
lines, and all interactions. Default height 20px. Supports line, bar, and
area layer types.

# myIO 1.1.0

## I/O interaction system
Expand Down
56 changes: 55 additions & 1 deletion R/addIoLayer.R
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,27 @@ addIoLayer <- function(myIO,
toolTipOptions = list(suppressY = FALSE))) {
assert_myIO(myIO)

if (isTRUE(myIO$x$config$sparkline)) {
sparkline_types <- c("line", "bar", "area")
if (!type %in% sparkline_types) {
stop(sprintf(
"Sparkline mode only supports types: %s. Got: '%s'",
paste(sparkline_types, collapse = ", "), type
), call. = FALSE)
}
}

existing_layers <- myIO$x$config$layers

if (is.null(data)) {
data <- myIO$x$data
}
data <- ensure_source_key(data)

if (inherits(data, "grouped_df")) {
return(expand_grouped_df(myIO, type, color, label, data, mapping, transform, options))
}

validate_layer_inputs(type, transform, mapping, label, data, existing_layers)

presets <- list(barSize = "large", toolTipOptions = list(suppressY = FALSE))
Expand Down Expand Up @@ -204,6 +218,15 @@ validate_layer_inputs <- function(type, transform, mapping, label, data, existin
rangeBar = c("x_var", "low_y", "high_y"),
area = c("x_var", "low_y", "high_y"),
hexbin = c("x_var", "y_var", "radius"),
survfit = c("time", "status"),
histogram_fit = c("value"),
dumbbell = c("x_var", "low_y", "high_y"),
waffle = c("category", "value"),
bump = c("x_var", "y_var", "group"),
radar = c("axis", "value"),
funnel = c("stage", "value"),
parallel = c("dimensions"),
calendarHeatmap = c("date", "value"),
c("x_var", "y_var")
)
}
Expand All @@ -216,7 +239,7 @@ validate_layer_inputs <- function(type, transform, mapping, label, data, existin
# Fields produced by the transform should be skipped in column-existence checks
skip_fields <- if (!is.null(transform_contract)) transform_contract$skip_column_check else character(0)

mapped_fields <- intersect(c("x_var", "y_var", "group", "level_1", "level_2", "value", "low_y", "high_y", "open", "high", "low", "close", "total", "source", "target"), names(mapping))
mapped_fields <- intersect(c("x_var", "y_var", "group", "level_1", "level_2", "value", "low_y", "high_y", "open", "high", "low", "close", "total", "source", "target", "date"), names(mapping))
mapped_fields <- setdiff(mapped_fields, skip_fields)
for (field in mapped_fields) {
if (!mapping[[field]] %in% colnames(data)) {
Expand All @@ -240,6 +263,31 @@ validate_layer_inputs <- function(type, transform, mapping, label, data, existin
stop("addIoLayer(): Mapped field '", mapping[["value"]], "' must be numeric for type '", type, "'.", call. = FALSE)
}

if (type == "calendarHeatmap") {
if (nrow(data) == 0L) {
stop("addIoLayer(): type 'calendarHeatmap' requires data with at least 1 row (got no rows).", call. = FALSE)
}
if (!is.numeric(data[[mapping[["value"]]]])) {
stop("addIoLayer(): Mapped field '", mapping[["value"]],
"' must be numeric for type 'calendarHeatmap'.", call. = FALSE)
}
date_col <- data[[mapping[["date"]]]]
dates <- tryCatch(as.Date(date_col), error = function(e) NULL)
if (is.null(dates) || any(is.na(dates))) {
stop("addIoLayer(): Mapped field '", mapping[["date"]],
"' must be Date or coercible via as.Date() for type 'calendarHeatmap'.",
call. = FALSE)
}
years <- unique(as.integer(format(dates, "%Y")))
if (length(years) > 1L) {
stop("addIoLayer(): type 'calendarHeatmap' data spans multiple calendar years (",
paste(range(years), collapse = "-"),
"). v1.2 supports a single year per layer. Use setFacet() for multi-year layouts (planned for v1.3).",
call. = FALSE)
}
data[[mapping[["date"]]]] <- format(dates, "%Y-%m-%d")
}

if (type == "waterfall" && !is.numeric(data[[mapping[["y_var"]]]])) {
stop("addIoLayer(): Mapped field '", mapping[["y_var"]], "' must be numeric for type '", type, "'.", call. = FALSE)
}
Expand Down Expand Up @@ -334,6 +382,12 @@ TRANSFORM_INPUT_CONTRACTS <- list(
"p_value", "label", "method", "statistic"),
auto_mapping = list(x1 = "x1", x2 = "x2", y = "y",
label = "label", p_value = "p_value")
),
survfit = list(
required_map = c("time", "status"),
skip_column_check = c("x_var", "y_var", "low_y", "high_y"),
auto_mapping = list(x_var = "time", y_var = "surv",
low_y = "ci_lower", high_y = "ci_upper")
)
)

Expand Down
92 changes: 92 additions & 0 deletions R/composite_histogram_fit.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#' Histogram + fitted distribution composite expansion
#'
#' Expands into a histogram layer plus a fitted density line.
#' Optionally includes a text annotation with distribution parameters.
#'
#' @keywords internal
composite_histogram_fit <- function(data, mapping, label, color, options) {
family <- if (is.null(options$family)) "normal" else options$family
show_params <- if (is.null(options$showParams)) FALSE else isTRUE(options$showParams)
bins <- if (is.null(options$bins)) 30L else as.integer(options$bins)
base_color <- if (is.null(color)) OKABE_ITO_PALETTE[[1]] else if (length(color) > 0) color[[1]] else OKABE_ITO_PALETTE[[1]]
line_color <- if (is.null(options$lineColor)) "#D55E00" else options$lineColor

fit_result <- transform_fit_distribution(data, mapping, options)

# Pre-bin the histogram in R so JS doesn't need to re-bin
val_col <- mapping$value
vals <- data[[val_col]]
vals <- vals[!is.na(vals)]
h <- graphics::hist(vals, breaks = bins, plot = FALSE)
hist_data <- data.frame(
x_var = h$mids,
y_var = h$counts,
x0 = h$breaks[-length(h$breaks)],
x1 = h$breaks[-1],
stringsAsFactors = FALSE
)
hist_data[["_source_key"]] <- sprintf("bin_%d", seq_len(nrow(hist_data)))

layers <- list(
list(
type = "bar",
data = hist_data,
mapping = list(x_var = "x_var", y_var = "y_var"),
transform = "identity",
label = paste0(label, " - histogram"),
color = base_color,
role = "histogram",
scaleHints = list(
xScaleType = "linear", yScaleType = "linear",
xExtentFields = list("x_var"), yExtentFields = list("y_var"),
domainMerge = "union"
)
),
list(
type = "line",
data = fit_result$data,
mapping = list(x_var = "x_var", y_var = "y_var"),
transform = "identity",
label = paste0(label, " - fit"),
color = line_color,
role = "density_line",
scaleHints = list(
xScaleType = "linear", yScaleType = "linear",
xExtentFields = list("x_var"), yExtentFields = list("y_var"),
domainMerge = "union"
)
)
)

if (show_params && length(fit_result$params) > 0) {
param_strings <- vapply(names(fit_result$params), function(p) {
paste0(p, " = ", round(fit_result$params[[p]], 4))
}, character(1))
param_text <- paste(param_strings, collapse = ", ")
annotation_label <- paste0(family, ": ", param_text)

x_range <- range(fit_result$data$x_var)
y_range <- range(fit_result$data$y_var)

text_data <- data.frame(
x_var = x_range[1] + 0.05 * diff(x_range),
y_var = y_range[2] * 0.95,
label = annotation_label,
stringsAsFactors = FALSE,
check.names = FALSE
)
text_data[["_source_key"]] <- "params_text"

layers[[length(layers) + 1L]] <- list(
type = "text",
data = text_data,
mapping = list(x_var = "x_var", y_var = "y_var"),
transform = "identity",
label = paste0(label, " - params"),
color = "#333333",
role = "params_text"
)
}

layers
}
Loading
Loading