Rotate whole ggplot, keep legend unrotated

This is a follow-up to https://forum.posit.co/t/rotating-plot-area-only-in-ggplot2/ (so maybe @jrmuirhead can help again??)

I am trying to rotate my plot by 45 degrees. So far so good with the solution above, but I also want:

  1. To have a non-rotated legend.
  2. To be able to export the final plot with ggsave.

Here is what I have so far:

library(ggplot2)
#> Warning: package 'ggplot2' was built under R version 4.1.2
library(grid)

p <- ggplot(mtcars, aes(mpg, color = factor(cyl))) + 
  geom_density()

grid.newpage()
pushViewport(viewport(name = "rotate", angle = 45, width = 0.7, height = 0.7))
print(p, vp = "rotate", newpage = FALSE)
#> Warning in grid.Call.graphics(C_setviewport, vp, TRUE): cannot clip to rotated
#> viewport
#> Warning in grid.Call.graphics(C_setviewport, vp, TRUE): cannot clip to rotated
#> viewport

Created on 2022-02-07 by the reprex package (v2.0.1)

Thanks!

1 Like

some approaches you can try
ggplot2 - Rotate entire ggplot() without rotating any text R - Stack Overflow

Thanks, I've seen that, but it does not give solutions to the two points I'm looking for:

  1. To have a non-rotated legend.
  2. To be able to export the final plot with ggsave .

You are asking to achieve effects that the software wasn't designed to perform.
Ultimately you may be best served in that regard by raising an issue on ggplot2 github site, asking for the features you desire to be implemented by the developers.
As a second best, although you can not use ggsave, you can save and restore any such chart by use of recordPlot() and save/load functions. also although you can't rotate the full legend, you can rotate their text elements.

library(ggplot2)
#> Warning: package 'ggplot2' was built under R version 4.1.2
library(grid)

rotation <- 45
(p <- ggplot(mtcars, aes(mpg, color = factor(cyl))) + 
  geom_density() + theme(legend.text = element_text(angle=(-1*rotation)),
                         text = element_text(angle=(-1*rotation)),
                         axis.text = element_text(angle=(-1*rotation)),
                         axis.title = element_text(angle=(-1*rotation)),
                         axis.title.y = element_text(angle=(-1*rotation))))

grid.newpage()
pushViewport(viewport(name = "rotate", angle = rotation, width = 0.7, height = 0.7))
print(p, vp = "rotate", newpage = FALSE)

a1 <- recordPlot()

save(a1,file = "mysavedplot.Rdata")

you can restart your R session losing your objects, and restore the visual from disk :

load("mysavedplot.Rdata")
a1

on second thoughts it may be possible to combine an untransformed legend with a transformed plot, doing something like plotting and rotating (without the legend) and then layering over it a plot consisting of untransformed legend only, although I don't have all that much time to experiment with that today

Yes, I was thinking something along those lines - perhaps extracting the legend as a (rotated) grob and then re-adding it?

Thanks!

This is the best I could do:

library(ggplot2)
#> Warning: package 'ggplot2' was built under R version 4.1.2
library(grid)
library(cowplot)
library(ggplotify)
#> Warning: package 'ggplotify' was built under R version 4.1.2

p <- ggplot(mtcars, aes(mpg, color = factor(cyl))) + 
  geom_density()


rotation <- 45

leg <- as.grob( ~ plot(get_legend(p + theme_void())))

p_rot <- p + theme(legend.position = "none",
                   axis.title.y = element_text(angle = -90)) + 
  annotation_custom(textGrob("This is a title!", rot = -rotation,
                             x = unit(1.1, "npc"), y = unit(1.1, "npc"))) + 
  annotation_custom(textGrob("This is a caption", rot = -rotation,
                             x = unit(-0.1, "npc"), y = unit(-0.1, "npc")))

grid.newpage()
vp <- viewport(name = "rotate", angle = rotation, width = 0.5, height = 0.5)
pushViewport(vp)
print(p_rot, vp = "rotate", newpage = FALSE)
#> Warning in grid.Call.graphics(C_setviewport, vp, TRUE): cannot clip to rotated
#> viewport
#> Warning in grid.Call.graphics(C_setviewport, vp, TRUE): cannot clip to rotated
#> viewport
vp = viewport(x=0.15, y=0.8, width=0, height=0)
pushViewport(vp)
grid.draw(leg)

Created on 2022-02-07 by the reprex package (v2.0.1)

1 Like

well done !
How might you wish to improve on that ?

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.