Skip to content

Commit 5b2ee0f

Browse files
committed
Better naming, fix #1731 as well, add tests
1 parent 15aca2b commit 5b2ee0f

File tree

3 files changed

+41
-16
lines changed

3 files changed

+41
-16
lines changed

R/ggplotly.R

+12-16
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,6 @@ ggplotly.plotly <- function(p = ggplot2::last_plot(), width = NULL, height = NUL
8282
p
8383
}
8484

85-
# nchar() needs a character vector; sometimes x will be a
86-
# factor
87-
nchar0 <- function(x, ...) nchar(as.character(x), ...)
88-
8985
#' @export
9086
ggplotly.ggmatrix <- function(p = ggplot2::last_plot(), width = NULL,
9187
height = NULL, tooltip = "all", dynamicTicks = FALSE,
@@ -131,7 +127,7 @@ ggplotly.ggmatrix <- function(p = ggplot2::last_plot(), width = NULL,
131127
titleY = TRUE, titleX = TRUE) %>%
132128
hide_legend() %>%
133129
layout(dragmode = "select")
134-
if (nchar0(p$title %||% "") > 0) {
130+
if (robust_nchar(p$title %||% "") > 0) {
135131
s <- layout(s, title = p$title)
136132
}
137133
for (i in seq_along(p$xAxisLabels)) {
@@ -440,7 +436,7 @@ gg2list <- function(p, width = NULL, height = NULL,
440436
font = text2font(theme$text)
441437
)
442438
# main plot title
443-
if (nchar0(plot$labels$title %||% "") > 0) {
439+
if (robust_nchar(plot$labels$title %||% "") > 0) {
444440
gglayout$title <- list(
445441
text = faced(plot$labels$title, theme$plot.title$face),
446442
font = text2font(theme$plot.title),
@@ -571,7 +567,7 @@ gg2list <- function(p, width = NULL, height = NULL,
571567
# allocate enough space for the _longest_ text label
572568
axisTextX <- theme[["axis.text.x"]] %||% theme[["axis.text"]]
573569
labz <- unlist(lapply(layout$panel_params, function(pp) { pp[["x"]]$get_labels %()% pp$x.labels }))
574-
lab <- labz[which.max(nchar0(labz))]
570+
lab <- longest_element(labz)
575571
panelMarginY <- panelMarginY + axisTicksX +
576572
bbox(lab, axisTextX$angle, unitConvert(axisTextX, "npc", "height"))[["height"]]
577573
}
@@ -583,7 +579,7 @@ gg2list <- function(p, width = NULL, height = NULL,
583579
# allocate enough space for the _longest_ text label
584580
axisTextY <- theme[["axis.text.y"]] %||% theme[["axis.text"]]
585581
labz <- unlist(lapply(layout$panel_params, function(pp) { pp[["y"]]$get_labels %()% pp$y.labels }))
586-
lab <- labz[which.max(nchar0(labz))]
582+
lab <- longest_element(labz)
587583
panelMarginX <- panelMarginX + axisTicksY +
588584
bbox(lab, axisTextY$angle, unitConvert(axisTextY, "npc", "width"))[["width"]]
589585
}
@@ -810,15 +806,15 @@ gg2list <- function(p, width = NULL, height = NULL,
810806

811807
# do some stuff that should be done once for the entire plot
812808
if (i == 1) {
813-
axisTickText <- axisObj$ticktext[which.max(nchar0(axisObj$ticktext))]
809+
axisTickText <- longest_element(axisObj$ticktext)
814810
side <- if (xy == "x") "b" else "l"
815811
# account for axis ticks, ticks text, and titles in plot margins
816812
# (apparently ggplot2 doesn't support axis.title/axis.text margins)
817813
gglayout$margin[[side]] <- gglayout$margin[[side]] + axisObj$ticklen +
818814
bbox(axisTickText, axisObj$tickangle, axisObj$tickfont$size)[[type]] +
819815
bbox(axisTitleText, axisTitle$angle, unitConvert(axisTitle, "pixels", type))[[type]]
820816

821-
if (nchar0(axisTitleText) > 0) {
817+
if (robust_nchar(axisTitleText) > 0) {
822818
axisTextSize <- unitConvert(axisText, "npc", type)
823819
axisTitleSize <- unitConvert(axisTitle, "npc", type)
824820
offset <-
@@ -840,7 +836,7 @@ gg2list <- function(p, width = NULL, height = NULL,
840836
}
841837
# facets have multiple axis objects, but only one title for the plot,
842838
# so we empty the titles and try to draw the title as an annotation
843-
if (nchar0(axisTitleText) > 0) {
839+
if (robust_nchar(axisTitleText) > 0) {
844840
# npc is on a 0-1 scale of the _entire_ device,
845841
# but these units _should_ be wrt to the plotting region
846842
# multiplying the offset by 2 seems to work, but this is a terrible hack
@@ -877,7 +873,7 @@ gg2list <- function(p, width = NULL, height = NULL,
877873
)
878874
if (is_blank(theme[["strip.text.x"]])) col_txt <- ""
879875
if (inherits(plot$facet, "FacetGrid") && lay$ROW != 1) col_txt <- ""
880-
if (nchar0(col_txt) > 0) {
876+
if (robust_nchar(col_txt) > 0) {
881877
col_lab <- make_label(
882878
col_txt, x = mean(xdom), y = max(ydom),
883879
el = theme[["strip.text.x"]] %||% theme[["strip.text"]],
@@ -894,7 +890,7 @@ gg2list <- function(p, width = NULL, height = NULL,
894890
)
895891
if (is_blank(theme[["strip.text.y"]])) row_txt <- ""
896892
if (inherits(plot$facet, "FacetGrid") && lay$COL != nCols) row_txt <- ""
897-
if (nchar0(row_txt) > 0) {
893+
if (robust_nchar(row_txt) > 0) {
898894
row_lab <- make_label(
899895
row_txt, x = max(xdom), y = mean(ydom),
900896
el = theme[["strip.text.y"]] %||% theme[["strip.text"]],
@@ -1184,7 +1180,7 @@ is_blank <- function(x) {
11841180
# given text, and x/y coordinates on 0-1 scale,
11851181
# convert ggplot2::element_text() to plotly annotation
11861182
make_label <- function(txt = "", x, y, el = ggplot2::element_text(), ...) {
1187-
if (is_blank(el) || is.null(txt) || nchar0(txt) == 0 || length(txt) == 0) {
1183+
if (is_blank(el) || is.null(txt) || robust_nchar(txt) == 0 || length(txt) == 0) {
11881184
return(NULL)
11891185
}
11901186
angle <- el$angle %||% 0
@@ -1219,9 +1215,9 @@ has_facet <- function(x) {
12191215

12201216
bbox <- function(txt = "foo", angle = 0, size = 12) {
12211217
# assuming the horizontal size of a character is roughly half of the vertical
1222-
n <- nchar0(txt)
1218+
n <- robust_nchar(txt)
12231219
if (sum(n) == 0) return(list(height = 0, width = 0))
1224-
w <- size * (nchar0(txt) / 2)
1220+
w <- size * (robust_nchar(txt) / 2)
12251221
angle <- abs(angle %||% 0)
12261222
# do the sensible thing in the majority of cases
12271223
if (angle == 0) return(list(height = size, width = w))

R/utils.R

+15
Original file line numberDiff line numberDiff line change
@@ -1139,3 +1139,18 @@ try_library <- function(pkg, fun = NULL) {
11391139
is_rstudio <- function() {
11401140
identical(.Platform$GUI, "RStudio")
11411141
}
1142+
1143+
# nchar() needs a non-empty character vector; sometimes x will be a
1144+
# factor, or an empty vector.
1145+
robust_nchar <- function(x, ...) {
1146+
if (length(x)) nchar(as.character(x), ...)
1147+
else 0
1148+
}
1149+
1150+
# Extract longest element, or blank if none
1151+
longest_element <- function(x) {
1152+
if (length(x))
1153+
x[which.max(robust_nchar(x))]
1154+
else
1155+
""
1156+
}

tests/testthat/test-ggplot-labels.R

+14
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,17 @@ test_that("xaxis/yaxis automargin defaults to TRUE", {
4040
expect_true(l$layout$xaxis$automargin)
4141
expect_true(l$layout$yaxis$automargin)
4242
})
43+
44+
test_that("factor labels work", {
45+
p <- ggplot(diamonds, aes(cut)) +
46+
geom_bar() +
47+
scale_x_discrete("Cut", labels=factor(letters[1:5]))
48+
plotly_build(p)
49+
})
50+
51+
test_that("empty labels work", {
52+
p <- ggplot(iris, aes(Petal.Length, Sepal.Width, color = Species)) +
53+
geom_point() +
54+
xlab(element_blank())
55+
plotly_build(p)
56+
})

0 commit comments

Comments
 (0)