Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Crop unused margin in a ggplot plot

Tags:

r

ggplot2

crop

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.

like image 304
deschen Avatar asked Sep 17 '26 09:09

deschen


2 Answers

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.

like image 199
Matthias Avatar answered Sep 19 '26 22:09

Matthias


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

like image 27
Junitar Avatar answered Sep 19 '26 23:09

Junitar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!