# Load the US shapefile
states <- st_as_sf(maps::map("state", plot = FALSE, fill = TRUE))
p <- states %>%
ggplot() +
geom_sf(size = 0.25) + #<<
coord_sf(crs = 2163) +
theme(
panel.border = element_blank(),
axis.text = element_blank(),
panel.grid = element_blank(),
axis.ticks = element_blank(),
plot.background = element_rect(fill = "#3c3c3c"),
panel.background = element_rect(fill = "#3c3c3c")
)
p
Recently I was participating in the 30DayMapChallenge where people were invited to make a map based on a different daily theme for one whole month.
Announcing #30DayMapChallenge in November 2019! Create a map each day of the month with the following themes πππ
β Topi Tjukanov (@tjukanov) October 25, 2019
No restriction on tools. All maps should be created by you. Doing less than 30 maps is fine. #gischat #geography #cartography #dataviz pic.twitter.com/6Go4VFWcJB
When making a geographical map, or any other visualization where I wanted to use a forced coordinate system), choosing the right aspect ratio to save my graphics has always been challenging. Lately, when participating in the map challenge, CΓ©dric Scherer made me realize that I was really struggling with white borders around my plots when it came the time to export them. He was right! :smile:
One question though: always wondering about your white space, do you not care and avoid to play around with the aspect ratio or is it on purpose?
β CΓ©dric Scherer (@CedScherer) December 9, 2019
The problem with choosing the right aspect ratio
Letβs make a simple map of the USA to illustrate the problem. In a markdown document, the generated graph looks good (i.e. no extra border) because knitr
is taking care of this for me (more on that later).
When it comes time to save my plots, I usually use the PDF format file unless they contain too much point. In that case, I will use the PNG format. When saving a graph in a file, however, it is difficult to find the right aspect ratio when using coordinate system that forces a specified ratio between the physical representation of data units on the axes (ex.: coord_fixed()
, geom_sf()
or coord_equal()
). To visualize the problem, I will save the previous plot using two different aspect ratios and then import them in my document to show you the difficulty of finding the right aspect ratio.
Aspect ratio of 7/4
Choosing an aspect ratio of 7/4 creates white borders on the sides of the plot.
file <- "img/fig_border_7_4.png"
ggsave(
file,
plot = p,
type = "cairo",
device = "png",
dpi = 600,
width = 7,
height = 4
)
Aspect ratio of 6/7
Choosing an aspect ratio of 6/7 creates white borders at the bottom and the top of the plot.
file <- "img/fig_border_6_7.png"
ggsave(
file,
plot = p,
type = "cairo",
device = "png",
dpi = 600,
width = 6,
height = 7
)
As it can be seen in the two figures above, there are two large white borders located either on the sides or above/below of the graph. It is because I have used geom_sf()
which set automatically the aspect ratio of the plot to respect the chosen geographical coordinate system. Of course, I could play around with trials and errors to find the best width and hight to use to save my plot.
But wait! There is a much better way to do it! :smirk: Actually, I found out there was a hidden gem in knitr
that allows cropping (using either pdfcrop or convert functions) to remove borders around an image. In fact, this is the function that is used to automatically remove borders around images when knitting an R Markdown document in R (see the initial plot of this post without borders). The function knitr::plot_crop(x)
(where x is the filename of the plot to be cropped) will trim any existing images on your hard drive.
First, letβs create our plot in PDF format and use knitr::plot_crop()
to remove the borders.
pdf_file <- "img/fig_border.pdf"
ggsave(
pdf_file,
device = cairo_pdf,
width = 5.51,
height = 4.68
)
knitr::plot_crop(pdf_file)
#> [1] "img/fig_border.pdf"
At this point, the borders have been removed from the original PDF. But what if you want to export this PDF into a bitmap image? This can be achieved using a combination of pdftools::pdf_render_page()
and png::writePNG()
. pdftools::pdf_render_page()
will take the filename of a PDF file and render into a raw bitmap array whereas png::writePNG()
will actually save the bitmap into a file.
png_file <- "img/fig_border_cropped.png"
bitmap <- pdftools::pdf_render_page(pdf_file, dpi = 600)
png::writePNG(bitmap, png_file)
Bang! No more borders around our plot π
Session info
#> β Session info βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
#> setting value
#> version R version 4.4.0 (2024-04-24)
#> os Ubuntu 24.04 LTS
#> system x86_64, linux-gnu
#> ui X11
#> language en_CA:en
#> collate en_CA.UTF-8
#> ctype en_CA.UTF-8
#> tz America/Toronto
#> date 2024-05-02
#> pandoc 3.1.3 @ /usr/bin/ (via rmarkdown)
#>
#> β Packages βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
#> ! package * version date (UTC) lib source
#> P askpass 1.2.0 2023-09-03 [?] RSPM (R 4.4.0)
#> P cachem 1.0.8 2023-05-01 [?] RSPM (R 4.4.0)
#> P class 7.3-22 2023-05-03 [?] CRAN (R 4.4.0)
#> P classInt 0.4-10 2023-09-05 [?] RSPM (R 4.4.0)
#> P cli 3.6.2 2023-12-11 [?] RSPM (R 4.4.0)
#> P colorspace 2.1-0 2023-01-23 [?] RSPM (R 4.4.0)
#> P DBI 1.2.2 2024-02-16 [?] RSPM (R 4.4.0)
#> P devtools 2.4.5 2022-10-11 [?] RSPM
#> P digest 0.6.35 2024-03-11 [?] RSPM (R 4.4.0)
#> P dplyr * 1.1.4 2023-11-17 [?] RSPM (R 4.4.0)
#> P e1071 1.7-14 2023-12-06 [?] RSPM (R 4.4.0)
#> P ellipsis 0.3.2 2021-04-29 [?] RSPM (R 4.4.0)
#> P evaluate 0.23 2023-11-01 [?] RSPM (R 4.4.0)
#> P extrafont 0.19 2023-01-18 [?] RSPM (R 4.4.0)
#> P extrafontdb 1.0 2012-06-11 [?] RSPM (R 4.4.0)
#> P fansi 1.0.6 2023-12-08 [?] RSPM (R 4.4.0)
#> P farver 2.1.1 2022-07-06 [?] CRAN (R 4.4.0)
#> P fastmap 1.1.1 2023-02-24 [?] RSPM (R 4.4.0)
#> P forcats * 1.0.0 2023-01-29 [?] RSPM (R 4.4.0)
#> P fs 1.6.4 2024-04-25 [?] CRAN (R 4.4.0)
#> P generics 0.1.3 2022-07-05 [?] RSPM (R 4.4.0)
#> P ggplot2 * 3.5.1 2024-04-23 [?] RSPM (R 4.4.0)
#> P ggpmthemes * 0.0.2 2024-05-02 [?] Github (pmassicotte/ggpmthemes@993d61e)
#> P glue 1.7.0 2024-01-09 [?] RSPM (R 4.4.0)
#> P gtable 0.3.5 2024-04-22 [?] RSPM (R 4.4.0)
#> P hms 1.1.3 2023-03-21 [?] RSPM (R 4.4.0)
#> P htmltools 0.5.8.1 2024-04-04 [?] RSPM (R 4.4.0)
#> P htmlwidgets 1.6.4 2023-12-06 [?] RSPM
#> P httpuv 1.6.15 2024-03-26 [?] RSPM (R 4.4.0)
#> P jsonlite 1.8.8 2023-12-04 [?] RSPM (R 4.4.0)
#> P KernSmooth 2.23-22 2023-07-10 [?] CRAN (R 4.4.0)
#> P knitr 1.46 2024-04-06 [?] RSPM (R 4.4.0)
#> P later 1.3.2 2023-12-06 [?] RSPM (R 4.4.0)
#> P lifecycle 1.0.4 2023-11-07 [?] RSPM (R 4.4.0)
#> P lubridate * 1.9.3 2023-09-27 [?] RSPM (R 4.4.0)
#> P magrittr 2.0.3 2022-03-30 [?] RSPM (R 4.4.0)
#> P maps 3.4.2 2023-12-15 [?] RSPM (R 4.4.0)
#> P memoise 2.0.1 2021-11-26 [?] RSPM (R 4.4.0)
#> P mime 0.12 2021-09-28 [?] RSPM (R 4.4.0)
#> P miniUI 0.1.1.1 2018-05-18 [?] RSPM (R 4.4.0)
#> P munsell 0.5.1 2024-04-01 [?] CRAN (R 4.4.0)
#> P pdftools 3.4.0 2023-09-25 [?] RSPM (R 4.4.0)
#> P pillar 1.9.0 2023-03-22 [?] RSPM (R 4.4.0)
#> P pkgbuild 1.4.4 2024-03-17 [?] RSPM (R 4.4.0)
#> P pkgconfig 2.0.3 2019-09-22 [?] RSPM (R 4.4.0)
#> P pkgload 1.3.4 2024-01-16 [?] RSPM
#> P png 0.1-8 2022-11-29 [?] RSPM (R 4.4.0)
#> P processx 3.8.4 2024-03-16 [?] RSPM (R 4.4.0)
#> P profvis 0.3.8 2023-05-02 [?] RSPM
#> P promises 1.3.0 2024-04-05 [?] RSPM (R 4.4.0)
#> P proxy 0.4-27 2022-06-09 [?] RSPM (R 4.4.0)
#> P ps 1.7.6 2024-01-18 [?] RSPM (R 4.4.0)
#> P purrr * 1.0.2 2023-08-10 [?] RSPM (R 4.4.0)
#> P qpdf 1.3.3 2024-03-25 [?] RSPM (R 4.4.0)
#> P quarto * 1.4 2024-03-06 [?] RSPM
#> P R.cache 0.16.0 2022-07-21 [?] RSPM
#> P R.methodsS3 1.8.2 2022-06-13 [?] RSPM
#> P R.oo 1.26.0 2024-01-24 [?] RSPM
#> P R.utils 2.12.3 2023-11-18 [?] RSPM
#> P R6 2.5.1 2021-08-19 [?] RSPM (R 4.4.0)
#> P ragg 1.3.0 2024-03-13 [?] RSPM
#> P Rcpp 1.0.12 2024-01-09 [?] RSPM (R 4.4.0)
#> P readr * 2.1.5 2024-01-10 [?] RSPM (R 4.4.0)
#> P remotes 2.5.0 2024-03-17 [?] RSPM
#> P renv 1.0.7 2024-04-11 [?] RSPM (R 4.4.0)
#> P rlang 1.1.3 2024-01-10 [?] RSPM (R 4.4.0)
#> P rmarkdown 2.26 2024-03-05 [?] RSPM (R 4.4.0)
#> P rstudioapi 0.16.0 2024-03-24 [?] RSPM
#> P Rttf2pt1 1.3.12 2023-01-22 [?] RSPM (R 4.4.0)
#> P scales 1.3.0 2023-11-28 [?] CRAN (R 4.4.0)
#> P sessioninfo 1.2.2 2021-12-06 [?] RSPM
#> P sf * 1.0-16 2024-03-24 [?] RSPM (R 4.4.0)
#> P shiny 1.8.1.1 2024-04-02 [?] RSPM (R 4.4.0)
#> P stringi 1.8.3 2023-12-11 [?] RSPM (R 4.4.0)
#> P stringr * 1.5.1 2023-11-14 [?] RSPM (R 4.4.0)
#> P styler * 1.10.3 2024-04-07 [?] RSPM
#> P systemfonts 1.0.6 2024-03-07 [?] RSPM (R 4.4.0)
#> P textshaping 0.3.7 2023-10-09 [?] RSPM
#> P tibble * 3.2.1 2023-03-20 [?] RSPM (R 4.4.0)
#> P tidyr * 1.3.1 2024-01-24 [?] RSPM (R 4.4.0)
#> P tidyselect 1.2.1 2024-03-11 [?] RSPM (R 4.4.0)
#> P tidyverse * 2.0.0 2023-02-22 [?] RSPM (R 4.4.0)
#> P timechange 0.3.0 2024-01-18 [?] RSPM (R 4.4.0)
#> P tinytex 0.50 2024-03-16 [?] RSPM (R 4.4.0)
#> P tzdb 0.4.0 2023-05-12 [?] RSPM (R 4.4.0)
#> P units 0.8-5 2023-11-28 [?] RSPM (R 4.4.0)
#> P urlchecker 1.0.1 2021-11-30 [?] RSPM
#> P usethis 2.2.3 2024-02-19 [?] RSPM
#> P utf8 1.2.4 2023-10-22 [?] RSPM (R 4.4.0)
#> P vctrs 0.6.5 2023-12-01 [?] RSPM (R 4.4.0)
#> P withr 3.0.0 2024-01-16 [?] RSPM (R 4.4.0)
#> P xfun 0.43 2024-03-25 [?] RSPM (R 4.4.0)
#> P xtable 1.8-4 2019-04-21 [?] RSPM (R 4.4.0)
#> P yaml 2.3.8 2023-12-11 [?] RSPM (R 4.4.0)
#>
#> [1] /tmp/RtmpEjPIPN/renv-use-libpath-2dff356b38eac0
#> [2] /home/filoche/.cache/R/renv/sandbox/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/a71ef467
#>
#> P ββ Loaded and on-disk path mismatch.
#>
#> ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ