在 ggplot 图中裁剪未使用的边距

Posted

技术标签:

【中文标题】在 ggplot 图中裁剪未使用的边距【英文标题】:Crop unused margin in a ggplot plot 【发布时间】:2019-09-10 10:28:28 【问题描述】:

我创建了一个要保存为 svg 的 ggplot 世界地图。两者都工作正常。但是,我想更改/指定要保存的绘图区域。

我的代码如下:

raw_plot = ggplot(data = world_for_plot,
                  aes(x = long,
                      y = lat,
                      group = group,
                      fill = "black")) +
  geom_polygon(aes(fill = results)) +
  coord_equal(1.3, expand=F) +
  scale_fill_continuous(na.value = '#F6F6F6', guide=F)

ggsave(file = "FOLDER\\LATAM.svg",
       plot = raw_plot)

这给了我以下情节:

但是,我希望有一个文件/绘图在顶部和底部没有所有不必要的空白:

有什么想法吗?我已经发现coord_equal 命令会产生一些问题。没有它,情节将填满整个情节区域。不过,我需要coord_equal 命令,否则世界地图会显得有些拉长。

【问题讨论】:

在ggsave中指定你想要的图形的大小和形状 但这只是将情节“放大”或缩小,不是吗?例如。如果我指定宽度 = 和高度 = ...,它会改变绘图的比例,但不会裁剪顶部的 x 像素和底部的 x 像素。 如果您正确选择纵横比(以匹配绘图),额外的边距将消失 好的,我玩了一下,确实可以减少边距。但是,我没有设法完全删除它,并且根据 wdith/height 值,图中的比率当然会发生变化。由于我选择了 1.3 的 coord_equal 值,这应该是我的高/宽纵横比,但仍然留有一些余量。 【参考方案1】:

如果您调整长度,这可能会起作用:

raw_plot + theme(plot.margin = margin(-2, 0, -2, 0, "cm"))

这里的边距顺序是上、右、下、左。

【讨论】:

【参考方案2】:

我最近遇到了同样的问题,所以这是我为有同样问题的人提供的解决方案。

tmaptools 有一个函数get_asp_ratio 来计算空间对象的纵横比。我们可以使用该比率来移除任何地图的外边距。

library(ggplot2)

world <- rnaturalearth::ne_countries(returnclass = "sf") # to get the world map

ggplot() +
  geom_sf(data = world) +
  coord_sf(expand = FALSE) +
  theme_void()

asp <- tmaptools::get_asp_ratio(world) # returns 2.070007

height <- 5
ggsave("world.svg", width = height * asp, height = height)

或者,如果我们不想依赖tmaptools,我们可以使用ggsave 的包装器来创建自己的函数。这本质上是基于tmaptools::get_asp_ratio 函数。

deg_to_rad <- function(x) 
  (mean(x) * pi) / 180


get_aspect_ratio <- function(geometry) 
  if (!inherits(geometry, c("Spatial", "Raster", "sf", "sfc"))) 
    stop('"geometry" must be of class "Spatial", "Raster", "sf" or "sfc".')
  
  bbox <- sf::st_bbox(geometry)
  xlim <- bbox[c(1, 3)]
  ylim <- bbox[c(2, 4)]
  xdeg <- diff(xlim)
  ydeg <- diff(ylim)
  if (xdeg == 0 || ydeg == 0) 
    asp <- 1
   else 
    is_lon_lat <- sf::st_is_longlat(geometry)
    asp <- unname((xdeg / ydeg) * ifelse(is_lon_lat, cos(deg_to_rad(ylim)), 1))
  
  asp


save_ggmap <- function(filename, plot = last_plot(), width = NA, height = NA, ...) 
  geometry <- ggplot_build(plot)$data[[1]]$geometry
  asp <- get_aspect_ratio(geometry)
  if (is.na(width) && !is.na(height)) 
    width <- height * asp
   else if (is.na(height) && !is.na(width)) 
    height <- width / asp
  
  ggsave(filename, plot, width = width, height = height, ...)

我们可以像ggsave一样使用这个函数。我们只需要指定widthheight,该函数就会自动以正确的纵横比保存地图。

ggplot() +
  geom_sf(data = world) +
  coord_sf(expand = FALSE) +
  theme_void()

save_ggmap("world.svg", width = 8)

要去除内边距,我们可以使用theme(plot.margin = margin(0, 0, 0, 0))

【讨论】:

以上是关于在 ggplot 图中裁剪未使用的边距的主要内容,如果未能解决你的问题,请参考以下文章

使用 cowplot 时减少绘图之间的边距

R:如何在 ggplot2 中绘制 svm 的超平面和边距?

Android - 自定义样式中指定的边距未生效

R:如何在图中删除这个微小的轴边距

打印html页面时的边距

matlab subplot 的边距(with tight margins)