Search code examples
rggplot2pca

Force scatter plot grid to be square in ggpot2


I'm trying to force the grid of a scatter plot to be composed of squares, with x and y values that have different ranges.

I tried to force a square shape of the whole plot (aspect.ratio=1), but this does not solve the problem of different ranges. Then I tried to change limits of values of my axes.

1)Here is what I tried first:

p + theme(aspect.ratio = 1) +
    coord_fixed(ratio=1, xlim = c(-0.050,0.050),ylim = c(-0.03,0.03))

2) I changed the ratio by using the range of the values for each axis:

p + coord_fixed(ratio=0.06/0.10, xlim = c(-0.050,0.050), ylim = c(-0.03,0.03))

3)Then I changed the limits of y to match those of x:

p + theme(aspect.ratio = 1) +
          coord_fixed(ratio=1, xlim = c(-0.050,0.050),ylim = c(-0.05,0.05))

1) The grid on the background is composed by rectangles.

Rectangles

2) I would expect this to change the position of the tick marks automatically in order to give me a grid composed of squares. Still triangles.

still rectangles

3) It obviously worked 'cause I matched the ranges of x and y. But there was a lot of empty space in the graph.

Squares but ugly

Is there something else I should try?

Thanks in advance.


Solution

  • If you want the plot to be square and you want the grid to be square you can do this by rescaling the y variable to be on the same scale as the x variable (or vice versa) for plotting, and then inverting the rescaling to generate the correct axis value labels for the rescaled axis.

    Here's an example using the mtcars data frame, and we'll use the rescale function from the scales package.

    First let's create a plot of mpg vs. hp but with the hp values rescaled to be on the same scale as mpg:

    library(tidyverse)
    library(scales)
    theme_set(theme_bw())
    
    p = mtcars %>% 
      mutate(hp.scaled = rescale(hp, to=range(mpg))) %>% 
      ggplot(aes(mpg, hp.scaled)) +
      geom_point() +
      coord_fixed() +
      labs(x="mpg", y="hp")
    

    enter image description here

    Now we can invert the rescaling to generate the correct value labels for hp. We do that below by supplying the inverting function to the labels argument of scale_y_continuous:

    p + scale_y_continuous(labels=function(x) rescale(x, to=range(mtcars$hp)))
    

    enter image description here

    But note that rescaling back to the original hp scale results in non-pretty breaks. We can fix that by generating pretty breaks on the hp scale, rescaling those to the mpg scale to get the locations where we want the tick marks and then inverting that to get the label values. However, in that case we won't get a square grid if we want to keep the overall plot panel square:

    p + scale_y_continuous(breaks = rescale(pretty_breaks(n=5)(mtcars$hp), 
                                            from=range(mtcars$hp), 
                                            to=range(mtcars$mpg)),
                           labels = function(x) rescale(x, from=range(mtcars$mpg), to=range(mtcars$hp)))
    

    enter image description here