11

In R I always find it annoying that base R, lattice and ggplot2 plots all work with absolute point sizes for the size of text and plot symbols.

This means that if you increase say the size of your plot window to get a page-filling graph from

windows(width=5,height=5);qplot(Sepal.Length, Petal.Length, data = iris, color = Species, size = Petal.Width, alpha = I(0.7))

to

windows(width=10,height=10);qplot(Sepal.Length, Petal.Length, data = iris, color = Species, size = Petal.Width, alpha = I(0.7))

that the relative scaling of the text and plot symbols change relative the rest. The same applies to base R and lattice plots.

In the context of some graph export functions I am writing I was wondering if it would be possible to write a function that would take the output of the current graphics device (which can be accessed using recordPlot()), and scale all plot symbols and text as well as line widths by an arbitrary %, thereby allowing the graph to be exported at any size, whilst still maintaining the same look? I.e. a function to proportionally scale the whole graph to a larger or smaller size while keeping the look the same?

PS the same would be required to be able to scale the RStudio plot window on high DPI 4K screens and still make it legible (right now RStudio uses pixel doubling but this makes the plot window look really fuzzy, and also causes problems in combination with Cleartype on Windows, causing colour fringing).

Community
  • 1
  • 1
Tom Wenseleers
  • 7,535
  • 7
  • 63
  • 103

2 Answers2

5

for some reason the point size is encoded as fontsize, so it doesn't seem easy to convert it to units that would scale automatically. If you know what scaling you'd want to apply, then the following might help

library(ggplot2)
p <- qplot(Sepal.Length, Petal.Length, data = iris, 
           geom=c("point","line"),
           color = Species, size = Petal.Width, alpha = I(0.7))

library(gtable)
library(grid)

g <- ggplotGrob(p)
pts <- g$grobs[[4]][["children"]][[2]] # geom_point layer
lns <- g$grobs[[4]][["children"]][[3]] # geom_line layer
g$grobs[[4]][["children"]][[2]] <- editGrob(pts, size=1.2*pts$size)
gp <- modifyList(lns$gp, list(lwd=1.2*lns$gp$lwd))
g$grobs[[4]][["children"]][[3]] <- editGrob(lns, gp=gp)

grid.newpage()
grid.draw(g)

enter image description here

baptiste
  • 75,767
  • 19
  • 198
  • 294
  • Thx for this - when I try the code g and p look the same though. Any thoughts? Also, what I am looking for is a generic way to scale all graphics elements, including line widths, plot symbols and font sizes by some factor. So that if you e.g. scale your plot window by a factor of 2 you could scale all graphics elements by the same factor... This would ideally have to work for ggplot2 as well as lattice or base R graphs... – Tom Wenseleers Sep 05 '15 at 08:46
  • i'm using the dev version of ggplot2, it's quite possible that earlier versions used size instead of fontsize (i think it's a recent move) – baptiste Sep 05 '15 at 08:56
  • Ha OK I'll try with the dev version of ggplot2 then - though this would still only be a partial ggplot2 solution then I guess, and I am looking for a solution that would also work e.g. with lattice graphs. As an alternative solution, is it not possible by any chance to change the ppi of the graphics window (I think that's now taken to be 72)? E.g. capture graph with recordPlot(), change ppi to change scaling, and then redraw? – Tom Wenseleers Sep 05 '15 at 09:04
  • the resolution would be a device-dependent setting, that's not controlled by the plot – baptiste Sep 05 '15 at 09:20
  • i don't know a general solution to your problem. grid has some settings that scale according to the parent viewport such as cex, but unfortunately they're not always used consistently. – baptiste Sep 05 '15 at 09:23
  • OK I see - many thanks in any case for your help and advice! Ha and btw - can line widths also be scaled proportionally using a similar method like that above? – Tom Wenseleers Sep 05 '15 at 09:26
  • Thanks - seems to work for size of plot symbols and line widths in those particular layers, though not e.g. for the line widths in the gridlines in the background, the tickmarks, or size of the plot symbols in the legend and also not for the fonts or any other layers there might be. Alternative approach perhaps could be to look for any sublist element of g and scale all sublists named size, lwd or fontsize by a certain factor? – Tom Wenseleers Sep 05 '15 at 10:21
  • personally, i'd save the plot as a pdf file, and open it at the required zoom level. – baptiste Sep 05 '15 at 11:05
  • agreed that that is the easiest, but still for many things it seems desirable to be able to scale R plot windows as well, with relative sizes remaining the same, e.g. to support high DPI 4K monitors nowadays... – Tom Wenseleers Sep 05 '15 at 11:18
4

This seems to be closer to your end goal

library(ggplot2)
p <- qplot(Sepal.Length, Petal.Length, data = iris, 
           geom=c("point","line"),
           color = Species, size = Petal.Width, alpha = I(0.7))
library(grid)
print(p, vp=viewport(gp=gpar(cex=2, lex=2)))
baptiste
  • 75,767
  • 19
  • 198
  • 294
  • Thanks also for this solution - +1 - though probably also not close enough to the desired result to be really usable - e.g. windows(height=5,width=5); p and windows(height=10,width=10); print(p, vp=viewport(gp=gpar(cex=2, lex=2))) result in quite different results, with e.g. size of plot symbols and spacing in the legend not scaling along... Quite tricky... Seems to be the kind of thing that would really have to be supported at some low level in grDevices I guess... Maybe with some dpi setting that would tell how many dpi your screen is... – Tom Wenseleers Sep 05 '15 at 11:28