-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Clean up strip rendering code #3683
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
That was fast! And seems to have improved the readability of the code a lot too. I'll likely need a few days to review this. I also want to check out the branch and make sure it works with ggtext. |
No problem. And yes the old code was quite polluted |
This is running into problems on 3.2 because grid was a mess back then (unit subset-assignment was completely borked). @hadley can we drop 3.2 support a bit earlier than anticipated? |
That would basically imply dropping 3.2 support globally which I'm loathe to do without a really good reason (and I don't think cleaning up strip rendering is that reason) |
That is fair... I can try to get around it and then we can clean up my clean up after R4.0 |
If I remember correctly, we ran into a similar issue when implementing the |
Yeah... that, or just reassemble the units. I'd rather not make a conditional on a version that will fall out of support in a few months |
I've checked out the code. As currently written, it doesn't work with ggtext, because the function library(tidyverse)
library(ggtext)
library(glue)
count(mtcars, cyl, carb) %>%
mutate(cyl_lab = as.character(
glue("Cylinders {cyl} <span style='color:red'>(n={n})</span>")
)) %>%
ggplot(aes(carb, n)) +
geom_col() +
facet_wrap(~cyl_lab) +
theme(
strip.text = element_markdown(),
strip.text.x = element_markdown(),
strip.text.y = element_markdown()
)
#> Error: Unknown input Created on 2019-12-21 by the reprex package (v0.3.0) I can work around this issue by recreating the same data structure that ggplot2 is using, and in fact I do so already for rotated text, for a variety of reasons (see example below). However, I wouldn't want to have to wrap every text element into this extended data structure just so strip labels work appropriately. If library(tidyverse)
library(ggtext)
library(glue)
count(mtcars, cyl, carb) %>%
mutate(cyl_lab = as.character(
glue("Cylinders {cyl} <span style='color:red'>(n={n})</span>")
)) %>%
ggplot(aes(carb, n)) +
geom_col() +
facet_wrap(~cyl_lab) +
theme(
strip.text = element_markdown(angle = 12),
strip.text.x = element_markdown(angle = 12),
strip.text.y = element_markdown(angle = 12)
) Created on 2019-12-21 by the reprex package (v0.3.0) |
The problem is not so much reporting the sizes, as setting them. we have to resize the strips to the width or height of the largest strip after they have been created. |
Sure. So how about adding one step where you iterate over all grobs, check if they are If you look at the following code in |
I'll have a look at that tomorrow - I'm not entirely sure I understand what is going on inside |
Demonstration that this should work (since it works fine with my code). library(tidyverse)
library(ggtext)
library(glue)
df <- count(mtcars, cyl, carb) %>%
mutate(cyl_lab = as.character(
glue("Cylinders {cyl} <span style='color:red'>(n={n})</span>")
))
ggplot(df, aes(carb, n)) +
geom_col() +
facet_wrap(~cyl_lab) +
theme(
strip.text = element_markdown(angle = 1),
strip.text.x = element_markdown(angle = 1),
strip.text.y = element_markdown(angle = 1)
) df$cyl_lab[1] <- paste0(df$cyl_lab[1], "<br>and a second line of label")
ggplot(df, aes(carb, n)) +
geom_col() +
facet_wrap(~cyl_lab) +
theme(
strip.text = element_markdown(angle = 1),
strip.text.x = element_markdown(angle = 1),
strip.text.y = element_markdown(angle = 1)
) Created on 2019-12-21 by the reprex package (v0.3.0) |
unrelated, but it appears as if the coloured text are written with a shifted baseline. Is that intended? |
I think it looks like that because of the 1 degree of rotation that has been applied. Without rotation it looks correct to me. library(tidyverse)
library(ggtext)
df <- count(mtcars, cyl, carb)
ggplot(df, aes(carb, n)) +
geom_col() +
ggtitle("Cylinders 4 <span style='color:red'>(n=5)</span>") +
theme(plot.title = element_markdown()) Created on 2019-12-21 by the reprex package (v0.3.0) |
Ah - yeah. rendering of rotated text with Cairo is just a sad affair |
I haven't tested this, because I don't want to jump through the hoops of checking out your branch right now, but adding something like this to the beginning of grobs <- lapply(grobs, function(g) {
if (inherits(g, "titleGrob")) return(g)
add_margins(g, grobHeight(g), grobWidth(g), margin_x = TRUE, margin_y = TRUE)
}) |
@clauswilke I have fixed the unit operations so the change works on 3.2, as well as added your requested code block. Can you check that it now works with ggtext and review it if it does |
assemble_strips <- function(grobs, theme, horizontal = TRUE, clip) { | ||
if (length(grobs) == 0 || is.zero(grobs[[1]])) return(grobs) | ||
|
||
# Add margins to non-titleGrobs so they behave eqivalently |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spelling: "equivalently"
Perfect! library(tidyverse)
library(glue)
#>
#> Attaching package: 'glue'
#> The following object is masked from 'package:dplyr':
#>
#> collapse
library(ggtext)
count(mtcars, cyl, carb) %>%
mutate(cyl_lab = as.character(
glue("Cylinders {cyl} <span style='color:red'>(n={n})</span>")
)) %>%
ggplot(aes(carb, n)) +
geom_col() +
facet_wrap(~cyl_lab) +
theme(
strip.text = element_markdown(),
strip.text.x = element_markdown(),
strip.text.y = element_markdown()
) Created on 2020-01-06 by the reprex package (v0.3.0) |
R/margins.R
Outdated
@@ -96,7 +96,7 @@ title_spec <- function(label, x, y, hjust, vjust, angle, gp = gpar(), | |||
#' Given a text grob, `add_margins()` adds margins around the grob in the | |||
#' directions determined by `margin_x` and `margin_y`. | |||
#' | |||
#' @param grob Text grob to add margins to. | |||
#' @param grob A gList with a text grob |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just write "with a grob", or "containing a grob, such as a text grob".
Fix #3557
This PR gets strip rendering in line with the rest of the theming by correctly using
element_render()
to render strip text instead of the current hack. There is still some special considerations to be done, as strips are sized to the largest strip for alignment and this has to be done after the creation of the titleGrob. I don't think there is any way around the current approach of setting width/height directly in the viewport.The PR also adds explicit theme elements for top, bottom, left, and right strips, which inherits from strip.text.x and strip.text.y. This is necessary to control the angle of vertical strips and is in line with how it is handled for axis titles. We should watch out for any visual breakage downstream that this might affect (I predict none or very few).