tylermorganwall / rayshader

R Package for 2D and 3D mapping and data visualization
https://www.rayshader.com/
2.06k stars 214 forks source link

render_compass() and render_label() not showing [PATCH] #204

Closed HenrikBengtsson closed 2 years ago

HenrikBengtsson commented 2 years ago

Issue

render_compass() may silently return without generating a compass. A reproducible example is:

library(rayshader)

dem <- geoviz::mapzen_dem(37.4611, -121.8646, square_km = 1.0, max_tiles = 20L)

heightmap <- matrix(
  raster::extract(dem, raster::extent(dem), method = "bilinear"),
  nrow = ncol(dem),
  ncol = nrow(dem)
)

plot_3d(
  hillshade = sphere_shade(heightmap),
  heightmap = heightmap,
  shadow = FALSE  ## required for bug
)

## Does not work; there's nothing added. There's no warning or error
render_compass()

Attachment: dem.zip - dem.rds in case online data changes.

Troubleshooting

After some debugging, I tracked it down to one of the (x,y,z) coordinates passed to rgl is NaN, which can be seen as:

trace(render_compass, at = list(c(6,3,5)), tracer = quote({ print(xyz_range); }), print = FALSE)
render_compass()
#>         x   y      z
#> [1,] -388 NaN -388.5
#> [2,]  389 NaN  389.5

Patch

I think there's a missing na.rm = TRUE for range() when calculating xyz_range;

diff --git a/R/render_compass.R b/R/render_compass.R
index ac17f00..3618ea4 100644
--- a/R/render_compass.R
+++ b/R/render_compass.R
@@ -117,7 +117,7 @@ render_compass = function(angle = 0, position = "SE",
       id_base = get_ids_with_labels("surface_tris")$id
     }
     fullverts = rgl::rgl.attrib(id_base,"vertices")
-    xyz_range = apply(fullverts,2,range)
+    xyz_range = apply(fullverts,2,range,na.rm=TRUE)
     widths = xyz_range[2,c(1,3)] - xyz_range[1,c(1,3)]
     maxwidth = max(widths) 
     compass_radius = c(maxwidth/10,maxwidth/10,maxwidth/10)
@@ -139,7 +139,7 @@ render_compass = function(angle = 0, position = "SE",
     } else {
       fullverts = rgl::rgl.attrib(id_shadow,"vertices")
     }
-    xyz_range = apply(fullverts,2,range) * scale_distance * 
+    xyz_range = apply(fullverts,2,range,na.rm=TRUE) * scale_distance * 
       matrix(c(1,1,1/scale_distance,1/scale_distance,1,1),ncol=3,nrow=2)
     radial_dist = sqrt((xyz_range[1,1] - radius)^2 + (xyz_range[1,3] - radius)^2)
     y = xyz_range[2,2]

Session info

I'm using rayshader from GitHub:

GithubRepo: rayshader
GithubUsername: tylermorganwall
GithubRef: HEAD
GithubSHA1: dc1bb008d378d397fe7f57ac1732b999af70e5e1

with

> sessionInfo()
R version 4.1.2 Patched (2021-11-01 r81123)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.6 LTS

Matrix products: default
BLAS:   /home/hb/software/R-devel/R-4-1-branch/lib/R/lib/libRblas.so
LAPACK: /home/hb/software/R-devel/R-4-1-branch/lib/R/lib/libRlapack.so

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

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

other attached packages:
[1] rayshader_0.26.8

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.8        Rttf2pt1_1.3.9    raster_3.5-11     knitr_1.37       
 [5] magrittr_2.0.1    hms_1.1.1         progress_1.2.2    doParallel_1.0.16
 [9] lattice_0.20-45   R6_2.5.1          rlang_0.99.0.9003 fastmap_1.1.0    
[13] foreach_1.5.1     tools_4.1.2       grid_4.1.2        parallel_4.1.2   
[17] xfun_0.29         png_0.1-7         terra_1.5-12      cli_3.1.0        
[21] extrafontdb_1.0   htmltools_0.5.2   iterators_1.0.13  ellipsis_0.3.2   
[25] digest_0.6.29     rgl_0.108.3       lifecycle_1.0.1   pkgdown_2.0.2    
[29] crayon_1.4.2      fs_1.5.2          htmlwidgets_1.5.4 vctrs_0.3.8      
[33] codetools_0.2-18  cachem_1.0.6      memoise_2.0.1     sp_1.4-6         
[37] compiler_4.1.2    prettyunits_1.1.1 extrafont_0.17    jsonlite_1.7.3   
[41] pkgconfig_2.0.3  

BugWhisperingAsUsual

HenrikBengtsson commented 2 years ago

There's a similar problem with render_label(). The patch is:

diff --git a/R/render_label.R b/R/render_label.R
index 7dbb76b..240f005 100644
--- a/R/render_label.R
+++ b/R/render_label.R
@@ -115,7 +115,7 @@ render_label = function(heightmap, text, lat, long, altitude=NULL, extent=NULL,
       z = altitude
     }
     if(is.null(z)) {
-      z = max(heightmap)*1.1
+      z = max(heightmap,na.rm=TRUE)*1.1
     }
     if(is.null(extent) && (!missing(lat) || !missing(long)) && (!is.null(x) && !is.null(y))) {
       stop("extent required when using lat/long instead of x/y")
tylermorganwall commented 2 years ago

Thanks for the bug report! This will be fixed in the next update.

tylermorganwall commented 2 years ago

Fixed in 89119188054b9c38c09b49ffdc28a6d632f24f3f.