Search code examples
rpdfggplot2svgcairo

Inconsistent panel border width when exporting as SVG with Cairo


I am generating figures for a paper in svg format, and when I export the ggplot to .svg, I obtain inconsistent panel border widths depending on the device I use to export. I need to use CairoSVG as some figures have symbols that the standard device does not generate properly.

It does not depend on the data, so here I am showing some dummy examples.

figure = ggplot(mtcars, aes(x = mpg, y = disp)) + 
         geom_point()

ggsave(figure, filename = "./output/figure.svg", 
       width = 2, height = 2)
ggsave(figure, filename = "./output/figure_cairo.svg", 
       device = CairoSVG, width = 2, height = 2)

Output from default svg device: enter image description here Output from CairoSVG device (as you can see, bottom and right borders are wider): enter image description here

The weird thing is that when I edit the CairoSVG output, select the panel and Ungroup the elements, the panel border width becomes consistent. However, the line width is thicker than when using the "default" svg device. enter image description here

Can anyone guess why is this happening and if there is anyway of not having to manually edit the figures after exporting?

It does not happen with pdf/CairoPDF though:

ggsave(figure, filename = "./output/figure.pdf", 
       width = 2, height = 2)
ggsave(figure, filename = "./output/figure_cairo.pdf", 
       device = cairo_pdf(), width = 2, height = 2)

enter image description here

Here is my sessionInfo in case it helps:

sessionInfo()
R version 4.1.1 (2021-08-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19043)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252    LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                           LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] Cairo_1.5-12.2  forcats_0.5.1   stringr_1.4.0   dplyr_1.0.7     purrr_0.3.4     readr_2.0.1     tidyr_1.1.3    
 [8] tibble_3.1.2    ggplot2_3.3.5   tidyverse_1.3.1 biomaRt_2.48.3 

loaded via a namespace (and not attached):
 [1] bitops_1.0-7           fs_1.5.0               lubridate_1.7.10       bit64_4.0.5            filelock_1.0.2        
 [6] progress_1.2.2         httr_1.4.2             GenomeInfoDb_1.28.1    tools_4.1.1            backports_1.2.1       
[11] utf8_1.2.1             R6_2.5.1               DBI_1.1.1              BiocGenerics_0.38.0    colorspace_2.0-2      
[16] withr_2.4.2            tidyselect_1.1.1       prettyunits_1.1.1      bit_4.0.4              curl_4.3.2            
[21] compiler_4.1.1         cli_3.0.1              rvest_1.0.1            Biobase_2.52.0         xml2_1.3.2            
[26] labeling_0.4.2         scales_1.1.1           rappdirs_0.3.3         systemfonts_1.0.2      digest_0.6.27         
[31] rmarkdown_2.10         svglite_2.0.0          XVector_0.32.0         htmltools_0.5.1.1      pkgconfig_2.0.3       
[36] dbplyr_2.1.1           fastmap_1.1.0          rlang_0.4.11           readxl_1.3.1           rstudioapi_0.13       
[41] RSQLite_2.2.7          generics_0.1.0         farver_2.1.0           jsonlite_1.7.2         RCurl_1.98-1.3        
[46] magrittr_2.0.1         GenomeInfoDbData_1.2.6 Rcpp_1.0.7             munsell_0.5.0          S4Vectors_0.30.0      
[51] fansi_0.5.0            lifecycle_1.0.0        yaml_2.2.1             stringi_1.7.3          zlibbioc_1.38.0       
[56] BiocFileCache_2.0.0    grid_4.1.1             blob_1.2.2             parallel_4.1.1         crayon_1.4.1          
[61] Biostrings_2.60.1      haven_2.4.3            hms_1.1.0              KEGGREST_1.32.0        knitr_1.33            
[66] pillar_1.6.2           GenomicRanges_1.44.0   stats4_4.1.1           reprex_2.0.1           XML_3.99-0.6          
[71] glue_1.4.2             evaluate_0.14          modelr_0.1.8           png_0.1-7              vctrs_0.3.8           
[76] tzdb_0.1.2             cellranger_1.1.0       gtable_0.3.0           assertthat_0.2.1       cachem_1.0.5          
[81] xfun_0.24              broom_0.7.9            AnnotationDbi_1.54.1   memoise_2.0.0          IRanges_2.26.0        
[86] ellipsis_0.3.2 

Solution

  • This might just be because of how devices handle clipping masks. If you want the more consistent behaviour, you can try turning of the clipping for panels altogether. Below; a demonstration of how that affects the look of borders.

    library(ggplot2)
    
    p <- ggplot(mtcars, aes(x = mpg, y = disp)) + 
      geom_point() +
      theme(panel.border = element_rect(colour = "black", fill = NA,
                                        size = 5))
    
    p
    

    p + coord_cartesian(clip = "off")
    

    Created on 2021-09-04 by the reprex package (v2.0.1)