有没有办法删除 ggplot 之外的空白?

Is there a way to remove the whitespace outside of a ggplot?

我正在使用我用来创建静态地图的代码包含在一个闪亮的应用程序中。我有一个问题,虽然绘图大小比实际绘图大得多,所以布局看起来不对。有什么办法可以减少图外的空白吗?

如果可能的话,我希望输出只是情节本身。

# reprex
library(terra)
library(sf)
library(magrittr)
library(ggplot2)

lux <- vect(system.file("ex/lux.shp", package = "terra"))

p <- lux %>% 
  st_as_sf() %>%
  ggplot() +
  geom_sf(aes(fill = NAME_2), colour = "white", size = 0.2) +
  theme(legend.position = "None") +
# found online - removes the whitespace around the plot but not the external whitespace
  theme(plot.margin=grid::unit(c(0,0,0,0), "mm")) 

p

您的绘图包含空白的原因是由于 geom_sf() 对坐标系施加的约束。绘图的纵横比通常会自行调整以适应典型绘图中 window 的大小,但在 shapefile (sf) 的情况下,纵横比由特定的 coordinate reference system,或与该特定投影相关的 CRS。您之前在地图中看到过这种情况,由于试图将地球表面投影到 2D 平面上,每张地图都会出现变形。

因此,geom_sf() 生成具有适当纵横比的地图。如果您的视图 window 或输出图像与该纵横比不匹配,那么您将在两侧或顶部留有空白以进行补偿。那么,解决问题的方法是要么改变你的图的纵横比(这看起来不正确,也不是一个好主意)或者让你的输出图像或 window 匹配你的图的纵横比.

TL;DR - 使用 tmaptools::get_asp_ratio() 获取绘图对象的纵横比,然后以该纵横比保存绘图图像。

现在提供一些解释性图片,以帮助说明 geom_sf()geom_polygon() 功能不同的原因,以及如何在代表性示例中解决问题。

地图使用 geom_polygon()

除非您用 coord_fixed() 固定绘图区域的比例,否则 geom_polygon() 将始终随着输出纵横比的变化而挤压和拉伸。

library(ggplot2)

my_map <- map_data("usa")
p1 <-
  ggplot(my_map, aes(long, lat)) +
  geom_polygon(aes(group=group), fill='white', color='black') +
  ggtitle('USA Using geom_polygon()')

这是一张方形地图:

ggsave('p1_square.png', plot=p1, width=5, height=5)

这是一张矩形地图:

ggsave('p1_rect.png', plot=p1, width=15, height=5)

地图使用 geom_sf()

相比之下,您可以看到具有 geom_sf() 的地图始终保持其纵横比,无论输出大小如何。

library(sf)

world1 <- sf::st_as_sf(map('usa', plot = FALSE, fill = TRUE))
p2 <-
  ggplot() + geom_sf(data = world1, fill='white') + ggtitle('USA Using geom_sf()')

方形输出:

ggsave('p2_square.png', plot=p2, width=5, height=5)

矩形输出:

ggsave('p2_rect.png', plot=p2, width=15, height=5)

如何删除空格?

那么,现在应该很明显了 为什么 你有空格...但是 我们如何删除它? 嗯,答案是您需要使用 sf 对象使用的 CRS 给出的相同纵横比来保存您的绘图。您需要的是一种获取该信息的方法。 sf 包中的函数 st_crs() 可以获得您的 shapefile 使用的 CRS 的名称,但它不会直接为您提供纵横比。为此,您可以使用 tmaptools 库中的 get_asp_ratio() 函数,然后使用它来计算您的 width/height。这里需要注意的是,我们需要在 sf 对象 上使用 get_asp_ratio() 而不是在绘图对象 上使用 get_asp_ratio()。在这种情况下,那是 world1 而不是 p2.

plot_ratio <- get_asp_ratio(world1)
ggsave('p2_perfect.png', plot=p2, width = plot_ratio*5, height=5)

这为我们提供了与您的地图纵横比完美匹配的绘图输出: