1
votes

I have created a ggplot worldmap that I want to save as svg. Both work fine. However, I want to change/specify the area of the plot that gets saved.

My code looks as follows:

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)

This gives me the following plot:

enter image description here

However, I want to have a file/plot that doesn't have all the unnecessary white space on top and bottom:

enter image description here

Any ideas? I already figured out that the coord_equal command creates some problems. Without it, the plot fills out the whole plot area. However, I need the coord_equal command, otherwise the world map would look stretched.

2
specify the size and shape of the figure you want in ggsave - Richard Telford
But this just "zooms" the plot in or out, no? E.g. if I specify width = and height = ..., it chnages the ratios of the plot, but it doesn't crop x pixels on top and x pixels at the bottom. - deschen
If you pick the aspect ratio correctly (to match the plot) the extra margin will go away - Richard Telford
Ok, I played around with it and I can indeed reduce the margin. However, I didn't manage to delete it completely and depending on the wdith/height values, the ratio in the plot of course changes. Since I selected a coord_equal value of 1.3, this should be my aspect ratio for height/width, but that still leaves some margin. - deschen

2 Answers

1
votes

This might work if you adjust the lengths:

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

The order of the margins here is top, right, bottom, left.

1
votes

I recently faced the same problem so here're my solutions for people with the same issue.

tmaptools has a function get_asp_ratio to compute the aspect ratio of spatial objects. We can use that ratio to remove the outer margin of any map.

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)

Alternatively, if we don't want to depend on tmaptools, we can make our own functions with a wrapper around ggsave. This is essentially based on the tmaptools::get_asp_ratio function.

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, ...)
}

We can use the function the same way as ggsave. We only have to specify either the width or height and the function will save the map with the right aspect ratio automatically.

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

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

To remove the inner margin, we can use theme(plot.margin = margin(0, 0, 0, 0)).