diff --git a/DESCRIPTION b/DESCRIPTION
index 4e0268275f..a44b1740ad 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -65,7 +65,6 @@ Suggests:
webshot,
listviewer,
dendextend,
- sf,
maptools,
rgeos,
png,
diff --git a/NEWS.md b/NEWS.md
index ff0a9df5a7..0d8ed408a7 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -8,6 +8,10 @@
* `ggplotly()` now uses the `layout.legend.title` (instead of `layout.annotations`) plotly.js API to convert guides for discrete scales. (#1961)
+## Improvements
+
+* `ggplotly()` now better positions axis titles for `facet_wrap()`/`facet_grid()`. (#1975)
+
# 4.9.4.1
## BUG FIXES
diff --git a/R/ggplotly.R b/R/ggplotly.R
index e984373e03..e29dd2b907 100644
--- a/R/ggplotly.R
+++ b/R/ggplotly.R
@@ -833,11 +833,12 @@ gg2list <- function(p, width = NULL, height = NULL,
gglayout[[axisName]] <- axisObj
# do some stuff that should be done once for the entire plot
+ is_x <- xy == "x"
if (i == 1) {
# Split ticktext elements by "\n" to account for linebreaks
axisTickText <- strsplit(as.character(axisObj$ticktext), split = "\n", fixed = TRUE)
axisTickText <- longest_element(unlist(axisTickText))
- side <- if (xy == "x") "b" else "l"
+ side <- if (is_x) "b" else "l"
# account for axis ticks, ticks text, and titles in plot margins
# (apparently ggplot2 doesn't support axis.title/axis.text margins)
gglayout$margin[[side]] <- gglayout$margin[[side]] + axisObj$ticklen +
@@ -847,40 +848,45 @@ gg2list <- function(p, width = NULL, height = NULL,
if (robust_nchar(axisTitleText) > 0) {
axisTextSize <- unitConvert(axisText, "npc", type)
axisTitleSize <- unitConvert(axisTitle, "npc", type)
- offset <-
- (0 -
- bbox(axisTickText, axisText$angle, axisTextSize)[[type]] -
- bbox(axisTitleText, axisTitle$angle, axisTitleSize)[[type]] / 2 -
- unitConvert(theme$axis.ticks.length, "npc", type))
}
# add space for exterior facet strips in `layout.margin`
if (has_facet(plot)) {
stripSize <- unitConvert(stripText, "pixels", type)
- if (xy == "x") {
+ if (is_x) {
gglayout$margin$t <- gglayout$margin$t + stripSize
}
- if (xy == "y" && inherits(plot$facet, "FacetGrid")) {
+ if (is_x && inherits(plot$facet, "FacetGrid")) {
gglayout$margin$r <- gglayout$margin$r + stripSize
}
# facets have multiple axis objects, but only one title for the plot,
# so we empty the titles and try to draw the title as an annotation
if (robust_nchar(axisTitleText) > 0) {
- # npc is on a 0-1 scale of the _entire_ device,
- # but these units _should_ be wrt to the plotting region
- # multiplying the offset by 2 seems to work, but this is a terrible hack
- x <- if (xy == "x") 0.5 else offset
- y <- if (xy == "x") offset else 0.5
- gglayout$annotations <- c(
- gglayout$annotations,
- make_label(
- faced(axisTitleText, axisTitle$face), x, y, el = axisTitle,
- xanchor = if (xy == "x") "center" else "right",
- yanchor = if (xy == "x") "top" else "center",
- annotationType = "axis"
- )
+ axisAnn <- make_label(
+ faced(axisTitleText, axisTitle$face),
+ el = axisTitle,
+ x = if (is_x) 0.5 else 0,
+ y = if (is_x) 0 else 0.5,
+ xanchor = if (is_x) "center" else "right",
+ yanchor = if (is_x) "top" else "center",
+ annotationType = "axis"
)
+
+ textMargin <- sum(axisText$margin[if (is_x) c(1, 3) else c(2, 4)])
+ class(textMargin) <- setdiff(class(textMargin), "margin")
+ titleMargin <- axisTitle$margin[if (is_x) 1 else 2]
+ class(titleMargin) <- setdiff(class(titleMargin), "margin")
+ offset <- bbox(axisTickText, axisText$angle, axisTextSize)[[type]] +
+ unitConvert(theme$axis.ticks.length, "npc", type) +
+ unitConvert(textMargin, "npc", type) +
+ unitConvert(titleMargin, "npc", type)
+
+ offset <- unitConvert(grid::unit(offset, "npc"), "pixels", type)
+
+ shift <- if (is_x) "yshift" else "xshift"
+ axisAnn[[1]][[shift]] <- -1 * offset
+ gglayout$annotations <- c(gglayout$annotations, axisAnn)
}
}
}
diff --git a/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet-hline-vline.svg b/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet-hline-vline.svg
index 6d95bf1dc5..fcefe8f84a 100644
--- a/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet-hline-vline.svg
+++ b/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet-hline-vline.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet-hline.svg b/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet-hline.svg
index e26cad3c1f..2251a09ed8 100644
--- a/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet-hline.svg
+++ b/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet-hline.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet.svg b/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet.svg
index f8a552ac7a..69ab22f532 100644
--- a/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet.svg
+++ b/tests/testthat/_snaps/cookbook-lines/cookbook-axes-scatter-facet.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-facets/3-panels.svg b/tests/testthat/_snaps/ggplot-facets/3-panels.svg
index 15805b8593..641300c8cb 100644
--- a/tests/testthat/_snaps/ggplot-facets/3-panels.svg
+++ b/tests/testthat/_snaps/ggplot-facets/3-panels.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-facets/barley.svg b/tests/testthat/_snaps/ggplot-facets/barley.svg
index c0b3689be2..145e0fab63 100644
--- a/tests/testthat/_snaps/ggplot-facets/barley.svg
+++ b/tests/testthat/_snaps/ggplot-facets/barley.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-facets/facet-grid-free-y.svg b/tests/testthat/_snaps/ggplot-facets/facet-grid-free-y.svg
index 15255df1e5..ba7953beea 100644
--- a/tests/testthat/_snaps/ggplot-facets/facet-grid-free-y.svg
+++ b/tests/testthat/_snaps/ggplot-facets/facet-grid-free-y.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-facets/facet-grid-free.svg b/tests/testthat/_snaps/ggplot-facets/facet-grid-free.svg
index 1fe7258da8..f27841664e 100644
--- a/tests/testthat/_snaps/ggplot-facets/facet-grid-free.svg
+++ b/tests/testthat/_snaps/ggplot-facets/facet-grid-free.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-facets/facet-wrap-free-x.svg b/tests/testthat/_snaps/ggplot-facets/facet-wrap-free-x.svg
index 1029c4981d..d78ecf7397 100644
--- a/tests/testthat/_snaps/ggplot-facets/facet-wrap-free-x.svg
+++ b/tests/testthat/_snaps/ggplot-facets/facet-wrap-free-x.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-facets/facet-wrap-free-y.svg b/tests/testthat/_snaps/ggplot-facets/facet-wrap-free-y.svg
index 47a8f23c04..9a31c01a26 100644
--- a/tests/testthat/_snaps/ggplot-facets/facet-wrap-free-y.svg
+++ b/tests/testthat/_snaps/ggplot-facets/facet-wrap-free-y.svg
@@ -1 +1 @@
-
+
diff --git a/tests/testthat/_snaps/ggplot-facets/facet-wrap-free.svg b/tests/testthat/_snaps/ggplot-facets/facet-wrap-free.svg
index 97d0ba917b..0e3af757f7 100644
--- a/tests/testthat/_snaps/ggplot-facets/facet-wrap-free.svg
+++ b/tests/testthat/_snaps/ggplot-facets/facet-wrap-free.svg
@@ -1 +1 @@
-
+