<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>hypertidy</title>
<link>https://hypertidy.org/</link>
<atom:link href="https://hypertidy.org/index.xml" rel="self" type="application/rss+xml"/>
<description>Geospatial data, GDAL, and R — Michael Sumner</description>
<generator>quarto-1.9.38</generator>
<lastBuildDate>Fri, 26 Jun 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>Icechunk is coming - versioned cloud-native Zarr, GDAL, and R</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2026-06-26_icechunk-is-coming/</link>
  <description><![CDATA[ 






<p><a href="https://icechunk.io">Icechunk</a> is a transactional storage engine for Zarr and provides git-style versioning for large scientific datasets. This post is about Icechunk from a GDAL perspective and some impact that will have on the R community and its interactions with Zarr.</p>
<section id="what-is-icechunk" class="level2">
<h2 class="anchored" data-anchor-id="what-is-icechunk">What is Icechunk?</h2>
<p>Zarr is a chunked array format designed for cloud object storage. Icechunk is a Rust library that sits on top of Zarr and adds git-like snapshots combined with <a href="https://icechunk.io/en/stable/understanding/concepts/#why-transactions-matter">ACID transactions</a> - (which means reliable and guaranteed read and write).</p>
<p>(From their docs) this provides:</p>
<ul>
<li>Safety: Recover from corrupted or accidentally deleted data using version history</li>
<li>Consistency: Ensure readers always see complete, valid snapshots - never partial writes</li>
<li>Reproducibility: Reference any version of your data permanently via commits or tags</li>
</ul>
<p>Typical usage involves the Python packages <a href="https://pypi.org/project/xarray/">xarray</a> and <a href="https://pypi.org/project/icechunk/">icechunk</a>, but <a href="https://crates.io/crates/icechunk">Rust Icechunk</a> can be used directly, in combination with <a href="https://crates.io/crates/zarrs_icechunk">zarrs_icechunk</a>, and now in an <a href="https://github.com/OSGeo/gdal/milestone/72">upcoming GDAL release 3.14</a> via the read-only <a href="https://gdal.org/en/latest/drivers/raster/icechunk.html">Icechunk driver</a>.</p>
<p>Please be aware that Icechunk in GDAL is very new, and not yet in an officially supported release but if you are interested to get involved it can be used today. (GDAL 3.14 is milestoned for sometime in November 2026).</p>
</section>
<section id="what-works-in-gdal-and-r-today" class="level2">
<h2 class="anchored" data-anchor-id="what-works-in-gdal-and-r-today">What works in GDAL and R today</h2>
<p>GDAL 3.14 ships a <code>/vsiicechunk/</code> virtual filesystem and Icechunk driver, and will be available in gdalcubes, gdalraster, sf, terra, and vapour in various forms once that support lands in R packages.</p>
<p>The following examples can be run in this Linux docker container, for example:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">docker</span> pull ghcr.io/hypertidy/gdal-r-full:dev</span>
<span id="cb1-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">docker</span> run <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--rm</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-ti</span>  ghcr.io/hypertidy/gdal-r-full:dev</span></code></pre></div></div>
<p>(If that doesn’t work, or you want help with docker/GDAL/R just contact me directly)</p>
<p>Here is a single cli call that gives a GDAL multidimensional summary of an Icechunk store.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb2-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">gdal</span> mdim info <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb2-2">  /vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb2-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_NO_SIGN_REQUEST YES <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_REGION us-west-2</span></code></pre></div></div>
<details>
<summary>
Click here for the full mdim info output
</summary>
<pre><code>Driver: Icechunk

Dimensions:
  Name (path)  Size      Type      Direction
  -----------  ----  ------------  ---------
  /init_time   3264
  /latitude     721  HORIZONTAL_Y
  /lead_time     61
  /longitude   1440  HORIZONTAL_X

Coordinates (indexing variables):
  Name (path)   Dimension    Type              Unit
  -----------  -----------  -------  ------------------------
  /init_time   (init_time)  Int64    seconds since 1970-01-01
  /latitude    (latitude)   Float64  degree_north
  /lead_time   (lead_time)  Float64  seconds
  /longitude   (longitude)  Float64  degree_east

Data variables:
                  Name (path)                   Type              Unit                    Shape             Chunk size
  -------------------------------------------  -------  ------------------------  ---------------------  -----------------

 (/init_time):
  /expected_forecast_length                    Float64  seconds                   [3264]                 [23360]
  /ingested_forecast_length                    Float64  seconds                   [3264]                 [23360]

 (/init_time, /lead_time):
  /valid_time                                  Int64    seconds since 1970-01-01  [3264, 61]             [23360, 61]

 (/init_time, /lead_time, /latitude, /longitude):
  /dew_point_temperature_2m                    Float32  degree_Celsius            [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /downward_long_wave_radiation_flux_surface   Float32  W m-2                     [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /downward_short_wave_radiation_flux_surface  Float32  W m-2                     [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /geopotential_height_500hpa                  Float32  m                         [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /geopotential_height_850hpa                  Float32  m                         [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /geopotential_height_925hpa                  Float32  m                         [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /precipitation_surface                       Float32  kg m-2 s-1                [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /pressure_reduced_to_mean_sea_level          Float32  Pa                        [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /pressure_surface                            Float32  Pa                        [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /temperature_2m                              Float32  degree_Celsius            [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /temperature_850hpa                          Float32  degree_Celsius            [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /temperature_925hpa                          Float32  degree_Celsius            [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /total_cloud_cover_atmosphere                Float32  percent                   [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /wind_u_100m                                 Float32  m s-1                     [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /wind_u_10m                                  Float32  m s-1                     [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /wind_v_100m                                 Float32  m s-1                     [3264, 61, 721, 1440]  [1, 61, 241, 240]
  /wind_v_10m                                  Float32  m s-1                     [3264, 61, 721, 1440]  [1, 61, 241, 240]

Scalar arrays:
  Name (path)   Type   Unit
  ------------  -----  ----
  /spatial_ref  Int64

Attributes:
         Name           Type                                      Value
  -------------------  ------  ----------------------------------------------------------------------------
  attribution          String  "ECMWF AIFS Single forecast data processed by dynamical.org from ECMWF Open
                               Data."
  dataset_id           String  "ecmwf-aifs-single-forecast"
  dataset_version      String  "0.1.0"
  description          String  "Weather forecasts from the ECMWF Artificial Intelligence Forecasting System
                               (AIFS) Single model."
  forecast_domain      String  "Forecast lead time 0-360 hours (0-15 days) ahead"
  forecast_resolution  String  "6 hourly"
  license              String  "CC-BY-4.0"
  name                 String  "ECMWF AIFS Single forecast"
  spatial_domain       String  "Global"
  spatial_resolution   String  "0.25 degrees (~20km)"
  time_domain          String  "Forecasts initialized 2024-04-01 00:00:00 UTC to Present"
  time_resolution      String  "Forecasts initialized every 6 hours"

Arrays:

  - /init_time:
      Dimensions:    (/init_time)
      Shape:         [3264]
      Chunk size:    [23360]
      Type:          Int64
      Unit:          seconds since 1970-01-01
      Nodata value:  0

      Attributes:
                 Name            Type                       Value
        ----------------------  ------  ---------------------------------------------
        calendar                String  "proleptic_gregorian"
        long_name               String  "Forecast initialization time"
        standard_name           String  "forecast_reference_time"
        statistics_approximate  String  {"min":"2024-04-01T00:00:00","max":"Present"}

      Structural metadata:
        COMPRESSOR  { "name": "blosc", "configuration": { "typesize": 8, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } }

  - /latitude:
      Dimensions:    (/latitude)
      Shape:         [721]
      Chunk size:    [721]
      Type:          Float64
      Unit:          degree_north
      Nodata value:  "NaN"

      Attributes:
                 Name            Type          Value
        ----------------------  ------  --------------------
        _FillValue              String  "AAAAAAAA+H8="
        axis                    String  "Y"
        long_name               String  "Latitude"
        statistics_approximate  String  {"min":-90,"max":90}

      Structural metadata:
        COMPRESSOR  { "name": "blosc", "configuration": { "typesize": 8, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } }

  - /lead_time:
      Dimensions:    (/lead_time)
      Shape:         [61]
      Chunk size:    [61]
      Type:          Float64
      Unit:          seconds
      Nodata value:  "NaN"

      Attributes:
                 Name            Type                         Value
        ----------------------  ------  --------------------------------------------------
        _FillValue              String  "AAAAAAAA+H8="
        dtype                   String  "timedelta64[us]"
        long_name               String  "Forecast lead time"
        standard_name           String  "forecast_period"
        statistics_approximate  String  {"min":"0 days 00:00:00","max":"15 days 00:00:00"}

      Structural metadata:
        COMPRESSOR  { "name": "blosc", "configuration": { "typesize": 8, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } }

  - /longitude:
      Dimensions:    (/longitude)
      Shape:         [1440]
      Chunk size:    [1440]
      Type:          Float64
      Unit:          degree_east
      Nodata value:  "NaN"

      Attributes:
                 Name            Type             Value
        ----------------------  ------  -------------------------
        _FillValue              String  "AAAAAAAA+H8="
        axis                    String  "X"
        long_name               String  "Longitude"
        statistics_approximate  String  {"min":-180,"max":179.75}

      Structural metadata:
        COMPRESSOR  { "name": "blosc", "configuration": { "typesize": 8, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } }

  - /dew_point_temperature_2m:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          degree_Celsius
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "2 metre dewpoint temperature"
        short_name     String  "2d"
        standard_name  String  "dew_point_temperature"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /downward_long_wave_radiation_flux_surface:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          W m-2
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "Surface downward long-wave radiation flux"
        short_name     String  "sdlwrf"
        standard_name  String  "surface_downwelling_longwave_flux_in_air"
        step_type      String  "avg"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /downward_short_wave_radiation_flux_surface:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          W m-2
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "Surface downward short-wave radiation flux"
        short_name     String  "sdswrf"
        standard_name  String  "surface_downwelling_shortwave_flux_in_air"
        step_type      String  "avg"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /expected_forecast_length:
      Dimensions:    (/init_time)
      Shape:         [3264]
      Chunk size:    [23360]
      Type:          Float64
      Unit:          seconds
      Nodata value:  "NaN"

      Attributes:
                 Name            Type                         Value
        ----------------------  ------  --------------------------------------------------
        _FillValue              String  "AAAAAAAA+H8="
        dtype                   String  "timedelta64[us]"
        long_name               String  "Expected forecast length"
        statistics_approximate  String  {"min":"0 days 00:00:00","max":"15 days 00:00:00"}

      Structural metadata:
        COMPRESSOR  { "name": "blosc", "configuration": { "typesize": 8, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } }

  - /geopotential_height_500hpa:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          m
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "Geopotential height"
        short_name     String  "gh"
        standard_name  String  "geopotential_height"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /geopotential_height_850hpa:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          m
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "Geopotential height"
        short_name     String  "gh"
        standard_name  String  "geopotential_height"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /geopotential_height_925hpa:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          m
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "Geopotential height"
        short_name     String  "gh"
        standard_name  String  "geopotential_height"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /ingested_forecast_length:
      Dimensions:    (/init_time)
      Shape:         [3264]
      Chunk size:    [23360]
      Type:          Float64
      Unit:          seconds
      Nodata value:  "NaN"

      Attributes:
                 Name            Type                         Value
        ----------------------  ------  --------------------------------------------------
        _FillValue              String  "AAAAAAAA+H8="
        dtype                   String  "timedelta64[us]"
        long_name               String  "Ingested forecast length"
        statistics_approximate  String  {"min":"0 days 00:00:00","max":"15 days 00:00:00"}

      Structural metadata:
        COMPRESSOR  { "name": "blosc", "configuration": { "typesize": 8, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } }

  - /precipitation_surface:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          kg m-2 s-1
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                       Value
        -------------  ------  ------------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        comment        String  "Average precipitation rate since the previous forecast step. Units equivalent
                               to mm/s."
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "Precipitation rate"
        short_name     String  "prate"
        standard_name  String  "precipitation_flux"
        step_type      String  "avg"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /pressure_reduced_to_mean_sea_level:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          Pa
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "Pressure reduced to MSL"
        short_name     String  "prmsl"
        standard_name  String  "air_pressure_at_mean_sea_level"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /pressure_surface:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          Pa
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "Surface pressure"
        short_name     String  "sp"
        standard_name  String  "surface_air_pressure"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /spatial_ref:
      Dimensions:    ()
      Shape:         []
      Type:          Int64
      Nodata value:  0

      Attributes:
                   Name               Type                                        Value
        ---------------------------  -------  -----------------------------------------------------------------------------
        comment                      String   "This coordinate reference system matches the source data which follows WMO
                                              conventions of assuming the earth is a perfect sphere with a radius of 6,371,
                                              229m. It is similar to EPSG:4326, but EPSG:4326 uses a more accurate
                                              representation of the earth's shape."
        crs_wkt                      String   "GEOGCS[\"unknown\",DATUM[\"unknown\",SPHEROID[\"unknown\",6371229,0]],
                                              PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",
                                              0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AXIS[\"Longitude\",EAST],
                                              AXIS[\"Latitude\",NORTH]]"
        geographic_crs_name          String   "unknown"
        grid_mapping_name            String   "latitude_longitude"
        horizontal_datum_name        String   "unknown"
        inverse_flattening           Float64  0
        longitude_of_prime_meridian  Float64  0
        prime_meridian_name          String   "Greenwich"
        reference_ellipsoid_name     String   "unknown"
        semi_major_axis              Float64  6371229
        semi_minor_axis              Float64  6371229
        spatial_ref                  String   "GEOGCS[\"unknown\",DATUM[\"unknown\",SPHEROID[\"unknown\",6371229,0]],
                                              PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",
                                              0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AXIS[\"Longitude\",EAST],
                                              AXIS[\"Latitude\",NORTH]]"

      Structural metadata:
        COMPRESSOR  { "name": "zstd", "configuration": { "level": 0, "checksum": false } }

  - /temperature_2m:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          degree_Celsius
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "2 metre temperature"
        short_name     String  "2t"
        standard_name  String  "air_temperature"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /temperature_850hpa:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          degree_Celsius
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "Temperature"
        short_name     String  "t"
        standard_name  String  "air_temperature"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /temperature_925hpa:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          degree_Celsius
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "Temperature"
        short_name     String  "t"
        standard_name  String  "air_temperature"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /total_cloud_cover_atmosphere:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          percent
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "Total cloud cover"
        short_name     String  "tcc"
        standard_name  String  "cloud_area_fraction"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /valid_time:
      Dimensions:    (/init_time, /lead_time)
      Shape:         [3264, 61]
      Chunk size:    [23360, 61]
      Type:          Int64
      Unit:          seconds since 1970-01-01
      Nodata value:  0

      Attributes:
                 Name            Type                       Value
        ----------------------  ------  ---------------------------------------------
        calendar                String  "proleptic_gregorian"
        long_name               String  "Valid time"
        standard_name           String  "time"
        statistics_approximate  String  {"min":"2024-04-01T00:00:00","max":"Present"}

      Structural metadata:
        COMPRESSOR  { "name": "blosc", "configuration": { "typesize": 8, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } }

  - /wind_u_100m:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          m s-1
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "100 metre U wind component"
        short_name     String  "100u"
        standard_name  String  "eastward_wind"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /wind_u_10m:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          m s-1
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "10 metre U wind component"
        short_name     String  "10u"
        standard_name  String  "eastward_wind"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /wind_v_100m:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          m s-1
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "100 metre V wind component"
        short_name     String  "100v"
        standard_name  String  "northward_wind"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }

  - /wind_v_10m:
      Dimensions:    (/init_time, /lead_time, /latitude, /longitude)
      Shape:         [3264, 61, 721, 1440]
      Chunk size:    [1, 61, 241, 240]
      Type:          Float32
      Unit:          m s-1
      Nodata value:  "NaN"

      Attributes:
            Name        Type                                     Value
        -------------  ------  --------------------------------------------------------------------------
        _FillValue     String  "AAAAAAAA+H8="
        coordinates    String  "expected_forecast_length ingested_forecast_length spatial_ref valid_time"
        long_name      String  "10 metre V wind component"
        short_name     String  "10v"
        standard_name  String  "northward_wind"
        step_type      String  "instant"

      Structural metadata:
        COMPRESSOR  { "name": "sharding_indexed", "configuration": { "chunk_shape": [ 1, 61, 241, 240 ], "codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "blosc", "configuration": { "typesize": 4, "cname": "zstd", "clevel": 3, "shuffle": "shuffle", "blocksize": 0 } } ], "index_codecs": [ { "name": "bytes", "configuration": { "endian": "little" } }, { "name": "crc32c" } ], "index_location": "end" } }</code></pre>
</details>
<p>It’s a lot of output! For comparison let’s see what xarray will show as equivalent summary.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>xarray.Dataset<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> Size: <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">14TB</span></span>
<span id="cb4-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Dimensions:</span>                                     <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time:</span> 3264,</span>
<span id="cb4-3">                                                 <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">latitude:</span> 721, lead_time: 61,</span>
<span id="cb4-4">                                                 <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">longitude:</span> 1440<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb4-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Coordinates:</span></span>
<span id="cb4-6">  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">*</span> init_time                                   <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">datetime64</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span>ns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">26kB</span> ...</span>
<span id="cb4-7">  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">*</span> latitude                                    <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">latitude</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float64</span> 6kB 90.0 ....</span>
<span id="cb4-8">  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">*</span> lead_time                                   <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">lead_time</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float64</span> 488B 0.0 ...</span>
<span id="cb4-9">  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">*</span> longitude                                   <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">longitude</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float64</span> 12kB <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-180...</span></span>
<span id="cb4-10"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Data</span> variables: <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">12/21</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb4-11">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">dew_point_temperature_2m</span>                    <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time,</span> lead_time, latitude, longitude<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float32</span> 827GB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span> 61, 721, 1440<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-12">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">downward_long_wave_radiation_flux_surface</span>   <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time,</span> lead_time, latitude, longitude<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float32</span> 827GB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span> 61, 721, 1440<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-13">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">downward_short_wave_radiation_flux_surface</span>  <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time,</span> lead_time, latitude, longitude<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float32</span> 827GB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span> 61, 721, 1440<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-14">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">expected_forecast_length</span>                    <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float64</span> 26kB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-15">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">geopotential_height_500hpa</span>                  <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time,</span> lead_time, latitude, longitude<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float32</span> 827GB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span> 61, 721, 1440<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-16">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">geopotential_height_850hpa</span>                  <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time,</span> lead_time, latitude, longitude<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float32</span> 827GB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span> 61, 721, 1440<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-17">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">...</span>                                          ...</span>
<span id="cb4-18">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">total_cloud_cover_atmosphere</span>                <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time,</span> lead_time, latitude, longitude<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float32</span> 827GB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span> 61, 721, 1440<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-19">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">valid_time</span>                                  <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time,</span> lead_time<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float32</span> 796kB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span> 61<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-20">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">wind_u_100m</span>                                 <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time,</span> lead_time, latitude, longitude<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float32</span> 827GB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span> 61, 721, 1440<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-21">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">wind_u_10m</span>                                  <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time,</span> lead_time, latitude, longitude<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float32</span> 827GB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span> 61, 721, 1440<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-22">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">wind_v_100m</span>                                 <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time,</span> lead_time, latitude, longitude<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float32</span> 827GB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span> 61, 721, 1440<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-23">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">wind_v_10m</span>                                  <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time,</span> lead_time, latitude, longitude<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">float32</span> 827GB dask.array<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>chunksize=<span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">3264,</span> 61, 721, 1440<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">,</span> meta=np.ndarray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb4-24"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Attributes:</span></span>
<span id="cb4-25">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">attribution:</span>          ECMWF AIFS Single forecast data processed by dynami...</span>
<span id="cb4-26">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">dataset_id:</span>           ecmwf-aifs-single-forecast</span>
<span id="cb4-27">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">dataset_version:</span>      0.1.0</span>
<span id="cb4-28">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">description:</span>          Weather forecasts from the ECMWF Artificial Intelli...</span>
<span id="cb4-29">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">forecast_domain:</span>      Forecast lead time 0-360 hours <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">0-15</span> days<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">ahead</span></span>
<span id="cb4-30">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">forecast_resolution:</span>  6 hourly</span>
<span id="cb4-31">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">license:</span>              CC-BY-4.0</span>
<span id="cb4-32">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">name:</span>                 ECMWF AIFS Single forecast</span>
<span id="cb4-33">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">spatial_domain:</span>       Global</span>
<span id="cb4-34">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">spatial_resolution:</span>   0.25 degrees <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">~20km</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb4-35">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">time_domain:</span>          Forecasts initialized 2024-04-01 00:00:00 UTC to Pr...</span>
<span id="cb4-36">    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">time_resolution:</span>      Forecasts initialized every 6 hours</span></code></pre></div></div>
<p>That’s a lot denser, but the important thing is that GDAL has access to the same rich underlying Zarr data and note that xarray has clipped the full list of variables in the summary.</p>
<p>There are a few things to unpack in this cli call.</p>
<section id="gdal-multidimensional" class="level3">
<h3 class="anchored" data-anchor-id="gdal-multidimensional">GDAL multidimensional</h3>
<p><code>gdal mdim</code> provides a <a href="https://gdal.org/en/stable/programs/index.html#multidimensional-raster-commands">family of apps</a> for the <a href="https://gdal.org/en/stable/user/multidim_raster_data_model.html">GDAL multidimensional raster model</a> - this means that array data is presented in its native form with potentially multiple dimensions, and multiple variables like the NetCDF4 or HDF5 file type, whereas the classic 2D raster model (a 2D grid with one or more bands) can only present one variable and must unroll higher dimension out as bands.</p>
<p>The xarray output and the gdal mdim info output above is <em>human readable</em>, for a programmatic summary we can call</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">gdal</span> mdim info <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--format</span> json <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb5-2">  /vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb5-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_NO_SIGN_REQUEST YES <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_REGION us-west-2</span></code></pre></div></div>
<p>and in R we can do</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_config_option</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AWS_NO_SIGN_REQUEST"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"YES"</span>)</span>
<span id="cb6-2">gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_config_option</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AWS_REGION"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"us-west-2"</span>)</span>
<span id="cb6-3">json <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mdim_info</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cout =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>)</span>
<span id="cb6-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">substr</span>(json, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>))</span>
<span id="cb6-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># {</span></span>
<span id="cb6-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   "type": "group",</span></span>
<span id="cb6-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   "driver": "Icechunk",</span></span>
<span id="cb6-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   "name": "/",</span></span>
<span id="cb6-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   "attributes": {</span></span>
<span id="cb6-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "attribution": "ECMWF AIFS Single forecast data processed by dynamical.org from ECMWF Open Data.",</span></span>
<span id="cb6-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "dataset_id": "ecmwf-aifs-single-forecast",</span></span>
<span id="cb6-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "dataset_version": "0.1.0",</span></span>
<span id="cb6-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "description": "Weather forecasts from the ECMWF Artificial Intelligence Forecasting System (AIFS) Single model.",</span></span>
<span id="cb6-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "forecast_domain": "Forecast lead time 0-360 hours (0-15 days) ahead",</span></span>
<span id="cb6-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "forecast_resolution": "6 hourly",</span></span>
<span id="cb6-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "license": "CC-BY-4.0",</span></span>
<span id="cb6-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "name": "ECMWF AIFS Single forecast",</span></span>
<span id="cb6-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "spatial_domain": "Global",</span></span>
<span id="cb6-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "spatial_resolution": "0.25 degrees (~20km)",</span></span>
<span id="cb6-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "time_domain": "Forecasts initialized 2024-04-01 00:00:00 UTC to Present",</span></span>
<span id="cb6-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     "time_resolution": "Forecasts initialized every 6 hours"</span></span>
<span id="cb6-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   },</span></span>
<span id="cb6-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   "dimensions": [</span></span>
<span id="cb6-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     {</span></span>
<span id="cb6-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#       "name": "init_time",</span></span>
<span id="cb6-26"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#       "full_name": "/init_time",</span></span>
<span id="cb6-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#       "size": 3264,</span></span>
<span id="cb6-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#       "indexing_variable": "/init_time"</span></span>
<span id="cb6-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     },</span></span>
<span id="cb6-30"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     {</span></span>
<span id="cb6-31"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#       "name": "latitude",</span></span>
<span id="cb6-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#       "full_name": "/latit...  </span></span></code></pre></div></div>
<p>or with terra (in-dev, only on github atm)</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1">terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGDALconfig</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AWS_NO_SIGN_REQUEST"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"YES"</span>)</span>
<span id="cb7-2">terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGDALconfig</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AWS_REGION"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"us-west-2"</span>)</span>
<span id="cb7-3">terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk"</span>)</span>
<span id="cb7-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># class       : SpatRaster</span></span>
<span id="cb7-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># size        : 721, 1440, 3384768  (nrow, ncol, nlyr)</span></span>
<span id="cb7-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># resolution  : 0.25, 0.25  (x, y)</span></span>
<span id="cb7-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># extent      : -180.125, 179.875, -90.125, 90.125  (xmin, xmax, ymin, ymax)</span></span>
<span id="cb7-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># coord. ref. : lon/lat WGS 84 (CRS84) (OGC:CRS84)</span></span>
<span id="cb7-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># sources     : v0.1.0.icechunk</span></span>
<span id="cb7-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># varnames    : dew_point_temperature_2m (2 metre dewpoint temperature)</span></span>
<span id="cb7-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#               downward_long_wave_radiation_flux_surface (Surface downward long-wave radiation flux)</span></span>
<span id="cb7-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#               downward_short_wave_radiation_flux_surface (Surface downward short-wave radiation flux)</span></span>
<span id="cb7-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#               geopotential_height_500hpa (Geopotential height)</span></span>
<span id="cb7-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#               geopotential_height_850hpa (Geopotential height)</span></span>
<span id="cb7-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#               ...</span></span>
<span id="cb7-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># names       :    dew_p~600_1,    dew_p~600_2,    dew_p~600_3,    dew_p~600_4,    dew_p~600_5,    dew_p~600_6, ...</span></span>
<span id="cb7-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># unit        : degree_Celsius, degree_Celsius, degree_Celsius, degree_Celsius, degree_Celsius, degree_Celsius, ...</span></span>
<span id="cb7-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># depth       : 1.71193e+09 to 1.78241e+09 (: 3264 steps)</span></span>
<span id="cb7-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># time        : 0</span></span>
<span id="cb7-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Warning message:</span></span>
<span id="cb7-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [rast] skipped array (different geometry): /valid_time</span></span></code></pre></div></div>
<p>or sf/stars</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Sys.setenv</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AWS_NO_SIGN_REQUEST"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"YES"</span>)</span>
<span id="cb8-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Sys.setenv</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AWS_REGION"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"us-west-2"</span>)</span>
<span id="cb8-3">s <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> sf<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gdal_read_mdim</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">proxy =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb8-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str</span>(s)</span>
<span id="cb8-5">List of <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span></span>
<span id="cb8-6"> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span> array_list<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>List of <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">17</span></span>
<span id="cb8-7">  ..<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span> dew_point_temperature_2m                  <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span></span>
<span id="cb8-8">  ..<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span> downward_long_wave_radiation_flux_surface <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span></span>
<span id="cb8-9">  ..<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span> downward_short_wave_radiation_flux_surface<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span></span>
<span id="cb8-10">...</span></code></pre></div></div>
<details>
<summary>
Click here for the full sf structure info output
</summary>
<pre><code>List of 4
 $ array_list:List of 17
  ..$ dew_point_temperature_2m                  : NULL
  ..$ downward_long_wave_radiation_flux_surface : NULL
  ..$ downward_short_wave_radiation_flux_surface: NULL
  ..$ geopotential_height_500hpa                : NULL
  ..$ geopotential_height_850hpa                : NULL
  ..$ geopotential_height_925hpa                : NULL
  ..$ precipitation_surface                     : NULL
  ..$ pressure_reduced_to_mean_sea_level        : NULL
  ..$ pressure_surface                          : NULL
  ..$ temperature_2m                            : NULL
  ..$ temperature_850hpa                        : NULL
  ..$ temperature_925hpa                        : NULL
  ..$ total_cloud_cover_atmosphere              : NULL
  ..$ wind_u_100m                               : NULL
  ..$ wind_u_10m                                : NULL
  ..$ wind_v_100m                               : NULL
  ..$ wind_v_10m                                : NULL
 $ dimensions:List of 4
  ..$ init_time:List of 5
  .. ..$ from     : int 1
  .. ..$ to       : int 3264
  .. ..$ values   :List of 1
  .. .. ..$ : num [1:3264(1d)] 1.71e+09 1.71e+09 1.71e+09 1.71e+09 1.71e+09 ...
  .. .. .. ..- attr(*, "units")= chr "seconds since 1970-01-01"
  .. .. .. ..- attr(*, "d_names")= chr "init_time"
  .. .. .. ..- attr(*, "attributes")= Named chr [1:4] "proleptic_gregorian" "Forecast initialization time" "forecast_reference_time" "{ \"min\": \"2024-04-01T00:00:00\", \"max\": \"Present\" }"
  .. .. .. .. ..- attr(*, "names")= chr [1:4] "calendar" "long_name" "standard_name" "statistics_approximate"
  .. ..$ type     : chr ""
  .. ..$ direction: chr ""
  ..$ lead_time:List of 5
  .. ..$ from     : int 1
  .. ..$ to       : int 61
  .. ..$ values   :List of 1
  .. .. ..$ : num [1:61(1d)] 0 21600 43200 64800 86400 ...
  .. .. .. ..- attr(*, "units")= chr "seconds"
  .. .. .. ..- attr(*, "d_names")= chr "lead_time"
  .. .. .. ..- attr(*, "attributes")= Named chr [1:5] "AAAAAAAA+H8=" "timedelta64[us]" "Forecast lead time" "forecast_period" ...
  .. .. .. .. ..- attr(*, "names")= chr [1:5] "_FillValue" "dtype" "long_name" "standard_name" ...
  .. ..$ type     : chr ""
  .. ..$ direction: chr ""
  ..$ latitude :List of 5
  .. ..$ from     : int 1
  .. ..$ to       : int 721
  .. ..$ values   :List of 1
  .. .. ..$ : num [1:721(1d)] 90 89.8 89.5 89.2 89 ...
  .. .. .. ..- attr(*, "units")= chr "degree_north"
  .. .. .. ..- attr(*, "d_names")= chr "latitude"
  .. .. .. ..- attr(*, "attributes")= Named chr [1:4] "AAAAAAAA+H8=" "Y" "Latitude" "{ \"min\": -90.0, \"max\": 90.0 }"
  .. .. .. .. ..- attr(*, "names")= chr [1:4] "_FillValue" "axis" "long_name" "statistics_approximate"
  .. ..$ type     : chr "HORIZONTAL_Y"
  .. ..$ direction: chr ""
  ..$ longitude:List of 5
  .. ..$ from     : int 1
  .. ..$ to       : int 1440
  .. ..$ values   :List of 1
  .. .. ..$ : num [1:1440(1d)] -180 -180 -180 -179 -179 ...
  .. .. .. ..- attr(*, "units")= chr "degree_east"
  .. .. .. ..- attr(*, "d_names")= chr "longitude"
  .. .. .. ..- attr(*, "attributes")= Named chr [1:4] "AAAAAAAA+H8=" "X" "Longitude" "{ \"min\": -180.0, \"max\": 179.75 }"
  .. .. .. .. ..- attr(*, "names")= chr [1:4] "_FillValue" "axis" "long_name" "statistics_approximate"
  .. ..$ type     : chr "HORIZONTAL_X"
  .. ..$ direction: chr ""
 $ srs       : chr NA
 $ geometry  : list()</code></pre>
</details>
<p>That is leveraged by stars to give</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Sys.setenv</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AWS_NO_SIGN_REQUEST"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"YES"</span>)</span>
<span id="cb10-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Sys.setenv</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AWS_REGION"</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"us-west-2"</span>)</span>
<span id="cb10-3">stars<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_mdim</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">proxy =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb10-4"></span>
<span id="cb10-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># stars_proxy object with 17 attributes in 17 file(s):</span></span>
<span id="cb10-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># $dew_point_temperature_2m</span></span>
<span id="cb10-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [1] "[...]/v0.1.0.icechunk"</span></span>
<span id="cb10-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># </span></span>
<span id="cb10-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># $downward_long_wave_radiation_flux_surface</span></span>
<span id="cb10-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [1] "[...]/v0.1.0.icechunk"</span></span>
<span id="cb10-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># </span></span>
<span id="cb10-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ...</span></span>
<span id="cb10-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># </span></span>
<span id="cb10-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># $temperature_925hpa</span></span>
<span id="cb10-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [1] "[...]/v0.1.0.icechunk"</span></span>
<span id="cb10-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># </span></span>
<span id="cb10-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># $total_cloud_cover_atmosphere</span></span>
<span id="cb10-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [1] "[...]/v0.1.0.icechunk"</span></span>
<span id="cb10-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># </span></span>
<span id="cb10-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># $wind_u_100m</span></span>
<span id="cb10-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [1] "[...]/v0.1.0.icechunk"</span></span>
<span id="cb10-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># </span></span>
<span id="cb10-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># $wind_u_10m</span></span>
<span id="cb10-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [1] "[...]/v0.1.0.icechunk"</span></span>
<span id="cb10-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># </span></span>
<span id="cb10-26"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># $wind_v_100m</span></span>
<span id="cb10-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [1] "[...]/v0.1.0.icechunk"</span></span>
<span id="cb10-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># </span></span>
<span id="cb10-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># $wind_v_10m</span></span>
<span id="cb10-30"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [1] "[...]/v0.1.0.icechunk"</span></span>
<span id="cb10-31"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># </span></span>
<span id="cb10-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># dimension(s):</span></span>
<span id="cb10-33"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#           from   to         offset     delta  refsys x/y</span></span>
<span id="cb10-34"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># longitude    1 1440         -180.1      0.25      NA [x]</span></span>
<span id="cb10-35"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># latitude     1  721          90.12     -0.25      NA [y]</span></span>
<span id="cb10-36"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># lead_time    1   61          0 [s] 21600 [s] udunits    </span></span>
<span id="cb10-37"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># init_time    1 3264 2024-04-01 UTC   6 hours POSIXct    </span></span></code></pre></div></div>
<p>Please note that this store contains pretty simple regular array data, and so the relationship of data arrays to their coordinates is simple, the map in longitude/latitude is a regular grid and so slices of that can correspond to the normal <em>raster</em> model where a bounding box (or corner coordinates + resolution) is sufficient to georeference the data. Multidimensional data can be more general and more complex than that.</p>
<p>This post won’t explore any more detail of the various ways R packages support mdim.</p>
</section>
</section>
<section id="multidimensional" class="level2">
<h2 class="anchored" data-anchor-id="multidimensional">Multidimensional?</h2>
<p><em>Please hang in here for a few sections</em>, we are diverting down a GDAL and object storage rabbit hole, but it’s not long and then we’ll get back to Icechunk in the naming a thing section.</p>
<p>We can treat this store as raster data in the normal 2D way, but note that there are caveats and real performance implications depending on the way data is laid out in a given store.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb11-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">gdalinfo</span> /vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_NO_SIGN_REQUEST YES <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_REGION us-west-2</span>
<span id="cb11-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Driver:</span> Icechunk/Icechunk</span>
<span id="cb11-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Files:</span> /vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk</span>
<span id="cb11-4"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Size</span> is 512, 512</span>
<span id="cb11-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Subdatasets:</span></span>
<span id="cb11-6">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_1_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/dew_point_temperature_2m</span>
<span id="cb11-7">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_1_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/dew_point_temperature_2m</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-8">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_2_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/downward_long_wave_radiation_flux_surface</span>
<span id="cb11-9">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_2_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/downward_long_wave_radiation_flux_surface</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-10">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_3_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/downward_short_wave_radiation_flux_surface</span>
<span id="cb11-11">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_3_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/downward_short_wave_radiation_flux_surface</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-12">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_4_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/geopotential_height_500hpa</span>
<span id="cb11-13">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_4_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/geopotential_height_500hpa</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-14">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_5_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/geopotential_height_850hpa</span>
<span id="cb11-15">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_5_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/geopotential_height_850hpa</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-16">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_6_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/geopotential_height_925hpa</span>
<span id="cb11-17">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_6_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/geopotential_height_925hpa</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-18">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_7_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/precipitation_surface</span>
<span id="cb11-19">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_7_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/precipitation_surface</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-20">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_8_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/pressure_reduced_to_mean_sea_level</span>
<span id="cb11-21">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_8_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/pressure_reduced_to_mean_sea_level</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-22">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_9_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/pressure_surface</span>
<span id="cb11-23">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_9_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/pressure_surface</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-24">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_10_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/temperature_2m</span>
<span id="cb11-25">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_10_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/temperature_2m</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-26">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_11_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/temperature_850hpa</span>
<span id="cb11-27">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_11_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/temperature_850hpa</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-28">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_12_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/temperature_925hpa</span>
<span id="cb11-29">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_12_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/temperature_925hpa</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-30">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_13_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/total_cloud_cover_atmosphere</span>
<span id="cb11-31">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_13_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/total_cloud_cover_atmosphere</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-32">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_14_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/valid_time</span>
<span id="cb11-33">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_14_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/valid_time</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Int64</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-34">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_15_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/wind_u_100m</span>
<span id="cb11-35">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_15_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/wind_u_100m</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-36">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_16_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/wind_u_10m</span>
<span id="cb11-37">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_16_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/wind_u_10m</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-38">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_17_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/wind_v_100m</span>
<span id="cb11-39">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_17_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/wind_v_100m</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-40">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_18_NAME</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>ZARR:<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}"</span>:/wind_v_10m</span>
<span id="cb11-41">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SUBDATASET_18_DESC</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">[</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3264x61x721x1440</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">]</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/wind_v_10m</span> <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Float32</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-42"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Corner</span> Coordinates:</span>
<span id="cb11-43"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Upper</span> Left  <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span>    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">0.0,</span>    0.0<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-44"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Lower</span> Left  <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span>    <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">0.0,</span>  512.0<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-45"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Upper</span> Right <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span>  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">512.0,</span>    0.0<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-46"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Lower</span> Right <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span>  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">512.0,</span>  512.0<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb11-47"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">Center</span>      <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span>  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">256.0,</span>  256.0<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span></code></pre></div></div>
<p>Those strings like <code>"ZARR:\"/vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk}\":/dew_point_temperature_2m"</code> (note the embedded escaped quotes) can be used by the more tradition GDAL classic raster model.</p>
<p>We’ll come back to the <code>/vsiicechunk</code> and <code>{/vsis3}</code> parts of this string a bit later.</p>
</section>
<section id="setting-config-options-and-environment-variables-for-gdal" class="level2">
<h2 class="anchored" data-anchor-id="setting-config-options-and-environment-variables-for-gdal">Setting config options and environment variables for GDAL</h2>
<p>GDAL config options can be set through a package wrapper - <code>gdalraster::set_config_option("AWS_NO_SIGN_REQUEST", "YES")</code> or <code>terra::setGDALconfig("AWS_NO_SIGN_REQUEST", "YES")</code> - or as process environment variables (<code>Sys.setenv(AWS_NO_SIGN_REQUEST = "YES")</code>, or <code>KEY=value</code> in the shell). Both routes are <em>global and sticky</em>: once set they can affect every other step, spooky-action-at-a-distance that we want to avoid.</p>
<p>That’s why setting config <em>inline</em> - <code>--config KEY=VALUE</code> on the <code>gdal mdim info</code> call is a clean option: it lives and dies in one line, a bit like <code>with</code> in Python or <code>with()</code> in R. The R equivalent for env vars and options is <code>withr::with_envvar()</code> / <code>withr::with_options()</code>, true scoped context managers.</p>
<p>With online storage it can be bewildering what exact configuration you need and what you have, but it does come down to a fairly comprehensible set of ideas. This post is not a guide to online storage access configuration, or a guide to <a href="https://gdal.org/en/stable/user/configoptions.html">GDAL configuration options</a> but there’s a finite set of concepts in this jungle so don’t be put off by the complexity.</p>
<p><strong>Auth - keyed vs anonymous.</strong> If a dataset is not public, you will need something like <code>AWS_ACCESS_KEY_ID</code> and <code>AWS_SECRET_ACCESS_KEY</code>. If it is public, you will need something like <code>AWS_NO_SIGN_REQUEST=YES</code> (or <code>--no-sign-request</code>).</p>
<p><strong>Addressing.</strong> Everything is a <em>key</em> inside a <em>bucket</em>. You reference an object as <code>s3://bucket/key</code> (Amazon), <code>gs://bucket/key</code> (Google Storage), <code>abfss://…</code> (Azure storage) - and that’s the whole model. (Azure bends it slightly: a storage <em>account</em> holds <em>containers</em> holding <em>blobs</em>, and the scheme carries the account, <code>abfss://container@account.dfs.core.windows.net/key</code>.)</p>
<p><strong>Endpoint, region, hosting-style.</strong> That object is hosted on an <em>endpoint</em> - <code>s3://</code> is shorthand for <code>s3.&lt;region&gt;.amazonaws.com</code>, <code>gs://</code> for <code>storage.googleapis.com</code>. A <em>custom</em> endpoint means pointing at your own host - <code>AWS_S3_ENDPOINT=your.endpoint.net</code> - so that <code>s3</code> in <code>s3://bucket/key</code> resolves to your host and not Amazon’s. Virtual hosting just means the bucket goes before the endpoint in the final url <code>https://bucket.s3.&lt;region&gt;.amazonaws.com/key</code> vs <code>https://my.custom.endpoint.net/bucket/key</code>. It’s confusing, until you know what it does and when you might need it. For non-AWS S3 implementations (MinIO, Ceph) this usually goes together with path-style addressing, <code>AWS_VIRTUAL_HOSTING=NO</code>, since most of them don’t do virtual-host style. Again on a custom S3 <code>AWS_REGION</code> is sometimes needed but probably shouldn’t matter - set it to ““.</p>
<section id="gdal-and-the-virtual-filesystem" class="level3">
<h3 class="anchored" data-anchor-id="gdal-and-the-virtual-filesystem">GDAL and the virtual filesystem</h3>
<p>Everything above is generic - true of any R tool talking to object storage - and GDAL addresses remote objects through its own <em>virtual filesystem</em> (VSI) rather than the <code>s3://</code>-style schemes. Again, bucket, key but with a different prefix:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>cloud-native</th>
<th>GDAL VSI</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>s3://bucket/key</code></td>
<td><code>/vsis3/bucket/key</code></td>
</tr>
<tr class="even">
<td><code>gs://bucket/key</code></td>
<td><code>/vsigs/bucket/key</code></td>
</tr>
<tr class="odd">
<td><code>abfss://container/key</code></td>
<td><code>/vsiaz/container/key</code></td>
</tr>
</tbody>
</table>
<p>This is the most common first stumble: <code>s3://…</code> handed to <code>terra::rast()</code> or <code>vapour::gdal_raster_data()</code> won’t open; the <code>/vsis3/…</code> form will. Be aware that some packages in R and other langs will do their own heuristics to wrap different protocols: ‘https://’, ‘s3://’, ‘virtualizarr://’ etc - this can be helpful but also very confusing, and this post cannot summarize that landscape. When GDAL is in use my preference is to use GDAL protocols without wrapping. The config options from above (<code>AWS_NO_SIGN_REQUEST</code>, <code>AWS_S3_ENDPOINT</code>, and friends) all still apply unchanged - VSI only changes how you <em>name</em> the object, it doesn’t affect how or if it’s accessible.</p>
<p>The same <code>/vsi*</code> mechanism abstracts over a whole zoo of access methods, all of which GDAL then reads as if they were ordinary local files:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 50%">
<col style="width: 50%">
</colgroup>
<thead>
<tr class="header">
<th>prefix</th>
<th>what it opens</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>/vsicurl/</code></td>
<td>any file over plain HTTP/HTTPS (range-requested, not downloaded whole)</td>
</tr>
<tr class="even">
<td><code>/vsizip/</code></td>
<td>a file <em>inside</em> a ZIP archive</td>
</tr>
<tr class="odd">
<td><code>/vsitar/</code>, <code>/vsigzip/</code></td>
<td>likewise for TAR / gzip</td>
</tr>
<tr class="even">
<td><code>/vsimem/</code></td>
<td>an in-memory buffer</td>
</tr>
<tr class="odd">
<td><code>/vsiswift/</code>, <code>/vsioss/</code></td>
<td>OpenStack Swift, Alibaba OSS, …</td>
</tr>
<tr class="even">
<td><code>/vsistdout/</code></td>
<td>stream output straight to standard out</td>
</tr>
</tbody>
</table>
<p>The real payoff is that these <em>compose</em> - you chain prefixes right-to-left to stack the abstractions. To read a single GeoTIFF sitting inside a ZIP that lives in an S3 bucket, none of which you download in full:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb12-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/vsizip//vsis3/bucket/archive.zip/inside.tif</span></span></code></pre></div></div>
<p>GDAL signs the S3 request, range-reads the ZIP’s central directory, pulls just the bytes for <code>inside.tif</code>, and hands you a raster. That’s the whole world the VSI layer opens up: object storage, archives, compression, and HTTP are all just prefixes over the same “name a thing, read its bytes” idea.</p>
</section>
<section id="sec-naming" class="level3">
<h3 class="anchored" data-anchor-id="sec-naming">Naming a thing inside a thing</h3>
<p>That earlier chain glued its prefixes by plain concatenation - <code>/vsizip/</code> meets <code>/vsis3/</code>, and since both carry a leading slash you get the doubled <code>//</code>. GDAL finds the archive boundary inside that run by heuristic: it spots the <code>.zip</code>. The brace form, <code>/vsizip/{…}</code>, makes the boundary <em>explicit</em> rather than guessed - and once the inner path carries its own punctuation (a URL with a query string, say) explicit is the only thing that works.</p>
<p>GEBCO 2026 ships its global grid as a single zip behind a download URL ending <code>…gebco_2026_geotiff.zip?download=1</code>. To reach into it without pulling the whole archive, chain <code>/vsizip/</code> over <code>/vsicurl/</code>, braces around the inner path because of that <code>?download=1</code> which masks the fact that it’s a zip file:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb13-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">/vsizip/{/vsicurl/https://dap.ceda.ac.uk/bodc/gebco/global/gebco_2026/ice_surface_elevation/geotiff/gebco_2026_geotiff.zip?download=1}</span></span></code></pre></div></div>
<p>If we point GDAL at that archive it can’t return a single raster, so it tells you what’s in there instead:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb14-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">ERROR</span> 4: ... not recognized as being in a supported file format.</span>
<span id="cb14-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">The</span> archive contains several files:</span>
<span id="cb14-3">  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">…}/gebco_2026_n0.0_s-90.0_w0.0_e90.0_geotiff.tif</span></span>
<span id="cb14-4">  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">…}/gebco_2026_n0.0_s-90.0_w-180.0_e-90.0_geotiff.tif</span></span>
<span id="cb14-5">  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">…</span>   <span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">six</span> more files<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">)</span></span>
<span id="cb14-6">  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">…}/GEBCO_Grid_documentation.pdf</span></span>
<span id="cb14-7">  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">…}/GEBCO_Grid_terms_of_use.pdf</span></span></code></pre></div></div>
<p>That listing is a <em>logical</em> filesystem - real files physically inside the zip in an opaque form, enumerated out of a remote archive. Append one of them after the closing brace and you’ve named a single item; GDAL opens it.</p>
<p>Compare that to the subdataset syntax, multiple subdatasets of classic 2D raster we saw in the Icechunk store above:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb15-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">ZARR:</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsiicechunk/{/vsis3/.../v0.1.0.icechunk}"</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">:/dew_point_temperature_2m</span></span></code></pre></div></div>
<p>Again we have bracing of an internal <code>/vsi*</code> item but the thing named after it, <code>/dew_point_temperature_2m</code>, isn’t a file but a variable in a <em>logical</em> hierarchy, a node in the Zarr data model. <code>/vsizip/</code> descends into the <em>structural</em> contents of an archive, <code>ZARR:</code> over <code>/vsiicechunk/</code> into the <em>logical</em> contents of a data model - that’s why we see different forms of addressing in stores.</p>
<p>GDAL can list things, here we use <code>gdal vsi list</code> to see the structural contents:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb16-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">gdal</span> vsi list   /vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb16-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_NO_SIGN_REQUEST YES <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_REGION us-west-2</span>
<span id="cb16-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">repo</span></span>
<span id="cb16-4"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">chunks</span></span>
<span id="cb16-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">manifests</span></span>
<span id="cb16-6"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">overwritten</span></span>
<span id="cb16-7"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">snapshots</span></span>
<span id="cb16-8"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">transactions</span></span></code></pre></div></div>
<p>ok we think, those look like directories so let’s go deeper (eek!):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb17-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">gdal</span> vsi list   /vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk/chunks <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb17-2"> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_NO_SIGN_REQUEST YES <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_REGION us-west-2</span>
<span id="cb17-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">0003DSF0M0N9B5MP3R9G</span></span>
<span id="cb17-4"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">0010VXY96ABV0RP45T30</span></span>
<span id="cb17-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">0015TP2QVGT990JE9PM0</span></span>
<span id="cb17-6"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">...</span></span></code></pre></div></div>
<p>yes it’s valid content but not something we can understand - we are seeing the internal structure of a complex sophisticated cloud format. We know it’s Icechunk so lets wield the Icechunk virtualization tool</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb18-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">gdal</span> vsi list /vsiicechunk/{/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk} <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb18-2"> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_NO_SIGN_REQUEST YES <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--config</span> AWS_REGION us-west-2</span>
<span id="cb18-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">zarr.json</span></span>
<span id="cb18-4"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">dew_point_temperature_2m</span></span>
<span id="cb18-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">downward_long_wave_radiation_flux_surface</span></span>
<span id="cb18-6"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">downward_short_wave_radiation_flux_surface</span></span>
<span id="cb18-7"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">expected_forecast_length</span></span>
<span id="cb18-8"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">geopotential_height_500hpa</span></span>
<span id="cb18-9"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">geopotential_height_850hpa</span></span>
<span id="cb18-10"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">geopotential_height_925hpa</span></span>
<span id="cb18-11"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">ingested_forecast_length</span></span>
<span id="cb18-12"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">init_time</span></span>
<span id="cb18-13"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">latitude</span></span>
<span id="cb18-14"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">lead_time</span></span>
<span id="cb18-15"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">longitude</span></span>
<span id="cb18-16"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">precipitation_surface</span></span>
<span id="cb18-17"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pressure_reduced_to_mean_sea_level</span></span>
<span id="cb18-18"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pressure_surface</span></span>
<span id="cb18-19"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">spatial_ref</span></span>
<span id="cb18-20"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">temperature_2m</span></span>
<span id="cb18-21"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">temperature_850hpa</span></span>
<span id="cb18-22"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">temperature_925hpa</span></span>
<span id="cb18-23"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">total_cloud_cover_atmosphere</span></span>
<span id="cb18-24"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">valid_time</span></span>
<span id="cb18-25"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">wind_u_100m</span></span>
<span id="cb18-26"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">wind_u_10m</span></span>
<span id="cb18-27"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">wind_v_100m</span></span>
<span id="cb18-28"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">wind_v_10m</span></span></code></pre></div></div>
<p>and now we are back in <em>logical</em> ground, this is the interpretation that <code>gdal mdim info</code> gave us above, not raw listing of the structural contents.</p>
<p>That shows some of the depth of GDAL abstraction. “Name a thing, read its bytes” it’s not just bytes on a disk. A thing can be an object in a bucket, a member of an archive, a variable in a chunked store, etc - and the path is the recipe for access.</p>
<p>The distinction between <em>material</em> structure (thousands of small manifest files on S3) and <em>logical/virtual</em> structure (the clean array hierarchy you see via <code>/vsiicechunk/</code>) is a key icechunk concept. GDAL’s <code>/vsi*</code> filesystem stack handles this transparently - the same way <code>/vsicurl/</code>, <code>/vsis3/</code>, <code>/vsigs/</code> abstract over HTTP and object stores.</p>
</section>
</section>
<section id="what-about-python" class="level2">
<h2 class="anchored" data-anchor-id="what-about-python">What about python?</h2>
<p>Above we saw how GDAL and some R packages interact with the Icechunk store, how do we do that in Python?</p>
<p>This time we don’t have a single description of the store, we have to use infrastructure to encode the details.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> icechunk</span>
<span id="cb19-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> xarray </span>
<span id="cb19-3"></span>
<span id="cb19-4">storage <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> icechunk.s3_storage(</span>
<span id="cb19-5">    bucket<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dynamical-ecmwf-aifs-single"</span>,</span>
<span id="cb19-6">    prefix<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ecmwf-aifs-single-forecast/v0.1.0.icechunk"</span>,</span>
<span id="cb19-7">    region<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"us-west-2"</span>,</span>
<span id="cb19-8">    anonymous<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>,           <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># the AWS_NO_SIGN_REQUEST=YES equivalent</span></span>
<span id="cb19-9">)</span>
<span id="cb19-10">repo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> icechunk.Repository.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">open</span>(storage)</span>
<span id="cb19-11">session <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> repo.readonly_session(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"main"</span>)</span>
<span id="cb19-12">ds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> xarray.open_zarr(session.store, consolidated<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>)</span>
<span id="cb19-13">ds</span>
<span id="cb19-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># &lt;xarray.Dataset&gt; Size: 14TB</span></span>
<span id="cb19-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Dimensions:                                     (init_time: 3265,</span></span>
<span id="cb19-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#                                                  lead_time: 61, latitude: 721,</span></span>
<span id="cb19-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#                                                  longitude: 1440)</span></span>
<span id="cb19-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Coordinates:</span></span>
<span id="cb19-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * init_time                                   (init_time) datetime64[ns] 26kB ...</span></span>
<span id="cb19-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     expected_forecast_length                    (init_time) timedelta64[us] 26kB dask.array&lt;chunksize=(3265,), meta=np.ndarray&gt;</span></span>
<span id="cb19-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     ingested_forecast_length                    (init_time) timedelta64[us] 26kB dask.array&lt;chunksize=(3265,), meta=np.ndarray&gt;</span></span>
<span id="cb19-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * lead_time                                   (lead_time) timedelta64[us] 488B ...</span></span>
<span id="cb19-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     valid_time                                  (init_time, lead_time) datetime64[ns] 2MB dask.array&lt;chunksize=(3265, 61), meta=np.ndarray&gt;</span></span>
<span id="cb19-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * latitude                                    (latitude) float64 6kB 90.0 ....</span></span>
<span id="cb19-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * longitude                                   (longitude) float64 12kB -180...</span></span>
<span id="cb19-26"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     spatial_ref                                 int64 8B ...</span></span>
<span id="cb19-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Data variables: (12/17)</span></span>
<span id="cb19-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     dew_point_temperature_2m                    (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     downward_long_wave_radiation_flux_surface   (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-30"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     geopotential_height_500hpa                  (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-31"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     geopotential_height_850hpa                  (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     precipitation_surface                       (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-33"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     downward_short_wave_radiation_flux_surface  (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-34"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     ...                                          ...</span></span>
<span id="cb19-35"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     wind_u_100m                                 (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-36"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     temperature_925hpa                          (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-37"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     total_cloud_cover_atmosphere                (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-38"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     wind_u_10m                                  (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-39"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     wind_v_100m                                 (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-40"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     wind_v_10m                                  (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(1, 61, 241, 240), meta=np.ndarray&gt;</span></span>
<span id="cb19-41"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Attributes:</span></span>
<span id="cb19-42"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     dataset_id:           ecmwf-aifs-single-forecast</span></span>
<span id="cb19-43"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     dataset_version:      0.1.0</span></span>
<span id="cb19-44"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     name:                 ECMWF AIFS Single forecast</span></span>
<span id="cb19-45"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     description:          Weather forecasts from the ECMWF Artificial Intelli...</span></span>
<span id="cb19-46"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     attribution:          ECMWF AIFS Single forecast data processed by dynami...</span></span>
<span id="cb19-47"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     license:              CC-BY-4.0</span></span>
<span id="cb19-48"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     spatial_domain:       Global</span></span>
<span id="cb19-49"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     spatial_resolution:   0.25 degrees (~20km)</span></span>
<span id="cb19-50"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     time_domain:          Forecasts initialized 2024-04-01 00:00:00 UTC to Pr...</span></span>
<span id="cb19-51"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     time_resolution:      Forecasts initialized every 6 hours</span></span>
<span id="cb19-52"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     forecast_domain:      Forecast lead time 0-360 hours (0-15 days) ahead</span></span>
<span id="cb19-53"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     forecast_resolution:  6 hourly</span></span></code></pre></div></div>
<p>We looked above at this xarray representation but up there we didn’t use the same infrastructure or show the code. The one above was made with</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> os</span>
<span id="cb20-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> xarray</span>
<span id="cb20-3"></span>
<span id="cb20-4">os.environ[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AWS_NO_SIGN_REQUEST"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"YES"</span></span>
<span id="cb20-5">os.environ[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AWS_REGION"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"us-west-2"</span></span>
<span id="cb20-6"></span>
<span id="cb20-7">ds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> xarray.open_dataset(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsis3/dynamical-ecmwf-aifs-single/ecmwf-aifs-single-forecast/v0.1.0.icechunk"</span>, engine <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gdalxarray"</span>, chunks <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {})</span>
<span id="cb20-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># &lt;xarray.Dataset&gt; Size: 14TB</span></span>
<span id="cb20-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Dimensions:                                     (init_time: 3265,</span></span>
<span id="cb20-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#                                                  latitude: 721, lead_time: 61,</span></span>
<span id="cb20-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#                                                  longitude: 1440)</span></span>
<span id="cb20-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Coordinates:</span></span>
<span id="cb20-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * init_time                                   (init_time) datetime64[ns] 26kB ...</span></span>
<span id="cb20-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     expected_forecast_length                    (init_time) float64 26kB dask.array&lt;chunksize=(3265,), meta=np.ndarray&gt;</span></span>
<span id="cb20-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     ingested_forecast_length                    (init_time) float64 26kB dask.array&lt;chunksize=(3265,), meta=np.ndarray&gt;</span></span>
<span id="cb20-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * latitude                                    (latitude) float64 6kB 90.0 ....</span></span>
<span id="cb20-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * lead_time                                   (lead_time) float64 488B 0.0 ...</span></span>
<span id="cb20-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     valid_time                                  (init_time, lead_time) float32 797kB dask.array&lt;chunksize=(3265, 61), meta=np.ndarray&gt;</span></span>
<span id="cb20-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * longitude                                   (longitude) float64 12kB -180...</span></span>
<span id="cb20-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     spatial_ref                                 float32 4B ...</span></span>
<span id="cb20-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Data variables: (12/17)</span></span>
<span id="cb20-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     dew_point_temperature_2m                    (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     downward_long_wave_radiation_flux_surface   (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     downward_short_wave_radiation_flux_surface  (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     geopotential_height_500hpa                  (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-26"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     geopotential_height_850hpa                  (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     geopotential_height_925hpa                  (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     ...                                          ...</span></span>
<span id="cb20-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     temperature_925hpa                          (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-30"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     total_cloud_cover_atmosphere                (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-31"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     wind_u_100m                                 (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     wind_u_10m                                  (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-33"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     wind_v_100m                                 (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-34"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     wind_v_10m                                  (init_time, lead_time, latitude, longitude) float32 827GB dask.array&lt;chunksize=(3265, 61, 721, 1440), meta=np.ndarray&gt;</span></span>
<span id="cb20-35"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Attributes:</span></span>
<span id="cb20-36"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     attribution:          ECMWF AIFS Single forecast data processed by dynami...</span></span>
<span id="cb20-37"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     dataset_id:           ecmwf-aifs-single-forecast</span></span>
<span id="cb20-38"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     dataset_version:      0.1.0</span></span>
<span id="cb20-39"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     description:          Weather forecasts from the ECMWF Artificial Intelli...</span></span>
<span id="cb20-40"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     forecast_domain:      Forecast lead time 0-360 hours (0-15 days) ahead</span></span>
<span id="cb20-41"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     forecast_resolution:  6 hourly</span></span>
<span id="cb20-42"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     license:              CC-BY-4.0</span></span>
<span id="cb20-43"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     name:                 ECMWF AIFS Single forecast</span></span>
<span id="cb20-44"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     spatial_domain:       Global</span></span>
<span id="cb20-45"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     spatial_resolution:   0.25 degrees (~20km)</span></span>
<span id="cb20-46"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     time_domain:          Forecasts initialized 2024-04-01 00:00:00 UTC to Pr...</span></span>
<span id="cb20-47"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     time_resolution:      Forecasts initialized every 6 hours</span></span></code></pre></div></div>
<p>That seems very similar, and hopefully for the in-dev GDAL xarray backend <a href="https://github.com/hypertidy/gdalxarray">gdalxarray</a> it’s an equivalent connection (I’m not going to validate any further here in this post).</p>
<p>What this illustrates is while the configuration set up can be confusing, these are the very same generic store-auth settings cast different ways. Is it desirable to consolidate these? Is one necessarily better or more capable? Icechunk-Python auth and addressing through typed constructor arguments, GDAL through the VSI path plus config.</p>
<section id="what-about-not-python" class="level3">
<h3 class="anchored" data-anchor-id="what-about-not-python">What about not python?</h3>
<p>I don’t have a strong opinion on what’s the right moves, I do have a strong opinion though that this not just a Python community. It was hard looking over the fence at xarray and Zarr and going ‘uhoh, this looks like I can’t ignore it’. The landscape and GDAL’s particular take on it is something I had the privilege to take a long deep dive on. I can’t ever remember the typed constructor incantation above - but I also web search <code>EMPTY_DIR</code> to find <code>GDAL_DISABLE_READDIR_ON_OPEN</code> which I just can’t recall though I reach for it often. This for me is about opening up to audiences that are not already in the tent, and maybe some who won’t ever use Python.</p>
<p>Should we have easier wrappers? Write the helper that sniffs an <code>s3://</code> address and sets the right path-style / anonymous / region knobs? How do we make that cross-language? I love everything out in the open, <code>protocol://path/to/data</code>, a few env vars a few function arguments, but env vars and function calls are hard won expertise.</p>
<p>Is consolidating these worth doing? Is there any scope for that or prior art?</p>
</section>
</section>
<section id="other-r-zarr-readers" class="level2">
<h2 class="anchored" data-anchor-id="other-r-zarr-readers">Other R Zarr readers</h2>
<p>Beyond GDAL, there is growing native R support for Zarr:</p>
<ul>
<li><strong>pizzarr</strong> (CRAN) - pure R Zarr V2 reader; r-universe builds include an optional high-performance Rust backend via the zarrs crate</li>
<li><strong>Rarr</strong> (Bioconducator) - A simple native R reader for Zarr Arrays, Rarr is actively developed and has good support for a growing number of codecs</li>
<li><strong>zarr</strong> (CRAN) - a native implementation in R with support for all required features of Zarr version 3.</li>
<li><strong>CopernicusMarine</strong> - Subset and download marine data from EU Copernicus Marine Service Information, has an in-built Zarr engine designed around the service</li>
<li><strong>zaro</strong> (r-universe) - Low-level Zarr interface (V2 and V3) built on Arrow filesystem and codec infrastructure</li>
<li><strong>RNetCDF</strong>, <strong>ncdf4</strong> - with the right build set up NetCDF has Zarr support, and this for example has been proved for using with <strong>tidync</strong></li>
</ul>
<p>Work is ongoing on multidim API coverage in the R ecosystem, I particularly want tight api bindings to the GDAL API with gdalraster but that will be a while still in the making.</p>
<p>The GDAL multidim API (used by <code>/vsiicechunk/</code>) is distinct from the classic 2D raster driver - terra now auto-detects which to use for the multidim drivers which are VRT/HDF5/NetCDF/Zarr/GRIB. If terra gives unexpected results, check whether it’s related to recent changes in mdim support.</p>
<p>For some time stars via sf has support for accessing Zarr via the classic or multidimensional raster model of GDAL.</p>
<p>For Icechunk specifically see <a href="https://icechunk.io">icechunk.io</a> and see the GDAL icechunk driver docs at <a href="https://gdal.org/en/latest/drivers/raster/icechunk.html">gdal.org icechunk</a> and ZARR driver at <a href="https://gdal.org/en/latest/drivers/raster/zarr.html">gdal.org zarr</a>.</p>


</section>

 ]]></description>
  <category>code</category>
  <category>news</category>
  <guid>https://hypertidy.org/posts/2026-06-26_icechunk-is-coming/</guid>
  <pubDate>Fri, 26 Jun 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>R, GDAL, Zarr, and the Missing Recipe Format for Raster Datasets</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2026-05-27_raster-stack-zarr-virtualization/</link>
  <description><![CDATA[ 






<p><em>The virtual-Zarr format that lets xarray describe 16,000 files in a tiny store doesn’t exist in R yet - but the pieces are in place, this post tries to show where they fit together</em> .</p>
<p>A common scenario in geospatial data workflows is multiple raster files. Let’s consider 23 snapshots of OISST sea surface temperature spread across 2025. One NetCDF file per date, each raster is the same grid, four variables each. Let’s see what R does with that. Here we assume <code>files</code> is a vector of paths to the NetCDF files.</p>
<p>(Fully reproducible setup, downloading directly from NCEI is in the appendix.)</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basename</span>(files))</span>
<span id="cb1-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># chr [1:23] "oisst-avhrr-v02r01.20250101.nc" "oisst-avhrr-v02r01.20250117.nc" "oisst-avhrr-v02r01.20250202.nc" ...</span></span>
<span id="cb1-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(terra)</span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(files)</span>
<span id="cb1-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># class       : SpatRaster</span></span>
<span id="cb1-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># size        : 720, 1440, 92  (nrow, ncol, nlyr)</span></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># resolution  : 0.25, 0.25  (x, y)</span></span>
<span id="cb1-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># extent      : 0, 360, -90, 90</span></span>
<span id="cb1-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># coord. ref. : lon/lat WGS 84 (CRS84)</span></span>
<span id="cb1-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># sources     : oisst-avhrr-v02r01.20250101.nc (4 layers)</span></span>
<span id="cb1-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#               oisst-avhrr-v02r01.20250117.nc (4 layers)</span></span>
<span id="cb1-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#               ... and 21 more sources</span></span>
<span id="cb1-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># varnames    : anom, err, ice, sst, anom, err, ...</span></span>
<span id="cb1-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># names       : anom_zlev=0, err_zlev=0, ice_zlev=0, sst_zlev=0, ...</span></span>
<span id="cb1-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># time (days) : 2025-01-01 to 2025-12-19 (23 steps)</span></span></code></pre></div></div>
<p>The result is pretty good. <code>terra::rast()</code> is no slouch: it reads all subdatasets across all files, concatenates band-wise, preserves the time axis, carries units, and records depth metadata. For a lot of workflows this is exactly what is needed, and it’s lazy — no pixel values are read until they are needed.</p>
<p>But look at the names: <code>anom_zlev=0</code>, <code>err_zlev=0</code>, <code>ice_zlev=0</code>, <code>sst_zlev=0</code> — repeated 23 times, 92 layers total. Four variables and 23 timesteps are there, flattened into band order. The n-D structure — <em>this is a (variable × time × lat × lon) array</em> — is implicit in the interleaving, not encoded anywhere. There’s an implicit contract about how this was unrolled, there are conventions for band ordering, workarounds for the <code>_zlev=0</code> naming. Nothing is wrong, but the band-stack model forces all of that n-D structure into a single axis, and recovering it requires a lot of information that is not usual in the multi-band model.</p>
<p>We can sidestep the variable interleaving with the <code>vrt://</code> URI syntax:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vrt</span>(</span>
<span id="cb2-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vrt://%s?sd_name=sst"</span>, files),</span>
<span id="cb2-3">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/tmp/sst_stack.vrt"</span>,</span>
<span id="cb2-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">options =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-separate"</span>,</span>
<span id="cb2-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">overwrite =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb2-6">)</span>
<span id="cb2-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># class       : SpatRaster</span></span>
<span id="cb2-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># size        : 720, 1440, 23  (nrow, ncol, nlyr)</span></span>
<span id="cb2-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># source      : sst_stack.vrt</span></span>
<span id="cb2-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># names       : r_1, r_2, r_3, ..., r_23</span></span></code></pre></div></div>
<p>One variable, 23 layers. The <code>vrt://</code> GDAL protocol is worth knowing: it lets us name a subdataset in a URI query string, vectorizing cleanly with <code>sprintf</code> and using the underlying raster-stack capability of GDAL VRT (<code>-separate</code>). But there’s a trade-off: no time axis, layer names are <code>r_1</code> through <code>r_23</code> rather than dates. We fixed the variable interleaving problem and lost the coordinate metadata.</p>
<p><code>rast(files, "sst")</code> also selects a single subdataset without the <code>vrt://</code> syntax, and produces the same 23-layer result — but it goes through the <code>ncdf4</code> backend rather than GDAL, so it doesn’t produce a VRT file and doesn’t carry the same interoperability guarantees. The two approaches look similar but are doing different things underneath, and that distinction matters for what comes next.</p>
<p><code>stars</code> approaches this differently. In default <em>proxy</em> (lazy) mode it uses GDAL classic raster and keeps variables as separate attributes, file-per-timestep structure explicit, doing this by harvesting metadata from the underlying files as carried by GDAL. <code>stars::read_mdim()</code> goes further — it uses the GDAL multidimensional API and gives named attributes, real dimension coordinates with udunits, proper n-D structure. The representation is right, but it too has limits; details are in the appendix.</p>
<p>None of these approaches is <em>the best</em> — each embeds real expertise and genuine design choices. But with excellent tools like terra and stars, <strong>you still can’t hand someone a file that says “this is a year of global SST.”</strong> You can hand them code, or you can hand them gigabytes. The code only works if they have the same files in the same place. The gigabytes require a format decision and a copy operation.</p>
<p>There’s no serializable recipe that is light, language-agnostic, and handles a broad variety of cases.</p>
<section id="fifteen-minutes-with-xarray" class="level2">
<h2 class="anchored" data-anchor-id="fifteen-minutes-with-xarray">Fifteen minutes with xarray</h2>
<p>A key moment for me was while learning Python and xarray, I was impressed that xarray could open these files — a huge list of them (16,337 days of OISST at time of writing) as local files or remote URLs. xarray checks them all for consistency, detects that what is really there is four variables in longitude, latitude, and time, and that time is an implicit concatenation from a single time step in each of those thousands of files. It’s remarkable: one object in memory in Python, ready to lazy-read any part of the four 16337×720×1440 arrays. But that took about 15 minutes to run, let alone the software and computing infrastructure setup I had been through. And then: how do you share that progress with colleagues?</p>
<p>Everybody knows you aren’t supposed to serialize in-memory objects to <em>binary</em>, we all have scary experiences with <code>.Rdata</code> and <code>.rds</code>, and Python has the same with its <em>pickle</em>. (I thought: <em>“hmmm, what’s the xarray equivalent of a VRT?”</em> Spoiler: there isn’t one — and although VirtualiZarr does serve that role, it’s missing an intermediate state where we only record what files were opened and what structure was learned.)</p>
<hr>
</section>
<section id="what-the-vrt-already-does" class="level2">
<h2 class="anchored" data-anchor-id="what-the-vrt-already-does">What the VRT already does</h2>
<p>Back to our 23 files — a sample of the 16,337+ in the full OISST set as of writing.</p>
<p>Open <code>/tmp/sst_stack.vrt</code> in a text editor (<code>browseURL("/tmp/sst_stack.vrt")</code> works too). It’s a few kilobytes of XML that fully describes a virtual 23-layer SST dataset — source files, spatial extent, band mapping. It’s a tiny file: you could email it, put it in a repository, or patch the source paths to <code>/vsicurl/https://....nc</code> URLs so it works without any local files at all. Anyone with GDAL can open it with <code>rast("sst_stack.vrt")</code> and get exactly what you built, without copying a byte of the underlying data.</p>
<p>That’s a <em>recipe</em>: we’ve described our dataset as a small chunk of text that GDAL can open very quickly.</p>
<p><strong>VRT</strong> <a href="https://gdal.org/en/stable/drivers/raster/vrt.html">(Virtual Format)</a> is a plain XML file that describes a virtual raster dataset. It can mosaic, warp, reproject, reband, and combine source files without touching the underlying data. For the 2D raster world it is exactly the recipe format that’s missing from the terra/stars in-memory story. The 2D VRT is one of GDAL’s most underappreciated features — already powering a lot of geospatial infrastructure, especially where band-stacking or tile-mosaicking is sufficient as the solution.</p>
<p>So what about the full n-D case: multiple variables, time coordinates, arbitrary dimensions?</p>
<hr>
</section>
<section id="what-zarr-figured-out" class="level2">
<h2 class="anchored" data-anchor-id="what-zarr-figured-out">What Zarr figured out</h2>
<p>The Python/xarray community has been working on exactly this problem, approaching it from the chunk level rather than the file level.</p>
<p>Zarr is a chunked array format. An array is split into regular chunks; each chunk is compressed independently and stored as a separate object — a file, an S3 object, a range of bytes in a larger store. The chunks themselves are opaque: raw numeric arrays in compressed bytes, not self-describing. What makes Zarr work is the metadata sidecar: a small JSON file that records the shape, dtype, chunk layout, compression codec, and dimension coordinates — everything xarray needs to provide a rich, self-describing interface over the data. This is really good for cloud access: fetch only the chunks you need, in parallel, without a format-specific library. It’s a bit like taking a pile of NetCDF files and turning them inside out — all the metadata (tiny in comparison to the data) is placed upfront in JSON, and all the compressed opaque chunks are stored as individually addressable objects.</p>
<p>The deeper insight comes when you realize that <strong>HDF5, netCDF4, GeoTIFF, GRIB, and others already store their data in chunks</strong>. The chunks are buried inside files that require format-specific libraries to navigate, but the byte ranges are all there. We just need an index.</p>
<p><a href="https://github.com/fsspec/kerchunk">kerchunk</a> and its successor <a href="https://virtualizarr.readthedocs.io/">VirtualiZarr</a> do exactly that: open your existing files, find where each chunk lives (file path, byte offset, byte length), and write that index as a JSON or Parquet reference store. The bulk data never moves. What you get is a Zarr-shaped recipe that points back into your original files. It’s worth noting that this idea is not new — NASA and Unidata’s <a href="https://opendap.github.io/DMRpp-wiki/DMRpp.html">DMR++</a> format did the same thing for OPeNDAP, indexing chunk byte-ranges in HDF5/netCDF files as a sidecar that an OPeNDAP server can serve directly. <a href="https://cogeo.org">Cloud-Optimized GeoTIFF</a> is the same idea applied to TIFF: the IFD tile index is moved to the front of the file so a client can read the chunk map in one range request and fetch only what it needs thereafter. The difference is that Zarr’s client-side framing made the pattern composable and ecosystem-wide rather than tied to a specific server or format.</p>
<p>NOTE: this is very much pseudo code showing the overall style - see the <a href="https://virtualizarr.readthedocs.io/en/latest/usage.html">Usage VirtualiZarr pages</a> for more examples, and we have a real example in the appendix.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> virtualizarr <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> open_virtual_dataset</span>
<span id="cb3-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> xarray <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> xr</span>
<span id="cb3-3"></span>
<span id="cb3-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># index the chunks — no data copied</span></span>
<span id="cb3-5">combined <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> xr.concat(</span>
<span id="cb3-6">    [open_virtual_dataset(f) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> f <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> files],</span>
<span id="cb3-7">    dim<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"time"</span></span>
<span id="cb3-8">)</span>
<span id="cb3-9">combined.virtualize.to_kerchunk(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sst_virtual.zarr"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">format</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"zarr"</span>)</span>
<span id="cb3-10"></span>
<span id="cb3-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># open it — chunk-aware, lazy, S3-ready, fully structured</span></span>
<span id="cb3-12">ds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> xr.open_dataset(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sst_virtual.zarr/"</span>, engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"kerchunk"</span>)</span>
<span id="cb3-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># &lt;xarray.Dataset&gt;</span></span>
<span id="cb3-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Dimensions:  (time: 23, zlev: 1, lat: 720, lon: 1440)</span></span>
<span id="cb3-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Coordinates:</span></span>
<span id="cb3-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * time     (time) datetime64[ns] 2025-01-01 ... 2025-12-19</span></span>
<span id="cb3-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * lat      (lat) float32 -90.0 ... 89.75</span></span>
<span id="cb3-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * lon      (lon) float32 0.0 ... 359.75</span></span>
<span id="cb3-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Data variables: anom, err, ice, sst</span></span></code></pre></div></div>
<p>The store is kilobytes of metadata, the actual data stays where it is, and the n-D structure is fully encoded. Compare this to the terra output above:</p>
<ul>
<li><code>sst</code>, <code>anom</code>, <code>err</code>, <code>ice</code> as <strong>named variables</strong>, not interleaved bands</li>
<li><code>time</code> as a real coordinate with date values, not layer indices <code>r_1..r_23</code></li>
<li><code>lat</code>, <code>lon</code>, <code>zlev</code> as labelled dimensions with coordinate values</li>
<li>the whole thing serialized as a directory anyone with Zarr support can open</li>
</ul>
<p>This is what <code>stars::read_mdim()</code> is reaching toward in R — the representation is structurally similar. The difference is that the xarray object came from a small Zarr store, not from reconstructing structure at runtime over 23 original netCDF files. That difference is the recipe.</p>
<hr>
</section>
<section id="gdal-is-the-bridge" class="level2">
<h2 class="anchored" data-anchor-id="gdal-is-the-bridge">GDAL is the bridge</h2>
<p>GDAL already spans both worlds.</p>
<p>GDAL has a <a href="https://gdal.org/en/stable/user/multidim_raster_data_model.html"><strong>multidimensional API</strong></a> (the “mdim” layer) that represents data as named arrays with labelled dimensions — the same model as xarray, not the band-stacked model of classic GDAL rasters. GDAL’s Zarr driver can open VirtualiZarr/kerchunk reference stores through this API. A store created in Python is readable via GDAL — which means it’s reachable from R today.</p>
<p>More importantly, GDAL has <a href="https://gdal.org/en/stable/programs/gdal_mdim_mosaic.html"><code>gdal mdim mosaic</code></a> — a tool that takes a collection of raster files and produces a <strong>multidim VRT</strong> describing them as a unified n-D array dataset. This VRT encodes the array structure, dimension names, coordinate values, and source file mapping. It is the GDAL-native recipe for an n-D dataset — and as shown in the appendix, <code>stars::read_mdim()</code> opens it faithfully, giving you the full multi-file dataset with the right structure, right coordinates, and a serializable description that travels independently of the original files.</p>
<p>Converting a GDAL multidim VRT to a Zarr reference store is a small transformation on kilobytes of XML, not a data operation. That’s the near-term path to R-native VirtualiZarr creation.</p>
<hr>
</section>
<section id="the-gap-creation-not-reading" class="level2">
<h2 class="anchored" data-anchor-id="the-gap-creation-not-reading">The gap: creation, not reading</h2>
<p>R can <em>read</em> virtual stores — Zarr and multidim VRT and VirtualiZarr Parquet reference via <code>stars::read_mdim()</code>, <code>gdalraster::mdim_translate</code> or <a href="https://github.com/hypertidy/zaro"><code>zaro</code></a> or real Zarr with <a href="https://CRAN.R-project.org/package=pizzarr">pizzarr</a> or <a href="https://CRAN.R-project.org/package=zarr">zarr</a>. What R can’t yet do is <em>create</em> the chunk-level byte-reference stores that VirtualiZarr generates for HDF5 and netCDF.</p>
<p>That’s a frontier, and I’ve been exloring where the pieces could converge:</p>
<p><strong><code>gdal mdim mosaic</code></strong> creates multidim VRTs from file collections today. The XML fully describes what a VirtualiZarr store needs — shape, chunks, coordinate values, source file paths and byte offsets. This is the hard structural work; emitting the Zarr reference store format from it is a straightforward conversion.</p>
<p><strong><code>rhdf5</code></strong> can now open remote HDF5 files at URLs or on S3 (dev version on GitHub). The next step is extracting chunk byte-reference indices directly - a core operation that VirtualiZarr performs in Python (with HDF5 library, GRIB libraries, TIFF libraries some in C++ and some in Rust). Step 7 in the appendix shows remote access, and a pending PR in my rhdf5 fork has already use that to harvest remote byte references from HDF5 and NetCDF.</p>
<p><strong><code>zaro</code></strong> (pure-R Zarr reader via Arrow) already reads VirtualiZarr Parquet stores. The reading side is there, and needs comparison with <code>pizzarr</code>, and <code>zarr</code> and other zarr-enabled packages.</p>
<p><strong><code>vrtstack</code></strong> generates multidim VRTs from 2D raster collections in R - the <code>gdal mdim mosaic</code> equivalent <em>for simple cases of multiple 2D raster</em> - without leaving R.</p>
<p>The path: <code>vrtstack</code> or <code>gdal mdim mosaic</code> for file collections → emit Zarr reference store → readable by <code>zaro</code>, xarray, or any Zarr-aware tool. In this way R can become a first-class creator of portable dataset descriptions, not just a consumer of what Python produces.</p>
<hr>
</section>
<section id="why-this-matters-beyond-r" class="level2">
<h2 class="anchored" data-anchor-id="why-this-matters-beyond-r">Why this matters beyond R</h2>
<p>A Zarr reference store created from OISST netCDF files is immediately openable in Python, R, GDAL and in theory any tool that speaks Zarr.</p>
<p>STAC is complementary but different: STAC describes <em>where</em> files are and their spatiotemporal footprint. A virtual store describes <em>what the dataset structurally is</em> — how chunks map to array coordinates, what the dimensions mean, how to reassemble a slice. A STAC item can point to a virtual store the way it points to a COG.</p>
<p>The R community has genuine leverage here. GDAL is the common substrate between R and the xarray/Zarr ecosystem. R is not just catching up, there are things we can do that aren’t on any other roadmap.</p>
<hr>
</section>
<section id="what-would-help" class="level2">
<h2 class="anchored" data-anchor-id="what-would-help">What would help</h2>
<p>If you work with time series of raster files and you’ve felt this friction:</p>
<ul>
<li><strong>Talk about your use case</strong> — what files, what structure, what would a portable dataset description let you do that you can’t do today?</li>
<li><strong>Try <code>terra::vrt()</code> and try the <code>vrt://</code> URI syntax</strong> for netCDF subdataset selection.</li>
<li><strong>Try <code>stars::read_mdim()</code> on a <code>gdal mdim mosaic</code> VRT</strong> — the full tour in the appendix shows how these fit together</li>
<li><strong>Try <code>remotes::install_github("hypertidy/tidync@multi-input")</code></strong> if you have remote netCDF files and want to skip the download entirely — Step 8 in the appendix shows what this already looks like.</li>
<li><strong>Look at <code>vrtstack</code> and <code>zaro</code></strong> on the <a href="https://github.com/hypertidy">hypertidy GitHub</a>, vrtstack builds a multidim VRT from 2D rasters (multidim GDAL supports COG, but doesn’t support <em>builiding these</em>), zaro is a read-implementation for Zarr that is primarily based around Arrow.</li>
<li><strong>File issues against GDAL’s multidim API</strong> when you find gaps — R users exercising it in real workflows makes it better for everyone.</li>
<li><strong>Check out gdalraster (and my multidim branch)</strong> there’s a long way to go for multidim but <a href="https://firelab.github.io/gdalraster/">gdalraster</a> is a rich package has a super strong basis for faithfully carrying the core facilities of the multidim api <a href="https://github.com/mdsumner/gdalraster/tree/gdalmultidim-api">exposed to R</a>.</li>
</ul>
<hr>
</section>
<section id="appendix" class="level2">
<h2 class="anchored" data-anchor-id="appendix">Appendix: a progressive tour on 23 OISST files</h2>
<section id="appendix-setup" class="level3">
<h3 class="anchored" data-anchor-id="appendix-setup">Setup: download 23 OISST files from NCEI</h3>
<p>All code below uses only this setup, and we use a multidim VRT representation later to act as an intermediate form.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(glue)</span>
<span id="cb4-2"></span>
<span id="cb4-3">date  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.Date</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2025-01-01"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"16 days"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length.out =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">23</span>)</span>
<span id="cb4-4">base0 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://www.ncei.noaa.gov/data/sea-surface-temperature-optimum-interpolation/v2.1/access/avhrr"</span></span>
<span id="cb4-5">ym    <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">format</span>(date, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%Y%m"</span>)</span>
<span id="cb4-6">ymd   <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">format</span>(date, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%Y%m%d"</span>)</span>
<span id="cb4-7">urls  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"{base0}/{ym}/oisst-avhrr-v02r01.{ymd}.nc"</span>)</span>
<span id="cb4-8"></span>
<span id="cb4-9">dir   <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempdir</span>()</span>
<span id="cb4-10">files <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">file.path</span>(dir, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">basename</span>(urls))</span>
<span id="cb4-11"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">download.file</span>(urls, files, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"libcurl"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mode =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wb"</span>)</span></code></pre></div></div>
<section id="setup-part-2-create-a-gdal-multidimensional-vrt" class="level4">
<h4 class="anchored" data-anchor-id="setup-part-2-create-a-gdal-multidimensional-vrt">Setup part 2: create a GDAL multidimensional VRT</h4>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">writeLines</span>(glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/{urls}"</span>), tf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>())</span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system</span>(glue<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gdal mdim mosaic @{tf} oisst_2025_sample.vrt"</span>))</span>
<span id="cb5-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## piggyback::pb_upload("oisst_2025_sample.vrt")</span></span></code></pre></div></div>
<p>The URL structure itself is the catalogue: a simple path template over date components, no database required. 23 files, ~3.5MB each, ~80MB total.</p>
</section>
</section>
<section id="step-1-terra-rast-band-stacked-all-variables-time-preserved" class="level3">
<h3 class="anchored" data-anchor-id="step-1-terra-rast-band-stacked-all-variables-time-preserved">Step 1 — terra: <code>rast()</code>, band-stacked, all variables, time preserved</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(files)</span>
<span id="cb6-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># class       : SpatRaster</span></span>
<span id="cb6-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># size        : 720, 1440, 92  (nrow, ncol, nlyr)</span></span>
<span id="cb6-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># sources     : oisst-avhrr-v02r01.20250101.nc (4 layers)</span></span>
<span id="cb6-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#               ... and 22 more sources</span></span>
<span id="cb6-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># varnames    : anom, err, ice, sst, anom, err, ice, sst, ...</span></span>
<span id="cb6-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># names       : anom_zlev=0, err_zlev=0, ice_zlev=0, sst_zlev=0, ...</span></span>
<span id="cb6-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># unit        :      Celsius,    Celsius,          %,    Celsius, ...</span></span>
<span id="cb6-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># time (days) : 2025-01-01 to 2025-12-19 (23 steps)</span></span></code></pre></div></div>
<p>terra uses the <code>ncdf4</code> R package for netCDF reads — a design inherited from the <code>raster</code> package - rather than routing through GDAL. This is why its behaviour differs from stars proxy mode. The time axis survives via ncdf4’s own metadata handling. The n-D structure is flattened into 92 bands; recovering it means knowing the 4-variable interleaving convention.</p>
<p>Bundling all bands from all variables that share the same dimensions is a choice made by terra, GDAL has a similar capacity but it is not used here (and is in fact unusable by these files for other reasons).</p>
</section>
<section id="step-2-terra-vrt-with-vrt-single-variable-time-lost" class="level3">
<h3 class="anchored" data-anchor-id="step-2-terra-vrt-with-vrt-single-variable-time-lost">Step 2 — terra: <code>vrt()</code> with <code>vrt://</code>, single variable, time lost</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vrt</span>(</span>
<span id="cb7-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"vrt://%s?sd_name=sst"</span>, files),</span>
<span id="cb7-3">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/tmp/sst_stack.vrt"</span>,</span>
<span id="cb7-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">options =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-separate"</span>,</span>
<span id="cb7-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">overwrite =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span></span>
<span id="cb7-6">)</span>
<span id="cb7-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># class       : SpatRaster</span></span>
<span id="cb7-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># size        : 720, 1440, 23  (nrow, ncol, nlyr)</span></span>
<span id="cb7-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># source      : sst_stack.vrt</span></span>
<span id="cb7-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># names       : r_1, r_2, r_3, ..., r_23</span></span></code></pre></div></div>
<p><code>vrt://</code> URI syntax selects a subdataset inline; <code>?sd_name=sst</code> is the query param.. The result is a real file — a 2D recipe for this one variable. But trade-offs: time coordinate is gone, layer names are positional. The 2D VRT has no slot for dimension coordinates, it can only carry raw metadata on a dataset or on a band.</p>
</section>
<section id="step-3-stars-read_stars-proxy-gdal-classic-raster-variables-separated" class="level3">
<h3 class="anchored" data-anchor-id="step-3-stars-read_stars-proxy-gdal-classic-raster-variables-separated">Step 3 — stars: <code>read_stars()</code> proxy, GDAL classic raster, variables separated</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_stars</span>(files)</span>
<span id="cb8-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># stars_proxy object with 4 attributes in 92 file(s):</span></span>
<span id="cb8-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># $sst</span></span>
<span id="cb8-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  [1] "[...]/oisst-avhrr-v02r01.20250101.nc:sst"</span></span>
<span id="cb8-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  [2] "[...]/oisst-avhrr-v02r01.20250117.nc:sst"</span></span>
<span id="cb8-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  ...</span></span>
<span id="cb8-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># $anom, $err, $ice  (similarly, 23 files each)</span></span>
<span id="cb8-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span></span>
<span id="cb8-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># dimension(s):</span></span>
<span id="cb8-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#      from   to offset delta  refsys x/y</span></span>
<span id="cb8-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># x       1 1440      0  0.25      NA [x]</span></span>
<span id="cb8-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># y       1  720     90 -0.25      NA [y]</span></span>
<span id="cb8-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># zlev    1    1  0 [m]    NA udunits</span></span>
<span id="cb8-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># time    1   23     NA    NA      NA</span></span></code></pre></div></div>
<p>stars proxy mode uses GDAL classic raster and separates variables as attributes rather than interleaving as bands — a meaningful structural difference from terra. Time is present as a dimension but without coordinate values, it’s fully lazy at this point as made clear by the lists of files in subdataset syntax.</p>
</section>
<section id="step-4-stars-read_mdim-on-a-single-file-right-model-wrong-scope" class="level3">
<h3 class="anchored" data-anchor-id="step-4-stars-read_mdim-on-a-single-file-right-model-wrong-scope">Step 4 — stars: <code>read_mdim()</code> on a single file, right model, wrong scope</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1">stars<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_mdim</span>(files[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>L])</span>
<span id="cb9-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># stars object with 4 dimensions and 4 attributes</span></span>
<span id="cb9-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># attribute(s):</span></span>
<span id="cb9-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#            Min.  1st Qu.  Median      Mean  3rd Qu.   Max.     NAs</span></span>
<span id="cb9-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># sst [°C]  -1.80    -1.80   -1.78  -1.70779    -1.64  -1.03   89635</span></span>
<span id="cb9-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># anom [°C] -0.72    -0.08   -0.02  -0.03531     0.00   0.49   89635</span></span>
<span id="cb9-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># err [°C]   0.30     0.30    0.30   0.30446     0.30   0.35   89635</span></span>
<span id="cb9-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ice [%]    0.19     0.81    0.95   0.87747     0.98   1.00   91877</span></span>
<span id="cb9-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># dimension(s):</span></span>
<span id="cb9-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#      from   to  offset  delta          refsys x/y</span></span>
<span id="cb9-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># lon     1 1440       0   0.25  WGS 84 (CRS84) [x]</span></span>
<span id="cb9-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># lat     1  720     -90   0.25  WGS 84 (CRS84) [y]</span></span>
<span id="cb9-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># zlev    1    1  0 [m]      NA         udunits</span></span>
<span id="cb9-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># time    1    1  17532 [days since 1978-01-01 12:00:00]  NA  udunits</span></span></code></pre></div></div>
<p><code>read_mdim()</code> goes through GDAL’s multidimensional API: named attributes, labelled dimensions, udunits-encoded time coordinate, proper spatial reference. This is a rich representation of the dataset.</p>
<p>But pass stars all 23 files and it silently opens only the first, one timestep, and no error. stars has other ways of concatenating files <code>along</code> dimensions but it’s only applied to GDAL classic raster context.</p>
<p>This is a pivot point.</p>
</section>
<section id="step-5-gdal-mdim-mosaic-read_mdim-the-full-tour" class="level3">
<h3 class="anchored" data-anchor-id="step-5-gdal-mdim-mosaic-read_mdim-the-full-tour">Step 5 — <code>gdal mdim mosaic</code> + <code>read_mdim()</code>, the full tour</h3>
<p><code>gdal mdim mosaic</code> is the missing piece. It takes a collection of files and produces a multidim VRT that describes them as a unified n-D array — dimension coordinates and all:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb10-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># writeLines(sprintf("/vsicurl/%s", urls), "filelist.txt")</span></span>
<span id="cb10-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">gdal</span> mdim mosaic <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--input</span> @filelist.txt <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-o</span> /tmp/sst_mdim.vrt</span></code></pre></div></div>
<p>Or from R via <code>vrtstack</code> or a direct <code>system()</code> call. Now hand that VRT to <code>read_mdim()</code>:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1">stars<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_mdim</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/tmp/sst_mdim.vrt"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">proxy =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb11-2">stars_proxy object with <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span> attributes <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">file</span>(s)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb11-3"><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">$</span>sst</span>
<span id="cb11-4">[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[...]/sst_mdim.vrt"</span></span>
<span id="cb11-5"></span>
<span id="cb11-6"><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>anom</span>
<span id="cb11-7">[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[...]/sst_mdim.vrt"</span></span>
<span id="cb11-8"></span>
<span id="cb11-9"><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>err</span>
<span id="cb11-10">[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[...]/sst_mdim.vrt"</span></span>
<span id="cb11-11"></span>
<span id="cb11-12"><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>ice</span>
<span id="cb11-13">[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[...]/sst_mdim.vrt"</span></span>
<span id="cb11-14"></span>
<span id="cb11-15"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dimension</span>(s)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb11-16">     from   to offset delta x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>y</span>
<span id="cb11-17">lon     <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1440</span>      <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span> [x]</span>
<span id="cb11-18">lat     <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>  <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">720</span>    <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span> [y]</span>
<span id="cb11-19">zlev    <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>    <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>      <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>    <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb11-20">time    <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>   <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">23</span>  <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">17167</span>    <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span></span></code></pre></div></div>
<p>23 time steps in <code>/tmp/sst_mdim.vrt</code> which is a tiny file of XML.</p>
<p>This is what <code>gdal mdim mosaic</code> unlocks: <code>read_mdim()</code> and friends need VRT to make the multi-file case work.</p>
</section>
<section id="step-6-skip-the-download-url-access-who-can-and-cant" class="level3">
<h3 class="anchored" data-anchor-id="step-6-skip-the-download-url-access-who-can-and-cant">Step 6 — skip the download: URL access, who can and can’t</h3>
<p>The files we downloaded are publicly accessible over plain HTTPS. Why download at all? Let’s see who can open them directly.</p>
<p><strong>GDAL</strong> — just works. GDAL’s <code>/vsicurl/</code> virtual filesystem handles HTTP range requests transparently, and both <code>terra::rast()</code> (via GDAL for the spatial read) and <code>stars::read_mdim()</code> can open the URLs directly once you prefix them appropriately. No download needed.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># GDAL-backed read direct from URL</span></span>
<span id="cb12-2">stars<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_mdim</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste0</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/"</span>, urls[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>L]))</span>
<span id="cb12-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># stars object with 4 dimensions and 4 attributes</span></span>
<span id="cb12-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ... same output as Step 4, no local file required</span></span></code></pre></div></div>
<p><strong>ncdf4</strong> — the picture is more complicated. ncdf4 routes through the netCDF-C library, which expects either a local file path or an OPeNDAP/Thredds <code>dodsC</code> URL. A plain HTTPS URL fails, and the error is instructive:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1">ncdf4<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nc_open</span>(urls[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb13-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># syntax error, unexpected WORD_WORD, expecting SCAN_ATTR or</span></span>
<span id="cb13-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># SCAN_DATASET or SCAN_ERROR</span></span>
<span id="cb13-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># context: &lt;!DOCTYPE^ HTML PUBLIC ...&gt;&lt;h1&gt;Not Found&lt;/h1&gt;...</span></span>
<span id="cb13-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Error in ncdf4::nc_open: NetCDF: file not found</span></span></code></pre></div></div>
<p>ncdf4 tried to parse the 404 HTML response as netCDF syntax. But there’s a workaround — the <code>#mode=bytes</code> suffix instructs the HDF5 layer to use HTTP byte-range requests rather than treating the URL as a file path:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1">ncdf4<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nc_open</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%s#mode=bytes"</span>, urls[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]))</span>
<span id="cb14-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># File https://...oisst-avhrr-v02r01.20250101.nc#mode=bytes</span></span>
<span id="cb14-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># (NC_FORMAT_NETCDF4):</span></span>
<span id="cb14-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   4 variables (excluding dimension variables):</span></span>
<span id="cb14-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   sst, anom, err, ice ...</span></span></code></pre></div></div>
<p>It works — but you have to know the magic suffix. And because terra’s netCDF reading is backed by ncdf4, it inherits this same limitation: plain HTTPS URLs don’t work without <code>#mode=bytes</code>, and OPeNDAP <code>dodsC</code> URLs are the usual workaround for terra users working with remote data.</p>
<p>This is the library-identity problem: the same URL provides three different outcomes depending on which library is doing the opening. GDAL’s cloud-native HTTP access is a first-class citizen but the ’/vsi*’ prefix is clearly not popular in some communities; NetCDF’s is an afterthought requiring a suffix that hardly anyone seems to know about. The recipe format inherits these differences — a VRT that references HTTPS URLs is GDAL-native and just works; a workflow built on NetCDF needs extra plumbing.</p>
</section>
<section id="step-7-rhdf5-dev-opening-the-door-to-chunk-indexing-dev-not-yet-on-cran" class="level3">
<h3 class="anchored" data-anchor-id="step-7-rhdf5-dev-opening-the-door-to-chunk-indexing-dev-not-yet-on-cran">Step 7 — rhdf5-dev: opening the door to chunk indexing <em>(dev, not yet on CRAN)</em></h3>
<p>The development version of <code>rhdf5</code> on GitHub can open remote HDF5 files over HTTPS and S3 using the ROS3 virtual file driver — no download, no <code>#mode=bytes</code> workaround, just direct anonymous access:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># remotes::install_github("grimbough/rhdf5")</span></span>
<span id="cb15-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(rhdf5)</span>
<span id="cb15-3"></span>
<span id="cb15-4">fapl <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">H5Pcreate</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"H5P_FILE_ACCESS"</span>)</span>
<span id="cb15-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">H5Pset_fapl_ros3</span>(fapl)   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># no credentials → anonymous mode</span></span>
<span id="cb15-6"></span>
<span id="cb15-7">fid <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">H5Fopen</span>(urls[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">flags =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"H5F_ACC_RDONLY"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fapl =</span> fapl)</span>
<span id="cb15-8">fid</span>
<span id="cb15-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># HDF5 FILE</span></span>
<span id="cb15-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#         name /</span></span>
<span id="cb15-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     filename</span></span>
<span id="cb15-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span></span>
<span id="cb15-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   name       otype       dclass              dim</span></span>
<span id="cb15-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 0 anom  H5I_DATASET    INTEGER  1440 x 720 x 1 x 1</span></span>
<span id="cb15-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 1 err   H5I_DATASET    INTEGER  1440 x 720 x 1 x 1</span></span>
<span id="cb15-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 2 ice   H5I_DATASET    INTEGER  1440 x 720 x 1 x 1</span></span>
<span id="cb15-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 3 lat   H5I_DATASET      FLOAT  720</span></span>
<span id="cb15-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 4 lon   H5I_DATASET      FLOAT  1440</span></span>
<span id="cb15-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 5 sst   H5I_DATASET    INTEGER  1440 x 720 x 1 x 1</span></span>
<span id="cb15-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 6 time  H5I_DATASET      FLOAT  1</span></span>
<span id="cb15-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 7 zlev  H5I_DATASET      FLOAT  1</span></span></code></pre></div></div>
<p>What you’re seeing here is the raw HDF5 structure of the file — variables as datasets, dimensions as separate float arrays, all visible without reading a single data value. This is exactly the level at which VirtualiZarr operates: it walks this structure, reads the chunk B-tree for each dataset, and records the byte offset and length of every chunk.</p>
<p>Once <code>rhdf5</code> can expose those chunk byte-references — which is the next step in its development — R will have a native path to VirtualiZarr store creation without Python, without shelling out, and working directly on files at HTTPS or S3 URLs. The <code>H5Pset_fapl_ros3()</code> call with no credentials is the anonymous S3/HTTPS access pattern: it works for any publicly accessible endpoint that supports range requests, including NCEI, NASA Earthdata public buckets, and most open data archives.</p>
<p>The reading side (<code>zaro</code>) is already there. The indexing side (<code>rhdf5-dev</code>) is almost there. The assembly side (<code>gdal mdim mosaic</code> → Zarr reference store) is a small conversion on top of infrastructure that already exists. The pieces are in place.</p>
</section>
<section id="step-8-tidync-dev-multi-file-remote-concat-in-one-call-unmerged-dev-branch" class="level3">
<h3 class="anchored" data-anchor-id="step-8-tidync-dev-multi-file-remote-concat-in-one-call-unmerged-dev-branch">Step 8 — tidync dev: multi-file remote concat in one call <em>(unmerged dev branch)</em></h3>
<p>tidync recently got an update in a dev branch to accept multiple files — long on the wishlist but out of reach in the early years of the package. I had also forgotten that remote access to NetCDF is possible via its own library by appending <code>#mode=bytes</code> to the URL — this means we don’t always need an OPeNDAP-enabled server for remote read. (GDAL uses its own techniques for remote access via <code>/vsicurl/</code>.)</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># remotes::install_github("hypertidy/tidync@multi-input")</span></span>
<span id="cb16-2">tidync<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tidync</span>(</span>
<span id="cb16-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%s#mode=bytes"</span>, urls),</span>
<span id="cb16-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fast =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>,</span>
<span id="cb16-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">concat_dim =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"time"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">values =</span> date)</span>
<span id="cb16-6">)</span>
<span id="cb16-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># not a file:</span></span>
<span id="cb16-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ' https://.../oisst-avhrr-v02r01.20250101.nc#mode=bytes '</span></span>
<span id="cb16-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span></span>
<span id="cb16-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ... attempting remote connection</span></span>
<span id="cb16-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span></span>
<span id="cb16-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Connection succeeded.</span></span>
<span id="cb16-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Data Source (23): oisst-avhrr-v02r01.20250101.nc#mode=bytes,</span></span>
<span id="cb16-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#                   oisst-avhrr-v02r01.20250117.nc#mode=bytes ...</span></span>
<span id="cb16-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Concatenated along 'time' (23/23 steps, 23 sources, fast mode)</span></span>
<span id="cb16-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span></span>
<span id="cb16-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Grids (5) &lt;dimension family&gt; : &lt;associated variables&gt;</span></span>
<span id="cb16-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span></span>
<span id="cb16-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [1]   D3,D2,D1,D0 : sst, anom, err, ice    **ACTIVE GRID**</span></span>
<span id="cb16-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [2]   D0          : time</span></span>
<span id="cb16-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [3]   D1          : zlev</span></span>
<span id="cb16-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [4]   D2          : lat</span></span>
<span id="cb16-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [5]   D3          : lon</span></span>
<span id="cb16-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span></span>
<span id="cb16-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Dimensions 4 (all active):</span></span>
<span id="cb16-26"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   dim  name  length     min       max  unlim coord_dim</span></span>
<span id="cb16-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   D0   time      23   20089     20441   TRUE  TRUE</span></span>
<span id="cb16-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   D1   zlev       1       0         0  FALSE  TRUE</span></span>
<span id="cb16-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   D2   lat      720  -89.875   89.875  FALSE  TRUE</span></span>
<span id="cb16-30"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   D3   lon     1440    0.125   359.88  FALSE  TRUE</span></span></code></pre></div></div>
<p>Twenty-three remote netCDF files concatenated into one lazy n-D dataset in a single call — <code>#mode=bytes</code> vectorized over the URL vector, a synthetic time axis injected via <code>concat_dim</code>, all four variables on the active grid, unlimited time dimension, proper coordinates throughout. We have tested this on the full set of 16,000+ URLs and it opens in less than a minute using the <code>fast</code> and <code>concat_dim</code> mechanism to declare the values on the concatenating dimension.</p>
<p>The “not a file / attempting remote connection / Connection succeeded” in the output is tidync doing its own detective work: it knows this isn’t a local path, tries the remote connection, and succeeds. The <code>#mode=bytes</code> suffix — the ncdf4 workaround from Step 6 — unlocks the whole thing.</p>
<p>This is an R equivalent of the xarray open: the same structure, the same laziness, the same multi-file concatenation. The recipe here is the code rather than a store on disk — and the <code>tidync</code> object it produces is fully navigable with <code>hyper_filter()</code> and <code>hyper_array()</code> without touching the data. The serializable recipe (the Zarr store, the multidim VRT) is still the goal for sharing and interoperability, but as a working representation for analysis, this is already there.</p>
<p>In the last section of the appendix we virtualize to the “normal” xarray/Zarr model, but then open that again with different tools. The same store, opened by four different tools across two languages - there’s a recipe, but it’s not a nailed down ecosystem yet.</p>
</section>
<section id="the-xarray-counterpart-for-comparison" class="level3">
<h3 class="anchored" data-anchor-id="the-xarray-counterpart-for-comparison">The xarray counterpart — for comparison</h3>
<p>First create the VirtualiZarr version. We use the GDAL mdim VRT hosted above because it’s convenient — and that’s where this effort will start: GDAL already has all the metadata and array concatenating logic, and we can pair that with byte reference extraction improvements to GDAL’s <code>GetRawBlockInfo()</code>.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> lxml <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> etree</span>
<span id="cb17-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> requests</span>
<span id="cb17-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> urllib.parse <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> urlparse</span>
<span id="cb17-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> xarray <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> xr</span>
<span id="cb17-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> obstore.store <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> HTTPStore</span>
<span id="cb17-6"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> obspec_utils.registry <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> ObjectStoreRegistry</span>
<span id="cb17-7"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> virtualizarr <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> open_virtual_mfdataset</span>
<span id="cb17-8"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> virtualizarr.parsers <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> HDFParser</span>
<span id="cb17-9"></span>
<span id="cb17-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 1. parse the VRT to get source URLs</span></span>
<span id="cb17-11">r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> requests.get(</span>
<span id="cb17-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://github.com/mdsumner/quarto-blog/releases/download/latest/oisst_2025_sample.vrt"</span></span>
<span id="cb17-13">)</span>
<span id="cb17-14">tree <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> etree.fromstring(r.content)</span>
<span id="cb17-15">urls <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sorted</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span>(             <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># sorted: set() loses order, filenames are date-stamped</span></span>
<span id="cb17-16">    el.text.replace(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>)</span>
<span id="cb17-17">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> el <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> tree.findall(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".//SourceFilename"</span>)</span>
<span id="cb17-18">))</span>
<span id="cb17-19"></span>
<span id="cb17-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 2. set up the object store (anonymous HTTP)</span></span>
<span id="cb17-21">parsed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> urlparse(urls[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>])</span>
<span id="cb17-22">bucket <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>parsed<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>scheme<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">://</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>parsed<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>netloc<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb17-23">registry <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ObjectStoreRegistry({bucket: HTTPStore.from_url(bucket)})</span>
<span id="cb17-24">parser <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> HDFParser()</span>
<span id="cb17-25"></span>
<span id="cb17-26"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 3. open as a single virtual dataset — no data read, no files downloaded</span></span>
<span id="cb17-27">combined <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> open_virtual_mfdataset(</span>
<span id="cb17-28">    urls,</span>
<span id="cb17-29">    concat_dim<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"time"</span>,</span>
<span id="cb17-30">    parser<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>parser,</span>
<span id="cb17-31">    registry<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>registry,</span>
<span id="cb17-32">    combine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"nested"</span>,</span>
<span id="cb17-33">)</span>
<span id="cb17-34"></span>
<span id="cb17-35"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 4. serialize — a directory store describing all 23 files</span></span>
<span id="cb17-36">combined.virtualize.to_kerchunk(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sst_virtual.zarr"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">format</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"zarr"</span>)</span></code></pre></div></div>
<p>Now open with xarray:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># note the trailing slash — this is a Zarr directory store, not a single file</span></span>
<span id="cb18-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># fsspec needs it to resolve the .zmetadata index correctly</span></span>
<span id="cb18-3">ds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> xr.open_dataset(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sst_virtual.zarr/"</span>, engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"kerchunk"</span>)</span>
<span id="cb18-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># &lt;xarray.Dataset&gt; Size: 763MB</span></span>
<span id="cb18-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Dimensions:  (time: 23, zlev: 1, lat: 720, lon: 1440)</span></span>
<span id="cb18-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Coordinates:</span></span>
<span id="cb18-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * time  (time) datetime64[ns] 2025-01-01T12:00:00 ... 2025-12-19T12:00:00</span></span>
<span id="cb18-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * zlev  (zlev) float32 0.0</span></span>
<span id="cb18-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * lat   (lat) float32 -89.88 -89.62 ... 89.62 89.88</span></span>
<span id="cb18-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#   * lon   (lon) float32 0.125 0.375 ... 359.6 359.9</span></span>
<span id="cb18-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Data variables:</span></span>
<span id="cb18-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     anom  (time, zlev, lat, lon) float64 191MB ...</span></span>
<span id="cb18-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     err   (time, zlev, lat, lon) float64 191MB ...</span></span>
<span id="cb18-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     ice   (time, zlev, lat, lon) float64 191MB ...</span></span>
<span id="cb18-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     sst   (time, zlev, lat, lon) float64 191MB ...</span></span>
<span id="cb18-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Attributes: (12/37)</span></span>
<span id="cb18-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     Conventions:   CF-1.6, ACDD-1.3</span></span>
<span id="cb18-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     title:         NOAA/NCEI 1/4 Degree Daily Optimum Interpolation ...</span></span>
<span id="cb18-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     metadata_link: https://doi.org/10.25921/RE9P-PT57</span></span>
<span id="cb18-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#     sensor:        Thermometer, AVHRR</span></span></code></pre></div></div>
<p>That virtual store is available here:</p>
<pre><code>https://raw.githubusercontent.com/mdsumner/quarto-blog/refs/heads/main/data/sst_virtual.zarr</code></pre>
<p>Open with xarray directly from the URL (note the trailing slash):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1">xr.open_dataset(</span>
<span id="cb20-2">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://raw.githubusercontent.com/mdsumner/quarto-blog/refs/heads/main/data/sst_virtual.zarr/"</span>,</span>
<span id="cb20-3">    engine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"kerchunk"</span></span>
<span id="cb20-4">)</span></code></pre></div></div>
<p>Open with GDAL:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> osgeo <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> gdal</span>
<span id="cb21-2">ds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gdal.OpenEx(</span>
<span id="cb21-3">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ZARR:</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/vsicurl/https://raw.githubusercontent.com/mdsumner/quarto-blog/refs/heads/main/data/sst_virtual.zarr</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>,</span>
<span id="cb21-4">    gdal.OF_MULTIDIM_RASTER</span>
<span id="cb21-5">)</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb22-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">gdal</span> mdim info <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ZARR:</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/vsicurl/https://raw.githubusercontent.com/mdsumner/quarto-blog/refs/heads/main/data/sst_virtual.zarr</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span></code></pre></div></div>
<p>Open with zaro:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb23-1">z <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">zaro</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"virtualizarr://https://raw.githubusercontent.com/mdsumner/quarto-blog/refs/heads/main/data/sst_virtual.zarr"</span>)</span>
<span id="cb23-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">zaro_meta</span>(z)</span>
<span id="cb23-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [zaro] found .zmetadata (Zarr V2 consolidated)</span></span>
<span id="cb23-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># [zaro]   8 arrays: anom, err, ice, lat, lon, sst, time, zlev</span></span>
<span id="cb23-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># &lt;zaro::ZaroMeta&gt;</span></span>
<span id="cb23-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  @ zarr_format    : int 2</span></span>
<span id="cb23-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  @ node_type      : chr "group"</span></span>
<span id="cb23-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  @ attributes     :List of 37</span></span>
<span id="cb23-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  .. $ Conventions: chr "CF-1.6, ACDD-1.3"</span></span>
<span id="cb23-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  .. $ title      : chr "NOAA/NCEI 1/4 Degree Daily Optimum Interpolation ..."</span></span>
<span id="cb23-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  .. $ metadata_link: chr "https://doi.org/10.25921/RE9P-PT57"</span></span>
<span id="cb23-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#  ...</span></span></code></pre></div></div>
<p>Open with stars:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb24-1">stars<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_mdim</span>(</span>
<span id="cb24-2">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ZARR:</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/vsicurl/https://raw.githubusercontent.com/mdsumner/quarto-blog/refs/heads/main/data/sst_virtual.zarr</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb24-3">)</span>
<span id="cb24-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># stars object with 4 dimensions and 4 attributes</span></span>
<span id="cb24-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># attribute(s), summary of first 1e+05 cells:</span></span>
<span id="cb24-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#            Min. 1st Qu. Median       Mean 3rd Qu. Max.   NAs</span></span>
<span id="cb24-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># anom [°C] -1.58   -0.61  -0.43 -0.3861891   -0.20 1.45 89635</span></span>
<span id="cb24-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># err [°C]   0.30    0.30   0.30  0.3042393    0.30 0.35 89635</span></span>
<span id="cb24-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ice [%]    0.16    0.62   0.87  0.7743456    0.96 1.00 93223</span></span>
<span id="cb24-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># sst [°C]  -1.80   -1.80  -1.66 -1.4256025   -1.29 1.19 89635</span></span>
<span id="cb24-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># dimension(s):</span></span>
<span id="cb24-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#      from   to                                 offset</span></span>
<span id="cb24-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># lon     1 1440                                      0</span></span>
<span id="cb24-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># lat     1  720                                    -90</span></span>
<span id="cb24-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># zlev    1    1                                  0 [m]</span></span>
<span id="cb24-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># time    1   23  17167 [days since 1978-01-01T12:00:00]</span></span>
<span id="cb24-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#                                    delta         refsys x/y</span></span>
<span id="cb24-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># lon                                 0.25 WGS 84 (CRS84) [x]</span></span>
<span id="cb24-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># lat                                 0.25 WGS 84 (CRS84) [y]</span></span>
<span id="cb24-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># zlev                                  NA        udunits</span></span>
<span id="cb24-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># time  16 [days since 1978-01-01T12:00:00]        udunits</span></span></code></pre></div></div>
<p>Oh, and turns out <code>terra::rast()</code> <em>does</em> support multidim (not our VRT file sadly):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb25" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb25-1">r <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ZARR:</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/vsicurl/https://raw.githubusercontent.com/mdsumner/quarto-blog/refs/heads/main/data/sst_virtual.zarr</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">md  =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb25-2">class       <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> SpatRaster</span>
<span id="cb25-3">size        <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">720</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1440</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">92</span>  (nrow, ncol, nlyr)</span>
<span id="cb25-4">resolution  <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>  (x, y)</span>
<span id="cb25-5">extent      <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">360</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>  (xmin, xmax, ymin, ymax)</span>
<span id="cb25-6">coord. ref. <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> lon<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span>lat WGS <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">84</span> (CRS84) (OGC<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>CRS84)</span>
<span id="cb25-7">sources     <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> sst_virtual.zarr</span>
<span id="cb25-8">varnames    <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">anom</span> (Daily sea surface temperature anomalies)</span>
<span id="cb25-9">              <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">err</span> (Estimated error standard deviation of analysed_sst)</span>
<span id="cb25-10">              <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ice</span> (Sea ice concentration)</span>
<span id="cb25-11">              <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sst</span> (Daily sea surface temperature)</span>
<span id="cb25-12">names       <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> anom_<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>v<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>_1, anom_<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>v<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>_2, anom_<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>v<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>_3, anom_<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>v<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>_4, anom_<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>v<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>_5, anom_<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span>v<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>_6, ...</span>
<span id="cb25-13">unit        <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>     Celsius,     Celsius,     Celsius,     Celsius,     Celsius,     Celsius, ...</span>
<span id="cb25-14">depth       <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb25-15"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">time</span> (days) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2025-01-01</span> to <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2025-12-19</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">23</span> steps)</span></code></pre></div></div>
<p>There’s a lot here.</p>
<hr>
<p><em>Michael Sumner is a research software engineer at the Australian Antarctic Division. Packages mentioned — <code>tidync</code> (rOpenSci reviewed), <code>vapour</code>, <code>vrtstack</code>, <code>zaro</code> — are part of the <a href="https://github.com/hypertidy">hypertidy</a> ecosystem.</em></p>


</section>
</section>

 ]]></description>
  <category>code</category>
  <category>news</category>
  <category>r-packages</category>
  <category>python</category>
  <category>zarr</category>
  <category>gdal</category>
  <category>netcdf</category>
  <guid>https://hypertidy.org/posts/2026-05-27_raster-stack-zarr-virtualization/</guid>
  <pubDate>Wed, 27 May 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Check it out: geos</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2026-03-24_check-out-geos/</link>
  <description><![CDATA[ 






<p>The <a href="https://paleolimbot.github.io/geos/">geos</a> package provides a direct R interface to the GEOS library. It operates on a <code>geos_geometry</code> vector type and speaks wk natively — any wk-handleable geometry can be passed in, and the results can flow back out to wk, sf, or anything else.</p>
<p>This is the geometry engine for the wk ecosystem. Where wk handles representation and PROJ handles transformation, geos handles <em>computation</em>: buffers, intersections, unions, predicates, distances, triangulations.</p>
<section id="geometry-vectors" class="level2">
<h2 class="anchored" data-anchor-id="geometry-vectors">Geometry vectors</h2>
<p>geos stores geometries in an external pointer vector class:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(geos)</span>
<span id="cb1-2"></span>
<span id="cb1-3">g <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_geos_geometry</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb1-4">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"</span>,</span>
<span id="cb1-5">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POINT (5 5)"</span>,</span>
<span id="cb1-6">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"LINESTRING (0 0, 10 10)"</span></span>
<span id="cb1-7">))</span>
<span id="cb1-8">g</span>
<span id="cb1-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; &lt;geos_geometry[3]&gt;</span></span>
<span id="cb1-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] &lt;POLYGON [0 0...10 10]&gt;</span></span>
<span id="cb1-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [2] &lt;POINT [5 5]&gt;</span></span>
<span id="cb1-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [3] &lt;LINESTRING [0 0...10 10]&gt;</span></span></code></pre></div></div>
<p>The input can be WKT strings, WKB, wk vectors, or sf objects — anything with a <code>wk_handle()</code> method gets converted automatically:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## from wk::xy()</span></span>
<span id="cb2-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_geos_geometry</span>(wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xy</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb2-3"></span>
<span id="cb2-4"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## from sf</span></span>
<span id="cb2-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(sf)</span>
<span id="cb2-6">nc <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_read</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.file</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"shape/nc.shp"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">package =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sf"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">quiet =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb2-7">nc_geos <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_geos_geometry</span>(nc)</span></code></pre></div></div>
</section>
<section id="operations" class="level2">
<h2 class="anchored" data-anchor-id="operations">Operations</h2>
<p>geos provides vectorized access to the GEOS C API. Operations are functions, not methods — they take geometry vectors and return geometry vectors or values:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## buffer</span></span>
<span id="cb3-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_buffer</span>(g[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">distance =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb3-3"></span>
<span id="cb3-4"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## intersection</span></span>
<span id="cb3-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_intersection</span>(g[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_buffer</span>(g[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb3-6"></span>
<span id="cb3-7"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## union</span></span>
<span id="cb3-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_unary_union</span>(g)</span>
<span id="cb3-9"></span>
<span id="cb3-10"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## simplify</span></span>
<span id="cb3-11"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_simplify</span>(g[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tolerance =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb3-12"></span>
<span id="cb3-13"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## centroid</span></span>
<span id="cb3-14"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_centroid</span>(g[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span></code></pre></div></div>
<p>Binary predicates are also vectorized:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_intersects</span>(g[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], g[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])</span>
<span id="cb4-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] TRUE</span></span>
<span id="cb4-3"></span>
<span id="cb4-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_contains</span>(g[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], g[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])</span>
<span id="cb4-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] TRUE</span></span>
<span id="cb4-6"></span>
<span id="cb4-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_disjoint</span>(g[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], g[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>])</span>
<span id="cb4-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] FALSE</span></span></code></pre></div></div>
</section>
<section id="spatial-indexing" class="level2">
<h2 class="anchored" data-anchor-id="spatial-indexing">Spatial indexing</h2>
<p>geos includes an STRtree implementation for fast spatial queries:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## build a spatial index</span></span>
<span id="cb5-2">pts <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_geos_geometry</span>(wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xy</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span>)))</span>
<span id="cb5-3">tree <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_strtree</span>(pts)</span>
<span id="cb5-4"></span>
<span id="cb5-5"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## query the index</span></span>
<span id="cb5-6">query_geom <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_geos_geometry</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POLYGON ((0.4 0.4, 0.6 0.4, 0.6 0.6, 0.4 0.6, 0.4 0.4))"</span>)</span>
<span id="cb5-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_strtree_query</span>(tree, query_geom)</span></code></pre></div></div>
<p>The newer <code>geos_basic_strtree()</code> uses <code>wk::wk_envelope()</code> for index construction, which is extremely efficient for <code>wk::xy()</code> input — the envelope is just the point itself, computed without any geometry parsing overhead.</p>
</section>
<section id="construction-from-coordinates" class="level2">
<h2 class="anchored" data-anchor-id="construction-from-coordinates">Construction from coordinates</h2>
<p>You don’t need to go through WKT to build geometries. geos provides direct constructors:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## points from x, y</span></span>
<span id="cb6-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_make_point</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb6-3"></span>
<span id="cb6-4"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## linestring from coordinates</span></span>
<span id="cb6-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_make_linestring</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb6-6"></span>
<span id="cb6-7"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## polygon from coordinates (ring is closed automatically)</span></span>
<span id="cb6-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_make_polygon</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>))</span>
<span id="cb6-9"></span>
<span id="cb6-10"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## collections</span></span>
<span id="cb6-11"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_make_collection</span>(</span>
<span id="cb6-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POINT (0 0)"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POINT (1 1)"</span>),</span>
<span id="cb6-13">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type_id =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"multipoint"</span></span>
<span id="cb6-14">)</span></code></pre></div></div>
<p>These constructors use <code>feature_id</code> and <code>ring_id</code> arguments for building multi-part and multi-ring geometries from flat coordinate vectors, similar to how data often arrives from databases or CSV files.</p>
</section>
<section id="wk-compatibility" class="level2">
<h2 class="anchored" data-anchor-id="wk-compatibility">wk compatibility</h2>
<p>geos implements <code>wk_handle()</code> for its geometry type, so all wk operations work:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## extract coordinates</span></span>
<span id="cb7-2">wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_coords</span>(nc_geos)</span>
<span id="cb7-3"></span>
<span id="cb7-4"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## compute bounding boxes</span></span>
<span id="cb7-5">wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_envelope</span>(nc_geos)</span>
<span id="cb7-6"></span>
<span id="cb7-7"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## convert to wk types</span></span>
<span id="cb7-8">wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_wkt</span>(nc_geos)</span>
<span id="cb7-9">wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_wkb</span>(nc_geos)</span>
<span id="cb7-10"></span>
<span id="cb7-11"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## convert to sf</span></span>
<span id="cb7-12">sf<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_as_sfc</span>(nc_geos)</span></code></pre></div></div>
<p>This means geos integrates into any workflow that uses wk as the interchange format. Read vector data with gdalraster (WKB output), convert to geos for geometric operations, transform with PROJ, write back with gdalraster — all through wk.</p>
</section>
<section id="geos-vs-sf-for-geometric-operations" class="level2">
<h2 class="anchored" data-anchor-id="geos-vs-sf-for-geometric-operations">geos vs sf for geometric operations</h2>
<p>sf uses GEOS internally for its geometry operations (<code>st_buffer()</code>, <code>st_intersection()</code>, etc.). The difference is:</p>
<ul>
<li><strong>sf</strong> wraps GEOS through its own C++ layer, with results returned as sfc geometry columns inside sf data frames. The operations are tightly integrated with the sf data model.</li>
<li><strong>geos</strong> wraps GEOS directly, with results as standalone geometry vectors. No data frame, no attributes — just geometry in, geometry out.</li>
</ul>
<p>If you’re working within sf, use sf’s functions. If you’re working outside sf — with wk vectors, plain data frames, or formats that don’t map to sf’s model — geos gives you the same geometric operations without the sf world view.</p>
<p>Workflows can deliberately separate I/O (gdalraster/vapour), geometry (wk/geos), transformation (PROJ/reproj), and even grid logic (vaster), geos is the geometric computation layer.</p>
</section>
<section id="measurement-and-properties" class="level2">
<h2 class="anchored" data-anchor-id="measurement-and-properties">Measurement and properties</h2>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_area</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"</span>)</span>
<span id="cb8-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] 100</span></span>
<span id="cb8-3"></span>
<span id="cb8-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_length</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"LINESTRING (0 0, 10 0, 10 10)"</span>)</span>
<span id="cb8-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] 20</span></span>
<span id="cb8-6"></span>
<span id="cb8-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_is_valid</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"</span>)</span>
<span id="cb8-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] TRUE</span></span>
<span id="cb8-9"></span>
<span id="cb8-10"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_is_empty</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POINT EMPTY"</span>)</span>
<span id="cb8-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] TRUE</span></span>
<span id="cb8-12"></span>
<span id="cb8-13"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geos_num_coordinates</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"</span>)</span>
<span id="cb8-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] 5</span></span></code></pre></div></div>
<p>Install from CRAN:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">install.packages</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geos"</span>)</span></code></pre></div></div>
<p>Links:</p>
<ul>
<li><a href="https://CRAN.R-project.org/package=geos">geos on CRAN</a></li>
<li><a href="https://paleolimbot.github.io/geos/">geos documentation</a></li>
<li><a href="https://github.com/paleolimbot/geos">GitHub</a></li>
</ul>
</section>
<section id="check-it-out-series" class="level2">
<h2 class="anchored" data-anchor-id="check-it-out-series">Check it out series</h2>
<p>This is part of a series of posts for foundational spatial support in R. These posts include:</p>
<ul>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-wk/">wk</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-reproj/">reproj</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-proj-wk-transform/">PROJ/wk transform</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-gdalraster/">gdalraster</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-geos/">geos</a> (this one!)</li>
</ul>


</section>

 ]]></description>
  <category>r-packages</category>
  <category>vector</category>
  <guid>https://hypertidy.org/posts/2026-03-24_check-out-geos/</guid>
  <pubDate>Tue, 24 Mar 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Check it out: reproj</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2026-03-24_check-out-reproj/</link>
  <description><![CDATA[ 






<p>The <a href="https://hypertidy.github.io/reproj/">reproj</a> package provides a single generic function, <code>reproj()</code>, for transforming coordinates between map projections. It works with matrices, data frames, and anything else that a package author cares to add a method for.</p>
<p>Coordinate transformation is a basic operation on numbers, it shouldn’t require a specific spatial data format.</p>
<section id="the-generic" class="level2">
<h2 class="anchored" data-anchor-id="the-generic">The generic</h2>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(reproj)</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## matrix in, matrix out</span></span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reproj</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">147</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea +datum=WGS84"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OGC:CRS84"</span>)</span>
<span id="cb1-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt;          [,1]     [,2] [,3]</span></span>
<span id="cb1-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1,] 5969744 -9803200    0</span></span></code></pre></div></div>
<p>The <code>source</code> and <code>target</code> arguments accept anything that the PROJ library understands: EPSG codes, proj-strings, WKT2, authority:code strings. The output is always a matrix — 2, 3, or 4 columns depending on input and the <code>four</code> argument.</p>
<p>Convenience helpers <code>reproj_xy()</code> and <code>reproj_xyz()</code> force 2- or 3-column output:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reproj_xy</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">147</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea +datum=WGS84"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OGC:CRS84"</span>)</span>
<span id="cb2-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt;          [,1]     [,2]</span></span>
<span id="cb2-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1,] 5969744 -9803200</span></span></code></pre></div></div>
</section>
<section id="the-generic-method-model" class="level2">
<h2 class="anchored" data-anchor-id="the-generic-method-model">The generic method model</h2>
<p><code>reproj()</code> is an S3 generic. This means any package can import it and add a method for its own spatial type. The method extracts the source CRS from the object and the user only needs to supply the target:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## hypothetical method for a spatial type that carries its own CRS</span></span>
<span id="cb3-2">reproj.my_spatial_thing <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x, target, ...) {</span>
<span id="cb3-3">  coords <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">extract_coords</span>(x)</span>
<span id="cb3-4">  source <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_crs</span>(x)</span>
<span id="cb3-5">  result <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reproj</span>(coords, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target =</span> target, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source =</span> source, ...)</span>
<span id="cb3-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rebuild_my_thing</span>(x, result, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> target)</span>
<span id="cb3-7">}</span></code></pre></div></div>
<p>This pattern is already used by the silicate and quadmesh packages — their <code>reproj()</code> methods know where the coordinates live and what the source CRS is, so the user just says <code>reproj(my_mesh, target_crs)</code>.</p>
<p>The value of this design is that the generic lives in a small, dependency-light package. A downstream package can <code>@importFrom reproj reproj</code> without pulling in GDAL or any heavy spatial stack. The transformation itself is done by the PROJ library via the <code>PROJ</code> R package (preferred) or the <code>proj4</code> package as fallback.</p>
<p>For example we could write a <code>reproj.sf</code> and a <code>.sfc</code>:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">reproj.sfc <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x, target, ..., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>) {</span>
<span id="cb4-2">  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## handle this format with wk</span></span>
<span id="cb4-3">  handled <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_wkb</span>(x)</span>
<span id="cb4-4">  crs <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_crs</span>(handled)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>wkt</span>
<span id="cb4-5">  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## stop if not a valid crs, we need source specified</span></span>
<span id="cb4-6">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.null</span>(source)) {</span>
<span id="cb4-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">stopifnot</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.na</span>(crs))</span>
<span id="cb4-8">  } <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> {</span>
<span id="cb4-9">    crs <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> source</span>
<span id="cb4-10"> }</span>
<span id="cb4-11"> trans <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> PROJ<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_trans_create</span>(crs, target)</span>
<span id="cb4-12"> sf<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_as_sfc</span>(wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_transform</span>(handled, trans))</span>
<span id="cb4-13">}</span>
<span id="cb4-14"></span>
<span id="cb4-15">reproj.sf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x, target, ..., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span>) {</span>
<span id="cb4-16"> sf<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_set_geometry</span>(x, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reproj.sfc</span>(sf<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_geometry</span>(x), target, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source =</span> source))</span>
<span id="cb4-17">}</span></code></pre></div></div>
<p>That’s not very useful since <code>sf::st_transform</code> already exists but demonstrates the utility for any other object, and you can force input of a source if your object does not support that already. We could decompose our object to coordinates and transform those more directly, but anything handled by wk is already supported by this simpler mechanism.</p>
</section>
<section id="crs-preservation" class="level2">
<h2 class="anchored" data-anchor-id="crs-preservation">CRS preservation</h2>
<p>A key principle: when reproj transforms an object that has a method, the <em>output carries the new CRS</em>. The silicate method rebuilds the mesh with the target CRS attached. The quadmesh method does the same. The idea is that format-specific methods preserve the full object structure while updating both coordinates and CRS metadata.</p>
<p>For plain matrices and data frames, there’s no CRS to carry, and the target and source must be specified.</p>
</section>
<section id="under-the-hood-proj-package" class="level2">
<h2 class="anchored" data-anchor-id="under-the-hood-proj-package">Under the hood: PROJ package</h2>
<p>reproj delegates the actual math to the <a href="https://hypertidy.github.io/PROJ/">PROJ</a> R package, which wraps the PROJ C library. The PROJ package provides:</p>
<ul>
<li><code>PROJ::proj_trans()</code> — transform coordinates, accepting wk types</li>
<li><code>PROJ::proj_trans_create()</code> — create a reusable transformation object (a <code>wk_trans</code>)</li>
<li><code>PROJ::proj_crs_text()</code> — convert between CRS representations (WKT2, proj-string, PROJJSON)</li>
</ul>
</section>
<section id="reproj-vs-sfst_transform-vs-terraproject" class="level2">
<h2 class="anchored" data-anchor-id="reproj-vs-sfst_transform-vs-terraproject">reproj vs sf::st_transform vs terra::project</h2>
<p>sf and terra both have projection functions, but they’re tied to their respective data models. <code>sf::st_transform()</code> works on sf objects. <code>terra::project()</code> works on SpatVector and SpatRaster.</p>
<p>reproj works on <em>anything</em>. It’s deliberately format-agnostic: give it a matrix of coordinates, a source CRS, and a target CRS. This makes it useful for packages that don’t depend on sf or terra, and for workflows where spatial data isn’t in a standard spatial format — track data as data frames, coordinates pulled from a netCDF, vertices from an rgl mesh, cell centres computed from a grid specification.</p>
</section>
<section id="example-transforming-track-data" class="level2">
<h2 class="anchored" data-anchor-id="example-transforming-track-data">Example: transforming track data</h2>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(reproj)</span>
<span id="cb5-2"></span>
<span id="cb5-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## some GPS fixes as a plain data frame</span></span>
<span id="cb5-4">tracks <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(</span>
<span id="cb5-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lon =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">147.3</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">147.4</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">147.5</span>),</span>
<span id="cb5-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lat =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">42.9</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">42.8</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">42.7</span>),</span>
<span id="cb5-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">time =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.POSIXct</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2024-01-01 08:00"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2024-01-01 09:00"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2024-01-01 10:00"</span>))</span>
<span id="cb5-8">)</span>
<span id="cb5-9"></span>
<span id="cb5-10"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## transform to a local projection</span></span>
<span id="cb5-11">xy <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reproj_xy</span>(</span>
<span id="cb5-12">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(tracks<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>lon, tracks<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>lat),</span>
<span id="cb5-13">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=utm +zone=55 +south +datum=WGS84"</span>,</span>
<span id="cb5-14">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span></span>
<span id="cb5-15">)</span>
<span id="cb5-16"></span>
<span id="cb5-17">tracks<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> xy[, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb5-18">tracks<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>y <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> xy[, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]</span></code></pre></div></div>
<p>Install from CRAN:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">install.packages</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"reproj"</span>)</span></code></pre></div></div>
<p>Links:</p>
<ul>
<li><a href="https://CRAN.R-project.org/package=reproj">reproj on CRAN</a></li>
<li><a href="https://hypertidy.github.io/reproj/">reproj documentation</a></li>
<li><a href="https://CRAN.R-project.org/package=PROJ">PROJ on CRAN</a></li>
<li><a href="https://github.com/hypertidy/reproj">GitHub (reproj)</a></li>
<li><a href="https://github.com/hypertidy/PROJ">GitHub (PROJ)</a></li>
</ul>
</section>
<section id="check-it-out-series" class="level2">
<h2 class="anchored" data-anchor-id="check-it-out-series">Check it out series</h2>
<p>This is part of a series of posts for foundational spatial support in R. These posts include:</p>
<ul>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-wk/">wk</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-reproj/">reproj</a> (this one!)</li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-proj-wk-transform/">PROJ/wk transform</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-gdalraster/">gdalraster</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-geos/">geos</a></li>
</ul>


</section>

 ]]></description>
  <category>r-packages</category>
  <category>projections</category>
  <guid>https://hypertidy.org/posts/2026-03-24_check-out-reproj/</guid>
  <pubDate>Tue, 24 Mar 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Check it out: wk</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2026-03-24_check-out-wk/</link>
  <description><![CDATA[ 






<p>The <a href="https://paleolimbot.github.io/wk/">wk</a> package is a foundation for geometry handling in R. It’s a lightweight, dependency-free geometry column with CRS support, vctrs integration, and a handler-based streaming API. Any data frame with a wk column works as well as the column itself with supported functions.</p>
<section id="what-wk-provides" class="level2">
<h2 class="anchored" data-anchor-id="what-wk-provides">What wk provides</h2>
<p>wk defines several vector types that carry geometry and coordinate reference system information as first-class attributes:</p>
<ul>
<li><code>wk::wkt()</code> — well-known text, human-readable</li>
<li><code>wk::wkb()</code> — well-known binary, compact and fast</li>
<li><code>wk::xy()</code>, <code>wk::xyz()</code>, <code>wk::xym()</code>, <code>wk::xyzm()</code> — coordinate vectors (points)</li>
<li><code>wk::rct()</code> — rectangles (bounding boxes)</li>
<li><code>wk::crc()</code> — circles</li>
</ul>
<p>All of these carry a <code>crs</code> attribute and behave properly as vctrs types. They can live in data frame columns, get subset, combined, and compared — with CRS compatibility checked automatically.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(wk)</span>
<span id="cb1-2">pts <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xy</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">147</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">148</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">149</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">43</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">44</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>)</span>
<span id="cb1-3">pts</span>
<span id="cb1-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; &lt;wk_xy[3] with CRS=EPSG:4326&gt;</span></span>
<span id="cb1-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] (147 -42) (148 -43) (149 -44)</span></span></code></pre></div></div>
<p>You can put these directly in a data frame:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">d <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data.frame</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Hobart"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"South"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Further"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">geometry =</span> pts)</span>
<span id="cb2-2">d</span>
<span id="cb2-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt;     name     geometry</span></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; 1 Hobart  (147 -42)</span></span>
<span id="cb2-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; 2  South  (148 -43)</span></span>
<span id="cb2-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; 3 Further (149 -44)</span></span></code></pre></div></div>
<p>Subset, combine, and merge all work correctly. The CRS propagates through operations and mismatches are caught:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## combining vectors with different CRS will error</span></span>
<span id="cb3-2">pts_other <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xy</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3857"</span>)</span>
<span id="cb3-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">try</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(pts, pts_other))</span>
<span id="cb3-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; Error: CRS objects are not equal</span></span></code></pre></div></div>
</section>
<section id="crs-handling" class="level2">
<h2 class="anchored" data-anchor-id="crs-handling">CRS handling</h2>
<p>The CRS system in wk is deliberately general. At the C level, the PROJ library <code>proj_create()</code> function accepts a remarkably wide range of CRS definition strings. The <a href="https://proj.org/en/stable/development/reference/functions.html#transformation-setup">PROJ C API documentation</a> lists many valid types of inputs from ‘auth:code’, PROJJSON, WKT variants and PROJ4 strings. The CRS support in wk is similarly open to inputs, the key functions in wk are:</p>
<ul>
<li><code>wk_crs()</code> — get the CRS from any wk-compatible object</li>
<li><code>wk_set_crs()</code> — set or replace the CRS</li>
<li><code>wk_crs_equal()</code> — compare CRS values</li>
<li><code>wk_crs_proj_definition()</code> — extract a PROJ-compatible string (used by PROJ and other packages)</li>
</ul>
<p>The sentinel value <code>wk_crs_inherit()</code> signals “inherit from context” and is used for empty or zero-length geometry vectors. This means you can safely combine an empty geometry with a CRS-bearing one without triggering a mismatch.</p>
</section>
<section id="interchange" class="level2">
<h2 class="anchored" data-anchor-id="interchange">Interchange</h2>
<p>wk acts as a common interchange format. Other formats that are supported are ‘raw binary’, ‘raw text’, geos package vectors, sf data frames and geometry vectors. The gdalraster package can emit vector geometry in wk format. Conversions to and from other formats are built in:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## sf -&gt; wk</span></span>
<span id="cb4-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(sf)</span>
<span id="cb4-3">nc <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_read</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.file</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"shape/nc.shp"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">package =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sf"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">quiet =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb4-4">wkb <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_wkb</span>(nc)</span>
<span id="cb4-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_crs</span>(wkb)</span>
<span id="cb4-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] "NAD27"</span></span>
<span id="cb4-7"></span>
<span id="cb4-8"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## wk -&gt; sf</span></span>
<span id="cb4-9">sf<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_as_sfc</span>(wkb)</span>
<span id="cb4-10"></span>
<span id="cb4-11"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## terra -&gt; wk</span></span>
<span id="cb4-12">geos<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_geos_geometry</span>(terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vect</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>src<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span>))</span></code></pre></div></div>
<p>The geos package accepts wk types directly. The PROJ package transforms them. The gdalraster package (via <code>ogr_layer_create()</code> and friends) can write them. This is an interchange layer that allows packages to stay independent of formats, just as the underlying libraries GDAL, PROJ, GEOS already allow.</p>
</section>
<section id="the-handler-api" class="level2">
<h2 class="anchored" data-anchor-id="the-handler-api">The handler API</h2>
<p>The real power of wk is its streaming handler API. Rather than materializing geometry in memory, wk can stream coordinates through a chain of handlers — read, transform, and write without ever building an intermediate object.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## count coordinates without materializing geometry</span></span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_count</span>(wkb)</span>
<span id="cb5-3"></span>
<span id="cb5-4"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## extract coordinates as a data frame</span></span>
<span id="cb5-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_coords</span>(wkb)</span>
<span id="cb5-6"></span>
<span id="cb5-7"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## compute bounding boxes per feature</span></span>
<span id="cb5-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_envelope</span>(wkb)</span>
<span id="cb5-9"></span>
<span id="cb5-10"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## transform coordinates (see the PROJ post) https://www.hypertidy.org/posts/2026-03-24_check-out-proj-wk-transform/</span></span>
<span id="cb5-11"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_transform</span>(pts, PROJ<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_trans_create</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3857"</span>))</span></code></pre></div></div>
<p>The <code>wk_handle()</code> generic is what makes this extensible. Any package can implement a <code>wk_handle()</code> method for its geometry type and immediately plug into the wk ecosystem — filters, transforms, writers all just work.</p>
</section>
<section id="geometric-operations-via-wk" class="level2">
<h2 class="anchored" data-anchor-id="geometric-operations-via-wk">Geometric operations via wk</h2>
<p>wk itself includes several useful operations that don’t require GEOS:</p>
<ul>
<li><code>wk_vertices()</code> — extract all vertices from a geometry</li>
<li><code>wk_coords()</code> / <code>wk_coords&lt;-()</code> — get/set coordinates</li>
<li><code>wk_flatten()</code> — flatten collections to simple geometries</li>
<li><code>wk_collection()</code> — collect simple geometries into multi/collection types</li>
<li><code>wk_linestring()</code> / <code>wk_polygon()</code> — construct from coordinates</li>
<li><code>wk_set_z()</code> / <code>wk_drop_z()</code> — add or remove Z dimension</li>
<li><code>wk_orient()</code> / <code>wk_clockwise()</code> / <code>wk_counterclockwise()</code> — rewind polygon rings</li>
</ul>
<p>For geometric predicates, buffering, intersection and the like try <a href="https://paleolimbot.github.io/geos/">geos</a> (see the <a href="https://www.hypertidy.org/posts/2026-03-24_check-out-geos/">geos</a> post in this series).</p>
<p>Install from CRAN:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">install.packages</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wk"</span>)</span></code></pre></div></div>
<p>Links:</p>
<ul>
<li><a href="https://CRAN.R-project.org/package=wk">wk on CRAN</a></li>
<li><a href="https://paleolimbot.github.io/wk/">wk documentation</a></li>
<li><a href="https://github.com/paleolimbot/wk">GitHub</a></li>
</ul>
</section>
<section id="check-it-out-series" class="level2">
<h2 class="anchored" data-anchor-id="check-it-out-series">Check it out series</h2>
<p>This is part of a series of posts for foundational spatial support in R. These posts include:</p>
<ul>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-wk/">wk</a> (this one!)</li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-reproj/">reproj</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-proj-wk-transform/">PROJ/wk transform</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-gdalraster/">gdalraster</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-geos/">geos</a></li>
</ul>


</section>

 ]]></description>
  <category>r-packages</category>
  <category>vector</category>
  <guid>https://hypertidy.org/posts/2026-03-24_check-out-wk/</guid>
  <pubDate>Tue, 24 Mar 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Check it out: proj_trans_create and wk_transform</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2026-03-24_check-out-proj-wk-transform/</link>
  <description><![CDATA[ 






<p>The <a href="https://hypertidy.github.io/PROJ/">PROJ</a> R package provides <code>proj_trans_create()</code>, which creates a reusable coordinate transformation object that plugs directly into wk’s <code>wk_transform()</code>. This is the mechanism that connects the PROJ C library to any geometry type that speaks wk.</p>
<p>This post goes into some detail on what CRS representations are accepted, how R’s CRS objects get resolved to strings that PROJ understands, and how wk’s <code>wk_crs_proj_definition()</code> generic bridges the gap.</p>
<section id="what-proj-accepts-as-a-crs-definition" class="level2">
<h2 class="anchored" data-anchor-id="what-proj-accepts-as-a-crs-definition">What PROJ accepts as a CRS definition</h2>
<p>At the C level, PROJ’s <code>proj_create()</code> function accepts a remarkably wide range of CRS definition strings. The <a href="https://proj.org/en/stable/development/reference/functions.html#transformation-setup">PROJ C API documentation</a> lists the following as valid inputs:</p>
<ul>
<li>A <strong>proj-string</strong>, e.g.&nbsp;<code>"+proj=utm +zone=55 +south +datum=WGS84 +type=crs"</code></li>
<li>A <strong>WKT string</strong> (WKT2:2019 preferred, WKT1 accepted), e.g.&nbsp;<code>GEOGCRS["WGS 84", ...]</code></li>
<li>An <strong>object code</strong>, e.g.&nbsp;<code>"EPSG:4326"</code>, <code>"urn:ogc:def:crs:EPSG::4326"</code>, or <code>"urn:ogc:def:coordinateOperation:EPSG::1671"</code></li>
<li>An <strong>object name</strong>, e.g.&nbsp;<code>"WGS 84"</code> or <code>"WGS 84 / UTM zone 31N"</code> — matched by heuristics when the name is not unique</li>
<li>An <strong>OGC URN</strong> for compound CRS, e.g.&nbsp;<code>"urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717"</code> or the abbreviated <code>"EPSG:2393+5717"</code></li>
<li>An <strong>OGC URN</strong> for concatenated operations, e.g.&nbsp;<code>"urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895,coordinateOperation:EPSG::1618"</code></li>
<li>A <strong>PROJJSON string</strong> (added in PROJ 6.2) — the JSON representation of a CRS or coordinate operation, schema at <a href="https://proj.org/schemas/v0.4/projjson.schema.json" class="uri">https://proj.org/schemas/v0.4/projjson.schema.json</a></li>
<li>A <strong>compound CRS</strong> from two names joined with <code>" + "</code>, e.g.&nbsp;<code>"WGS 84 + EGM96 height"</code> (added in PROJ 7.1)</li>
</ul>
<p>That’s a lot of ways to say the same thing. In R, the PROJ package wraps this directly — <code>proj_trans_create()</code> and <code>proj_crs_text()</code> accept all of these forms as character strings.</p>
<p>There is a critical distinction for proj-strings: if the string contains <code>+type=crs</code>, it’s interpreted as a CRS definition. Geographic CRS with <code>+type=crs</code> are assumed to have longitude-latitude axis order with degree units. Without <code>+type=crs</code>, the proj-string is interpreted as a <em>coordinate operation</em> (a transformation step, not a CRS). This matters in some contexts but many packages (PROJ, sf, terra) will detect this case and add the ‘+type=crs’ because it’s common and convenient.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(PROJ)</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## this is a CRS ("+type=crs" present):</span></span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_crs_text</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea +type=crs"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">format =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>L)</span>
<span id="cb1-5"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## returns a proper WKT2 CRS</span></span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## this is technically a transformation step, NOT a CRS (no "+type=crs") but workarounds are often used (as here)</span></span>
<span id="cb1-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_crs_text</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">format =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>L)</span></code></pre></div></div>
<p>The PROJ library documentation explicitly says: “The use of proj-string to describe a CRS is discouraged. It is a legacy means of conveying CRS descriptions: use of object codes (EPSG:XXXX typically) or WKT description is recommended for better expressivity.” This is absolutely true but if you want to define your own CRS, just a simple equal area project such as “+proj=laea +lon_0=-147 +lat_0=-42 +datum=WGS4” then you can easily convert from a proj string to WKT, but write the WKT from scratch?? That’s hard but don’t let it put you off, use map projections, specified in a few characters as PROJ strings - if you need a specific datum you’ll need to get a full-blown WKT string by some means.</p>
</section>
<section id="crs-representations-you-can-work-with-in-r" class="level2">
<h2 class="anchored" data-anchor-id="crs-representations-you-can-work-with-in-r">CRS representations you can work with in R</h2>
<p><code>proj_crs_text()</code> converts between CRS representations. The <code>format</code> argument selects the output:</p>
<ul>
<li><code>format = 0L</code> → WKT2 (the default, most expressive)</li>
<li><code>format = 1L</code> → proj-string</li>
<li><code>format = 2L</code> → PROJJSON</li>
</ul>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(PROJ)</span>
<span id="cb2-2"></span>
<span id="cb2-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## WKT2</span></span>
<span id="cb2-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_crs_text</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">format =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>L))</span></code></pre></div></div>
<pre><code>GEOGCRS["WGS 84",
    ENSEMBLE["World Geodetic System 1984 ensemble",
        MEMBER["World Geodetic System 1984 (Transit)"],
        MEMBER["World Geodetic System 1984 (G730)"],
        MEMBER["World Geodetic System 1984 (G873)"],
        MEMBER["World Geodetic System 1984 (G1150)"],
        MEMBER["World Geodetic System 1984 (G1674)"],
        MEMBER["World Geodetic System 1984 (G1762)"],
        MEMBER["World Geodetic System 1984 (G2139)"],
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]],
        ENSEMBLEACCURACY[2.0]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["geodetic latitude (Lat)",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["geodetic longitude (Lon)",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    USAGE[
        SCOPE["Horizontal component of 3D system."],
        AREA["World."],
        BBOX[-90,-180,90,180]],
    ID["EPSG",4326]]</code></pre>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## proj-string</span></span>
<span id="cb4-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_crs_text</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">format =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>L)</span>
<span id="cb4-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; "+proj=longlat +datum=WGS84 +no_defs +type=crs"</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## PROJJSON</span></span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_crs_text</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">format =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>L))</span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode json code-with-copy"><code class="sourceCode json"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-2">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"$schema"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://proj.org/schemas/v0.7/projjson.schema.json"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-3">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"type"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GeographicCRS"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-4">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"WGS 84"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-5">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"datum_ensemble"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-6">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"World Geodetic System 1984 ensemble"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-7">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"members"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">[</span></span>
<span id="cb6-8">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-9">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"World Geodetic System 1984 (Transit)"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-10">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-11">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"authority"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-12">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"code"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1166</span></span>
<span id="cb6-13">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-14">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-15">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-16">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"World Geodetic System 1984 (G730)"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-17">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-18">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"authority"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-19">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"code"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1152</span></span>
<span id="cb6-20">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-21">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-22">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-23">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"World Geodetic System 1984 (G873)"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-24">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-25">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"authority"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-26">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"code"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1153</span></span>
<span id="cb6-27">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-28">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-29">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-30">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"World Geodetic System 1984 (G1150)"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-31">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-32">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"authority"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-33">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"code"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1154</span></span>
<span id="cb6-34">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-35">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-36">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-37">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"World Geodetic System 1984 (G1674)"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-38">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-39">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"authority"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-40">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"code"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1155</span></span>
<span id="cb6-41">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-42">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-43">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-44">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"World Geodetic System 1984 (G1762)"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-45">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-46">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"authority"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-47">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"code"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1156</span></span>
<span id="cb6-48">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-49">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-50">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-51">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"World Geodetic System 1984 (G2139)"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-52">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-53">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"authority"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-54">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"code"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1309</span></span>
<span id="cb6-55">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-56">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-57">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-58">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"World Geodetic System 1984 (G2296)"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-59">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-60">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"authority"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-61">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"code"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1383</span></span>
<span id="cb6-62">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-63">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-64">    <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">]</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-65">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"ellipsoid"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-66">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"WGS 84"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-67">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"semi_major_axis"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6378137</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-68">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"inverse_flattening"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">298.257223563</span></span>
<span id="cb6-69">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb6-70">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"accuracy"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2.0"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-71">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-72">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"authority"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-73">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"code"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6326</span></span>
<span id="cb6-74">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-75">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb6-76">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"coordinate_system"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-77">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"subtype"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ellipsoidal"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-78">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"axis"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">[</span></span>
<span id="cb6-79">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-80">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Geodetic latitude"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-81">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"abbreviation"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lat"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-82">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"direction"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"north"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-83">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"unit"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"degree"</span></span>
<span id="cb6-84">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-85">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-86">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Geodetic longitude"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-87">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"abbreviation"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lon"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-88">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"direction"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"east"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-89">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"unit"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"degree"</span></span>
<span id="cb6-90">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-91">    <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb6-92">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb6-93">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"scope"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Horizontal component of 3D system."</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-94">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"area"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"World."</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-95">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"bbox"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-96">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"south_latitude"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">-90</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-97">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"west_longitude"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">-180</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-98">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"north_latitude"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-99">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"east_longitude"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span></span>
<span id="cb6-100">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb6-101">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-102">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"authority"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-103">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"code"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4326</span></span>
<span id="cb6-104">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-105"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>PROJJSON is the most machine-friendly format — it’s the full CRS definition in a structure you can parse, manipulate, and round-trip without information loss. WKT2 is the canonical text representation and equally complete. Proj-strings are the most compact, but lose information (datum ensemble members, axis order details, usage scope). Every conversion to proj-string is potentially lossy.</p>
</section>
<section id="how-wk-bridges-crs-objects-to-proj-strings" class="level2">
<h2 class="anchored" data-anchor-id="how-wk-bridges-crs-objects-to-proj-strings">How wk bridges CRS objects to PROJ strings</h2>
<p>In the wk package, a CRS can be <em>any R object</em>. The <code>crs</code> attribute on a <code>wk::wkt()</code>, <code>wk::wkb()</code>, or <code>wk::xy()</code> vector is deliberately untyped — it could be a string like <code>"EPSG:4326"</code>, an integer like <code>4326</code>, an sf <code>crs</code> object, or something else entirely. wk doesn’t interpret the CRS, it just propagates it.</p>
<p>The bridge to PROJ is <code>wk_crs_proj_definition()</code>. This is an S3 generic that takes a CRS object and returns a character string that the PROJ library can understand. This is the function that <code>PROJ::proj_trans()</code> and <code>PROJ::proj_trans_create()</code> call internally to resolve CRS arguments.</p>
<p>The built-in methods handle the common cases:</p>
<ul>
<li><strong>character</strong> → returned as-is (assumed to be an authority:code string, WKT, PROJJSON, or proj-string already)</li>
<li><strong>integer</strong> or <strong>double</strong> → formatted as <code>"EPSG:&lt;code&gt;"</code> (e.g.&nbsp;<code>4326</code> → <code>"EPSG:4326"</code>)</li>
<li><strong>NULL</strong> → <code>NA_character_</code> (no CRS)</li>
<li><strong><code>wk_crs_inherit()</code></strong> → <code>NA_character_</code> (inherit from context)</li>
</ul>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(wk)</span>
<span id="cb7-2"></span>
<span id="cb7-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_crs_proj_definition</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>)</span>
<span id="cb7-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] "EPSG:4326"</span></span>
<span id="cb7-5"></span>
<span id="cb7-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_crs_proj_definition</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4326</span>)</span>
<span id="cb7-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] "EPSG:4326"</span></span>
<span id="cb7-8"></span>
<span id="cb7-9"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_crs_proj_definition</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4326</span>L)</span>
<span id="cb7-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] "EPSG:4326"</span></span></code></pre></div></div>
<p>For sf’s <code>crs</code> class, sf registers its own method so that <code>wk_crs_proj_definition()</code> returns the correct string for the installed version of PROJ. Other packages can do the same — this is the extension point for custom CRS types.</p>
<p>The <code>verbose</code> argument controls how much detail is returned. With <code>verbose = FALSE</code> (the default), it returns the most compact form — typically the authority:code string. With <code>verbose = TRUE</code>, it returns PROJJSON or WKT2 for maximum expressivity.</p>
<section id="wk_crs_projjson" class="level3">
<h3 class="anchored" data-anchor-id="wk_crs_projjson">wk_crs_projjson()</h3>
<p>There’s also <code>wk_crs_projjson()</code>, which returns the PROJJSON representation of a CRS. For shortcut-style CRS values like <code>"EPSG:4326"</code> or <code>4326</code>, wk includes cached lookup tables — <code>wk_proj_crs_view</code> and <code>wk_proj_crs_json</code> — containing pre-rendered PROJJSON for all CRS definitions in the PROJ database (based on PROJ 9.3.0 as of wk 0.9.x). This means <code>wk_crs_projjson("EPSG:4326")</code> works without PROJ being installed — the lookup is pure R against shipped data.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## get PROJJSON for a known EPSG code, no PROJ library needed</span></span>
<span id="cb8-2">pj <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_crs_projjson</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>)</span>
<span id="cb8-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(pj)</span>
<span id="cb8-4"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## full PROJJSON output</span></span></code></pre></div></div>
<p>This is the mechanism that allows wk-based packages to inspect CRS properties without linking to the PROJ C library.</p>
</section>
</section>
<section id="the-transformation-pipeline" class="level2">
<h2 class="anchored" data-anchor-id="the-transformation-pipeline">The transformation pipeline</h2>
<p>With all that context, here’s how <code>proj_trans_create()</code> works:</p>
<ol type="1">
<li>It calls <code>wk_crs_proj_definition()</code> on the <code>source_crs</code> and <code>target_crs</code> arguments to get PROJ-compatible strings</li>
<li>It passes those strings to the PROJ C library’s <code>proj_create_crs_to_crs()</code> function, which finds the best available transformation pipeline between the two CRS</li>
<li>It wraps the result in a <code>wk_trans</code> object — an external pointer with an <code>wk_trans_inverse()</code> method</li>
</ol>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(PROJ)</span>
<span id="cb9-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(wk)</span>
<span id="cb9-3"></span>
<span id="cb9-4"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## create a transformation object</span></span>
<span id="cb9-5">trans <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_trans_create</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3857"</span>)</span>
<span id="cb9-6"><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>proj_trans at <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0x55800593fd60</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb9-7">type<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> Concatenated Operation</span>
<span id="cb9-8">id<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> pipeline</span>
<span id="cb9-9">description<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> axis order <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">change</span> (<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>D) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> Popular Visualisation Pseudo<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>Mercator</span>
<span id="cb9-10">definition<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> proj<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span>pipeline step proj<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span>unitconvert xy_in<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span>deg xy_out<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span>rad step proj<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span>webmerc lat_0<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> lon_0<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> x_0<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> y_0<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> ellps<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span>WGS84</span>
<span id="cb9-11">area_of_use<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb9-12">  name<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> World</span>
<span id="cb9-13">  bounds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>]</span>
<span id="cb9-14">source_crs<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb9-15">  type<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> Geographic <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>D CRS</span>
<span id="cb9-16">  id<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> EPSG<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4326</span></span>
<span id="cb9-17">  name<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> WGS <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">84</span></span>
<span id="cb9-18">  area_of_use<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb9-19">    name<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> World.</span>
<span id="cb9-20">    bounds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>]</span>
<span id="cb9-21">target_crs<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb9-22">  type<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> Projected CRS</span>
<span id="cb9-23">  id<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> EPSG<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3857</span></span>
<span id="cb9-24">  name<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> WGS <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">84</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> Pseudo<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>Mercator</span>
<span id="cb9-25">  area_of_use<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb9-26">    name<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> World between <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">85.06</span>°S and <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">85.06</span>°N.</span>
<span id="cb9-27">    bounds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">85.06</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">85.06</span>]</span></code></pre></div></div>
<p>The source and target can be any form PROJ accepts — EPSG codes, WKT2, PROJJSON, proj-strings with <code>+type=crs</code>, object names:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## all of these create equivalent transformations:</span></span>
<span id="cb10-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_trans_create</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3857"</span>)</span>
<span id="cb10-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_trans_create</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4326</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3857</span>)</span>
<span id="cb10-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_trans_create</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"WGS 84"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"WGS 84 / Pseudo-Mercator"</span>)</span>
<span id="cb10-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_trans_create</span>(</span>
<span id="cb10-6">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=longlat +datum=WGS84 +type=crs"</span>,</span>
<span id="cb10-7">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +type=crs"</span></span>
<span id="cb10-8">)</span></code></pre></div></div>
</section>
<section id="applying-the-transformation-with-wk_transform" class="level2">
<h2 class="anchored" data-anchor-id="applying-the-transformation-with-wk_transform">Applying the transformation with wk_transform</h2>
<p><code>wk::wk_transform()</code> takes any wk-handleable geometry and applies the transformation through wk’s streaming handler API. This means the transformation works on <em>any</em> geometry type — points, lines, polygons, collections — without materializing intermediate representations:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## transform point coordinates</span></span>
<span id="cb11-2">pts <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xy</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">147</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">148</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">149</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">43</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">44</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>)</span>
<span id="cb11-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_transform</span>(pts, trans)</span>
<span id="cb11-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; &lt;wk_xy[3] with CRS=EPSG:3857&gt;</span></span>
<span id="cb11-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] (16362893 -5160980) (16474013 -5311971) (16585132 -5465442)</span></span>
<span id="cb11-6"></span>
<span id="cb11-7"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## transform well-known text geometries</span></span>
<span id="cb11-8">poly <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wkt</span>(</span>
<span id="cb11-9">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POLYGON ((147 -42, 148 -42, 148 -43, 147 -43, 147 -42))"</span>,</span>
<span id="cb11-10">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span></span>
<span id="cb11-11">)</span>
<span id="cb11-12"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_transform</span>(poly, trans)</span>
<span id="cb11-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; &lt;wk_wkt[1] with CRS=EPSG:3857&gt;</span></span>
<span id="cb11-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] POLYGON ((16362893 -5160980, ...))</span></span>
<span id="cb11-15"></span>
<span id="cb11-16"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## transform well-known binary</span></span>
<span id="cb11-17">wkb_geom <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as_wkb</span>(poly)</span>
<span id="cb11-18"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_transform</span>(wkb_geom, trans)</span>
<span id="cb11-19"></span>
<span id="cb11-20"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## transform sf geometries (sf implements wk_handle)</span></span>
<span id="cb11-21"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## wk_transform(sf_sfc_object, trans) — just works</span></span></code></pre></div></div>
<p>The CRS of the output is updated automatically. The output carries the target CRS from the transformation.</p>
<p>The transformation object is reusable — create it once, apply it to many geometry vectors. This avoids paying the PROJ pipeline setup cost for each call.</p>
</section>
<section id="inverse-transformations" class="level2">
<h2 class="anchored" data-anchor-id="inverse-transformations">Inverse transformations</h2>
<p><code>wk_trans_inverse()</code> flips a transformation:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">inv <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_trans_inverse</span>(trans)</span>
<span id="cb12-2"></span>
<span id="cb12-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## round-trip</span></span>
<span id="cb12-4">pts_proj <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_transform</span>(pts, trans)</span>
<span id="cb12-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wk_transform</span>(pts_proj, inv)</span>
<span id="cb12-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; &lt;wk_xy[3] with CRS=EPSG:4326&gt;</span></span>
<span id="cb12-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] (147 -42) (148 -43) (149 -44)</span></span></code></pre></div></div>
</section>
<section id="the-convenience-wrapper-projproj_trans" class="level2">
<h2 class="anchored" data-anchor-id="the-convenience-wrapper-projproj_trans">The convenience wrapper: PROJ::proj_trans()</h2>
<p>If you don’t need a reusable transformation object, <code>PROJ::proj_trans()</code> combines the create and transform steps. It accepts matrices, data frames, wk geometry vectors, and sf <code>sfc</code> columns:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## matrix form — requires explicit source</span></span>
<span id="cb13-2">PROJ<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_trans</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">147</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea +type=crs"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>)</span>
<span id="cb13-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt;          x        y</span></span>
<span id="cb13-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1,] 5969744 -9803200</span></span>
<span id="cb13-5"></span>
<span id="cb13-6"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## wk type with CRS — source is inferred from the data</span></span>
<span id="cb13-7">PROJ<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_trans</span>(wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xy</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">147</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea +type=crs"</span>)</span>
<span id="cb13-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; &lt;wk_xy[1] with CRS=+proj=laea +type=crs&gt;</span></span>
<span id="cb13-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] (5969744 -9803200)</span></span>
<span id="cb13-10"></span>
<span id="cb13-11"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## full WKT geometries work too</span></span>
<span id="cb13-12">PROJ<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_trans</span>(</span>
<span id="cb13-13">  wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wkt</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"POLYGON ((1 1, 0 1, 0 0, 1 0, 1 1))"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>),</span>
<span id="cb13-14">  <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3112</span></span>
<span id="cb13-15">)</span>
<span id="cb13-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; &lt;wk_wkt[1] with CRS=EPSG:3112&gt;</span></span>
<span id="cb13-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#&gt; [1] POLYGON ((-1.351177e+07 -7779443, ...))</span></span></code></pre></div></div>
<p>When the input has a CRS (via <code>wk_crs()</code>), the <code>source_crs</code> argument can be omitted — <code>proj_trans()</code> reads it from the data using <code>wk_crs_proj_definition()</code>.</p>
</section>
<section id="the-typecrs-distinction" class="level2">
<h2 class="anchored" data-anchor-id="the-typecrs-distinction">The +type=crs distinction</h2>
<p>This is worth emphasizing because it catches people. In PROJ 6+, a bare proj-string like <code>"+proj=laea"</code> is a <em>coordinate operation</em>, not a CRS. The library draws a hard line between “a description of a coordinate reference system” and “a description of a mathematical operation to apply to coordinates.”</p>
<p>To specify a CRS using a proj-string, you <em>must</em> include <code>+type=crs</code>:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## CRS — works as source/target for transformations</span></span>
<span id="cb14-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_crs_text</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea +type=crs"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">format =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>L)</span>
<span id="cb14-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## returns proper WKT2</span></span>
<span id="cb14-4"></span>
<span id="cb14-5"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## coordinate operation — not a CRS</span></span>
<span id="cb14-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">proj_crs_text</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">format =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>L)</span>
<span id="cb14-7"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## NOT a CRS definition</span></span></code></pre></div></div>
<p>Object codes (<code>"EPSG:4326"</code>), WKT2, and PROJJSON are unambiguous — they always describe a CRS. Proj-strings need the <code>+type=crs</code> disambiguation. The recommendation from the PROJ documentation is to prefer authority:code strings or WKT2 for CRS definitions. But, use proj strings because they are easy and expressive, when you need a formal WKT2 for a particular operation define it carefully.</p>
</section>
<section id="how-this-connects-to-reproj" class="level2">
<h2 class="anchored" data-anchor-id="how-this-connects-to-reproj">How this connects to reproj</h2>
<p>The <a href="https://hypertidy.github.io/reproj/">reproj</a> package (see the <a href="https://www.hypertidy.org/posts/2026-03-24_check-out-reproj/">reproj</a> post in this series) uses <code>PROJ::proj_trans()</code> under the hood.</p>
<p>The relationship is:</p>
<ul>
<li><strong>reproj</strong> — high-level generic, format-agnostic, delegates to PROJ</li>
<li><strong>PROJ</strong> — mid-level wrapper around the PROJ C library, returns wk types, uses <code>wk_crs_proj_definition()</code> for CRS resolution</li>
<li><strong>wk</strong> — the geometry representation, streaming protocol, and CRS bridge generic</li>
<li><strong>PROJ C library</strong> (<code>libproj</code>) — the actual math, <code>proj_create()</code> does the parsing</li>
</ul>
<p>If you want maximum control and reusable transformation objects, use <code>proj_trans_create()</code> + <code>wk_transform()</code> directly. If you want a quick one-liner for a matrix of coordinates, use <code>reproj()</code>. They’re different interfaces to the same underlying capability.</p>
</section>
<section id="further-reading" class="level2">
<h2 class="anchored" data-anchor-id="further-reading">Further reading</h2>
<ul>
<li><a href="https://proj.org/en/stable/development/reference/functions.html#transformation-setup">PROJ C API: Transformation setup</a> — the canonical reference for what <code>proj_create()</code> accepts</li>
<li><a href="https://proj.org/schemas/v0.4/projjson.schema.json">PROJJSON schema</a></li>
<li><a href="https://paleolimbot.github.io/wk/reference/wk_crs_proj_definition.html">wk <code>wk_crs_proj_definition()</code> docs</a></li>
<li><a href="https://hypertidy.github.io/PROJ/reference/proj_trans.html">PROJ R package <code>proj_trans()</code> docs</a></li>
<li><a href="https://paleolimbot.github.io/wk/reference/wk_transform.html">wk <code>wk_transform()</code> docs</a></li>
</ul>
<p>Install from CRAN:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">install.packages</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PROJ"</span>)</span>
<span id="cb15-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">install.packages</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"wk"</span>)</span></code></pre></div></div>
</section>
<section id="check-it-out-series" class="level2">
<h2 class="anchored" data-anchor-id="check-it-out-series">Check it out series</h2>
<p>This is part of a series of posts for foundational spatial support in R. These posts include:</p>
<ul>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-wk/">wk</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-reproj/">reproj</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-proj-wk-transform/">PROJ/wk transform</a> (this one!)</li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-gdalraster/">gdalraster</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-geos/">geos</a></li>
</ul>


</section>

 ]]></description>
  <category>r-packages</category>
  <category>projections</category>
  <guid>https://hypertidy.org/posts/2026-03-24_check-out-proj-wk-transform/</guid>
  <pubDate>Tue, 24 Mar 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Check it out: gdalraster</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2026-03-24_check-out-gdalraster/</link>
  <description><![CDATA[ 






<p>The <a href="https://firelab.github.io/gdalraster/">gdalraster</a> package provides a comprehensive interface to the GDAL library for R. It handles raster I/O, vector I/O, the virtual filesystem, coordinate transformation, and a large collection of GDAL utilities — all through a direct, low-level API that doesn’t impose a high-level spatial data model.</p>
<section id="raster-io" class="level2">
<h2 class="anchored" data-anchor-id="raster-io">Raster I/O</h2>
<p>The core raster interface is <code>GDALRaster</code>, an Rcpp module class that wraps a GDAL dataset handle:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(gdalraster)</span>
<span id="cb1-2"></span>
<span id="cb1-3">f <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.file</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"extdata/storm_lake.lcp"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">package =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gdalraster"</span>)</span>
<span id="cb1-4">ds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">new</span>(GDALRaster, f, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb1-5"></span>
<span id="cb1-6">ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">info</span>()</span>
<span id="cb1-7">ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dim</span>()       <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># c(ncol, nrow, nbands)</span></span>
<span id="cb1-8">ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">res</span>()       <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># c(xres, yres)</span></span>
<span id="cb1-9">ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bbox</span>()      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># c(xmin, ymin, xmax, ymax)</span></span>
<span id="cb1-10">ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getProjection</span>()</span>
<span id="cb1-11"></span>
<span id="cb1-12"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## read a band</span></span>
<span id="cb1-13">data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">band =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>,</span>
<span id="cb1-14">                <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xoff =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">yoff =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>,</span>
<span id="cb1-15">                <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xsize =</span> ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getRasterXSize</span>(),</span>
<span id="cb1-16">                <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ysize =</span> ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getRasterYSize</span>(),</span>
<span id="cb1-17">                <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">out_xsize =</span> ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getRasterXSize</span>(),</span>
<span id="cb1-18">                <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">out_ysize =</span> ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getRasterYSize</span>())</span>
<span id="cb1-19"></span>
<span id="cb1-20">ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span>()</span></code></pre></div></div>
<p>The <code>read()</code> method maps directly to GDAL’s <code>RasterIO</code> — you specify the source window and the output size. This gives full control over decimation, oversampling, and partial reads. No intermediate abstraction, no automatic resampling decisions you didn’t ask for.</p>
</section>
<section id="vector-io" class="level2">
<h2 class="anchored" data-anchor-id="vector-io">Vector I/O</h2>
<p>gdalraster provides vector read/write through OGR:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## list layers in a data source</span></span>
<span id="cb2-2">dsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.file</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"extdata/ynp_fires_1984_2022.gpkg"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">package =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gdalraster"</span>)</span>
<span id="cb2-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ogr_ds_layer_names</span>(dsn)</span>
<span id="cb2-4"></span>
<span id="cb2-5"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## feature count and extent</span></span>
<span id="cb2-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ogr_ds_layer_count</span>(dsn)</span>
<span id="cb2-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ogr_layer_field_names</span>(dsn, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mtbs_perims"</span>)</span>
<span id="cb2-8"></span>
<span id="cb2-9"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## read features as a data frame with WKB geometry</span></span>
<span id="cb2-10">lyr <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">new</span>(GDALVector, dsn, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mtbs_perims"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">read_only =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb2-11">feat <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> lyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fetch</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># all features</span></span>
<span id="cb2-12">lyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span>()</span></code></pre></div></div>
<p>The geometry comes back as WKB — directly compatible with wk. You can pass it to <code>wk::as_wkt()</code>, <code>geos::as_geos_geometry()</code>, or <code>sf::st_as_sfc()</code> as needed. gdalraster reads the data; what you do with the geometry is up to you and whatever packages you choose.</p>
</section>
<section id="virtual-filesystem" class="level2">
<h2 class="anchored" data-anchor-id="virtual-filesystem">Virtual filesystem</h2>
<p>GDAL’s <code>/vsicurl/</code>, <code>/vsizip/</code>, <code>/vsimem/</code> and other virtual filesystem handlers are all available:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## read a remote file without downloading</span></span>
<span id="cb3-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vsi_read_dir</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/"</span>)</span>
<span id="cb3-3"></span>
<span id="cb3-4"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## open a GeoPackage over HTTP</span></span>
<span id="cb3-5">dsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_AUS.gpkg"</span></span>
<span id="cb3-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ogr_ds_layer_names</span>(dsn)</span>
<span id="cb3-7"></span>
<span id="cb3-8"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## read inside a remote zip</span></span>
<span id="cb3-9"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vsi_read_dir</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsizip//vsicurl/https://github.com/OSGeo/gdal/raw/refs/heads/master/autotest/gcore/data/byte.tif.zip"</span>)</span>
<span id="cb3-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#[1] "byte.tif"</span></span></code></pre></div></div>
<p>This is essential for cloud-native workflows. The same dataset string that works locally works over HTTP, S3, or Azure — GDAL handles the transport.</p>
</section>
<section id="the-warper" class="level2">
<h2 class="anchored" data-anchor-id="the-warper">The warper</h2>
<p><code>warp()</code> provides access to GDAL’s warper API for raster reprojection and resampling:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## warp to a new projection</span></span>
<span id="cb4-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(</span>
<span id="cb4-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">src_filename =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"input.tif"</span>,</span>
<span id="cb4-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dst_filename =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"output.tif"</span>,</span>
<span id="cb4-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3577"</span>,</span>
<span id="cb4-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tr =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>),           <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># target resolution</span></span>
<span id="cb4-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">r =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bilinear"</span>              <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># resampling method</span></span>
<span id="cb4-8">)</span></code></pre></div></div>
<p>This is the same warper that <code>gdalwarp</code> uses on the command line. For building VRTs, mosaics, and complex raster pipelines, gdalraster provides <code>buildVRT()</code>, <code>translate()</code>, and <code>rasterFromRaster()</code>.</p>
</section>
<section id="vrt-construction" class="level2">
<h2 class="anchored" data-anchor-id="vrt-construction">VRT construction</h2>
<p>One of the most powerful features is programmatic VRT (Virtual Raster) construction:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## create a VRT from multiple source files</span></span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">buildVRT</span>(</span>
<span id="cb5-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">vrt_filename =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mosaic.vrt"</span>,</span>
<span id="cb5-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">input_rasters =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tile1.tif"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tile2.tif"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"tile3.tif"</span>)</span>
<span id="cb5-5">)</span>
<span id="cb5-6"></span>
<span id="cb5-7"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## add sources to a VRT programmatically</span></span>
<span id="cb5-8">ds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">new</span>(GDALRaster, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"output.vrt"</span>, <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>)</span>
<span id="cb5-9">ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">addSimpleSource</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">band =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">src_filename =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"source.tif"</span>, ...)</span>
<span id="cb5-10">ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span>()</span></code></pre></div></div>
<p>VRTs are GDAL’s answer to lazy raster operations — the XML file describes the operation but nothing is computed until you read pixels.</p>
</section>
<section id="configuration-and-utilities" class="level2">
<h2 class="anchored" data-anchor-id="configuration-and-utilities">Configuration and utilities</h2>
<p>gdalraster exposes GDAL configuration options:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## set GDAL config for performance tuning</span></span>
<span id="cb6-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_config_option</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GDAL_CACHEMAX"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"512"</span>)</span>
<span id="cb6-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_config_option</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GDAL_HTTP_MULTIRANGE"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"YES"</span>)</span>
<span id="cb6-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_config_option</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GDAL_NUM_THREADS"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ALL_CPUS"</span>)</span>
<span id="cb6-5"></span>
<span id="cb6-6"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## check what's set</span></span>
<span id="cb6-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_config_option</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GDAL_CACHEMAX"</span>)</span>
<span id="cb6-8"></span>
<span id="cb6-9"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## GDAL/PROJ/GEOS version info</span></span>
<span id="cb6-10"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gdal_version</span>()</span></code></pre></div></div>
<p>Plus a full set of geometry utilities (<code>g_buffer()</code>, <code>g_intersection()</code>, etc.) that use GEOS through GDAL’s OGR layer, and coordinate transformation via <code>transform_xy()</code>.</p>
<p>Install from CRAN:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">install.packages</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gdalraster"</span>)</span></code></pre></div></div>
<p>Links:</p>
<ul>
<li><a href="https://CRAN.R-project.org/package=gdalraster">gdalraster on CRAN</a></li>
<li><a href="https://usdaforestservice.github.io/gdalraster/">gdalraster documentation</a></li>
<li><a href="https://github.com/USDAForestService/gdalraster">GitHub</a></li>
</ul>
</section>
<section id="check-it-out-series" class="level2">
<h2 class="anchored" data-anchor-id="check-it-out-series">Check it out series</h2>
<p>This is part of a series of posts for foundational spatial support in R. These posts include:</p>
<ul>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-wk/">wk</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-reproj/">reproj</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-proj-wk-transform/">PROJ/wk transform</a></li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-gdalraster/">gdalraster</a> (this one!)</li>
<li><a href="https://www.hypertidy.org/posts/2026-03-24_check-out-geos/">geos</a></li>
</ul>


</section>

 ]]></description>
  <category>r-packages</category>
  <category>gdal</category>
  <category>raster</category>
  <category>vector</category>
  <guid>https://hypertidy.org/posts/2026-03-24_check-out-gdalraster/</guid>
  <pubDate>Tue, 24 Mar 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>What’s on geodata.ucdavis.edu and how to access it</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2026-03-17_geodata-package-data/</link>
  <description><![CDATA[ 






<p>The R package <a href="https://CRAN.R-project.org/package=geodata">geodata</a> provides functions for downloading climate, elevation, soil, crop, species occurrence, and administrative boundary data. All of its raster and vector data is hosted on a single Apache web server at <code>geodata.ucdavis.edu</code>.</p>
<p>Every file on that server is directly accessible via HTTP. This means we can enumerate, inspect, and in some cases read them using GDAL’s virtual filesystem — without downloading anything first.</p>
<p>This post documents the full site structure, the file formats served, and which files can be streamed via <code>/vsicurl/</code> (they all can, but without efficient tiling it’s probably best to make local copies for large raster).</p>
<section id="helper-functions" class="level2">
<h2 class="anchored" data-anchor-id="helper-functions">Helper functions</h2>
<p>The code snippets below use a small set of helper functions that wrap <code>gdalraster::vsi_read_dir()</code> and related GDAL calls. Source them with:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">source</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://github.com/mdsumner/quarto-blog/releases/download/latest/geodata-ucdavis-tools.R"</span>)</span></code></pre></div></div>
</div>
<p>This provides: <code>vsi_list()</code>, <code>geodata_files()</code>, <code>gdalinfo()</code>, <code>check_block_size()</code>, and <code>streamability_report()</code>.</p>
</section>
<section id="site-structure" class="level2">
<h2 class="anchored" data-anchor-id="site-structure">Site structure</h2>
<p>The server has three top-level paths that contain spatial data:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 37%">
<col style="width: 62%">
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Path</th>
<th style="text-align: left;">Contents</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;"><code>/climate/</code></td>
<td style="text-align: left;">WorldClim 2.1 and 1.4, CMIP5 legacy data</td>
</tr>
<tr class="even">
<td style="text-align: left;"><code>/cmip6/</code></td>
<td style="text-align: left;">Downscaled CMIP6 projections</td>
</tr>
<tr class="odd">
<td style="text-align: left;"><code>/geodata/</code></td>
<td style="text-align: left;">Soil, landcover, crops, elevation, travel time, OSM, buildings</td>
</tr>
<tr class="even">
<td style="text-align: left;"><code>/gadm/</code></td>
<td style="text-align: left;">GADM administrative boundaries (versions 2.8, 3.6, 4.0, 4.1)</td>
</tr>
</tbody>
</table>
<p>The root URL itself and some intermediate directories serve an <code>index.html</code> that says “Hello World!” rather than an Apache directory listing. The data directories below these do have standard Apache autoindex enabled, which is what makes <code>vsi_read_dir()</code> work.</p>
</section>
<section id="enumerating-files" class="level2">
<h2 class="anchored" data-anchor-id="enumerating-files">Enumerating files</h2>
<p>GDAL’s <code>/vsicurl/</code> handler can parse Apache directory listings. The <code>gdalraster</code> package exposes this via <code>vsi_read_dir()</code>:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(gdalraster)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>GDAL 3.13.0dev-a3b7b01d3e-dirty (released 2026-02-23), GEOS 3.12.1, PROJ 9.7.0</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## flat directory — returns filenames</span></span>
<span id="cb4-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vsi_read_dir</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "agg"                           "bdod_0-5cm_mean_30s.tif"      
 [3] "bdod_15-30cm_mean_30s.tif"     "bdod_30-60cm_mean_30s.tif"    
 [5] "bdod_5-15cm_mean_30s.tif"      "cec_0-5cm_mean_30s.tif"       
 [7] "cec_15-30cm_mean_30s.tif"      "cec_30-60cm_mean_30s.tif"     
 [9] "cec_5-15cm_mean_30s.tif"       "cfvo_0-5cm_mean_30s.tif"      
[11] "cfvo_15-30cm_mean_30s.tif"     "cfvo_30-60cm_mean_30s.tif"    
[13] "cfvo_5-15cm_mean_30s.tif"      "clay_0-5cm_mean_30s.tif"      
[15] "clay_15-30cm_mean_30s.tif"     "clay_30-60cm_mean_30s.tif"    
[17] "clay_5-15cm_mean_30s.tif"      "files.txt"                    
[19] "fill"                          "nitrogen_0-5cm_mean_30s.tif"  
[21] "nitrogen_15-30cm_mean_30s.tif" "nitrogen_30-60cm_mean_30s.tif"
[23] "nitrogen_5-15cm_mean_30s.tif"  "ocd_0-5cm_mean_30s.tif"       
[25] "ocd_15-30cm_mean_30s.tif"      "ocd_30-60cm_mean_30s.tif"     
[27] "ocd_5-15cm_mean_30s.tif"       "phh2o_0-5cm_Q0.05_30s.tif"    
[29] "phh2o_0-5cm_Q0.95_30s.tif"     "phh2o_0-5cm_mean_30s.tif"     
[31] "phh2o_15-30cm_mean_30s.tif"    "phh2o_30-60cm_mean_30s.tif"   
[33] "phh2o_5-15cm_Q0.05_30s.tif"    "phh2o_5-15cm_Q0.95_30s.tif"   
[35] "phh2o_5-15cm_mean_30s.tif"     "raw"                          
[37] "sand_0-5cm_mean_30s.tif"       "sand_15-30cm_mean_30s.tif"    
[39] "sand_30-60cm_mean_30s.tif"     "sand_5-15cm_mean_30s.tif"     
[41] "silt_0-5cm_mean_30s.tif"       "silt_15-30cm_mean_30s.tif"    
[43] "silt_30-60cm_mean_30s.tif"     "silt_5-15cm_mean_30s.tif"     
[45] "soc_0-5cm_mean_30s.tif"        "soc_15-30cm_mean_30s.tif"     
[47] "soc_30-60cm_mean_30s.tif"      "soc_5-15cm_mean_30s.tif"      </code></pre>
</div>
</div>
<p>For structured enumeration with URLs and GDAL dataset names:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">soilgrids <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geodata_files</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geodata/soil/soilgrids"</span>)</span>
<span id="cb6-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(soilgrids)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>                                                                           url
1   https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_0-5cm_mean_30s.tif
2 https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_15-30cm_mean_30s.tif
3 https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_30-60cm_mean_30s.tif
4  https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_5-15cm_mean_30s.tif
5    https://geodata.ucdavis.edu/geodata/soil/soilgrids/cec_0-5cm_mean_30s.tif
6  https://geodata.ucdavis.edu/geodata/soil/soilgrids/cec_15-30cm_mean_30s.tif
                       file ext
1   bdod_0-5cm_mean_30s.tif tif
2 bdod_15-30cm_mean_30s.tif tif
3 bdod_30-60cm_mean_30s.tif tif
4  bdod_5-15cm_mean_30s.tif tif
5    cec_0-5cm_mean_30s.tif tif
6  cec_15-30cm_mean_30s.tif tif
                                                                                gdaldsn
1   /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_0-5cm_mean_30s.tif
2 /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_15-30cm_mean_30s.tif
3 /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_30-60cm_mean_30s.tif
4  /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_5-15cm_mean_30s.tif
5    /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/cec_0-5cm_mean_30s.tif
6  /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/cec_15-30cm_mean_30s.tif</code></pre>
</div>
</div>
<p>This returns a data.frame with columns <code>url</code>, <code>file</code>, <code>ext</code>, and <code>gdaldsn</code>. The <code>gdaldsn</code> column contains the <code>/vsicurl/</code> path for files GDAL can read, and <code>NA</code> for files it cannot (<code>.rds</code>, <code>.txt</code>, etc.).</p>
</section>
<section id="whats-there-a-complete-inventory" class="level2">
<h2 class="anchored" data-anchor-id="whats-there-a-complete-inventory">What’s there: a complete inventory</h2>
<section id="soilgrids-geodatasoilsoilgrids" class="level3">
<h3 class="anchored" data-anchor-id="soilgrids-geodatasoilsoilgrids">SoilGrids (<code>/geodata/soil/soilgrids/</code>)</h3>
<p>Global soil properties at 30 arc-second resolution. 48 TIF files covering 8 properties (bdod, cec, cfvo, clay, nitrogen, ocd, phh2o, sand, silt, soc) at 4 depth intervals, plus pH quantiles. Files range from 83 MB to 546 MB.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1">soilgrids <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geodata_files</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geodata/soil/soilgrids"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pattern =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">.tif$"</span>)</span>
<span id="cb8-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(soilgrids)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 44</code></pre>
</div>
</div>
<p><strong>Format</strong>: Single-band GeoTIFF, LZW compressed, <code>Block=43200x1</code> (row-striped). No overviews. No internal tiling.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">check_block_size</span>(soilgrids<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>gdaldsn[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>xblock yblock 
 43200      1 
attr(,"full_width")
[1] 43200
attr(,"is_row_striped")
[1] TRUE
attr(,"is_tiled")
[1] FALSE</code></pre>
</div>
</div>
<p><strong>Streamability</strong>: Row-striped layout means sub-region reads via <code>/vsicurl/</code> require decompressing entire rows spanning the full 43200 pixel width. Reading a small bounding box will transfer most of the file. These files are best downloaded locally.</p>
<p>The <code>geodata::soil_world_vsi()</code> function constructs <code>/vsicurl/</code> paths to these same files — the name suggests streaming is the intended use, but the row-striped layout makes it impractical for anything less than a large regional or global read.</p>
</section>
<section id="worldclim-2.1-tiles-climateworldclim2_1tilestile" class="level3">
<h3 class="anchored" data-anchor-id="worldclim-2.1-tiles-climateworldclim2_1tilestile">WorldClim 2.1 tiles (<code>/climate/worldclim/2_1/tiles/tile/</code>)</h3>
<p>30 arc-second resolution climate data, pre-tiled into 72 spatial tiles. 8 variables (bio, elev, prec, srad, tavg, tmax, tmin, wind). Bio tiles have 19 bands; monthly variables have 12 bands; elevation has 1. File sizes range from ~5 MB (ocean/ice tiles) to ~550 MB (land-dense tiles).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">wc_tiles <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geodata_files</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"climate/worldclim/2_1/tiles/tile"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pattern =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">.tif$"</span>)</span>
<span id="cb12-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(wc_tiles)  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## expect 576 = 72 tiles × 8 variables</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 576</code></pre>
</div>
</div>
<p><strong>Format</strong>: Multi-band GeoTIFF. Block layout should be checked:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">check_block_size</span>(wc_tiles<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>gdaldsn[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>xblock yblock 
  3600      1 
attr(,"full_width")
[1] 3600
attr(,"is_row_striped")
[1] TRUE
attr(,"is_tiled")
[1] FALSE</code></pre>
</div>
</div>
</section>
<section id="worldclim-2.1-global-climateworldclim2_1base" class="level3">
<h3 class="anchored" data-anchor-id="worldclim-2.1-global-climateworldclim2_1base">WorldClim 2.1 global (<code>/climate/worldclim/2_1/base/</code>)</h3>
<p>Global grids at 10m, 5m, 2.5m, and 30s resolution. All stored as <code>.zip</code> files containing one or more TIF files per variable.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 32%">
<col style="width: 29%">
<col style="width: 37%">
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Resolution</th>
<th style="text-align: left;">Variables</th>
<th style="text-align: left;">Example size</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">10 minute</td>
<td style="text-align: left;">bio, elev, prec, srad, tavg, tmax, tmin, vapr, wind</td>
<td style="text-align: left;">1.3 MB – 48 MB</td>
</tr>
<tr class="even">
<td style="text-align: left;">5 minute</td>
<td style="text-align: left;">same</td>
<td style="text-align: left;">4.6 MB – 171 MB</td>
</tr>
<tr class="odd">
<td style="text-align: left;">2.5 minute</td>
<td style="text-align: left;">same</td>
<td style="text-align: left;">17 MB – 628 MB</td>
</tr>
<tr class="even">
<td style="text-align: left;">30 second</td>
<td style="text-align: left;">same</td>
<td style="text-align: left;">323 MB – 9.7 GB</td>
</tr>
</tbody>
</table>
<p>GDAL can read inside these zips via <code>/vsizip//vsicurl/</code>:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## example: 10-minute bioclim, first file inside the zip</span></span>
<span id="cb16-2">dsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsizip//vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/base/wc2.1_10m_bio.zip"</span></span>
<span id="cb16-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## list the contents of the zip</span></span>
<span id="cb16-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vsi_read_dir</span>(dsn)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "wc2.1_10m_bio_1.tif"  "wc2.1_10m_bio_10.tif" "wc2.1_10m_bio_11.tif"
 [4] "wc2.1_10m_bio_12.tif" "wc2.1_10m_bio_13.tif" "wc2.1_10m_bio_14.tif"
 [7] "wc2.1_10m_bio_15.tif" "wc2.1_10m_bio_16.tif" "wc2.1_10m_bio_17.tif"
[10] "wc2.1_10m_bio_18.tif" "wc2.1_10m_bio_19.tif" "wc2.1_10m_bio_2.tif" 
[13] "wc2.1_10m_bio_3.tif"  "wc2.1_10m_bio_4.tif"  "wc2.1_10m_bio_5.tif" 
[16] "wc2.1_10m_bio_6.tif"  "wc2.1_10m_bio_7.tif"  "wc2.1_10m_bio_8.tif" 
[19] "wc2.1_10m_bio_9.tif" </code></pre>
</div>
</div>
<p>The internal TIF filenames follow the pattern <code>wc2.1_{res}_{var}_{number}.tif</code>.</p>
</section>
<section id="worldclim-2.1-country-extracts-climateworldclim2_1tilesiso" class="level3">
<h3 class="anchored" data-anchor-id="worldclim-2.1-country-extracts-climateworldclim2_1tilesiso">WorldClim 2.1 country extracts (<code>/climate/worldclim/2_1/tiles/iso/</code>)</h3>
<p>30 arc-second data clipped to individual countries, identified by ISO 3166-1 alpha-3 codes.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb18-1">iso <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geodata_files</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"climate/worldclim/2_1/tiles/iso"</span>)</span>
<span id="cb18-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(iso)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>                                                                                 url
1  https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_bio.tif
2 https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_elev.tif
3 https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_prec.tif
4 https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_srad.tif
5 https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_tavg.tif
6 https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_tmax.tif
                    file ext
1  ABW_wc2.1_30s_bio.tif tif
2 ABW_wc2.1_30s_elev.tif tif
3 ABW_wc2.1_30s_prec.tif tif
4 ABW_wc2.1_30s_srad.tif tif
5 ABW_wc2.1_30s_tavg.tif tif
6 ABW_wc2.1_30s_tmax.tif tif
                                                                                      gdaldsn
1  /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_bio.tif
2 /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_elev.tif
3 /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_prec.tif
4 /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_srad.tif
5 /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_tavg.tif
6 /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/iso/ABW_wc2.1_30s_tmax.tif</code></pre>
</div>
</div>
</section>
<section id="worldclim-1.4-climateworldclim1_4" class="level3">
<h3 class="anchored" data-anchor-id="worldclim-1.4-climateworldclim1_4">WorldClim 1.4 (<code>/climate/worldclim/1_4/</code>)</h3>
<p>Legacy WorldClim version in BIL (Band Interleaved by Line) format inside zip files. Three subdirectories: <code>cur/</code> (current), <code>fut/</code> (future projections), <code>pst/</code> (past / LGM / mid-Holocene).</p>
<p>BIL format is GDAL-readable but, like the row-striped TIFs, does not support efficient random access.</p>
</section>
<section id="cmip6-projections-cmip6" class="level3">
<h3 class="anchored" data-anchor-id="cmip6-projections-cmip6">CMIP6 projections (<code>/cmip6/</code>)</h3>
<p>Downscaled and bias-corrected CMIP6 future climate data. Organised as:</p>
<pre><code>/cmip6/{resolution}/{model}/{ssp}/</code></pre>
<p>Resolutions: <code>30s</code>, <code>2.5m</code>, <code>5m</code>, <code>10m</code>. 23 GCMs. 4 SSPs (ssp126, ssp245, ssp370, ssp585). 4 time periods (2021-2040, 2041-2060, 2061-2080, 2081-2100). Variables: bioc, prec, tmax, tmin.</p>
<p>At 30s resolution these are bare TIF files, some exceeding 20 GB.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb21-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## list models at 2.5 minute resolution</span></span>
<span id="cb21-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vsi_read_dir</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://geodata.ucdavis.edu/cmip6/2.5m/"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "ACCESS-CM2"       "ACCESS-ESM1-5"    "AWI-CM-1-1-MR"    "BCC-CSM2-MR"     
 [5] "CMCC-ESM2"        "CNRM-CM6-1"       "CNRM-CM6-1-HR"    "CNRM-ESM2-1"     
 [9] "CanESM5"          "CanESM5-CanOE"    "EC-Earth3-Veg"    "EC-Earth3-Veg-LR"
[13] "FIO-ESM-2-0"      "GFDL-ESM4"        "GISS-E2-1-G"      "GISS-E2-1-H"     
[17] "HadGEM3-GC31-LL"  "INM-CM4-8"        "INM-CM5-0"        "IPSL-CM6A-LR"    
[21] "MIROC-ES2L"       "MIROC6"           "MPI-ESM1-2-HR"    "MPI-ESM1-2-LR"   
[25] "MRI-ESM2-0"       "UKESM1-0-LL"     </code></pre>
</div>
</div>
<p>There is also a <code>/cmip6/tiles/</code> directory with tiled versions.</p>
</section>
<section id="cmip5-projections-climatecmip5" class="level3">
<h3 class="anchored" data-anchor-id="cmip5-projections-climatecmip5">CMIP5 projections (<code>/climate/cmip5/</code>)</h3>
<p>Legacy CMIP5 data at 30s, 2.5m, 5m, 10m resolutions. Separate directories for <code>lgm/</code> (Last Glacial Maximum) and <code>mid/</code> (mid-Holocene).</p>
</section>
<section id="elevation" class="level3">
<h3 class="anchored" data-anchor-id="elevation">Elevation</h3>
<p>TODO: locate and document. The <code>geodata</code> package provides <code>elevation_3s()</code>, <code>elevation_30s()</code>, and <code>elevation_global()</code> — the URLs for these need to be traced from the source code.</p>
</section>
<section id="landcover-geodatalandcover" class="level3">
<h3 class="anchored" data-anchor-id="landcover-geodatalandcover">Landcover (<code>/geodata/landcover/</code>)</h3>
<p>Two subdirectories:</p>
<ul>
<li><code>/geodata/landcover/30s/</code> — 30 arc-second aggregated landcover fractions</li>
<li><code>/geodata/landcover/3deg_cogs/</code> — ESA WorldCover 10m data as 3-degree tiles, labelled as COGs in the directory name</li>
</ul>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb23-1">lc_cogs <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geodata_files</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geodata/landcover/3deg_cogs"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pattern =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">.tif$"</span>)</span>
<span id="cb23-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(lc_cogs)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 2651</code></pre>
</div>
</div>
<p>The <code>3deg_cogs</code> files follow the naming convention <code>ESA_WorldCover_10m_2020_v100_{lat}{lon}_Map.tif</code>. If these are genuine COGs (internally tiled with overviews), they would be efficiently streamable via <code>/vsicurl/</code>.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb25" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb25-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## check whether these are really COGs</span></span>
<span id="cb25-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">check_block_size</span>(lc_cogs<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>gdaldsn[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>xblock yblock 
  1024   1024 
attr(,"full_width")
[1] 36000
attr(,"is_row_striped")
[1] FALSE
attr(,"is_tiled")
[1] TRUE</code></pre>
</div>
</div>
</section>
<section id="crops-geodatacrops" class="level3">
<h3 class="anchored" data-anchor-id="crops-geodatacrops">Crops (<code>/geodata/crops/</code>)</h3>
<p>Subdirectories for SPAM and Monfreda crop data, plus cropland density and crop calendars. File formats and structure need to be enumerated.</p>
</section>
<section id="gadm-administrative-boundaries-gadmgadm4.1" class="level3">
<h3 class="anchored" data-anchor-id="gadm-administrative-boundaries-gadmgadm4.1">GADM administrative boundaries (<code>/gadm/gadm4.1/</code>)</h3>
<p>Per-country boundaries in multiple formats:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 31%">
<col style="width: 18%">
<col style="width: 34%">
<col style="width: 15%">
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Subdirectory</th>
<th style="text-align: left;">Format</th>
<th style="text-align: left;">GDAL-readable</th>
<th style="text-align: left;">Notes</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;"><code>gpkg/</code></td>
<td style="text-align: left;">GeoPackage</td>
<td style="text-align: left;">Yes</td>
<td style="text-align: left;">SQLite-based, supports HTTP range requests</td>
</tr>
<tr class="even">
<td style="text-align: left;"><code>shp/</code></td>
<td style="text-align: left;">Shapefile (zipped)</td>
<td style="text-align: left;">Yes, via /vsizip/</td>
<td style="text-align: left;">Multiple component files</td>
</tr>
<tr class="odd">
<td style="text-align: left;"><code>json/</code></td>
<td style="text-align: left;">GeoJSON</td>
<td style="text-align: left;">Yes</td>
<td style="text-align: left;"></td>
</tr>
<tr class="even">
<td style="text-align: left;"><code>pck/</code></td>
<td style="text-align: left;">RDS (R serialization)</td>
<td style="text-align: left;">No</td>
<td style="text-align: left;">Used by <code>geodata::gadm()</code></td>
</tr>
<tr class="odd">
<td style="text-align: left;"><code>kmz/</code></td>
<td style="text-align: left;">KMZ (zipped KML)</td>
<td style="text-align: left;">Yes, via /vsizip/</td>
<td style="text-align: left;"></td>
</tr>
</tbody>
</table>
<p>Whole-dataset archives:</p>
<ul>
<li><code>gadm_410-gpkg.zip</code> — 1.4 GB, all countries in one GeoPackage</li>
<li><code>gadm_410-gdb.zip</code> — 913 MB, FileGDB format</li>
<li><code>gadm_410-levels.zip</code> — 2.5 GB, separated by admin level</li>
<li><code>gadm_410-raw.gpkg</code> — 2.6 GB, bare GeoPackage on HTTP</li>
</ul>
<p>The <code>gadm_410-raw.gpkg</code> is directly streamable:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb27-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## open GADM as a single GeoPackage over HTTP</span></span>
<span id="cb27-2">dsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://geodata.ucdavis.edu/gadm/gadm4.1/gadm_410-raw.gpkg"</span></span>
<span id="cb27-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## list layers</span></span>
<span id="cb27-4">gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ogr_ds_layer_names</span>(dsn)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "gadm41_raw"</code></pre>
</div>
</div>
<p>Per-country GeoPackage files are also streamable:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb29" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb29-1">dsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_AUS.gpkg"</span></span>
<span id="cb29-2">gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ogr_ds_layer_names</span>(dsn)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "ADM_ADM_0" "ADM_ADM_1" "ADM_ADM_2"</code></pre>
</div>
</div>
</section>
<section id="other-datasets" class="level3">
<h3 class="anchored" data-anchor-id="other-datasets">Other datasets</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 17%">
<col style="width: 29%">
<col style="width: 52%">
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Path</th>
<th style="text-align: left;">Contents</th>
<th style="text-align: left;">geodata function</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;"><code>/geodata/travel/</code></td>
<td style="text-align: left;">Travel time rasters</td>
<td style="text-align: left;"><code>travel_time()</code></td>
</tr>
<tr class="even">
<td style="text-align: left;"><code>/geodata/osm/</code></td>
<td style="text-align: left;">OpenStreetMap extracts (highways, places)</td>
<td style="text-align: left;"><code>osm()</code></td>
</tr>
<tr class="odd">
<td style="text-align: left;"><code>/geodata/buildings/</code></td>
<td style="text-align: left;">Building footprint data</td>
<td style="text-align: left;">—</td>
</tr>
</tbody>
</table>
<p>These need further enumeration.</p>
</section>
<section id="datasets-not-on-this-server" class="level3">
<h3 class="anchored" data-anchor-id="datasets-not-on-this-server">Datasets not on this server</h3>
<p>Some <code>geodata</code> functions fetch data from external APIs rather than <code>geodata.ucdavis.edu</code>:</p>
<ul>
<li><code>sp_occurrence()</code> — queries the GBIF API</li>
<li><code>bio_oracle()</code> — queries the Bio-Oracle server at <code>bio-oracle.org</code></li>
</ul>
</section>
</section>
<section id="block-layout-and-streamability" class="level2">
<h2 class="anchored" data-anchor-id="block-layout-and-streamability">Block layout and streamability</h2>
<p>The central question for remote access is whether a file’s internal layout supports efficient HTTP range requests. GDAL’s <code>/vsicurl/</code> handler issues byte-range requests to read specific portions of a file. This works well when the file is internally tiled (e.g., COG format with <code>Block=256x256</code>) but poorly when the file is row-striped (<code>Block=width×1</code>).</p>
<p>For a row-striped file, reading a small spatial window requires decompressing one or more full rows, each spanning the entire raster width. For a 43200-pixel-wide global grid, every row is a complete scan line from -180° to +180°. A single HTTP range request per row, times the number of rows in the window, with full LZW decompression of each row. For a small bounding box this is extremely wasteful.</p>
<section id="what-we-know" class="level3">
<h3 class="anchored" data-anchor-id="what-we-know">What we know</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 30%">
<col style="width: 35%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Collection</th>
<th style="text-align: left;">Block layout</th>
<th style="text-align: left;">Streamable?</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">SoilGrids TIFs</td>
<td style="text-align: left;">43200×1 (row-striped)</td>
<td style="text-align: left;">No — download</td>
</tr>
<tr class="even">
<td style="text-align: left;">WorldClim 2.1 tiles</td>
<td style="text-align: left;">TODO: check</td>
<td style="text-align: left;">Probably row-striped</td>
</tr>
<tr class="odd">
<td style="text-align: left;">WorldClim 2.1 global zips</td>
<td style="text-align: left;">N/A (zip)</td>
<td style="text-align: left;">Via /vsizip/, but still row-striped inside</td>
</tr>
<tr class="even">
<td style="text-align: left;">CMIP6 30s TIFs</td>
<td style="text-align: left;">TODO: check</td>
<td style="text-align: left;">Unknown</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Landcover 3deg COGs</td>
<td style="text-align: left;">TODO: check</td>
<td style="text-align: left;">Likely yes (name says COGs)</td>
</tr>
<tr class="even">
<td style="text-align: left;">Landcover 30s</td>
<td style="text-align: left;">TODO: check</td>
<td style="text-align: left;">Unknown</td>
</tr>
<tr class="odd">
<td style="text-align: left;">GADM GeoPackage</td>
<td style="text-align: left;">N/A (vector)</td>
<td style="text-align: left;">Yes — SQLite random access works over HTTP</td>
</tr>
<tr class="even">
<td style="text-align: left;">GADM raw GeoPackage</td>
<td style="text-align: left;">N/A (vector)</td>
<td style="text-align: left;">Yes</td>
</tr>
</tbody>
</table>
</section>
<section id="how-to-check" class="level3">
<h3 class="anchored" data-anchor-id="how-to-check">How to check</h3>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb31" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb31-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## for any TIF on the server</span></span>
<span id="cb31-2">bs <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">check_block_size</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://geodata.ucdavis.edu/path/to/file.tif"</span>)</span>
<span id="cb31-3">bs</span>
<span id="cb31-4"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## if is_row_striped is TRUE: download, don't stream</span></span>
<span id="cb31-5"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## if is_tiled is TRUE: streaming is efficient</span></span></code></pre></div></div>
</div>
</section>
</section>
<section id="generating-file-tables" class="level2">
<h2 class="anchored" data-anchor-id="generating-file-tables">Generating file tables</h2>
<p>For any collection, generate a complete table of URLs and GDAL dataset names:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb32" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb32-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## SoilGrids: all TIFs</span></span>
<span id="cb32-2">sg <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geodata_files</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geodata/soil/soilgrids"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pattern =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">.tif$"</span>)</span>
<span id="cb32-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(sg[, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"url"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gdaldsn"</span>)])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>                                                                           url
1   https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_0-5cm_mean_30s.tif
2 https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_15-30cm_mean_30s.tif
3 https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_30-60cm_mean_30s.tif
4  https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_5-15cm_mean_30s.tif
5    https://geodata.ucdavis.edu/geodata/soil/soilgrids/cec_0-5cm_mean_30s.tif
6  https://geodata.ucdavis.edu/geodata/soil/soilgrids/cec_15-30cm_mean_30s.tif
                                                                                gdaldsn
1   /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_0-5cm_mean_30s.tif
2 /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_15-30cm_mean_30s.tif
3 /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_30-60cm_mean_30s.tif
4  /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/bdod_5-15cm_mean_30s.tif
5    /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/cec_0-5cm_mean_30s.tif
6  /vsicurl/https://geodata.ucdavis.edu/geodata/soil/soilgrids/cec_15-30cm_mean_30s.tif</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb34" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb34-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## WorldClim tiles: all TIFs</span></span>
<span id="cb34-2">wc <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geodata_files</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"climate/worldclim/2_1/tiles/tile"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pattern =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">.tif$"</span>)</span>
<span id="cb34-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(wc[, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"url"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gdaldsn"</span>)])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>                                                                                      url
1  https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_bio.tif
2 https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_elev.tif
3 https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_prec.tif
4 https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_srad.tif
5 https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_tavg.tif
6 https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_tmax.tif
                                                                                           gdaldsn
1  /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_bio.tif
2 /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_elev.tif
3 /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_prec.tif
4 /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_srad.tif
5 /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_tavg.tif
6 /vsicurl/https://geodata.ucdavis.edu/climate/worldclim/2_1/tiles/tile/tile_10_wc2.1_30s_tmax.tif</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb36" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb36-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## GADM 4.1 GeoPackages</span></span>
<span id="cb36-2">gadm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geodata_files</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gadm/gadm4.1/gpkg"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pattern =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">.gpkg$"</span>)</span>
<span id="cb36-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(gadm[, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"url"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gdaldsn"</span>)])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>                                                            url
1 https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_ABW.gpkg
2 https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_AFG.gpkg
3 https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_AGO.gpkg
4 https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_AIA.gpkg
5 https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_ALA.gpkg
6 https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_ALB.gpkg
                                                                 gdaldsn
1 /vsicurl/https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_ABW.gpkg
2 /vsicurl/https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_AFG.gpkg
3 /vsicurl/https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_AGO.gpkg
4 /vsicurl/https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_AIA.gpkg
5 /vsicurl/https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_ALA.gpkg
6 /vsicurl/https://geodata.ucdavis.edu/gadm/gadm4.1/gpkg/gadm41_ALB.gpkg</code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb38" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb38-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## CMIP6 models at 2.5 minute resolution</span></span>
<span id="cb38-2"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## first list the model directories, then enumerate within each</span></span>
<span id="cb38-3">models <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vsi_read_dir</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://geodata.ucdavis.edu/cmip6/2.5m/"</span>)</span>
<span id="cb38-4">models</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "ACCESS-CM2"       "ACCESS-ESM1-5"    "AWI-CM-1-1-MR"    "BCC-CSM2-MR"     
 [5] "CMCC-ESM2"        "CNRM-CM6-1"       "CNRM-CM6-1-HR"    "CNRM-ESM2-1"     
 [9] "CanESM5"          "CanESM5-CanOE"    "EC-Earth3-Veg"    "EC-Earth3-Veg-LR"
[13] "FIO-ESM-2-0"      "GFDL-ESM4"        "GISS-E2-1-G"      "GISS-E2-1-H"     
[17] "HadGEM3-GC31-LL"  "INM-CM4-8"        "INM-CM5-0"        "IPSL-CM6A-LR"    
[21] "MIROC-ES2L"       "MIROC6"           "MPI-ESM1-2-HR"    "MPI-ESM1-2-LR"   
[25] "MRI-ESM2-0"       "UKESM1-0-LL"     </code></pre>
</div>
</div>
</section>
<section id="still-to-document" class="level2">
<h2 class="anchored" data-anchor-id="still-to-document">Still to document</h2>
<p>Several areas need further investigation:</p>
<ul>
<li>Elevation data paths (<code>elevation_3s</code>, <code>elevation_30s</code>, <code>elevation_global</code>)</li>
<li>Exact contents of <code>/geodata/crops/</code>, <code>/geodata/travel/</code>, <code>/geodata/osm/</code>, <code>/geodata/buildings/</code></li>
<li>Block layout of WorldClim tiles, CMIP6 30s TIFs, and landcover COGs</li>
<li>Contents of <code>/geodata/landcover/30s/</code></li>
<li>Contents of <code>/geodata/soil/soilgrids/agg/</code>, <code>fill/</code>, and <code>raw/</code> subdirectories</li>
<li>The <code>/cmip6/tiles/</code> tiled variant structure</li>
</ul>


</section>

 ]]></description>
  <category>code</category>
  <category>news</category>
  <category>raster</category>
  <category>vector</category>
  <category>gdal</category>
  <category>spatial</category>
  <guid>https://hypertidy.org/posts/2026-03-17_geodata-package-data/</guid>
  <pubDate>Tue, 17 Mar 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Map Reprojection and Map Edges</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2026-02-20_map-extent-projection/</link>
  <description><![CDATA[ 






<section id="map-reprojection" class="level1">
<h1>Map Reprojection</h1>
<p>A recent <a href="https://github.com/r-tmap/tmap/issues/1136">issue on the tmap package</a> reports a white patch appearing at the top of a map rendered in an Albers Equal Area projection. The basemap tiles don’t fill the whole plot area. It’s tempting to call this a tmap bug, but the underlying problem is more general. It affects any tool that needs to compute the geographic footprint of a projected extent: tile-fetching packages, GDAL utilities, raster warping workflows, and vector reprojection. An almost identical issue was <a href="https://github.com/OSGeo/gdal/issues/12100">reported against GDAL’s gdal_translate</a> and <a href="https://gdal.org/en/stable/programs/gdal_translate.html">fixed in GDAL 3.11</a> by densifying the <code>projwin</code> boundary instead of transforming only corner points.</p>
<p>The core question is: when you have a rectangular region in a map, what area does it cover in another map projection? If you only transform the four corners, you get a quadrilateral. But the actual footprint is a curved shape, because straight lines in the projected CRS trace curves through geographic space. For conic projections like Albers, the top edge of the rectangle sweeps a wider arc in longitude than the corners alone suggest. The difference between the four-corner bounding box and the true footprint is the missing area in the map.</p>
<section id="a-picture-of-the-problem" class="level2">
<h2 class="anchored" data-anchor-id="a-picture-of-the-problem">A picture of the problem</h2>
<p>The fix is to <em>densify</em> the boundary of the projected rectangle before transforming it. Add intermediate vertices along each edge, then reproject the resulting polygon, and compute the bounding box of that. The more vertices you add, the better the approximation.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(terra)</span>
<span id="cb1-2">vdsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsizip//vsicurl/https://github.com/user-attachments/files/20692539/AEA_polygon.zip"</span></span>
<span id="cb1-3">v <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vect</span>(vdsn)</span>
<span id="cb1-4"></span>
<span id="cb1-5"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## The extent as a polygon in projected space</span></span>
<span id="cb1-6">box_proj <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.polygons</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(v))</span>
<span id="cb1-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crs</span>(box_proj) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crs</span>(v)</span>
<span id="cb1-8"></span>
<span id="cb1-9"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Transform with sparse corners only</span></span>
<span id="cb1-10">box_ll_sparse <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span>(box_proj, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>)</span>
<span id="cb1-11"></span>
<span id="cb1-12"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Densify first (add vertices every 10 km), then transform</span></span>
<span id="cb1-13">box_dense <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">densify</span>(box_proj, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">interval =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span>)</span>
<span id="cb1-14">box_ll_dense <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span>(box_dense, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>)</span>
<span id="cb1-15"></span>
<span id="cb1-16"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Compare the extents</span></span>
<span id="cb1-17"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(box_ll_sparse)</span>
<span id="cb1-18"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(box_ll_dense)</span>
<span id="cb1-19"></span>
<span id="cb1-20"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Plot them together</span></span>
<span id="cb1-21"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(box_ll_dense, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">border =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"blue"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lwd =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">main =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sparse corners vs. densified boundary"</span>)</span>
<span id="cb1-22"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(box_ll_sparse, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">border =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"red"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lwd =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb1-23"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">legend</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bottomright"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Densified"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sparse (4 corners)"</span>),</span>
<span id="cb1-24">       <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"blue"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"red"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lwd =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span></code></pre></div></div>
<p>The gap between the red quadrilateral and the blue curve is exactly the area that goes missing when software transforms only the corner points.</p>
</section>
<section id="how-this-relates-to-map-tiles" class="level2">
<h2 class="anchored" data-anchor-id="how-this-relates-to-map-tiles">How this relates to map tiles</h2>
<p>Web map tile services (TMS, WMTS, XYZ) serve imagery in tiles at fixed zoom levels, typically in Web Mercator (EPSG:3857). Packages like <a href="https://github.com/riatelab/maptiles">maptiles</a>, <a href="https://github.com/hypertidy/ceramic">ceramic</a>, and <a href="https://github.com/paleolimbot/rosm">rosm</a> do an excellent job of fetching, compositing, and caching these tiles for use in R. Their workflow is roughly: determine the geographic extent needed, request the right tiles at the right zoom level, stitch them, and return a raster in the desired CRS.</p>
<p>The extent determination step is where the densification problem bites. If the user’s map is in a conic projection and the package computes the longlat extent by transforming only the viewport corners, the requested tiles won’t cover the full area.</p>
<p>There is an alternative approach that sidesteps tile-fetching entirely, by treating the tile server as a GDAL data source and using <code>gdalwarp</code> to produce an image directly on a target grid. GDAL’s warper handles extent computation internally via <code>GDALSuggestedWarpOutput()</code>, which densifies the source boundary as part of its calculation. This means the “white patch” problem doesn’t occur.</p>
</section>
<section id="using-gdal-warp-with-a-tile-server" class="level2">
<h2 class="anchored" data-anchor-id="using-gdal-warp-with-a-tile-server">Using GDAL warp with a tile server</h2>
<p>A TMS or WMTS endpoint can be opened by GDAL as a raster data source, given the right connection string. The <code>esri()</code> helper function below constructs a WMTS connection string from an ArcGIS REST service URL:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Helper functions:</span></span>
<span id="cb2-2"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## esri() builds a WMTS connection string from an ArcGIS REST Services URL</span></span>
<span id="cb2-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## fit_dims() computes aspect-ratio-preserving pixel dimensions</span></span>
<span id="cb2-4"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## (fit_dims is available in the hypertidy/vaster package)</span></span>
<span id="cb2-5"></span>
<span id="cb2-6">esri <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(url) {</span>
<span id="cb2-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"WMTS:%s/WMTS/1.0.0/WMTSCapabilities.xml"</span>, url)</span>
<span id="cb2-8">}</span>
<span id="cb2-9"></span>
<span id="cb2-10"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## fit_dims is also available from vaster::fit_dims()</span></span>
<span id="cb2-11">fit_dims <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1024</span>L, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">wh =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(size, size)) {</span>
<span id="cb2-12">  wh <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(wh, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length.out =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>L)</span>
<span id="cb2-13">  w <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> wh[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>L]; h <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> wh[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>L]</span>
<span id="cb2-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.integer</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ceiling</span>(size <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(w, h) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">max</span>(w, h)))</span>
<span id="cb2-15">}</span></code></pre></div></div>
<p>With these in hand, the workflow is:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(terra)</span>
<span id="cb3-2"></span>
<span id="cb3-3">dsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">esri</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">url =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://services.arcgisonline.com/arcgis/rest/services/Ocean/World_Ocean_Base/MapServer"</span>)</span>
<span id="cb3-4">vdsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsizip//vsicurl/https://github.com/user-attachments/files/20692539/AEA_polygon.zip"</span></span>
<span id="cb3-5"></span>
<span id="cb3-6">v <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vect</span>(vdsn)</span>
<span id="cb3-7"></span>
<span id="cb3-8"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Compute pixel dimensions that preserve the aspect ratio of the extent</span></span>
<span id="cb3-9">dm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fit_dims</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1024</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">diff</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.vector</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(v)))[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>L, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>L)])</span>
<span id="cb3-10"></span>
<span id="cb3-11">source <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(dsn)</span>
<span id="cb3-12"></span>
<span id="cb3-13"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Build the target grid: same CRS and extent as the input vector data,</span></span>
<span id="cb3-14"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## with the computed dimensions, and matching number of layers (RGB)</span></span>
<span id="cb3-15">target <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(v), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ncols =</span> dm[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>L], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nrows =</span> dm[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>L],</span>
<span id="cb3-16">               <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crs</span>(v), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nlyr =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nlyr</span>(source))</span>
<span id="cb3-17"></span>
<span id="cb3-18"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Warp the tile server imagery onto the target grid</span></span>
<span id="cb3-19"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## by_util = TRUE calls gdalwarp rather than terra's internal resampler</span></span>
<span id="cb3-20">im <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(dsn), target, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by_util =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb3-21"></span>
<span id="cb3-22"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plotRGB</span>(im)</span>
<span id="cb3-23"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(v, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
<p>The <code>project()</code> call with <code>by_util = TRUE</code> invokes <code>gdalwarp</code> under the hood, which reads tiles from the server as needed to fill the target grid. GDAL computes the correct source extent internally, including the densification step.</p>
<p>A few details worth noting about this code:</p>
<ul>
<li>The <code>nlyr = nlyr(source)</code> argument on the target raster is necessary so that all bands (RGB) are included. Without it, the target would default to a single band.</li>
<li>The <code>by_util = TRUE</code> flag is essential. Without it, <code>project()</code> uses terra’s internal logic driving a lower level part of the GDAL api, which does not automatically target the appropriate resolution level (it will take forever to process pixels that are not needed).</li>
<li>The <code>dsn</code> variable is a WMTS connection string that GDAL opens as a raster source. The same approach works with TMS (XYZ) endpoints, though the connection string format is different (it requires a small XML file or an inline XML specification; a good reference is the <a href="https://gdal.org/en/stable/drivers/raster/wms.html">GDAL TMS driver documentation</a>).</li>
</ul>
</section>
<section id="reprojecting-the-target-grid-definition" class="level2">
<h2 class="anchored" data-anchor-id="reprojecting-the-target-grid-definition">Reprojecting the target grid definition</h2>
<p>If the desired output CRS is different from the input vector CRS, the key insight is to reproject the <em>target grid definition</em>, not the image data. Build the target grid in the source CRS first (where the extent is known), then reproject the empty grid to the desired output CRS. GDAL’s warp step will then fill it correctly.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Build the target in the vector's native CRS</span></span>
<span id="cb4-2">target0 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(v), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ncols =</span> dm[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>L], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nrows =</span> dm[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>L],</span>
<span id="cb4-3">                <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crs</span>(v), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nlyr =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nlyr</span>(source))</span>
<span id="cb4-4"></span>
<span id="cb4-5"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Reproject the empty grid definition to Web Mercator</span></span>
<span id="cb4-6">target <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span>(target0, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3857"</span>)</span>
<span id="cb4-7"></span>
<span id="cb4-8"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Warp the source imagery onto the reprojected target</span></span>
<span id="cb4-9">im <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(dsn), target, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by_util =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb4-10"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plotRGB</span>(im)</span>
<span id="cb4-11"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span>(v, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3857"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
<p>Reprojecting an empty raster grid with <code>project()</code> (or equivalently, <code>gdalwarp</code> on a small raster) computes the appropriate output extent and resolution by densifying the source boundary before transforming. This is a lightweight way to answer the question “what does this extent look like in another CRS?”</p>
</section>
<section id="extent-reprojection-as-a-general-operation" class="level2">
<h2 class="anchored" data-anchor-id="extent-reprojection-as-a-general-operation">Extent reprojection as a general operation</h2>
<p>The task of computing a bounding box in one CRS from a bounding box in another CRS appears in many contexts. Several tools address it:</p>
<ul>
<li><p><code>reproj::reproj_extent()</code> in the <a href="https://hypertidy.github.io/reproj/">reproj</a> package does this directly. It densifies the input extent boundary, transforms the points, and returns the bounding box. The documentation describes it as a simple version of what GDAL’s <code>GDALSuggestedWarpOutput()</code> does.</p></li>
<li><p><code>terra::project()</code> applied to a <code>SpatExtent</code> or an empty <code>SpatRaster</code> achieves the same result, using GDAL internally.</p></li>
<li><p>In sf and stars, <code>sf::st_transform()</code> on an <code>sfc_POLYGON</code> representing the bounding box will reproject the boundary (sf applies segmentization as part of its transformation pipeline when working with s2). <code>st_bbox()</code> of the result gives the target extent.</p></li>
<li><p>In gdalraster, <code>gdalraster::warp()</code> with appropriate <code>-te</code> and <code>-te_srs</code> arguments lets you specify the target extent in a different CRS from the output. The <code>-te_srs</code> option tells <code>gdalwarp</code> to interpret the <code>-te</code> coordinates in the given CRS and transform them (with densification) to the output CRS.</p></li>
<li><p>Similarly, <code>gdal_translate</code> has <code>-projwin_srs</code>, which specifies the CRS of the <code>-projwin</code> coordinates. As of <a href="https://gdal.org/en/stable/programs/gdal_translate.html">GDAL 3.11</a>, the projwin boundary is fully densified before transformation. In earlier versions, only the two corner points were transformed, leading to the same class of error described here.</p></li>
</ul>
<p>All of these ultimately rely on the same principle: you cannot determine the geographic footprint of a projected rectangle from its corners alone. The boundary must be sampled densely enough to capture the curvature of the transformation.</p>
</section>
<section id="the-vector-side-densifying-features" class="level2">
<h2 class="anchored" data-anchor-id="the-vector-side-densifying-features">The vector side: densifying features</h2>
<p>The same issue applies to vector geometries. A polygon or line with sparse vertices in one CRS will have incorrect geometry after reprojection if the segments are long relative to the curvature of the transformation. This is not about datum shifts or projection accuracy at individual points — point reprojection is exact. It is about the fact that a straight line segment in one CRS is not, in general, a straight line in another.</p>
<p>Consider a coastline polygon with vertices every 100 km, stored in an Albers Equal Area CRS. Those long straight edges are reasonable approximations of the coastline <em>in that projection</em>. But when reprojected to longitude/latitude, each straight edge should trace a curve through geographic space. Without densification, the reprojected polygon connects the transformed endpoints with straight lines in the target CRS, which follow different paths than the original segments.</p>
<p><code>sf::st_segmentize()</code> and <code>terra::densify()</code> add intermediate vertices along existing edges. The critical point is that this must happen <em>before</em> reprojection, in the source CRS, so that the added vertices capture the geometry as it was defined. After reprojection, the denser vertex set produces a polygon that faithfully represents the original shape in the new CRS.</p>
<p>Neither sf nor terra applies densification automatically during reprojection. It is the caller’s responsibility to decide whether it is needed and to choose an appropriate segment length. For small-area, high-resolution data the effect is negligible, but for continental extents or coarse geometries it can be significant.</p>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>The white patch in the tmap basemap, the missing data in <code>gdal_translate -projwin_srs</code> before GDAL 3.11, and the distortion of coarse polygons after reprojection are all the same problem. A rectangular extent in a projected CRS is not a rectangle in geographic coordinates. The boundary curves, and capturing that curvature requires sampling it with enough points.</p>
<p>This applies whenever software needs to answer the question “what geographic area does this projected region cover?” The answer is to densify before transforming — whether the input is a viewport boundary for fetching tiles, a bounding box for subsetting, or the edges of a polygon for display.</p>
<p>The GDAL warp approach to tile servers avoids the problem for raster imagery by letting GDAL handle extent computation internally. For vector data, <code>st_segmentize()</code> or <code>densify()</code> should be part of any reprojection workflow involving coarse geometries.</p>
<p>Code and helper functions used in this post are available at <a href="https://gist.github.com/mdsumner/264b80cae0bb1e72d93b22b6edd19a27">this gist</a>.</p>
<hr>
<p><em>Possible future additions: equivalent workflows using sf::gdal_utils(), gdalraster::warp(), and vapour::vapour_warp_raster() to show the same operations without terra.</em></p>


</section>
</section>

 ]]></description>
  <category>code</category>
  <category>projections</category>
  <category>maps</category>
  <category>spatial</category>
  <guid>https://hypertidy.org/posts/2026-02-20_map-extent-projection/</guid>
  <pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Detecting hidden grids in curvilinear coordinates</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2026-02-07_cryptic-curvilinear-detection/cryptic-curvilinear.html</link>
  <description><![CDATA[ 






<section id="the-problem" class="level2">
<h2 class="anchored" data-anchor-id="the-problem">The problem</h2>
<p>A lot of gridded data arrives with two-dimensional longitude and latitude arrays: one value per pixel, stored explicitly. This is the standard representation for curvilinear grids in NetCDF and HDF — satellite swaths, model output on rotated grids, polar data. The coordinates describe the geographic location of every cell, and in many cases they genuinely need to: the grid may be irregular, oblique, or follow a sensor’s scan geometry.</p>
<p>But sometimes those coordinates are hiding something. The data was originally produced on a regular projected grid — polar stereographic, Lambert conformal conic, Mercator — and at some point in the processing chain the projection was discarded and replaced with lon/lat arrays computed from it. The regularity is gone. The CRS is gone. What was four numbers and a coordinate reference system is now two arrays of floating-point values, one per pixel, carrying no more information than the originals but consuming orders of magnitude more storage and, critically, obscuring the actual structure of the data.</p>
<p>This is an entropy problem. A 316×332 grid in EPSG:3412 at 25 km resolution is fully specified by a CRS string and four extent values. Storing lon/lat arrays for every pixel replaces those with 209,824 coordinate values — a 52,000:1 expansion — and the extra values are <em>noisier</em> than the originals because they’ve accumulated floating-point error from the forward projection.</p>
<p>It would be useful to be able to detect this automatically.</p>
</section>
<section id="detecting-regularity" class="level2">
<h2 class="anchored" data-anchor-id="detecting-regularity">Detecting regularity</h2>
<p>The in-development R package <a href="https://github.com/mdsumner/gproj">gproj</a> includes tools for characterising coordinate geometry and selecting appropriate projections. Among these is a regularity detection pipeline that can identify “cryptic curvilinear” grids — data that presents as irregular lon/lat arrays but is in fact a regular projected grid with lost metadata.</p>
<p>The approach is layered.</p>
<section id="step-1-is-it-rectilinear-in-lonlat" class="level3">
<h3 class="anchored" data-anchor-id="step-1-is-it-rectilinear-in-lonlat">Step 1: Is it rectilinear in lon/lat?</h3>
<p>The simplest hidden structure is a rectilinear grid: longitude varies only along one axis, latitude only along the other. This is tested by checking the standard deviation of each coordinate along each matrix dimension.</p>
<p><code>detect_rectilinear()</code> classifies these into subtypes. If both marginal sequences have uniform spacing, it’s a regular lon/lat grid. If longitude is uniform but latitude spacing follows the Mercator y-formula — <code>y = ln(tan(π/4 + φ/2))</code> — then it’s a Mercator grid that was “devolved” to lon/lat.</p>
<p>Running this on an AVISO altimetry product with 1080×915 lon/lat arrays:</p>
<pre><code>Rectilinear:        TRUE
Type:               mercator_devolved
Lon regular:        TRUE (0.3333° spacing)
Mercator test:      TRUE (max deviation: 1e-12)
Mercator resolution: 37106 m</code></pre>
<p>The deviation from perfect Mercator spacing is at machine epsilon — the coordinates were computed analytically. The 1,976,400 stored values can be replaced by a CRS and an extent.</p>
</section>
<section id="step-2-is-it-regular-in-a-projected-crs" class="level3">
<h3 class="anchored" data-anchor-id="step-2-is-it-regular-in-a-projected-crs">Step 2: Is it regular in a projected CRS?</h3>
<p>When the grid isn’t rectilinear in lon/lat, it may be regular in some projected coordinate system. The test:</p>
<ol type="1">
<li>Characterise the data geometry — centre, extent, hemisphere — to select candidate projections.</li>
<li>Project the lon/lat arrays into each candidate CRS.</li>
<li>Check whether the projected coordinates form a regular grid: constant spacing along rows and columns, with rows horizontal in projected space.</li>
</ol>
<p>The <code>params()</code> function in gproj computes a geometric characterisation from any set of lon/lat coordinates:</p>
<pre><code>&lt;params: 104912 points&gt;
  centre:     -0.0000, -88.1448
  extent:     [0.17, 359.84] x [-89.84, -39.36]
  span:       359.67° lon x 50.47° lat
  hemisphere: polar_south
  aspect:     wide
  axis:       azimuth=180.0°, tilt=90.0°, var_ratio=0.51/0.46/0.02</code></pre>
<p>This is a CryoSat-2 sea ice product distributed as a NetCDF file with 316×332 lon/lat arrays. The <code>params()</code> output immediately tells us it’s circumpolar Antarctic data with no dominant axis orientation (variance split evenly between two components — characteristic of polar data rather than an elongated swath).</p>
<p>Projecting the coordinates into EPSG:3412 (NSIDC Sea Ice Polar Stereographic South) and testing regularity:</p>
<pre><code>Max row-y SD:      13.42 m
Median dx:         25000 m
Max dx deviation:  74.8 m
Median dy:         -25000 m
Max dy deviation:  71.0 m</code></pre>
<p>Row-level y standard deviation of 13 metres on a 25 km grid means rows are horizontal to within 0.05% of a cell width. The x and y spacing deviations of ~70 m (0.3%) are the accumulated floating-point noise from the trig functions in the lon/lat → projection → lon/lat → projection roundtrip.</p>
<p>These numbers are unambiguous. A genuinely curvilinear grid would show deviations of 10–100% of the cell size. The gap between 0.3% and “not regular” is enormous.</p>
</section>
<section id="step-3-recover-the-grid-specification" class="level3">
<h3 class="anchored" data-anchor-id="step-3-recover-the-grid-specification">Step 3: Recover the grid specification</h3>
<p>Once regularity is confirmed, the resolution is snapped to the nearest “round” value (25000 rather than 24999.7) and the extent is recovered from the cell centres plus half-cell margins:</p>
<pre><code>Recovered extent:  -3950030  3950000  -3949995  4349967
Known NSIDC extent: -3950000  3950000  -3950000  4350000
Difference:         -30       0        5        -33</code></pre>
<p>Within 33 metres of the exact grid specification. The extent values snap to exact multiples of the resolution, completing the reconstruction:</p>
<pre><code>CRS:          EPSG:3412
Resolution:   25000 × 25000 m
Dimensions:   316 × 332
Extent:       -3950000  3950000  -3950000  4350000</code></pre>
<p>The 209,824 coordinate values have been replaced by four numbers and a CRS string. The reconstructed grid is not an approximation — it is the original grid, recovered (near enough to) exactly.</p>
</section>
</section>
<section id="the-mercator-case" class="level2">
<h2 class="anchored" data-anchor-id="the-mercator-case">The Mercator case</h2>
<p>A subtler variant of this problem occurs with global ocean products. A Mercator projection produces a regular grid in eastings and northings, but when projected to lon/lat the latitude spacing becomes non-uniform: cells are compressed toward the poles following the inverse Mercator formula. The longitude spacing remains uniform.</p>
<p>This is easy to miss because the grid <em>looks</em> rectilinear — it has separable 1D coordinate axes — and many tools will happily treat it as a lon/lat grid with variable spacing. But it’s not: it’s a Mercator grid with specific metric properties that are lost when treated as plain lon/lat.</p>
<p>The detection is straightforward: convert the latitude values to Mercator y-coordinates and check whether the spacing becomes uniform. For the AVISO product tested above, the deviation from perfect Mercator spacing is 10⁻¹² — indistinguishable from the analytical formula.</p>
</section>
<section id="swath-geometry-and-projection-selection" class="level2">
<h2 class="anchored" data-anchor-id="swath-geometry-and-projection-selection">Swath geometry and projection selection</h2>
<p>Not all lon/lat arrays hide regular grids. Satellite swath data from sensors like VIIRS or MODIS is genuinely curvilinear — the coordinates follow the sensor’s scan geometry, and there is no single projected CRS that makes them regular. But the coordinates still have structure that can be exploited.</p>
<p>The <code>params()</code> function characterises this structure using PCA on the 3D Cartesian coordinates of the data points. Converting lon/lat to points on the unit sphere before PCA avoids the distortions that would arise from operating directly in longitude/latitude space (particularly near the poles or antimeridian).</p>
<p>For a VIIRS swath boundary:</p>
<pre><code>&lt;params: 32436 points&gt;
  centre:     -113.56, -20.81
  extent:     [-180, 180] x [-84.44, 57.66]
  hemisphere: polar_south
  axis:       azimuth=12.4°, tilt=77.6°, var_ratio=0.85/0.14/0.02</code></pre>
<p>The variance ratio of 0.85 in the first component indicates a strongly elongated dataset. The azimuth of 12.4° gives the bearing of the dominant axis — essentially the satellite ground track orientation.</p>
<p>This feeds directly into projection selection. The <code>proj()</code> function uses the geometric characterisation to generate appropriate CRS parameters:</p>
<ul>
<li>Polar data with no dominant axis → stereographic or Lambert azimuthal equal-area, centred on the pole</li>
<li>Elongated data with a dominant axis → oblique Mercator aligned to the data’s axis</li>
<li>Mid-latitude wide bands → conic projections with secant latitudes derived from the data extent</li>
<li>Small regions → stereographic centred on the data</li>
</ul>
<p>For the VIIRS swath, this produces an oblique Mercator projection aligned to the 12.4° ground track, which straightens the swath into a narrow strip in projected coordinates (aspect ratio ~11:1).</p>
</section>
<section id="the-opportunity" class="level2">
<h2 class="anchored" data-anchor-id="the-opportunity">The opportunity</h2>
<p>The detection of hidden regular grids is not a theoretical exercise. These grids exist throughout operational data archives — sea ice products, ocean altimetry, atmospheric reanalyses, satellite imagery. Every file that stores redundant lon/lat arrays for a regular projected grid is:</p>
<ul>
<li>Wasting storage (often 2× the data volume for the coordinate arrays alone)</li>
<li>Losing precision (floating-point coordinates are noisier than the exact grid specification)</li>
<li>Obscuring structure (downstream tools treat the data as irregular, triggering unnecessary resampling)</li>
<li>Creating friction (users must discover the projection through external documentation or domain expertise)</li>
</ul>
<p>The regularity test demonstrated here is simple — a few lines of linear algebra and some tolerance checks — and could be applied routinely during data ingest or quality assessment. The tolerance gap between “regular with floating-point noise” (0.3% deviation) and “genuinely irregular” is wide enough that false positives are unlikely.</p>
<p>For data producers, the message is: if your data is on a regular projected grid, store the grid specification, not the coordinates. A CRS string and four extent values are complete, exact, and universally understood.</p>
<p>For data consumers and tool developers, the message is: when you encounter 2D lon/lat arrays, test for regularity before treating them as curvilinear. The answer may save you considerable complexity.</p>
<p>The gproj package is in early development at <a href="https://github.com/mdsumner/gproj">github.com/mdsumner/gproj</a>.</p>
<p>A previous iteration of this discussion was published here <a href="https://www.hypertidy.org/posts/2025-09-04_broken-netcdf/#throw-all-that-away-ignore-everything-above.">hypertidy.org: Coordinates broken in NetCDF</a>.</p>


</section>

 ]]></description>
  <category>gdal</category>
  <category>raster</category>
  <category>netcdf</category>
  <category>projections</category>
  <guid>https://hypertidy.org/posts/2026-02-07_cryptic-curvilinear-detection/cryptic-curvilinear.html</guid>
  <pubDate>Sat, 07 Feb 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Raster logic without pixels</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2025-12-21_vaster-grid-logic/vaster-grid-logic.html</link>
  <description><![CDATA[ 






<section id="raster-logic-is-in-our-software" class="level2">
<h2 class="anchored" data-anchor-id="raster-logic-is-in-our-software">Raster logic is in our software</h2>
<p>Every geospatial package that works with grids has <em>raster logic</em> inside. The old {raster} package in R established powerful abstraction functions and now {terra} includes an improved suite of those, the {stars} package has its own internally, GDAL obviously uses these abstractions deeply, and xarray and many other Python packages also provide this. There is similar logic built into R’s matrix and array functions, its visualization <code>image()</code> function, and the newer <code>rasterImage()</code>.</p>
<p>Is there a problem? This logic is almost always coupled to a data structure. You can’t use raster’s <code>cellFromXY()</code> without a RasterLayer. You can’t use terra’s <code>xyFromCell()</code> or <code>cells()</code> without a SpatRaster. Many packages have embedded this reinvented wheel, and to more or less degree lock the wheel inside a bigger machine.</p>
<p>The logic itself is beautifully simple: given a grid with certain dimensions (ncol, nrow) and a spatial extent (xmin, xmax, ymin, ymax, or identically ‘bbox’ xmin,ymin,xmax,ymax), you can compute everything else. Cell indices, row/column positions, coordinate centres and corners, cropping and snapping—all of it flows from six numbers and some basic arithmetic.</p>
<p>That’s what <a href="https://hypertidy.github.io/vaster/">{vaster}</a> extracts: the logic alone, without any data. (This logic of course is not especially 2D and extends into n-dimensional concepts as well illustrated by xarray and others, but please let’s park that from our discussion here.)</p>
</section>
<section id="r-already-knows-this-sort-of" class="level2">
<h2 class="anchored" data-anchor-id="r-already-knows-this-sort-of">R already knows this (sort of)</h2>
<p>R’s base graphics already embody two distinct models for placing gridded data in space.</p>
<section id="the-image-model-rectilinear-coordinates" class="level3">
<h3 class="anchored" data-anchor-id="the-image-model-rectilinear-coordinates">The <code>image()</code> model: rectilinear coordinates</h3>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1">m <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> volcano[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>]</span>
<span id="cb1-2">x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length.out =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nrow</span>(m) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-3">y <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length.out =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ncol</span>(m) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-4"></span>
<span id="cb1-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">image</span>(x, y, m, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">terrain.colors</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-12-21_vaster-grid-logic/vaster-grid-logic_files/figure-html/image-model-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>The <code>image()</code> function takes explicit coordinate vectors for cell boundaries. This is the <em>rectilinear</em> model—you define where every edge falls. It’s flexible (cells don’t need to be square, or even uniform), but it means carrying around those vectors.</p>
<p>Notice <code>x</code> has <code>nrow(m) + 1</code> elements, and <code>y</code> has <code>ncol(m) + 1</code>. These are <em>edge</em> coordinates, not centres. The function figures out that a 10×15 matrix needs 11×16 edges. (Centres are also a valid input for <code>image()</code>, it quietly handles either case of ‘n’ or ‘n+1’, note this has implications for interpretation of a grid but that takes us away from the main topic here).</p>
</section>
<section id="the-rasterimage-model-bounding-box-placement" class="level3">
<h3 class="anchored" data-anchor-id="the-rasterimage-model-bounding-box-placement">The <code>rasterImage()</code> model: bounding box placement</h3>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(<span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xlim =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ylim =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">asp =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xlab =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"x"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ylab =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"y"</span>)</span>
<span id="cb2-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rasterImage</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.raster</span>(scales<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rescale</span>(m)), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xleft =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ybottom =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xright =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ytop =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">interpolate =</span> F)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-12-21_vaster-grid-logic/vaster-grid-logic_files/figure-html/rasterImage-model-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>The <code>rasterImage()</code> function takes a different approach: you hand it an image and four numbers defining the bounding box. The function stretches or compresses the image to fit. This is the <em>affine</em> model—the grid is implicitly regular within the box.</p>
<p>These two models are part of a foundation of all raster handling. GeoTIFFs use the affine model (extent + dimension → implicit coordinates). NetCDF often uses the rectilinear model (explicit coordinate arrays). Both are valid; both are useful; both involve the same underlying logic.</p>
</section>
<section id="ximage-unifying-both-models" class="level3">
<h3 class="anchored" data-anchor-id="ximage-unifying-both-models">{ximage}: unifying both models</h3>
<p>There’s a sort of frustration in base with <code>image()</code> and <code>rasterImage()</code>, each has features the other lacks. <code>image()</code> handles numeric data with colour palettes and is geared to R’s matrix orientation, can create a plot or add to an existing one, but by default will draw into a unit square. <code>rasterImage()</code> handles the orientation more aligned to external raster data and graphics, but only works with unit-scaled data or pre-rendered images—no palette mapping, and no plot creation (only adding to an existing plot) .</p>
<p><a href="https://github.com/hypertidy/ximage">ximage</a> merges the features of both into one function that uses the rasterImage orientation:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ximage)</span>
<span id="cb3-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(vaster)</span>
<span id="cb3-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Plot numeric data in GIS orientation with extent</span></span>
<span id="cb3-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ximage</span>(volcano, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extent =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">61</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">87</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">terrain.colors</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">24</span>))</span>
<span id="cb3-5"></span>
<span id="cb3-6"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Add contours that respect the same extent</span></span>
<span id="cb3-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xcontour</span>(volcano, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extent =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">61</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">87</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">levels =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">120</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">140</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">160</span>))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-12-21_vaster-grid-logic/vaster-grid-logic_files/figure-html/ximage-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Or RGB arrays, or nativeRaster, or hex colours—all work</span></span>
<span id="cb4-2">img <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> png<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">readPNG</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.file</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"img"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Rlogo.png"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">package=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"png"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">native =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb4-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ximage</span>(img, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extent =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">160</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>))</span>
<span id="cb4-4">maps<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)  </span>
<span id="cb4-5"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## nonsensical map, but we can do what we want and maps why not</span></span>
<span id="cb4-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># they can be fun and used with non spatial data too</span></span>
<span id="cb4-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ximage</span>(img, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extent =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">152</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">158</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">44</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb4-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_extent</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">152</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">158</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">44</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">border =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"firebrick"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lwd =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-12-21_vaster-grid-logic/vaster-grid-logic_files/figure-html/ximage-2.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Once we separate the <em>data</em> (a matrix of values) from the <em>placement</em> (extent as four numbers), you can handle any input type with the same logic. The orientation confusion disappears because {ximage} adopts the rasterImage convention—the one that matches how GDAL and every other geospatial tool returns data.</p>
<p>This is {vaster}’s philosophy applied to plotting: the spatial meaning comes from the six numbers (dimension + extent), not from the data structure.</p>
</section>
</section>
<section id="what-vaster-provides" class="level2">
<h2 class="anchored" data-anchor-id="what-vaster-provides">What vaster provides</h2>
<p>{vaster} gives that underlying logic with no attachment to any data format or structure. All you need are dimension and extent (and extent is optional, a sensible default is [0,nx], [0,ny] rather than unit-square).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(vaster)</span>
<span id="cb5-2"></span>
<span id="cb5-3">dm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ncol, nrow</span></span>
<span id="cb5-4">ex <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">160</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># xmin, xmax, ymin, ymax</span></span>
<span id="cb5-5"></span>
<span id="cb5-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Cell centres - implicit from dimension and extent</span></span>
<span id="cb5-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">x_centre</span>(dm, ex)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] 100.75 102.25 103.75 105.25 106.75 108.25 109.75 111.25 112.75 114.25
[11] 115.75 117.25 118.75 120.25 121.75 123.25 124.75 126.25 127.75 129.25
[21] 130.75 132.25 133.75 135.25 136.75 138.25 139.75 141.25 142.75 144.25
[31] 145.75 147.25 148.75 150.25 151.75 153.25 154.75 156.25 157.75 159.25</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">y_centre</span>(dm, ex)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] -49 -47 -45 -43 -41 -39 -37 -35 -33 -31 -29 -27 -25 -23 -21 -19 -17 -15 -13
[20] -11</code></pre>
</div>
</div>
<p>What cell contains a given point?</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Some arbitrary coordinates</span></span>
<span id="cb9-2">pts <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">120.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">145.2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">110.8</span>), </span>
<span id="cb9-3">             <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">25.3</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">42.1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">15.7</span>))</span>
<span id="cb9-4"></span>
<span id="cb9-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_from_xy</span>(dm, ex, pts)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 294 671  88</code></pre>
</div>
</div>
<p>What are the coordinates of cells 1, 100, and 800?</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xy_from_cell</span>(dm, ex, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">800</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>       [,1] [,2]
[1,] 100.75  -11
[2,] 129.25  -15
[3,] 159.25  -49</code></pre>
</div>
</div>
<p>Convert between row/column and cell index:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Cell to row, column</span></span>
<span id="cb13-2">cell <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span></span>
<span id="cb13-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">row_from_cell</span>(dm, cell)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 2</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">col_from_cell</span>(dm, cell)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 2</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb17-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Row, column to cell</span></span>
<span id="cb17-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cell_from_row_col</span>(dm, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">row =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 95</code></pre>
</div>
</div>
<p>None of this requires loading imagery or touching files. It’s pure computation from first principles.</p>
<p>Note here that indexing is via R’s convention: 1-based, both for cell and row and col.</p>
</section>
<section id="the-snap-problem" class="level2">
<h2 class="anchored" data-anchor-id="the-snap-problem">The snap problem</h2>
<p>One of the most common operations in raster work is “snapping”—taking an arbitrary region and aligning it to an existing grid. You want to crop to an area of interest, but you need cell-aligned boundaries.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb19-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># A reference grid: 3-degree cells covering the globe</span></span>
<span id="cb19-2">ref_dm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb19-3">ref_ex <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>)</span>
<span id="cb19-4"></span>
<span id="cb19-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Some arbitrary region of interest (not aligned to anything)</span></span>
<span id="cb19-6">roi <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">154.7</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">44.2</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">9.8</span>)</span>
<span id="cb19-7"></span>
<span id="cb19-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Snap to the reference grid</span></span>
<span id="cb19-9">snapped <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vcrop</span>(roi, ref_dm, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extent =</span> ref_ex)</span>
<span id="cb19-10">snapped</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>$extent
[1]  12 156 -54   0

$dimension
[1] 12  3</code></pre>
</div>
</div>
<p>The result gives you the exact dimension and extent for the crop window, aligned to the reference grid. No data needed—just the numbers.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb21-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_extent</span>(ref_ex, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">border =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey"</span>)</span>
<span id="cb21-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">v =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">x_corner</span>(ref_dm, ref_ex), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>)</span>
<span id="cb21-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">h =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">y_corner</span>(ref_dm, ref_ex), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grey90"</span>)</span>
<span id="cb21-4"></span>
<span id="cb21-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Original ROI (arbitrary)</span></span>
<span id="cb21-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_extent</span>(roi, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">border =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"red"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lwd =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb21-7"></span>
<span id="cb21-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Snapped ROI (grid-aligned)</span></span>
<span id="cb21-9"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_extent</span>(snapped<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>extent, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">border =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"blue"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lwd =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-12-21_vaster-grid-logic/vaster-grid-logic_files/figure-html/snap-plot-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>The red box is what we asked for; the blue box is what we get when we respect the grid alignment.</p>
</section>
<section id="the-geotransform-connection" class="level2">
<h2 class="anchored" data-anchor-id="the-geotransform-connection">The geotransform connection</h2>
<p>GDAL uses a six-element “geotransform” to encode the affine relationship between pixel coordinates and geographic coordinates. This is the workhorse of georeferenced raster data. {vaster} speaks this language:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb22-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># From extent and dimension to geotransform</span></span>
<span id="cb22-2">gt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">extent_dim_to_gt</span>(ex, dm)</span>
<span id="cb22-3">gt</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> xmin  xres yskew  ymax xskew  yres 
100.0   1.5   0.0 -10.0   0.0  -2.0 </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb24-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># And back again</span></span>
<span id="cb24-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gt_dim_to_extent</span>(gt, dm)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>xmin xmin ymax ymax 
 100  160  -50  -10 </code></pre>
</div>
</div>
<p>This matters when you’re working directly with GDAL (via {gdalraster}, {vapour}, or Python’s osgeo.gdal) and need to set up or interpret raster metadata without constructing heavyweight objects.</p>
</section>
<section id="why-does-this-matter" class="level2">
<h2 class="anchored" data-anchor-id="why-does-this-matter">Why does this matter?</h2>
<ol type="1">
<li><p><strong>Lightweight tooling</strong>: Sometimes we just need to compute cell indices or snap extents. We shouldn’t need to load terra or GDAL for that.</p></li>
<li><p><strong>Cross-package compatibility</strong>: The logic is the same whether you’re working with terra, stars, GDAL, or raw arrays. Having it in one place means consistent behaviour everywhere.</p></li>
<li><p><strong>Teaching and understanding</strong>: Separating the logic from the data makes it clearer what raster operations actually <em>do</em>. The magic isn’t in the file format or the object class—it’s in the relationship between dimension and extent.</p></li>
</ol>
</section>
<section id="the-ecosystem-what-you-can-build-with-pure-logic" class="level2">
<h2 class="anchored" data-anchor-id="the-ecosystem-what-you-can-build-with-pure-logic">The ecosystem: what you can build with pure logic</h2>
<p>Once you separate grid logic from data, interesting things become possible. Here are three packages that build on this foundation, taken (ahem) shamelessly from the hypertidy suite. (I’m not ignoring other important packages in R and Python that use these ideas, but these are chosen to focus on the core idea of what vaster is and why it exists. )</p>
<section id="fasterize-fast-polygon-rasterization" class="level3">
<h3 class="anchored" data-anchor-id="fasterize-fast-polygon-rasterization">{fasterize}: fast polygon rasterization</h3>
<p><a href="https://github.com/hypertidy/fasterize">fasterize</a> is a high-performance replacement for <code>raster::rasterize()</code>. It uses the classic scanline algorithm to burn polygons onto a grid. The original fasterize required an actual RasterLayer as a template—not for its data, but for its six numbers (dimension and extent).</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb26" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb26-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## fasterize needs a "raster", but really it just needs dimension + extent</span></span>
<span id="cb26-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(fasterize)</span>
<span id="cb26-3">r <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> raster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">raster</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ncol =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nrow =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">800</span>, </span>
<span id="cb26-4">                    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xmn =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xmx =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ymn =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ymx =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">80</span>)</span>
<span id="cb26-5">result <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fasterize</span>(polygons_sf, r, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">field =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"value"</span>)</span></code></pre></div></div>
<p>The raster object is just a vessel for grid metadata, but fasterize also will create an actual numeric matrix in memory - so it has these two limitations at input and output. With raster logic available separately, we can drive the same algorithm with nothing but numbers.</p>
</section>
<section id="controlledburn-dont-materialize-just-rasterize" class="level3">
<h3 class="anchored" data-anchor-id="controlledburn-dont-materialize-just-rasterize">{controlledburn}: don’t materialize, just rasterize</h3>
<p><a href="https://github.com/hypertidy/controlledburn">controlledburn</a> takes the fasterize algorithm and strips away the last step: instead of filling a raster with values, it returns the <em>indices</em> of which cells each polygon covers. The output is run-length encoded scanline segments—start, end, row, polygon_id.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb27-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(controlledburn)</span>
<span id="cb27-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(vaster)</span>
<span id="cb27-3"></span>
<span id="cb27-4"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Define a grid with just numbers</span></span>
<span id="cb27-5">ext <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">160</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb27-6">dm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>)</span>
<span id="cb27-7"></span>
<span id="cb27-8"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Get the cell coverage index, not pixel values</span></span>
<span id="cb27-9">idx <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">burn_polygon</span>(polygons_sf, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extent =</span> ext, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dimension =</span> dm)</span></code></pre></div></div>
<p>For a 500,000 × 400,000 grid, materializing a raster would require terabytes. But storing the polygon coverage as run-length scanline indices? Tens of megabytes for typical distributions that real world polygons embody. The grid logic is the same—only the output changes.</p>
<p>This is the “cell abstraction” always implicit in raster operations. We can use these indices for extraction, for streaming aggregation, for anything that doesn’t require all pixels to exist at once.</p>
</section>
<section id="grout-tiling-without-tiles" class="level3">
<h3 class="anchored" data-anchor-id="grout-tiling-without-tiles">{grout}: tiling without tiles</h3>
<p><a href="https://github.com/hypertidy/grout">grout</a> applies the same principle to tiling. Given a grid’s dimension and extent, plus a block size, it computes the complete tiling scheme: how many tiles, where each one falls, how much overlap (“dangle”) occurs when dimensions don’t divide evenly.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb28" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb28-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(grout)</span>
<span id="cb28-2"></span>
<span id="cb28-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## A raster that's 87 × 61 with 8 × 8 tiles</span></span>
<span id="cb28-4">scheme <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grout</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">87</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">61</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extent =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">87</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">61</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">blocksize =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>))</span>
<span id="cb28-5">scheme</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>          tiles: 4, 11 (x * y = 44)
          block: 8, 16 
         dangle: 1, 3 
tile resolution: 8, 16 
    tile extent: 0, 88, -3, 61 (xmin,xmax,ymin,ymax)
          grain: 8, 16 (8 : x, 16 : y)</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb30" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb30-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## Get offset/size for each tile (for GDAL RasterIO)</span></span>
<span id="cb30-2">dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glimpse</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tile_index</span>(scheme))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Rows: 44
Columns: 11
$ tile     &lt;int&gt; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18…
$ offset_x &lt;dbl&gt; 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 0, 8, 16, 24, 32, 4…
$ offset_y &lt;dbl&gt; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, …
$ tile_col &lt;dbl&gt; 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 2, 3, 4, 5, 6, 7, 8, 9,…
$ tile_row &lt;dbl&gt; 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ ncol     &lt;dbl&gt; 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8…
$ nrow     &lt;dbl&gt; 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 1…
$ xmin     &lt;dbl&gt; 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 0, 8, 16, 24, 32, 4…
$ xmax     &lt;dbl&gt; 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 8, 16, 24, 32, 40,…
$ ymin     &lt;dbl&gt; 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 29, 29, 29, 29, 2…
$ ymax     &lt;dbl&gt; 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 45, 45, 45, 45, 4…</code></pre>
</div>
</div>
<p>No data loaded. No files opened. Just the arithmetic of how a grid subdivides. This is exactly what you need to drive tiled reading from GDAL, or to generate web map tile pyramids, or to parallelize processing across spatial chunks.</p>
</section>
<section id="the-common-thread" class="level3">
<h3 class="anchored" data-anchor-id="the-common-thread">The common thread</h3>
<p>All three packages share a design principle: <strong>the grid specification is just six numbers, and most operations don’t need anything else</strong>.</p>
<p>{fasterize} showed that fast rasterization doesn’t need heavy objects—just geometry and grid metadata. {controlledburn} showed you don’t even need to materialize pixels—indices are enough. {grout} showed that tiling is pure arithmetic on dimension and extent.</p>
<p>{vaster} is the foundation that makes this all clean. Instead of each package reinventing <code>cellFromXY()</code> and friends, they can share a common vocabulary for grid logic.</p>
</section>
</section>
<section id="python-has-a-similar-mix-of-history-concepts-and-tools" class="level2">
<h2 class="anchored" data-anchor-id="python-has-a-similar-mix-of-history-concepts-and-tools">Python has a similar mix of history, concepts, and tools</h2>
<p>The Python geospatial ecosystem has grappled with the same issues that motivated {vaster}.</p>
<p>A <a href="https://discourse.pangeo.io/t/comparing-odc-stac-load-and-stackstac-for-raster-composite-workflow/4097">recent pangeo discussion</a> compared <code>odc.stac</code> and <code>stackstac</code>—two packages for loading satellite imagery into xarray. Despite ostensibly doing the same thing, they produce different results. Why?</p>
<p><strong>Pixel coordinates: edge or centre?</strong> When you say a pixel is at coordinate (100.0, 200.0), do you mean that’s its centre, or its top-left corner? <code>odc.stac</code> defaults to centre, <code>stackstac</code> defaults to edge. Both are valid conventions; GIS tools tend toward corners, while climate/ocean data tends toward centres. But if you don’t know which convention your tool uses, your data shifts by half a pixel.</p>
<p><strong>Coordinate snapping</strong>: When your requested bounding box doesn’t align perfectly with the source grid, what happens? Different tools make different choices about how to snap—and those choices are usually invisible, buried in the library internals.</p>
<p>These are exactly the questions {vaster} makes explicit. Dimension and extent. Corner or centre. Snap in or snap out. The logic is universal; only the defaults vary.</p>
<section id="xarrays-new-rasterindex" class="level3">
<h3 class="anchored" data-anchor-id="xarrays-new-rasterindex">xarray’s new RasterIndex</h3>
<p>The xarray team recently <a href="https://xarray.dev/blog/flexible-indexing">announced flexible indexing</a>, including a <code>RasterIndex</code> that computes coordinates on-the-fly from an affine transform rather than storing explicit coordinate arrays. Sound familiar?</p>
<p>From the post:</p>
<blockquote class="blockquote">
<p>For 2D raster images, this function often takes the form of an Affine Transform. The rasterix library extends Xarray with a RasterIndex which computes coordinates for geospatial images such as GeoTiffs via Affine Transform.</p>
</blockquote>
<p>This is the same insight: <strong>coordinates are implicit in dimension and extent</strong>. You don’t need to materialize a 7-terabyte coordinate array when six numbers suffice. The xarray team is building infrastructure for raster grid logic itself.</p>
<p>The Python ecosystem will align around this conceptual foundation—grid logic as well as R and other language.</p>
</section>
</section>
<section id="the-r-matrix-connection" class="level2">
<h2 class="anchored" data-anchor-id="the-r-matrix-connection">The R matrix connection</h2>
<p>R’s matrices already have most of this logic, just without the spatial semantics. A matrix has dimension (nrow, ncol). When you use <code>image()</code> with explicit coordinates, you’re adding extent. The <code>[i, j]</code> indexing is cell-from-row-column. <code>which(m &gt; threshold, arr.ind = TRUE)</code> gives you row-column-from-cell.</p>
<p>{vaster} makes this connection explicit. It treats dimension and extent as first-class inputs, just as R treats matrices as first-class objects. The spatial meaning is in the numbers, not the container.</p>
</section>
<section id="example-raster-logic-is-a-simplifying-principle" class="level2">
<h2 class="anchored" data-anchor-id="example-raster-logic-is-a-simplifying-principle">Example: raster logic is a simplifying principle</h2>
<p>Enough theory! Let’s make a map. The following string defines a huge world-coverage image server.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb32" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb32-1">dsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"WMTS:https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/WMTS/1.0.0/WMTSCapabilities.xml,layer=World_Imagery"</span></span></code></pre></div></div>
</div>
<p>So, obviously we need a huge stack of Python geospatial to make a map image … or maybe we can just use generic tools and do it in R.</p>
<p>We’re using {gdalraster} here because it’s the thinnest wrapper over the GDAL API, but the same calls work through {terra}, {vapour}, or Python’s osgeo.gdal. The point isn’t the package — it’s that the interface is just numbers and strings. I’m still using a mix of tools and plotting … but that’s life.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb33" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb33-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(gdalraster)</span>
<span id="cb33-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ximage)</span>
<span id="cb33-3">ds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">new</span>(GDALRaster, dsn)  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## same as terra::rast(dsn) or osgeo.gdal.Open(dsn) or rioxarray.open_rasterio(dsn)</span></span>
<span id="cb33-4">ds</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>C++ object of class GDALRaster
 Driver : OGC Web Map Tile Service (WMTS)
 DSN    : WMTS:https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/WMTS/1.0.0/WMTSCapabilities.xml,layer=World_Imagery
 Dim    : 1073741766, 1070224430, 4
 CRS    : WGS 84 / Pseudo-Mercator (EPSG:3857)
 Res    : 0.037323, 0.037323
 Bbox   : -20037507.260427, -19971868.890929, 20037507.248165, 19971868.903191</code></pre>
</div>
</div>
<p>We don’t want the whole world and certainly not that much detail, how about Mawson Station in Antarctica, Mawson is at approximately 62.87E and -67.6S.</p>
<p>We should define a local equal area projection, on Mawson.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb35" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb35-1">prj <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea +lon_0=62.8742 +lat_0=-67.6033"</span></span></code></pre></div></div>
</div>
<p>What is the right extent or bbox for that projection? It’s just metres around the <em>zero-point</em>, let’s go with a range.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb36" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb36-1">b <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">125000</span></span>
<span id="cb36-2">tfile <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".vrt"</span>) <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## use GDAL to manage IO and cleanup, same in other tools</span></span>
<span id="cb36-3">chk <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(dsn, tfile, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> prj, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cl_arg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-te"</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, b, b,  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-ts"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1024</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0...10...20...30...40...50...60...70...80...90...100 - done.</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb38" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb38-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ximage</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_ds</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">new</span>(GDALRaster, tfile), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bands =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">asp =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-12-21_vaster-grid-logic/vaster-grid-logic_files/figure-html/warp-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>What about a different data source, can we see any meaningful data in sea ice at this time of year?</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb39" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb39-1">icedsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://data.seaice.uni-bremen.de/amsr2/asi_daygrid_swath/s3125/2025/dec/Antarctic3125/asi-AMSR2-s3125-20251220-v5.4.tif"</span></span>
<span id="cb39-2"></span>
<span id="cb39-3">tfile <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".vrt"</span>)</span>
<span id="cb39-4">chk <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(icedsn, tfile, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> prj, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cl_arg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-te"</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, b, b,  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-ts"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1024</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0...10...20...30...40...50...60...70...80...90...100 - done.</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb41" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb41-1">dat <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_ds</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">new</span>(GDALRaster, tfile), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bands =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb41-2">dat[dat <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb41-3"></span>
<span id="cb41-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ximage</span>(dat, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grey.colors</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">asp =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-12-21_vaster-grid-logic/vaster-grid-logic_files/figure-html/sst-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb42" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb42-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">summary</span>(dat)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
   1.00   94.00   98.00   90.99  100.00  100.00  576851 </code></pre>
</div>
</div>
<p>Not unexpectedly at 3.125km resolution it’s a bit sparse on information, but we didn’t have to use a different approach to get coincident data. The ice is thick here, to see Mawson at about this time from Sentinel 2 imagery, try <a href="https://projects.pawsey.org.au/estinel/catalog/catalog-browser.html?location=Mawson_Station_20m&amp;date=2025-12-18&amp;viewtype=view_q128&amp;sort=alphabetical">the estinel catalog</a>, click ‘ESA’ and zoom around for more, you’ll see that dark hole in the sea ice).</p>
<p>What about the bathymetry? Even at this scale we can see the disparity between bathymetric and topographic detail.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb44" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb44-1">bathdsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://projects.pawsey.org.au/idea-gebco-tif/GEBCO_2024.tif"</span></span>
<span id="cb44-2">tfile <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".vrt"</span>)</span>
<span id="cb44-3">chk <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(bathdsn, tfile, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> prj, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cl_arg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-te"</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, b, b,  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-ts"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1024</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0...10...20...30...40...50...60...70...80...90...100 - done.</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb46" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb46-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ximage</span>(dat <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_ds</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">new</span>(GDALRaster, tfile), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bands =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">hcl.colors</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">128</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">asp =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-12-21_vaster-grid-logic/vaster-grid-logic_files/figure-html/b2-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Let’s zoom right in, and this time we’ll use terra so that adding contours is easy, read the REMA v2 2m topography and add it as contours.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb47" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb47-1">b <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3000</span></span>
<span id="cb47-2">tfile <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".vrt"</span>)</span>
<span id="cb47-3">chk <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(dsn, tfile, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> prj, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cl_arg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-te"</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, b, b,  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-ts"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1024</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0...10...20...30...40...50...60...70...80...90...100 - done.</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb49" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb49-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ximage</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_ds</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">new</span>(GDALRaster, tfile), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bands =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">asp =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb49-2"></span>
<span id="cb49-3">remadsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://raw.githubusercontent.com/mdsumner/rema-ovr/main/REMA-2m_dem_ovr.vrt"</span></span>
<span id="cb49-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(terra)</span>
<span id="cb49-5">r <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, b, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, b), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> prj, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ncols =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1024</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nrows =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1024</span>)</span>
<span id="cb49-6">tfile <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".vrt"</span>)</span>
<span id="cb49-7">chk <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(remadsn, tfile, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> prj, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cl_arg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-te"</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>b, b, b,  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-ts"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1024</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1024</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0...10...20...30...40...50...60...70...80...90...100 - done.</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb51" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb51-1">rema <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_ds</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">new</span>(GDALRaster, tfile), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">bands =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb51-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">contour</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setValues</span>(r, rema), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-12-21_vaster-grid-logic/vaster-grid-logic_files/figure-html/zoom-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Note that throughout we’ve done no juggling of input coverage or extent or determining output resolution - we ask GDAL for “enough pixels” to see, because that’s what we’re doing and it sorts that out. Reading enough pixels for a view from an efficient data source takes very little time, with raster logic as a core guideline it also takes very little time to craft our scripts.</p>
</section>
<section id="thanks" class="level2">
<h2 class="anchored" data-anchor-id="thanks">Thanks</h2>
<p>Hopefully this sparks some interest in the simplicity of raster grid logic and more use of the GDAL warp api to its full potential. Please contact me if you have any interest or questions.</p>
<p>https://github.com/hypertidy/vaster/issues</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb52" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb52-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sessionInfo</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>R version 4.5.1 (2025-06-13)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 22.04.5 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;  LAPACK version 3.10.0

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

time zone: Etc/UTC
tzcode source: system (glibc)

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

other attached packages:
[1] grout_0.0.2.9009      ximage_0.0.0.9012     gdalraster_2.3.0.9007
[4] terra_1.8-80          vaster_0.5.0         

loaded via a namespace (and not attached):
 [1] bit_4.6.0          jsonlite_2.0.0     dplyr_1.1.4        compiler_4.5.1    
 [5] maps_3.4.1.1       tidyselect_1.2.1   Rcpp_1.1.0         xml2_1.5.1        
 [9] palr_0.4.0         nanoarrow_0.7.0-2  parallel_4.5.1     dichromat_2.0-0.1 
[13] scales_1.4.0       png_0.1-8          yaml_2.3.10        fastmap_1.2.0     
[17] R6_2.6.1           generics_0.1.4     yyjsonr_0.1.21     knitr_1.50        
[21] htmlwidgets_1.6.4  tibble_3.3.0       pillar_1.11.1      RColorBrewer_1.1-3
[25] rlang_1.1.6        xfun_0.53          bit64_4.6.0-1      cli_3.6.5         
[29] magrittr_2.0.4     wk_0.9.4.9000      digest_0.6.39      rstudioapi_0.15.0 
[33] rappdirs_0.3.3     lifecycle_1.0.4    vctrs_0.6.5        evaluate_1.0.5    
[37] glue_1.8.0         farver_2.1.2       codetools_0.2-19   rmarkdown_2.29    
[41] pkgconfig_2.0.3    tools_4.5.1        htmltools_0.5.8.1 </code></pre>
</div>
</div>


</section>

 ]]></description>
  <category>raster</category>
  <category>vaster</category>
  <guid>https://hypertidy.org/posts/2025-12-21_vaster-grid-logic/vaster-grid-logic.html</guid>
  <pubDate>Sun, 21 Dec 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Coordinates broken in NetCDF</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2025-09-04_broken-netcdf/</link>
  <description><![CDATA[ 






<section id="a-netcdf-file" class="level2">
<h2 class="anchored" data-anchor-id="a-netcdf-file">A NetCDF file</h2>
<p>There’s a NetCDF file at this URL:</p>
<pre><code>"https://zenodo.org/records/7327711/files/CS2WFA_25km_201007.nc?download=1"</code></pre>
<p>It’s fairly straightforward:</p>
<pre><code>netcdf CS2WFA_25km_201007 {
dimensions:
        y = 332 ;
        x = 316 ;
        time = 1 ;
variables:
        float time(time) ;
                time:long_name = "time" ;
                time:units = "months since 2000-01-01" ;
                time:calendar = "360_day" ;
        double lat(y, x) ;
                lat:long_name = "latitude" ;
                lat:units = "degrees_north" ;
        double lon(y, x) ;
                lon:long_name = "longitude" ;
                lon:units = "degrees_east" ;
...
        double sea_ice_concentration(time, y, x) ;
                sea_ice_concentration:least_significant_digit = 4LL ;
                sea_ice_concentration:units = "1" ;
                sea_ice_concentration:standard_name = "sea_ice_area_fraction" ;
                sea_ice_concentration:description = "Mean sea ice concentration in grid cell, from Bootstrap V3 concentration algorithm (Comiso, 2017 https://doi.org/10.5067/7Q8HCCWS4I0R)" ;

// global attributes:
                :title = "Antarctic sea ice physical properties obtained from CryoSat-2 using the CS2WFA algorithm" ;
                :institution = "NASA GSFC Cryospheric Sciences Laboratory and University of Maryland-College Park" ;
                :history = "File created on November 15, 2022, 12:09:06" ;

group: sea_ice_thickness {
  ...
group: density {
  variables:
        double ice_density(time, y, x) ;
                ice_density:least_significant_digit = 4LL ;
 ...
  } // group density
}</code></pre>
<p>There’s a root group with four variables defined in time,y,x and another two groups with further variables on that same grid.</p>
<p>Each data array is 316x332x1 and we can tell that every lon,lat pair is stored explicitly. This fits a convention in NetCDF where time is “unlimited” and we’re only looking at a subset of an overall time series, that could well be continually generated day to day still now.</p>
<p>Let’s investigate the coordinates. We’ll use GDAL via a commonly used wrapper in R, its ‘vsicurl’ protocol to stream from the internet, and declare the driver explicitly (lest we get the less sophisticated HDF5 interpretation).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#dsn &lt;- "NETCDF:/vsicurl/https://zenodo.org/records/7327711/files/CS2WFA_25km_201007.nc?download=1"</span></span>
<span id="cb3-2">dsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NETCDF:../CS2WFA_25km_201007.nc"</span></span>
<span id="cb3-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(terra)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>terra 1.8.62</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1">lon <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(dsn, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lon"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: [rast] GDAL did not find an extent. installing the ncdf4 package may
help</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1">lat <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(dsn, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lat"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: [rast] GDAL did not find an extent. installing the ncdf4 package may
help</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(lon, lat))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-09-04_broken-netcdf/index_files/figure-html/coords-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>We get a message from terra about “cells not equally spaced”, which means that when reading an array the geospatial context in GDAL didn’t find anything specifying a compact representation of coordinates, but lon and lat <em>are the coordinates</em> <strong>as data</strong>, so we can safely ignore this message. (There’s another message about ncdf4, but ignore that too it’s terra try(ing) stuff. )</p>
<p>We won’t pay attention to “time”, because our file only has one time step. We’re interested in these lon,lat coordinates. What does the data itself look like? Again we choose one of the 3D variables (with degenerate 3rd dimension ‘time’) by name.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1">ice <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(dsn, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sea_ice_concentration"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: [rast] GDAL did not find an extent. installing the ncdf4 package may
help</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(ice)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-09-04_broken-netcdf/index_files/figure-html/data-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>That should look familiar, though notice that we don’t have any spatial information it’s just a matrix in its own index coordinates, 0,316 for x and 0,332 for y.</p>
<p>Let’s plot the coordinates. Now we can see our data in a much more spatial-ish context.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1">xyz <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">values</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(lon, lat, ice))</span>
<span id="cb13-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(xyz[,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pch =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"."</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> palr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">d_pal</span>(xyz[,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>]), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">asp =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb13-3">maps<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"world2"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-09-04_broken-netcdf/index_files/figure-html/plot-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>We now don’t have a nice gridded dataset, it’s points in longitude latitude. What can we do to plot it in that nice polar aspect with proper spatial referencing?</p>
<p>Let’s have a look at this dataset from a GDAL perspective. Now we use the API package <code>gdalraster</code> which gives a lot more control over GDAL itself. I’m going to skip over interrogating the syntax for a particular array, like we did with terra and ‘sea_ice_concentration’ above, I construct the subdataset syntax to open.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NETCDF:/vsicurl/https://zenodo.org/records/7327711/files/CS2WFA_25km_201007.nc?download=1"</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "NETCDF:/vsicurl/https://zenodo.org/records/7327711/files/CS2WFA_25km_201007.nc?download=1"</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1">sds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%s:sea_ice_concentration"</span>, dsn)</span>
<span id="cb16-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(gdalraster)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>GDAL 3.12.0dev-4e2b27da8f (released 2025-08-26), GEOS 3.12.1, PROJ 9.3.1</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>
Attaching package: 'gdalraster'</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>The following object is masked from 'package:terra':

    rasterize</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb20-1">ds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">new</span>(GDALRaster, sds)</span>
<span id="cb20-2">ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">info</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>Driver: netCDF/Network Common Data Format
Files: ../CS2WFA_25km_201007.nc
Size is 316, 332
Metadata:
  NC_GLOBAL#history=File created on November 15, 2022, 12:09:06
  NC_GLOBAL#institution=NASA GSFC Cryospheric Sciences Laboratory and University of Maryland-College Park
  NC_GLOBAL#title=Antarctic sea ice physical properties obtained from CryoSat-2 using the CS2WFA algorithm
  NETCDF_DIM_EXTRA={time}
  NETCDF_DIM_time_DEF={1,5}
  NETCDF_DIM_time_VALUES=126
  sea_ice_concentration#description=Mean sea ice concentration in grid cell, from Bootstrap V3 concentration algorithm (Comiso, 2017 https://doi.org/10.5067/7Q8HCCWS4I0R)
  sea_ice_concentration#least_significant_digit=4
  sea_ice_concentration#standard_name=sea_ice_area_fraction
  sea_ice_concentration#units=1
  time#calendar=360_day
  time#long_name=time
  time#units=months since 2000-01-01
Geolocation:
  SRS=GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST],AUTHORITY["EPSG","4326"]]
  X_DATASET=NETCDF:"../CS2WFA_25km_201007.nc":lon
  X_BAND=1
  Y_DATASET=NETCDF:"../CS2WFA_25km_201007.nc":lat
  Y_BAND=1
  PIXEL_OFFSET=0
  PIXEL_STEP=1
  LINE_OFFSET=0
  LINE_STEP=1
  GEOREFERENCING_CONVENTION=PIXEL_CENTER
Corner Coordinates:
Upper Left  (    0.0,    0.0)
Lower Left  (    0.0,  332.0)
Upper Right (  316.0,    0.0)
Lower Right (  316.0,  332.0)
Center      (  158.0,  166.0)
Band 1 Block=316x332 Type=Float64, ColorInterp=Undefined
  NoData Value=9.969209968386869e+36
  Unit Type: 1
  Metadata:
    NETCDF_VARNAME=sea_ice_concentration
    least_significant_digit=4
    units=1
    standard_name=sea_ice_area_fraction
    description=Mean sea ice concentration in grid cell, from Bootstrap V3 concentration algorithm (Comiso, 2017 https://doi.org/10.5067/7Q8HCCWS4I0R)
    NETCDF_DIM_time=126</code></pre>
</div>
</div>
<p>The interesting part of that output is under “Geolocation:”. We can see that while GDAL doesn’t have spatial referencing for this array, it does seem to know that’s it’s possible because of the X_DATASET and Y_DATASET. These can be used by the GDAL warper API (warp means “reprojection” or “reshaping” for an image) in order to resolve to a <em>new</em> spatial gridded dataset … but also note, the same facilities used to “reproject” one regular grid to another are also the same that can be used to generate a regular grid from irregular geolocation coordinates (we have a point for every data point, but those coordinates might be less dense, or might be GCPs or RCPs, and no matter what coordinate system those latent coordinates are using, we can warp to whatever spatial grid we like). So let’s warp.</p>
<p>We don’t have to specifying the geolocation arrays, we saw that GDAL already knows this. We’ll write our new gridded dataset conveniently to a temporary virtual “file” so we can avoid more cleanup.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb22-1">gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(sds,  tf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".tif"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0...10...20...30...40...50...60...70...80...90...100 - done.</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb24-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(icegrid <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(tf))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-09-04_broken-netcdf/index_files/figure-html/warp-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb25" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb25-1">icegrid</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
size        : 127, 902, 1  (nrow, ncol, nlyr)
resolution  : 0.398722, 0.3987662  (x, y)
extent      : 0.164645, 359.8119, -89.80441, -39.1611  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326) 
source      : filedb3943dea1d4.tif 
name        : filedb3943dea1d4 </code></pre>
</div>
</div>
<p>We indeed now have a spatial grid, a raster. But perhaps we don’t like the 0,360 convention. We can set the target extent, GDAL had to figure one out from the input geolocation arrays, and it will usually do a good job but it’s really our responsibility to specify what we want for reproducibility in later workflows.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb27-1">gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(sds,  tf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".tif"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, </span>
<span id="cb27-2">                 <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cl_arg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-te"</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">39</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-to"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GEOLOC_NORMALIZE_LONGITUDE_MINUS_180_PLUS_180=YES"</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0...10...20...30...40...50...60...70...80...90...100 - done.</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb29" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb29-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(icegrid <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(tf))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-09-04_broken-netcdf/index_files/figure-html/extent-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb30" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb30-1">icegrid</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
size        : 194, 1371, 1  (nrow, ncol, nlyr)
resolution  : 0.2625821, 0.2628866  (x, y)
extent      : -180, 180, -90, -39  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326) 
source      : filedb394444fc021.tif 
name        : filedb394444fc021 </code></pre>
</div>
</div>
<p>Another thing that is also our responsibility is the dimensions of the grid and the resolution, obviously this and extent (or bbox, bounding box) are all interlinked so we augment our bounding box / extent setting with a nice clean resolution.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb32" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb32-1">gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(sds,  tf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".tif"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, </span>
<span id="cb32-2">                 <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cl_arg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-te"</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">39</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-tr"</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.25</span>,</span>
<span id="cb32-3">                            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-to"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GEOLOC_NORMALIZE_LONGITUDE_MINUS_180_PLUS_180=YES"</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0...10...20...30...40...50...60...70...80...90...100 - done.</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb34" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb34-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(icegrid <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(tf))</span>
<span id="cb34-2">maps<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-09-04_broken-netcdf/index_files/figure-html/extent2-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb35" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb35-1">icegrid</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
size        : 204, 1440, 1  (nrow, ncol, nlyr)
resolution  : 0.25, 0.25  (x, y)
extent      : -180, 180, -90, -39  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326) 
source      : filedb39443fd3375.tif 
name        : filedb39443fd3375 </code></pre>
</div>
</div>
<p>That is all well and nice, and we’ve quietly demonstrated some of the key powers of GDAL:</p>
<ul>
<li>virtualization, streaming read, read a particular variable</li>
<li>investigate GDAL logic (coordinates are linked to data via latent “geolocation” arrays)</li>
<li>warping with heuristics to a CRS</li>
<li>warping with a grid specification, and using geolocation arrays to guide the grid-resolving process</li>
<li>setting grid specification with any of crs, extent(bbox), resolution, dimension, and allowing GDAL to internally wrap from 0,360 context to -180,180</li>
</ul>
<p>But, we still don’t have that nice polar aspect we saw from the raw array above. So we change CRS. ‘EPSG:3412’ is a Polar Stereographic map projection on the south pole, commonly used for standard sea ice products. As a grid this has nice properties, that don’t require edge-wrap for a matrix model, it’s true scale at approximately where the coastline of Antarctica is, and it preserves shape (this means not all cells are exactly the same size, but they’re close enough for where the sea ice is).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb37" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb37-1">gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(sds,  tf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".tif"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3412"</span>, </span>
<span id="cb37-2">                <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cl_arg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-to"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GEOLOC_NORMALIZE_LONGITUDE_MINUS_180_PLUS_180=YES"</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0...10...20...30...40...50...60...70...80...90...100 - done.</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb39" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb39-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(polargrid <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(tf))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-09-04_broken-netcdf/index_files/figure-html/polargrid-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb40" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb40-1">polargrid</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
size        : 348, 332, 1  (nrow, ncol, nlyr)
resolution  : 24999.84, 24999.84  (x, y)
extent      : -3950080, 4349868, -4337584, 4362361  (xmin, xmax, ymin, ymax)
coord. ref. : NSIDC Sea Ice Polar Stereographic South (EPSG:3412) 
source      : filedb39427e3e998.tif 
name        : filedb39427e3e998 </code></pre>
</div>
</div>
<p>To make sure let’s get some spatial data to plot with this.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb42" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb42-1">v <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vect</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsizip//vsicurl/https://github.com/wmgeolab/geoBoundaries/raw/main/releaseData/CGAZ/geoBoundariesCGAZ_ADM0.zip"</span>, </span>
<span id="cb42-2">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">query =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SELECT shapeGroup FROM geoBoundariesCGAZ_ADM0 WHERE shapeGroup IN ('ATA')"</span>)</span>
<span id="cb42-3">v <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crop</span>(v, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">84</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)) <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## small hack to remove the pole seam</span></span>
<span id="cb42-4">v <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span>(v, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3412"</span>)</span>
<span id="cb42-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(polargrid)</span>
<span id="cb42-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(v, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-09-04_broken-netcdf/index_files/figure-html/spatial-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Looks good! We’ve plotted the original data in the correct polar aspect.</p>
<p>But, the data aren’t exactly the same, we’ve added pixels in the heuristic used by GDAL to determine the grid specification from the extent and resolution of the geolocation array longitude and latitudes.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb43" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb43-1">ice</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
size        : 332, 316, 1  (nrow, ncol, nlyr)
resolution  : 1, 1  (x, y)
extent      : 0, 316, 0, 332  (xmin, xmax, ymin, ymax)
coord. ref. :  
source      : CS2WFA_25km_201007.nc:sea_ice_concentration 
varname     : sea_ice_concentration (sea_ice_area_fraction) 
name        : sea_ice_concentration 
unit        :                     1 </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb45" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb45-1">polargrid</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
size        : 348, 332, 1  (nrow, ncol, nlyr)
resolution  : 24999.84, 24999.84  (x, y)
extent      : -3950080, 4349868, -4337584, 4362361  (xmin, xmax, ymin, ymax)
coord. ref. : NSIDC Sea Ice Polar Stereographic South (EPSG:3412) 
source      : filedb39427e3e998.tif 
name        : filedb39427e3e998 </code></pre>
</div>
</div>
<p>So, let’s try to use the same grid.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb47" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb47-1">gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(sds,  tf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".tif"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3412"</span>, </span>
<span id="cb47-2">                <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cl_arg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-ts"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">316</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">332</span>,</span>
<span id="cb47-3">                           </span>
<span id="cb47-4">                  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-to"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GEOLOC_NORMALIZE_LONGITUDE_MINUS_180_PLUS_180=YES"</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0...10...20...30...40...50...60...70...80...90...100 - done.</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb49" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb49-1">polargrid <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(tf)</span>
<span id="cb49-2"></span>
<span id="cb49-3">polargrid</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
size        : 332, 316, 1  (nrow, ncol, nlyr)
resolution  : 26265.66, 26204.65  (x, y)
extent      : -3950080, 4349868, -4337584, 4362361  (xmin, xmax, ymin, ymax)
coord. ref. : NSIDC Sea Ice Polar Stereographic South (EPSG:3412) 
source      : filedb394ad7590c.tif 
name        : filedb394ad7590c </code></pre>
</div>
</div>
<p>We can’t do that without giving them the same extent, but we still don’t know what that is for the original data. So let’s calculate it.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb51" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb51-1">xy <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">values</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(lon, lat)), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">to =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3412"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">from =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>)</span>
<span id="cb51-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">range</span>(xy[,<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] -3937527  4337533</code></pre>
</div>
</div>
</section>
<section id="throw-all-that-away-ignore-everything-above." class="level2">
<h2 class="anchored" data-anchor-id="throw-all-that-away-ignore-everything-above.">Throw all that away, ignore everything above.</h2>
<p>You should never ever do the above for a dataset that doesn’t need it. This is a major problem in array computation worlds, there’s a lowest common denominator that will work but why not be smart about it, and keep fidelity with the original scheme for a dataset.</p>
<p>The problem here is that we can’t reconstruct the actual grid in the file, we have to treat it as points in geolocation arrays, and infer something about the grid. Here’s the answer:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb53" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb53-1">ex <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xmin =</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3950000</span>,  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xmax =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3950000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ymin  =</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3950000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ymax =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4350000</span>)</span>
<span id="cb53-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">diff</span>(ex)[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">316</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">332</span>)  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## look familiar?</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> xmax  ymax 
25000 25000 </code></pre>
</div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb55" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb55-1">set_ext <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x, ex) {terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(x) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> ex; x}</span>
<span id="cb55-2"></span>
<span id="cb55-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_ext</span>(ice, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(ex)))</span>
<span id="cb55-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(v, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> T)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-09-04_broken-netcdf/index_files/figure-html/set_extent-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb56" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb56-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(polargrid); <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(v, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-09-04_broken-netcdf/index_files/figure-html/set_extent-2.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Now finally, we get exactly the same answer.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb57" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb57-1">gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">warp</span>(sds,  tf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".tif"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">t_srs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:3412"</span>, </span>
<span id="cb57-2">                <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">cl_arg =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-ts"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">316</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">332</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-te"</span>, ex[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], ex[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>], ex[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], ex[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>],</span>
<span id="cb57-3">                           </span>
<span id="cb57-4">                  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-to"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"GEOLOC_NORMALIZE_LONGITUDE_MINUS_180_PLUS_180=YES"</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>0...10...20...30...40...50...60...70...80...90...100 - done.</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb59" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb59-1">polargrid <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(tf)</span>
<span id="cb59-2"></span>
<span id="cb59-3">polargrid</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
size        : 332, 316, 1  (nrow, ncol, nlyr)
resolution  : 25000, 25000  (x, y)
extent      : -3950000, 3950000, -3950000, 4350000  (xmin, xmax, ymin, ymax)
coord. ref. : NSIDC Sea Ice Polar Stereographic South (EPSG:3412) 
source      : filedb3946450fee3.tif 
name        : filedb3946450fee3 </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb61" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb61-1">polargrid <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set_ext</span>(ice, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(ex))</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Warning: [-] CRS do not match</code></pre>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
size        : 332, 316, 1  (nrow, ncol, nlyr)
resolution  : 25000, 25000  (x, y)
extent      : -3950000, 3950000, -3950000, 4350000  (xmin, xmax, ymin, ymax)
coord. ref. : NSIDC Sea Ice Polar Stereographic South (EPSG:3412) 
source(s)   : memory
varname     : filedb3946450fee3 
name        : filedb3946450fee3 
min value   :                 0 
max value   :                 0 </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb64" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb64-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># class       : SpatRaster </span></span>
<span id="cb64-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># size        : 332, 316, 1  (nrow, ncol, nlyr)</span></span>
<span id="cb64-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># resolution  : 25000, 25000  (x, y)</span></span>
<span id="cb64-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># extent      : -3950000, 3950000, -3950000, 4350000  (xmin, xmax, ymin, ymax)</span></span>
<span id="cb64-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># coord. ref. : NSIDC Sea Ice Polar Stereographic South (EPSG:3412) </span></span>
<span id="cb64-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># source(s)   : memory</span></span>
<span id="cb64-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># varname     : fileb328ade0cec2 </span></span>
<span id="cb64-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># name        : fileb328ade0cec2 </span></span>
<span id="cb64-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># min value   :                0 </span></span>
<span id="cb64-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># max value   :                0 </span></span></code></pre></div></div>
</div>
<p>But how did we do that? We plucked some magic numbers out of the air. We can’t obtain those four numbers from the lon lat arrays, we can’t find them in the file, they aren’t in the metadata or the website. We just know, because NSIDC sea ice products are standard on a 3412 grid at 25km resolution.</p>
<p>These four numbers: -3950000, 3950000, -3950000, 4350000 are entirely cryptic in the data store itself, and require an expert to notice the problem. We can throw away 332 * 316 * 2 values <em>from every file</em>, replace them with these four values and we have a better and more faithful representation of the original data.</p>
<p>This is an entropy problem.</p>
<p>I refer to this kind of problem as “cryptic curvilinear”. The data present as an irregular grid with curvlinear coordinates, but they are entirely unnecessary, we can replace them with 4 values that anyone can remember and we have the following easy ways to fix, roughly in increasing difficulty and decreasing utility:</p>
<ul>
<li>set “-a_srs”, and -a_ullr” in gdal raster convert, or via “vrt://{dsn}?a_ullr=,,,” syntax</li>
<li>OR set “-a_srs”, and “-a_gt” in gdal raster convert, or via “vrt://{dsn}?a_gt=,,,,,” syntax</li>
<li>set extent with terra in R and set the crs</li>
<li>open with rasterio and set geotransform and set spatial ref (same as set extent with R)</li>
<li>modify the coordinates in xarray, and set the crs</li>
</ul>
</section>
<section id="oh-but-sure-there-are-bad-files-out-there" class="level2">
<h2 class="anchored" data-anchor-id="oh-but-sure-there-are-bad-files-out-there">Oh, but sure there are bad files out there</h2>
<p>There are so many.</p>
<ul>
<li>GHRSST noisy, low precision degenerate rectilinear coordinates</li>
<li>OISST and NSIDC, have degenerate rectilinear coordinates that don’t cause problems</li>
</ul>


</section>

 ]]></description>
  <category>netcdf</category>
  <category>gdal</category>
  <guid>https://hypertidy.org/posts/2025-09-04_broken-netcdf/</guid>
  <pubDate>Thu, 04 Sep 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>GDAL multidim and cloud-ready ZARR</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2025-03-12_r-py-multidim/r-py-multidim.html</link>
  <description><![CDATA[ 






<section id="the-gdal-api" class="level2">
<h2 class="anchored" data-anchor-id="the-gdal-api">The GDAL API</h2>
<p>I have been working on a better understanding of the <a href="https://gdal.org/en/stable/user/multidim_raster_data_model.html">GDAL multidimensional model</a> and to do that really needs a closer look at the GDAL API itself.</p>
<p>This post demonstrates loading the GDAL API via its Python bindings into R. We connect to a modern “cloud-ready” ZARR dataset, find out some details about its contents and then convert from its native multidimensional form to a more classic 2D raster model, then use that to create a map from Sentinel 2 imagery.</p>
<p>We don’t go very deep into any part, but just want to show a quick tour of some parts of GDAL that don’t get as much attention as deserved (IMO). I’m using a very recent version of GDAL, which might mean some code doesn’t work for you. If that’s the case please let me know and I can explore alternatives and identify when/how the newer features will be more available. There are some echoes here of an older post I made about GDAL in R: https://www.hypertidy.org/posts/2017-09-01_gdal-in-r/</p>
</section>
<section id="zarr-and-the-european-space-agency-esa" class="level2">
<h2 class="anchored" data-anchor-id="zarr-and-the-european-space-agency-esa">ZARR and the European Space Agency (ESA)</h2>
<p>The ESA is moving Copernicus to <a href="https://zarr.dev">ZARR</a>, launching its <a href="https://zarr.eopf.copernicus.eu/">Earth Observation Processing Framework (EOPF) data format (Zarr)</a>. ZARR is “a community project to develop specifications and software for storage of large N-dimensional typed arrays”.</p>
<p>A ZARR is a dataset consisting of trees of array chunks stored (usually) in object storage and indexed by fairly simple JSON metadata that describes how those chunks align together in one potentially very large array. The idea is that all the metadata lives upfront in instantly readable JSON, and changes made to the dataset (extending it each day as new data arrives) affects only the relevant chunks and the small parts of the JSON. This is different to a long list of NetCDFs that grows every day, where the metadata is self-contained for each file and there is no overarching abstraction for the entire file set.</p>
<p>ZARR is usually in object storage, and loaded by datacube software such as <a href="https://xarray.dev">xarray</a>. It’s not intended to be zipped into a huge file and downloaded or read, the real power lies in the entire dataset being lazy, and understood by software that needs just one data set description (url, or S3 path, etc).</p>
</section>
<section id="esa-sample-zarr-datasets" class="level2">
<h2 class="anchored" data-anchor-id="esa-sample-zarr-datasets">ESA sample Zarr datasets</h2>
<p>The ESA provide a set of example ZARRs that are available in zip files:</p>
<p>https://eopf-public.s3.sbg.perf.cloud.ovh.net/product.html</p>
<p>We choose one that is described by this URL:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1">url <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://eopf-public.s3.sbg.perf.cloud.ovh.net/eoproducts/S02MSIL1C_20230629T063559_0000_A064_T3A5.zarr.zip"</span></span></code></pre></div></div>
</div>
</section>
<section id="gdal-urls-and-zip-files" class="level2">
<h2 class="anchored" data-anchor-id="gdal-urls-and-zip-files">GDAL urls and zip files</h2>
<p>GDAL doesn’t force us to download data, but we need some syntax to leverage its remote capabilities in the simplest way. The Virtual File System (VSI) allows us to declare special sources like zip files <code>/vsizip/</code> and urls <code>/vsicurl/</code>, which we can chain together. With ZARR we also need careful quoting of the description, and we declare the ZARR driver upfront.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">(dsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'ZARR:"/vsizip//vsicurl/%s"'</span>, url))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "ZARR:\"/vsizip//vsicurl/https://eopf-public.s3.sbg.perf.cloud.ovh.net/eoproducts/S02MSIL1C_20230629T063559_0000_A064_T3A5.zarr.zip\""</code></pre>
</div>
</div>
</section>
<section id="gdal-and-multidimensional-datasets" class="level2">
<h2 class="anchored" data-anchor-id="gdal-and-multidimensional-datasets">GDAL and multidimensional datasets</h2>
<p>GDAL has a multidimensional mode for data sources that aren’t “imagery” in the traditional sense. (If we open one of these datasets in “classic” mode we end up with a lot of bands on a 2D raster, or potentially many bands on many <em>sub</em>datasets within a more general container. Zarr is a container format, much like HDF5 and NetCDF).</p>
<p>Multidimensional mode is avaible in the API via <code>OpenEx()</code> and declaring type <code>OF_MULTIDIM_RASTER</code>.</p>
<p>To actually load this python library we use <a href="https://posit.co/blog/reticulate-1-41/">{reticulate} <code>py_require()</code></a> which drives the awesome <a href="https://docs.astral.sh/uv/">Python uv</a> package manager.</p>
<p>(For some reason the pypi name of the package is “gdal”, but the actual module is obtained with “osgeo.gdal”).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">reticulate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">py_require</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gdal"</span>)</span>
<span id="cb4-2">gdal <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> reticulate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">import</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"osgeo.gdal"</span>)</span>
<span id="cb4-3">gdal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">UseExceptions</span>()</span>
<span id="cb4-4"></span>
<span id="cb4-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">names</span>(gdal), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">40</span>)  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## see that we have a huge coverage of the underlying API, 544 elements at time of writing</span></span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code> [1] "GCI_NIRBand"                       "GCI_CyanBand"                     
 [3] "GFU_RedMax"                        "GRT_COMPOSITE"                    
 [5] "GRT_AGGREGATION"                   "GRIORA_Gauss"                     
 [7] "GPI_RGB"                           "GFT_Integer"                      
 [9] "GFU_AlphaMin"                      "GCI_SAR_C_Band"                   
[11] "GCI_OtherIRBand"                   "ApplyVerticalShiftGrid"           
[13] "CPLE_NoWriteAccess"                "deprecation_warn"                 
[15] "Rasterize"                         "GCI_SAR_K_Band"                   
[17] "TermProgress_nocb"                 "GMF_ALL_VALID"                    
[19] "DCAP_CREATECOPY"                   "GRA_Q1"                           
[21] "config_option"                     "DCAP_FIELD_DOMAINS"               
[23] "GDAL_GCP_Info_set"                 "wrapper_GDALVectorTranslateDestDS"
[25] "ColorTable"                        "ContourGenerate"                  
[27] "DCAP_COORDINATE_EPOCH"             "GDT_UInt16"                       
[29] "GDsCDeleteRelationship"            "GCI_YCbCr_CbBand"                 
[31] "IsLineOfSightVisible"              "BuildVRTInternalObjects"          
[33] "DEMProcessing"                     "GDALDestroyDriverManager"         
[35] "DCAP_RENAME_LAYERS"                "MultiDimInfoOptions"              
[37] "CPLES_XML_BUT_QUOTES"              "DitherRGB2PCT"                    
[39] "GDT_TypeCount"                     "GARIO_ERROR"                      </code></pre>
</div>
</div>
<p>The API elements chain in the usual way that works in python with ‘object.element.thing.etc’ syntax uses R’s <code>$</code> accessor.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">gdal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>Dimension<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>GetIndexingVariable</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>&lt;function Dimension.GetIndexingVariable at 0x7f08c9f61760&gt;
 signature: (self, *args) -&gt; 'GDALMDArrayHS *'</code></pre>
</div>
</div>
</section>
<section id="open-the-data" class="level2">
<h2 class="anchored" data-anchor-id="open-the-data">Open the data</h2>
<p>It’s not very exciting yet.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1">ds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> gdal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">OpenEx</span>(dsn, gdal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>OF_MULTIDIM_RASTER)</span>
<span id="cb8-2">ds</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>&lt;osgeo.gdal.Dataset; proxy of &lt;Swig Object of type 'GDALDatasetShadow *' at 0x7f08ca0ebcf0&gt; &gt;</code></pre>
</div>
</div>
<p>To actually find out what’s in there we have to traverse a tree of potentially nested “groups” that organize actual datasets in a hierarchy.</p>
<p>Get the root group and dive in, it’s very tediuous but shows some of what is there. There might be MDArrays in a group, or there might just be more groups.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1">rg <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetRootGroup</span>()</span>
<span id="cb10-2">rg<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetMDArrayNames</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>list()</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1">rg<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetGroupNames</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "conditions"   "measurements" "quality"     </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1">g1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> rg<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">OpenGroup</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"quality"</span>)</span>
<span id="cb14-2">g1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetMDArrayNames</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>list()</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1">g1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetGroupNames</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "l1c_quicklook" "mask"         </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb18-1">g2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> g1<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">OpenGroup</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"l1c_quicklook"</span>)</span>
<span id="cb18-2">g2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetMDArrayNames</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>list()</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb20-1">g2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetGroupNames</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "r10m"</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb22-1">g3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> g2<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">OpenGroup</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"r10m"</span>)</span>
<span id="cb22-2">g3<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetMDArrayNames</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "band" "x"    "y"    "tci" </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb24-1">g3<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetGroupNames</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>list()</code></pre>
</div>
</div>
<p>Finally we got to actual data, we recognize ‘tci’ as being the quicklook RGB of Sentinel 2.</p>
<p>To avoid tedium write a quick recursive function to find all the MDArray, at each level use <code>GetFullName()</code> which provides the cumulative path to where we are in the tree.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb26" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb26-1">get_all_mdnames <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(rootgroup) {</span>
<span id="cb26-2">  groups <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> rootgroup<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetGroupNames</span>()</span>
<span id="cb26-3">  groupname <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> rootgroup<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetFullName</span>()</span>
<span id="cb26-4">  amd <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> rootgroup<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetMDArrayNames</span>()</span>
<span id="cb26-5">  md <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%s/%s"</span>, groupname, amd)</span>
<span id="cb26-6">  md <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(md, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unlist</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lapply</span>(groups, \(.g) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_all_mdnames</span>(rootgroup<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">OpenGroup</span>(.g)))))</span>
<span id="cb26-7">  md</span>
<span id="cb26-8">}</span>
<span id="cb26-9"></span>
<span id="cb26-10"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_all_mdnames</span>(ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetRootGroup</span>())</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>  [1] "/conditions/geometry/angle"                        
  [2] "/conditions/geometry/band"                         
  [3] "/conditions/geometry/detector"                     
  [4] "/conditions/geometry/x"                            
  [5] "/conditions/geometry/y"                            
  [6] "/conditions/geometry/mean_sun_angles"              
  [7] "/conditions/geometry/mean_viewing_incidence_angles"
  [8] "/conditions/geometry/sun_angles"                   
  [9] "/conditions/geometry/viewing_incidence_angles"     
 [10] "/conditions/mask/detector_footprint/r10m/x"        
 [11] "/conditions/mask/detector_footprint/r10m/y"        
 [12] "/conditions/mask/detector_footprint/r10m/b02"      
 [13] "/conditions/mask/detector_footprint/r10m/b03"      
 [14] "/conditions/mask/detector_footprint/r10m/b04"      
 [15] "/conditions/mask/detector_footprint/r10m/b08"      
 [16] "/conditions/mask/detector_footprint/r20m/x"        
 [17] "/conditions/mask/detector_footprint/r20m/y"        
 [18] "/conditions/mask/detector_footprint/r20m/b05"      
 [19] "/conditions/mask/detector_footprint/r20m/b06"      
 [20] "/conditions/mask/detector_footprint/r20m/b07"      
 [21] "/conditions/mask/detector_footprint/r20m/b11"      
 [22] "/conditions/mask/detector_footprint/r20m/b12"      
 [23] "/conditions/mask/detector_footprint/r20m/b8a"      
 [24] "/conditions/mask/detector_footprint/r60m/x"        
 [25] "/conditions/mask/detector_footprint/r60m/y"        
 [26] "/conditions/mask/detector_footprint/r60m/b01"      
 [27] "/conditions/mask/detector_footprint/r60m/b09"      
 [28] "/conditions/mask/detector_footprint/r60m/b10"      
 [29] "/conditions/mask/l1c_classification/r60m/x"        
 [30] "/conditions/mask/l1c_classification/r60m/y"        
 [31] "/conditions/mask/l1c_classification/r60m/b00"      
 [32] "/conditions/meteorology/cams/latitude"             
 [33] "/conditions/meteorology/cams/longitude"            
 [34] "/conditions/meteorology/cams/aod1240"              
 [35] "/conditions/meteorology/cams/aod469"               
 [36] "/conditions/meteorology/cams/aod550"               
 [37] "/conditions/meteorology/cams/aod670"               
 [38] "/conditions/meteorology/cams/aod865"               
 [39] "/conditions/meteorology/cams/bcaod550"             
 [40] "/conditions/meteorology/cams/duaod550"             
 [41] "/conditions/meteorology/cams/isobaricInhPa"        
 [42] "/conditions/meteorology/cams/number"               
 [43] "/conditions/meteorology/cams/omaod550"             
 [44] "/conditions/meteorology/cams/ssaod550"             
 [45] "/conditions/meteorology/cams/step"                 
 [46] "/conditions/meteorology/cams/suaod550"             
 [47] "/conditions/meteorology/cams/surface"              
 [48] "/conditions/meteorology/cams/time"                 
 [49] "/conditions/meteorology/cams/valid_time"           
 [50] "/conditions/meteorology/cams/z"                    
 [51] "/conditions/meteorology/ecmwf/latitude"            
 [52] "/conditions/meteorology/ecmwf/longitude"           
 [53] "/conditions/meteorology/ecmwf/isobaricInhPa"       
 [54] "/conditions/meteorology/ecmwf/msl"                 
 [55] "/conditions/meteorology/ecmwf/number"              
 [56] "/conditions/meteorology/ecmwf/r"                   
 [57] "/conditions/meteorology/ecmwf/step"                
 [58] "/conditions/meteorology/ecmwf/surface"             
 [59] "/conditions/meteorology/ecmwf/tco3"                
 [60] "/conditions/meteorology/ecmwf/tcwv"                
 [61] "/conditions/meteorology/ecmwf/time"                
 [62] "/conditions/meteorology/ecmwf/u10"                 
 [63] "/conditions/meteorology/ecmwf/v10"                 
 [64] "/conditions/meteorology/ecmwf/valid_time"          
 [65] "/measurements/reflectance/r10m/x"                  
 [66] "/measurements/reflectance/r10m/y"                  
 [67] "/measurements/reflectance/r10m/b02"                
 [68] "/measurements/reflectance/r10m/b03"                
 [69] "/measurements/reflectance/r10m/b04"                
 [70] "/measurements/reflectance/r10m/b08"                
 [71] "/measurements/reflectance/r20m/x"                  
 [72] "/measurements/reflectance/r20m/y"                  
 [73] "/measurements/reflectance/r20m/b05"                
 [74] "/measurements/reflectance/r20m/b06"                
 [75] "/measurements/reflectance/r20m/b07"                
 [76] "/measurements/reflectance/r20m/b11"                
 [77] "/measurements/reflectance/r20m/b12"                
 [78] "/measurements/reflectance/r20m/b8a"                
 [79] "/measurements/reflectance/r60m/x"                  
 [80] "/measurements/reflectance/r60m/y"                  
 [81] "/measurements/reflectance/r60m/b01"                
 [82] "/measurements/reflectance/r60m/b09"                
 [83] "/measurements/reflectance/r60m/b10"                
 [84] "/quality/l1c_quicklook/r10m/band"                  
 [85] "/quality/l1c_quicklook/r10m/x"                     
 [86] "/quality/l1c_quicklook/r10m/y"                     
 [87] "/quality/l1c_quicklook/r10m/tci"                   
 [88] "/quality/mask/r10m/x"                              
 [89] "/quality/mask/r10m/y"                              
 [90] "/quality/mask/r10m/b02"                            
 [91] "/quality/mask/r10m/b03"                            
 [92] "/quality/mask/r10m/b04"                            
 [93] "/quality/mask/r10m/b08"                            
 [94] "/quality/mask/r20m/x"                              
 [95] "/quality/mask/r20m/y"                              
 [96] "/quality/mask/r20m/b05"                            
 [97] "/quality/mask/r20m/b06"                            
 [98] "/quality/mask/r20m/b07"                            
 [99] "/quality/mask/r20m/b11"                            
[100] "/quality/mask/r20m/b12"                            
[101] "/quality/mask/r20m/b8a"                            
[102] "/quality/mask/r60m/x"                              
[103] "/quality/mask/r60m/y"                              
[104] "/quality/mask/r60m/b01"                            
[105] "/quality/mask/r60m/b09"                            
[106] "/quality/mask/r60m/b10"                            </code></pre>
</div>
</div>
<p>Happily, we see our target MDArray name in there <code>/quality/l1c_quicklook/r10m/tci</code>.</p>
</section>
<section id="actual-data" class="level2">
<h2 class="anchored" data-anchor-id="actual-data">Actual data</h2>
<p>Finally let’s get some data out. We can obtain the MDArray now by full name and find out some properties.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb28" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb28-1">reticulate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">py_require</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"gdal"</span>)</span>
<span id="cb28-2">gdal <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> reticulate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">import</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"osgeo.gdal"</span>)</span>
<span id="cb28-3">gdal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">UseExceptions</span>()</span>
<span id="cb28-4"></span>
<span id="cb28-5">dsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ZARR:</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/vsizip//vsicurl/https://eopf-public.s3.sbg.perf.cloud.ovh.net/eoproducts/S02MSIL1C_20230629T063559_0000_A064_T3A5.zarr.zip</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb28-6"></span>
<span id="cb28-7">ds <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> gdal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">OpenEx</span>(dsn, gdal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>OF_MULTIDIM_RASTER)</span>
<span id="cb28-8">rg <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> ds<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetRootGroup</span>()</span>
<span id="cb28-9">mdname <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/quality/l1c_quicklook/r10m/tci"</span></span>
<span id="cb28-10">md <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> rg<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">OpenMDArrayFromFullname</span>(mdname)</span>
<span id="cb28-11">md<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetDimensionCount</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 3</code></pre>
</div>
</div>
<p>Traverse the dimensions to get their sizes and names.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb30" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb30-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vapply</span>(md<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetDimensions</span>(), \(.d) .d<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetSize</span>(), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>L)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1]     3 10980 10980</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb32" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb32-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vapply</span>(md<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetDimensions</span>(), \(.d) .d<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetName</span>(), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "band" "y"    "x"   </code></pre>
</div>
</div>
<p>Explore some metadata attributes.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb34" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb34-1">mnames <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vapply</span>(md<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetAttributes</span>(), \(.a) .a<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetName</span>(), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>)</span>
<span id="cb34-2"></span>
<span id="cb34-3">(meta <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setNames</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lapply</span>(md<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetAttributes</span>(), \(.a) <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unlist</span>(.a<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Read</span>())), mnames))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>$long_name
[1] "TCI: True Color Image"

$`proj:bbox`
[1]  300000 4490220  409800 4600020

$`proj:epsg`
[1] 32636

$`proj:shape`
[1] 10980 10980

$`proj:transform`
[1]      10       0  300000       0     -10 4600020       0       0       1

$`proj:wkt2`
[1] "PROJCS[\"WGS 84 / UTM zone 36N\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",33],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH],AUTHORITY[\"EPSG\",\"32636\"]]"</code></pre>
</div>
</div>
<p>We see that the CRS information is in there, but sadly while the geotransform of the data is maintained when we convert to classic raster the CRS does not make the journey (the geotransform is just the image bbox intermingled with its resolution in a mathematical abstraction used in matrix manipulation).</p>
<p>A multidim raster can be converted to classic form, either in whole or after applying a <code>$GetView()</code> operation that acts like numpy ‘[:]’ array subsetting.</p>
<p>When converting to classic raster we specify the x, then y dimensions of the dataset, which from multdim convention are in reverse order. (Note that dimension 0 is the “3rd” dimension in normal thinking, here that dimension is “band” or a dimension for each of red, green, blue in the quicklook image).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb36" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb36-1">cc <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> md<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">AsClassicDataset</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>L, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>L)</span>
<span id="cb36-2">tr <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unlist</span>(cc<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetGeoTransform</span>())</span>
<span id="cb36-3">dm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(cc<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>RasterXSize, cc<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>RasterYSize)</span>
<span id="cb36-4">cc<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetSpatialRef</span>() <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## empty, so we retrieve from the attributes</span></span>
<span id="cb36-5">crs <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> cc<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">GetMetadata</span>()[[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"proj:wkt2"</span>]]</span></code></pre></div></div>
</div>
<p>Now, I used <code>reproj_extent</code> to convert the dataset’s bbox to one in longlat, but I won’t share that here, we’ll just use the result so our map is a little more familiar. The source data xy bbox is <code>xmin: 300000 ymin: 4490220  xmax: 409800 ymax:4600020</code>, and we take small section of that which is this in longitude latitude:</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb37" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb37-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># xmin,xmax,ymin,ymax converted below to bbox </span></span>
<span id="cb37-2">ex <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">31.689</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">31.774</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">40.665</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">40.724</span>)</span></code></pre></div></div>
</div>
<p>To warp the imagery to this region we first need to set the CRS properly on the dataset, so translate to a temporary VRT and use that dataset for the next step.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb38" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb38-1">dsvrt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> gdal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Translate</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".vrt"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tmpdir =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem"</span>), cc, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">options =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-a_srs"</span>, crs))</span>
<span id="cb38-2">tf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> tf <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsimem/result.tif"</span></span>
<span id="cb38-3">ww <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> gdal<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Warp</span>(tf, dsvrt,  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dstSRS =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">outputBounds =</span> ex[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)])</span>
<span id="cb38-4">ww<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Close</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 0</code></pre>
</div>
</div>
<p>Finally we can read the image, plot it, obtain some contextual data and be assured that our map is correct.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb40" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb40-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(gdalraster)</span>
<span id="cb40-2">data <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_ds</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">new</span>(GDALRaster, tf))</span></code></pre></div></div>
</div>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb41" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb41-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(osmdata)</span>
<span id="cb41-2">x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">opq</span>(ex[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)]) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add_osm_feature</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">key =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"highway"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">osmdata_sf</span>()</span>
<span id="cb41-3"></span>
<span id="cb41-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(sf)</span>
<span id="cb41-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_raster</span>(data)</span>
<span id="cb41-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(x<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>osm_lines[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"hotpink"</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2025-03-12_r-py-multidim/r-py-multidim_files/figure-html/osm-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>We had a look at GDAL multidimensional API, converting a 3D dataset to classic raster, augmenting the missing CRS information on a virtual copy and then warping an image to a familiar map context.</p>
<p>There is ongoing work to bring the full GDAL API to R in <a href="https://github.com/USDAForestService/gdalraster">{gdalraster}</a>, and in-development version of gdalraster to add the <code>GDALMultiDimRaster</code> class and helpers: https://github.com/mdsumner/gdalraster/tree/multidimnew.</p>
<p>Please get in touch if any of this is of interest!</p>
</section>
<section id="late-bonus-section-bluelink-ocean-model" class="level2">
<h2 class="anchored" data-anchor-id="late-bonus-section-bluelink-ocean-model">Late Bonus Section: Bluelink ocean model</h2>
<p>This is something I want to use VRT to encapsulate as one whole dataset, here just a test on one file (there are 174 of these ocean_temp files, up to June 2024 at time of writing).</p>
<p>Note that we are using ‘/fileServer/’ from Thredds, not ‘/dodsC/’. GDAL uses userfaultd as a trick to read NetCDF remotely.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb42" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb42-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> osgeo <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> gdal</span>
<span id="cb42-2">dsn <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/vsicurl/https://thredds.nci.org.au/thredds/fileServer/gb6/BRAN/BRAN2023/daily/ocean_temp_2010_01.nc"</span></span>
<span id="cb42-3">ds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> gdal.OpenEx(dsn, gdal.OF_MULTIDIM_RASTER)</span>
<span id="cb42-4">rg <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ds.GetRootGroup()</span>
<span id="cb42-5">rg.GetMDArrayNames()</span>
<span id="cb42-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># ['xt_ocean', 'yt_ocean', 'st_ocean', 'Time', 'nv', 'st_edges_ocean', 'average_T1', 'average_T2', 'average_DT', 'Time_bnds', 'temp']</span></span>
<span id="cb42-7"></span>
<span id="cb42-8">temp <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rg.OpenMDArrayFromFullname(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"//temp"</span>)</span>
<span id="cb42-9">[d.GetName() <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> d <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> temp.GetDimensions()]</span>
<span id="cb42-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#['Time', 'st_ocean', 'yt_ocean', 'xt_ocean']</span></span>
<span id="cb42-11">[d.GetSize() <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> d <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> temp.GetDimensions()]</span>
<span id="cb42-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#[31, 51, 1500, 3600]</span></span></code></pre></div></div>
<p>I don’t know why xarray can seemingly read netcdf from S3, but not from normal url? Maybe just something fsspec I need to understand?</p>
<p>I also noticed that if the file is local the array names at root level are like this:</p>
<pre><code>['//xt_ocean', '//yt_ocean', '//st_ocean', '//Time', '//nv', '//st_edges_ocean', '//average_T1', '//average_T2', '//average_DT', '//Time_bnds', '//temp']
</code></pre>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb44" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb44-1">gdalraster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gdal_version</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "GDAL 3.11.0dev-dd6009a0eb, released 2018/99/99"
[2] "3110000"                                       
[3] "20189999"                                      
[4] "3.11.0dev-dd6009a0eb"                          </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb46" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb46-1">devtools<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">session_info</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>─ Session info ───────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.4.2 (2024-10-31)
 os       Ubuntu 20.04.6 LTS
 system   x86_64, linux-gnu
 ui       X11
 language (EN)
 collate  en_AU.UTF-8
 ctype    en_AU.UTF-8
 tz       Australia/Hobart
 date     2025-03-12
 pandoc   3.2 @ /usr/lib/rstudio-server/bin/quarto/bin/tools/x86_64/ (via rmarkdown)

─ Packages ───────────────────────────────────────────────────────────────────
 package     * version     date (UTC) lib source
 bit           4.5.0.1     2024-12-03 [2] CRAN (R 4.4.2)
 bit64         4.6.0-1     2025-01-16 [2] CRAN (R 4.4.2)
 cachem        1.1.0       2024-05-16 [2] CRAN (R 4.4.1)
 class         7.3-23      2025-01-01 [4] CRAN (R 4.4.2)
 classInt      0.4-11      2025-01-08 [2] CRAN (R 4.4.2)
 cli           3.6.4       2025-02-13 [2] CRAN (R 4.4.2)
 codetools     0.2-20      2024-03-31 [4] CRAN (R 4.4.1)
 curl          6.2.1       2025-02-19 [2] CRAN (R 4.4.2)
 DBI           1.2.3       2024-06-02 [2] CRAN (R 4.4.1)
 devtools      2.4.5       2022-10-11 [2] CRAN (R 4.4.1)
 digest        0.6.37      2024-08-19 [2] CRAN (R 4.4.1)
 e1071         1.7-16      2024-09-16 [2] CRAN (R 4.4.1)
 ellipsis      0.3.2       2021-04-29 [2] CRAN (R 4.4.1)
 evaluate      1.0.3       2025-01-10 [2] CRAN (R 4.4.2)
 fastmap       1.2.0       2024-05-15 [2] CRAN (R 4.4.1)
 fs            1.6.5.9000  2024-12-18 [2] Github (r-lib/fs@8d40528)
 gdalraster  * 1.12.0.9250 2025-03-10 [1] local
 generics      0.1.3       2022-07-05 [2] CRAN (R 4.4.1)
 glue          1.8.0       2024-09-30 [2] CRAN (R 4.4.1)
 here          1.0.1       2020-12-13 [2] CRAN (R 4.4.1)
 htmltools     0.5.8.1     2024-04-04 [2] CRAN (R 4.4.1)
 htmlwidgets   1.6.4       2023-12-06 [2] CRAN (R 4.4.1)
 httpuv        1.6.15      2024-03-26 [2] CRAN (R 4.4.1)
 httr2         1.1.0       2025-01-18 [2] CRAN (R 4.4.2)
 jsonlite      1.9.0       2025-02-19 [2] CRAN (R 4.4.2)
 KernSmooth    2.23-26     2025-01-01 [4] CRAN (R 4.4.2)
 knitr         1.49        2024-11-08 [2] CRAN (R 4.4.2)
 later         1.3.2       2023-12-06 [2] CRAN (R 4.4.1)
 lattice       0.22-6      2024-03-20 [4] CRAN (R 4.4.1)
 lifecycle     1.0.4       2023-11-07 [2] CRAN (R 4.4.1)
 lubridate     1.9.4       2024-12-08 [2] CRAN (R 4.4.2)
 magrittr      2.0.3       2022-03-30 [2] CRAN (R 4.4.1)
 Matrix        1.7-0       2024-04-26 [2] CRAN (R 4.4.1)
 memoise       2.0.1       2021-11-26 [2] CRAN (R 4.4.1)
 mime          0.12        2021-09-28 [2] CRAN (R 4.4.1)
 miniUI        0.1.1.1     2018-05-18 [2] CRAN (R 4.4.1)
 nanoarrow     0.6.0       2024-10-13 [2] CRAN (R 4.4.2)
 osmdata     * 0.2.5       2023-08-14 [2] CRAN (R 4.4.2)
 pkgbuild      1.4.4       2024-03-17 [2] CRAN (R 4.4.1)
 pkgload       1.4.0       2024-06-28 [2] CRAN (R 4.4.1)
 png           0.1-8       2022-11-29 [2] CRAN (R 4.4.1)
 profvis       0.4.0       2024-09-20 [2] CRAN (R 4.4.1)
 promises      1.3.0       2024-04-05 [2] CRAN (R 4.4.1)
 proxy         0.4-27      2022-06-09 [2] CRAN (R 4.4.1)
 purrr         1.0.4.9000  2025-02-19 [2] Github (tidyverse/purrr@9c8beb4)
 R6            2.6.1       2025-02-15 [2] CRAN (R 4.4.2)
 rappdirs      0.3.3       2021-01-31 [2] CRAN (R 4.4.1)
 Rcpp          1.0.14      2025-01-12 [2] CRAN (R 4.4.2)
 remotes       2.5.0       2024-03-17 [2] CRAN (R 4.4.1)
 reticulate  * 1.41.0      2025-02-24 [2] CRAN (R 4.4.2)
 rlang         1.1.5       2025-01-17 [2] CRAN (R 4.4.2)
 rmarkdown     2.29        2024-11-04 [2] CRAN (R 4.4.2)
 rprojroot     2.0.4       2023-11-05 [2] CRAN (R 4.4.1)
 rstudioapi    0.16.0      2024-03-24 [2] CRAN (R 4.4.1)
 sessioninfo   1.2.2       2021-12-06 [2] CRAN (R 4.4.1)
 sf          * 1.0-19      2024-11-05 [2] CRAN (R 4.4.2)
 shiny         1.9.1       2024-08-01 [2] CRAN (R 4.4.1)
 timechange    0.3.0       2024-01-18 [2] CRAN (R 4.4.1)
 units         0.8-5       2023-11-28 [2] CRAN (R 4.4.1)
 urlchecker    1.0.1       2021-11-30 [2] CRAN (R 4.4.1)
 usethis       3.0.0       2024-07-29 [2] CRAN (R 4.4.1)
 vctrs         0.6.5       2023-12-01 [2] CRAN (R 4.4.1)
 withr         3.0.2       2024-10-28 [2] CRAN (R 4.4.1)
 wk            0.9.4       2024-10-11 [2] CRAN (R 4.4.1)
 xfun          0.50        2025-01-07 [2] CRAN (R 4.4.2)
 xml2          1.3.6       2023-12-04 [2] CRAN (R 4.4.1)
 xtable        1.8-4       2019-04-21 [2] CRAN (R 4.4.1)
 yaml          2.3.10      2024-07-26 [2] CRAN (R 4.4.1)

 [1] /perm_storage/home/mdsumner/R/x86_64-pc-linux-gnu-library/4.4
 [2] /usr/local/lib/R/site-library
 [3] /usr/lib/R/site-library
 [4] /usr/lib/R/library

─ Python configuration ───────────────────────────────────────────────────────
 python:         /perm_storage/home/mdsumner/.cache/R/reticulate/uv/cache/archive-v0/twFzciVwGCsaiQXG6_cWf/bin/python3
 libpython:      /perm_storage/home/mdsumner/.local/share/uv/python/cpython-3.11.11-linux-x86_64-gnu/lib/libpython3.11.so
 pythonhome:     /perm_storage/home/mdsumner/.cache/R/reticulate/uv/cache/archive-v0/twFzciVwGCsaiQXG6_cWf:/perm_storage/home/mdsumner/.cache/R/reticulate/uv/cache/archive-v0/twFzciVwGCsaiQXG6_cWf
 virtualenv:     /perm_storage/home/mdsumner/.cache/R/reticulate/uv/cache/archive-v0/twFzciVwGCsaiQXG6_cWf/bin/activate_this.py
 version:        3.11.11 (main, Feb 12 2025, 14:51:05) [Clang 19.1.6 ]
 numpy:          /perm_storage/home/mdsumner/.cache/R/reticulate/uv/cache/archive-v0/twFzciVwGCsaiQXG6_cWf/lib/python3.11/site-packages/numpy
 numpy_version:  2.2.3
 osgeo:          /perm_storage/home/mdsumner/.cache/R/reticulate/uv/cache/archive-v0/twFzciVwGCsaiQXG6_cWf/lib/python3.11/site-packages/osgeo
 
 NOTE: Python version was forced by py_require()

──────────────────────────────────────────────────────────────────────────────</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb48" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb48-1">reticulate<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">py_require</span>()</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>══════════════════════════ Python requirements ══════════════════════════</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>── Current requirements ─────────────────────────────────────────────────</code></pre>
</div>
<div class="cell-output cell-output-stdout">
<pre><code> Python:   [No Python version specified. Will default to '3.11.11']
 Packages: numpy, gdal</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>── R package requests ───────────────────────────────────────────────────</code></pre>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>R package  Python packages                           Python version      
reticulate numpy                                                         </code></pre>
</div>
</div>


</section>

 ]]></description>
  <category>gdal</category>
  <category>zarr</category>
  <category>netcdf</category>
  <guid>https://hypertidy.org/posts/2025-03-12_r-py-multidim/r-py-multidim.html</guid>
  <pubDate>Mon, 30 Jun 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Conservative regridding with GDAL (?)</title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2024-12-11_conservative_gdal/</link>
  <description><![CDATA[ 






<p>Can GDAL do conservative re-gridding? For cases of regular grid to regular grid, yes I think it can.</p>
<p>Please note that I’m using tools I’m comfortable with, because I wrote them. I will reframe in other tools and other languages in time. For some reason I’d been blocked on understanding this issue.</p>
<section id="simple-grid-with-four-values" class="level2">
<h2 class="anchored" data-anchor-id="simple-grid-with-four-values">Simple grid with four values</h2>
<p>Take a grid, 2x2 with values 1,2,3,4 that sums to <code>10</code> and warp it to a new size.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## target</span></span>
<span id="cb1-2">dm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb1-3"></span>
<span id="cb1-4">g1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), dm[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], dm[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb1-5">e1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(vapour)</span>
<span id="cb1-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(terra)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>terra 1.8.29</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## we need this so we can use MEM: via dsn::mem()</span></span>
<span id="cb3-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Sys.setenv</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">GDAL_MEM_ENABLE_OPEN =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"YES"</span>)</span>
<span id="cb3-3"></span>
<span id="cb3-4"></span>
<span id="cb3-5"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## dsn::mem generates a Memory raster, </span></span>
<span id="cb3-6"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## gdal_raster_data is the warper, here we get identity</span></span>
<span id="cb3-7">sg <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gdal_raster_data</span>(dsn<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mem</span>(g1, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extent =</span> e1, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">projection =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>))</span>
<span id="cb3-8"></span>
<span id="cb3-9"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unique</span>(sg[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 1 2 3 4</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(sg[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 10</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## spatialize for easy plotting</span></span>
<span id="cb7-2">tor <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x) {</span>
<span id="cb7-3"> </span>
<span id="cb7-4">  dm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">attr</span>(x, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dimension"</span>)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb7-5">  r <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">attr</span>(x, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"extent"</span>)), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ncols =</span> dm[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nrows =</span> dm[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">attr</span>(x, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"projection"</span>), </span>
<span id="cb7-6">                   <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">vals =</span> x[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]])</span>
<span id="cb7-7">  r</span>
<span id="cb7-8">}</span>
<span id="cb7-9"></span>
<span id="cb7-10">r <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sum"</span></span>
<span id="cb7-11"></span>
<span id="cb7-12"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">##   (always use mem() "live" to avoid the garbage collector, and only for Float64 I'm afraid)</span></span>
<span id="cb7-13"></span>
<span id="cb7-14"></span>
<span id="cb7-15"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## now use the same extent but reduce pixel size</span></span>
<span id="cb7-16">tg <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gdal_raster_data</span>(dsn<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mem</span>(g1, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extent =</span> e1, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">projection =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target_ext =</span> e1,</span>
<span id="cb7-17">                         <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target_dim =</span> dm <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">resample =</span> r)</span>
<span id="cb7-18"></span>
<span id="cb7-19"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str</span>(tg)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>List of 1
 $ : num [1:256] 0.0156 0.0156 0.0156 0.0156 0.0156 ...
 - attr(*, "dimension")= num [1:2] 16 16
 - attr(*, "extent")= num [1:4] -1 1 -1 1
 - attr(*, "projection")= chr "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AU"| __truncated__</code></pre>
</div>
</div>
<p>So we have a lot more values as we resized from 2x2 to 16x16.</p>
<p>It still looks the same, but the overall quantity has been distributed.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tor</span>(tg), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">main =</span> r)</span>
<span id="cb9-2"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## draw boundaries on</span></span>
<span id="cb9-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abline</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">v =</span> vaster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">x_corner</span>(dm <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, e1), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">h =</span> vaster<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">y_corner</span>(dm <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, e1))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2024-12-11_conservative_gdal/index_files/figure-html/resize-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(tg[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]]))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 10</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## our sum of 10 was distributed across 256 pixels</span></span>
<span id="cb12-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unique</span>(tg[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 0.015625 0.031250 0.046875 0.062500</code></pre>
</div>
</div>
<p>Now a different example, an actual map projection change.</p>
<p>But, gawd … there’s a bug here. WIP</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## now try reprojecting our unit 1x1 longlat grid to LAEA centred a few degrees east and north</span></span>
<span id="cb14-2">crs <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea +lon_0=5 +lat_0=0"</span></span>
<span id="cb14-3"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## reproject the extent, we use a densified boundary to find the new extent</span></span>
<span id="cb14-4">prex <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> reproj<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reproj_extent</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), crs, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">source =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>)</span>
<span id="cb14-5">newg <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gdal_raster_data</span>(dsn<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mem</span>(g1, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extent =</span> e1, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">projection =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>), </span>
<span id="cb14-6">                         <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target_ext =</span> prex, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target_res =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target_crs =</span> crs, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">resample =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sum"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">options =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"-tap"</span>)</span>
<span id="cb14-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tor</span>(newg))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2024-12-11_conservative_gdal/index_files/figure-html/reproj-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(newg[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 10</code></pre>
</div>
</div>
<p>And what about trying to return, of course this can only be approximate (I want to know how this compares to other tools.)</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb17-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## what if we go the other way, </span></span>
<span id="cb17-2"></span>
<span id="cb17-3">newdm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">attr</span>(newg, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"dimension"</span>)</span>
<span id="cb17-4">newext <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">attr</span>(newg, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"extent"</span>)</span>
<span id="cb17-5">x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gdal_raster_data</span>(dsn<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mem</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(newg[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]],newdm[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">byrow =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>),  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extent =</span> newext, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">projection =</span> crs), </span>
<span id="cb17-6">                 <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target_dim =</span> dm, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target_ext =</span> e1, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">target_crs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"EPSG:4326"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">resample =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sum"</span>)</span>
<span id="cb17-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tor</span>(x))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2024-12-11_conservative_gdal/index_files/figure-html/reverse-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb18-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(x[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]])</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 9.496864</code></pre>
</div>
</div>


</section>

 ]]></description>
  <category>gdal</category>
  <category>raster</category>
  <guid>https://hypertidy.org/posts/2024-12-11_conservative_gdal/</guid>
  <pubDate>Wed, 11 Dec 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title></title>
  <dc:creator>Michael Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2024-12-05_idea_update/idea-update.html</link>
  <description><![CDATA[ undefined ]]></description>
  <category>overview</category>
  <guid>https://hypertidy.org/posts/2024-12-05_idea_update/idea-update.html</guid>
  <pubDate>Thu, 05 Dec 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Plot at native resolution, with R</title>
  <dc:creator>Michael D. Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2024-12-04_plot_native/</link>
  <description><![CDATA[ 






<p>Plot native, something I should have done long ago.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' Plot raster at native resolution</span></span>
<span id="cb1-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'</span></span>
<span id="cb1-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' Determines the current device size and plots the raster centred on its own</span></span>
<span id="cb1-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' middle to plot at native resolution. </span></span>
<span id="cb1-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'</span></span>
<span id="cb1-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @param x as SpatRaster</span></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @param ... passed to terra::plot</span></span>
<span id="cb1-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'</span></span>
<span id="cb1-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @return the input raster, cropped corresponding to the plot made</span></span>
<span id="cb1-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @export</span></span>
<span id="cb1-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#'</span></span>
<span id="cb1-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' @examples</span></span>
<span id="cb1-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' plot_native(terra::rast(volcano))</span></span>
<span id="cb1-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#' plot_native(terra::disagg(terra::rast(volcano), 64))</span></span>
<span id="cb1-15">plot_native <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(x, ...) {</span>
<span id="cb1-16">  ex <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.vector</span>(terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(x))</span>
<span id="cb1-17">  at <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span></span>
<span id="cb1-18">  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## take the centre</span></span>
<span id="cb1-19">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">is.null</span>(at)) {</span>
<span id="cb1-20">    at <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">apply</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(ex, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, mean)</span>
<span id="cb1-21">  }</span>
<span id="cb1-22">  dv <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dev.size</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"px"</span>)</span>
<span id="cb1-23">  scl <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">res</span>(x)</span>
<span id="cb1-24">  halfx <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> dv[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> scl[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb1-25">  halfy <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> dv[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> scl[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]</span>
<span id="cb1-26">  cropex <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(at[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> halfx, at[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> halfx, at[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> halfy, at[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> halfy)</span>
<span id="cb1-27">  x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">crop</span>(x, terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(cropex), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">extend =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb1-28">  add <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span></span>
<span id="cb1-29">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nlyr</span>(x) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>) terra<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plotRGB</span>(x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> add) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(x, ..., <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> add)</span>
<span id="cb1-30">  x</span>
<span id="cb1-31">}</span></code></pre></div></div>
</div>
<p>So as an example read this world imagery.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">dsn <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"&lt;GDAL_WMS&gt;&lt;Service name=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">TMS</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">&gt;&lt;ServerUrl&gt;http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/${z}/${y}/${x}&lt;/ServerUrl&gt;&lt;/Service&gt;&lt;DataWindow&gt;&lt;UpperLeftX&gt;-20037508.34&lt;/UpperLeftX&gt;&lt;UpperLeftY&gt;20037508.34&lt;/UpperLeftY&gt;&lt;LowerRightX&gt;20037508.34&lt;/LowerRightX&gt;&lt;LowerRightY&gt;-20037508.34&lt;/LowerRightY&gt;&lt;TileLevel&gt;17&lt;/TileLevel&gt;&lt;TileCountX&gt;1&lt;/TileCountX&gt;&lt;TileCountY&gt;1&lt;/TileCountY&gt;&lt;YOrigin&gt;top&lt;/YOrigin&gt;&lt;/DataWindow&gt;&lt;Projection&gt;EPSG:900913&lt;/Projection&gt;&lt;BlockSizeX&gt;256&lt;/BlockSizeX&gt;&lt;BlockSizeY&gt;256&lt;/BlockSizeY&gt;&lt;BandsCount&gt;3&lt;/BandsCount&gt;&lt;MaxConnections&gt;10&lt;/MaxConnections&gt;&lt;Cache /&gt;&lt;ZeroBlockHttpCodes&gt;204,404,403&lt;/ZeroBlockHttpCodes&gt;&lt;/GDAL_WMS&gt;"</span></span>
<span id="cb2-2"></span>
<span id="cb2-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(terra)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>terra 1.7.83</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">im <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">project</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(dsn), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rast</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e6</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">res =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea +lon_0=147 +lat_0=-42"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by_util =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb4-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plotRGB</span>(im)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2024-12-04_plot_native/index_files/figure-html/image-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Do we have more, or less resolution than our device can handle? This next plot shows that we have more, and the cropped raster is returned to match the device.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dim</span>(im))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 2000 2000    3</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">dev.size</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"px"</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 1344  960</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot_native</span>(im)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2024-12-04_plot_native/index_files/figure-html/native-res-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
dimensions  : 960, 1344, 3  (nrow, ncol, nlyr)
resolution  : 1000, 1000  (x, y)
extent      : -672000, 672000, -480000, 480000  (xmin, xmax, ymin, ymax)
coord. ref. : +proj=laea +lat_0=-42 +lon_0=147 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs 
source(s)   : memory
colors RGB  : 1, 2, 3 
names       : GDAL_WMS&gt;_1, GDAL_WMS&gt;_2, GDAL_WMS&gt;_3 
min values  :           0,           0,           0 
max values  :         255,         237,         213 </code></pre>
</div>
</div>



 ]]></description>
  <category>raster</category>
  <category>gdal</category>
  <guid>https://hypertidy.org/posts/2024-12-04_plot_native/</guid>
  <pubDate>Wed, 04 Dec 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>GDAL and image tiles, the {ceramic} package</title>
  <dc:creator>Michael D. Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2023-04-22_gdal_image_tiles/</link>
  <description><![CDATA[ 






<p>A new version of <a href="https://hypertidy.github.io/ceramic/">{ceramic}</a> is now on CRAN, version 0.8.0.</p>
<p>The package exists for two purpose</p>
<ol type="1">
<li>to download tiles from image servers</li>
<li>to load raster data from image servers</li>
</ol>
<p>NOTE: we need a Mapbox key for the Mapbox servers see, please see <a href="https://hypertidy.github.io/ceramic/reference/get_api_key.html">ceramic::get_api_key()</a>.</p>
<p>The original versions of ceramic didn’t really separate these tasks but the new version does.</p>
<section id="get-raster-data-from-online" class="level2">
<h2 class="anchored" data-anchor-id="get-raster-data-from-online">Get raster data from online</h2>
<p>We can read satellite imagery or elevation with a central point and a buffer (in metres).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ceramic)</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Loading required package: terra</code></pre>
</div>
<div class="cell-output cell-output-stderr">
<pre><code>terra 1.7.23</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1">pt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">147.3257</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">42.8826</span>)</span>
<span id="cb4-2"></span>
<span id="cb4-3">(im <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cc_location</span>(pt, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">buffer =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15000</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25000</span>)))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
dimensions  : 960, 576, 3  (nrow, ncol, nlyr)
resolution  : 52.08333, 52.08333  (x, y)
extent      : 16385222, 16415222, -5319119, -5269119  (xmin, xmax, ymin, ymax)
coord. ref. : WGS 84 / Pseudo-Mercator (EPSG:3857) 
source(s)   : memory
colors RGB  : 1, 2, 3 
names       : red, green, blue 
min values  :   0,     0,    0 
max values  : 255,   255,  252 </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1">(el <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cc_elevation</span>(pt, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">buffer =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15000</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25000</span>)))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
dimensions  : 960, 576, 1  (nrow, ncol, nlyr)
resolution  : 52.08333, 52.08333  (x, y)
extent      : 16385222, 16415222, -5319119, -5269119  (xmin, xmax, ymin, ymax)
coord. ref. : WGS 84 / Pseudo-Mercator (EPSG:3857) 
source(s)   : memory
name        :  lyr.1 
min value   :   -1.9 
max value   : 1264.9 </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1">op <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">par</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mfcol =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb8-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(el, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend =</span> F); <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(im, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>); <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(el, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend =</span> F, </span>
<span id="cb8-3">                                                 <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">hcl.colors</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">64</span>)[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tail</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq_len</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">64</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">45</span>)])</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2023-04-22_gdal_image_tiles/index_files/figure-html/hobart-image-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">par</span>(op)</span></code></pre></div></div>
</div>
<p>These raster objects are in terra ‘SpatRaster’ format (older ceramic used raster package).</p>
<p>These use the Mapbox ‘mapbox.satellite’ and ‘mapbox-terrain-rgb’ tile servers.</p>
</section>
<section id="get-raster-tiles-from-online" class="level2">
<h2 class="anchored" data-anchor-id="get-raster-tiles-from-online">Get raster tiles from online</h2>
<p>If we want the actual tiles, we can use the original <code>get_tiles()</code> function. (In older versions <code>cc_location()</code> and <code>cc_elevation()</code> would <em>invoke</em> <code>get_tiles</code>, but no longer).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1">pt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">147.3257</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">42.8826</span>)</span>
<span id="cb10-2"></span>
<span id="cb10-3">imtiles <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_tiles</span>(pt, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">buffer =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15000</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25000</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Preparing to download: 24 tiles at zoom = 12 from 
https://api.mapbox.com/v4/mapbox.satellite/</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">str</span>(imtiles)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>List of 3
 $ files : chr [1:24] "/perm_storage/home/mdsumner/.cache/.ceramic/api.mapbox.com/v4/mapbox.satellite/12/3722/2586.jpg" "/perm_storage/home/mdsumner/.cache/.ceramic/api.mapbox.com/v4/mapbox.satellite/12/3723/2586.jpg" "/perm_storage/home/mdsumner/.cache/.ceramic/api.mapbox.com/v4/mapbox.satellite/12/3724/2586.jpg" "/perm_storage/home/mdsumner/.cache/.ceramic/api.mapbox.com/v4/mapbox.satellite/12/3725/2586.jpg" ...
 $ tiles :List of 2
  ..$ tiles:'data.frame':   24 obs. of  2 variables:
  .. ..$ x: int [1:24] 3722 3723 3724 3725 3722 3723 3724 3725 3722 3723 ...
  .. ..$ y: int [1:24] 2586 2586 2586 2586 2587 2587 2587 2587 2588 2588 ...
  .. ..- attr(*, "out.attrs")=List of 2
  .. .. ..$ dim     : Named int [1:2] 4 6
  .. .. .. ..- attr(*, "names")= chr [1:2] "x" "y"
  .. .. ..$ dimnames:List of 2
  .. .. .. ..$ x: chr [1:4] "x=3722" "x=3723" "x=3724" "x=3725"
  .. .. .. ..$ y: chr [1:6] "y=2586" "y=2587" "y=2588" "y=2589" ...
  ..$ zoom : int 12
  ..- attr(*, "class")= chr "tile_grid"
 $ extent: num [1:4] 16385222 16415222 -5319119 -5269119</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1">eltiles <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get_tiles</span>(pt, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">buffer =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15000</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25000</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Preparing to download: 24 tiles at zoom = 12 from 
https://api.mapbox.com/v4/mapbox.satellite/</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb16-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gsub</span>(ceramic<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ceramic_cache</span>(), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>,  eltiles<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>files))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] "/api.mapbox.com/v4/mapbox.satellite/12/3722/2586.jpg"
[2] "/api.mapbox.com/v4/mapbox.satellite/12/3723/2586.jpg"
[3] "/api.mapbox.com/v4/mapbox.satellite/12/3724/2586.jpg"
[4] "/api.mapbox.com/v4/mapbox.satellite/12/3725/2586.jpg"
[5] "/api.mapbox.com/v4/mapbox.satellite/12/3722/2587.jpg"
[6] "/api.mapbox.com/v4/mapbox.satellite/12/3723/2587.jpg"</code></pre>
</div>
</div>
<p>And to see what tiles we have we can materialize their footprint in <a href="https://paleolimbot.github.io/wk/reference/rct.html">wk::rct()</a> form, this is way more efficient than having to use polygons.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb18-1">zoomtiles <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> ceramic<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ceramic_tiles</span>(imtiles<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>tiles<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>zoom)</span>
<span id="cb18-2"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## sub out the ones we just triggered</span></span>
<span id="cb18-3">zoomtiles <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> dplyr<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(zoomtiles, fullname <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%in%</span> imtiles<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>files)</span>
<span id="cb18-4">rc <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> ceramic<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tiles_to_polygon</span>(zoomtiles)</span>
<span id="cb18-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(rc)</span>
<span id="cb18-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ext</span>(im), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## see the image from above is not the tiles, but the buffer around a point</span></span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2023-04-22_gdal_image_tiles/index_files/figure-html/rct-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb19-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">read_tiles</span>(pt, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">buffer =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15000</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">25000</span>)))  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## but we can read thos tiles exactly</span></span></code></pre></div></div>
<div class="cell-output cell-output-stderr">
<pre><code>Preparing to download: 24 tiles at zoom = 12 from 
https://api.mapbox.com/v4/mapbox.satellite/</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb21-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(rc, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">border =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2023-04-22_gdal_image_tiles/index_files/figure-html/rct-2.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
</section>
<section id="diverse-query-inputs" class="level2">
<h2 class="anchored" data-anchor-id="diverse-query-inputs">Diverse query inputs</h2>
<p>Finally, we can use a point and buffer to get imagery, or we can use a spatial object, currently supported are objects from {geos}, {wk}, {terra}, {sf}, {sp}, {raster}, and {stars}.</p>
<p>Here’s an example.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb22-1">wkarea <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> wk<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rct</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xmin =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">5e6</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ymin =</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2e6</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xmax =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2e6</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ymax =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">3e6</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">crs =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"+proj=laea +lon_0=25 +lat_0=31"</span>)</span>
<span id="cb22-2">im2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cc_location</span>(wkarea)</span>
<span id="cb22-3">el2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cc_elevation</span>(wkarea)</span>
<span id="cb22-4">op <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">par</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mfcol =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb22-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(el2, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend =</span> F); <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(im2, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>); <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(el2, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grey.colors</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">128</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">legend =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2023-04-22_gdal_image_tiles/index_files/figure-html/wk-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb23-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">par</span>(op)</span></code></pre></div></div>
</div>
<p>(Please note that the result is still in Mercator, the query can be in any projection but we’re not matching that here, only its extent - ceramic version 0.8.0 is merely a stepping stone to some of the things we can do better with GDAL).</p>
<p>Previous versions of <code>cc_location()</code> and <code>cc_elevation()</code> were stuck with only ‘zoom’ and ‘max_tiles’ arguments, these make sense when you restrict exactly to the available tiles but when you just want a given area and a resolution, ‘dimension’ is more appropriate.</p>
<p>By default, the dimension is chosen relative to the graphics device. But, we can also specify exactly what we want. (Use zero for one of the dimensions to let the system figure out an appropriate size for the query you have).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb24-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cc_location</span>(wkarea)</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
dimensions  : 960, 776, 3  (nrow, ncol, nlyr)
resolution  : 7094.906, 7094.906  (x, y)
extent      : 4203326, 9708973, 105375.6, 6916485  (xmin, xmax, ymin, ymax)
coord. ref. : WGS 84 / Pseudo-Mercator (EPSG:3857) 
source(s)   : memory
colors RGB  : 1, 2, 3 
names       : red, green, blue 
min values  :   0,     0,    0 
max values  : 255,   255,  255 </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb26" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb26-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cc_location</span>(wkarea, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dimension =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">700</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
dimensions  : 700, 400, 3  (nrow, ncol, nlyr)
resolution  : 13766.3, 9730.157  (x, y)
extent      : 4203326, 9709847, 105375.6, 6916485  (xmin, xmax, ymin, ymax)
coord. ref. : WGS 84 / Pseudo-Mercator (EPSG:3857) 
source(s)   : memory
colors RGB  : 1, 2, 3 
names       : red, green, blue 
min values  :   0,     2,    0 
max values  : 255,   255,  255 </code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb28" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb28-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cc_location</span>(wkarea, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dimension =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1024</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>class       : SpatRaster 
dimensions  : 1267, 1024, 3  (nrow, ncol, nlyr)
resolution  : 5377.463, 5377.463  (x, y)
extent      : 4203326, 9709847, 103240.4, 6916485  (xmin, xmax, ymin, ymax)
coord. ref. : WGS 84 / Pseudo-Mercator (EPSG:3857) 
source(s)   : memory
colors RGB  : 1, 2, 3 
names       : red, green, blue 
min values  :   0,     1,    0 
max values  : 255,   255,  255 </code></pre>
</div>
</div>
</section>
<section id="some-other-improvements" class="level2">
<h2 class="anchored" data-anchor-id="some-other-improvements">Some other improvements</h2>
<ul>
<li>it’s faster, for loading reads data from image servers directly with the GDAL warper API</li>
<li>we have separation of tile downloading and interaction from raster loading via GDAL</li>
<li>we don’t materialize tiles as polygons, we have the tile description, or the compact <code>rct</code> representation</li>
<li>new functions <code>read_tiles()</code>, <code>unpack_rgb()</code>,</li>
</ul>
<p>See the full list of changes here: <a href="https://hypertidy.github.io/ceramic/news/index.html">https://hypertidy.github.io/ceramic/news/index.html</a>.</p>
<p>ceramic is my final CRAN package that had direct dependencies on rgdal, rgeos, or maptools - in some ways it was the most challenging for me and had loomed as a problem for some time. But, I’ve progressed my own tool kit well in the time and I learnt a lot with this update.</p>
<p>A future version will probably make the separation (are we tiles, or are we loading raster?) more complete, at any rate there are better ways to organize these things now. There are data sources, data readers and writers, data structures, and algorithms. This work is part of a family of tools that aims to make that orthogonality real and accessible.</p>


</section>

 ]]></description>
  <category>gdal</category>
  <category>r-packages</category>
  <category>ceramic</category>
  <guid>https://hypertidy.org/posts/2023-04-22_gdal_image_tiles/</guid>
  <pubDate>Sat, 22 Apr 2023 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Degenerate Rectilinear (WIP)</title>
  <dc:creator>Michael D. Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2022-12-09_netcdf-degenerate-rectilinear/</link>
  <description><![CDATA[ 






<p>There are a lot of problems when it comes to array representation in data formats and software. There is a whole family of complex issues with sometimes subtle or even cryptic causes, and here we focus on one particular detail.</p>
<section id="degenerate-rectilinear-coordinates" class="level2">
<h2 class="anchored" data-anchor-id="degenerate-rectilinear-coordinates">Degenerate Rectilinear Coordinates</h2>
<p>I have taken to saying this phrase to describe a particular situation in array handling. I get confused responses, or normally just no response or feedback on the term itself. I think it’s <em>extremely</em> important though. Python communities raced up to where R was a few years back and just sped on by without any nod to what R folks had learned, I think that’s a huge failure and I take it personally.</p>
<p>Here’s what it is. Let’s say we have a pretty low resolution grid of the world, we break up the entire range of longitude and latitude into intervals, 360 for <em>meridians</em> and 180 for <em>parallels</em>.</p>
<p>(This is neat because in whole number terms, this is exactly the right number).</p>
<p>So, define a grid, we make it a farily typical 1-degree-per-pixel grid of the entire globe flattened unceremoniously from an<br>
angular coordinate system “longitude and latitude” to one where we just plot those numbers in x,y on a flat plane.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## define a grid in -180,180 -90,90 (360x180)</span></span>
<span id="cb1-2">dm <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">360</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>)</span>
<span id="cb1-3">xlim <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>)</span>
<span id="cb1-4">ylim <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>)</span>
<span id="cb1-5"></span>
<span id="cb1-6"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## create a grid</span></span>
<span id="cb1-7">dat <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>L, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>L)[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">each =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">180</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">each =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span>)]</span>
<span id="cb1-8"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## we don't get much from this because 0,1 0,1</span></span>
<span id="cb1-9"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## and the world isn't 0,360 0,180 anyway (that would have been handy!)</span></span>
<span id="cb1-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#image(dat)</span></span>
<span id="cb1-11"></span>
<span id="cb1-12"></span>
<span id="cb1-13">xs <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq</span>(xlim[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], xlim[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length.out =</span> dm[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-14">ys <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq</span>(ylim[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], ylim[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length.out =</span> dm[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-15"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">image</span>(xs, ys, dat, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">asp =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-16">maps<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">add =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2022-12-09_netcdf-degenerate-rectilinear/index_files/figure-html/grid-stuff-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>What happened there? Well, <code>dat</code> is a matrix, a 2D array in R. It has 360 <em>rows</em> and 180 <em>columns</em> (but yes, we are treating the world map as if it had 360 columns, 180 rows - but that is not this blogpost). Just don’t question it right now, but be assured we are treating the world as having 360 unique whole number longitudes, and 180 unique whole number latitudes.</p>
<p>We can <code>image()</code> that, by which I mean draw a pixel map on the screen of all the values in the matrix as if they were a field of little rectangles.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">image</span>(dat)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2022-12-09_netcdf-degenerate-rectilinear/index_files/figure-html/image-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>But, that’s very boring because we don’t have any idea where anything is in 0,1 0,1 space.</p>
<p>What if we use <code>xlim</code> and <code>ylim</code>, these are <code>plot()</code> arguments in R (and exist in <code>image()</code> too).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">image</span>(dat, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xlim =</span> xlim, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ylim =</span> ylim)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2022-12-09_netcdf-degenerate-rectilinear/index_files/figure-html/xlim-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Ok that was a trick, our matrix is drawn as a tiny dot right at 0,0, because xlim/ylim is about the plot not the data.</p>
<p>No more tricks, <code>image()</code> has 3 arguments <code>x,y,z</code> for normal usage.</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">image</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> xs, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> ys, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">z =</span> dat, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">asp =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2022-12-09_netcdf-degenerate-rectilinear/index_files/figure-html/xyz-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>Why does that work? We essentially have an x coordinate and a y coordinate for every pixel <em>edge</em>. We have one for the left side of the leftmost pixel column, and the second one is the right side of the left most pixel, and so on. We used <code>dm[1] + 1</code> and <code>dm[2] + 1</code> up there exactly because we wanted xlim and ylim to be the very extremes of the data.</p>
<p>Cool, explained - a matrix has a coordinate array for each side, we plot it like a map with those. Done.</p>
</section>
<section id="we-are-so-so-so-not-done." class="level2">
<h2 class="anchored" data-anchor-id="we-are-so-so-so-not-done.">We are so so so not done.</h2>
<p>I’m not here to explain how <code>image()</code> works in R, but that’s kind of necessary because I want people who <em>don’t use R</em> to also read this.</p>
</section>
<section id="what-is-rectilinear" class="level2">
<h2 class="anchored" data-anchor-id="what-is-rectilinear">What is Rectilinear?</h2>
<p>Rectilinear means varying in one dimension. When applied to axis coordinates it just means you have a position along the axis for each step. These can vary in how big each step is, and that is exactly when we say it’s <em>rectilinear</em>, because otherwise it’s <em>regular</em>.</p>
<p>Our <code>ys</code> above are a regular list of coordinates, each one is exactly the same distance apart (distance in the frame we are using, forget about the actual Earth).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1">op <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">par</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mfrow =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(ys)</span>
<span id="cb5-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">range</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">diff</span>(ys))</span></code></pre></div></div>
<div class="cell-output cell-output-stdout">
<pre><code>[1] 1 1</code></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">diff</span>(ys))</span></code></pre></div></div>
<div class="cell-output-display">
<div>
<figure class="figure">
<p><img src="https://hypertidy.org/posts/2022-12-09_netcdf-degenerate-rectilinear/index_files/figure-html/ys-1.png" class="img-fluid figure-img" width="672"></p>
</figure>
</div>
</div>
</div>
<p>See? They just plod along with exactly the same delta between each, in this case the step size is 1 but it could be anything.</p>
</section>
<section id="what-do-you-mean-degenerate" class="level2">
<h2 class="anchored" data-anchor-id="what-do-you-mean-degenerate">What do you mean Degenerate?</h2>
<blockquote class="blockquote">
<p>Isn’t this a bad word, pejorative?</p>
</blockquote>
<p>Well no, it means something very specific.</p>
<p>It means even though there is a quite a lot of data, the <em>information</em> is confused or confounded. The required information could be expressed very compactly, but it’s actually obscured by the details.</p>


</section>

 ]]></description>
  <category>netcdf</category>
  <category>raster</category>
  <guid>https://hypertidy.org/posts/2022-12-09_netcdf-degenerate-rectilinear/</guid>
  <pubDate>Fri, 09 Dec 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>GDAL raster read/write by blocks</title>
  <dc:creator>Michael D. Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2022-04-05_gdal_raster_blocks/</link>
  <description><![CDATA[ 






<section id="read-and-write-raster-by-blocks." class="level2">
<h2 class="anchored" data-anchor-id="read-and-write-raster-by-blocks.">Read and write raster by blocks.</h2>
<p>A block is another word for a tile, a tile in a small-ish raster window within a larger raster. Tiles can be very clever, such as 256x256, they make a nice way to organize large data- keeping pieces of data that are nearby spatial nearby to each other in memory. There is a pair of functions internal to <a href="https://github.com/hypertidy/vapour">vapour</a> that will 1) read data from a raster block 2) write data to a raster block. At the moment only Float64 data is handled.</p>
</section>
<section id="tiles" class="level2">
<h2 class="anchored" data-anchor-id="tiles">Tiles</h2>
<p>Tiles are a way of organizing rasters, a tile may be 256x256, 512x512 (typically powers of 2 for sensible reasons), or they may be of higher dimensions 256x256x8 - this is really a private detail for a storage format, such as a file. The data values stored in a tile are a nother matter, these are like variables - we might have 1 variable (say elevation) stored in a double floating point value, or we might have 3 variables of byte values for storing an RGB image. These are independent concepts to the size of the tile, and strictly there may be no variables at all, just the abstract idea of the tiling.</p>
<p>Another kind of block, or tile is a the <em>scanline</em> of a raster. Imagine reading each row of the raster, from the top row to the bottom. Each line is its own kind of degenerate tile. We can read from a raster this way no matter what its internal tiling is, just software might be opening several tiles and reading just one line from each. So, best if we match our “tile attack” to the native structure of the data.</p>
<p>Here we find a large, tiled raster, obtain its internal tiling, and use that to <em>update</em> a copy of the same file.</p>
<p>Please note how we copy the source file, then write to that. There’s probably other software better suited to doing this atm, this post simply aims to air the topic a little in an R context.</p>
<p>Here we use only temporary files that we download, and copy as needed. In practice, you should set this up to work across different physical disks, and for better workflow we need the ability to open an empty file to write to (WIP).</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1">raster_url <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ftp://ftp.data.pgc.umn.edu/elev/dem/setsm/REMA/mosaic/v1.1/200m/REMA_200m_dem.tif"</span></span>
<span id="cb1-2"></span>
<span id="cb1-3">readfrom_file <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pattern =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"readfrom"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".tif"</span>)</span>
<span id="cb1-4">writeto_file <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tempfile</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">pattern =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"writeto"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fileext =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">".tif"</span>)</span>
<span id="cb1-5"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## file size is 1.3Gb</span></span>
<span id="cb1-6">curl<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">curl_download</span>(raster_url, readfrom_file)</span>
<span id="cb1-7"></span>
<span id="cb1-8"><span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## this now makes a copy of the 1.3Gb file, so we have two of them</span></span>
<span id="cb1-9">fs<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">file_copy</span>(readfrom_file, writeto_file)</span></code></pre></div></div>
</div>
<p>Now we want the tiling</p>
<div class="cell">
<div class="code-copy-outer-scaffold"><div class="sourceCode cell-code" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb2-1">info <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> vapour<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vapour_raster_info</span>(readfrom_file)</span>
<span id="cb2-2">tiling <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dimension =</span> info<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>dimXY, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tiles =</span> info<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>tilesXY)</span>
<span id="cb2-3">fac <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb2-4">fac <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> tiling<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>tiles</span>
<span id="cb2-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (tiling<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>tiles[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) {</span>
<span id="cb2-6">  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## let's take fac scanlines at a time</span></span>
<span id="cb2-7">  tiling<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>tiles[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> fac</span>
<span id="cb2-8">}</span>
<span id="cb2-9">calc_steps <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(dimension, tiles) {</span>
<span id="cb2-10">  bounds_x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, dimension, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">by =</span> tiles)</span>
<span id="cb2-11">  steps_x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span>  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(tiles, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length.out =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(bounds_x)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb2-12">  dangle_x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(steps_x) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span>dimension</span>
<span id="cb2-13">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (dangle_x <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) steps_x[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(steps_x)] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> steps_x[<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(steps_x)] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> dangle_x</span>
<span id="cb2-14">  </span>
<span id="cb2-15">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(bounds_x, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>), steps_x)</span>
<span id="cb2-16">}</span>
<span id="cb2-17">x_step <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">calc_steps</span>(tiling<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>dimension[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>], tiling<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>tiles[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb2-18">y_step <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">calc_steps</span>(tiling<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>dimension[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], tiling<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>tiles[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>])</span>
<span id="cb2-19">y_step</span>
<span id="cb2-20"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">system.time</span>({</span>
<span id="cb2-21"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (i <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq_along</span>(x_step[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]])) {</span>
<span id="cb2-22">  startx <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> x_step[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]][i]</span>
<span id="cb2-23">  countx <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> x_step[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]][i]</span>
<span id="cb2-24">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (j <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">seq_along</span>(y_step[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]])) {</span>
<span id="cb2-25">  starty <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> y_step[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]][j]</span>
<span id="cb2-26">  county <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> y_step[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>]][j]</span>
<span id="cb2-27">    </span>
<span id="cb2-28">  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## now read</span></span>
<span id="cb2-29">  offset <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(startx, starty)</span>
<span id="cb2-30">  dimension <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(countx, county)</span>
<span id="cb2-31">  vals <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> vapour<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vapour_read_raster_block</span>(readfrom_file, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">offset =</span> offset, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dimension =</span> dimension, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">band_output_type =</span> info<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>datatype, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">band =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)[[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>L]]</span>
<span id="cb2-32">  </span>
<span id="cb2-33">  <span class="do" style="color: #5E5E5E;
background-color: null;
font-style: italic;">## do something to the values</span></span>
<span id="cb2-34">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">any</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">na.omit</span>(vals) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> info<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>nodata_value)) {</span>
<span id="cb2-35">    vals <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> vals <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb2-36">    vapour<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vapour_write_raster_block</span>(writeto_file, vals, offset, dimension, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">band =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">overwrite =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb2-37">  }</span>
<span id="cb2-38">  }</span>
<span id="cb2-39">}</span></code></pre></div></div>
</div>


</section>

 ]]></description>
  <category>gdal</category>
  <category>raster</category>
  <guid>https://hypertidy.org/posts/2022-04-05_gdal_raster_blocks/</guid>
  <pubDate>Wed, 04 May 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>GDAL warper with R</title>
  <dc:creator>Michael D. Sumner</dc:creator>
  <link>https://hypertidy.org/posts/2022-04-25_gdalwarper-in-R/</link>
  <description><![CDATA[ 






<section id="an-unfinished-post" class="level2">
<h2 class="anchored" data-anchor-id="an-unfinished-post">An unfinished post</h2>
<p>There’s several meanings floating around when you say the “GDAL warper”. It can mean</p>
<ul>
<li>command-line <a href="https://gdal.org/apps">gdalwarp</a></li>
<li>the <em>rasterio</em> package in Python, and its <a href="https://rasterio.readthedocs.io/en/latest/topics/virtual-warping.html">WarpedVRT</a></li>
<li>the GDAL C++ API warping library</li>
</ul>
<p>We can also mean</p>
<ul>
<li>the <em>sf</em> package in R, and its <a href="https://r-spatial.github.io/sf/reference/gdal_utils.html">gdal_utils()</a> function</li>
<li>the <em>stars</em> package in R, and its <a href="https://r-spatial.github.io/stars/reference/st_warp.html">st_warp()</a> function</li>
<li>the <em>terra</em> package in R, and its <a href="https://rspatial.github.io/terra/reference/project.html">project()</a> function</li>
<li>the <a href="https://github.com/gearslaboratory/gdalUtils">gdalUtils</a> package in R</li>
<li>the <a href="https://github.com/JoshOBrien/gdalUtilities">gdalUtilities</a> package in R</li>
</ul>
<p>But, what I mean is the GDAL C++ API warping library.</p>
</section>
<section id="the-gdal-c-api-warping-library" class="level2">
<h2 class="anchored" data-anchor-id="the-gdal-c-api-warping-library">The GDAL C++ API warping library</h2>
<p>GDAL is complex. It deals with very many different formats, and has many tools. In terms of this post, it has very <em>low-level development facilities</em>, written in C++. This means you can usually go as deep as you need into a geospatial problem by writing C++ code against the library directly. Often you don’t need C++ and can use Python, and sometimes you can use R depending on what is exposed there. Sometimes you need to modify GDAL itself, and you can do anything you want then(!), which is how open source is supposed to work.</p>
<p>Key feature of the <em>gdalwarp_lib.cpp</em> <code>GDALWarp()</code> C++ function, versus the <code>GDALWarpDirect()</code>, <code>GDALWarpIndirect()</code> and the lower level <code>GDALWarpMulti()</code> and <code>GDALWarpImage()</code> functions.</p>
<p>When we use <em>gdalwarp_lib</em>, we get handling of multiple-zoom level sources without intervention on our own.</p>
<p>Most use cases I see of the warper facilities are for whole-sale conversion of large datasets, multiple input files converted to a another projection in a large output file or series of tiles.</p>
</section>
<section id="the-warper-is-also-a-generalized-rasterio" class="level2">
<h2 class="anchored" data-anchor-id="the-warper-is-also-a-generalized-rasterio">The warper is also a generalized RasterIO</h2>
<p>(rasterio is a famous python package for using GDAL’s raster facilities, it’s not what we mean here).</p>
<p>RasterIO is a C++ function in the GDAL library, its job is to take a source data set (i.e.&nbsp;a path to GeoTIFF) and to provide you with a window of pixels from that source. A window can be a subset, the entire raster, or a resampling (i.e.&nbsp;fewer pixels than native) of either the entire or a subset of the raster.</p>
<p>It’s really, cool and using it looks like this:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode c++ code-with-copy"><code class="sourceCode cpp"><span id="cb1-1">err <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> rasterBand<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span>RasterIO<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>GF_Read<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> </span>
<span id="cb1-2">                           Xoffset<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Yoffset<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> </span>
<span id="cb1-3">                           nXSize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> nYSize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-4">                           <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span>double_scanline<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">],</span> </span>
<span id="cb1-5">                           outXSize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> outYSize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> </span>
<span id="cb1-6">                           GDT_Float64<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-7">                           <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span>psExtraArg<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span></code></pre></div></div>
<p>There is <em>a lot</em> going on in that function call, but in short the key parts are (these are my argument-variable-names):</p>
<ul>
<li><code>rasterBand-&gt;RasterIO()</code> is the way we read a pixel values, we have a raster band and we call the member function RasterIO()</li>
<li><code>Xoffset</code>, <code>Yoffset</code> is the first column and row we should consider for reading (0,0 if we start at the top left corner)</li>
<li><code>nXSize</code>, <code>nYSize</code></li>
<li><code>outXSize</code>, <code>outYSize</code> is the dimension of the window we get out</li>
</ul>
<p>That last bits, the two kinds of <em>Size</em> is the magic, we can ask to start at a particular row,column and read out a given number of pixels in x and y. But, not only that we can specifiy where to end in the source. If nXSize and outXSize are not equal in value then we have asked for a resampling of the source “only read every <code>nXSize / outXSize</code> values in the x direction. If they are equal, just read every one. Note also that we might ask for an outX/YSize that is <em>larger</em> than the source nXSize/nYSize - and this would give us a resampling to higher resolution. This is really where the resampling algorithm comes in. ‘Nearest neighbour’ would give us copies of pixels, ‘Bilinear’ and interpolation between source pixels for new pixels in between. Other algorithms include ‘Cubic’, ‘Lanczos’, ‘Average’, ‘Sum’.</p>
<p>This is the key behind the fast and lazy reads provided by the terra and sf packages in R, this was originally available also in rgdal and raster made heavy use of it.</p>
<p>But, what is the offset and the size? We really want to think in geographic coordinates, and this is exactly what <code>crop()</code> does for example. We get a discretized crop, not an exact one because we only get to read by this raster-based mechanism - we are bound to the size and alignment of the source pixels.</p>
<p>Under the hood, functions like crop() do the following:</p>
<pre class="psuedorcode"><code>offsets/scale vs. xlim,ylim</code></pre>
<p>The other arguments in RasterIO.</p>
<ul>
<li><code>GF_Read</code> controls the mode we are into (read or write or update)</li>
<li><code>GDT_Float64</code> controls the type of data we get out (64 bit doubles here, GDAL will auto-convert if the source is different type)</li>
<li><code>0, 0, &amp;psExtraArg</code> are further details we won’t discuss (though, the way resampling is done is controlled in the extra args options).</li>
</ul>
<p>What are its limitations:</p>
<ul>
<li>only one source at a time, you can’t resample from multiple rasters at once (we are using offset/size indexing so the rasters must all be the same shape, you can read multiple bands)</li>
<li></li>
</ul>
<p>What is interesting about RasterIO vs.&nbsp;Warping is that we would never ever use warping for pure graphics. It doesn’t make sens</p>
</section>
<section id="enter-the-wutang-warper" class="level2">
<h2 class="anchored" data-anchor-id="enter-the-wutang-warper">Enter the <del>WuTang</del> Warper!</h2>
<p>Doing discretized extent raster math is boring. With the warper we don’t need to do it.</p>
<p>This is because the warper is for <em>changing projections</em>, this is an entire re-modelling of raster data. (in the 2000s it was possible to do but still quite slow and problematic, hence you have very slowly changing standards and perceptions of what is possible/normal/appropriate in software comunities etc.).</p>
<p>This is a global longlat data set, but we want a local projection so we adopt one by finding its specification.</p>
<pre><code>
</code></pre>
<p>If we were using RasterIO we’d have to do this kind of math to run the index function.</p>
<p>But with the warper, we can use an extent (but we still need to <em>align</em> it, or we won’t get what the RasterIO facility would faithfully give).</p>


</section>

 ]]></description>
  <category>news</category>
  <category>code</category>
  <guid>https://hypertidy.org/posts/2022-04-25_gdalwarper-in-R/</guid>
  <pubDate>Mon, 25 Apr 2022 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
