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

1

7

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

Joleen answered 12/11, 2014 at 19:2 Comment(2)
Well, it looks like you have the answer inside your question, what else result would you like to achieve that you cannot already?Aglitter
Athos, to the best of my knowledge both questions (why? + programmatically changing?) are not answered by the illustration.Joleen
A
8

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.

Androus answered 12/11, 2014 at 19:43 Comment(5)
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.Joleen
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.Joleen
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).Joleen
changed question to make it more clear, thanks for pointing that out.Joleen
@Joleen think I found a solution you'll like, see edits.Androus

© 2022 - 2024 — McMap. All rights reserved.