tidyverse / ggplot2

An implementation of the Grammar of Graphics in R
https://ggplot2.tidyverse.org
Other
6.47k stars 2.02k forks source link

axis.text.y and "Vectorized input to `element_text()` is not officially supported" - is there any smart way to address it? #4533

Closed Generalized closed 3 years ago

Generalized commented 3 years ago

Is there any way to achieve the effect presented on the screenshot, made with the instructions I show below - which triggers a warning?

Description of the effect to achieve: There is a set of faceted Kaplan-Meier curves. The study sponsor wants each panel to have it's own risk table (it cannot be negotiated - the risk table must be shown there and not elsewhere). Each row of the risk table is linked to a corresponding curve by label and color. I also had to make the font a bit smaller. With the code I made it works perfectly and was accepted by the study sponsor.

obraz

which is made with this code:

 ..... +
 scale_y_continuous(breaks = c(-.2, -.1, 0, .2, .4, .6, .8, 1),
                     labels = c("Resectable", "Unresectable", "0", "0.2", "0.4", "0.6", "0.8", "1"),
                     limits = c(-0.2, 1)) +
  # make some space from the left
  scale_x_continuous(breaks = c(0, 30, 60, 90, 120), limits = c(-5, NA)) +
  # format the axis elements  
  theme(axis.text.y = element_text(colour = c("green3", "red3", rep("black", 6)),
                                   size = c(7.5, 7.5, rep(8, 6)))) +
  scale_color_manual(values=c("Resectable"="green3", "Unresectable"="red3"))

What bothers me is the warning (as mentioned in the title) I get all the time. This is triggered by this line

  theme(axis.text.y = element_text(colour = c("green3", "red3", rep("black", 6)),
                                   size = c(7.5, 7.5, rep(8, 6)))) +

Is there any simple, elegant solution allowing me to obtain this very effect without the warning?

I read, that you may remove this awesome feature (vectorization on the element_text) some day - which would be really a pity, so the code will break. Please guide me how to achieve the same with similar efforts, as this template will be used by me very often.

teunbrand commented 3 years ago

Just to provide a reprex, the following triggers the warning:

library(ggplot2)

ggplot(mtcars, aes(wt, mpg)) +
  geom_point() +
  theme(axis.text.y = element_text(colour = c("red", "green", rep("black", 4))))
#> Warning: Vectorized input to `element_text()` is not officially supported.
#> Results may be unexpected or may change in future versions of ggplot2.

In these types of cases I usually find the ggtext package does a good job. You can wrap the labels beforehand or in a function fed to the labels argument.

library(ggtext)
library(glue)

ggplot(mtcars, aes(wt, mpg)) +
  geom_point() +
  scale_y_continuous(
    labels = function(x) {
      colours <- c("red", "green", rep("black", length(x) - 2))
      glue("<span style='color:{colours}'>{x}</span>")
    }
  ) +
  theme(axis.text.y = element_markdown())

Created on 2021-06-27 by the reprex package (v1.0.0)

Given that you already give the labels verbatim, you could put the html tags around it.

Generalized commented 3 years ago

Oh, this is marvellous. Thank you very much for this solution.

I can only hope that the ggtext package will be maintained for a long time (not abandoned and removed from the CRAN) in the future, because I will need to employ it in my workflow (I work in the medical industry, where the aspect of persistence of solutions is critical).

So, although this solution is clean, elegant, easy and I am going to use it, but, honestly, I would prefer to have it done entirely in the ggplot2 - just to limit the external dependencies. (BTW, this one is also interesting: https://thomasadventure.blog/posts/mdthemes-is-on-cran-markdown-powered-themes-for-ggplot2/ ). But I'm afraid there's no way to do that without hacks.

Maybe the Authors, @hadley , @clauswilke, @thomasp85, who decide on the final "shape" of the ggplot2 package could consider preserving this, or add a way to achieve that effect other way? This would be really nice to have this feature without employing third-party packages.

yutannihilation commented 3 years ago

Sorry, we already decided not to allow vectorized inputs here. That's why you see the warning. For more context, please refer to the discussion around https://github.com/tidyverse/ggplot2/issues/3492#issuecomment-524620901.

balthasars commented 3 weeks ago

@yutannihilation Sorry to open this again: Is ggtext still the recommended solution?

Like @Generalized I'm also a bit skeptical about using ggtext given that it has not received very little development activity since its initial release.

Moreover, it's been ~5 years since the ggplot2 deprecation cycle started, are there any plans of this going away anytime soon?

clauswilke commented 3 weeks ago

If ggtext solves your problem go ahead and use it, but I don't expect that it'll see much development going forward. @thomasp85 is approaching the problem in a much more systematic way in his marquee package and so you may want to check that out: https://cran.r-project.org/web/packages/marquee/index.html

balthasars commented 3 weeks ago

@clauswilke Thank you for the heads-up, just checked it out!

Unfortunately marquee does not seem to provide a sustainable solution to the vectorized input problem I'm looking for though, given that there's still a warning for this use case

library(ggplot2)
gg <- ggplot(data = mtcars, aes(x = disp, y = mpg)) +
  geom_line() +
  labs(subtitle = c("left-aligned subtitle", "right-aligned subtitle"))

gg +
  theme(
    plot.subtitle = marquee::element_marquee(hjust = c(0, 1))
  )
#> Warning: Vectorized input to `element_text()` is not officially supported.
#> ℹ Results may be unexpected or may change in future versions of ggplot2.

Created on 2024-08-27 with reprex v2.1.0

Was mostly getting at this use case here https://github.com/wilkelab/ggtext/issues/116

clauswilke commented 3 weeks ago

The original example here was about coloring and using the marquee package you can give each label its own color without needing to vectorize input to element_text(). Similarly, I think you can specify different alignment options for each label, using the style system: https://marquee.r-lib.org/reference/style.html