如何在ggplot中修复纵横比?

111

我试图调整绘图大小以适应我的文档,但是我很难让绘制的图形成为一个正方形。

示例:

pdf(file = "./out.pdf", width = 5, height = 5)
p <- ggplot(mydata, aes(x = col1, y = col2))
print(p)
aux <- dev.off()

尽管x和y的限制相同,但结果中的图形不是正方形。我猜测R会将外部面板设置为5x5英寸,但不关心实际图形的大小。

我该如何使我的图形不再扭曲?

5个回答

133
在ggplot中保持绘图的纵横比的机制是在绘图中添加一个coord_fixed()层。这将保持绘图本身的纵横比,而不考虑实际边界框的形状。(我还建议您使用ggsave将生成的绘图保存为pdf/png等格式,而不是使用pdf(); print(p); dev.off()序列。)
library(ggplot2)
df <- data.frame(
    x = runif(100, 0, 5),
    y = runif(100, 0, 5))

ggplot(df, aes(x=x, y=y)) + geom_point() + coord_fixed()

插入图像描述


3
你知道为什么ggplot一直坚持把y轴标签放在左侧吗?我想知道如何防止这种情况发生... - Chase
@chase 一个笨拙的解决办法是修改标题的 hjust 位置 - 尝试 opts(axis.title.y=theme_text(hjust=10))。但是很遗憾,这似乎行不通。请参见 ggplot 邮件列表讨论和 @Baptiste 的回答:http://groups.google.com/group/ggplot2/browse_thread/thread/7f8a51b61af0febb。 - Andrie
3
该行为已在开发版本中修复。 - hadley
7
在更一般的问题标题下,您是否可以添加关于如何计算比率(coord_fixed的参数)的信息,假设在两个轴上不使用相同的限制? - htorque
1
根据@htorque的评论;如果将y定义为y=runif(100, 0, 50),则图形的方面比例不再是正方形。 coord_fixed()只会使每个轴的比例尺相等,是这样吗? - a different ben
如果您建议使用ggsave而不是pdf,如何将多个图绘制到一个唯一的pdf中,每页一个图?谢谢。 - HanniBaL90

109
为确保特定的宽高比,例如正方形,请使用theme(aspect.ratio=1)
安德里的回答并没有提供完整的图片,因为该示例提供了可能不太自然的数据,其中x轴的范围等于y轴的范围。但是,如果数据如下:
df <- data.frame(
  x = runif(100, 0, 50),
  y = runif(100, 0, 5))
ggplot(df, aes(x=x, y=y)) + geom_point() + coord_fixed()

那么情节将如下所示:

enter image description here

coord_fixed()函数还有一个参数可以调整轴的比例:

ratio 纵横轴的比例,以 y / x 表示

因此,可以使用以下代码制作正方形的绘图:

ggplot(df, aes(x=x, y=y)) + geom_point() + coord_fixed(ratio=10)

但是你需要根据变量或图形区域的限制进行调整(并非所有限制都像这些示例一样可以整除)。


2
这是更优秀的答案,因为它不一定假设“x”轴和“y”轴具有相同的单位范围! - Brunox13

21

为了完整起见: 如果您想考虑非常不同的轴限制:

df <- data.frame(
  x = runif(100, 0, 5000),
  y = runif(100, 0, 5))
ratio.display <- 4/3
ratio.values <- (max(df$x)-min(df$x))/(max(df$y)-min(df$y))
plot <- ggplot(df, aes(x=x, y=y)) + geom_point()
plot + coord_fixed(ratio.values / ratio.display)

导致:


18
这样做比plot + theme(aspect.ratio=4/3)更好在于什么?ggplot可以有多个图层、多个数据集,并且轴可以具有任意扩展因子,因此从一个数据源计算y/x的比率似乎非常脆弱。 - baptiste
3
因为这显然不容易发现,这一事实得到证实,因为这里有三个回答,但没有一个提到它。你应该把它放在一个回答中,这绝对是更好的解决方案。 - Graipher

6

根据baptiste的建议和Graipher答案,因为它既优雅又有用。

df <- data.frame(
  x = runif(100, 0, 5000),
  y = runif(100, 0, 5))
aspect.ratio <- 4/3
ratio.values <- (max(df$x)-min(df$x))/(max(df$y)-min(df$y))
plot <- ggplot(df, aes(x=x, y=y)) + geom_point() + theme(aspect.ratio=4/3)

Plot with 1:1 aspect ratio


2
我看到了这篇文章,想要添加更多信息。如果您计划将图像插入RMD文档中,则可以从r块处理aspect.ratio。根据您的布局,有3种方法可以更改图像的纵横比(取决于您的工作流程)。
#1. 在创建图形时
myPlot <- ggplot(data = iris,
aes(x=Species, y = Sepal.Length)) +
geom_point() +
theme(aspect.ratio = 6.5/11)

#2. 使用ggsave保存图像时

ggsave("images/plot1.png", myPlot, width=11, height=6.5, dpi=400)

#3. 在rmd文档中。如果您计划使用officedown(并创建docx作为文档输出),那么我发现6.5/11的纵横比与fig.width为9.4的组合在横向页面上是最好的。

  <!---BLOCK_LANDSCAPE_START--->
    ```{r fig.id="my-fig", fig.cap="", fig.width=9.4, fig.asp = 6.5/11}
    myPlot
    ```
 <!---BLOCK_LANDSCAPE_STOP--->

应该注意,如果您计划将ggplot插入到您的Rmd文档中,您可以跳过步骤#1和#2,直接使用选项#3。

1
第三种方法对我很有效,因为其他方法在图和图形之间留下了奇怪的边距。 - Tobias P. G.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接