Skip to content

Commit 24ffe8f

Browse files
authored
Merge pull request #1773 from dmurdoch/master
ggplotly() failed when labels or title were a factor, because nchar()…
2 parents c5beddf + 5b2ee0f commit 24ffe8f

File tree

3 files changed

+41
-12
lines changed

3 files changed

+41
-12
lines changed

R/ggplotly.R

+12-12
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ ggplotly.ggmatrix <- function(p = ggplot2::last_plot(), width = NULL,
127127
titleY = TRUE, titleX = TRUE) %>%
128128
hide_legend() %>%
129129
layout(dragmode = "select")
130-
if (nchar(p$title %||% "") > 0) {
130+
if (robust_nchar(p$title %||% "") > 0) {
131131
s <- layout(s, title = p$title)
132132
}
133133
for (i in seq_along(p$xAxisLabels)) {
@@ -436,7 +436,7 @@ gg2list <- function(p, width = NULL, height = NULL,
436436
font = text2font(theme$text)
437437
)
438438
# main plot title
439-
if (nchar(plot$labels$title %||% "") > 0) {
439+
if (robust_nchar(plot$labels$title %||% "") > 0) {
440440
gglayout$title <- list(
441441
text = faced(plot$labels$title, theme$plot.title$face),
442442
font = text2font(theme$plot.title),
@@ -567,7 +567,7 @@ gg2list <- function(p, width = NULL, height = NULL,
567567
# allocate enough space for the _longest_ text label
568568
axisTextX <- theme[["axis.text.x"]] %||% theme[["axis.text"]]
569569
labz <- unlist(lapply(layout$panel_params, function(pp) { pp[["x"]]$get_labels %()% pp$x.labels }))
570-
lab <- labz[which.max(nchar(labz))]
570+
lab <- longest_element(labz)
571571
panelMarginY <- panelMarginY + axisTicksX +
572572
bbox(lab, axisTextX$angle, unitConvert(axisTextX, "npc", "height"))[["height"]]
573573
}
@@ -579,7 +579,7 @@ gg2list <- function(p, width = NULL, height = NULL,
579579
# allocate enough space for the _longest_ text label
580580
axisTextY <- theme[["axis.text.y"]] %||% theme[["axis.text"]]
581581
labz <- unlist(lapply(layout$panel_params, function(pp) { pp[["y"]]$get_labels %()% pp$y.labels }))
582-
lab <- labz[which.max(nchar(labz))]
582+
lab <- longest_element(labz)
583583
panelMarginX <- panelMarginX + axisTicksY +
584584
bbox(lab, axisTextY$angle, unitConvert(axisTextY, "npc", "width"))[["width"]]
585585
}
@@ -806,15 +806,15 @@ gg2list <- function(p, width = NULL, height = NULL,
806806

807807
# do some stuff that should be done once for the entire plot
808808
if (i == 1) {
809-
axisTickText <- axisObj$ticktext[which.max(nchar(axisObj$ticktext))]
809+
axisTickText <- longest_element(axisObj$ticktext)
810810
side <- if (xy == "x") "b" else "l"
811811
# account for axis ticks, ticks text, and titles in plot margins
812812
# (apparently ggplot2 doesn't support axis.title/axis.text margins)
813813
gglayout$margin[[side]] <- gglayout$margin[[side]] + axisObj$ticklen +
814814
bbox(axisTickText, axisObj$tickangle, axisObj$tickfont$size)[[type]] +
815815
bbox(axisTitleText, axisTitle$angle, unitConvert(axisTitle, "pixels", type))[[type]]
816816

817-
if (nchar(axisTitleText) > 0) {
817+
if (robust_nchar(axisTitleText) > 0) {
818818
axisTextSize <- unitConvert(axisText, "npc", type)
819819
axisTitleSize <- unitConvert(axisTitle, "npc", type)
820820
offset <-
@@ -836,7 +836,7 @@ gg2list <- function(p, width = NULL, height = NULL,
836836
}
837837
# facets have multiple axis objects, but only one title for the plot,
838838
# so we empty the titles and try to draw the title as an annotation
839-
if (nchar(axisTitleText) > 0) {
839+
if (robust_nchar(axisTitleText) > 0) {
840840
# npc is on a 0-1 scale of the _entire_ device,
841841
# but these units _should_ be wrt to the plotting region
842842
# multiplying the offset by 2 seems to work, but this is a terrible hack
@@ -873,7 +873,7 @@ gg2list <- function(p, width = NULL, height = NULL,
873873
)
874874
if (is_blank(theme[["strip.text.x"]])) col_txt <- ""
875875
if (inherits(plot$facet, "FacetGrid") && lay$ROW != 1) col_txt <- ""
876-
if (nchar(col_txt) > 0) {
876+
if (robust_nchar(col_txt) > 0) {
877877
col_lab <- make_label(
878878
col_txt, x = mean(xdom), y = max(ydom),
879879
el = theme[["strip.text.x"]] %||% theme[["strip.text"]],
@@ -890,7 +890,7 @@ gg2list <- function(p, width = NULL, height = NULL,
890890
)
891891
if (is_blank(theme[["strip.text.y"]])) row_txt <- ""
892892
if (inherits(plot$facet, "FacetGrid") && lay$COL != nCols) row_txt <- ""
893-
if (nchar(row_txt) > 0) {
893+
if (robust_nchar(row_txt) > 0) {
894894
row_lab <- make_label(
895895
row_txt, x = max(xdom), y = mean(ydom),
896896
el = theme[["strip.text.y"]] %||% theme[["strip.text"]],
@@ -1180,7 +1180,7 @@ is_blank <- function(x) {
11801180
# given text, and x/y coordinates on 0-1 scale,
11811181
# convert ggplot2::element_text() to plotly annotation
11821182
make_label <- function(txt = "", x, y, el = ggplot2::element_text(), ...) {
1183-
if (is_blank(el) || is.null(txt) || nchar(txt) == 0 || length(txt) == 0) {
1183+
if (is_blank(el) || is.null(txt) || robust_nchar(txt) == 0 || length(txt) == 0) {
11841184
return(NULL)
11851185
}
11861186
angle <- el$angle %||% 0
@@ -1215,9 +1215,9 @@ has_facet <- function(x) {
12151215

12161216
bbox <- function(txt = "foo", angle = 0, size = 12) {
12171217
# assuming the horizontal size of a character is roughly half of the vertical
1218-
n <- nchar(txt)
1218+
n <- robust_nchar(txt)
12191219
if (sum(n) == 0) return(list(height = 0, width = 0))
1220-
w <- size * (nchar(txt) / 2)
1220+
w <- size * (robust_nchar(txt) / 2)
12211221
angle <- abs(angle %||% 0)
12221222
# do the sensible thing in the majority of cases
12231223
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)