Search code examples
rplotr-grid

Preserving aspect ratio in R's grid graphics


To draw a "crossed" rectangle of height 2 times larger than its width using the low-level graphics package facilities I call:

xlim <- c(0, 500)
ylim <- c(0, 1000)
plot.new()
plot.window(xlim, ylim, asp=1)
rect(xlim[1], ylim[1], xlim[2], ylim[2])
lines(c(xlim[1], xlim[2]), c(ylim[1], ylim[2]))
lines(c(xlim[1], xlim[2]), c(ylim[2], ylim[1]))

The figure has a nice feature: the aspect ratio is preserved so that if I change the size of the plot window, I get the same height-to-width proportions.

How can I obtain an equivalent result with grid graphics?


Solution

  • You should create a viewport that uses Square Normalised Parent Coordinates, see ?unit:

    "snpc": (...) This is useful for making things which are a proportion of the viewport, but have to be square (or have a fixed aspect ratio).

    Here is the code:

    library('grid')
    xlim <- c(0, 500)
    ylim <- c(0, 1000)
    grid.newpage() # like plot.new()
    pushViewport(viewport( # like plot.window()
            x=0.5, y=0.5, # a centered viewport
            width=unit(min(1,diff(xlim)/diff(ylim)), "snpc"), # aspect ratio preserved
            height=unit(min(1,diff(ylim)/diff(xlim)), "snpc"),
            xscale=xlim, # cf. xlim
            yscale=ylim  # cf. ylim
    ))
    # some drawings:
    grid.rect(xlim[1], ylim[1], xlim[2], ylim[2], just=c(0, 0), default.units="native")
    grid.lines(xlim, ylim, default.units="native")
    grid.lines(xlim, rev(ylim), default.units="native")
    

    The default.units argument in e.g. grid.rect forces the plotting functions to use the native (xscale/yscale) viewport coordinates. just=c(0, 0) indicates that xlim[1], ylim[1] denote the bottom-left node of the rectangle.