rsbivand / rgrass

Interpreted interface between the GRASS geographical information system and R
https://rsbivand.github.io/rgrass/
24 stars 8 forks source link

Experimenting with reading straight from the GRASS database #75

Closed florisvdh closed 2 weeks ago

florisvdh commented 1 year ago

With read_RAST() and read_VECT() GRASS is currently instructed to write a temp file using a {v,r}.out.* module, which may cause extra overhead and take disk space. It may be shortcut by using the GDAL-GRASS GIS driver to read from the GRASS database. This is a standalone driver.

Current results from experimenting at the GRASS Community Meeting in Prague:

# If the drivers were compiled & installed from source 
# (https://github.com/OSGeo/gdal-grass), run:
# Sys.setenv(GDAL_DRIVER_PATH="/usr/lib/gdalplugins")
#
# But if installed from the ubuntugis-unstable PPA (`apt install libgdal-grass`),
# then it will just work out-of-the-box on Ubuntu
# See https://repology.org/project/gdal-grass/versions for other distros.

library(terra)
#> terra 1.7.29
library(rgrass)
#> Loading required package: XML
#> GRASS GIS interface loaded with GRASS version: (GRASS not running)

gdal(drivers = TRUE) |> 
  tibble::as_tibble() |> 
  dplyr::filter(stringr::str_detect(name, "GRASS|grass"))
#> # A tibble: 3 × 5
#>   name           type   can   vsi   long.name           
#>   <chr>          <chr>  <chr> <lgl> <chr>               
#> 1 GRASS          raster read  FALSE GRASS Rasters (7+)  
#> 2 GRASSASCIIGrid raster read  TRUE  GRASS ASCII Grid    
#> 3 OGR_GRASS      vector read  FALSE GRASS Vectors (5.7+)

initGRASS(
  home=tempdir(), 
  gisDbase="/home/floris/grassdata", 
  location="nc_basic_spm_grass7", 
  mapset="PERMANENT", 
  override=TRUE
  )
#> No gisBase set. Trying to detect from the GRASS_INSTALLATION environment variable.
#> No GRASS_INSTALLATION environment variable was found.
#> Trying to set gisBase by running command `grass --config path` (requires grass in the system PATH).
#> Taking gisBase value from `grass --config path` output: /usr/lib/grass82
#> gisdbase    /home/floris/grassdata 
#> location    nc_basic_spm_grass7 
#> mapset      PERMANENT 
#> rows        1350 
#> columns     1500 
#> north       228500 
#> south       215000 
#> west        630000 
#> east        645000 
#> nsres       10 
#> ewres       10 
#> projection:
#>  PROJCRS["NAD83(HARN) / North Carolina",
#>     BASEGEOGCRS["NAD83(HARN)",
#>         DATUM["NAD83 (High Accuracy Reference Network)",
#>             ELLIPSOID["GRS 1980",6378137,298.257222101,
#>                 LENGTHUNIT["metre",1]]],
#>         PRIMEM["Greenwich",0,
#>             ANGLEUNIT["degree",0.0174532925199433]],
#>         ID["EPSG",4152]],
#>     CONVERSION["SPCS83 North Carolina zone (meters)",
#>         METHOD["Lambert Conic Conformal (2SP)",
#>             ID["EPSG",9802]],
#>         PARAMETER["Latitude of false origin",33.75,
#>             ANGLEUNIT["degree",0.0174532925199433],
#>             ID["EPSG",8821]],
#>         PARAMETER["Longitude of false origin",-79,
#>             ANGLEUNIT["degree",0.0174532925199433],
#>             ID["EPSG",8822]],
#>         PARAMETER["Latitude of 1st standard parallel",36.1666666666667,
#>             ANGLEUNIT["degree",0.0174532925199433],
#>             ID["EPSG",8823]],
#>         PARAMETER["Latitude of 2nd standard parallel",34.3333333333333,
#>             ANGLEUNIT["degree",0.0174532925199433],
#>             ID["EPSG",8824]],
#>         PARAMETER["Easting at false origin",609601.22,
#>             LENGTHUNIT["metre",1],
#>             ID["EPSG",8826]],
#>         PARAMETER["Northing at false origin",0,
#>             LENGTHUNIT["metre",1],
#>             ID["EPSG",8827]]],
#>     CS[Cartesian,2],
#>         AXIS["easting (X)",east,
#>             ORDER[1],
#>             LENGTHUNIT["metre",1]],
#>         AXIS["northing (Y)",north,
#>             ORDER[2],
#>             LENGTHUNIT["metre",1]],
#>     USAGE[
#>         SCOPE["Engineering survey, topographic mapping."],
#>         AREA["United States (USA) - North Carolina - counties of Alamance; Alexander; Alleghany; Anson; Ashe; Avery; Beaufort; Bertie; Bladen; Brunswick; Buncombe; Burke; Cabarrus; Caldwell; Camden; Carteret; Caswell; Catawba; Chatham; Cherokee; Chowan; Clay; Cleveland; Columbus; Craven; Cumberland; Currituck; Dare; Davidson; Davie; Duplin; Durham; Edgecombe; Forsyth; Franklin; Gaston; Gates; Graham; Granville; Greene; Guilford; Halifax; Harnett; Haywood; Henderson; Hertford; Hoke; Hyde; Iredell; Jackson; Johnston; Jones; Lee; Lenoir; Lincoln; Macon; Madison; Martin; McDowell; Mecklenburg; Mitchell; Montgomery; Moore; Nash; New Hanover; Northampton; Onslow; Orange; Pamlico; Pasquotank; Pender; Perquimans; Person; Pitt; Polk; Randolph; Richmond; Robeson; Rockingham; Rowan; Rutherford; Sampson; Scotland; Stanly; Stokes; Surry; Swain; Transylvania; Tyrrell; Union; Vance; Wake; Warren; Washington; Watauga; Wayne; Wilkes; Wilson; Yadkin; Yancey."],
#>         BBOX[33.83,-84.33,36.59,-75.38]],
#>     ID["EPSG",3358]]

## RASTERS

# g.findfile hint comes from Vaclav Petras
filename_ras <- "elevation"
elevation_path_for_gdalgrass <- execGRASS(
  "g.findfile", 
  element = "cellhd", 
  file = filename_ras, 
  intern = TRUE,
  mapset = "PERMANENT"
  )[4]
elevation_path_for_gdalgrass <- regmatches(
  elevation_path_for_gdalgrass, 
  regexpr("(?<==['\"]).+(?=['\"]$)", elevation_path_for_gdalgrass, perl = TRUE)
  )
elevation_path_for_gdalgrass
#> [1] "/home/floris/grassdata/nc_basic_spm_grass7/PERMANENT/cellhd/elevation"

res <- rast(elevation_path_for_gdalgrass)
res
#> class       : SpatRaster 
#> dimensions  : 1350, 1500, 1  (nrow, ncol, nlyr)
#> resolution  : 10, 10  (x, y)
#> extent      : 630000, 645000, 215000, 228500  (xmin, xmax, ymin, ymax)
#> coord. ref. : +proj=lcc +lat_0=33.75 +lon_0=-79 +lat_1=36.1666666666667 +lat_2=34.3333333333333 +x_0=609601.22 +y_0=0 +ellps=GRS80 +units=m +no_defs 
#> source      : elevation 
#> color table : 1 
#> name        : elevation 
#> min value   :  55.57879 
#> max value   : 156.32986
inMemory(res)
#> [1] FALSE
# describe(elevation_path_for_gdalgrass)

stars::read_stars(elevation_path_for_gdalgrass)
#> stars object with 2 dimensions and 1 attribute
#> attribute(s), summary of first 1e+05 cells:
#>    elevation    
#>  121    : 2113  
#>  126    : 2086  
#>  133    : 1757  
#>  134    : 1645  
#>  135    : 1462  
#>  (Other): 7823  
#>  NA's   :83114  
#> dimension(s):
#>   from   to offset delta                       refsys x/y
#> x    1 1500 630000    10 +proj=lcc +lat_0=33.75 +l... [x]
#> y    1 1350 228500   -10 +proj=lcc +lat_0=33.75 +l... [y]
stars::read_stars(elevation_path_for_gdalgrass, proxy = TRUE)
#> stars_proxy object with 1 attribute in 1 file(s):
#> $elevation
#> [1] "[...]/elevation"
#> 
#> dimension(s):
#>   from   to offset delta                       refsys x/y
#> x    1 1500 630000    10 +proj=lcc +lat_0=33.75 +l... [x]
#> y    1 1350 228500   -10 +proj=lcc +lat_0=33.75 +l... [y]

## VECTORS

filename_vec <- "zipcodes"
zipcodes_path_for_gdalgrass <- execGRASS(
  "g.findfile", 
  element = "vector", 
  file = filename_vec, 
  intern = TRUE,
  mapset = "PERMANENT"
)[4]
zipcodes_path_for_gdalgrass <- regmatches(
  zipcodes_path_for_gdalgrass, 
  regexpr("(?<==['\"]).+(?=['\"]$)", zipcodes_path_for_gdalgrass, perl = TRUE)
) |> 
  paste0("/head")
zipcodes_path_for_gdalgrass
#> [1] "/home/floris/grassdata/nc_basic_spm_grass7/PERMANENT/vector/zipcodes/head"

vect(zipcodes_path_for_gdalgrass, layer = "zipcodes")
#> Warning in p@ptr$read(x, layer, query, extent, filter, proxy, what): GDAL Error
#> 1: Cannot reset cursor.
#> Warning in p@ptr$read(x, layer, query, extent, filter, proxy, what): GDAL Error
#> 1: Attributes not found.
#>  class       : SpatVector 
#>  geometry    : polygons 
#>  dimensions  : 48, 12  (geometries, attributes)
#>  extent      : 610047.9, 677060.7, 196327.5, 258102.6  (xmin, xmax, ymin, ymax)
#>  source      : head (zipcodes)
#>  coord. ref. : +proj=lcc +lat_0=33.75 +lon_0=-79 +lat_1=36.1666666666667 +lat_2=34.3333333333333 +x_0=609601.22 +y_0=0 +ellps=GRS80 +units=m +no_defs 
#>  names       :   cat OBJECTID WAKE_ZIPCO PERIMETER ZIPCODE_ ZIPCODE_ID
#>  type        : <int>    <int>      <num>     <num>    <num>      <num>
#>  values      :     1        1  2.625e+08 8.075e+04        2         27
#>                    2        2  3.163e+07 3.106e+04        7         25
#>                    3        3   5.44e+08 1.153e+05        8         20
#>      ZIPNAME    ZIPNUM           ZIPCODE        NAME SHAPE_Leng SHAPE_Area
#>        <chr>     <num>             <chr>       <chr>      <num>      <num>
#>    CREEDMOOR 2.752e+04   CREEDMOOR 27522   CREEDMOOR  8.078e+04  2.624e+08
#>  YOUNGSVILLE  2.76e+04 YOUNGSVILLE 27596 YOUNGSVILLE  3.106e+04  3.163e+07
#>      RALEIGH 2.762e+04     RALEIGH 27615     RALEIGH  1.153e+05   5.44e+08

sf::st_read(zipcodes_path_for_gdalgrass, layer = "zipcodes")
#> Reading layer `zipcodes' from data source 
#>   `/home/floris/grassdata/nc_basic_spm_grass7/PERMANENT/vector/zipcodes/head' 
#>   using driver `OGR_GRASS'
#> Simple feature collection with 48 features and 12 fields
#> Geometry type: POLYGON
#> Dimension:     XY
#> Bounding box:  xmin: 610047.9 ymin: 196327.5 xmax: 677060.7 ymax: 258102.6
#> CRS:           NA

sf::sf_extSoftVersion()
#>           GEOS           GDAL         proj.4 GDAL_with_GEOS     USE_PROJ_H 
#>       "3.11.1"        "3.6.2"        "9.1.1"         "true"         "true" 
#>           PROJ 
#>        "9.1.1"
terra::gdal()
#> [1] "3.6.2"

Created on 2023-06-05 with reprex v2.0.2

Session info ``` r sessioninfo::session_info() #> ─ Session info ─────────────────────────────────────────────────────────────── #> setting value #> version R version 4.3.0 (2023-04-21) #> os Linux Mint 21.1 #> system x86_64, linux-gnu #> ui X11 #> language nl_BE:nl #> collate nl_BE.UTF-8 #> ctype nl_BE.UTF-8 #> tz Europe/Brussels #> date 2023-06-05 #> pandoc 2.19.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown) #> #> ─ Packages ─────────────────────────────────────────────────────────────────── #> package * version date (UTC) lib source #> abind 1.4-5 2016-07-21 [3] CRAN (R 4.2.0) #> class 7.3-22 2023-05-03 [3] RSPM (R 4.2.0) #> classInt 0.4-9 2023-02-28 [3] RSPM (R 4.2.0) #> cli 3.6.1 2023-03-23 [3] RSPM (R 4.2.0) #> codetools 0.2-19 2023-02-01 [3] RSPM (R 4.2.0) #> DBI 1.1.3 2022-06-18 [3] RSPM (R 4.2.0) #> digest 0.6.31 2022-12-11 [3] RSPM (R 4.2.0) #> dplyr 1.1.2 2023-04-20 [3] RSPM (R 4.2.0) #> e1071 1.7-13 2023-02-01 [3] RSPM (R 4.2.0) #> evaluate 0.21 2023-05-05 [3] RSPM (R 4.2.0) #> fansi 1.0.4 2023-01-22 [3] RSPM (R 4.2.0) #> fastmap 1.1.1 2023-02-24 [3] RSPM (R 4.2.0) #> fs 1.6.2 2023-04-25 [3] RSPM (R 4.2.0) #> generics 0.1.3 2022-07-05 [3] RSPM (R 4.2.0) #> glue 1.6.2 2022-02-24 [3] RSPM (R 4.2.0) #> htmltools 0.5.5 2023-03-23 [3] RSPM (R 4.2.0) #> KernSmooth 2.23-21 2023-05-03 [3] RSPM (R 4.2.0) #> knitr 1.43 2023-05-25 [3] RSPM (R 4.2.0) #> lifecycle 1.0.3 2022-10-07 [3] RSPM (R 4.2.0) #> lwgeom 0.2-13 2023-05-22 [3] RSPM (R 4.2.0) #> magrittr 2.0.3 2022-03-30 [3] RSPM (R 4.2.0) #> pillar 1.9.0 2023-03-22 [3] RSPM (R 4.2.0) #> pkgconfig 2.0.3 2019-09-22 [3] CRAN (R 4.0.1) #> proxy 0.4-27 2022-06-09 [3] RSPM (R 4.2.0) #> purrr 1.0.1 2023-01-10 [3] RSPM (R 4.2.0) #> R.cache 0.16.0 2022-07-21 [3] RSPM (R 4.2.0) #> R.methodsS3 1.8.2 2022-06-13 [3] RSPM (R 4.2.0) #> R.oo 1.25.0 2022-06-12 [3] RSPM (R 4.2.0) #> R.utils 2.12.2 2022-11-11 [3] RSPM (R 4.2.0) #> R6 2.5.1 2021-08-19 [3] RSPM (R 4.2.0) #> Rcpp 1.0.10 2023-01-22 [3] RSPM (R 4.2.0) #> reprex 2.0.2 2022-08-17 [3] RSPM (R 4.2.0) #> rgrass * 0.3-9 2023-06-04 [1] local #> rlang 1.1.1 2023-04-28 [3] RSPM (R 4.2.0) #> rmarkdown 2.22 2023-06-01 [3] RSPM (R 4.2.0) #> rstudioapi 0.14 2022-08-22 [3] RSPM (R 4.2.0) #> sessioninfo 1.2.2 2021-12-06 [3] RSPM (R 4.2.0) #> sf 1.0-12 2023-03-19 [1] CRAN (R 4.3.0) #> stars 0.6-1 2023-04-06 [3] RSPM (R 4.2.0) #> stringi 1.7.12 2023-01-11 [3] RSPM (R 4.2.0) #> stringr 1.5.0 2022-12-02 [3] RSPM (R 4.2.0) #> styler 1.10.0 2023-05-24 [3] RSPM (R 4.2.0) #> terra * 1.7-29 2023-04-22 [1] CRAN (R 4.2.3) #> tibble 3.2.1 2023-03-20 [3] RSPM (R 4.2.0) #> tidyselect 1.2.0 2022-10-10 [3] RSPM (R 4.2.0) #> units 0.8-2 2023-04-27 [3] RSPM (R 4.2.0) #> utf8 1.2.3 2023-01-31 [3] RSPM (R 4.2.0) #> vctrs 0.6.2 2023-04-19 [3] RSPM (R 4.2.0) #> withr 2.5.0 2022-03-03 [3] RSPM (R 4.2.0) #> xfun 0.39 2023-04-20 [3] RSPM (R 4.2.0) #> XML * 3.99-0.14 2023-03-19 [3] RSPM (R 4.2.0) #> yaml 2.3.7 2023-01-23 [3] RSPM (R 4.2.0) #> #> [1] /home/floris/lib/R/library #> [2] /usr/local/lib/R/site-library #> [3] /usr/lib/R/site-library #> [4] /usr/lib/R/library #> #> ────────────────────────────────────────────────────────────────────────────── ```

sf doesn't get a CRS though, and the others appear to get a PROJ string, maybe derived from the PROJ_INFO file (by the driver?) even though the EPSG code is set in the GRASS side.

@neteler @wenzeslaus

To be discussed.