Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
300ab23
settings container
vincentarelbundock Sep 10, 2025
17f952b
sanitize_() functions now use settings
vincentarelbundock Sep 10, 2025
d138d8d
internal settings: more internal reorg
vincentarelbundock Sep 10, 2025
cd77067
sanitize_facet()
vincentarelbundock Sep 10, 2025
17718e7
sanitize_datapoints()
vincentarelbundock Sep 10, 2025
302f20c
some types use settings
vincentarelbundock Sep 10, 2025
134479a
more types use settings vault
vincentarelbundock Sep 10, 2025
ce17c17
more types
vincentarelbundock Sep 10, 2025
a913e12
minor tinyplot
vincentarelbundock Sep 10, 2025
b5cb630
Merge branch 'main' into internal_settings_v3
vincentarelbundock Oct 3, 2025
cf0a56d
type_text uses settings container
vincentarelbundock Oct 3, 2025
45a24f6
type_rug uses settings container
vincentarelbundock Oct 3, 2025
6911823
type_ribbon uses settings container
vincentarelbundock Oct 3, 2025
fecde66
type_density uses settings container
vincentarelbundock Oct 3, 2025
289c377
type_boxplot uses settings container
vincentarelbundock Oct 3, 2025
9063873
type_splineplot uses settings container
vincentarelbundock Oct 3, 2025
8093b0b
type_barplot uses settings container
vincentarelbundock Oct 3, 2025
166ba73
all types use settings container
vincentarelbundock Oct 3, 2025
8ecb589
type_data() returns settings containers for all types
vincentarelbundock Oct 3, 2025
59ffc47
flip almost works
vincentarelbundock Oct 3, 2025
a0f3342
type_bubble.R
vincentarelbundock Oct 3, 2025
75b52e8
lim_args function
vincentarelbundock Oct 3, 2025
d09042c
fix barplot axes
vincentarelbundock Oct 3, 2025
d75c9f1
lim_args uses settings container
vincentarelbundock Oct 3, 2025
1c4044c
make check passes
vincentarelbundock Oct 3, 2025
ccd199c
by_aesthetics
vincentarelbundock Oct 3, 2025
30befef
consolidate legend processing
vincentarelbundock Oct 3, 2025
59c178d
format settings list
vincentarelbundock Oct 3, 2025
6a41a7b
reorg
vincentarelbundock Oct 3, 2025
84cac74
docs
vincentarelbundock Oct 3, 2025
2d9b7fb
fix vignette
vincentarelbundock Oct 3, 2025
4ed4063
by_col and by_bg use settings
vincentarelbundock Oct 3, 2025
19dd28b
by_col + by_bg -> by_aesthetics
vincentarelbundock Oct 5, 2025
fc6df93
type_info should go in container settings
vincentarelbundock Oct 6, 2025
552b811
modify_list -> update_settings
vincentarelbundock Oct 6, 2025
813e59c
by_aesthetics() treats by_col and by_bg in the same way as others
vincentarelbundock Oct 6, 2025
612133f
stats::setNames is already imported
vincentarelbundock Nov 18, 2025
c52555e
raw_input is not necessary
vincentarelbundock Nov 19, 2025
1fdef88
comments and reorder by_aesthetics.R
vincentarelbundock Nov 19, 2025
b0a1e07
update_settings everywhere except 1
vincentarelbundock Nov 19, 2025
033c55e
settings list2env subset
vincentarelbundock Nov 19, 2025
e3b4ee7
avoid do.call in type_boxplot
vincentarelbundock Nov 19, 2025
9747199
sanitize_ribbon_alpha
vincentarelbundock Nov 19, 2025
f33a6fd
settings: list -> env
vincentarelbundock Nov 19, 2025
c47e624
settings: list -> env
vincentarelbundock Nov 19, 2025
cd54e7e
settings: list -> env
vincentarelbundock Nov 19, 2025
0674e2e
settings: list -> env
vincentarelbundock Nov 19, 2025
b355c2c
cruft
vincentarelbundock Nov 19, 2025
e584616
fix R check
vincentarelbundock Nov 19, 2025
656c32c
rename
grantmcdermott Nov 19, 2025
6d27eb3
tweak order and add comments
grantmcdermott Nov 19, 2025
221f825
tweak vignette wording
grantmcdermott Nov 19, 2025
4686c0e
tweaks
grantmcdermott Nov 19, 2025
819e0a7
tweak
grantmcdermott Nov 19, 2025
c701699
news item
vincentarelbundock Nov 19, 2025
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
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ inst/user2025
#inst/tinytest/
Makefile
^.devcontainer
Rplots.pdf
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ importFrom(stats,predict)
importFrom(stats,qnorm)
importFrom(stats,qt)
importFrom(stats,quantile)
importFrom(stats,setNames)
importFrom(stats,spline)
importFrom(stats,terms)
importFrom(stats,weighted.mean)
Expand Down
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ where the formatting is also better._

## Dev version

### Breaking change

- Internal settings and parameters are now stored in an environment called `settings`, which can be accessed and modified by type-specific functions. This may require changes to users' custom type functions that previously accessed settings as passed arguments. This change was necessary to improve the modularity and maintainability of the codebase, and to add flexibility. (#473 @vincentarelbundock and @grantmcdermott)

### New features

- `type_text()` gains a `family` argument for controlling the font family,
Expand Down
153 changes: 112 additions & 41 deletions R/by_aesthetics.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,83 @@
by_col = function(ngrps = 1L, col = NULL, palette = NULL, gradient = NULL, ordered = NULL, alpha = NULL) {
#
## orchestration function -----
#

by_aesthetics = function(settings) {
env2env(
settings,
environment(),
c(
"datapoints", "by", "type", "null_by", "pch", "bg", "lty", "lwd",
"bubble", "cex", "alpha", "col", "fill", "ribbon.alpha"
)
)

by_ordered = FALSE
by_continuous = !null_by && inherits(datapoints$by, c("numeric", "integer"))
if (isTRUE(by_continuous) && type %in% c("l", "b", "o", "ribbon", "polygon", "polypath", "boxplot")) {
warning("\nContinuous legends not supported for this plot type. Reverting to discrete legend.")
by_continuous = FALSE
} else if (!null_by) {
by_ordered = is.ordered(by)
}

if (null_by) {
ngrps = 1L
} else if (is.factor(by)) {
ngrps = nlevels(by)
} else if (by_continuous) {
ngrps = 100L
} else {
ngrps = length(unique(by))
}

pch = by_pch(ngrps = ngrps, type = type, pch = pch)
lty = by_lty(ngrps = ngrps, type = type, lty = lty)
lwd = by_lwd(ngrps = ngrps, type = type, lwd = lwd)
cex = by_cex(ngrps = ngrps, type = type, bubble = bubble, cex = cex)

col = by_col(
col = col,
palette = settings$palette, # must use unevaluated palette
alpha = alpha,
by_ordered = by_ordered,
by_continuous = by_continuous,
ngrps = ngrps,
adjustcolor = adjustcolor
)

bg = by_bg(
bg = bg,
fill = fill,
col = col,
palette = settings$palette, # must use unevaluated palette
alpha = alpha,
by_ordered = by_ordered,
by_continuous = by_continuous,
ngrps = ngrps,
type = type,
by = by,
ribbon.alpha = ribbon.alpha,
adjustcolor = adjustcolor
)

# update settings
env2env(
environment(),
settings,
c("by_continuous", "by_ordered", "ngrps", "pch", "lty", "lwd", "cex", "col", "bg")
)
}


#
## subsidiary functions -----
#

by_col = function(col, palette, alpha, by_ordered, by_continuous, ngrps, adjustcolor) {
ordered = by_ordered
gradient = by_continuous

if (is.null(alpha)) alpha = 1
if (is.null(ordered)) ordered = FALSE
if (is.null(gradient)) gradient = FALSE
Expand Down Expand Up @@ -271,6 +350,38 @@ gen_pal_fun = function(pal, gradient = FALSE, alpha = NULL, n = NULL) {
}


by_bg = function(bg, fill, col, palette, alpha, by_ordered, by_continuous, ngrps, type, by, ribbon.alpha, adjustcolor) {
if (is.null(bg) && !is.null(fill)) bg = fill
if (!is.null(bg) && length(bg) == 1 && is.numeric(bg) && bg >= 0 && bg <= 1) {
alpha = bg
bg = "by"
}
if (!is.null(bg) && length(bg) == 1 && bg == "by") {
# use by_col processing, but with the bg-specific colors
bg = by_col(
col = NULL,
palette = palette,
alpha = alpha,
by_ordered = by_ordered,
by_continuous = by_continuous,
ngrps = ngrps,
adjustcolor = adjustcolor
)
} else if (length(bg) != ngrps) {
bg = rep(bg, ngrps)
}
if (type == "ribbon" || (type == "boxplot" && !is.null(by))) {
if (!is.null(bg)) {
bg = adjustcolor(bg, ribbon.alpha)
} else if (!is.null(col)) {
bg = adjustcolor(col, ribbon.alpha)
}
}

bg
}


by_pch = function(ngrps, type, pch = NULL) {
no_pch = FALSE
if (identical(type, "text")) {
Expand Down Expand Up @@ -427,43 +538,3 @@ by_cex = function(ngrps, type, bubble = FALSE, cex = NULL) {



by_bg = function(
adjustcolor,
alpha,
bg,
by,
by_continuous,
by_ordered,
col,
fill,
ngrps,
palette,
ribbon.alpha,
type) {
if (is.null(bg) && !is.null(fill)) bg = fill
if (!is.null(bg) && length(bg) == 1 && is.numeric(bg) && bg >= 0 && bg <= 1) {
alpha = bg
bg = "by"
}
if (!is.null(bg) && length(bg) == 1 && bg == "by") {
bg = by_col(
ngrps = ngrps,
col = NULL,
palette = palette,
gradient = by_continuous,
ordered = by_ordered,
alpha = alpha
)
} else if (length(bg) != ngrps) {
bg = rep(bg, ngrps)
}
if (type == "ribbon" || (type == "boxplot" && !is.null(by))) {
if (!is.null(bg)) {
bg = adjustcolor(bg, ribbon.alpha)
} else if (!is.null(col)) {
bg = adjustcolor(col, ribbon.alpha)
}
}

return(bg)
}
4 changes: 2 additions & 2 deletions R/draw_legend.R
Original file line number Diff line number Diff line change
Expand Up @@ -707,10 +707,10 @@ sanitize_legend = function(legend, legend_args) {
lnms = names(largs)
# check second position b/c first will be a symbol
if (is.null(lnms)) {
largs = stats::setNames(largs, c("", "x"))
largs = setNames(largs, c("", "x"))
} else if (length(largs) >= 2 && lnms[2] == "") {
lnms[2] = "x"
largs = stats::setNames(largs, lnms)
largs = setNames(largs, lnms)
} else {
largs[["x"]] = "right!"
}
Expand Down
44 changes: 30 additions & 14 deletions R/facet.R
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ draw_facet_window = function(
nfacets, nfacet_cols, nfacet_rows,
# axes args
axes, flip, frame.plot, oxaxis, oyaxis,
xlabs, xlim, xlim_user, xaxt, xaxs, xaxb, xaxl,
ylabs, ylim, ylim_user, yaxt, yaxs, yaxb, yaxl,
xlabs, xlim, null_xlim, xaxt, xaxs, xaxb, xaxl,
ylabs, ylim, null_ylim, yaxt, yaxs, yaxb, yaxl,
asp, log,
# other args (in approx. alphabetical + group ordering)
dots,
Expand Down Expand Up @@ -302,8 +302,8 @@ draw_facet_window = function(
# individual facet.
xfree = split(c(x, xmin, xmax), facet)[[ii]]
yfree = split(c(y, ymin, ymax), facet)[[ii]]
if (!xlim_user) xlim = range(xfree, na.rm = TRUE)
if (!ylim_user) ylim = range(yfree, na.rm = TRUE)
if (null_xlim) xlim = range(xfree, na.rm = TRUE)
if (null_ylim) ylim = range(yfree, na.rm = TRUE)
xext = extendrange(xlim, f = 0.04)
yext = extendrange(ylim, f = 0.04)
# We'll save this in a special .fusr env var (list) that we'll re-use
Expand Down Expand Up @@ -518,7 +518,27 @@ draw_facet_window = function(

#' @rdname facet
#' @keywords internal
facet_layout = function(facet, add = FALSE, facet.args = list()) {
#' @param settings A list of settings as created by `tinyplot()`.
facet_layout = function(settings) {
# Extract needed variables from settings
add = settings$add
facet.args = settings$facet.args
datapoints = settings$datapoints
facet_attr = settings$facet_attr

# Simplify facet if only one unique value
facet = datapoints$facet
if (!is.null(facet) && length(unique(facet)) == 1) {
facet = NULL
datapoints$facet = NULL
}

# Restore facet attributes
if (!is.null(facet)) {
attributes(facet) = facet_attr
attributes(datapoints$facet) = facet_attr
}

nfacet_rows = 1
nfacet_cols = 1
if (!is.null(facet)) {
Expand Down Expand Up @@ -565,15 +585,11 @@ facet_layout = function(facet, add = FALSE, facet.args = list()) {
cex_fct_adj = 1
}

list(
facets = facets,
ifacet = ifacet,
nfacets = nfacets,
nfacet_rows = nfacet_rows,
nfacet_cols = nfacet_cols,
oxaxis = oxaxis,
oyaxis = oyaxis,
cex_fct_adj = cex_fct_adj
# update settings
env2env(
environment(),
settings,
c("datapoints", "facets", "ifacet", "nfacets", "nfacet_rows", "nfacet_cols", "oxaxis", "oyaxis", "cex_fct_adj")
)
}

Expand Down
54 changes: 54 additions & 0 deletions R/flip.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
swap_elements = function(env, a, b) {
# Swap two elements in an environment
val_a = if (exists(a, envir = env, inherits = FALSE)) env[[a]] else NULL
val_b = if (exists(b, envir = env, inherits = FALSE)) env[[b]] else NULL

assign(a, val_b, envir = env)
assign(b, val_a, envir = env)
}


swap_columns = function(dp, a, b) {
va = dp[[a]]
vb = dp[[b]]
dp[[a]] = if (!is.null(vb)) vb else NULL
dp[[b]] = if (!is.null(va)) va else NULL
dp
}


flip_datapoints = function(settings) {
env2env(settings, environment(), c("flip", "type", "datapoints", "log"))

assert_flag(flip)
if (isTRUE(flip)) {
if (type == "boxplot") {
# boxplot: let horizontal=TRUE do most work; only swap labels
swap_elements(settings, "xlab", "ylab")
} else {
datapoints = swap_columns(datapoints, "xmin", "ymin")
datapoints = swap_columns(datapoints, "xmax", "ymax")
datapoints = swap_columns(datapoints, "x", "y")

# Swap all the x/y settings in the environment
swap_elements(settings, "x", "y")
swap_elements(settings, "xaxb", "yaxb")
swap_elements(settings, "xaxl", "yaxl")
swap_elements(settings, "xaxs", "yaxs")
swap_elements(settings, "xaxt", "yaxt")
swap_elements(settings, "xlab", "ylab")
swap_elements(settings, "xlabs", "ylabs")
swap_elements(settings, "xlim", "ylim")
swap_elements(settings, "xmax", "ymax")
swap_elements(settings, "xmin", "ymin")

if (!is.null(log)) {
log = chartr("xy", "yx", log)
assign("log", log, envir = settings)
}

# Copy modified datapoints back
assign("datapoints", datapoints, envir = settings)
}
}
}
55 changes: 37 additions & 18 deletions R/lim.R
Original file line number Diff line number Diff line change
@@ -1,30 +1,49 @@
# calculate limits of each plot

lim_args = function(
datapoints,
xlim, ylim,
xaxb = NULL, yaxb = NULL,
xlim_user = FALSE, ylim_user = FALSE,
type
) {

lim_args = function(settings) {
env2env(
settings,
environment(),
c(
"xaxb", "xlabs", "xlim", "null_xlim",
"yaxb", "ylabs", "ylim", "null_ylim",
"datapoints", "type"
)
)

# For cases where x/yaxb is provided and corresponding x/ylabs is not null...
# We can subset these here to provide breaks
if (!is.null(xaxb) && !is.null(xlabs)) {
xlabs = xlabs[names(xlabs) %in% xaxb]
xaxb = NULL # don't need this any more
}
if (!is.null(yaxb) && !is.null(ylabs)) {
ylabs = ylabs[names(ylabs) %in% yaxb]
yaxb = NULL # don't need this any more
}

if (is.null(xlim)) {
xlim = range(c(datapoints[["x"]], datapoints[["xmin"]],
datapoints[["xmax"]]), finite = TRUE)
xlim = range(c(
datapoints[["x"]], datapoints[["xmin"]],
datapoints[["xmax"]]), finite = TRUE)
}
if (is.null(ylim)) {
ylim = range(c(datapoints[["y"]], datapoints[["ymin"]],
datapoints[["ymax"]]), finite = TRUE)
ylim = range(c(
datapoints[["y"]], datapoints[["ymin"]],
datapoints[["ymax"]]), finite = TRUE)
}

if (identical(type, "boxplot")) {
xlim = xlim + c(-0.5, 0.5)
}

if (!xlim_user && !is.null(xaxb) && type != "spineplot") xlim = range(c(xlim, xaxb))
if (!ylim_user && !is.null(yaxb) && type != "spineplot") ylim = range(c(ylim, yaxb))

out = list(xlim = xlim, ylim = ylim)
return(out)
}
if (null_xlim && !is.null(xaxb) && type != "spineplot") xlim = range(c(xlim, xaxb))
if (null_ylim && !is.null(yaxb) && type != "spineplot") ylim = range(c(ylim, yaxb))

# update settings
env2env(
environment(),
settings,
c("xlim", "ylim", "xlabs", "ylabs", "xaxb", "yaxb")
)
}
Loading