过去,我注意到ggplot(和基本图形)在创建PDF文件(Prevent PDF storing invisible map data)时绘制“不可见”数据。
我刚刚注意到,在创建PDF文件时,ggplot也会绘制不必要的重复图形元素。重复的数量与正在绘制的 Dataframe 中的观察值数量相对应。
例如,在下面的示例中,mpg
数据集有234个观测值。
library(ggplot2)
nrow(mpg)
> 234
p <- ggplot(mpg, aes(class, hwy))
p + geom_boxplot()+
geom_segment(aes(x = 5, y = 40, xend = 6, yend = 40))+
geom_text(label = "***", x = 5.5, y = 41, size = 6)
ggsave("mtcars.pdf")
在创建的PDF中,234个“***”副本相互叠加。这是geom_text
的正常行为,如帮助文件所述:geom_text() and geom_label() add labels for each row in the data
.
然而,也创建了geom_segment
的234个副本,尽管帮助文件并不建议这是正常行为。
这在PDF中实际上是不可见的(除了***和段看起来好像是粗体/加粗的),但它会创建不必要的对象,这些对象会无缘无故地增加PDF大小,特别是在处理大量离群值时。
我只检查了geom_segment
:对于其它元件也是如此。
有没有人知道如何避免这种行为?
1条答案
按热度按时间ryevplcw1#
所描述的问题影响所有输出格式,而不仅仅是PDF。当然,当输出为矢量图形格式(如PDF)时,它比位图更明显。在极端情况下,它会减慢绘制到任何图形设备的速度。问题的根源在于误解了最近版本的'ggplot 2'中实现的 * 图形分层语法 * 的工作原理我认为这是一种令人惊讶的美学Map行为。
我展示了这个问题背后的三个解决方案,并解释了它背后的内容。第一个解决方案,同意评论中提供的第一个建议,第二个是一个替代方案,虽然需要更多的冗长代码,但适用于其他情况。第三个是从@stefan的评论中复制的。
创建于2023年3月30日,使用reprex v2.0.2
使用
annotate()
,可以通过使用上述方法传递长度〉1的向量来添加多个注解。然而,annotate()
不“知道”面,因此在具有面的图的情况下,在每个面板中具有不同注解的唯一方法是直接使用几何体,但是将与用于其他几何体的 Dataframe 不同的 Dataframe 作为数据传递给它们。这种方法如下所示,在这种情况下,使用单个绘图面板和单个注解是多余的,但更通用,可以与facet一起使用。创建于2023-03-30带有reprex v2.0.2
第三种可能性是在设置Map时将常量值作为参数传递给
aes()
,如@stefan和@Jon Spring在其评论中所述,在整个图级别没有默认数据。创建于2023-03-30使用reprex v2.0.2
这三种方法是等效的,因为它们阻止
geom_segment()
和geom_text()
将mpg
视为其数据输入。在第一种情况下,因为annotate()
通过设计确保了这一点,在第二种情况下,因为我们使用本地数据参数覆盖了整个图的默认数据,而在第三个示例中,通过不在对ggplot()
的调用中传递数据参数来避免创建默认值。第三种方法在'ggplot 2'的历史上只有几年才开始使用。因为以前使用
aes()
来Map常量值是不允许的或有不同的解释。在aes()
中Map常量值仍然让用户感到困惑,因为将美学Map到常量并不覆盖数据的整个图默认值,即使这些数据不再Map到几何中的任何美学,从而导致本问题中描述的令人惊讶的行为。这个令人惊讶的行为,至少对我来说,可以用一个额外的,人为的例子更清楚地证明,基于调用
data.frame()
与默认参数,以构建一个“空” Dataframe 作为参数传递,以覆盖整个图数据。并且由于没有缺少美学Map而正确地生成绘图。基于未Map到美学的数据中的行数生成图形对象的多个副本是“令人惊讶的”行为。这种行为似乎源于“ggplot 2”开发期间aes()
行为的变化。创建于2023-03-30使用reprex v2.0.2
注意:有三种常用的几何图形是不寻常的,因为它们的行为取决于是否存在Map
geom_hline()
、geom_vline()
和geom_abline()
。