trevorld / ggpattern

ggplot geoms with pattern fills
https://trevorldavis.com/R/ggpattern/dev/
Other
356 stars 18 forks source link

[BUG] Pattern fails in pdf figures #105

Closed eliocamp closed 7 months ago

eliocamp commented 7 months ago

Bug description

Patterns fail to render correctly in Evince and Firefox with pdf device.

Evince shows circular patterns with holes as a single square and firefox renders each individual dot very slowly. These problems go away by using cairo_pdf.

Minimal, reproducible example

This knitr document:

---
title: "Untitled"
date: "2023-11-28"
output: pdf_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, 
                      dev = "pdf")

library(ggplot2)
library(ggpattern)
pattern_dots <- ggplot2::ggproto("GeomDots", ggpattern::GeomPolygonPattern)
ggplot2::update_geom_defaults(pattern_dots,
                              list(pattern = "circle",
                                   colour = NA,
                                   pattern_colour = "black",
                                   pattern_fill = "black",
                                   pattern_density = 0.3,
                                   pattern_alpha = 1,
                                   pattern_spacing = 0.02,
                                   fill = NA
                              ))

data <- expand.grid(lon = seq(0, 360, by = 2.5),
                    lat = seq(-90, 0, by = 2.5)) |> 
  transform(h = cos(lat*pi/180*3))

ggplot(data, aes(lon, lat)) +
  geom_contour_filled(aes(z = h)) +
  stat_contour_filled(aes(z = h), 
                      breaks = c(-0.8, .4), fill = NA, geom = pattern_dots) +
  coord_polar()

PDF opened by Evince (v 45.0)

![image](https://github.com/coolbutuseless/ggpattern/assets/8617595/ece3b37d-2786-479f-a29a-702d45380c8b)

Opened by Firefox (v 120)

[Screen record from 2023-11-28 12.32.13.webm](https://github.com/coolbutuseless/ggpattern/assets/8617595/53fd2ca9-0f49-44c4-84e2-08cce7b4c42f)

**Session info**

Please enter here the results of `xfun::session_info("ggpattern")`

``` r
xfun::session_info("ggpattern") 
#> R version 4.3.1 (2023-06-16)
#> Platform: x86_64-pc-linux-gnu (64-bit)
#> Running under: elementary OS 6.1 Jólnir
#> 
#> Locale:
#>   LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#>   LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
#>   LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
#>   LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#>   LC_ADDRESS=C               LC_TELEPHONE=C            
#>   LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
#> 
#> Package version:
#>   cachem_1.0.8       class_7.3.22       classInt_0.4.10    cli_3.6.1         
#>   colorspace_2.1.0   DBI_1.1.3          e1071_1.7.13       fansi_1.0.5       
#>   farver_2.1.1       fastmap_1.1.1      ggpattern_1.0.1    ggplot2_3.4.4.9000
#>   glue_1.6.2         graphics_4.3.1     grDevices_4.3.1    grid_4.3.1        
#>   gridpattern_1.1.0  gtable_0.3.4       isoband_0.2.7      KernSmooth_2.23.21
#>   labeling_0.4.3     lattice_0.21.8     lifecycle_1.0.4    magrittr_2.0.3    
#>   MASS_7.3.60        Matrix_1.6.1.1     memoise_2.0.1      methods_4.3.1     
#>   mgcv_1.8.42        munsell_0.5.0      nlme_3.1.162       pillar_1.9.0      
#>   pkgconfig_2.0.3    png_0.1.8          proxy_0.4.27       R6_2.5.1          
#>   RColorBrewer_1.1.3 Rcpp_1.0.11        rlang_1.1.2        s2_1.1.4          
#>   scales_1.2.1       sf_1.0.14          splines_4.3.1      stats_4.3.1       
#>   tibble_3.2.1       tools_4.3.1        units_0.8.4        utf8_1.2.4        
#>   utils_4.3.1        vctrs_0.6.4        viridisLite_0.4.2  withr_2.5.2       
#>   wk_0.9.0
trevorld commented 7 months ago

A more minimal example:

library(ggplot2)
library(ggpattern)
pattern_dots <- ggplot2::ggproto("GeomDots", ggpattern::GeomPolygonPattern)
ggplot2::update_geom_defaults(pattern_dots,
                              list(pattern = "circle",
                                   colour = NA,
                                   pattern_colour = "black",
                                   pattern_fill = "black",
                                   pattern_density = 0.3,
                                   pattern_alpha = 1,
                                   pattern_spacing = 0.02,
                                   fill = NA
                              ))
data <- expand.grid(lon = seq(0, 360, by = 2.5),
                    lat = seq(-90, 0, by = 2.5)) |> 
  transform(h = cos(lat*pi/180*3))

gg <- ggplot(data, aes(lon, lat)) +
  geom_contour_filled(aes(z = h)) +
  stat_contour_filled(aes(z = h), 
                      breaks = c(-0.8, .4), fill = NA, geom = pattern_dots) +
  coord_polar()

pdf("pdf.pdf")
plot(gg)
invisible(dev.off())

cairo_pdf("cairo.pdf")
plot(gg)
invisible(dev.off())

evince

The evince issue with alpha masks and pdf() is a known bug in poppler: https://github.com/coolbutuseless/ggpattern/issues/70

firefox

I reproduce the firefox issue too. Don't think I can do anything to speed up firefox's rendering of pdf files...

raster fallback

Instead of using R's alpha mask feature you can instead opt into using a rasterized fallback if you set options(ggpattern_use_R4.1_masks = FALSE). If may not look as pretty especially at low resolutions but it may avoid some of the issues you notice. In particular with the default resolution it appears to render faster in firefox and I don't observe the visual bug in evince.

options(ggpattern_use_R4.1_masks = FALSE)
pdf("pdf.pdf")
plot(gg)
invisible(dev.off())