Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
GITHUB_PAT: ${{ secrets.PAT_GITHUB }}
GH_ACTION: "ENABLED"
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
ANIMINT2_TEST_GHPAGES: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main') }}
steps:
- uses: actions/checkout@v3
- name: install and update texlive
Expand Down Expand Up @@ -48,14 +49,18 @@ jobs:
run: |
npm install v8-to-istanbul
echo "Node modules installed"

- name: Install xvfb (JS_coverage)
if: matrix.test-suite == 'JS_coverage'
run: /usr/bin/sudo DEBIAN_FRONTEND=noninteractive apt-get install -y xvfb

- name: run tests
run: |
if [ "$TEST_SUITE" == "CRAN" ]; then
bash build.sh
elif [ "$TEST_SUITE" == "JS_coverage" ]; then
echo "Running testthat with JS coverage collection..."
Rscript -e "source('tests/testthat.R', chdir = TRUE)"
xvfb-run -a Rscript -e "source('tests/testthat.R', chdir = TRUE)"
else
echo "Running testthat with R coverage collection..."
Rscript -e 'covr::codecov(quiet = FALSE, type = "tests", test_files = "tests/testthat.R", flags = "r")'
Expand Down
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ Collate:
'uu_zzz.r'
'z_animint.R'
'z_animintHelpers.R'
'z_multiline.R'
'z_facets.R'
'z_geoms.R'
'z_helperFunctions.R'
Expand Down
13 changes: 11 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

- `update_axes`: Fixed issue #273 where axis tick text font-size was inconsistent between plots with and without `update_axes`. Previously, plots using `theme_animint(update_axes="x")` would lose `theme(axis.text = element_text(size=...))` styling after axis updates.

# Changes in version 2025.11.7 (PR#261)

- Fixed multiline text spacing: plot titles no longer overlap with plot area, and X/Y axis label spacing is now consistent.
- Fixed axis titles to scale correctly with `theme(text=element_text(size=X))` (issue #64).

# Changes in version 2025.10.31 (PR#271)

- `geom_point()` now warns when shape parameter is set to a value other than 21, since animint2 web rendering only supports shape=21 for proper display of both color and fill aesthetics.
Expand All @@ -30,6 +35,10 @@

- `geom_text(vjust!=0)` warning mentions vjust support in `geom_label_aligned()`.

# Changes in version 2025.10.21 (PR#221)

- Multi-line text support: `\n` now works in plot titles, axis titles, legend titles, and `geom_text()` labels. Created `R/z_multiline.R` with helper to convert `\n` to `<br/>` during R compilation. JavaScript renderer converts `<br/>` to SVG `<tspan>` elements for proper multi-line display.

# Changes in version 2025.10.17 (PR#255)

- `getCommonChunk()` uses default group=1 (previously 1:N which was slower).
Expand Down Expand Up @@ -259,7 +268,7 @@

# Changes in 2022.5.25

- Add ability to rotate geom_text labels, following ggplot2's semantics of rotation direction.
- Add ability to rotate geom_text labels, following ggplot2\'s semantics of rotation direction.

# Changes in 2022.5.24

Expand Down Expand Up @@ -324,4 +333,4 @@

# Changes in 2017.08.24

- DSL: clickSelects/showSelected are now specified as parameters rather than aesthetics.
- DSL: clickSelects/showSelected are now specified as parameters rather than aesthetics.
15 changes: 11 additions & 4 deletions R/z_animint.R
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ parsePlot <- function(meta, plot, plot.name){
for (xy in c("x", "y")) {
s <- function(tmp) sprintf(tmp, xy)
# one axis name per plot (ie, a xtitle/ytitle is shared across panels)
plot.info[[s("%stitle")]] <- if(is.blank(s("axis.title.%s"))){
axis_title_raw <- if(is.blank(s("axis.title.%s"))){
""
} else {
scale.i <- which(plot$scales$find(xy))
Expand All @@ -143,6 +143,10 @@ parsePlot <- function(meta, plot, plot.name){
lab.or.null
}
}
# Convert newlines to <br/> for multi-line axis titles (Issue #221)
plot.info[[s("%stitle")]] <- convertNewlinesToBreaks(axis_title_raw)
## axis title size.
plot.info[[s("%stitle_size")]] <- getTextSize(s("axis.title.%s"), theme.pars)
## panel text size.
plot.info[[s("strip_text_%ssize")]] <- getTextSize(
s("strip.text.%s"), theme.pars)
Expand Down Expand Up @@ -187,12 +191,13 @@ parsePlot <- function(meta, plot, plot.name){
# grab the unique axis labels (makes rendering simpler)
plot.info <- getUniqueAxisLabels(plot.info)

# grab plot title if present
plot.info$title <- if(is(theme.pars$plot.title, "blank")){
# grab plot title if present and convert newlines (Issue #221)
plot_title_raw <- if(is(theme.pars$plot.title, "blank")){
""
}else{
plot$labels$title
}
plot.info$title <- convertNewlinesToBreaks(plot_title_raw)
plot.info$title_size <- getTextSize("plot.title", theme.pars)

## Set plot width and height from animint.* options if they are
Expand Down Expand Up @@ -747,7 +752,6 @@ getLegendList <- function(plistextra){
gdefs <- guides_merge(gdefs)
gdefs <- guides_geom(gdefs, layers, default_mapping)
} else (zeroGrob())
names(gdefs) <- sapply(gdefs, function(i) i$title)

## adding the variable used to each LegendList
for(leg in seq_along(gdefs)) {
Expand Down Expand Up @@ -827,6 +831,9 @@ getLegendList <- function(plistextra){
}
}
legend.list <- lapply(gdefs, getLegend)
# Use the 'class' field from getLegend output for legend key names (Issue #221)
# This ensures JSON keys don't contain newlines or other special characters
names(legend.list) <- sapply(legend.list, function(i) i$class)
## Add a flag to specify whether or not there is both a color and a
## fill legend to display. If so, we need to draw the interior of
## the points in the color legend as the same color.
Expand Down
16 changes: 14 additions & 2 deletions R/z_animintHelpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,8 @@ getLegend <- function(mb){
names(data) <- paste0(geom, names(data))# aesthetics by geom
names(data) <- gsub(paste0(geom, "."), "", names(data), fixed=TRUE) # label isn't geom-specific
data$label <- paste(data$label) # otherwise it is AsIs.
# Convert newlines to <br/> for multi-line legend labels (Issue #221)
data$label <- convertNewlinesToBreaks(data$label)
data
}
dataframes <- mapply(function(i, j) cleanData(i$data, mb$key, j, i$params),
Expand All @@ -726,10 +728,16 @@ getLegend <- function(mb){
if(guidetype=="none"){
NULL
}else{
# Convert newlines to <br/> for multi-line legend title (Issue #221)
legend_title <- convertNewlinesToBreaks(mb$title)
# For the 'class' field (used as JSON key), sanitize newlines to spaces
# to avoid JSON parsing issues with control characters (Issue #221)
safe_title <- gsub("\n", " ", mb$title, fixed = TRUE)
legend_class <- if(mb$is.discrete) mb$selector else safe_title
list(guide = guidetype,
geoms = unlist(mb$geom.legend.list),
title = mb$title,
class = if(mb$is.discrete)mb$selector else mb$title,
title = legend_title,
class = legend_class,
selector = mb$selector,
is_discrete= mb$is.discrete,
legend_type = mb$legend_type,
Expand Down Expand Up @@ -913,6 +921,10 @@ split_recursive <- function(x, vars){
##' @author Toby Dylan Hocking
saveChunks <- function(x, meta){
if(is.data.frame(x)){
# Convert newlines to <br/> in label column for multi-line text (Issue #221)
if("label" %in% names(x)){
x$label <- convertNewlinesToBreaks(x$label)
}
this.i <- meta$chunk.i
csv.name <- sprintf("%s_chunk%d.tsv", meta$g$classed, this.i)
## Some geoms should be split into separate groups if there are NAs.
Expand Down
4 changes: 4 additions & 0 deletions R/z_multiline.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
convertNewlinesToBreaks <- function(text) {
gsub("\n", "<br/>", text, fixed = TRUE)
}

Loading
Loading