6

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

JBJ
  • 866
  • 9
  • 21
  • Well, it looks like you have the answer inside your question, what else result would you like to achieve that you cannot already? – Athos Nov 12 '14 at 19:44
  • Athos, to the best of my knowledge both questions (why? + programmatically changing?) are not answered by the illustration. – JBJ Nov 12 '14 at 20:02

1 Answers1

7

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.

Community
  • 1
  • 1
Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
  • thanks for the answer! Regarding programming: Yes you got the point. pulling the max(x) and max(y) values from aes(x,y) in ggplot would be what I need. Regarding your last point "don't use it": In this particular case not using would make sense, in more general cases it may not. Imagine I want a fixed ratio, say the golden ratio, for publications in a programmtic way for more complex data, then I need to set coord-fixed. I hope somebody can give me maybe even more hints towards why coord_fixed is not using tha range of the axis. – JBJ Nov 12 '14 at 19:55
  • Yes - that illustrates the behavior of coord_fixed very well - thanks. In your example referring to the actual axis scale units mke sense - in my example referring to the relative axis range makes sense. The question remains: why did hadley prefer the actual units over the range when the function is called `coord` but not `units_fixed`. If nobody has a more elaborate answer I'll accept yours. – JBJ Nov 12 '14 at 20:10
  • To help you understand: As you surely know, `ggsave` specifies the plot *area* width/heights, not the coordinate ratio. I want to control the relative *coordinate* ratio within the file. It should be programmatically the golden ratio. That is why `ggsave` specifications are not a solution, not is the default plotting behavior which does not scale the axis to the golden ratio. This is why I need `coord_fixed`. Further the implementation of the golden ratio is also not the problem, it is the re-scaling of the units. (Just as I asked in my question). – JBJ Nov 12 '14 at 20:18
  • changed question to make it more clear, thanks for pointing that out. – JBJ Nov 12 '14 at 20:23
  • @JBJ think I found a solution you'll like, see edits. – Gregor Thomas Nov 13 '14 at 00:20