Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Visual artefacts when plotting stars objects #573

Closed
tcwilkinson opened this issue Nov 2, 2022 · 17 comments
Closed

Visual artefacts when plotting stars objects #573

tcwilkinson opened this issue Nov 2, 2022 · 17 comments

Comments

@tcwilkinson
Copy link
Contributor

I'm not sure if this should be seen as a bug or just a necessary result of working with certain forms of translation.

I've noticed that plotting stars objects as sf or as curvilinear can result in some distracting visual artefacts (see examples below). I tried to work around, but have not found fix yet.

Suspect that these artefacts are not universal, can depend on graphics device, and device dimensions etc. etc. and won't be created by all datasets, but still don't like them much(!).

Is this a bug, or necessary result of working with rasters in a certain way (e.g. when transformed or warped)?

If the second, does anyone has good advice on how to avoid/reduce the effects of these, either within stars directly or by wrangling the data/plotting functions?


Some examples taken from the vignette docs (https://r-spatial.github.io/stars/articles/stars5.html), as per version: 3c0b627

## loading nc.st by following vignette, see https://r-spatial.github.io/stars/articles/stars5.html
ggplot() + geom_stars(data=nc.st,mapping=aes(fill=dens),sf=T)

image

Here the artifacts involve vertical and horizontal lines, looks like hairline outlines are created by converting each raster cell into polygon, to give a tartan effect. But color=NA and lwd=0 don't seem to help.

## first reated nc.curv following vignette, see  https://r-spatial.github.io/stars/articles/stars5.html
ggplot() + geom_stars(data=nc.curv,mapping=aes(fill=dens),col=NA)

image

Here the artifacts look like circles, but closer in you can see that it looks like rotate hairline border lines or gaps.

image

Attempting to remove these lines with color = NA results in warning (as geom_stars already seems to request this anyway), but changes nothing. lwd=0 (an alternative way of removing polygon borders in ggplot) also has no effect.

ggplot() + geom_stars(data=nc.curv,mapping=aes(fill=dens),color=NA)
## Warning message:
## Duplicated aesthetics after name standardisation: colour

Just for good measure, it's not just ggplot, you can also see these in base plot, though the effect is different, depending on the size of the output.

plot(nc.curv, border = NA, graticule = TRUE)

image

It doesn't seem to be a problem with non-translated regular projected raster in base plot though.

plot(nc.st)

image

@edzer
Copy link
Member

edzer commented Nov 2, 2022

Both look good on my computer, with

> sessionInfo()
R version 4.2.1 (2022-06-23)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 22.04.1 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_GB.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_GB.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_GB.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C       

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

other attached packages:
[1] ggplot2_3.3.6 stars_0.5-7   sf_1.0-9      abind_1.4-5  

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.9         pillar_1.8.1       compiler_4.2.1     class_7.3-20      
 [5] tools_4.2.1        digest_0.6.29      lifecycle_1.0.3    tibble_3.1.8      
 [9] gtable_0.3.1       pkgconfig_2.0.3    rlang_1.0.6        DBI_1.1.3         
[13] cli_3.4.0.9000     parallel_4.2.1     e1071_1.7-11       withr_2.5.0       
[17] dplyr_1.0.9        generics_0.1.3     vctrs_0.4.1        classInt_0.4-8    
[21] grid_4.2.1         tidyselect_1.2.0   glue_1.6.2         R6_2.5.1          
[25] fansi_1.0.3        farver_2.1.1       magrittr_2.0.3     scales_1.2.1      
[29] units_0.8-0        assertthat_0.2.1   colorspace_2.0-3   labeling_0.4.2    
[33] utf8_1.2.2         KernSmooth_2.23-20 proxy_0.4-27       munsell_0.5.0     
[37] lwgeom_0.2-9      

I assume it has something to do with your OS & graphics device combination. What happens if you plot directly to pdf or png?

@tcwilkinson
Copy link
Contributor Author

tcwilkinson commented Nov 3, 2022

That's certainly possible. Although I see similar effects in the pngs toward the end of the page from the generated html vignettes here: https://r-spatial.github.io/stars/articles/stars5.html

I am on macos, details below.

sessionInfo details
R version 4.2.1 (2022-06-23)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Monterey 12.5

Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.2/Resources/lib/libRlapack.dylib

locale:
[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/POSIX/en_GB.UTF-8/en_GB.UTF-8

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

other attached packages:
 [1] prismatic_1.1.1     morphogram_0.3.0    tictoc_1.1         
 [4] ggsn_0.5.0          ggfx_1.0.1          patchwork_1.1.2    
 [7] ggpubr_0.4.0        ggnewscale_0.4.8    ggrepel_0.9.1      
[10] rgbif_3.7.3         rnaturalearth_0.1.0 smoothr_0.2.2      
[13] hillshader_0.1.0    stars_0.5-6         abind_1.4-5        
[16] terra_1.6-34        raster_3.6-3        sp_1.5-0           
[19] lwgeom_0.2-9        sf_1.0-8            forcats_0.5.2      
[22] stringr_1.4.1       dplyr_1.0.10        purrr_0.3.5        
[25] readr_2.1.3         tidyr_1.2.1         tibble_3.1.8       
[28] ggplot2_3.3.6       tidyverse_1.3.2    

loaded via a namespace (and not attached):
  [1] googledrive_2.0.0       colorspace_2.0-3       
  [3] ggsignif_0.6.4          rjson_0.2.21           
  [5] ellipsis_0.3.2          class_7.3-20           
  [7] base64enc_0.1-3         fs_1.5.2               
  [9] httpcode_0.3.0          rstudioapi_0.14        
 [11] proxy_0.4-27            farver_2.1.1           
 [13] urltools_1.7.3          audio_0.1-10           
 [15] fansi_1.0.3             lubridate_1.8.0        
 [17] xml2_1.3.3              codetools_0.2-18       
 [19] doParallel_1.0.17       knitr_1.40             
 [21] jsonlite_1.8.3          broom_1.0.1            
 [23] dbplyr_2.2.1            png_0.1-7              
 [25] oai_0.3.2               compiler_4.2.1         
 [27] httr_1.4.4              backports_1.4.1        
 [29] assertthat_0.2.1        fastmap_1.1.0          
 [31] lazyeval_0.2.2          gargle_1.2.1           
 [33] cli_3.4.1               beepr_1.3              
 [35] htmltools_0.5.3         prettyunits_1.1.1      
 [37] tools_4.2.1             ggmap_3.0.0            
 [39] rnaturalearthdata_0.1.0 gtable_0.3.1           
 [41] glue_1.6.2              Rcpp_1.0.9             
 [43] carData_3.0-5           cellranger_1.1.0       
 [45] vctrs_0.5.0             crul_1.3               
 [47] conditionz_0.1.0        iterators_1.0.14       
 [49] xfun_0.34               rvest_1.0.3            
 [51] lifecycle_1.0.3         rstatix_0.7.0          
 [53] googlesheets4_1.0.1     MASS_7.3-58.1          
 [55] scales_1.2.1            ragg_1.2.4             
 [57] hms_1.1.2               parallel_4.2.1         
 [59] curl_4.3.3              geosphere_1.5-14       
 [61] triebeard_0.3.0         stringi_1.7.8          
 [63] maptools_1.1-5          foreach_1.5.2          
 [65] e1071_1.7-12            rayshader_0.24.10      
 [67] systemfonts_1.0.4       RgoogleMaps_1.4.5.3    
 [69] rlang_1.0.6             pkgconfig_2.0.3        
 [71] bitops_1.0-7            rgl_0.110.2            
 [73] lattice_0.20-45         labeling_0.4.2         
 [75] htmlwidgets_1.5.4       tidyselect_1.2.0       
 [77] plyr_1.8.7              magrittr_2.0.3         
 [79] R6_2.5.1                magick_2.7.3           
 [81] generics_0.1.3          DBI_1.1.3              
 [83] pillar_1.8.1            haven_2.5.1            
 [85] whisker_0.4             foreign_0.8-83         
 [87] withr_2.5.0             units_0.8-0            
 [89] modelr_0.1.9            crayon_1.5.2           
 [91] car_3.1-1               uuid_1.1-0             
 [93] KernSmooth_2.23-20      utf8_1.2.2             
 [95] tzdb_0.3.0              jpeg_0.1-9             
 [97] progress_1.2.2          readxl_1.4.1           
 [99] data.table_1.14.4       reprex_2.0.2           
[101] digest_0.6.30           classInt_0.4-8         
[103] textshaping_0.3.6       munsell_0.5.0          
[105] viridisLite_0.4.1     

Direct to png (or pdf) creates similar hairlines when you look closely:

ggsave("cache/test_nc_curv2.png",ggplot() + geom_stars(data=nc.curv) )
## Saving 7.07 x 4.03 in image

test_nc_curv2

Effect more pronounced when output png is smaller...

ggsave("cache/test_nc_curv72.png",ggplot() + geom_stars(data=nc.curv),width=7,height=4,units="in",dpi=72)

test_nc_curv72

@tcwilkinson
Copy link
Contributor Author

Looking further into geom_stars code, I see that, in these cases, the stars objects are being passed to geom_sf, so the problem is really there.

The problem is from a hairline gap or line that geom_sf is producing between polygons, also visible in original nc sf layer, despite selecting colour=NA and lwd=0:

ggplot() + geom_sf(data=nc,mapping=aes(fill=AREA),col=NA,lwd=0)

image

It doesn't cause a problem for these irregular polygons, although perhaps technically wrong, but with many tiny polygons (which the stars object becomes), then you start getting the artefacts.

@edzer Do these lines also appear for you? (i.e. is this platform / graphic dev specific)

@edzer
Copy link
Member

edzer commented Nov 3, 2022

No, they do not appear for me.

Although I see similar effects in the pngs toward the end of the page from the generated html vignettes here: https://r-spatial.github.io/stars/articles/stars5.html

That vignette was created by the MacOS GitHub actions runner (broken a.t.m.).

@tcwilkinson
Copy link
Contributor Author

tcwilkinson commented Nov 3, 2022

Thanks for checking.

So tha all suggests it is macos graphics device issue then (and not even hidden in geom_sf).

No idea where to chase something like that up! :-( Will look and update this issue if I can find something.

@tcwilkinson
Copy link
Contributor Author

tcwilkinson commented Nov 3, 2022

I now suspect that it has something to do with the ragg graphics engine and its feature of antialiasing fills...

ragg is the only device that provides anti-aliasing of fill, which results in obvious quality differences. The reason for not doing so in cairo is presumably to avoid artefacts when shapes are touching each other where anti-aliasing can result in a thin edge between the two shapes instead of a contiguous colour.

(see https://ragg.r-lib.org/articles/ragg_quality.html#observations )

When I uninstall ragg, and then use the cairo device (e.g. below), the png has no more hairlines:

ggsave("cache/test_nc_curv_noragg.png",ggplot() + geom_stars(data=nc.curv),type="cairo")

test_nc_curv_noragg

Just to compare, I checked alternative settings on RStudio -> Preferences -> General -> Graphics:

  • Quartz with Antialiasing. FAILS (hairline between polygons)
  • Quartz no Antialiasing. WORKS (no hairlines/contiguous polygons) BUT text and other things also not antialiased
  • Cairo PNG with Antialiasing. WORKS (no hairlines/contiguous polygons)
  • Cairo PNG no Antialiasing. WORKS (no hairlines/contiguous polygons) BUT text still antialiased
  • AGG with Antialiasing. FAILS (hairline between polygons)
  • AGG no Antialiasing. FAILS (hairline between polygons) BUT text still antialiased (since AGG always antialiases?)

=> Conclusion, ragg/AGG always antialiases, but this is a problem in case of contiguous polygons which will be very common for plotting stars objects.

Since ragg looks set to be widespread because of its cross-platform and text plotting advantages, this is important to sort out, but can only probably be fixed in ragg itself.


I think this may be related to issues in ragg:


@edzer Just to be sure, can I check what graphics device you have?

@edzer
Copy link
Member

edzer commented Nov 3, 2022

Fantastic. I believe I run cairo, as

> capabilities("cairo")
cairo 
 TRUE 

@edzer
Copy link
Member

edzer commented Nov 4, 2022

Just noticed that we see the artefacts also here which was created by GA on ubunty, afaict here (release). @kadyb do you have any idea how this can be suppressed on GA?

@kadyb
Copy link
Contributor

kadyb commented Nov 4, 2022

I didn't test, but maybe it will help? This needs to be added to RMarkdown.

knitr::opts_knit$set(dev.args = list(type = "cairo"))

edzer added a commit that referenced this issue Nov 4, 2022
@edzer
Copy link
Member

edzer commented Nov 5, 2022

@kadyb as you can see here (printed at the top) the option is set to cairo but the raster artefacts remain in subsequent figures.

edzer added a commit that referenced this issue Nov 5, 2022
@kadyb
Copy link
Contributor

kadyb commented Nov 5, 2022

Another idea is maybe removing the {ragg} package in workflow?

Edit: With the 1fa061e it seems to work (vignette 2) but macOS is unhappy:

polygon edge not found

tidyverse/ggplot2#2252

.onLoad failed in loadNamespace() for 'Cairo', details:
  call: dyn.load(file, DLLpath = DLLpath, ...)
  error: unable to load shared object '/Users/runner/work/_temp/Library/Cairo/libs/Cairo.so':
  dlopen(/Users/runner/work/_temp/Library/Cairo/libs/Cairo.so, 6): Library not loaded: /opt/X11/lib/libXrender.1.dylib
  Referenced from: /Users/runner/work/_temp/Library/Cairo/libs/Cairo.so
  Reason: image not found

Probably XQuartz must be installed.

@edzer
Copy link
Member

edzer commented Nov 5, 2022

CairoPNG did the job, but there are now new artefacts e.g. the figure in this section. How would you go about remove ragg?

What I don't understand is why I cannot get the artefacts on my own computer, Ubuntu, with ragg installed, and the default (png) knitr driver, but they arise on GA.

@kadyb
Copy link
Contributor

kadyb commented Nov 5, 2022

How would you go about remove ragg?

- name: "[Stage] Deploy"
run: Rscript -e "tic::deploy()"

run: Rscript -e "remove.packages('ragg')" -e "tic::deploy()"

What I don't understand is why I cannot get the artefacts on my own computer, Ubuntu, with ragg installed, and the default (png) knitr driver, but they arise on GA.

For me locally on Windows and Ubuntu using Cairo the plots look good.

edzer added a commit that referenced this issue Nov 5, 2022
@kadyb
Copy link
Contributor

kadyb commented Nov 5, 2022

It wasn't the best idea. Now we get this error: there is no package called ‘ragg’ from {pkgdown}. {ragg} is required by {pkgdown} by default. Rather, we should change this in the _pkgdown.yml configuration file: https://pkgdown.r-lib.org/reference/build_articles.html#figures

edzer added a commit that referenced this issue Nov 5, 2022
edzer added a commit that referenced this issue Nov 5, 2022
@edzer edzer closed this as completed in 048f96f Nov 5, 2022
@edzer
Copy link
Member

edzer commented Nov 5, 2022

Thanks @kadyb and @tcwilkinson ! The advice is to stay away from using ragg::agg_png(), which is the default in pkgdown.

@edzer
Copy link
Member

edzer commented Dec 30, 2022

In 2af98c3 I added a _pkgdown.yml file that makes the examples use png() rather than agg_png(); in the last example here we still see that that doesn't work everywhere, as

> agg_png("/tmp/x.png")
> dev.capabilities()$rasterImage
[1] NA

where

> png("/tmp/x.png")
> dev.capabilities()$rasterImage
[1] "yes"

@edzer
Copy link
Member

edzer commented Dec 30, 2022

Also, the examples there show that png() has its own challenges...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants