r-spatial / stars

Spatiotemporal Arrays, Raster and Vector Data Cubes
https://r-spatial.github.io/stars/
Apache License 2.0
556 stars 94 forks source link

Visual artefacts when plotting stars objects #573

Closed tcwilkinson closed 1 year ago

tcwilkinson commented 1 year ago

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: https://github.com/r-spatial/stars/commit/3c0b627f08516dec2bb11ab850d311abe5ad991d

## 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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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:

=> 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 commented 1 year ago

Fantastic. I believe I run cairo, as

> capabilities("cairo")
cairo 
 TRUE 
edzer commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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

kadyb commented 1 year ago

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

Edit: With the https://github.com/r-spatial/stars/commit/1fa061e4c25c88653a5b37d652b091442403af22 it seems to work (vignette 2) but macOS is unhappy:

polygon edge not found

https://github.com/tidyverse/ggplot2/issues/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 commented 1 year ago

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 commented 1 year ago

How would you go about remove ragg?

https://github.com/r-spatial/stars/blob/1fa061e4c25c88653a5b37d652b091442403af22/.github/workflows/tic.yml#L110-L111

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.

kadyb commented 1 year ago

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 commented 1 year ago

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

edzer commented 1 year ago

In https://github.com/r-spatial/stars/commit/2af98c364a0cd0b230f0f8056cd20434a993df3c 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 commented 1 year ago

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