Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

howto: Automatically set fixed coordinate ratio (coord_fixed) when x- and y-axis are on different scales?

My goal is to fix the coordinate aspect ratio of a plot from ggplot2 via coord_fixed(). I thought coord_fixed(ratio=1) did the job independently of the scales of the x- or y-axis. My intuition: the argument ratio refers to the ratio of the total range of coordinate x to the total range of coordinate y. Implying that a ratio of 1 always means that the x-axis will be as long as the y-axis in the plot.

Yet with x-coordinates in the 1000s and y-coordinates e.g. percent, coord_fixed does not behave not as I expect it.

2 Questions:

  1. Can you explain why coord_fixed takes the actual scale of the data into account but not the coordinate length as a whole?
  2. Can I change the coord_fixed programatically to always refer to the whole range of the x- and y-coordinate values?

Here's an illustration

library("ggplot2")
set.seed(123)
df = data.frame(x=runif(11)*1000,y=seq(0,.5,.05))
ggplot(df, aes(x,y)) +geom_point() +coord_fixed(1)

produces enter image description here

Rescaling the data by the ratio of x- and y-values in coord-fixed solves the issue

ggplot(df, aes(x,y)) +geom_point() +coord_fixed(1*max(df$x)/max(df$y))

However, this is not progammatically. I would have to specify the df$x manually to achieve the desired effect. See question 2: Is there a sensible way to automatize the re-scaling of the coordinates within coord_fixed depending on which data is on the x-/y-axis in my ggplot plot?

enter image description here

like image 821
JBJ Avatar asked Nov 12 '14 19:11

JBJ


1 Answers

Can you plain why coord_fixed takes the actual scale of the data into account but not the coordinate length as a whole?

That's the point of coord_fixed. It's especially useful when, e.g., x and y are measures of length in the same units. (Basically whenever x and y have the same units, coord_fixed with ratio = 1 is what you want.)

For example, if my data is a square and a triangle, coord_fixed is the only way to make the square actually square

shapes <- data.frame(x = c(1, 1, 2, 2, 1, 3, 3, 4, 3),
                     y = c(1, 2, 2, 1, 1, 1, 2, 1, 1),
                     name = c(rep("square", 5), rep("isosceles triangle", 4)))

shape.plot <- ggplot(shapes, aes(x = x, y = y, group = name, color = name)) +
    geom_path()

shape.plot # distorted
shape.plot + coord_fixed() # square!

Can I change the coord_fixed programatically to always refer to the whole range of the x- and y-coordinate values?

I would recommend not overwriting it, you could try to create your own version much as in your answer (though if you want to pull the appropriate values out of the x and y specifications of aes() you'll have a challenge---and you'll learn more about ggplot's internal workings than I know). However, the default behavior (without specifying any coord) seems to be what you're looking for.

If you compare

# your code
ggplot(df, aes(x,y)) + geom_point() + coord_fixed(1 * max(df$x) / max(df$y))

# no coord at all
ggplot(df, aes(x,y)) + geom_point()

they're basically the same. So, the modification of coord_fixed you seem to be looking for is don't use coord_fixed.

Aspect ratio of plot area (independent of coordinates): don't use coord_fixed

Just found out about this from this semi-related post: if you want a specific aspect ratio of the plot area, you can get it with theme(), e.g.

p1 <- ggplot(df, aes(x,y)) + geom_point()
p1 + theme(aspect.ratio = 1)
p1 + theme(aspect.ratio = (1 + sqrt(5))/ 2)  # golden ratio portrait
p1 + theme(aspect.ratio = 2 / (1 + sqrt(5))) # golden ratio landscape

This is, of course, data-agnostic. I think the take-home message is that if you want the scales of your data taken into account, relative to each other, use coord_fixed. If you want to change the aspect ratio of the plotting area but still fit the data, use theme(aspect.ratio). If you want to change the aspect ratio of a saved file, use the height and width arguments of your saving function.

like image 123
Gregor Thomas Avatar answered Nov 11 '22 04:11

Gregor Thomas