diff --git a/DESCRIPTION b/DESCRIPTION
index 6ae98a2..0d2f992 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -2,7 +2,9 @@ Package: ggrepel
Version: 0.9.5.9999
Authors@R: c(
person("Kamil", "Slowikowski", email = "kslowikowski@gmail.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-2843-6370")),
+ person("Pedro", "Aphalo", role = "ctb", comment = c(ORCID = "0000-0003-3385-972X")),
person("Alicia", "Schep", role = "ctb", comment = c(ORCID = "0000-0002-3915-0618")),
+ person("Teun", "van den Brand", role = c("ctb"), comment = c(ORCID = "0000-0002-9335-7468")),
person("Sean", "Hughes", role = "ctb", comment = c(ORCID = "0000-0002-9409-9405")),
person("Trung Kien", "Dang", role = "ctb", comment = c(ORCID = "0000-0001-7562-6495")),
person("Saulius", "Lukauskas", role = "ctb"),
@@ -17,7 +19,6 @@ Authors@R: c(
person("Robrecht", "Cannoodt", role = "ctb", comment = c(ORCID = "0000-0003-3641-729X")),
person("MichaĆ", "Krassowski", role = "ctb", comment = c(ORCID = "0000-0002-9638-7785")),
person("Michael", "Chirico", role = "ctb", comment = c(ORCID = "0000-0003-0787-087X")),
- person("Pedro", "Aphalo", role = "ctb", comment = c(ORCID = "0000-0003-3385-972X")),
person("Francis", "Barton", role = "ctb")
)
Title: Automatically Position Non-Overlapping Text Labels with 'ggplot2'
diff --git a/NAMESPACE b/NAMESPACE
index 41e3ec4..3940a93 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -11,7 +11,10 @@ export(position_nudge_repel)
import(Rcpp)
import(ggplot2)
importFrom(grid,convertHeight)
+importFrom(grid,convertUnit)
importFrom(grid,convertWidth)
+importFrom(grid,convertX)
+importFrom(grid,convertY)
importFrom(grid,curveGrob)
importFrom(grid,gList)
importFrom(grid,gTree)
@@ -25,6 +28,8 @@ importFrom(grid,grobY)
importFrom(grid,is.grob)
importFrom(grid,is.unit)
importFrom(grid,makeContent)
+importFrom(grid,popViewport)
+importFrom(grid,pushViewport)
importFrom(grid,resolveHJust)
importFrom(grid,resolveVJust)
importFrom(grid,roundrectGrob)
@@ -34,5 +39,6 @@ importFrom(grid,stringHeight)
importFrom(grid,stringWidth)
importFrom(grid,textGrob)
importFrom(grid,unit)
+importFrom(grid,viewport)
importFrom(rlang,warn)
useDynLib(ggrepel)
diff --git a/R/geom-label-repel.R b/R/geom-label-repel.R
index dc9eac1..4b5acc4 100644
--- a/R/geom-label-repel.R
+++ b/R/geom-label-repel.R
@@ -211,14 +211,30 @@ GeomLabelRepel <- ggproto(
#' @noRd
makeContent.labelrepeltree <- function(x) {
+ # Absolute panel size
+ width <- width_cm( unit(1, "npc"))
+ height <- height_cm(unit(1, "npc"))
+
+ # Translate points to cm (assumed to be 0-1 range native at first)
+ x$data$x <- x$data$x * width
+ x$data$y <- x$data$y * height
+
# The padding around each bounding box.
- box_padding_x <- convertWidth(x$box.padding, "npc", valueOnly = TRUE)
- box_padding_y <- convertHeight(x$box.padding, "npc", valueOnly = TRUE)
+ box.padding <- length_cm(x$box.padding)
+ label.padding <- length_cm(x$label.padding)
+
+ # Input point diameter is assumed to be in mm
+ # We convert to radius in centimetres, by dividing by 20
+ # `.pt / .stroke` ~= 0.75 accounts for a historical error in ggplot2
+ point.size <- x$data$point.size
+ point.size[is.na(point.size)] <- 0
+ point.size <- point.size * .pt / .stroke / 20
# The padding around each point.
- if (is.na(x$point.padding)) {
- x$point.padding = unit(0, "lines")
- }
+ point.padding <- length_cm(x$point.padding)
+ point.padding[is.na(point.padding)] <- 0
+
+ min.segment.length <- length_cm(x$min.segment.length)
# Do not create text labels for empty strings.
valid_strings <- which(not_empty(x$lab))
@@ -232,8 +248,8 @@ makeContent.labelrepeltree <- function(x) {
row <- x$data[i, , drop = FALSE]
t <- textGrob(
x$lab[i],
- unit(row$x, "native") + x$label.padding,
- unit(row$y, "native") + x$label.padding,
+ unit(row$x + label.padding, "cm"),
+ unit(row$y + label.padding, "cm"),
gp = gpar(
fontsize = row$size * .pt,
fontfamily = row$family,
@@ -243,20 +259,20 @@ makeContent.labelrepeltree <- function(x) {
name = "text"
)
r <- roundrectGrob(
- row$x, row$y, default.units = "native",
- width = grobWidth(t) + 2 * x$label.padding,
- height = grobHeight(t) + 2 * x$label.padding,
+ unit(row$x, "cm"), unit(row$y, "cm"),
+ width = grobWidth(t) + unit(2 * label.padding, "cm"),
+ height = grobHeight(t) + unit(2 * label.padding, "cm"),
r = x$label.r,
gp = gpar(lwd = x$label.size * .pt),
name = "box"
)
- gw <- convertWidth(grobWidth(r), "native", TRUE)
- gh <- convertHeight(grobHeight(r), "native", TRUE)
+ gw <- width_cm(grobWidth(r))
+ gh <- height_cm(grobHeight(r))
c(
- "x1" = row$x - gw * row$hjust - box_padding_x + row$nudge_x,
- "y1" = row$y - gh * row$vjust - box_padding_y + row$nudge_y,
- "x2" = row$x + gw * (1 - row$hjust) + box_padding_x + row$nudge_x,
- "y2" = row$y + gh * (1 - row$vjust) + box_padding_y + row$nudge_y
+ "x1" = row$x - gw * row$hjust - box.padding + row$nudge_x * width,
+ "y1" = row$y - gh * row$vjust - box.padding + row$nudge_y * height,
+ "x2" = row$x + gw * (1 - row$hjust) + box.padding + row$nudge_x * width,
+ "y2" = row$y + gh * (1 - row$vjust) + box.padding + row$nudge_y * height
)
})
@@ -265,33 +281,15 @@ makeContent.labelrepeltree <- function(x) {
x$seed <- sample.int(.Machine$integer.max, 1L)
}
- # The points are represented by circles.
- x$data$point.size[is.na(x$data$point.size)] <- 0
-
- # Beware the magic numbers. I do not understand them.
- # I just accept them as necessary to get the code to work.
- p_width <- convertWidth(unit(1, "npc"), "inch", TRUE)
- p_height <- convertHeight(unit(1, "npc"), "inch", TRUE)
- p_ratio <- (p_width / p_height)
- if (p_ratio > 1) {
- p_ratio <- p_ratio ^ (1 / (1.15 * p_ratio))
- }
- point_size <- p_ratio * convertWidth(
- to_unit(x$data$point.size), "native", valueOnly = TRUE
- ) / 13
- point_padding <- p_ratio * convertWidth(
- to_unit(x$point.padding), "native", valueOnly = TRUE
- ) / 13
-
# Repel overlapping bounding boxes away from each other.
repel <- with_seed_null(x$seed, repel_boxes2(
data_points = as.matrix(x$data[,c("x","y")]),
- point_size = point_size,
- point_padding_x = point_padding,
- point_padding_y = point_padding,
+ point_size = point.size,
+ point_padding_x = point.padding,
+ point_padding_y = point.padding,
boxes = do.call(rbind, boxes),
- xlim = range(x$limits$x),
- ylim = range(x$limits$y),
+ xlim = c(0, width),
+ ylim = c(0, height),
hjust = x$data$hjust %||% 0.5,
vjust = x$data$vjust %||% 0.5,
force_push = x$force * 1e-6,
@@ -325,18 +323,18 @@ makeContent.labelrepeltree <- function(x) {
i,
x$lab[i],
# Position of text bounding boxes.
- x = unit(repel$x[i], "native"),
- y = unit(repel$y[i], "native"),
+ x = repel$x[i],
+ y = repel$y[i],
# Position of original data points.
x.orig = row$x,
y.orig = row$y,
# Width and height of text boxes.
- box.width = boxes[[i]]["x2"] - boxes[[i]]["x1"],
+ box.width = boxes[[i]]["x2"] - boxes[[i]]["x1"],
box.height = boxes[[i]]["y2"] - boxes[[i]]["y1"],
- box.padding = x$box.padding,
- label.padding = x$label.padding,
- point.size = point_size[i],
- point.padding = x$point.padding,
+ box.padding = box.padding,
+ label.padding = label.padding,
+ point.size = point.size[i],
+ point.padding = point.padding,
segment.curvature = row$segment.curvature,
segment.angle = row$segment.angle,
segment.ncp = row$segment.ncp,
@@ -364,7 +362,7 @@ makeContent.labelrepeltree <- function(x) {
lty = row$segment.linetype %||% 1
),
arrow = x$arrow,
- min.segment.length = x$min.segment.length,
+ min.segment.length = min.segment.length,
hjust = row$hjust,
vjust = row$vjust
)
@@ -386,15 +384,14 @@ makeContent.labelrepeltree <- function(x) {
makeLabelRepelGrobs <- function(
i,
label,
- x = unit(0.5, "npc"),
- y = unit(0.5, "npc"),
+ x = 0.5,
+ y = 0.5,
# Position of original data points.
x.orig = 0.5,
y.orig = 0.5,
# Width and height of text boxes.
box.width = 0,
box.height = 0,
- default.units = "npc",
box.padding = 0.25,
label.padding = 0.25,
point.size = 1,
@@ -420,41 +417,36 @@ makeLabelRepelGrobs <- function(
) {
stopifnot(length(label) == 1)
- if (!is.unit(x))
- x <- unit(x, default.units)
- if (!is.unit(y))
- y <- unit(y, default.units)
- if (!is.unit(box.width))
- box.width <- unit(box.width, default.units)
- if (!is.unit(box.height))
- box.height <- unit(box.height, default.units)
-
t <- textGrob(
label,
- x - box.width * (0.5 - hjust),
+ x - box.width * (0.5 - hjust),
y - box.height * (0.5 - vjust),
hjust = hjust,
vjust = vjust,
gp = text.gp,
+ default.units = "cm",
name = sprintf("textrepelgrob%s", i)
)
r <- roundrectGrob(
- x - box.width * (0.5 - hjust) - label.padding * (0.5 - hjust),
+ x - box.width * (0.5 - hjust) - label.padding * (0.5 - hjust),
y - box.height * (0.5 - vjust) - label.padding * (0.5 - vjust),
- default.units = "native",
- width = grobWidth(t) + 2 * label.padding,
- height = grobHeight(t) + 2 * label.padding,
+ default.units = "cm",
+ width = grobWidth(t) + unit(2 * label.padding, "cm"),
+ height = grobHeight(t) + unit(2 * label.padding, "cm"),
just = c(hjust, vjust),
r = r,
gp = rect.gp,
name = sprintf("rectrepelgrob%s", i)
)
- x1 <- convertWidth(x - 0.5 * grobWidth(r), "native", TRUE)
- x2 <- convertWidth(x + 0.5 * grobWidth(r), "native", TRUE)
- y1 <- convertHeight(y - 0.5 * grobHeight(r), "native", TRUE)
- y2 <- convertHeight(y + 0.5 * grobHeight(r), "native", TRUE)
+ gw <- width_cm(grobWidth(r))
+ gh <- height_cm(grobHeight(r))
+
+ x1 <- x - 0.5 * gw
+ x2 <- x + 0.5 * gw
+ y1 <- y - 0.5 * gh
+ y2 <- y + 0.5 * gh
point_pos <- c(x.orig, y.orig)
@@ -472,8 +464,6 @@ makeLabelRepelGrobs <- function(
}
# This seems just fine.
- point.padding <- convertWidth(to_unit(point.padding), "native", TRUE) / 2
-
point_int <- intersect_line_circle(int, point_pos, (point.size + point.padding))
# Compute the distance between the data point and the edge of the text box.
@@ -483,9 +473,8 @@ makeLabelRepelGrobs <- function(
# Scale the unit vector by the minimum segment length.
if (d > 0) {
- mx <- convertWidth(min.segment.length, "native", TRUE)
- my <- convertHeight(min.segment.length, "native", TRUE)
- min.segment.length <- sqrt((mx * dx / d) ^ 2 + (my * dy / d) ^ 2)
+ m <- min.segment.length * c(dx, dy) / d
+ min.segment.length <- sqrt(m[1]^2 + m[2]^2)
}
grobs <- list(textbox = list(rect = r, text = t))
@@ -507,7 +496,7 @@ makeLabelRepelGrobs <- function(
y1 = int[2],
x2 = point_int[1],
y2 = point_int[2],
- default.units = "native",
+ default.units = "cm",
curvature = segment.curvature,
angle = segment.angle,
ncp = segment.ncp,
diff --git a/R/geom-text-repel.R b/R/geom-text-repel.R
index 138dc3e..504aeb4 100644
--- a/R/geom-text-repel.R
+++ b/R/geom-text-repel.R
@@ -357,14 +357,29 @@ GeomTextRepel <- ggproto("GeomTextRepel", Geom,
#' @noRd
makeContent.textrepeltree <- function(x) {
+ # Absolute viewport size
+ width <- width_cm( unit(1, "npc"))
+ height <- height_cm(unit(1, "npc"))
+
+ # Translate points to cm (assumed to be 0-1 range native at first)
+ x$data$x <- x$data$x * width
+ x$data$y <- x$data$y * height
+
# The padding around each bounding box.
- box_padding_x <- convertWidth(x$box.padding, "native", valueOnly = TRUE)
- box_padding_y <- convertHeight(x$box.padding, "native", valueOnly = TRUE)
+ box.padding <- length_cm(x$box.padding)
+
+ # Input point diameter is assumed to be in mm
+ # We convert to radius in centimetres, by dividing by 20
+ # `.pt / .stroke` ~= 0.75 accounts for a historical error in ggplot2
+ point.size <- x$data$point.size
+ point.size[is.na(point.size)] <- 0
+ point.size <- point.size * .pt / .stroke / 20
# The padding around each point.
- if (is.na(x$point.padding)) {
- x$point.padding = unit(0, "lines")
- }
+ point.padding <- length_cm(x$point.padding)
+ point.padding[is.na(point.padding)] <- 0
+
+ min.segment.length <- length_cm(x$min.segment.length)
# Do not create text labels for empty strings.
valid_strings <- which(not_empty(x$lab))
@@ -378,7 +393,7 @@ makeContent.textrepeltree <- function(x) {
row <- x$data[i, , drop = FALSE]
tg <- textGrob(
x$lab[i],
- row$x, row$y, default.units = "native",
+ row$x, row$y, default.units = "cm",
rot = row$angle,
hjust = row$hjust,
vjust = row$vjust,
@@ -389,15 +404,15 @@ makeContent.textrepeltree <- function(x) {
lineheight = row$lineheight
)
)
- x1 <- convertWidth(grobX(tg, "west"), "native", TRUE)
- x2 <- convertWidth(grobX(tg, "east"), "native", TRUE)
- y1 <- convertHeight(grobY(tg, "south"), "native", TRUE)
- y2 <- convertHeight(grobY(tg, "north"), "native", TRUE)
+ x1 <- x_cm(grobX(tg, "west"))
+ x2 <- x_cm(grobX(tg, "east"))
+ y1 <- y_cm(grobY(tg, "south"))
+ y2 <- y_cm(grobY(tg, "north"))
c(
- "x1" = x1 - box_padding_x + row$nudge_x,
- "y1" = y1 - box_padding_y + row$nudge_y,
- "x2" = x2 + box_padding_x + row$nudge_x,
- "y2" = y2 + box_padding_y + row$nudge_y
+ "x1" = x1 - box.padding + row$nudge_x * width,
+ "y1" = y1 - box.padding + row$nudge_y * height,
+ "x2" = x2 + box.padding + row$nudge_x * width,
+ "y2" = y2 + box.padding + row$nudge_y * height
)
})
@@ -406,33 +421,15 @@ makeContent.textrepeltree <- function(x) {
x$seed <- sample.int(.Machine$integer.max, 1L)
}
- # The points are represented by circles.
- x$data$point.size[is.na(x$data$point.size)] <- 0
-
- # Beware the magic numbers. I do not understand them.
- # I just accept them as necessary to get the code to work.
- p_width <- convertWidth(unit(1, "npc"), "inch", TRUE)
- p_height <- convertHeight(unit(1, "npc"), "inch", TRUE)
- p_ratio <- (p_width / p_height)
- if (p_ratio > 1) {
- p_ratio <- p_ratio ^ (1 / (1.15 * p_ratio))
- }
- point_size <- p_ratio * convertWidth(
- to_unit(x$data$point.size), "native", valueOnly = TRUE
- ) / 13
- point_padding <- p_ratio * convertWidth(
- to_unit(x$point.padding), "native", valueOnly = TRUE
- ) / 13
-
# Repel overlapping bounding boxes away from each other.
repel <- with_seed_null(x$seed, repel_boxes2(
data_points = as.matrix(x$data[,c("x","y")]),
- point_size = point_size,
- point_padding_x = point_padding,
- point_padding_y = point_padding,
+ point_size = point.size,
+ point_padding_x = point.padding,
+ point_padding_y = point.padding,
boxes = do.call(rbind, boxes),
- xlim = range(x$limits$x),
- ylim = range(x$limits$y),
+ xlim = c(0, width),
+ ylim = c(0, height),
hjust = x$data$hjust %||% 0.5,
vjust = x$data$vjust %||% 0.5,
force_push = x$force * 1e-6,
@@ -466,15 +463,15 @@ makeContent.textrepeltree <- function(x) {
i,
x$lab[i],
# Position of text bounding boxes.
- x = unit(repel$x[i], "native"),
- y = unit(repel$y[i], "native"),
+ x = repel$x[i],
+ y = repel$y[i],
# Position of original data points.
x.orig = row$x,
y.orig = row$y,
rot = row$angle,
- box.padding = x$box.padding,
- point.size = point_size[i],
- point.padding = x$point.padding,
+ box.padding = box.padding,
+ point.size = point.size[i],
+ point.padding = point.padding,
segment.curvature = row$segment.curvature,
segment.angle = row$segment.angle,
segment.ncp = row$segment.ncp,
@@ -496,7 +493,7 @@ makeContent.textrepeltree <- function(x) {
lty = row$segment.linetype %||% 1
),
arrow = x$arrow,
- min.segment.length = x$min.segment.length,
+ min.segment.length = min.segment.length,
hjust = row$hjust,
vjust = row$vjust,
bg.colour = alpha(row$bg.colour, row$alpha),
@@ -519,8 +516,8 @@ makeTextRepelGrobs <- function(
i,
label,
# Position of text bounding boxes.
- x = unit(0.5, "npc"),
- y = unit(0.5, "npc"),
+ x = 0.5,
+ y = 0.5,
# Position of original data points.
x.orig = NULL,
y.orig = NULL,
@@ -550,11 +547,6 @@ makeTextRepelGrobs <- function(
) {
stopifnot(length(label) == 1)
- if (!is.unit(x))
- x <- unit(x, default.units)
- if (!is.unit(y))
- y <- unit(y, default.units)
-
# support any angle by converting to -360..360
rot <- rot %% 360
@@ -563,22 +555,21 @@ makeTextRepelGrobs <- function(
# a textGrob built with rot = 0.
# To support rotation height and width need to be expressed in units that
# are consistent on x and y axes, such as "char".
- string.height <- convertHeight(stringHeight(label), "char")
- string.width <- convertWidth(stringWidth(label), "char")
+ string.size <- string_cm(label, text.gp)
rot_radians <- rot * pi / 180
- x_adj <- x - cos(rot_radians) * string.width * (0.5 - hjust) +
- sin(rot_radians) * string.height * (0.5 - vjust)
- y_adj <- y - cos(rot_radians) * string.height * (0.5 - vjust) -
- sin(rot_radians) * string.width * (0.5 - hjust)
+ x_adj <- x - cos(rot_radians) * string.size[1] * (0.5 - hjust) +
+ sin(rot_radians) * string.size[2] * (0.5 - vjust)
+ y_adj <- y - cos(rot_radians) * string.size[2] * (0.5 - vjust) -
+ sin(rot_radians) * string.size[1] * (0.5 - hjust)
grobs <- shadowtextGrob(
label = label,
x = x_adj,
y = y_adj,
rot = rot,
- default.units = "native",
+ default.units = "cm",
hjust = hjust,
vjust = vjust,
gp = text.gp,
@@ -589,20 +580,19 @@ makeTextRepelGrobs <- function(
# the regular textgrob will always be the last one
tg <- grobs[[length(grobs)]]
- x1 <- convertWidth(grobX(tg, "west"), "native", TRUE)
- x2 <- convertWidth(grobX(tg, "east"), "native", TRUE)
- y1 <- convertHeight(grobY(tg, "south"), "native", TRUE)
- y2 <- convertHeight(grobY(tg, "north"), "native", TRUE)
+ x1 <- x_cm(grobX(tg, "west"))
+ x2 <- x_cm(grobX(tg, "east"))
+ y1 <- y_cm(grobY(tg, "south"))
+ y2 <- y_cm(grobY(tg, "north"))
point_pos <- c(x.orig, y.orig)
# Get the coordinates of the intersection between the line from the
# original data point to the centroid and the rectangle's edges.
- extra_padding_x <- convertWidth(unit(0.25, "lines"), "native", TRUE) / 2
- extra_padding_y <- convertHeight(unit(0.25, "lines"), "native", TRUE) / 2
+ extra_padding <- length_cm(unit(0.125, "lines"))
text_box <- c(
- x1 - extra_padding_x, y1 - extra_padding_y,
- x2 + extra_padding_x, y2 + extra_padding_y
+ x1 - extra_padding, y1 - extra_padding,
+ x2 + extra_padding, y2 + extra_padding
)
#int <- intersect_line_rectangle(point_pos, center, text_box)
int <- select_line_connection(point_pos, text_box)
@@ -615,20 +605,17 @@ makeTextRepelGrobs <- function(
}
# This seems just fine.
- point.padding <- convertWidth(to_unit(point.padding), "native", TRUE) / 2
-
point_int <- intersect_line_circle(int, point_pos, (point.size + point.padding))
# Compute the distance between the data point and the edge of the text box.
dx <- abs(int[1] - point_int[1])
dy <- abs(int[2] - point_int[2])
- d <- sqrt(dx * dx + dy * dy)
+ d <- sqrt(dx * dx + dy * dy)
# Scale the unit vector by the minimum segment length.
if (d > 0) {
- mx <- convertWidth(min.segment.length, "native", TRUE)
- my <- convertHeight(min.segment.length, "native", TRUE)
- min.segment.length <- sqrt((mx * dx / d) ^ 2 + (my * dy / d) ^ 2)
+ m <- min.segment.length * c(dx, dy) / d
+ min.segment.length <- sqrt(m[1]^2 + m[2]^2)
}
if (
@@ -648,7 +635,7 @@ makeTextRepelGrobs <- function(
y1 = int[2],
x2 = point_int[1],
y2 = point_int[2],
- default.units = "native",
+ default.units = "cm",
curvature = segment.curvature,
angle = segment.angle,
ncp = segment.ncp,
diff --git a/R/ggrepel-package.R b/R/ggrepel-package.R
index e8b29f0..d8ff6c7 100644
--- a/R/ggrepel-package.R
+++ b/R/ggrepel-package.R
@@ -22,6 +22,9 @@
#' @import ggplot2
#' @import Rcpp
#' @importFrom grid
+#' convertUnit
+#' convertX
+#' convertY
#' convertHeight
#' convertWidth
#' gList
@@ -46,6 +49,9 @@
#' curveGrob
#' setChildren
#' textGrob
+#' viewport
+#' pushViewport
+#' popViewport
#' @importFrom rlang
#' warn
#' @useDynLib ggrepel
diff --git a/R/utilities.R b/R/utilities.R
index 78a0a7c..72e8779 100644
--- a/R/utilities.R
+++ b/R/utilities.R
@@ -99,3 +99,20 @@ exclude_outside <- function(data, panel_scales) {
inside <- function(x, bounds) {
is.infinite(x) | (x <= bounds[2] & x >= bounds[1])
}
+
+# Utilities for converting units to centimetres
+x_cm <- function(x) convertX(x, "cm", valueOnly = TRUE)
+y_cm <- function(x) convertY(x, "cm", valueOnly = TRUE)
+width_cm <- function(x) convertWidth(x, "cm", valueOnly = TRUE)
+height_cm <- function(x) convertHeight(x, "cm", valueOnly = TRUE)
+length_cm <- function(x) {
+ convertUnit(x, "cm", typeFrom = "dimension", valueOnly = TRUE)
+}
+
+# Need to set a viewport with the correct graphical parameters to correctly
+# convert the size to centimetres
+string_cm <- function(x, gp) {
+ pushViewport(viewport(gp = gp))
+ on.exit(popViewport())
+ cbind(width = width_cm(stringWidth(x)), height = height_cm(stringHeight(x)))
+}
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-center-0.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-center-0.svg
index 7bb6ff5..aa8e8fb 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-center-0.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-center-0.svg
@@ -39,7 +39,7 @@
Hornet Sportabout
Merc 230
Merc 450SL
-Chrysler Imperial
+Chrysler Imperial
Toyota Corona
Pontiac Firebird
Ford Pantera L
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-center-180.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-center-180.svg
index 17cd580..84590b1 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-center-180.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-center-180.svg
@@ -39,9 +39,9 @@
Hornet Sportabout
Merc 230
Merc 450SL
-Chrysler Imperial
+Chrysler Imperial
Toyota Corona
-Pontiac Firebird
+Pontiac Firebird
Ford Pantera L
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-inward-0.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-inward-0.svg
index ea16c4b..fe4c928 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-inward-0.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-inward-0.svg
@@ -39,7 +39,7 @@
Hornet Sportabout
Merc 230
Merc 450SL
-Chrysler Imperial
+Chrysler Imperial
Toyota Corona
Pontiac Firebird
Ford Pantera L
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-inward-180.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-inward-180.svg
index 6f6e822..c1d2e2e 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-inward-180.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-inward-180.svg
@@ -39,7 +39,7 @@
Hornet Sportabout
Merc 230
Merc 450SL
-Chrysler Imperial
+Chrysler Imperial
Toyota Corona
Pontiac Firebird
Ford Pantera L
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-0.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-0.svg
index 60cb587..e5ca675 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-0.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-0.svg
@@ -36,15 +36,15 @@
Mazda
-RX4
+RX4
Hornet
Sportabout
Merc
230
-Merc
+Merc
450SL
-Chrysler
-Imperial
+Chrysler
+Imperial
Toyota
Corona
Pontiac
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-180.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-180.svg
index 48c52f3..14affb7 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-180.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-180.svg
@@ -36,15 +36,15 @@
Mazda
-RX4
+RX4
Hornet
Sportabout
Merc
230
Merc
450SL
-Chrysler
-Imperial
+Chrysler
+Imperial
Toyota
Corona
Pontiac
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-90.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-90.svg
index 6d25529..a212be1 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-90.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-multiline-90.svg
@@ -35,8 +35,8 @@
-Mazda
-RX4
+Mazda
+RX4
Hornet
Sportabout
Merc
@@ -44,7 +44,7 @@
Merc
450SL
Chrysler
-Imperial
+Imperial
Toyota
Corona
Pontiac
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-0.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-0.svg
index c7078bb..1c8c87d 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-0.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-0.svg
@@ -38,8 +38,8 @@
Mazda RX4
Hornet Sportabout
Merc 230
-Merc 450SL
-Chrysler Imperial
+Merc 450SL
+Chrysler Imperial
Toyota Corona
Pontiac Firebird
Ford Pantera L
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-180.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-180.svg
index 623fffe..00c6064 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-180.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-180.svg
@@ -39,7 +39,7 @@
Hornet Sportabout
Merc 230
Merc 450SL
-Chrysler Imperial
+Chrysler Imperial
Toyota Corona
Pontiac Firebird
Ford Pantera L
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-90.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-90.svg
index 6dc2606..68e1242 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-90.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-outward-90.svg
@@ -38,8 +38,8 @@
Mazda RX4
Hornet Sportabout
Merc 230
-Merc 450SL
-Chrysler Imperial
+Merc 450SL
+Chrysler Imperial
Toyota Corona
Pontiac Firebird
Ford Pantera L
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-0.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-0.svg
index 477d4f7..f47f01e 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-0.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-0.svg
@@ -39,7 +39,7 @@
Hornet Sportabout
Merc 230
Merc 450SL
-Chrysler Imperial
+Chrysler Imperial
Toyota Corona
Pontiac Firebird
Ford Pantera L
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-180.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-180.svg
index 335c8a7..9093397 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-180.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-180.svg
@@ -39,7 +39,7 @@
Hornet Sportabout
Merc 230
Merc 450SL
-Chrysler Imperial
+Chrysler Imperial
Toyota Corona
Pontiac Firebird
Ford Pantera L
diff --git a/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-90.svg b/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-90.svg
index b4574f3..eabf8de 100644
--- a/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-90.svg
+++ b/tests/testthat/_snaps/just-with-angle/geom-text-repel-zero-one-90.svg
@@ -39,7 +39,7 @@
Hornet Sportabout
Merc 230
Merc 450SL
-Chrysler Imperial
+Chrysler Imperial
Toyota Corona
Pontiac Firebird
Ford Pantera L
diff --git a/tests/testthat/test-grob-order.R b/tests/testthat/test-grob-order.R
index 233f406..bbdaf31 100644
--- a/tests/testthat/test-grob-order.R
+++ b/tests/testthat/test-grob-order.R
@@ -11,7 +11,7 @@ test_that("for geom_text_repel, all segment grobs come before text grobs", {
# Make a plot with no seed and get the label positions.
png_file <- withr::local_tempfile(pattern = "testthat_test-grob-order1")
png(png_file)
- p1 <- ggplot(dat1) + geom_text_repel(aes(wt, mpg, label = label))
+ p1 <- ggplot(dat1) + geom_text_repel(aes(wt, mpg, label = label), min.segment.length = 0)
print(p1)
grid.force()
grobnames <- names(grid.get(
@@ -33,7 +33,7 @@ test_that("for geom_label_repel, all rect grobs come before text grobs", {
# Make a plot with no seed and get the label positions.
png_file <- withr::local_tempfile(pattern = "testthat_test-grob-order1")
png(png_file)
- p1 <- ggplot(dat1) + geom_label_repel(aes(wt, mpg, label = label), max.overlaps = Inf)
+ p1 <- ggplot(dat1) + geom_label_repel(aes(wt, mpg, label = label), max.overlaps = Inf, min.segment.length = 0)
print(p1)
grid.force()
grobnames <- names(grid.get(