<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://9eo.org/feed.xml" rel="self" type="application/atom+xml" /><link href="https://9eo.org/" rel="alternate" type="text/html" /><updated>2026-08-09T19:31:04+00:00</updated><id>https://9eo.org/feed.xml</id><title type="html">Chris Holmes — 9eo.org</title><subtitle>Chris Holmes on cloud-native geospatial, open standards, and open ecosystems.</subtitle><author><name>Chris Holmes</name></author><entry><title type="html">Officially Announcing Geoparquet-io: a CLI/Python tool for GeoParquet</title><link href="https://9eo.org/blog/officially-announcing-geoparquet-io-a-cli-python-tool-for-geoparquet/" rel="alternate" type="text/html" title="Officially Announcing Geoparquet-io: a CLI/Python tool for GeoParquet" /><published>2026-03-09T00:00:00+00:00</published><updated>2026-03-09T00:00:00+00:00</updated><id>https://9eo.org/blog/officially-announcing-geoparquet-io-a-cli-python-tool-for-geoparquet</id><content type="html" xml:base="https://9eo.org/blog/officially-announcing-geoparquet-io-a-cli-python-tool-for-geoparquet/"><![CDATA[<p>I’m very proud we’ve reached the first 1.0 milestone for <a href="https://geoparquet.io">geoparquet-io</a>! We’ve published a <a href="https://cloudnativegeo.org/blog/2026/03/introducing-geoparquet-io/">blog post on cloudnativegeo.org</a> to announce it, so start there for what it is. The main goal is to make it easier to work with GeoParquet, which I am confident is the geospatial vector data format of the future.</p>

<p><img src="/assets/img/posts/officially-announcing-geoparquet-io-a-cli-python-tool-for-ge/1_5FD-IvBLRMgjw4m2te3YOQ.png" alt="" /></p>

<p>The project started in conjunction with writing up ‘<a href="https://github.com/opengeospatial/geoparquet/blob/main/format-specs/distributing-geoparquet.md">Best Practices for Distributing GeoParquet</a>’, to make it easy to check compliance with those practices, and then it grew to make it easy to implement those practices by default. In particular there were almost no tools to easily partition GeoParquet spatially across large datasets. The tool now <a href="https://geoparquet.io/guide/partition/">enables partitioning</a> by H3, S2, QuadKey, KD-Tree and recently A5. Plus it makes implementing <a href="https://medium.com/radiant-earth-insights/the-admin-partitioned-geoparquet-distribution-59f0ca1c6d96">admin-partitioning</a> super easy by automatically pulling in Overture and <a href="https://openknowledge.fao.org/items/aebf0333-a0e3-4177-9d4a-bb2472d0367e">GAUL boundaries</a> — see <a href="https://geoparquet.io/guide/partition/#by-admin-boundaries">the docs</a> for more info.</p>

<p>It’s further evolved to be my goto tool for working with GeoParquet, and indeed with any vector data, with both CLI and Python. I use it like a ‘cloud-native gdal/ogr’, to pull and transform data from any cloud bucket (or <a href="https://geoparquet.io/guide/extract/?h=bigquery#extracting-from-bigquery">BigQuery</a> and <a href="https://geoparquet.io/cli/extract/?h=arcgis#extract-arcgis">ArcGIS Feature Services</a>), and then upload it to other buckets, transforming it in a variety of ways along the way. Formatting a new dataset for sharing on <a href="https://www.linkedin.com/preload/#">Source Cooperative</a> used to take me a couple hours of DuckDB data munging, and now it’s a one or two liner and the download/upload time. All credit is due to the libraries we build on, especially DuckDB and GDAL/OGR, plus <a href="https://developmentseed.org/obstore/v0.2.0/">obstore</a> and PyArrow. And a big shout-out to <a href="https://geoarrow.org/">GeoArrow</a>, which is a key enabling format under the hood.</p>

<p>I’ll aim to highlight some of my favorite features in the coming weeks and months, and would love you to try it out and let me know how it goes. And a huge thanks goes to <a href="https://www.linkedin.com/preload/#">Nissim Lebovits</a> — without him it’d be a half finished project that shows promise, and I think it’s now has the potential to be a foundational tool for working with geospatial data. We had a great ‘relay race’, where I did the initial work, and when my efforts flagged he picked it up and made several weeks of awesome improvements. It inspired me to push on it more in December, and then as I got busy with Planet Labs (my day job) he was able to finish off all the core features and get us to a first real release.</p>

<p>Please try it out and let us know how it goes — our goal is to fix bugs plus take compelling suggestions and then call it 1.0.0 when it feels solid. And contributions are welcome! And no worries if you’re not an expert developer, just fire up your favorite AI coding tool, point it at the <a href="https://github.com/geoparquet/geoparquet-io/blob/main/CLAUDE.md">CLAUDE.md</a> file, and describe what you want. Test it out and then request to make a Pull Request — we’ll review and get it in the next release.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[I’m very proud we’ve reached the first 1.0 milestone for geoparquet-io! We’ve published a blog post on cloudnativegeo.org to announce it, so start there for what it is. The main goal is to make it easier to work with GeoParquet, which I am confident is the geospatial vector data format of the future.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://9eo.org/assets/img/posts/officially-announcing-geoparquet-io-a-cli-python-tool-for-ge/1_5FD-IvBLRMgjw4m2te3YOQ.png" /><media:content medium="image" url="https://9eo.org/assets/img/posts/officially-announcing-geoparquet-io-a-cli-python-tool-for-ge/1_5FD-IvBLRMgjw4m2te3YOQ.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Introducing geoparquet-io</title><link href="https://9eo.org/blog/introducing-geoparquet-io/" rel="alternate" type="text/html" title="Introducing geoparquet-io" /><published>2026-03-03T00:00:00+00:00</published><updated>2026-03-03T00:00:00+00:00</updated><id>https://9eo.org/blog/introducing-geoparquet-io</id><content type="html" xml:base="https://9eo.org/blog/introducing-geoparquet-io/"><![CDATA[<p>We’re releasing <code class="language-plaintext highlighter-rouge">geoparquet-io</code> (or, <code class="language-plaintext highlighter-rouge">gpio</code>), <a href="https://geoparquet.io/">an opinionated command-line tool</a> for converting, validating, and optimizing GeoParquet files.</p>

<p><code class="language-plaintext highlighter-rouge">gpio</code> is written in Python and uses DuckDB (with GDAL embedded for legacy format support), PyArrow, and <code class="language-plaintext highlighter-rouge">obstore</code> for fast operations on larger-than-memory datasets. By default, <code class="language-plaintext highlighter-rouge">gpio</code> enforces best practices: <code class="language-plaintext highlighter-rouge">bbox</code> columns, Hilbert ordering, ZSTD compression, and smart row group sizes.</p>

<h3 id="what-does-it-do">What does it do?</h3>

<p><code class="language-plaintext highlighter-rouge">gpio</code> offers a CLI and a <a href="https://en.wikipedia.org/wiki/Fluent_interface">fluent</a> Python API to help you create, validate, and optimize GeoParquet files. The CLI is designed for composability; commands chain together with Unix pipes, produce structured output with <code class="language-plaintext highlighter-rouge">--json</code> flags, and are predictable enough for use with AI coding assistants. The Python API keeps data in memory as Arrow tables, avoiding file I/O entirely and integrating directly into existing workflows.</p>

<h4 id="convert-with-optimized-defaults">Convert with optimized defaults</h4>

<p>With <code class="language-plaintext highlighter-rouge">gpio convert</code>, you can seamlessly convert from (and to) legacy formats like Shapefiles, GeoJSON, and GeoPackages:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># One command: converts, adds bbox, Hilbert-sorts, compresses
gpio convert buildings.shp buildings.parquet
</code></pre></div></div>

<p>By default, the resulting GeoParquet files are optimized for <a href="https://geoparquet.io/concepts/best-practices/">best practices</a>, including:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">bbox</code> column with covering metadata</li>
  <li>Hilbert curve spatial ordering</li>
  <li>ZSTD compression</li>
  <li>Appropriate row group sizes</li>
  <li>Automatic partitioning (when appropriate)</li>
</ul>

<p>These optimizations improve compression, I/O, and spatial query performance by 10–100x. Existing GeoParquet files can also be optimized in-place with <code class="language-plaintext highlighter-rouge">gpio check all --fix</code>.</p>

<h4 id="pipes-and-chains">Pipes and chains</h4>

<p>One of <code class="language-plaintext highlighter-rouge">gpio</code>’s strengths is composability. On the CLI, commands chain together with Unix pipes using Arrow IPC streaming—no intermediate files:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Extract Senegal from global admin boundaries, Hilbert-sort
gpio extract --bbox "-18,14,-11,18" \
 https://data.fieldmaps.io/edge-matched/humanitarian/intl/adm2_polygons.parquet | \
 gpio sort hilbert - senegal_adm2.parquet
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Chain enrichment steps together
gpio add bbox input.parquet | \
 gpio add h3 --resolution 9 - | \
 gpio sort hilbert - enriched.parquet
</code></pre></div></div>

<p>The Python API mirrors this with a fluent interface:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import geoparquet_io as gpio

gpio.read('buildings.parquet') \
 .add_bbox() \
 .add_h3(resolution=9) \
 .sort_hilbert() \
 .write('s3://bucket/optimized.parquet')
</code></pre></div></div>

<h4 id="large-files-and-cloud-workflows">Large files and cloud workflows</h4>

<p>Large files can be automatically partitioned based on a target row count. Partitioning strategies include H3, KD-tree, quadkey, admin boundaries (via Overture and GAUL), A5, and S2, as well as partitioning by an arbitrary existing column.</p>

<p>DuckDB handles all transformations with streaming SQL execution—memory stays constant regardless of file size. Its spatial extension reads legacy formats via GDAL’s <code class="language-plaintext highlighter-rouge">ST_Read</code>, and its httpfs extension handles remote file reads from S3, GCS, and Azure. PyArrow handles Parquet I/O and returns Arrow tables for seamless integration with pandas and Polars. For cloud writes, <code class="language-plaintext highlighter-rouge">obstore</code> enables streaming output to S3, GCS, and Azure.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Convert shapefile → auto-partition by H3 → write directly to S3
gpio convert large_roads.shp | \
 gpio partition h3 - s3://bucket/roads/ --auto --hive --profile prod
</code></pre></div></div>

<h4 id="why-not-gdal">Why not GDAL?</h4>

<p><code class="language-plaintext highlighter-rouge">gpio</code> uses GDAL under the hood—it’s what makes all the format conversions work. The difference is focus: GDAL is a general-purpose toolkit, while <code class="language-plaintext highlighter-rouge">gpio</code> is opinionated about cloud-native GeoParquet with sensible defaults.</p>

<p>One example is cloud storage. Remote reads and writes in <code class="language-plaintext highlighter-rouge">gpio</code> just work—pass a URL and go:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Just works - no /vsicurl prefix needed
gpio inspect https://data.fieldmaps.io/edge-matched/humanitarian/intl/adm2_polygons.parquet
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>Feature</th>
      <th>GDAL 3.9+</th>
      <th>gpio</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">bbox</code> column</td>
      <td>Yes (default)</td>
      <td>Yes</td>
    </tr>
    <tr>
      <td>Spatial sorting</td>
      <td>Optional, <code class="language-plaintext highlighter-rouge">bbox</code>-based</td>
      <td>Hilbert curve (better clustering)</td>
    </tr>
    <tr>
      <td>Sorting default</td>
      <td>OFF</td>
      <td>ON</td>
    </tr>
    <tr>
      <td>Sorting overhead</td>
      <td>Temp GeoPackage file</td>
      <td>In-memory or streaming</td>
    </tr>
    <tr>
      <td>Partitioning</td>
      <td>No</td>
      <td>H3, S2, A5, quadkey, KD-tree, admin</td>
    </tr>
    <tr>
      <td>Validation</td>
      <td>No</td>
      <td>Spec compliance checking</td>
    </tr>
    <tr>
      <td>Fix issues in-place</td>
      <td>No</td>
      <td><code class="language-plaintext highlighter-rouge">--fix</code> flags</td>
    </tr>
    <tr>
      <td>Read from S3/HTTP</td>
      <td><code class="language-plaintext highlighter-rouge">/vsis3/</code> or <code class="language-plaintext highlighter-rouge">/vsicurl/</code> prefix</td>
      <td>Just use the URL</td>
    </tr>
    <tr>
      <td>Write to S3</td>
      <td>Manual <code class="language-plaintext highlighter-rouge">/vsis3/</code> + env vars</td>
      <td>Direct path via <code class="language-plaintext highlighter-rouge">obstore</code></td>
    </tr>
    <tr>
      <td>Credential handling</td>
      <td>Manual configuration</td>
      <td>Automatic (AWS, GCP, Azure)</td>
    </tr>
  </tbody>
</table>

<h4 id="additional-features">Additional features</h4>

<ul>
  <li><code class="language-plaintext highlighter-rouge">bbox</code>-based subsetting of datasets for spatial filtering and extraction</li>
  <li>Service extraction from ArcGIS Feature Services and BigQuery tables → GeoParquet</li>
  <li>Easy inspection of metadata, row previews, and statistics</li>
  <li>PMTiles generation via the <code class="language-plaintext highlighter-rouge">gpio-pmtiles</code> plugin</li>
  <li>A <a href="https://github.com/geoparquet/geoparquet-io/tree/main/skills/geoparquet">Claude Code skill</a> for AI-assisted spatial data workflows</li>
</ul>

<p><code class="language-plaintext highlighter-rouge">gpio</code> supports GeoParquet 1.1, 2.0, and native Parquet geometry/geography types. For the full docs and examples, see <a href="https://geoparquet.io/">geoparquet.io</a>.</p>

<h3 id="how-can-i-help">How can I help?</h3>

<p><code class="language-plaintext highlighter-rouge">gpio</code> is currently released in <a href="https://pypi.org/project/geoparquet-io/">v1.0-beta</a>. At this stage, we’re looking for early users to help with stress-testing, bug reports, feature requests, and—of course—PRs. Check out the <a href="https://github.com/geoparquet/geoparquet-io/issues">open GitHub issues</a> to see what’s currently planned.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[We’re releasing geoparquet-io (or, gpio), an opinionated command-line tool for converting, validating, and optimizing GeoParquet files.]]></summary></entry><entry><title type="html">GeoParquet &amp;amp; Parquet geospatial types: A time of transition</title><link href="https://9eo.org/blog/geoparquet-parquet-geospatial-types-a-time-of-transition/" rel="alternate" type="text/html" title="GeoParquet &amp;amp; Parquet geospatial types: A time of transition" /><published>2025-09-26T00:00:00+00:00</published><updated>2025-09-26T00:00:00+00:00</updated><id>https://9eo.org/blog/geoparquet-parquet-geospatial-types-a-time-of-transition</id><content type="html" xml:base="https://9eo.org/blog/geoparquet-parquet-geospatial-types-a-time-of-transition/"><![CDATA[<p>Yesterday I read <a href="https://rednegra.net/">Sylvain Lesage</a>’s post <a href="https://rednegra.net/blog/20250925-parquet-with-geometry-type-is-not-geoparquet/">Parquet with GEOMETRY type is not GeoParquet</a> and started writing a reply for Linkedin but it ended up a bit too long to just be a comment, so I thought I’d just post it here as a blog. Overall it’s a great write-up and I appreciate that Sylvain took the time to share his understandings, and that he’s been diving deep to be able to support the geospatial + Parquet ecosystem. And most all of it is right on, but I wanted to provide some more context, and one tweak.</p>

<p>The only thing that I think is ‘off’ in the post is the timeline that says GeoParquet 1.1 was ‘published three months after the introduction of <code class="language-plaintext highlighter-rouge">GEOMETRY</code> and <code class="language-plaintext highlighter-rouge">GEOGRAPHY</code> in Parquet’. GeoParquet 1.1 was June 19th of 2024, while the geospatial types landed in Parquet core in March of 2025.</p>

<p><img src="/assets/img/posts/geoparquet-parquet-geospatial-types-a-time-of-transition/1_xhCaW6xO4wBdm0zDZQ9_KA.png" alt="" /></p>

<p>The original <a href="https://github.com/apache/parquet-format/pull/240">PARQUET-2471</a> discussion started about 1 month before the 1.1.0 release. And the main topic for the core GeoParquet group members after the 1.1.0 release was to help ensure that Parquet and Iceberg geospatial types would be compatible and work well for the geospatial world. The core GeoParquet people were all quite happy to see this — our goal was always to bring Geo to Parquet, and having it as a core type is really the end state we were working towards.</p>

<p>Most of the work of the GeoParquet community after 1.1.0 manifested as a focus on the <a href="https://medium.com/data-engineering-with-dremio/introducing-apache-iceberg-1-9-0-native-geospatial-support-enhanced-row-lineage-and-more-dead8950d391">Iceberg spec</a>, as there were many overlaps between the core Iceberg and Parquet communities and they chose to first figure out Iceberg. I’d say that the desire to get geospatial support into Iceberg ended up being the main driver for geospatial support in Parquet, because Iceberg wanted to be able to rely on ‘vanilla’ Parquet. So they really drove the changes, and made sure that the two specs were quite compatible.</p>

<p>Generally the GeoParquet group members were a bit more ‘behind the scenes’, trying to help educate the core Parquet and Iceberg teams and ensure that there’d be a good path forward from GeoParquet. Since the release many of the core Parquet and Iceberg geospatial implementations have been driven by people in the GeoParquet community, specifically the great team at <a href="https://wherobots.com/">Wherobots</a>.</p>

<p>We do have a rough plan for bringing GeoParquet and Parquet closer together, shared at a high level in <a href="https://cloudnativegeo.org/blog/2025/02/geoparquet-2.0-going-native/">GeoParquet 2.0: Going Native</a>. The latest thinking is that we’d do a GeoParquet 2.0, that would just have one geometry type — the Parquet one. We’d drop support for the Arrow geometry type, as having a native geo parquet geometry achieves one of the main goals behind the arrow geometry, which was native stats and not needing the bbox column. There are some small size advantages of GeoArrow relative to WKB, but it doesn’t seem worth having a whole other type. And GeoArrow has a great future, but there’s no compelling reason to try to get it into Parquet.</p>

<p>So the idea behind GeoParquet 2.0 is to help transition the GeoParquet implementations to just read and write Parquet. We’ll continue to write out the geo key metadata, so that implementations can read it, but as readers become able to just read native Parquet then many will likely just skip the geo metadata. We’ll also take bbox out of the spec, since it’s main purpose was to provide stats to drive optimized spatial queries, and that’s not needed since Parquet will provide stats on geo types. I hope that we’ll also be able to provide a list of libraries / tools that implement the specs so it’ll be easy to tell the status and we can all encourage people to upgrade.</p>

<p>There is one interesting metadata field that I don’t think will ever make sense to be in Parquet, but that the geo world does make extensive use of, and that’s the primary column. There’s no such concept in Parquet, but it’s used by many geospatial tools to determine which geometry column to render when there is more than one geometry. So I could see a world where the geo metadata of geoparquet sticks around for that purpose.</p>

<p>Unfortunately we’ve been quite slow to actually get a spec out the door. I’ve tended to be the one to drive the actual editing of the spec, and my summer was crazy busy trying to pull off a move to the Netherlands on top of vacations to see family that were planned ahead of the move, while trying to stay above water with my day job. Jia <a href="https://github.com/opengeospatial/geoparquet/issues/274">made an attempt</a> to run with it, but he’s also got a ton on his plate. I’m hoping in the next few months things will calm down and I can get to it.</p>

<p>But overall <a href="https://rednegra.net/blog/20250925-parquet-with-geometry-type-is-not-geoparquet/">the post</a> got most everything right, and our hope is to be able to provide clearer guidance in a GeoParquet 2.0 spec so that they are completely compatible and eventually it can just Parquet. Note that GDAL/OGR does have the ability to read/write Parquet geo types in version 3.12, and our hope is that when we have GeoParquet 2.0 it’ll make sense to have it write those by default.</p>

<p><img src="/assets/img/posts/geoparquet-parquet-geospatial-types-a-time-of-transition/1_0GixVSuOkA0jRL_R6l74Iw.png" alt="" /></p>

<p>Hopefully 2026 will be the year where we really start to see major datasets use Parquet GEOMETRY and GEOGRAPHY types. I believe most all the core Parquet libraries now support it, so the next step is really driving the geospatial libraries to start to not only use it, but to also write it by default. And the hope is that a GeoParquet 2.0 will help make that clear, and eventually all libraries will support the Parquet way so that GeoParquet metadata won’t even be necessary.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[Yesterday I read Sylvain Lesage’s post Parquet with GEOMETRY type is not GeoParquet and started writing a reply for Linkedin but it ended up a bit too long to just be a comment, so I thought I’d just post it here as a blog. Overall it’s a great write-up and I appreciate that Sylvain took the time to share his understandings, and that he’s been diving deep to be able to support the geospatial + Parquet ecosystem. And most all of it is right on, but I wanted to provide some more context, and one tweak.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://9eo.org/assets/img/posts/geoparquet-parquet-geospatial-types-a-time-of-transition/1_0GixVSuOkA0jRL_R6l74Iw.png" /><media:content medium="image" url="https://9eo.org/assets/img/posts/geoparquet-parquet-geospatial-types-a-time-of-transition/1_0GixVSuOkA0jRL_R6l74Iw.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">New Features of GeoParquet Downloader QGIS Plugin</title><link href="https://9eo.org/blog/new-features-of-geoparquet-downloader-qgis-plugin/" rel="alternate" type="text/html" title="New Features of GeoParquet Downloader QGIS Plugin" /><published>2025-02-20T00:00:00+00:00</published><updated>2025-02-20T00:00:00+00:00</updated><id>https://9eo.org/blog/new-features-of-geoparquet-downloader-qgis-plugin</id><content type="html" xml:base="https://9eo.org/blog/new-features-of-geoparquet-downloader-qgis-plugin/"><![CDATA[<p>It’s a true pleasure to share that in the time since my <a href="https://medium.com/radiant-earth-insights/a-deep-dive-into-geoparquet-downloader-qgis-plug-in-017c0b1facb1">last couple</a> of <a href="https://cholmes.medium.com/coding-qgis-plug-ins-with-ai-coding-tools-b04601427ec0">posts</a> about the <a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/">QGIS plugin to download GeoParquet data</a> there is now a real community of contributors making awesome advances to the plugin.</p>

<p><img src="/assets/img/posts/new-features-of-geoparquet-downloader-qgis-plugin/1_NrOftux7JzbrSSXuX5jckg.png" alt="" /></p>

<p>I got hooked on open source over 20 years ago when I wrote code and others showed up and made it better, and after a long hiatus from actual coding it’s been awesome to tap into that feeling again.</p>

<h2 id="latest-plugin-enhancements">Latest Plugin Enhancements</h2>

<p>So this time I get to mostly highlight the recent contributions from others. I did a couple smaller things too, but all the recent advances have been from a couple awesome contributors. These are spread across a three releases (0.4, 0.5 and 0.6), and you can get all the features by just searching for ‘GeoParquet Downloader’ in the QGIS plugin manager, and you should get 0.6 (if you don’t just refresh it).</p>

<p>The first enhancement was to improve the installation process, reporting to the user when DuckDB is getting downloaded and installed.</p>

<p><img src="/assets/img/posts/new-features-of-geoparquet-downloader-qgis-plugin/1_URZhFcSy3IPiMsLPYrth4Q.png" alt="" /></p>

<p>This was from <a href="https://github.com/merydian">Till Frankenbach</a>, and I think the installation process should now hopefully work for most people. He’s then followed that up with a number of great improvements, including the most visible change in the recent releases. We’ve <a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/issues/19">reduced from 3 buttons down to one</a>:</p>

<p><img src="/assets/img/posts/new-features-of-geoparquet-downloader-qgis-plugin/1_UuUno32b4P_UNUqJZvSPoQ.png" alt="" /></p>

<p>The default QGIS toolbar has a <em>lot</em> of buttons on it, and most people installing plugins have even more buttons to add, so that real estate becomes really precious. In the first iteration we had three buttons: one for Overture, one for Source Cooperative, and one for custom downloads. But they all went to the same dialog, though they started on different views. So we decided to just use one button. Till then followed up with a nice improvement <a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/pull/64">to save the state of the radio button</a>, so that if you’re usually using one of the tabs then it’ll be there when you go back to use it again.</p>

<p>Soon after Till started contributing we also had <a href="https://github.com/gisam">Sam Jackson</a> create a number of great improvements. The first was FlatGeobuf support — my second favorite vector format after GeoParquet, and one I use routinely.</p>

<p><img src="/assets/img/posts/new-features-of-geoparquet-downloader-qgis-plugin/1_YwbGG4PZxTQwJ3AB9wk8kA.png" alt="" /></p>

<p><em>More formats to save as</em></p>

<p>Then he added GeoJSON support, and even implemented my desire to properly warn people if they were going to download a ‘huge ass’ GeoJSON file, and ask them if they’d prefer a format that will handle things better.</p>

<screenshot of="" dialog="" for="" GeoJSON="">

I’ve had some bad experience with GeoJSON recently, when I’ve downloaded the entire Planet SkySat catalog, where once you get into gigabytes most tools will really struggle, QGIS included. But formats like GeoParquet and FlatGeobuf will be *much* smaller (like at least 20% the size, if not 10% or less), and they’ll also perform much better if they do get to tens of gigabytes.

He did also have the PR add shapefile, but after [some good discussion](https://github.com/cholmes/qgis_plugin_gpq_downloader/pull/62#issuecomment-2641324643) we decided that it’s ‘increasingly obsolete’ and we don’t want to support it. I’m still open to someone making the case that we *must* have it. But I think it’s pretty easy to use any of the other formats and then export to shapefile from QGIS. And then we don’t silently cut off the column names that are longer than 10 characters.

And Sam also added what I think is my favorite new feature — the ability to select multiple Overture layers and download them all at once:

![](https://miro.medium.com/v2/resize:fit:1400/1*mHkoj32uVsmTxn_Zk-yoQg.gif)

It makes it much easier to just get all the data you need for a given area, and it’s cool to just see all the data get added to the map as it comes in.

I also added a couple small improvements. I [upgraded](https://github.com/cholmes/qgis_plugin_gpq_downloader/pull/49) the Foursquare places data, and their [latest release](https://docs.foursquare.com/data-products/docs/fsq-os-places-release-notes#february-2025) included this snippet:

![](/assets/img/posts/new-features-of-geoparquet-downloader-qgis-plugin/1_43Cnd_vLJRmdi7v4e86mPQ.png)

These improvements are in-line with those I’ve [been writing up](https://github.com/opengeospatial/geoparquet/pull/254/files) to be best practices for large GeoParquet distributions (and I’ve been working on [making tools](https://medium.com/radiant-earth-insights/sharing-some-tools-for-working-with-geoparquet-fc5667b27373) to make it easier for people to test and implement). The performance of the Foursquare places on Hugging Face is *much* faster, down from over a minute to around ten seconds on my connection.

I also added a couple little fixes to make things more robust, which came from working with some interesting data. I was trying out some [fiboa field boundary data](https://github.com/fiboa/) and realized that columns like `admin:country_code` weren’t working right with geopackage data, so [I fixed that](https://github.com/cholmes/qgis_plugin_gpq_downloader/pull/51). And I’ve also been experimenting with NHD Data, trying out converting it to Parquet using best practices and [putting it on source.coop](https://source.coop/cholmes/nhd). And I realize that the code that uses the `bbox` column to accelerate querying only worked if the column was named bbox. But the spec allows any column name, you just have to specify the name in the metadata, and GDAL/OGR uses `geometry_bbox` if you column name is `geometry`. So I [fixed that too](https://github.com/cholmes/qgis_plugin_gpq_downloader/pull/55).

## What’s Next

So a huge thanks to Till and Sam, and I’m hoping they’ll continue to contribute great features. And hopefully someone will eventually surpass me in the commits leaderboard, as always happens in my most successful projects, as others most always prove better at making things robust and real than I do.

Till made a great contribution of refactoring the mess of code that comes from ‘my first qgis plugin’, which was the case for me with this one. I’m really excited about it, as it should enable us to make robust testing and hook it up to continuous integration, so that we can more confidently collaborate between multiple people. I just landed it on ‘main’, and we need to add back in a couple of Sam’s latest features before we release. And we’re also discussing if it makes sense to move it off my home repo, to an organization where it’d have a good home. Matt Travis, who was the very first outside contributor, also just recently [added a better workflow to create ‘releases’](https://github.com/cholmes/qgis_plugin_gpq_downloader/pull/73), and I hope to land that soon.

If you’re interested in diving in and contributing please do! There’s a good bit to help on the refactoring, like writing tests and making sure all the features work as they previously did. And I’ve still got a number of [‘good first issues’ tagged](https://github.com/cholmes/qgis_plugin_gpq_downloader/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22) in the issue tracker. Feel free to grab one, or add your own ideas to the issue tracker.
</screenshot>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[It’s a true pleasure to share that in the time since my last couple of posts about the QGIS plugin to download GeoParquet data there is now a real community of contributors making awesome advances to the plugin.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://9eo.org/assets/img/posts/new-features-of-geoparquet-downloader-qgis-plugin/1_NrOftux7JzbrSSXuX5jckg.png" /><media:content medium="image" url="https://9eo.org/assets/img/posts/new-features-of-geoparquet-downloader-qgis-plugin/1_NrOftux7JzbrSSXuX5jckg.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Collaborate on AI + Satellite data for agricultural field boundaries &amp;amp; insights!</title><link href="https://9eo.org/blog/collaborate-on-ai-satellite-data-for-agricultural-field-boundaries-insights/" rel="alternate" type="text/html" title="Collaborate on AI + Satellite data for agricultural field boundaries &amp;amp; insights!" /><published>2025-02-18T00:00:00+00:00</published><updated>2025-02-18T00:00:00+00:00</updated><id>https://9eo.org/blog/collaborate-on-ai-satellite-data-for-agricultural-field-boundaries-insights</id><content type="html" xml:base="https://9eo.org/blog/collaborate-on-ai-satellite-data-for-agricultural-field-boundaries-insights/"><![CDATA[<p>My main ‘side gig’ in addition to my ~3.5 days a week at <a href="https://www.planet.com/">Planet</a> is serving as an ‘industry fellow’ at the <a href="https://tgengine.org/">Taylor Geospatial Engine</a>. We had some great success with <a href="https://tgengine.org/innovation-bridge-2024-wrapped-a-collaboration-to-build-a-global-dataset-using-ai-and-satellite-imagery/">our first initiative</a>, which lead to <a href="https://fieldsofthe.world">Fields of The World</a> and <a href="https://github.com/fiboa">fiboa</a>.</p>

<p>I’m incredibly pumped that we’ll be launching ‘phase 2’ of the TGE initiative that lead to And I’d like to invite you to join us! Read the ful post from TGE at <a href="https://tgengine.org/tge-innovation-bridge-phase-2/">https://tgengine.org/tge-innovation-bridge-phase-2/</a>, and my take below.</p>

<p><img src="/assets/img/posts/collaborate-on-ai-satellite-data-for-agricultural-field-boun/1_SUsh4fmdc-2Rjcz6CObF7A.png" alt="" /></p>

<p><em>Come collaborate with me and Ivor!</em></p>

<p>The first initiative was one of the best collaborations I’ve ever been a part of. We <a href="https://tgengine.org/taylor-geospatial-engines-first-innovation-bridge/">kicked off</a> in St. Louis with ~20 people in person and a number of others participating remotely, representing 17 diverse organizations. And then a core group continued on for about 9 months, shipping an incredible amount of work that will likely be a foundation for many different projects for years to come. And everyone just worked together so well — at the wrap-up we all agreed that a main highlight was working with a group of people where there’s no drama and everyone’s contributing as best they can, towards a common goal that helps the world.</p>

<p>And I believe this iteration is going to be even more fun, as we have an incredible foundation to build on, and we’ll be working towards producing agricultural field boundaries using AI and satellite imagery for users who will really benefit. It should lead to some major strides towards a vision of a sustainable, global field boundary dataset that’s an open, digital public good.</p>

<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*5Nmpp0YGaxZEatYBNd2Jkw.gif" alt="" /></p>

<p><em>Results from the first initiative — over 118 million fields converted to the common fiboa standard.</em></p>

<p>We’ll be focusing on sustainable agricultural practices, reporting on deforestation regulations and food security, but we welcome anyone who is interested in high quality global field boundaries.</p>

<p>Read <a href="https://tgengine.org/tge-innovation-bridge-phase-2/">the post</a> for more information, and feel free to ask me any questions. We’ll be doing most all collaborations online, and are looking for individuals who want to build with us, and organizations to serve as ‘stakeholders’ to participate and give feedback.</p>

<p>All our events start with an in-person kickoff and sprint, and we’d love for you to join us in St. Louis (March 17–20). We may even have budget for a small number of travel grants. But even if you can’t make it in person do sign up <a href="https://forms.gle/Mf6qtk7KYxb6t1h6A">https://forms.gle/Mf6qtk7KYxb6t1h6A</a> and we’ll keep you in the loop. And you can also use that same for to express organizational interest in being a stakeholder.</p>

<p>And please spread this post to anyone working on anything related to field boundaries or agricultural insights. We firmly believe the best products come from bringing together a number of diverse perspectives and then aims for a simple, extensible solution that all can adapt. So we’d love to have you there and working with us.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[My main ‘side gig’ in addition to my ~3.5 days a week at Planet is serving as an ‘industry fellow’ at the Taylor Geospatial Engine. We had some great success with our first initiative, which lead to Fields of The World and fiboa.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://9eo.org/assets/img/posts/collaborate-on-ai-satellite-data-for-agricultural-field-boun/1_SUsh4fmdc-2Rjcz6CObF7A.png" /><media:content medium="image" url="https://9eo.org/assets/img/posts/collaborate-on-ai-satellite-data-for-agricultural-field-boun/1_SUsh4fmdc-2Rjcz6CObF7A.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Geoparquet 2.0: Going Native</title><link href="https://9eo.org/blog/geoparquet-2.0-going-native/" rel="alternate" type="text/html" title="Geoparquet 2.0: Going Native" /><published>2025-02-13T00:00:00+00:00</published><updated>2025-02-13T00:00:00+00:00</updated><id>https://9eo.org/blog/geoparquet-2.0-going-native</id><content type="html" xml:base="https://9eo.org/blog/geoparquet-2.0-going-native/"><![CDATA[<p><img src="/assets/img/posts/geoparquet-2.0-going-native/20250213-parquet_iceberg_new_geo_data_types.png" alt="New geo data types in Parquet and Iceberg" /></p>

<p>Seven months ago, we issued <a href="https://cloudnativegeo.org/blog/2024/07/embracing-geospatial-as-a-primary-data-type-a-call-to-action-for-the-data-community/">A Call to Action for the Data Community</a> to break down geospatial data silos and make GIS a core part of analytics. Today, we’re thrilled to announce two major developments that bring this vision closer to reality:</p>

<ul>
  <li>The Parquet specification has <a href="https://github.com/apache/parquet-format/blob/94b9d631aef332c78b8f1482fb032743a9c3c407/Geospatial.md?plain=1#L27">officially adopted</a> geospatial guidance, enabling native storage of GEOMETRY and GEOGRAPHY types</li>
  <li>Iceberg 3 now includes GEOMETRY and GEOGRAPHY as part of its <a href="https://github.com/apache/iceberg/blob/main/format/spec.md">official specification</a></li>
</ul>

<p>Now both Parquet and Iceberg support columns of type GEOMETRY or GEOGRAPHY just like INT32, INT64, FLOAT32, etc. columns! Yay! This is a landmark achievement for geospatial data! 🎉</p>

<h2 id="a-community-achievement">A Community Achievement</h2>

<p>First, a heartfelt thank you to everyone who contributed to this effort—engineers, early adopters, and advocates who pushed for geospatial data to be treated as a first-class citizen. This milestone wasn’t achieved overnight; it took years of collaboration across organizations and ecosystems. From the early days of GeoParquet 1.0 to today’s native Parquet support, this progress demonstrates the power of open-source community action.</p>

<h1 id="whats-changing-with-geoparquet-20">What’s Changing with GeoParquet 2.0</h1>

<p>The GeoParquet initiative has always aimed to make geospatial data “boringly interoperable.” With Parquet and Iceberg now supporting geometry types natively, GeoParquet is entering its next phase.</p>

<ul>
  <li>GeoParquet 1.0/1.1: Parquet files with additional metadata to “label” geometries/geographies</li>
  <li>GeoParquet 2.0: Regular Parquet files utilizing native GEOMETRY and GEOGRAPHY data types</li>
</ul>

<h2 id="recommendations-for-implementation">Recommendations for Implementation</h2>

<p>While native support represents the future of geospatial data storage, adoption will take time. We recommend:</p>

<ul>
  <li>Continuing with GeoParquet 1.1 for production systems until tools fully support Parquet’s native geospatial types. A few pioneer implementations have started.</li>
  <li>Planning for eventual migration to GeoParquet 2.0</li>
  <li>Following our upcoming migration guides and best practices and some discussions on exact differences between versions. In an ideal world we would make Geoparquet 2.0 files also be compatible with 1.1 and 1.0, stay tuned for that.</li>
</ul>

<h2 id="whats-next-for-the-spec">What’s Next for the Spec?</h2>

<p>While achieving native geospatial type support is a significant milestone, our work isn’t finished. Our immediate focus areas include:</p>

<ul>
  <li>Developing best practices for GeoParquet 2.0 implementation</li>
  <li>Creating clear transition guidelines from previous versions</li>
  <li>Establishing standards for CRS handling and performance optimization</li>
  <li>Continuing outreach and advocacy for widespread adoption</li>
</ul>

<h1 id="beyond-vector-data">Beyond Vector Data</h1>

<p>This is just the beginning of modernizing geospatial data storage. We’re already looking ahead to other types of geospatial data such as raster, point cloud, spatial indexes…</p>

<p>The journey to truly integrated geospatial analytics continues, but with GeoParquet 2.0, we’ve taken a major step forward. Stay tuned for more updates and guidance as we work toward making geospatial data a natural part of every analytics stack. And if you’d like to be more involved we’ll be working in the <a href="https://github.com/opengeospatial/geoparquet">GeoParquet GitHub repo</a>. We also run bi-weekly meetings on advancing geospatial in Parquet, Iceberg and Arrow, just join the <a href="https://groups.google.com/a/cloudnativegeo.org/g/geoparquet-community">geoparquet-community group</a> and you’ll be added to the calendar. And we’re also starting up a meeting for implementors of geospatial in Iceberg to share best practices and work through any issues.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Learn how to make QGIS Plugins with AI coding tools (video)</title><link href="https://9eo.org/blog/learn-how-to-make-qgis-plugins-with-ai-coding-tools-video/" rel="alternate" type="text/html" title="Learn how to make QGIS Plugins with AI coding tools (video)" /><published>2025-02-11T00:00:00+00:00</published><updated>2025-02-11T00:00:00+00:00</updated><id>https://9eo.org/blog/learn-how-to-make-qgis-plugins-with-ai-coding-tools-video</id><content type="html" xml:base="https://9eo.org/blog/learn-how-to-make-qgis-plugins-with-ai-coding-tools-video/"><![CDATA[<p>I recently <a href="https://cholmes.medium.com/coding-qgis-plug-ins-with-ai-coding-tools-b04601427ec0">published a post</a> on my experience using Cursor to create a <a href="https://medium.com/radiant-earth-insights/a-deep-dive-into-geoparquet-downloader-qgis-plug-in-017c0b1facb1">new QGIS plugin</a>. It seems to have inspired a few people, and so I decided to record a couple videos to try to show everyone exactly the process to do it. I’ve felt that being able to build things like QGIS Plugins has been life-changing, and so I just wanted to help demystify the process. And I’ve never really done any video recordings, but am inspired by <a href="https://www.youtube.com/@giswqs">Qiusheng Wu</a> and <a href="https://www.youtube.com/@MattForrest">Matt Forrest</a> so I thought I’d give it a try. I’m quite confident I’ll never get as good as they are, but it was fun to give it a try.</p>

<p><img src="/assets/img/posts/learn-how-to-make-qgis-plugins-with-ai-coding-tools-video/1_fioWcI-OQe56DNUVG711vg.png" alt="" /></p>

<p>The first video takes you all the way through making a first functional plugin. Lately I’ve been really enjoying using <a href="https://www.planet.com/products/planet-insights-platform/">Planet Insights Platform</a>, and so I decided to center the plugin around using the <a href="https://collections.sentinel-hub.com/planet-sandbox-data/">Planet Sandbox Data</a> that is available for anyone to explore. But it’s just an example, and indeed I encourage you to ‘scratch your own itch’ and build something that makes it easier to do something you often do.</p>

<p><a href="https://www.loom.com/embed/dfde7a06e6544d61a02f6eb042828f79?sid=9facb5f6-ec6e-42f3-a307-4899ef407d1e">https://www.loom.com/embed/dfde7a06e6544d61a02f6eb042828f79?sid=9facb5f6-ec6e-42f3-a307-4899ef407d1e</a></p>

<p>I then made a follow-up video on how to actually share your plugin with others. It goes a bit into how to use GitHub, plus how to first publish your plugin there. And then it also takes you through how to publish on the <a href="https://plugins.qgis.org/plugins/">QGIS Plugin Web Portal</a>, which in turn makes it so anyone can just install your plug-in directly from within QGIS.</p>

<p><a href="https://www.loom.com/embed/64d4c0258af8492b9dc6aaa9ae59cc01?sid=d0e87f3d-abcd-435f-a773-4226198ed14a">https://www.loom.com/embed/64d4c0258af8492b9dc6aaa9ae59cc01?sid=d0e87f3d-abcd-435f-a773-4226198ed14a</a></p>

<p>And you can even <a href="https://plugins.qgis.org/plugins/planet_sandbox_plugin/">see the plugin I made</a> online and install it into your QGIS!</p>

<p><img src="/assets/img/posts/learn-how-to-make-qgis-plugins-with-ai-coding-tools-video/1_GGc-JQ7Hd6oteR8dhQ0_Rw.png" alt="" /></p>

<p>But it’s still marked ‘experimental’ since it’s not that great (yet). I’m hoping to find time to expand it and make it a useful little tool.</p>

<p>If you’ve found these videos helpful do let me know — I’d likely be up to make more if there’s interest. Though I think I may pivot a bit to web applications, as I really like the potential there to really tailor applications to be used by anyone.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[I recently published a post on my experience using Cursor to create a new QGIS plugin. It seems to have inspired a few people, and so I decided to record a couple videos to try to show everyone exactly the process to do it. I’ve felt that being able to build things like QGIS Plugins has been life-changing, and so I just wanted to help demystify the process. And I’ve never really done any video recordings, but am inspired by Qiusheng Wu and Matt Forrest so I thought I’d give it a try. I’m quite confident I’ll never get as good as they are, but it was fun to give it a try.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://9eo.org/assets/img/posts/learn-how-to-make-qgis-plugins-with-ai-coding-tools-video/1_fioWcI-OQe56DNUVG711vg.png" /><media:content medium="image" url="https://9eo.org/assets/img/posts/learn-how-to-make-qgis-plugins-with-ai-coding-tools-video/1_fioWcI-OQe56DNUVG711vg.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">You, yes you, can help the Cloud Native Geospatial Movement!</title><link href="https://9eo.org/blog/you-yes-you-can-help-the-cloud-native-geospatial-movement/" rel="alternate" type="text/html" title="You, yes you, can help the Cloud Native Geospatial Movement!" /><published>2025-02-10T00:00:00+00:00</published><updated>2025-02-10T00:00:00+00:00</updated><id>https://9eo.org/blog/you-yes-you-can-help-the-cloud-native-geospatial-movement</id><content type="html" xml:base="https://9eo.org/blog/you-yes-you-can-help-the-cloud-native-geospatial-movement/"><![CDATA[<p>Have you benefitted from Cloud-Optimized GeoTIFF’s? SpatioTemporal Asset Catalogs? Zarr, COPC or GeoParquet? Not just the formats, but the whole ecosystem of tools and data around it? Well I’d like to present you with an incredibly easy opportunity to ‘pay it forward’ and help build and expand the movement. And all you have to do is attend a conference! One that should be a totally awesome experience, the <a href="https://2025-ut.cloudnativegeo.org/">first in-person CNG Conference</a>, from April 30th to May 2nd.</p>

<p><img src="/assets/img/posts/you-yes-you-can-help-the-cloud-native-geospatial-movement/1_zLVrw5ArMrSucwA82MRGpQ.png" alt="" /></p>

<p>I have big dreams for this conference, as my hope is that it can expand in the next few years to become a truly vendor-neutral gathering for anyone working in and around geospatial data. To be one of those conferences that has the critical mass where you know ‘everyone’ you want to talk to will be there. In North America there’s really only two options for this: Esri UC and GeoINT. Both are incredible events, but Esri UC controls their guest list (as they should…) and GeoINT is very focused on defense and intel (as it should…). I think a third would go beyond ‘GIS’ and beyond the strong core military-oriented use cases that do provide the core economic engine for the industry today. It’d be a big tent that is welcoming of anyone working with geospatial data on any use case, at any scale, with any tool.</p>

<p>The first CNG Conference will be the biggest Cloud Native Geo event ever, but it will not be a <em>huge</em> affair, and it’s really important that we ‘sell it out’ and demonstrate the momentum to get to larger venues and larger sponsors for the next few years. And I believe it’s going to be an awesome gathering of all types of people who like to nerd out on solving real world challenges with geospatial data and insights. You’ll certainly learn some new stuff, and make connections that you’ll likely reap rewards from for years. The cloud-native communities are a collection of tribes working on related problems, and this is going to be the first true in person gathering that combines the different tribes, to borrow from how <a href="https://foss4g.org/">FOSS4G</a> is often described. FOSS4G is one of my favorite conferences, and my hope is we can get that same energy, but expand from open source software to be inclusive of any commercial software, and also to be more centered around data (and standards).</p>

<p>So please, <a href="https://lu.ma/cng2025">buy your ticket soon</a> and join us! And don’t worry if you’re not already deep in Cloud-Native Geospatial, or even barely know what it is, as a major goal is to help everyone learn. One of the three primary tracks is ‘On-ramp to Cloud-Native Geospatial Data’.</p>

<p><img src="/assets/img/posts/you-yes-you-can-help-the-cloud-native-geospatial-movement/1_rteb05UEh2Hsc1KOguRnEA.png" alt="" /></p>

<p><em>From <a href="https://2025-ut.cloudnativegeo.org/">https://2025-ut.cloudnativegeo.org/</a></em></p>

<p>There’s a great line-up of speakers, with more coming. And if you want to give back ‘more’ than just attending, please <a href="https://events.cloudnativegeo.org/cng2025-presentations">apply to present</a> and share successes you’ve had with Cloud Native Geo. If you work for or lead in an organization that has benefitted from CNG then please try get them to <a href="https://2025-ut.cloudnativegeo.org/sponsor">sponsor</a>. There are a number of benefits your organization gets from sponsoring, and not just at the event — it also comes with commercial membership to Cloud Native Geo Forum. This gets 8 individual memberships to CNG, plus a blog post on CNG website, and a speaking slot at an event. And I’m pretty sure if they come in as sponsors soon then that spot will be at the CNG Conference. It will be a great opportunity for your products/work to reach an influential audience, in a vendor-neutral environment. If you need any help convincing your organization to sponsor feel free to get in touch — I’m happy to help.</p>

<p>I’m excited about how this event will build momentum for the CNG Forum. It’s a consolidation of this movement into a bit more of a formal structure, with a great mission:</p>

<p><img src="/assets/img/posts/you-yes-you-can-help-the-cloud-native-geospatial-movement/1_KJftYw0bGVykqjklsrfFpg.png" alt="" /></p>

<p>The vision is to make geospatial data easier to access to use, and to grow the resources being invested to make that happen. It’s all under the Radiant Earth non-profit (501(c)3), which means that all revenue from membership and the conference (after covering costs) goes back into strengthening the community, bringing people together more, and fulfilling the vision.</p>

<p>So please <a href="https://lu.ma/cng2025">buy your ticket</a>, <a href="https://cloudnativegeo.org/join/">join the CNG forum</a>, <a href="https://events.cloudnativegeo.org/cng2025-presentations">present</a> and/or <a href="https://2025-ut.cloudnativegeo.org/sponsor">sponsor</a>. It will make a real difference, and I promise it will be a valuable and fun time in Utah.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[Have you benefitted from Cloud-Optimized GeoTIFF’s? SpatioTemporal Asset Catalogs? Zarr, COPC or GeoParquet? Not just the formats, but the whole ecosystem of tools and data around it? Well I’d like to present you with an incredibly easy opportunity to ‘pay it forward’ and help build and expand the movement. And all you have to do is attend a conference! One that should be a totally awesome experience, the first in-person CNG Conference, from April 30th to May 2nd.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://9eo.org/assets/img/posts/you-yes-you-can-help-the-cloud-native-geospatial-movement/1_zLVrw5ArMrSucwA82MRGpQ.png" /><media:content medium="image" url="https://9eo.org/assets/img/posts/you-yes-you-can-help-the-cloud-native-geospatial-movement/1_zLVrw5ArMrSucwA82MRGpQ.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Coding QGIS Plug-ins with AI coding tools</title><link href="https://9eo.org/blog/coding-qgis-plug-ins-with-ai-coding-tools/" rel="alternate" type="text/html" title="Coding QGIS Plug-ins with AI coding tools" /><published>2025-02-03T00:00:00+00:00</published><updated>2025-02-03T00:00:00+00:00</updated><id>https://9eo.org/blog/coding-qgis-plug-ins-with-ai-coding-tools</id><content type="html" xml:base="https://9eo.org/blog/coding-qgis-plug-ins-with-ai-coding-tools/"><![CDATA[<p>Following up on <a href="https://cholmes.medium.com/a-deep-dive-into-geoparquet-downloader-qgis-plug-in-017c0b1facb1">my last post</a>, I wanted to share some more details about the experience of using AI tools to code a <a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/">plugin for QGIS</a>, one that has seen some reasonable success, with over 2000 downloads in the past couple of months. My hope is to inspire others to make their own QGIS plugins and other geospatial tools, as I think more people doing AI-assisted coding has the potential to accelerate the momentum of the open source ecosystem.</p>

<p><img src="/assets/img/posts/coding-qgis-plug-ins-with-ai-coding-tools/1_Nz9e-DlqZdqFe-QHuHya4w.png" alt="" /></p>

<p><em>Cursor &amp; QGIS — awesome together :)</em></p>

<h2 id="can-you-really-code-a-qgis-plug-in-just-using-ai-tools">Can you really code a QGIS plug-in just using AI tools?</h2>

<p>Before we dig in I want to give everyone who is not a coder some encouragement to jump in and try things out. The quick answer is yes! You can code a QGIS plug-in even if you’re not a software developer. I’m sure you’ve seen the videos of people building cool things with AI tools, but it can still be hard to actually dive into it. For me the most important thing is to have a real problem you’re trying to solve. I could never follow those tutorials about ‘making a e-commerce store’ since I just don’t care about making an e-commerce store. I could follow the instructions, and get a generic thing, but I wouldn’t actually learn much. But when I’m trying to solve something specific that I care about it becomes much easier, because I really want the result.</p>

<p>I’m guessing you have some interest in geospatial in general and likely QGIS specifically if you’re reading this post. So the top thing I’d encourage you to do is to think about something you’d like QGIS to do that it doesn’t do for you today. This could just be a common workflow that you do all the time, or it could be some cool new functionality you always wish it had. And if you want to start even easier than just think about some processing of files that doesn’t even use QGIS — doing a basic python program that processes geospatial data with GDAL/OGR or GeoPandas can be even easier than a QGIS plugin.</p>

<p>After I made the GeoParquet downloader QGIS plug-in I had one of the best developers I know reply with a <a href="https://bsky.app/profile/mohr.ws/post/3lcebxd7zcs2t">post on bluesky</a>:</p>

<p><img src="/assets/img/posts/coding-qgis-plug-ins-with-ai-coding-tools/1_jA2IhXTuUy0WhZGyTqxVcg.png" alt="" /></p>

<p>I responded that 99.5% was AI-coded — so Matthias still has to believe me when I downplay my coding skills :) I don’t actually write the code, I just instruct the AI what I want it to do. I am learning more, and at this point I perhaps could write more of the code, but I’d rather just get it right the first time than try to memorize the syntax or struggle when I mistype something.</p>

<p>Now, I am not without any coding experience, and I’ll share my background a bit below, so I’m not yet ready to say ‘anyone can make a QGIS plugin’. I do think there is a decent chance that the process of breaking problems down and iterating through debugging is likely a skill I retain that may not come instantly to someone with no coding experience. But I do think if you have a problem you want to solve and you are resilient then you can just use the chat interface to teach you everything you need to know — you just need to keep asking and aim to really understand it. No matter what you’ll learn something, and if it doesn’t work out today I’m confident that it won’t be long until anyone who is motivated can do it.</p>

<p>Since I started writing this article I did get a <a href="https://www.linkedin.com/feed/update/urn:li:activity:7286049681271320579/">great proof point</a> on how easy it can be:</p>

<p><img src="/assets/img/posts/coding-qgis-plug-ins-with-ai-coding-tools/1_wyVEdE4tVUZ87yD8KwyVOw.png" alt="" /></p>

<h2 id="my-background">My Background</h2>

<p>I wanted to share a bit more about my background, and how I have recently started programming again thanks to the power of AI tools. I started my career coding, serving as the first lead developer of <a href="https://geoserver.org">GeoServer</a> for a couple of years in 2002, learning a ton from a number of great early members of the GeoTools community — shout outs to Ian <a href="https://github.com/ischneider">Schneider</a>, <a href="https://github.com/groldan">Gabriel Roldan</a> and <a href="https://github.com/aaime">Andrea Aime</a>! But after less than two years I realized they were all better software engineers than me, so I (eventually) recruited all of them to work on GeoServer at OpenGeo, and I focused on community building (the fun part) and bringing in money to support the software (the less fun part, but a really essential one).</p>

<p>I found it really hard to do ‘both’, as coding was too fun and satisfying — I know of few other things you can get paid for where the day just flies by. So I cut myself from coding in order to figure out all the other things needed to turn a growing open source project into a successful ‘business’. It ended up being a lot of fun, and I learned a ton, but I did miss the act of creating software. After a few years, when I felt confident in things like ‘product management’, ‘business development’ and ‘managing’, I’d periodically try to code and it’d just be too frustrating. It’d take a couple hours just to get a few lines of barely working code down, as I’d first need to get my coding environment all set up, and then would struggle to remember basic syntax and would need to look up almost every call.</p>

<p>When ChatGPT came out it had been over 20 years since I’d seriously programmed, and I had under two years of total experience coding professionally. My first couple of attempts to use ChatGPT to code didn’t quite work, as it’d just get too much wrong to be worth it. But sometime around GPT-3 I wanted to <a href="https://cholmes.medium.com/cloud-native-geo-data-explorations-with-google-open-buildings-e7dcde0559ca">explore Google Open Buildings &amp; GeoParquet</a> and had my first success. As long as I gave it small, constrained tasks to process the data with GDAL/OGR or GeoPandas it’d do amazing. 75% of the time it’d give me a perfect result, 20% it’d get a bug but you could feed it the error and in 2–3 iterations it’d fix it. And 5% of the time it’d get stuck in a loop, trying to fix things but going back to the previous bad way, which was frustrating. But overall it felt ‘worth it’ and I was able to make far faster progress using it than not. Since then I’ve been taking on more ambitious projects as the LLM’s and tooling around them has improved, and this year I’m aiming to spend at *least *50% of my time doing AI-assisted software development.</p>

<h2 id="my-set-up">My Set Up</h2>

<p>Before I dig into my experiences building the plugin I first want to share a bit about what tools are working for me, and some ideas and recommendations for how to think about what to use. The first thing I will say is that if you’re coding you should absolutely pay instead of using the free versions. If you’re less experienced with coding then it’s harder to work through things when the LLM doesn’t get things right. And the latest models that you get from paying absolutely get things right more often. It’s hard to put a number on how much better they are, but my feeling is that even if it’s only 10–20% better then it can easily save you hours of frustration, and that having that frustration when you’re getting started can easily turn you off from pushing further. And in my experience it’s more than 20% better.</p>

<p>My primary tool for these types of projects is <a href="https://www.cursor.com/">Cursor</a>. I only discovered it after a number of months successfully coding with ChatGPT, but a number of great coders I work with said it was amazing, so I thought I’d give it a shot. I believe it’s the fastest I’ve gone from starting a free trial to deciding ‘yup, I’m absolutely going to pay for this’ — it was maybe 15–20 minutes. The key feature that moved me to buy is actually different than the one more advanced coders love. It’s the ability to generate ‘diffs’ on the code that is generated by the LLM.</p>

<p><img src="/assets/img/posts/coding-qgis-plug-ins-with-ai-coding-tools/1_EIjEDtvbSBToNbNmTlAAYw.png" alt="" /></p>

<p><em>Diffs in Cursor for the latest improvements for my plugin</em></p>

<p>You can see in the right side panel the code that gets generated by an LLM. It’s totally fine if you just take that code and use it, but if there’s a problem or if you want to add something to the code then it gets challenging to use the whole set of code. You either have to copy and paste the entire file each time, or you have to successfully spot every difference and copy over each line right. And in this example the LLM isn’t even generating the full file, you can see it says <code class="language-plaintext highlighter-rouge">// ... existing code ... </code>so when that happens you’d need to figure out the right place to insert your new code. Before cursor I had that go wrong enough times that I’d ask the LLM to <em>always</em> generate the entire code, and then would paste the whole thing in each time. But then it’d get unweildly if you had a larger file, and also would slow things down since it’d spend a lot of time reprinting things.</p>

<p>This ability to apply diffs was an absolute game changer in my productivity — you can have confidence that every difference between the new code and the current code is addressed. Now, this isn’t to say that the diffs are always great. Sometimes it messes things up, or redoes things that you don’t want it to redo. But the UI of cursor is such that you can go through each of the diffs and say hit ‘y’ or ’n’ to accept it.</p>

<p>I often will scan each diff to make sure it’s doing what I thought it would. Though often I’ll just apply the whole thing, run the file, see the results, and then just go back to examine the diffs if things didn’t work.</p>

<p>The other killer feature of Cursor, that expert coders love, is the ability to give the LLM the context of your entire codebase, not just the file you’re looking at. The QGIS plugin I made is a single file, so for this project that feature doesn’t matter much, but for my <a href="https://github.com/cholmes/geoparquet-tools">geoparquet-tools</a> project I’m trying to do some better programming practices of splitting things up, and it’s been great for that.</p>

<p>Cursor lets you select from different models, and it’s got access to most of the latest. It doesn’t have the most expensive ones, like o1, and you have some limit for how many calls you get to the latest. But you can enter an API key for your own LLM account if you want to have it use truly the latest models. I actually switched for this project to Claude Sonnet 3.5, and it’s now my go to within Cursor. I can’t say that it’s definitely better — it’s just that 4o was frustrating me and getting things wrong, and when I tried switching the model to Claude it nailed it, and I’ve just stuck with it since. The ‘best’ here is constantly changing, so it’s worth checking out leaderboards (like <a href="https://aider.chat/docs/leaderboards/">aider.chat</a> or <a href="https://livebench.ai/">https://livebench.ai/</a>).</p>

<p>And I also will use ChatGPT Plus occasionally. I don’t think it’s essential — if you want to stick with one tool I’d go with Cursor (or <a href="https://codeium.com/windsurf">Windsurf</a>, which Evan found great success with and it may be even better for those with little experience coding). You can use it’s chat interface to ask questions, just like you would with ChatGPT — you don’t have to have it give you code responses, you can just ask for background, how to do things, etc. For coding stuff I tend to use the o1 model, and I mostly just use it for things were the other models just are looped in bad answers (more about that later). And it can be useful for planning things out and suggesting an overall approach to things.</p>

<p>The explosion of useful tools in this space is incredible, so I imagine there will be some new tool set that’s even better before too long. I plan to re-evaluate every six months or so, but encourage you to just try things out. Just do please pay for one, and you’ll likely have a better experience. Perhaps in a couple years maybe the free tools will be more than sufficient, but that’s not the case right now.</p>

<h2 id="coding-the-geoparquet-downloader-plugin">Coding the geoparquet downloader plugin</h2>

<p>To be honest my successful coding of this plugin was a bit of a lark. As I mentioned in the previous post I’d been intimidated by QGIS coding — I think I looked into it once before and it was just too many things to learn. So I really wasn’t expecting it to work, as my AI successes in the past had all been on very discrete things, and when I tried to get too ambitious it’d get challenging. But I just asked it to make a plugin, and then asked how I run it to try it out, and it started working.</p>

<p>The key is to never ask for too much — always start small, and just ask for one more thing each time. Sometimes I’d try to ask for many things at once, and it’d get some of them, but then it was a lot more difficult to try to fix the one thing that was wrong, since too many things were introduced at once. So it’s best to just keep asking for tiny little improvements.</p>

<p>To start I just asked for a plugin that popped up a dialog to make sure that worked. I had to ask how to actually install it — you just zip it up and then you can ‘install zip file’ from the extensions folder, or you can copy it directly into the plugins folder. Then I just added more and more — first I hardcoded a specific Overture file to download, and got it so DuckDB ran the query to get it. I had experience with DuckDB so I knew what I wanted from the query, but LLM’s are really great at SQL, so it’s easy to have it form the query for you.</p>

<p>One thing I have learned is that the LLM’s do much, much better on well-established, well-documented tools. SQL is just incredible — I like SQL, but was never great at it, and now I feel like it’s a super power. I can just ask the LLM for all kinds of crazy analysis and it’ll make these complicated joins that do exactly what I want. GDAL/OGR and GeoPandas are both quite good. But often newer features aren’t as solid, as the LLM may have been trained before they became widely documented and used. But you can instruct it about them, usually I just paste the documentation in directly. So if you want to use some totally obscure tool then it can struggle — though always with a positive helpful and confident attitude, it just makes up whatever you want.</p>

<p>But I was pleasantly surprised to find the QGIS plugins is something they all know well. Which makes a lot of sense, as there is a very large ecosystem, so lots of code and documentation for it to learn from. Through out the process it’d come through with good answers to things that I thought it might struggle with. One example was that it become clear that my plugin was taking over the whole program, and QGIS would just stop doing anything else. So I just asked if there was a way to make it so that didn’t happen, and it said that I could run worker threads and then came up with all the code needed for that. I also wanted to open multiple dialogs, links you could click on, and reporting errors out in different ways, and it did all that well. Overall it handled most everything QGIS related with ease.</p>

<p><img src="/assets/img/posts/coding-qgis-plug-ins-with-ai-coding-tools/1_De7M5c7O9vsXZHTaEBwGFA.png" alt="" /></p>

<p><em>My plugin, now available to anyone directly through their QGIS!</em></p>

<p>I will admit that I definitely do not understand most of what’s going on. With my smaller python programs I’d always have a good sense of what was happening in most lines, but the structure of these is more complicated. But the cool thing is that you can just highlight code and ask it to explain it if you want to understand more.</p>

<h3 id="the-struggles">The struggles</h3>

<p>My biggest struggles came with getting the dependencies right. DuckDB is essential for everything to work, but it’s not installed in QGIS by default. The <a href="https://plugins.qgis.org/plugins/qduckdb/">QDuckDB</a> plugin did an amazing job packaging things for Windows, so for those users I recommended that they just install QDuckDB, and then I linked to their instructions for other users. For the next release we tried to make it so the plugin would automatically install DuckDB using PIP, and that was definitely my single biggest struggle. Matt Travis, the first outside contributor to the project, coded what looked like a great way to do it. But then it didn’t work on one operating system, so I tried another way, and that didn’t work on mine, and it was just a pain. I’m still not sure what is the ‘ideal’ route for QGIS plugins to get dependencies in, it seems to be that users are asked to manually get their python environments updated.</p>

<p>I would occasionally have the LLM get stuck in a frustrating loop. Usually it’d get the code right immediately, but about 15% of the time it’d generate an error. But the awesome thing is that usually you can just paste in the error that results back into the chat and it’ll realize what is wrong and fix it. But occasionally it’ll give you a fix that won’t work, and you paste the error back in and then its next fix will suggest something different that also doesn’t work. And when you paste those results back in it’ll give you the first fix again. And then it’ll just loop between the two things, getting it wrong each time. I’ve found the best thing to do in this situation is to try another LLM. Cursor makes it easy to just swap in a different model, going between Claude and OpenAI. These days I usually just jump to o1 through ChatGPT Plus, as it very often gets it right — I just paste in my full code and the problem (<em>and right before publishing: o3-mini-high seems even better, and can be called directly from Cursor)</em>.</p>

<p>The other way to get out of the loop is to to suggest different approaches to the problem. Sometimes that means going back a few steps and directing it in a different way. Sometimes it means reading up online on other options that people use (I suppose you could also try to ask the LLM for other approaches, I think sometimes that has worked for me). Occasionally I will bug my coder friends, and the nice thing is that usually you just need the name of a different approach from them and the LLM will take it from there.</p>

<h2 id="come-on-in-the-waters-fine">Come on in, the water’s fine!</h2>

<p>So overall the experience of coding my first QGIS plugin was incredibly pleasant. It didn’t all happen ‘automatically’, we’re not (yet) there with these tools, and I suspect they’re most always going to require some guidance and iteration. But the challenges were all surmountable. I think the biggest thing these tools do is really make the learning curve a lot less steep. You’re still going to have to dig in and learn quite a bit, but you get much more immediate positive feedback. More recently I started another plugin and I will admit that it was more of a challenge, and I got seriously stuck for more than two hours, so I suspect there’s still some luck involved to have it be easy.</p>

<p>In the time between writing this and actually posting it I have hit bigger bugs than I have before — one took almost 4 hours to resolve, and the other was almost two hours. It reminded me of the frustrating parts of coding, and is proof that it’s all not magical. But it is <em>so</em> satisfying when you get past one of these bugs. I hope everyone finds early success without hitting frustrating bugs, but at some point you will hit frustrations, and I encourage you to be hard headed and just keep on trying until you get it working.</p>

<p>So I do want to encourage everyone who has read this far to at least <em>try</em>. Get a trial of Cursor or Windsurf and set some time aside. Be sure to start with a problem you actually want to solve, something that will make your life easier. And just keep trying even if at first you don’t succeed, it is currentlye easier than it’s ever been, and that will only improve. It doesn’t have to be QGIS, but it’s a nice platform to build upon. I’m also going to try to record some videos of building a plugin, to help demystify things even more.</p>

<p>If you do build something that’s useful to you then <em>please</em> share the code on GitHub and publish to the QGIS plugin repository. Chances are it might be useful to someone else. I know it can be scary, I still remember the first time my boss told me I needed to push my code to be open source. But honestly no one is looking at your code and judging it — they’re just psyched to have something potentially useful, and psyched that you contributed something positive to the world.</p>

<p>Good luck! And if you want to dive in but don’t have a project that immediatly jumps to mind I do welcome all AI-assisted contributions to my <a href="https://github.com/cholmes/qgis_plugin_gpq_downloader">QGIS plugin</a>. I tagged a number of ‘<a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22">good first issues</a>’ and can easily add more, and am more than happy to offer advice &amp; help to anyone looking to contribute.</p>

<p><img src="/assets/img/posts/coding-qgis-plug-ins-with-ai-coding-tools/1_R1Pz7cmumt9wRvvjT4o9fg.png" alt="" /></p>

<p>Also, if you’re not signed up already do come to the <a href="https://2025-ut.cloudnativegeo.org/">Cloud Native Geo conference in Utah</a>. It’s going to be awesome.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[Following up on my last post, I wanted to share some more details about the experience of using AI tools to code a plugin for QGIS, one that has seen some reasonable success, with over 2000 downloads in the past couple of months. My hope is to inspire others to make their own QGIS plugins and other geospatial tools, as I think more people doing AI-assisted coding has the potential to accelerate the momentum of the open source ecosystem.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://9eo.org/assets/img/posts/coding-qgis-plug-ins-with-ai-coding-tools/1_Nz9e-DlqZdqFe-QHuHya4w.png" /><media:content medium="image" url="https://9eo.org/assets/img/posts/coding-qgis-plug-ins-with-ai-coding-tools/1_Nz9e-DlqZdqFe-QHuHya4w.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Exploring Field Boundary Data with LLMs</title><link href="https://9eo.org/blog/exploring-field-boundary-data-with-llms/" rel="alternate" type="text/html" title="Exploring Field Boundary Data with LLMs" /><published>2025-01-29T00:00:00+00:00</published><updated>2025-01-29T00:00:00+00:00</updated><id>https://9eo.org/blog/exploring-field-boundary-data-with-llms</id><content type="html" xml:base="https://9eo.org/blog/exploring-field-boundary-data-with-llms/"><![CDATA[<p><em>(Originally posted at <a href="https://tgengine.org/exploring-field-boundary-data-with-llms/">tgengine.org/exploring-field-boundary-data-with-llms</a> — including here to have a record of my writing)</em></p>

<p>A couple of months ago a great group of people gathered in St. Louis and participated in the final workshop and showcase for the first <a href="https://tgengine.org/innovation-bridge/">TGE Innovation Bridge</a>, focused on <a href="https://tgengine.org/taylor-geospatial-engines-first-innovation-bridge/">agricultural field boundaries</a>. It was an awesome event, and a great wrap up to an amazing set of work that launched <a href="https://github.com/fiboa">fiboa</a> and <a href="https://tgengine.org/introducing-fields-of-the-world">Fields of The World</a>. There will be more communication about the event, but the goal of this post is to share a bit of a deep dive on a demo that was pulled together to demonstrate the power of the schema-level interoperability that fiboa enables.</p>

<h2 id="connecting-llms-to-fiboa">Connecting LLM’s to fiboa</h2>

<p>The core demo was a chat interface to 3 different <a href="https://fiboa.org/map">fiboa datasets</a>, one for each of the Baltic countries, powered by OpenAI’s o1-mini.</p>

<p><a href="https://www.loom.com/embed/4cb5a4de6e3c4f4b9ccddde5bea6920d?sid=a824a416-e7e1-4134-9274-e5f43f39d96d">https://www.loom.com/embed/4cb5a4de6e3c4f4b9ccddde5bea6920d?sid=a824a416-e7e1-4134-9274-e5f43f39d96d</a></p>

<p>A second demo was created with three years of data in the Netherlands, to demonstrate asking questions over time:</p>

<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*zGQ3DcIfgFq-J59BKIpilA.gif" alt="" /></p>

<p>The total amount of time spent to build the demo was no more than 20 or so hours, and it’s more to demonstrate the concept than to be a robust interface. But it’s still quite cool that you can just ask questions and get relevant answers, and really explore the data in a way that you previously had to be a SQL expert to do. With more time we could have combined the two demos into a single interface, and made it able to handle a wider variety of data, but with the time constraints the goal was just to show the potential.</p>

<p>The experience from building the demo shows that it should be feasible to evolve it to be robust enough to handle any fiboa dataset, and the latest advances in AI, like Anthorpic’s <a href="https://modelcontextprotocol.io/">Model Context Protocol</a>, will make the technical bits ever easier. A further post will explore the tech stack that powers this demo, and there will likely be lots of innovation in the tech that enables people to ‘talk to data’. But aligning on standards for what is ‘in’ the data, like fiboa does for field boundaires, will always be necessary.</p>

<p>Anyone is welcome to play with the two demos, and to see the code that we used to build them, you can find them on huggingface:</p>

<ul>
  <li>
    <p>[<strong>Fiboa Baltics Demo](https://huggingface.co/spaces/cholmes/fiboa-demo)</strong></p>
  </li>
  <li>
    <p>[<strong>Fiboa Netherlands Demo](https://huggingface.co/spaces/cholmes/fiboa-nl)</strong></p>
  </li>
</ul>

<p>As mentioned above, they are not very robust, and they are on weak machines, so be warned they may not work that well. But if you are excited by the potential it’d be great to hear what types of questions you’re interested in asking. The demos will continue to evolve — the things at the top of the list are a satellite imagery base layer, responses with more human language (ie not always just the SQL table), state and county aggregations, and the ability to upload any fiboa file.</p>

<h2 id="enabling-llms-with-standard-data-schemas">Enabling LLM’s with standard data schemas</h2>

<p>Beyond just field boundaries and fiboa, this demo aims to show that aligning datasets at the schema level is a powerful way to enable LLM’s to interact with data.</p>

<p>It’s not all that difficult to train an LLM to understand a single dataset, but the LLM’s are not capable enough to understand every single potential choice that users might make for their attribute naming and how they represent their data.</p>

<p>A few months ago a Custom GPT to interface to a San Francisco building dataset was put together, and it seemed to work:</p>

<p><img src="/assets/img/posts/exploring-field-boundary-data-with-llms/1_KOg4LM1nvEkxWHQeRFyRAg.png" alt="" /></p>

<p>But on further inspection it was clear that it misunderstood the data, and used the wrong attribute to query on height. It wouldn’t be much work to teach it about the San Francisco dataset, but then asking questions across multiple datasets would require custom training for each dataset. It seems clear that the more variability you introduce the more likely the LLM is to make mistakes.</p>

<p>So instead of letting everyone just define all their own attributes and hoping the LLM’s can ‘figure it out’ and seamlessly translate queries across countless definitions, a much better model is to align on data standards — to build consensus that <a href="https://docs.overturemaps.org/schema/reference/buildings/building/">building height should be in attribute called ‘height</a>’ and it should be in meters, like how how Overture is standardizing their data:</p>

<p><img src="/assets/img/posts/exploring-field-boundary-data-with-llms/1_cixE6wyrbl2f1gr5ET-4KA.png" alt="" /></p>

<p>You can then train the LLM on a single standard, and indeed invest effort in documenting that standard really well so every attribute is fully explained, and then build precise converters that get all potential data into a common schema. In time just documenting the core data schema well in human language plus a structured format (JSON, etc) will likely make it easy for LLM’s to generate those precise converters with ease. And indeed as the schema gets used and has more tutorials and tools and implementations then future LLM’s trained on newer public data will likely just start to know the schema and be able to understand how to query the data without additional training.</p>

<p>This can start to build a really virtuous cycle where a few powerful tools built with LLM’s can help spur people to invest in building and translating their data into common data schemas, and when more more data that gets in the common schemas it’ll spur more powerful tools (built by LLM’s &amp; people) that will in turn motivate more data to be standardized. These sets of standardized can in turn be used as training data for using AI to more accurately generate more data, like the Fields of The World <a href="https://source.coop/kerner-lab/fields-of-the-world">Benchmark Dataset</a>.</p>

<p>So the goal is to continue to refine this demo to become a tool that can work with any fiboa dataset, and use it to continue that virtuous cycle for field boundary data, getting more data in the data schema, and spurring a wide array of tools that let data contributors get much more value out of their data.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[(Originally posted at tgengine.org/exploring-field-boundary-data-with-llms — including here to have a record of my writing)]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://miro.medium.com/v2/resize:fit:1400/1*zGQ3DcIfgFq-J59BKIpilA.gif" /><media:content medium="image" url="https://miro.medium.com/v2/resize:fit:1400/1*zGQ3DcIfgFq-J59BKIpilA.gif" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">A deep dive into GeoParquet Downloader QGIS Plug-in</title><link href="https://9eo.org/blog/a-deep-dive-into-geoparquet-downloader-qgis-plug-in/" rel="alternate" type="text/html" title="A deep dive into GeoParquet Downloader QGIS Plug-in" /><published>2025-01-27T00:00:00+00:00</published><updated>2025-01-27T00:00:00+00:00</updated><id>https://9eo.org/blog/a-deep-dive-into-geoparquet-downloader-qgis-plug-in</id><content type="html" xml:base="https://9eo.org/blog/a-deep-dive-into-geoparquet-downloader-qgis-plug-in/"><![CDATA[<p>Last month I released <a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/">my first QGIS plug-in</a>, and promised I’d write an in-depth post about it. I’ll give an overview and dig into some of the motivations, and then I’ll put the details of my experience of coding with AI in its own follow up post.</p>

<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*yGagLpKLbIiH0b4tMzhmtA.png" alt="" /></p>

<h2 id="background"><strong>Background</strong></h2>

<p>I’ve been a long time QGIS user, though am very far from an expert — I mostly open different files and visualize them. I’ve never been able to afford an Esri license, so it’s QGIS all the way for me. And I’ve always loved the plugin ecosystem: the fact that many people worldwide are adding all kinds of functionality so that anyone can customize it to their needs is just awesome, and a testament to the power of open source. There’s still things Esri can do better, but we’re now at the point where there’s a lot of things QGIS can do better.</p>

<p>I also recently have ‘become a coder’ again, thanks to the power of AI tools. I’ll dive into more of the experience in my next post, but it meant that I could tackle something like a new QGIS plugin as a (long) weekend project. I started it just to see if I could, and things kept working, so I kept pushing on.</p>

<h2 id="motivations"><strong>Motivations</strong></h2>

<p>One of my latest missions is to advance GeoParquet as a format to fulfill the promise of <a href="https://cholmes.medium.com/an-overview-of-cloud-native-vector-c223845638e0">cloud-native vector</a> data, enabling organizations to get most all the functionality of a Web Features Service like <a href="https://geoserver.org/">GeoServer </a>by simply putting up their data as GeoParquet on a cloud bucket. I was so excited when Overture Maps embraced the format, but they also got a good bit of pushback for not having a ‘download’ button and using traditional data formats.</p>

<p>I was confident that if things evolved right it shouldn’t be hard to give traditional GIS users an even better experience of getting the data, since you can easily stream just what you need and transform it on the fly. A big shout out to Jake Wasserman and Overture for really stepping in to help push forward the evolution, proposing the key <a href="https://github.com/opengeospatial/geoparquet/blob/v1.1.0/format-specs/geoparquet.md#covering">bbox covering</a> and upgrading Overture to fully implement it.</p>

<p>A few months ago it became possible to use <a href="https://medium.com/radiant-earth-insights/duckdb-the-indispensable-geospatial-tool-you-didnt-know-you-were-missing-5fe11c5633e5">my favorite new geospatial tool</a>, DuckDB (or a number of other tools), with any Overture data layer to select a spatial subset of the whole world and download just the area you cared about in tens of seconds and often faster.</p>

<p><img src="/assets/img/posts/a-deep-dive-into-geoparquet-downloader-qgis-plug-in/1_xmHYkSUfgoPxVTmffA7HcQ.png" alt="" /></p>

<p><em>Getting Overture data today</em></p>

<p>Overture has great docs for using DuckDB, and they also built a nice command-line tool, but you still have to be tech-oriented and inclined to use a terminal. They did also build a nice <a href="https://explore.overturemaps.org/#15/38.90678/-77.03649">Explorer app</a>, that lets you download small amounts of data. But if you wanted more than a few megabytes worth of data to load up in QGIS there still weren’t great options for those who do want to learn to use a terminal and CLI tools.</p>

<p>So I decided to see how far the LLM coding tools had come and figure out if I’d be able to write a QGIS plugin. QGIS development had always intimidated me: I think I had one class in college that did desktop UI’s and I found it hard to grok. But my first attempt got something on my screen and within twenty minutes I had a reasonable kernel of functionality. I ended up able to get the vast majority of it working as I wanted to in a few days during the week of Thanksgiving — coding on the plane and sneaking in mini-sprints between family time.</p>

<p>So my goal was to make it as easy as possible for any QGIS user to download Overture, and indeed to not force GeoParquet on them: with the plugin you can easily request data as a GeoPackage. And I also wanted to make it easy to download any GeoParquet data, so that the tool isn’t just for Overture data, but enables anyone distributing their data as GeoParquet to easily enable QGIS users to get their data.</p>

<h2 id="plugin-overview"><strong>Plugin Overview</strong></h2>

<p>This animated gif probably gives the quickest overview to understand what the plugin enables:</p>

<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*1g-eCgpuagS-zZKAns-5tw.gif" alt="" /></p>

<p>The idea is to make it simple to just download GeoParquet data into a local copy in QGIS. It currently just uses the bounds of the viewport, but I hope a future version can give more options to draw a geometry or use other QGIS layers (<a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/issues/10">contributors welcome!</a>).</p>

<p>Currently there are a few pre-set layers. All of Overture is obviously available, and it’s got a dedicated button to open its panel. And <a href="https://source.coop">Source Cooperative</a> is easily the other largest single collection of GeoParquet files (and if you have open data you’d like to make available on Source then you can likely host it there for free — just reach out!). I still need to add more Source Cooperative files, indeed I hope to make a complete <a href="https://github.com/fiboa">fiboa</a> &amp; <a href="https://fieldsofthe.world">Fields of The World</a> section, as we’ve got a lot of data up there.</p>

<p><img src="/assets/img/posts/a-deep-dive-into-geoparquet-downloader-qgis-plug-in/1_E7PTHGypolxC4gNSV9ALnw.png" alt="" /></p>

<p>And after the initial release I added a Hugging Face section, which for now is just the <a href="https://huggingface.co/datasets/foursquare/fsq-os-places">Foursquare OS Places</a> dataset, but it seems like more will be added (I contemplated adding the various embeddings datasets but wasn’t sure of the practical use case of making it easier to download). And you can also just enter any custom URL to a GeoParquet online.</p>

<p>Right now you can download data as GeoParquet, DuckDB and GeoPackage. GeoPackage will always work, as all QGIS installations support it. GeoParquet should work on most more recent installations, though <a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/wiki/Installing-GeoParquet-Support-in-QGIS">OS/X is less straightforward</a> (But I am working with <a href="http://opengis.ch">opengis.ch</a> to try to make this better!). DuckDB right now won’t load in QGIS, but I’m starting to collaborate with <a href="https://plugins.qgis.org/plugins/qduckdb/">QDuckDB</a> plugin team and I <em>think</em> I should be able to render the results of a DuckDB download if their plugin is installed.</p>

<p><img src="/assets/img/posts/a-deep-dive-into-geoparquet-downloader-qgis-plug-in/1_zJ2Scdy9QDtOBKcWiMZ2vA.png" alt="" /></p>

<p><em>The awesome QDuckDB plugin</em></p>

<p>And that team also deserves a shout-out. Their plugin was the one I looked at the most for how to structure things, and they are working to solve a core issue that I need for the plugin to work well — install DuckDB. DuckDB is the core engine that powers the entire thing, as everything I did was just wrappers to all of its amazing functionality.</p>

<h3 id="installing-the-plugin">Installing the plugin</h3>

<p>If this seems like something that’s useful to you it should be pretty easy to install the plugin. Just open the plugin manager and search for ‘GeoParquet’.</p>

<p><img src="/assets/img/posts/a-deep-dive-into-geoparquet-downloader-qgis-plug-in/1_Y5SwqVRnw413m6VrU_7cvQ.gif" alt="" /></p>

<p>I think the installation process is now pretty good. Matt Travis, the first outside contributor to the plugin, worked to get it to automatically install. I think it works most of the time, but I’m not 100% sure — it attempts to automatically use ‘pip’ to install DuckDB, but I’d guess that’s sometimes blocked. My hope is GDAL 3.11 <a href="https://github.com/OSGeo/gdal/pull/11459">with ADBC support</a> will enable a more ‘native’ DuckDB experience in QGIS, and that we’ll be able to include it as a core dependency.</p>

<p><img src="/assets/img/posts/a-deep-dive-into-geoparquet-downloader-qgis-plug-in/1_qGxMlfQn2gm-O3_ZhKApnQ.png" alt="" /></p>

<p><em>ADBC GDAL/OGR docs — coming in 3.11!</em></p>

<h2 id="future-features"><strong>Future Features</strong></h2>

<p>It is on the list for the plugin to <a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/issues">add support for more formats</a> (which should be a <a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22">great first issue</a> for any potential contributors) — FlatGeobuf is the top of my list, and File Geodatabase also sounds interesting. If there’s other formats desired just add them to the issue. I’m pretty opposed to adding Shapefile since it comes with <a href="http://switchfromshapefile.org/">so many limitations</a> that I think will get in the way of using Overture and other data, but if someone wants to make a PR and really needs it I’m sure I’d accept it.</p>

<p>I’ve got a number of ideas in the <a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/issues">issue tracker,</a> but I’d love to hear from others what they’d like to see. I don’t see this being a huge project, and indeed I could see one route of ‘success’ being that this type of functionality is more incorporated into the QGIS core. It’s a bit of a different workflow, that I actually think would also be interesting with traditional geospatial servers (WFS, ArcGIS Feature Service, etc). Instead of having QGIS try to stream data on each screen change just have the user manually ‘check out’ the data that they want — download it and then display / use that local version.</p>

<p>The top future ideas that I’m thinking about are:</p>

<ul>
  <li>
    <p>User configurable data sources, instead of me maintaining the list and manually updating when new ones come. I could see making it so an organization can make their own ‘tab’ and even button that has a bunch of layers that are relevant to their users. And to make it easy for a user to add their own layers, instead of having to enter each manually.</p>
  </li>
  <li>
    <p>More download options beyond just the viewport, as mentioned above.</p>
  </li>
  <li>
    <p>Better integration with STAC, though that will need data providers to implement. But ideally you could point at a STAC catalog and get the list of Geoparquet layers to download.</p>
  </li>
  <li>
    <p>Ability to point at a GeoParquet file and see how well it implements <a href="https://github.com/opengeospatial/geoparquet/pull/254">(in-progress) GeoParquet best practices</a>. I started <a href="https://github.com/cholmes/geoparquet-tools">a library to help do this</a>, so hope to finish that and wrap it in this QGIS plugin (or maybe it will be a standalone plugin).</p>
  </li>
</ul>

<h2 id="whats-next">What’s Next</h2>

<p>I’d love more help on this project, and my hope is to make it an experiment of AI-enabled open source. Since I wrote 99% of it with AI coding tools I’m very happy to have all the contributions be similarly made, so if you’ve been wondering about how it all works and want a practical introduction that creates code for others to use then please take an issue!</p>

<p>I had thought I would also share more about my experience of using AI coding tools to create it, but since this post is already quite long I’ll break it up into its own. I’ve also got a number of insights into the state of public GeoParquet files and how we can improve the ecosystem of public data, but I’ll also save that for its own post. So stay tuned! I hope to publish both of those posts soon.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[Last month I released my first QGIS plug-in, and promised I’d write an in-depth post about it. I’ll give an overview and dig into some of the motivations, and then I’ll put the details of my experience of coding with AI in its own follow up post.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://miro.medium.com/v2/resize:fit:1400/1*yGagLpKLbIiH0b4tMzhmtA.png" /><media:content medium="image" url="https://miro.medium.com/v2/resize:fit:1400/1*yGagLpKLbIiH0b4tMzhmtA.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Sharing some tools for working with GeoParquet</title><link href="https://9eo.org/blog/sharing-some-tools-for-working-with-geoparquet/" rel="alternate" type="text/html" title="Sharing some tools for working with GeoParquet" /><published>2025-01-22T00:00:00+00:00</published><updated>2025-01-22T00:00:00+00:00</updated><id>https://9eo.org/blog/sharing-some-tools-for-working-with-geoparquet</id><content type="html" xml:base="https://9eo.org/blog/sharing-some-tools-for-working-with-geoparquet/"><![CDATA[<p>A goal for me this year is to ‘ship more’, so in the spirit of releasing early and often I wanted to share a little new project I got going this past weekend. See <a href="https://github.com/cholmes/geoparquet-tools">https://github.com/cholmes/geoparquet-tools</a></p>

<p><img src="/assets/img/posts/sharing-some-tools-for-working-with-geoparquet/1_NZeKv85UjvMIQ2z13cSDXQ.png" alt="" /></p>

<p>It’s a collection of utilities for things I often want to do but that aren’t trivial out of the box with <a href="https://medium.com/radiant-earth-insights/duckdb-the-indispensable-geospatial-tool-you-didnt-know-you-were-missing-5fe11c5633e5">DuckDB</a>. It started focused on just checking GeoParquet files for ‘best practices’, which I’ve been working on writing up in this <a href="https://github.com/opengeospatial/geoparquet/pull/254/files">pull request</a>, as I realized that lots of people are publishing awesome data as GeoParquet but don’t always pick the best options (and the tools don’t always set the best defaults). So it can check compression, if there’s a bbox column, and row group size. It also attempts to check if a file is spatially ordered, but I’m not sure if it works across different types of approaches. It does seem to work with Hilbert curves generated from DuckDB.</p>

<p><img src="/assets/img/posts/sharing-some-tools-for-working-with-geoparquet/1_P-UgjjAQbC47YK8J8G_EDg.png" alt="" /></p>

<p>I do need to refine the row group reporting a bit — I think the row group size in bytes is more important than the number of row groups, but I want to try to gather more information about what’s optimal there.</p>

<p>From there I made a utility to do the <a href="https://cholmes.medium.com/using-duckdbs-hilbert-function-with-geop-8ebc9137fb8a">Hilbert ordering</a> that DuckDB can do. This was initially just for conveinence, so I could just make a one line call instead of remembering the complex SQL statement. But then I realized that it has some real utility as DuckDB still doesn’t pass through projection information, so if you run the Hilbert DuckDB command on projected data the output isn’t so useful. So I made the output utilize the input parquet metadata. It also writes things out with the best practices I’m checking for, including adding a bbox column. I’m hoping to make it easier to turn that on/off, and to also pull out CLI commands that can run the full formatting or any part of it, but it’s proven a bit trickier than I was hoping.</p>

<p>The other main functionality I was to make it easier to create the <a href="https://medium.com/radiant-earth-insights/the-admin-partitioned-geoparquet-distribution-59f0ca1c6d96">‘admin-partitioned’ GeoParquet distributions</a> that I blogged about awhile ago. I got excited about these, but then they didn’t seem to go anywhere. But I think there are some places it can be quite nice, and I want to try it on this <a href="https://source.coop/planet/eu-field-boundaries">Planet dataset of ML generated field boundaries for all of Europe.</a> So I decided to build a utility that’s a bit more generic.</p>

<p>Matthias Mohr and Ivor Bosloper put together this great <a href="https://github.com/fiboa/administrative-division-extension">administrative division extension</a> for <a href="https://github.com/fiboa">fiboa</a>:</p>

<p><img src="/assets/img/posts/sharing-some-tools-for-working-with-geoparquet/1_pxXPsR-DU9NKFJDxx2OUhA.png" alt="" /></p>

<p>I’ve been thinking a lot about pulling things out of fiboa / STAC to just be a part of the general GeoParquet ecosystem, and this one seems like a perfect one to start with. It has a real practical utility, as once you add these codes you can then split your files by them to partition them spatially.</p>

<p>I did it as two commands, one to add the column (<code class="language-plaintext highlighter-rouge">gt add admin-divisions</code>) and then one to split based on the column (<code class="language-plaintext highlighter-rouge">gt partition admin</code>). It’s just countries for now, but I hope to add subdivision_code. And it’s just based on Overture, but I also hope to make it so the definition of the admin boundaries is flexible and configurable.</p>

<p>My hope is to add more partitions to the CLI, like the ones Dewey discussed in his post on <a href="https://dewey.dunnington.ca/post/2024/partitioning-strategies-for-bigger-than-memory-spatial-data/">Partitioning strategies for bigger than memory spatial data</a>. And also hoping to get in more ‘sort’ options as well, and also expand the <code class="language-plaintext highlighter-rouge">gt add</code> sub-command to perhaps add h3, s2, geohash, etc. and to also add the bounding box column to any file (I built it into the hilbert sort, so just need to get it fully working and extract it out).</p>

<p>I was hoping to get to create my own first proper pypi package so I could let people <code class="language-plaintext highlighter-rouge">pip install geoparquet-tools,</code> but I ran out of time for this round. I hope to do it soon, and to also add proper tests. And then my further hope is to also distribute at least a subset of this functionality as a QGIS plugin, and/or incorporate in my <a href="https://github.com/cholmes/qgis_plugin_gpq_downloader/">geoparquet downloader plugin</a>, so people can easily check out how well remote parquet files follow the best practices.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[A goal for me this year is to ‘ship more’, so in the spirit of releasing early and often I wanted to share a little new project I got going this past weekend. See https://github.com/cholmes/geoparquet-tools]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://9eo.org/assets/img/posts/sharing-some-tools-for-working-with-geoparquet/1_NZeKv85UjvMIQ2z13cSDXQ.png" /><media:content medium="image" url="https://9eo.org/assets/img/posts/sharing-some-tools-for-working-with-geoparquet/1_NZeKv85UjvMIQ2z13cSDXQ.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Using DuckDB’s Hilbert Function with GeoP</title><link href="https://9eo.org/blog/using-duckdbs-hilbert-function-with-geop/" rel="alternate" type="text/html" title="Using DuckDB’s Hilbert Function with GeoP" /><published>2025-01-15T00:00:00+00:00</published><updated>2025-01-15T00:00:00+00:00</updated><id>https://9eo.org/blog/using-duckdbs-hilbert-function-with-geop</id><content type="html" xml:base="https://9eo.org/blog/using-duckdbs-hilbert-function-with-geop/"><![CDATA[<h2 id="using-duckdbs-hilbert-function-with-geoparquet">Using DuckDB’s Hilbert Function with GeoParquet</h2>

<p>DuckDB continues to be my go to tool for geospatial processing, after I <a href="https://cloudnativegeo.org/blog/2023/09/duckdb-the-indispensable-geospatial-tool-you-didnt-know-you-were-missing/">discovered it over a year ago</a>. Since that time its functionality has continued to expand, and as of version 1.1 it reads and writes GeoParquet natively, as long as you have the <a href="https://duckdb.org/docs/extensions/spatial/overview.html">spatial extension</a> installed.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LOAD spatial;
CREATE TABLE fields AS 
  (SELECT * from 'https://data.source.coop/kerner-lab/fields-of-the-world-cambodia/boundaries_cambodia_2021.parquet');
  COPY fields TO 'cambodia-fields.parquet';
</code></pre></div></div>

<p>Be sure to always run <code class="language-plaintext highlighter-rouge">LOAD spatial;</code> or the table won’t get a geometry column, it will just create blobs. If you see errors or your output data is just Parquet and not GeoParquet that’s likely the source of your problems. I often forget to add it at the beginning of my sessions — perhaps there is some nice way to configure DuckDB to always load it, but I don’t know it (yet).</p>

<p>I also do recommend that you always use zstd compression, as it generally results in at least 20% smaller files, and its speed is comparable to snappy.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>COPY fields TO 'c-fields.parquet' (FORMAT 'parquet', COMPRESSION 'zstd')
</code></pre></div></div>

<h2 id="spatial-optimization">Spatial Optimization</h2>

<p>DuckDB’s GeoParquet writer always includes the new <a href="https://medium.com/radiant-earth-insights/geoparquet-1-1-coming-soon-9b72c900fbf2#8e83">bounding box column</a>, which enables much faster spatial filtering (EDIT: It actually does not always include the bbox column, you need to add it manually — instructions below). If you are translating GIS data from any format with a spatial index (GeoPackage, FlatGeobuf, Shapefiles) into DuckDB then you don’t need to do anything additional. But sometimes you get data that is not spatially ordered at all. Previously I would write the data out from DuckDB and use another tool to order it, but now the <a href="https://duckdb.org/docs/extensions/spatial/functions#st_hilbert">ST_Hilbert</a> function can be used to order your data.</p>

<p>I recently got <a href="https://github.com/duckdb/duckdb-spatial/discussions/419">help on the DuckDB Spatial discussions</a> for how to properly do this, so wanted to write that up for everyone. I’ve been processing Planet metadata that gets served from Planet’s <a href="https://developers.planet.com/docs/apis/data/">Data API</a>, working to try to make a <a href="https://github.com/stac-utils/stac-geoparquet/blob/main/spec/stac-geoparquet-spec.md">STAC-GeoParquet</a> version of it. The data is ordered by time, so when you load the full dataset it just fills in everywhere.</p>

<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*I1aggfbTkgky9-93gbNdwA.gif" alt="" /></p>

<p>I had a false start with the Hilbert curve function, which resulted in a cool pattern of loading the data.</p>

<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*ffaJ7_pIha_VMjo4mD5tkA.gif" alt="" /></p>

<p>Unfortunately the resulting ordering isn’t all that helpful to optimize spatial queries.</p>

<p>After Max, the author of the DuckDB spatial extension, <a href="https://github.com/duckdb/duckdb-spatial/discussions/419#discussioncomment-11836423">explained the importance of the ‘bounds’ argument</a>, I was able to get much better results:</p>

<p><img src="https://miro.medium.com/v2/resize:fit:1400/1*liSxvgirsA1K7X-m9vh0Jw.gif" alt="" /></p>

<p>So I’d recommend if you are using the ST_Hilbert function that you <em>always</em> include the bounds. For a global dataset like mine you can just do something like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CREATE TABLE ps_ordered AS 
  SELECT * FROM ps ORDER BY 
  ST_Hilbert(geometry, ST_Extent(ST_MakeEnvelope(-180, -90, 180, 90)));
</code></pre></div></div>

<p>You can just order as you write the Parquet:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>COPY (SELECT * FROM ps ORDER BY 
      ST_Hilbert(geometry, ST_Extent(ST_MakeEnvelope(-180, -90, 180, 90))
   TO 'ps-sorted.parquet'  (FORMAT 'parquet', COMPRESSION 'zstd');
</code></pre></div></div>

<p>But it can be a pretty intensive operation on larger datasets, so I like to make the table and then write it out separately.</p>

<p>One cool thing is that proper ordering can help the size of the data, by enabling better compression. The original data was 1.37 gigabytes, and I believe was ordered by time. The badly ordered one was 2.21 gigabytes, and then the properly ordered one was only 1.24 gigabytes.</p>

<p><img src="/assets/img/posts/using-duckdbs-hilbert-function-with-geop/1_75t36eFk_tAc0hE94H2hnw.png" alt="" /></p>

<p>If your dataset is not global then you can use DuckDB to get the bounds of the dataset with a call like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SELECT st_extent(ST_Extent_Agg(COLUMNS(geometry)))::BOX_2D
</code></pre></div></div>

<p>You would have to save that call’s output somewhere — if you’re writing code that calls DuckDB you can just store it in your code, or you could use the bounds and then paste in to MakeEnvelope. Or you can try to do it all in one call — I’ve not tested extensively, but I believe this call should work (credit due to ChatGPT for this one):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SELECT *
    FROM ps
    ORDER BY st_hilbert(
        geometry,
        (
            SELECT st_extent(ST_Extent_Agg(COLUMNS(geometry)))::BOX_2D
            FROM ps
        )
    );
</code></pre></div></div>

<p>You can use that to create the table, or to directly write the data out.</p>

<h2 id="writing-the-bbox-column">Writing the bbox column</h2>

<p>As of DuckDB 1.3.x the bbox column is not actually written out automatically. I apologize for saying that above — it took me a couple months to realize that I had just happened to be mostly working with data like Overture that already had the bbox column.</p>

<p>You can write out the bbox column manually, though it’s not quite fully spec compliant as it doesn’t write the proper GeoParquet metadata. But some clients will still understand it. To add a bbox you can do a call like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(
    SELECT struct_pack(xmin := ddb_box.min_x, ymin := ddb_box.min_y, xmax := ddb_box.max_x, ymax := ddb_box.max_y)
    FROM (SELECT unnest(ST_Extent(&lt;table_name&gt;.&lt;geometry_column&gt;)::BOX_2D)) AS ddb_box
) as bbox 
</code></pre></div></div>

<p>In the example above it’d be:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SELECT *, 
    (
        SELECT struct_pack(xmin := ddb_box.min_x, ymin := ddb_box.min_y, xmax := ddb_box.max_x, ymax := ddb_box.max_y)
        FROM (SELECT unnest(ST_Extent(&lt;table_name&gt;.&lt;geometry_column&gt;)::BOX_2D)) AS ddb_box
    ) as bbox
    FROM ps
    ORDER BY st_hilbert(
        geometry,
        (
            SELECT st_extent(ST_Extent_Agg(COLUMNS(geometry)))::BOX_2D
            FROM ps
        )
    );
</code></pre></div></div>

<p>I hope this post helps others, and soon gets into the LLM’s. A big thanks to Max for all his amazing work on the spatial extension, and helping me figure out how to get the Hilbert curve working!</p>

<p><img src="/assets/img/posts/using-duckdbs-hilbert-function-with-geop/1_rkeac_6sq32hFtJABU1PbQ.png" alt="" /></p>

<p><em>Gratuitous Picture to use in story profile</em></p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[Using DuckDB’s Hilbert Function with GeoParquet]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://miro.medium.com/v2/resize:fit:1400/1*I1aggfbTkgky9-93gbNdwA.gif" /><media:content medium="image" url="https://miro.medium.com/v2/resize:fit:1400/1*I1aggfbTkgky9-93gbNdwA.gif" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Introduction to STAC GeoParquet</title><link href="https://9eo.org/blog/introduction-to-stac-geoparquet/" rel="alternate" type="text/html" title="Introduction to STAC GeoParquet" /><published>2024-08-29T00:00:00+00:00</published><updated>2024-08-29T00:00:00+00:00</updated><id>https://9eo.org/blog/introduction-to-stac-geoparquet</id><content type="html" xml:base="https://9eo.org/blog/introduction-to-stac-geoparquet/"><![CDATA[<p>This post introduces <a href="https://stac-utils.github.io/stac-geoparquet/latest/">STAC GeoParquet</a>, a specification and library for storing and serving <a href="https://stacspec.org/">SpatioTemporal Asset Catalogs</a> (STAC) metadata as <a href="https://geoparquet.org">GeoParquet</a>. By building on GeoParquet, STAC GeoParquet makes it easy to store, transmit, and analyze large collections of STAC items. It makes for a nice complement to a STAC API.</p>

<h2 id="stac-background">STAC Background</h2>

<p>STAC makes geospatial data queryable, especially “semi-structured” geospatial data like a collection of <a href="https://www.cogeo.org">cloud-optimized GeotTIFFs</a> (COGs) from a satellite. I can’t imagine trying to work with this type of data without a STAC API.</p>

<p>Concretely, STAC metadata consists of JSON documents describing the actual assets. STAC metadata can typically be accessed in two ways:</p>

<ol>
  <li>Through a <a href="https://github.com/radiantearth/stac-spec/blob/master/catalog-spec/catalog-spec.md">static STAC catalog</a>, which is just a JSON document linking to other JSON documents (STAC Collections and / or STAC Items, which include the links to the assets)</li>
  <li>Through a <a href="https://github.com/radiantearth/stac-api-spec">STAC API</a>, which also enables things like search.</li>
</ol>

<p>In practice, I haven’t encountered much data distributed as static STAC catalogs. It’s perhaps useful in some cases, but for large datasets or datasets that are constantly changing, a pile of JSON files becomes slow and impractical for both the data provider and consumer. A STAC API is almost a necessity to work with this type of data.</p>

<p>That said, <em>running</em> a STAC API is a hassle (speaking from experience here). You need some kind of <a href="https://github.com/stac-utils/pgstac">database</a> to store the STAC metadata and <a href="https://github.com/stac-utils/stac-fastapi">web servers</a> to handle the API requests. That database and those web servers need to be deployed, monitored, and maintained.</p>

<p>Finally, with either a static STAC catalog or an API, large collections of STAC items require you to move around <em>a lot</em> of JSON. That’s slow for the web servers to serialize, slow to send over the network, and slow to deserialize on your end.</p>

<h2 id="enter-stac-geoparquet">Enter STAC GeoParquet</h2>

<p>STAC GeoParquet offers a nice format for easily and efficiently storing, transferring, and querying large amounts of <em>homogenous</em> STAC items.
The basic idea is to represent a STAC collection as a GeoParquet dataset, where each column is a field from the STAC item (<code class="language-plaintext highlighter-rouge">id</code>, <code class="language-plaintext highlighter-rouge">datetime</code>, <code class="language-plaintext highlighter-rouge">eo:cloud_cover</code>, etc.) and each row is an individual item.</p>

<p>The <a href="https://stac-utils.github.io/stac-geoparquet/latest/spec/stac-geoparquet-spec/">STAC GeoParquet specification</a> describes how to convert between a set of STAC items and GeoParquet.</p>

<p>STAC GeoParquet optimizes for certain use cases by leveraging the strengths of the <a href="https://parquet.apache.org">Apache Parquet</a> file format, at the cost of some generality.</p>

<p>Parquet is a columnar file format, so all the records in a STAC GeoParquet dataset need to have the same schema. The more homogenous the items, the more efficiently you’ll be able to store them. In practice, this means that all the items in a collection should have the same properties available. This is considered a best practice in STAC anyway, but there may be some STAC collections that can’t be (efficiently) stored in stac-geoparquet. This is discussed in detail in <a href="https://stac-utils.github.io/stac-geoparquet/latest/schema/">Schema Considerations</a>.</p>

<p>STAC GeoParquet (and Parquet more generally) is optimized for bulk and analytic use cases. Tabular data analysis libraries (like <a href="https://pandas.pydata.org">pandas</a>, <a href="https://www.dask.org">Dask</a>, <a href="https://duckdb.org">DuckDB</a>, etc.) can read and efficiently query Parquet datasets. In particular, the Parquet file format’s support for statistics and partitioning can make certain access patterns extremely fast. A STAC GeoParquet dataset might be partitioned by time and space (using a quadkey, for example), letting you efficiently load subsets of the items. And Parquet is a columnar file format, so loading a subset of columns is fast and easy. These aspects of the file format pair nicely with cloud-native workflows, where HTTP range requests mean that you don’t even need to download data that your workflow would just filter out anyway.</p>

<p>You likely wouldn’t want to do “point” reads, where you look up an individual item by ID, from a STAC GeoParquet dataset. Databases like Postgres are much better suited for that type of workload.</p>

<p>And while STAC GeoParquet might not be a good on-disk format for a STAC API serving many small queries, it can still play an important role as a transmission format for queries returning large result sets. If a user makes a request that returns many items, it will be faster to transmit those results as STAC GeoParquet rather than JSON, thanks to Parquet’s more efficient compression and serialization options.</p>

<p>One neat feature is the ability to embed the Collection metadata in the Parquet file’s metadata. This gives you a great single-file format for moving around small to medium sized collections (large collections may need to be partitioned into multiple files, but can still be treated as a single dataset by Parquet readers).</p>

<p>In summary, JSON and Parquet are very different file formats that are appropriate for different use-cases. JSON is record oriented, while Parquet is column oriented. JSON is flexible with respect to types and schemas, while Parquet is strict (which can make building a STAC GeoParquet dataset from a collection of STAC items difficult). STAC GeoParquet inherits all these properties, which affects the use-cases it’s appropriate for.</p>

<h2 id="example">Example</h2>

<p>As a simple example, we’ll look at what it takes to access one month’s worth of sentinel-2-l2a items from the Planetary Computer’s <a href="https://planetarycomputer.microsoft.com/dataset/sentinel-2-l2a">sentinel-2-l2a collection</a>. January, 2020 had about 267,880 items.</p>

<p>With some clever code to parallelize requests to the STAC API, we can fetch those items in about 160 seconds.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; t0 = time.time()
&gt;&gt;&gt; futures = [search(client, period) for period in periods]
&gt;&gt;&gt; features_nested = await asyncio.gather(*futures)
&gt;&gt;&gt; features = list(itertools.chain.from_iterable(features_nested))
&gt;&gt;&gt; t1 = time.time()
&gt;&gt;&gt; print(f"{t1 - t0:0.2f}")
162.16
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">search</code> method is a couple dozen lines of moderately complex, async Python. Out of curiosity, I serialized that to disk as (uncompressed) ndjson, and it took up about 4.5 GB of space.</p>

<p>With the <a href="https://stac-utils.github.io/stac-geoparquet/latest/"><code class="language-plaintext highlighter-rouge">stac-geoparquet</code></a> Python library, we can convert the JSON items to GeoParquet:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; import stac_geoparquet
&gt;&gt;&gt; rbr = stac_geoparquet.arrow.parse_stac_items_to_arrow(features)
&gt;&gt;&gt; stac_geoparquet.arrow.to_parquet(rbr, "sentinel-2-l2a.parquet")
</code></pre></div></div>

<p>That takes only 260 MB on disk. It can be read with a simple:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; table = pyarrow.parquet.read_table("sentinel-2-l2a.parquet")
</code></pre></div></div>

<p>which finishes in just under 5 seconds. That’s not entirely a fair comparison to the 160 seconds from the API, since I’m loading that from disk rather than the network, but there’s ample room to spare.</p>

<p>The STAC GeoParquet Python library can also write to the <a href="https://docs.delta.io/latest/delta-intro.html">Delta</a> Table format.</p>

<p>Once in GeoParquet, various clients can query the dataset. If you’re a fan of SQL, <a href="https://duckdb.org">DuckDB</a> supports reading Parquet files:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ duckdb
D select * from 'sentinel-2-l2a.parquet' where "eo:cloud_cover" &lt; 10 limit 10;
</code></pre></div></div>

<p>Or using <a href="https://ibis-project.org">ibis</a> we can get the average cloudiness per platform for each hour:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; counts = (
... ibis.read_parquet("sentinel-2-l2a.parquet")
... .group_by(
... _.platform,
... hour=_.datetime.truncate("h")
... ).aggregate(cloud_cover=_["eo:cloud_cover"].mean(), count=_.count())
... .order_by(["platform", "hour"])
... )
┌─────────────┬─────────────────────┬─────────────┬───────┐
│ platform │ hour │ cloud_cover │ count │
├─────────────┼─────────────────────┼─────────────┼───────┤
│ string │ timestamp │ float64 │ int64 │
├─────────────┼─────────────────────┼─────────────┼───────┤
│ Sentinel-2A │ 2020-01-01 02:00:00 │ 63.445030 │ 192 │
│ Sentinel-2A │ 2020-01-01 04:00:00 │ 26.992815 │ 57 │
│ Sentinel-2A │ 2020-01-01 05:00:00 │ 72.727221 │ 95 │
│ Sentinel-2A │ 2020-01-01 06:00:00 │ 0.097324 │ 10 │
│ Sentinel-2A │ 2020-01-01 07:00:00 │ 54.984660 │ 131 │
│ Sentinel-2A │ 2020-01-01 10:00:00 │ 48.270195 │ 161 │
│ Sentinel-2A │ 2020-01-01 11:00:00 │ 97.241751 │ 27 │
│ Sentinel-2A │ 2020-01-01 12:00:00 │ 70.159764 │ 131 │
│ Sentinel-2A │ 2020-01-01 14:00:00 │ 47.591773 │ 388 │
│ Sentinel-2A │ 2020-01-01 15:00:00 │ 50.362548 │ 143 │
│ … │ … │ … │ … │
└─────────────┴─────────────────────┴─────────────┴───────┘
</code></pre></div></div>

<h2 id="summary">Summary</h2>

<p>So, in all STAC GeoParquet offers a very convenient and high-performance way to distribute large STAC collections, provided the items in that collection are pretty homogenous (which they probably should be, for your users’ sake). It by no means replaces the need for a STAC API in all use cases. Databases like Postgres are <em>really</em> good at certain workloads. STAC GeoParquet complements a STAC API, by handling the bulk-access use-case that a typical JSON-based REST API struggles with. And if you just need to distribute a relatively static collection of STAC items, putting STAC GeoParquet on Blob Storage strikes a really nice balance between hardship for the producer and usefulness for the consumer.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[This post introduces STAC GeoParquet, a specification and library for storing and serving SpatioTemporal Asset Catalogs (STAC) metadata as GeoParquet. By building on GeoParquet, STAC GeoParquet makes it easy to store, transmit, and analyze large collections of STAC items. It makes for a nice complement to a STAC API.]]></summary></entry><entry><title type="html">Embracing Geospatial as a Primary Data Type: A Call to Action for the Data Community</title><link href="https://9eo.org/blog/embracing-geospatial-as-a-primary-data-type-a-call-to-action-for-the-data-community/" rel="alternate" type="text/html" title="Embracing Geospatial as a Primary Data Type: A Call to Action for the Data Community" /><published>2024-07-17T00:00:00+00:00</published><updated>2024-07-17T00:00:00+00:00</updated><id>https://9eo.org/blog/embracing-geospatial-as-a-primary-data-type-a-call-to-action-for-the-data-community</id><content type="html" xml:base="https://9eo.org/blog/embracing-geospatial-as-a-primary-data-type-a-call-to-action-for-the-data-community/"><![CDATA[<p><img src="/assets/img/posts/embracing-geospatial-as-a-primary-data-type-a-call-to-action/20240716-embracing-geospatial.png" alt="Embracing Geospatial as a Primary Data Type" /></p>

<p>Over two years ago, the GeoParquet project brought together a diverse group of interests around a clear objective: standardizing how geospatial data is used within Parquet. The initial goal was modest: to ensure that any tool reading or writing spatially located geometries (points, lines and polygons) does so in a consistent and interoperable way.</p>

<p>But the ultimate goal of the effort has been to make geospatial a primary data type within the broader data community, thereby breaking the ‘GIS’ data silo and enabling the seamless integration of geospatial data with all other data types. We envision a world where spatial data is simply another column in your dataset, not a special case requiring unique handling. This integration will unlock new insights, reduce the need for specialized tools, and make geospatial information accessible to a broader range of users and innovations.</p>

<p>Without standardization, the current situation is that geospatial datasets are often non-interoperable. Spatial data might be a column in each system, but moving data between systems requires extensive overhead to transform it properly due to insufficient metadata. Naively adding geospatial types to big data systems often leads to poor performance because the necessary metadata and indexes for effective spatial operations are not considered. This fragmentation and inefficiency highlight the urgent need for standardized approaches.</p>

<h3 id="progress-and-adoption">Progress and Adoption</h3>

<p>Since its inception, the GeoParquet group has launched versions 1.0 and 1.1, witnessing significant adoption across various tools (<a href="https://geoparquet.org/#implementations">over 20 tools and libraries implement the specification</a>) and datasets.</p>

<p><img src="/assets/img/posts/embracing-geospatial-as-a-primary-data-type-a-call-to-action/20240717-geoparquet-tools.png" alt="Software libraries and tools for GeoParquet" /></p>

<p><em>A few of the organizations that provide software libraries and tools for GeoParquet. Their contributions are building a robust ecosystem for geospatial data management and analysis using GeoParquet.</em></p>

<p>One of the main design goals for the GeoParquet specification was to make it as easy as possible for a non-geospatial expert to implement, while also providing the ability to properly handle any of the obscure requirements that geospatial experts need for critical applications.</p>

<p>If someone has a bunch of longitude and latitude GPS points they should be easily able to figure out how to store them in GeoParquet without having to understand coordinate reference systems, polygon winding orders and spherical edges. But that point data should work seamlessly when it’s joined with data exported from 3 different national governments who all use different projections, in a system that needs the epoch right because it requires sub-centimeter accuracy in an area where the movement of the continental plates affects the output.</p>

<p>Getting the right balance of simplicity and complexity for GeoParquet has involved extensive discussion for each of the resulting 8 metadata fields. One major goal for each field was to establish good default values, so that systems that did not have complex requirements could safely ignore them while also naturally doing the right thing when writing out the data.</p>

<p>The resulting collection of metadata fields ensures that geospatial data transferred across systems can be fully understood without ambiguity or errors. Our hope is that these fields can be leveraged by other systems who wish to add geospatial support, enabling them to start simple by hardcoding a smaller number of acceptable values, but able to start with the right fields to handle all the nuance of the geospatial world.</p>

<p>Initially, we added this metadata as an extension in the form of a JSON string within the Parquet file metadata, as that was Parquet’s only available extension point. However, with growing interest in geospatial support within the data community, it’s time to refine our strategy. Parquet is not alone in the data ecosystem. The rise of open table formats in data lakes and other technologies makes it clear that spatial types need to be fully handled at all layers.</p>

<h3 id="moving-forward">Moving forward</h3>

<p>Last month, we organized a meetup in San Francisco, inviting people working on various technologies like Parquet, Arrow, Iceberg, Delta, and others interested in adding geospatial support. The consensus was the need for a coordinated approach to ensure geospatial types are handled correctly across all levels of the stack, in order to avoid interoperability issues between different layers and necessary transformations.</p>

<p>Currently, groups are working on adding geospatial capabilities to Arrow, Parquet, Iceberg, Delta, etc. Our proposal is to coordinate these efforts. We suggest leveraging the research and discussions from the GeoParquet group, as documented in its specification (with extensive justification for the decisions available in the issues and pull requests). The ideal outcome is that GeoParquet itself becomes unnecessary, with geospatial being treated as a primary data type in all relevant formats and protocols, accompanied by the right metadata.</p>

<h3 id="a-path-forward">A path forward</h3>

<p>The tentative conclusion of our meeting in San Francisco was to start with the standardization of <a href="https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry">Well-Known Binary</a> (WKB) support in Arrow, Parquet, and Iceberg, representing these as native types across these technologies. This likely consists of three main tasks:</p>

<ul>
  <li>Complete the work to add a WKB data type to Parquet. Work has <a href="https://github.com/apache/parquet-format/pull/240">already started</a>, but funding is needed to complete it.</li>
  <li>Create an Apache Arrow <a href="https://arrow.apache.org/docs/format/CanonicalExtensions.html#official-list">Canonical Extension</a> for WKB. The core work for WKB in Arrow is mostly complete in conjunction with <a href="https://geoarrow.org/">GeoArrow</a>, but this will help promote it as a mature, interoperable (but less efficient) encoding option.</li>
  <li>Continue and complete the support for geospatial data in Apache Iceberg through the usage of WKB. There are several threads of collaboration on this, see <a href="https://github.com/apache/iceberg/issues/2586">this issue</a> for some of the history.</li>
</ul>

<p>And getting these basics working is just the beginning. The potential of a second phase is to go beyond WKB and align on optimized geometry encodings that fit more directly into the paradigms of modern data formats and protocols, enabling more performance and efficiency in an interoperable way.</p>

<p>Finally, this initial path of interoperability is thus far only focused on geospatial <a href="https://en.wikipedia.org/wiki/Data_model_(GIS)#Vector_data_model">vector data</a>. Similar initiatives will be needed to fit other types of geospatial data such as <a href="https://en.wikipedia.org/wiki/Data_model_(GIS)#Raster_data_model">raster</a>, <a href="https://en.wikipedia.org/wiki/Point_cloud">point clouds</a>, <a href="https://en.wikipedia.org/wiki/Discrete_global_grid">discrete global grid systems</a> (such as <a href="https://h3geo.org">H3</a> and <a href="https://s2geometry.io">S2</a>) into the mainstream data formats &amp; protocols.</p>

<h3 id="call-to-action">Call to Action</h3>

<p>We call on the community to combine these efforts into a single effort, ensuring all pieces fit together seamlessly. We propose to center this effort around the existing GeoParquet community group, which meets bi-weekly and has already conducted extensive discussions. The task of integrating geospatial types into various data stacks will not be simple, but we have a clear roadmap compatible with all existing initiatives.</p>

<p>If you are working on geospatial support in any relevant data technology, please consider joining the GeoParquet meetup group (suggestions are welcome for a new name that reflects the broader collaboration) and collaborate with others - just email requests [at] geoparquet.org and ask to be added to the calendar invite. Now that geospatial is being added to many standards and protocols, we have the opportunity to coordinate our efforts and establish robust geospatial support from the start, reducing frictions and limitations for years to come.</p>

<p>Interested in seeing this happening and can provide financial support? We also want to hear from you. There is already some initial funding available from OGC, sponsored by Planet and CARTO, to push forward Iceberg support for geospatial.</p>

<p>The future for geospatial is bright! Let’s work together to ensure it integrates seamlessly into the broader data ecosystem.</p>

<h3 id="relevant-links-and-initiatives">Relevant links and initiatives</h3>

<ul>
  <li>GeoParquet: <a href="https://geoparquet.org">geoparquet.org</a></li>
  <li>GeoArrow: <a href="https://geoarrow.org/">geoarrow.org</a></li>
  <li>Geo on Iceberg: <a href="https://github.com/apache/iceberg/issues/2586">geo on iceberg github issue</a></li>
</ul>

<p>Checkout the notes from the San Francisco Meeting: <a href="https://docs.google.com/document/d/1Dj9F8185qmrz2CpEvgKDlXQkHpBL8CjqGy_JS-hMetI/edit#heading=h.d8n988fv1mve">GeoParquet in person meetup at Data + AI conference</a></p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Towards Flexible Data Schemas</title><link href="https://9eo.org/blog/towards-flexible-data-schemas/" rel="alternate" type="text/html" title="Towards Flexible Data Schemas" /><published>2024-05-13T00:00:00+00:00</published><updated>2024-05-13T00:00:00+00:00</updated><id>https://9eo.org/blog/towards-flexible-data-schemas</id><content type="html" xml:base="https://9eo.org/blog/towards-flexible-data-schemas/"><![CDATA[<p><em>By <a href="https://beta.source.coop/cholmes/">Chris Holmes</a>, <a href="https://tgengine.org/">Taylor Geospatial Engine</a> Industry Fellow</em></p>

<p>Following up on <a href="https://cloudnativegeo.org/blog/2024/04/common-schemas-and-ids/">the importance of data schemas and ID’s</a> blog post, I wanted to dig into the topic of data schemas. In the Cloud Native Spatial Data Infrastructure section, it posited that instead of a model like OpenStreetMap, where everyone contributes to a single database, a better inspiration might be open source software. This way of working wouldn’t require everyone to follow the same set of community and governance norms — it would encourage different approaches and more experimentation, and a wider variety of data types to collaborate around. That section closed with the thought:</p>

<p><em>We … don’t envision a single data schema that everyone has to align to. Instead, there’s a way to start with a small, common core of information that gives data providers the flexibility to use the pieces that are relevant to them and easily add their own.</em></p>

<p>I believe the foundation we’ve been laying with Cloud Native Geospatial formats has the potential to lead to much greater interoperability between data, if we can get a few things right. So, I wanted to use this post to explore how we can do things a bit differently and potentially get closer to that vision by building on these great new formats.</p>

<h3 id="flexible-schemas">Flexible Schemas</h3>

<p>The first thing that we can do differently than what came before is to flexibly combine different data schemas. The key is to move away from how the geospatial world has done things with XML, particularly the way validation works. In the XML world, you’d use an XML Schema to define how each field should work, and then the same XML Schema would validate if the fields in your document had the proper values. The big problem was that if an extra field was added, then the validation would fail. You could, of course, extend the XML Schema definition, but it it’s not easy to ‘mix and match’ — to just have a few different XML Schemas validate different parts of your data.</p>

<p>The cool thing is that with JSON Schema, you can easily do this. Six different JSON Schemas can all validate the same JSON file, each checking their particular part. And the situation is similar with Parquet &amp; GeoParquet: there’s nothing that will break there either if the data has an extra column. We’ve used this to great effect in <a href="https://stacspec.org/">STAC</a> — the core STAC spec only defines a few fields, and includes the JSON Schema to validate the core. But each ‘extension’ in STAC also has its own JSON Schema. Any STAC Validator will use each extension’s schema to validate the whole file.</p>

<p>This has profound implications, since it enables a much more ‘bottom up’ approach to the evolution of the ‘data schema.’ In the XML world, you needed everyone to agree, and if someone disagreed they’d need to fork the XML Schema and redefine what they wanted. Users would then need to pick between which validation they wanted to use. So, it was really important that a top down entity set the standard. With the bottom up approach, anyone can define just a few fields for their own use, and others can define similar things in their own way. Of course, the core ‘thing,’ like SpatioTemporal Assets, needs to be done well. But I believe the key here is to make that core as simple as possible, so many extensions can thrive. Then, it’s just real world usage that decides which fields are important. And it also allows ‘incubation’ — a single organization can just decide to make their own validator for their fields. An example of this is Planet, with the <a href="http://github.com/planetlabs/stac-extension">Planet STAC Extension</a>:</p>

<p><img src="/assets/img/posts/towards-flexible-data-schemas/0_43IfFqwur-vRqPej.png" alt="" /></p>

<p>It uses a bunch of the common extensions like view, eo, proj and raster. And then it has some fields that are very specific to Planet’s system (item_type, strip_id, quality category), but there are a number of fields for which there is not yet a STAC extension. I say ‘yet’ because these are fields that are likely things that other satellites have for metadata, like clear_percent, ground_control and black_fill. They can be defined for Planet’s validation, since their users expect them. But others in the community can also look at Planet’s and decide to adopt what they did. And if a few different providers all do something similar, we can come together and agree on a common definition that we’ll all use. If two people decide to define the same ‘thing’ and both feel theirs is right, then both can exist, but likely one will gain more adoption and become the standard.</p>

<h3 id="global-datasets">Global Datasets</h3>

<p>One of my main observations from the last twenty years of working with standards is that having more data following the standard is the key to success. The best thought out specification that everyone agrees on will lose out to a poorly specified set way of doing things that has tons of data that everyone actually uses. This dynamic was clear with GML vs KML. The latter didn’t even have a formal specification for many years, but there was tons of data saved as KML. And the reason there was tons of data in KML in the first place is because it gave you access to an unprecedented amount of data in Google Earth for free — even if that data wasn’t itself available in KML.</p>

<p>So whatever dataset is the largest and most important in an ecosystem usually becomes the standard way of doing things, even if it didn’t set out to be ‘a standard’ — it becomes the defacto standard. Key to STAC’s success was that early on both Landsat and Sentinel 2 were available in the standard, and indeed it enabled those two major datasets to be more interoperable with each other.</p>

<p>With the explosion of satellite imagery and the continued advances in AI and computer vision we’re seeing more datasets that are truly global. The best of these will play a major role in setting the standard data schemas for whatever type of data they represent. Indeed I think we’ll see an interplay between aligning schemas for validated training data about foundational geospatial data types and the schemas of the resulting models. And hopefully, we’ll see major governmental data providers stepping up to the role they play in setting standards — a federal government defining a reusable schema for a particular domain, putting foundational data out in it, and also encouraging each state to use the same schema.</p>

<p><a href="https://overturemaps.org/">Overture Maps</a> is doing really great work in building open global datasets for some of the most foundational geospatial layers, leveraging AI extensively. And they are taking their role in setting a data schema standard seriously, working to make it a flexible core that other attributes can be added to. I’m also excited to be working on <a href="https://cloudnativegeo.org/blog/2024/04/introducing-fiboa/">fiboa</a> as part of Taylor Geospatial Engine’s <a href="https://www.linkedin.com/pulse/taylor-geospatial-engines-first-innovation-bridge-jennifer-marcus-jez8c/">Field Boundary Initiative</a>. It’s centered around the potential to use AI and Earth Observation data to build global datasets, and it’s doing some great innovation around the core data schemas to enable that.</p>

<h3 id="cloud-native-geo-formats-require-deeper-alignment">Cloud-Native Geo Formats Require Deeper Alignment</h3>

<p>I believe one of the main mistakes of past Spatial Data Infrastructure efforts was to try to punt on the hard problem of getting people to align their data. The message was that everyone could keep their database in its same schema, and the application servers delivering the API’s could just transform everything into standard schemas on the fly. This proved to be incredibly annoying to get right, as being able to map from anything to a complex data schema isn’t easy, and the tools to help do this well never really took off.</p>

<p>I think the fact that a Cloud-Native Spatial Data Infrastructure is fundamentally based on formats instead of API’s means that it will force people to confront the hard problem of actually aligning their data. We <em>should</em> be trying to get everyone actually using the same data schema in their day to day work, not just doing their internal work in one schema and transforming it into another schema to share it with others. It’ll be much easier if you share the buildings file from the city of Belém and its core attributes follow the same definitions as Overture. We shouldn’t have to go through data interchange servers (like Web Feature Services) just to share interoperable data: our goal needs to be making the actual data interoperable.</p>

<p>Obviously it’s unrealistic to expect everyone to just change their core database to a new schema. But it’s easier to use an ETL tool or a bit of code to actually transform the data and publish it than it is to set up a server and define an on the fly schema mapping against its database. And if we can get small core schema definitions with easy to use extensions then we won’t need to convince Belém to drop their schema and fully adopt ‘the standard’ — they should be able to update a couple core fields and define their own extensions that match their existing data schema, and slowly migrate to implementing more of the standard extensions.</p>

<h3 id="riding-the-wave-of-mainstream-data-innovation">Riding the Wave of Mainstream Data Innovation</h3>

<p>The other thing we are starting to do is align with all the investment in mainstream data science and data engineering. One of the ways the founders would explain Planet in the early days was that they were leveraging the trillions of dollars of investment that has gone into the cell phone. Other satellites would buy parts that were ‘made for space,’ and were egregiously expensive because they were specially designed, with no economies of scale. Planet bought mostly off the shelf components, and was able to tap into the speed of innovation of the much bigger non-space world.</p>

<p>By embracing Parquet, we’re starting to do the same thing with geospatial. I think the comparison is apt — we’ve tended to build our own special stacks, reinventing how others do things. Open source geospatial software has been much better, like with PostGIS drafting off of PostgreSQL. But there is now huge investment going into lots of innovation around data.</p>

<p>In the context of data schemas, there are many people looking at data governance, and tools to define and validate data schemas. And so, we should be able to tap into a number of existing tools to do what we want with Parquet, instead of having to build all the tools from scratch.</p>

<h2 id="making-it-work">Making it work</h2>

<p>There’s some relatively easy things we can do to usher in an era of bottom-up innovation in data schemas. This should lead to much greater collaboration, and hopefully start a flywheel of Cloud-Native Spatial Data Infrastructure participation that will lead to a successful global SDI.</p>

<p>I think the key is to make it easy to create simple core schemas with easy to define extensions on top of the core. This mostly means creating a core toolset so anyone can create a schema, translate data into the schema, and validate any data against both that schema and its extensions.</p>

<p>The cool thing is that I think STAC has defined a really good way to do this, that just needs to be generalized and enhanced a bit.</p>

<h2 id="generalizing-the-stac-way">Generalizing the STAC way</h2>

<p>So STAC is ready to use if you want a data schema for data where the geometry is an indicator of the footprint of some other type of data, and there are links to the actual data. And then you can tap into all sorts of STAC extensions that help define additional parts of a flexible data schema. But if your data is like the vast majority of vector data, where the geometry and properties <em>are</em> the data, not metadata about some other data, then you can’t tap into all the great extensions and validation tools.</p>

<p>To generalize what STAC does, I believe we can build a construct that lets any type of vector data define a core JSON Schema and links to extensions. With STAC, you just look for stac_version and then you know that it can validate against the core STAC extension, and then stac_extensions is a list of links to the JSON schemas of the extensions it implements. The links are naturally versioned, as part of the URL of the schemas.</p>

<p>A general version could just have a definition that links to a single core schema (validating the geometry and any other attributes that are considered ‘core’). And then an extensions list that works the exact same way as STAC extensions. It perhaps could even directly use some STAC extension definitions like the MGRS extension, which could be used by any number of vector datasets that want to include MGRS:</p>

<p><img src="/assets/img/posts/towards-flexible-data-schemas/0_SqU71XmO6fj-jY3n.png" alt="" /></p>

<p>Close readers will likely note that this approach would all unfortunately be incompatible with STAC, since STAC has hard coded versions. But I think if a wider ecosystem takes off in a big way we could consider a STAC 2.0 that fits properly into the hierarchy. And there’s probably some less elegant hacks you could do to make it all work together if that was needed.</p>

<p>The other bit that would make a ton of sense to generalize is the STAC extension repository template. This to me is one of the most clever parts of the STAC ecosystem, and it’s all thanks to<a href="https://mohr.ws/"> Matthias Mohr</a>.</p>

<p><img src="/assets/img/posts/towards-flexible-data-schemas/0_0ZVGTdWiYM-u08WG.png" alt="" /></p>

<p><a href="https://github.com/stac-extensions/template">https://github.com/stac-extensions/template</a></p>

<p>The core is it gives you a clear set of guidelines to fill out your own extension. You don’t need to check 3 other extensions to see how they do it, you just change the right places for yours and it then ‘fits’ with the ecosystem. But it goes far beyond that, as it clones a set of continuous integration tools. It will automatically check your markdown formatting, and once you finish your JSON Schema it will also check that all your examples conform to STAC and your defined extension.</p>

<p>And then when you publish a release it will automatically publish the JSON Schema in your repo on github pages, to be the official link. STAC validators can then immediately make use of it. So to create any new version of your extension you just need to cut a release. I hadn’t even known that anything like this was possible, but it made it such a breeze to create a new extension. You can focus on your data model, and not on how to release it and integrate into tooling, since it all ‘just works.’</p>

<p>Astute readers will realize that the recently announced fiboa project has explored a number of these ideas. It is a vector dataset focused on field boundaries, and it defined a <a href="https://github.com/fiboa/specification">small core</a> and flexible extensions; Matthias adapted the STAC extension template concepts to a <a href="https://github.com/fiboa/extension-template">fiboa extension template</a>. We have yet to go all the way to a ‘definition’ schema defined by a link to the core schema, as it felt like too much complexity for the first version, but if others start to do similar things we could do so by 1.0.</p>

<h3 id="enhancing-the-stac-schema-toolset">Enhancing the STAC schema toolset</h3>

<p>So I think there’s a few ways we’d ideally go beyond just generalizing how STAC does things. The first one is to be compatible with GeoParquet. GeoParquet is a much more naturally default format for vector data on the cloud than GeoJSON is, and its support of different projections also will help support a wider variety of use cases. GeoJSON worked well for STAC, particularly because we had both the<a href="https://github.com/radiantearth/stac-spec/blob/master/best-practices.md#static-catalogs"> static STAC</a> and the<a href="https://github.com/radiantearth/stac-api-spec"> STAC API</a> options. I originally imagined that large data sets would naturally be stored in a database and use a server that clients would query. But the fully cloud native approach has been quite appealing, and a number of very large datasets are just on object stores, and consist of millions of individual JSON files (next to the actual data files).</p>

<p>We’ve recently started to standardize on how to represent a full STAC collection in GeoParquet with the<a href="https://github.com/stac-utils/stac-geoparquet/blob/main/spec/stac-geoparquet-spec.md"> STAC GeoParquet Spec</a>. I’ll hold off on a deep dive on that, but it’s pretty cool to be able to just query the entire STAC catalog without needing an API.</p>

<p>So for non-’asset’ data, where the geometries and properties are the data, not metadata, GeoParquet makes much more sense than GeoJSON as the main distribution format. But my hunch is that it likely will still make sense to define data schemas in more human readable formats. There is some argument for defining the core schemas completely abstractly, in something like UML, since formats will continue to change and we should be adaptable to that. But from my experience that introduces an unnecessary layer of abstraction. With STAC I actually started a SpatioTemporal Asset Metadata (STAM) spec, see<a href="https://github.com/radiantearth/stam-spec"> https://github.com/radiantearth/stam-spec</a>, to try to make abstract definitions that could map to JSON but also other formats (like GeoParquet though it didn’t exist yet, or as Tiff tags in a GeoTIFF). But it was a pain to try to maintain both and just didn’t add much.</p>

<h3 id="fiboa-schema">fiboa Schema</h3>

<p>For fiboa, Matthias defined something a bit less abstract than UML, defining <a href="https://github.com/fiboa/specification/blob/main/core/schema/schema.yaml">a human-readable YAML-based</a> language to describe the attributes and constraints and named <a href="https://github.com/fiboa/schema">fiboa Schema</a> for now. Pure JSON schema didn’t quite work, since JSON has a limited number of types, so it couldn’t precisely describe the different data types commonly found in file formats such as GeoPackage and GeoParquet. Our intention is also that users create extensions, which need a separate schema definition for the added properties. As such the language is much simpler to lower the entry barrier for newcomer as we found in STAC and other projects that JSON Schema is too difficult for many. Nevertheless, the language is based on JSON Schema so it can easily be converted to valid JSON Schema. We’re not sure if it’s the right answer for all time, but it is working pretty well as a way to easily define schema information and have it validate in both JSON Schema and Parquet.</p>

<p>Overture is also using JSON Schema to define their schemas, so it’s nice they’re thinking in similar directions. Nevertheless, they’ve also identified the data type limitations that we’ve seen. For example, temporal information are stored in strings instead of native temporal data types and numerical types always use the biggest container (e.g. int32 instead of uint8). They say the final format for Overture deliveries hasn’t been set yet, but the most recent releases were GeoParquet. They also recently embraced snake_case for their naming, which is a minor detail, but does make it easier to potentially share extensions between the projects. My hope if that we can get to some common tools that let projects define schemas for vector data with properties across various file formats such as GeoParquet in human readable formats and get automatic validation tools. We are also experimenting and discussing with other related projects such as Overture to get feedback on our approach to make it general enough for other use cases.</p>

<h3 id="measuring-success">Measuring Success</h3>

<p>One final idea to generalize and hopefully really enhance is<a href="https://stacindex.org/"> STAC Index</a>. STAC Index provides a list of all public STAC Catalogs, and you can use a<a href="https://github.com/radiantearth/stac-browser"> STAC Browser</a> to easily browse the full extent of any of them. One of the original ideas of STAC Index was to crawl all the catalogs and provide lots of interesting stats on them. Tim Schaub built a crawler to do this and reported on the results in the<a href="https://developers.planet.com/blog/2022/Aug/31/state-of-stac/"> State of STAC blog post</a>, but ideally it would be a continuous crawling and reporting of stats.</p>

<p>I believe the key to a Cloud-Native Spatial Data Infrastructure is to make it really easy to measure how successful adoption has been. Not just counting the total of number of GeoParquet datasets, but to to track more details to be able to get some real nuance. Things like number of rows in GeoParquet, stats by particular data schemas (like fiboa), global spatial data coverage by data type, etc. There is a chance we’ll still use STAC, but likely just at the ‘collection’ level, to provide metadata on GeoParquet files. Though that’s something we’re still figuring out in fiboa — if we should adopt STAC Collection directly or just aim to be compatible with it — the latter feels a bit simpler.</p>

<p>So STAC Index should be enhanced to really be the ‘Cloud-Native SDI Index’, and serve as a clear KPI and scoreboard to really measure adoption. I should probably spend a whole blog post on the topic of measuring standard adoption at some point, as I have a suspicion that making it really easy to measure the actual adoption is a powerful lever to drive adoption.</p>

<h2 id="lets-do-this">Let’s do this!</h2>

<p>So for me the next major project is to work on flexible schemas for foundational data sets. One obvious one is buildings, and Overture is doing incredible work there. They’re truly crushing it on figuring out a core, flexible data schema with global ideas, but I think it’d be awesome to build on what they’re doing in two ways. The first is to try to build validation tooling, and experiment with making other building datasets ‘overture compatible’. And the second would be to try out ‘extending’ their core schema with some additional fields. Perhaps something like building color, or roof type. I suppose the ideal would be to find some better attributed building dataset and make it Overture compatible — try to conflate the geometries, merge the common attributes, and make a schema for the extended attributes.</p>

<p>And then in fiboa we’re taking a serious run at defining flexible schemas for field boundaries and ag related data. If you’ve got interest in that then please join us! And if you’re interested in a different domain than buildings and field boundaries then don’t hesitate to take these ideas and run with them. And I just talked to a group about doing the same approach for forest data, so if you’re interested in collaborating on that let me know.We don’t have any explicit channel on the Cloud Native Geo slack, but I’m sure we can start on #geoparquet or #general and then spin one up.</p>

<p>Awhile ago on twitter I read this cool post on<a href="https://twitter.com/yohaniddawela/status/1729468846728163661"> sub-national GDP</a>.</p>

<p><img src="/assets/img/posts/towards-flexible-data-schemas/0_uHc69EU3F-VeaIUB.png" alt="" /></p>

<p>This does seem like another opportunity — use Overture<a href="https://docs.overturemaps.org/reference/admins/locality"> locality schema</a> for sub-national boundaries at the core but add an attribute for GDP and other economic stats, and harmonize all the datasets listed.</p>

<p>I’d also love to hear of other opportunities for collaborations on data schemas, and other success stories where there are interoperable data standards, particular in domains that are further afield. I think it’d be interesting to try to adapt some of the successful ones into cloud-native formats, just to see if it works and if it adds value. So if anyone wants to work on that don’t hesitate to get in touch.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[By Chris Holmes, Taylor Geospatial Engine Industry Fellow]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://9eo.org/assets/img/posts/towards-flexible-data-schemas/0_0ZVGTdWiYM-u08WG.png" /><media:content medium="image" url="https://9eo.org/assets/img/posts/towards-flexible-data-schemas/0_0ZVGTdWiYM-u08WG.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">fiboa: The Ecosystem</title><link href="https://9eo.org/blog/fiboa-the-ecosystem/" rel="alternate" type="text/html" title="fiboa: The Ecosystem" /><published>2024-05-02T00:00:00+00:00</published><updated>2024-05-02T00:00:00+00:00</updated><id>https://9eo.org/blog/fiboa-the-ecosystem</id><content type="html" xml:base="https://9eo.org/blog/fiboa-the-ecosystem/"><![CDATA[<p>fiboa is a new collaborative project to improve farm field boundary data interoperability and other associated agriculture data, that we <a href="https://cloudnativegeo.org/blog/2024/04/introducing-fiboa/">introduced</a> a couple of weeks ago. This post complements our previous deep dive into the <a href="https://cloudnativegeo.org/blog/2024/04/fiboa-core-specification-extensions/">follow-up post</a> core specification and its extensions. In that post, we mentioned that fiboa is not just a specification; it’s a complete system. It includes the entire ecosystem of data adhering to the specification, the discussions and conversations that evolve the specs, and of course, the community people who are building it all together. In this post, we introduce the initial tools, data, and community that form that ecosystem.</p>

<h2 id="data">Data</h2>

<p>The goal of fiboa isn’t to create a data schema - the schema is a means to get at the goal of more data and more open data about field boundaries and agriculture to help us make better decisions. And indeed the best way to make a good data schema is not to go in a room and try to create the most perfect ontology - it’s to actually work with data and evolve the core specification and extensions to better represent real-world data. Our next step is to work with a number of organizations to ensure that their data can be represented in fiboa. To jump-start this process, we’ve converted a number of existing datasets and made them available on <a href="https://source.coop">Source Cooperative</a>.</p>

<p>For those unfamiliar with Source, it’s a data hosting utility provided by Radiant Earth, built with great support for <a href="https://cloudnativegeo.org/">cloud-native geospatial formats</a>. We’ll likely put most public datasets up on Source, as it’s a user-friendly platform. Anyone else is also welcome to host their fiboa-compliant data there. You can also easily host them on any cloud or simply use them locally, but it can be quite beneficial to put larger data up there, as it becomes easy for users to download just the subset of data they want.</p>

<p><img src="/assets/img/posts/fiboa-the-ecosystem/20240417-fiboa-image6.png" alt="fiboa data on Source Cooperative" /></p>

<p>The first of the datasets that was converted was <a href="https://beta.source.coop/repositories/fiboa/de-nrw/description/">Field Boundaries for North Rhine-Westphalia (NRW), Germany</a>. It was followed by 1.3 million <a href="https://beta.source.coop/repositories/fiboa/austria/description/">field boundaries for Austria</a>, plus boundaries for <a href="https://beta.source.coop/repositories/fiboa/de-bb/description/">Berlin / Brandenburg</a>, <a href="https://beta.source.coop/repositories/fiboa/de-nds/description/">Lower Saxony</a>, and <a href="https://beta.source.coop/repositories/fiboa/de-sh/description/">Schleswig-Holstein in Germany</a>. It’s pretty easy to convert existing datasets (more details in the ‘tools’ section below), so if you’re interested in contributing to fiboa, then converting and uploading a new fiboa dataset on Source is a great way to start. There are a few potential datasets listed in the <a href="https://github.com/fiboa/data/issues">fiboa data repository tracker</a>; if you’ve got ideas of other great datasets to contribute, don’t hesitate to add them to the tracker. We’re also hoping to get several commercial companies to contribute at least samples of their data implementing fiboa. The academic work that Taylor Geospatial Engine is funding is also going to harmonize and make publicly available some interesting datasets.</p>

<h2 id="tools">Tools</h2>

<p>As part of the initial release of fiboa, <a href="https://mohr.ws/">Matthias Mohr</a> has built several tools to make the ecosystem more immediately useful. The main tools are all available from the <a href="https://github.com/fiboa/cli">fiboa command-line interface (CLI)</a>. This can be easily installed by running pip install fiboa-cli on any command line with Python 3.9 or above installed. It works like any command-line tool, and you can just type ‘fiboa’ on your command line and you can explore from there:</p>

<p><img src="https://cloudnativegeo.org/images/20240502-fiboa-ecosystem-image1.gif" alt="GIF of fiboa CLI" /></p>

<p>The most important command is likely <code class="language-plaintext highlighter-rouge">validate</code>, which lets you check any GeoJSON and GeoParquet file to confirm whether it is a valid fiboa file. This operation is key to ensuring interoperability. It does no good to just have people ‘try’ to implement the specification with no way to ensure that they are doing it correctly. Validation will ideally be written into any workflow with fiboa data, to ensure all tools can count on it being represented properly.</p>

<p>All the validation is completely dynamic. fiboa files themselves point at the versions of core and extensions that they declare themselves as supporting, which means if there is a new release then they can immediately point at the new release file’s location and the validators will check against the latest. This means that there does not need to be a new release of the validators for each new extension release since it automatically follows where the file points. The validator works against local files as well as remote files.</p>

<p>The ‘describe’ tool is a favorite of mine, to quickly get a sense of the data.</p>

<p><img src="https://cloudnativegeo.org/images/20240502-fiboa-ecosystem-image3.png" alt="fiboa describe cli tool." /></p>

<p>The fiboa ‘create’ tool is also quite useful, as it can take a GeoJSON file and the intended schemas and transform them into the GeoParquet version.</p>

<p>And then there are a bunch of utilities to help with creating fiboa files and metadata. They include <code class="language-plaintext highlighter-rouge">create-geojson</code> which makes a fiboa GeoJSON from a fiboa GeoParquet, <code class="language-plaintext highlighter-rouge">create-geoparquet</code> which does the opposite, and <code class="language-plaintext highlighter-rouge">fiboa jsonschema</code> which will write out the valid JSON Schema for a given fiboa file.</p>

<p>Matthias has put together a few nice tutorials, and all of these fiboa tools are covered in the ‘CLI Basics tutorial’. You can read the <a href="https://github.com/fiboa/tutorials/tree/main/cli-basics">text version</a> of it, or watch <a href="https://www.youtube.com/watch?v=_5HKsw8OvF0">the video</a>. The tutorial also covers this <a href="https://github.com/fiboa/tutorials/blob/main/cli-basics/load-fiboa.ipynb">great Jupyter notebook</a> that demonstrates how to do some analysis of fiboa data.</p>

<p><img src="/assets/img/posts/fiboa-the-ecosystem/20240502-fiboa-ecosystem-image2.png" alt="fiboa cli demo." /></p>

<p><em>Video tutorial on the fiboa command-line interface <a href="https://www.youtube.com/watch?v=_5HKsw8OvF0">on YouTube</a>.</em></p>

<p>There is also a new converter tool, which can take non-fiboa data and help you turn it into fiboa data. Each converter must be implemented as part of the CLI library, but once it’s there then it’s available for anyone to convert any ‘official’ data to the fiboa version. Currently, there are only converters for open datasets in Germany and Austria, but it is relatively easy to add one. Doing so will make it simple for any user of agricultural datasets to convert for other regions. Matthis put together a great tutorial on how to easily create a new converter using the templates. A <a href="https://github.com/fiboa/tutorials/blob/main/cli-convert/README.md">text version</a> and <a href="https://www.youtube.com/watch?v=-SUDzug29Cg&amp;list=PLENrKR4uOfvXH-bDf1ornXgO6NdEL25ZS&amp;index=4">video</a> are available for this process as well. If you do create a new converter, please contribute it to the project so others can also use it.</p>

<h2 id="community">Community</h2>

<p>While there’s a great start to the ecosystem above, we’re still in the early days. The key now is building an amazing community that can make this effort far bigger than we’ve dreamed of. We did the initial workshop in person to build up trust and connection as humans in an initial group, but our next goal is for the community to be centered online, in the style of the best open communities that we all know about. We hope to do more in-person events, but as a way to enhance the primary online collaborations. It will take some time to transition, and this is where we could use help! Mostly by joining in the effort, especially if you weren’t in the original workshop. We will not see this effort as successful until there are more people contributing than there were at the first workshop.</p>

<p>We’ve just recently started forming the rituals and communications that form the community. The center will certainly be the <a href="https://github.com/fiboa/">fiboa organization</a> on GitHub. This is where the <a href="https://github.com/fiboa/specification">core specification</a>, most of <a href="https://github.com/fiboa/extensions">the extensions</a>, the <a href="https://github.com/fiboa/software">core tools</a>, and the <a href="https://github.com/fiboa/specification/discussions">discussion forum</a> live. It’s also where we’re doing all the <a href="https://github.com/orgs/fiboa/projects/2">project management</a> of all the different pieces. We aim to add tags in our projects on ideas for good first tasks to help beginner contributors find easy ways to get involved.</p>

<p>We do think some real-time discussion can really move things forward. We have bi-weekly Zoom meetings for progress checks (see <a href="https://github.com/orgs/fiboa/projects/2/views/3">project board</a>). Yet we strive to follow best practices for online communities, aiming to make all decisions fully online in the repositories, and posting everything that happens, so that the Zoom meetings are a complement to the core running of the project and not how the project is run. We’ll also aim for some ‘break out’ sessions to enable higher bandwidth collaboration on key topics like defining new extensions, delving into core spec questions, or giving deeper demo sessions. Anyone and everyone is welcome to join both the bi-weekly calls and any break-out sessions. You can get these calls added to your Google calendar by joining the <a href="https://groups.google.com/a/tgengine.org/g/fiboa">fiboa Google Group</a>. Join the #fiboa Slack channel on the <a href="https://join.slack.com/t/cloudnativegeo/shared_invite/zt-2i37pc3nm-9bXiRHYrI6fH5qFh2VaLFA">Cloud Native Geospatial Slack</a> for async / chat communication.</p>

<h2 id="join-us">Join us!</h2>

<p>There are many ways to contribute, some mentioned above. If you’d like to learn more (even if you aren’t ready to contribute), join our Slack or jump into the bi-weekly meetings. All are welcome to just join and observe. And if you just want to ‘do something’ then the best way is to actually try to take an existing field boundary dataset and try to convert it to fiboa, and uploading it to Source Cooperative. Matthias’s tutorials should guide you. If any questions remain, please feel encouraged to ask them on the fiboa Slack channel. We are also planning to publish more information, documentation, and tutorials in the future. But until then, just jump in and get in touch.</p>

<p>We look forward to working with you, and building this project together!</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[fiboa is a new collaborative project to improve farm field boundary data interoperability and other associated agriculture data, that we introduced a couple of weeks ago. This post complements our previous deep dive into the follow-up post core specification and its extensions. In that post, we mentioned that fiboa is not just a specification; it’s a complete system. It includes the entire ecosystem of data adhering to the specification, the discussions and conversations that evolve the specs, and of course, the community people who are building it all together. In this post, we introduce the initial tools, data, and community that form that ecosystem.]]></summary></entry><entry><title type="html">fiboa: Core Specification &amp;amp; Extensions</title><link href="https://9eo.org/blog/fiboa-core-specification-extensions/" rel="alternate" type="text/html" title="fiboa: Core Specification &amp;amp; Extensions" /><published>2024-04-29T00:00:00+00:00</published><updated>2024-04-29T00:00:00+00:00</updated><id>https://9eo.org/blog/fiboa-core-specification-extensions</id><content type="html" xml:base="https://9eo.org/blog/fiboa-core-specification-extensions/"><![CDATA[<p>Last week, we <a href="https://cloudnativegeo.org/blog/2024/04/introducing-fiboa/">introduced fiboa</a>, a collaborative project with the <a href="https://tgengine.org/">Taylor Geospatial Engine (TGE)</a> designed to standardize farm field boundary data and bootstrap an ‘architecture of participation’ around agricultural and related data. The center of <a href="https://github.com/fiboa/">fiboa</a> is a <a href="https://github.com/fiboa/specification/tree/main">specification</a> for representing field boundary data in GeoJSON &amp; GeoParquet in a standard way, with optional ‘extensions’ that specify additional attributes. But we believe that thinking of fiboa as ‘just’ a specification is outdated. fiboa is the entire ecosystem of data adhering to the specification, tools to help convert data (including using AI models to in turn create more data), the discussions and conversations that evolve the specs, and of course the community people who are building it all together.</p>

<p>This blog post dives into the heart of fiboa: the core specification and its extensions. We’ll explore the core attributes that define this format and how the extensions enable interoperability of all types of information that can be associated with a field boundary. You should start with the <a href="https://cloudnativegeo.org/blog/2024/04/introducing-fiboa/">Introducing fiboa post</a> if you’ve not read it, as it articulates the overall philosophy behind the project. This post goes deep into the specification &amp; extensions, and then we’ll follow up with the current state of tools, data, and community.</p>

<h2 id="core-specification">Core specification</h2>

<p>The core of fiboa is quite simple: it is a set of definitions for attribute names and values. One clear example is <code class="language-plaintext highlighter-rouge">area</code>. It’s quite common for geospatial files representing field boundaries to have a column for the area of the field, but it’s often called different things: <code class="language-plaintext highlighter-rouge">area</code>, <code class="language-plaintext highlighter-rouge">area_ha</code>, <code class="language-plaintext highlighter-rouge">totalArea</code>, etc. And even if it’s called the same thing the actual data definition could be different: area could easily be in acres or hectares, or even something else. So what fiboa does is picks a definition; in our case area is in hectares and must be a ‘float’ between 0 and 100,000. Any data that implements fiboa and successfully validates can then be definitively interpreted as being in hectares.</p>

<p><img src="/assets/img/posts/fiboa-core-specification-extensions/20240429-fiboa-spec-image2.png" alt="fiboa Core Spec" /></p>

<p><em>fiboa Core Spec, at &lt;github.com/fiboa/specification/tree/main/core&gt;</em></p>

<p>fiboa specifies the attributes in a <a href="https://github.com/fiboa/specification/tree/main/core/schema">human-readable form</a> as shown above, along with a machine-readable <a href="https://github.com/fiboa/specification/blob/main/core/schema/schema.yaml">yaml</a> file. Then there are folders for <a href="https://github.com/fiboa/specification/tree/main/geoparquet">GeoParquet</a> and <a href="https://github.com/fiboa/specification/tree/main/geojson">GeoJSON</a> outputs that contain official examples and specs. This means that there are <a href="https://github.com/fiboa/cli">validation tools</a> that can take any data in those formats and report whether it properly implements the core fiboa data schema (along with any extensions - more on those soon).</p>

<p><img src="/assets/img/posts/fiboa-core-specification-extensions/20240429-fiboa-spec-image1.png" alt="fiboa Core Spec" /></p>

<p><em>Validation of <a href="https://beta.source.coop/repositories/fiboa/de-nrw/description/">Field Boundaries for North Rhine-Westphalia (NRW), Germany</a> using the <a href="https://github.com/fiboa/cli">fiboa CLI</a></em></p>

<p>GeoJSON generally works best for things like API responses or transferring small amounts of data. GeoParquet shines when storing or moving any sizable amount of data since it is a much faster and more compact format. GeoParquet is a newer format and there is not yet universal tool support, but a big benefit is it can be stored on the cloud and clients can easily stream just the bits they need. Major data projects like <a href="https://overturemaps.org/">Overture Maps</a> are supporting it and the ecosystem is growing fast, so we decided to embrace it as we envision all global fields represented in fiboa, and billions of polygons are much better served by a more modern <a href="https://guide.cloudnativegeo.org/">cloud-native geospatial format</a>. For the <a href="https://tgengine.org/innovation-bridge/field-boundary-initiative/">TGE Field Boundary Initiative</a>, we’re using <a href="https://beta.source.coop">Source Cooperative</a> as our primary data infrastructure, and it works great with GeoParquet.</p>

<p>Thankfully it is quite easy to transform any fiboa data into other geospatial formats like GeoPackage or Flatgeobuf, as the attribute names and values will be retained. We do not recommend using Shapefile due to various technical limitations of the format. Unofficial validators may emerge for those, or we could consider officially supporting them - we just wanted to start with a small core.</p>

<p>The number of attributes in the core is quite small, and that’s by design. The idea is that most all the ‘interesting’ data about the field will be in extensions. So even something that many people would consider a core property like ‘crop classification’ will go in extensions. This is so that the definitions can evolve more easily, and so we don’t have people who don’t adopt fiboa because they have their own crop classification system that works better for their use case. The extensions give the possibility of several crop classification extensions. Practically we do hope that one main crop classification extension emerges, and that will likely happen if the largest, most valuable datasets all use the same extension. But we don’t believe the small group of people involved at the start can get all the core attributes completely right from the start. Indeed we don’t even believe that there is one ‘true’ answer to the right data schema for agricultural data. So our approach is to create the tools for everyone to define what they need and to then validate against their own extensions. Naturally, some frequently used ‘core extensions’ will emerge. Much of the inspiration for this comes from the <a href="https://stacspec.org/en">STAC specification</a>. For STAC, several well-used extensions have emerged, and therefore we expect the same for fiboa.</p>

<p>As of right now, the only required attributes <a href="https://github.com/fiboa/specification/blob/afaa9dd04bf5c5f6b60508ee419b02c31d470052/core/README.md">in the core</a> fiboa specification are <code class="language-plaintext highlighter-rouge">id</code> and <code class="language-plaintext highlighter-rouge">geometry</code>. Then we have optional attributes for spatial properties (<code class="language-plaintext highlighter-rouge">bbox</code>, <code class="language-plaintext highlighter-rouge">area</code>, and <code class="language-plaintext highlighter-rouge">perimeter</code>), and a couple of properties about the creation (<code class="language-plaintext highlighter-rouge">determination_method</code> and <code class="language-plaintext highlighter-rouge">determination_datetime</code>).</p>

<p><img src="/assets/img/posts/fiboa-core-specification-extensions/20240429-fiboa-spec-image3.png" alt="fiboa determination properties" /></p>

<p>The method used to create the boundary is quite important, particularly in AI use cases where you would not want to train an AI on data that itself was auto-created by AI from other imagery. The <code class="language-plaintext highlighter-rouge">determination_datetime</code> was the subject of much debate, and we did talk through various datetimes that people care about a lot but decided that it’d be best to cover all the various datetime options in an extension that is explicit about what each time means. We did want to have one date time in the core and coalesced on the <code class="language-plaintext highlighter-rouge">determination_datetime</code>, which is the last time at which this particular field was observed, so you can tell if a field is up to date or created a while ago. We thought about making the datetime attribute required but did not want to end up with a bunch of bad time data as many datasets don’t have precise time information and they’d just end up dumping ‘something’ in there.</p>

<p>The core will likely evolve a good bit, and feedback on these decisions is more than welcome, as this release mostly aims to start the conversation. When we feel it’s more settled we’ll likely call it ‘beta’, but there are still some big things to figure out, like <a href="https://github.com/fiboa/specification/issues/4">what should be at the ‘collection’ level</a> and <a href="https://github.com/fiboa/specification/issues/13">what to do when different collections of data are merged</a>.</p>

<h2 id="extensions">Extensions</h2>

<p>I touched on the philosophy behind extensions above, and it’s hopefully clear that <a href="https://github.com/fiboa/extensions">extensions</a> in fiboa aren’t just extraneous information that doesn’t really matter. The bulk of fiboa’s value will be in extensions. There will likely be lots of different types of extensions: some that are generally accepted as the main way to do things in fiboa and widely understood by tools and others that are very niche and not widely used but valuable to a small number of users (e.g. an extension specific to a company or organization to help them better validate their data).</p>

<p>Implementing an extension enables the dataset to make use of the ecosystem of fiboa tools, including validations to ensure that the values in a dataset meet the requirements of an extension. This, in turn, lets tools ‘know’ that a particular value in two different datasets means the exact same thing and can be combined. This should lead to much more innovation in tools to work with the data since tool providers don’t need to code against particular datasets or try to get everyone to convert their data into a random schema for the tool to work. Everyone can work towards a common target, creating a virtuous cycle where converting agricultural data to fiboa makes it work with more tools, more tools get created because there’s more data in fiboa, and then more data gets converted because there are even more tools that come from converting data.</p>

<p>We put in quite a bit of work to make the process of creating extensions as easy as possible (and by ‘we’ I mean Matthias Mohr did a ton of awesome work, funded by TGE). Each extension is defined by a GitHub repository that contains all the information about the extension and publishes the schemas that tools directly call for validation. The cool thing is that Matthias created a ‘template’ where all you need to do is hit ‘use template’ and you’re 80% of the way to making an extension.</p>

<p><img src="/assets/img/posts/fiboa-core-specification-extensions/20240429-fiboa-spec-image4.png" alt="fiboa extension-template" /></p>

<p>You edit the readme, customize a YAML template, and create an example GeoJSON file. Then, the repo template provides all the tools to convert it to GeoParquet, validate everything, and run continuous integration to ensure each new commit remains valid. When you hit ‘release’ for the repo, the schema is automatically published and any of the ecosystem tools can instantly start validating datasets against it. This was awesome to see in action at the initial workshop, as I was able to fully release a new extension and then validate data against it using the <a href="https://github.com/fiboa/cli">command-line tool</a> in just a couple of hours.</p>

<p>Matthias has built a tutorial on creating a new extension, for anyone interested in trying to create one. You can find it at <a href="https://github.com/fiboa/tutorials/tree/main/create-extension">github.com/fiboa/tutorials/tree/main/create-extension</a>, and it has a link to the video recording there as well.</p>

<h3 id="initial-extensions">Initial Extensions</h3>

<p>So far we’ve only managed to create <a href="https://github.com/fiboa/extensions?tab=readme-ov-file#list-of-extensions">four extensions</a>, but we aim for many more over the next few months. The one that saw a lot of effort during the workshop was the <a href="https://github.com/fiboa/ai-ecosystem-extension">AI Ecosystem Extension</a>.</p>

<p><img src="/assets/img/posts/fiboa-core-specification-extensions/20240429-fiboa-spec-image5.png" alt="fiboa AI ecosystem extension" /></p>

<p>It includes everything you’d want in a dataset to be able to reliable machine learning from it, including things like the author, the quality, the confidence, and whether it was machine-generated. In time some of these things may migrate to more general extensions, but the idea was to first get down everything that an AI/ML tool would need to be able to use the fiboa dataset and run models with it. There was also work done in the workshop so <a href="https://github.com/lezcano/geotorch">GeoTorch</a> could easily read in the data.</p>

<p>The other extension made in the workshop is the <a href="https://github.com/fiboa/tillage-extension">Tillage Extension</a>. I worked with Jason Riopel of Bayer and Katie Murphy of the Donald Danforth Plant Science Center on this one. We started it as a ‘management practices’ extension but quickly realized that there were several attributes about tillage that people would use, so we broke it out into its own extension. I knew close to nothing about tillage, so it was cool to have them brainstorm what people want to know, what to call the attributes, and how to explain them. The extension is by no means ‘done’, but we managed to put out a 0.1 release. The next step will be to try to get one or more ‘real’ datasets converted, to validate that it works with existing data.</p>

<p>The <a href="https://github.com/fiboa/inspire-extension">INSPIRE</a> and <a href="https://github.com/fiboa/flik-extension">FLIK</a> extensions define specific identifiers that are commonly used in the EU and Germany. Those two were added to support <a href="https://github.com/fiboa/data">some of the first datasets converted to fiboa</a> and <a href="https://beta.source.coop/fiboa/">hosted on Source Cooperative</a>. I think that will be one of the main ways extensions get developed - start with a dataset to be converted and look at the attributes that aren’t already in fiboa. And then figure out if some of them are really ‘common’ ones that many datasets would want to represent. It’s worth doing some looking <a href="https://github.com/fiboa/data-survey">at other datasets</a>, but since making an extension is so easy it’s also great to just create the extension and then solicit feedback as others hit similar problems, and evolve it in the open.</p>

<h3 id="next-extensions">Next Extensions</h3>

<p>While each extension gets an individual repository, we also have an overall Extensions Repository at <a href="https://github.com/fiboa/extensions">github.com/fiboa/extensions</a> that lists all available extensions. The issues in the extensions repository serve as a tracker for potential new extensions. Right now we’ve only got three extensions listed as priorities, but the workshop generated many more ideas that we’ll post to the tracker soon. Some examples include yield, crop classification, soil moisture, phenology, irrigation, soil information, climate risk, harvest dates, deforestation, ownership information, surface temperature, etc.</p>

<p>Two proposed extensions that are pretty critical to get to soon are Identifiers and Timestamps. For IDs, we are particularly interested in things like Varda’s <a href="https://www.varda.ag/global-field-id">Global FieldID</a> being represented easily, to help promote their awesome work. We know that many other ID schemes are important to people, so creating an extension to allow for those to exist within fiboa is a priority. For Timestamps, we anticipate a deep discussion of all the different types of time that people care about with fields. We started talking about it at the workshop, and it became clear it was a much bigger topic than we could handle in an hour or two. We also ticketed ‘management practices’, which will likely be broken into multiple extensions on cover crop, fertility, crop protection, manure, irrigation, residue management, etc. It may make sense to have an overarching extension that groups them together.</p>

<p>Extensions are generally the area that is ripest for collaboration, and we’re keen to get at least some initial alpha releases out. The recommended way to work on these is to start with one dataset that represents some additional data related to field boundaries and see how they do it. Ideally, at least a couple of datasets that represent the same attributes are found, and if they all do things similarly then it should be easy to determine what goes in the extension. If their approach differs, just pick the one that makes the most sense and is the most future-proof. The idea is to release ‘early and often’, and to get feedback through actually ‘doing’, not trying to gather all potential stakeholders in a room. Ideally, by a ‘1.0 release’ of any extension there are many different datasets in fiboa that use the extension, so we feel confident that it works well.</p>

<h2 id="next-steps">Next Steps</h2>

<p>So I hope this post served as a solid introduction to the core fiboa specifications. We’ll aim to follow-up very soon with details on the data, tools and community that are just as important as the core spec. And after that we’ll post more of the ‘why’ behind the initiative. If you’re intrigued by what you’ve read then please consider joining us! We certainly can’t do it all alone, and this movement is only going to succeed beyond our dreams if we manage to attract far more people than the original group. We’ve got a lot of great momentum, and the amazing support of Taylor Geospatial Engine, but the goal is to use these next months to really bootstrap the community that will live beyond the initial <a href="https://tgengine.org/introducing-taylor-geospatial-engine-and-the-innovation-bridge-program/">Innovation Bridge Initiative</a>.</p>

<p>To join the community check out our <a href="https://github.com/fiboa#developer-communication-channels">developer communication channels</a> or just start digging into all the repos linked to from <a href="https://github.com/fiboa/">github.com/fiboa</a>.</p>

<p><img src="/assets/img/posts/fiboa-core-specification-extensions/20240429-fiboa-spec-image6.png" alt="fiboa Developer Communication Channels" /></p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[Last week, we introduced fiboa, a collaborative project with the Taylor Geospatial Engine (TGE) designed to standardize farm field boundary data and bootstrap an ‘architecture of participation’ around agricultural and related data. The center of fiboa is a specification for representing field boundary data in GeoJSON &amp; GeoParquet in a standard way, with optional ‘extensions’ that specify additional attributes. But we believe that thinking of fiboa as ‘just’ a specification is outdated. fiboa is the entire ecosystem of data adhering to the specification, tools to help convert data (including using AI models to in turn create more data), the discussions and conversations that evolve the specs, and of course the community people who are building it all together.]]></summary></entry><entry><title type="html">Introducing fiboa</title><link href="https://9eo.org/blog/introducing-fiboa/" rel="alternate" type="text/html" title="Introducing fiboa" /><published>2024-04-17T00:00:00+00:00</published><updated>2024-04-17T00:00:00+00:00</updated><id>https://9eo.org/blog/introducing-fiboa</id><content type="html" xml:base="https://9eo.org/blog/introducing-fiboa/"><![CDATA[<p>We are excited to announce fiboa (Field Boundaries for Agriculture), a new project we’re collaborating on with the <a href="https://tgengine.org/">Taylor Geospatial Engine</a> (TGE) focused on improving interoperability of farm field boundary data and other associated agriculture data. We’re excited about the enormous potential of this project, and we’ve already started a community of people who share our excitement.</p>

<p>fiboa is the first concrete result from the <a href="https://tgengine.org/innovation-bridge/field-boundary-initiative/">TGE Field Boundary Initiative</a>, which aims to enable practical applications of AI and computer vision to Earth observation imagery for a better understanding of global food security. The initiative has spurred collaboration between academia, industry, NGOs, and governmental organizations toward creating shared global field boundary datasets that can be used to create a more sustainable and equitable agriculture sector.</p>

<p>We worked with TGE to launch this effort in February at a workshop in St. Louis that brought together almost 20 different organizations including Microsoft, Google, Bayer, and the World Resources Institute. At the end of the two days, we shipped version 0.1 of the <a href="https://github.com/fiboa/specification/blob/main/core/README.md">fiboa core specification</a> (we have continued to work on it and it is now at version 0.2), which provides a common language for any dataset to describe field boundaries and a way to add <a href="https://github.com/fiboa/extensions">extensions</a> to add ancillary data and metadata about fields.</p>

<p><img src="/assets/img/posts/introducing-fiboa/20240417-fiboa-image3a.png" alt="" /></p>

<h3 id="why-a-farm-field-boundary-data-schema">Why a farm field boundary data schema?</h3>

<p>We recently wrote about how <a href="../blog/2024/04/common-schemas-and-ids/">commonly used data schemas are essential</a> to enable data interoperability and collaboration on complex global challenges. fiboa is our first effort to put that thinking into practice by creating a common schema for farm field boundaries.</p>

<p>Farm fields are a foundational unit of production for any agricultural supply chain. Efforts to improve agricultural practices such as the European Union’s deforestation regulation (EUDR) will only succeed if we have reliable information about where food comes from, and many of the world’s most common food products like wheat, maize, potatoes, and soybeans originate from farm fields. Despite this, there is not yet a commonly accepted data schema to describe farm fields.</p>

<p>By convening a community of practitioners who work with field data, we hope to solve this problem quickly and practically, creating a shared language that will foster and accelerate innovation among everyone working to understand agricultural supply chains. A common schema will enable seamless exchange of data among a variety of tools rather than requiring data engineers to create mappings from one dataset to another.</p>

<h3 id="why-now">Why now?</h3>

<p>We’re doing this now because we are at a point when it is possible to create and distribute planetary-scale field boundary data much more quickly and cheaply than ever before. Many field boundaries around the world can be derived by applying machine learning (ML) techniques to freely available satellite imagery. TGE has funded research teams led by <a href="https://hannah-rae.github.io/?trk=article-ssr-frontend-pulse_little-text-block">Dr. Hannah Kerner</a> at Arizona State University and <a href="https://engineering.wustl.edu/faculty/Nathan-Jacobs.html?trk=article-ssr-frontend-pulse_little-text-block">Dr. Nathan Jacobs</a> at Washington University in St. Louis to accelerate research in this area and determine if ML-derived data can be commercially viable.</p>

<p>Simultaneously, advances in cloud-native vector data formats like GeoParquet also make it trivial to share the large volumes of field boundary data that can be produced from satellite imagery. We will be working with researchers who produce field boundary data to get it into the fiboa specification and then publish it in cloud-native formats on <a href="https://source.coop/">Source Cooperative</a>.</p>

<h3 id="how-will-this-work">How will this work?</h3>

<p>Though we don’t have a formally published set of collaboration principles, this declaration from the <a href="https://ieeexplore.ieee.org/document/1677461">Internet Engineering Task Force</a> (IETF) is a good summary of our approach:</p>

<blockquote>
  <p>“We reject: kings, presidents, and voting. We believe in: rough consensus and running code.”</p>
</blockquote>

<p>We place higher value on practical, working solutions and the broad agreement of participants than trying to vote for the perfect data schema. The principles that guide us are similar to the <a href="https://github.com/radiantearth/stac-spec/blob/master/principles.md">Core Principles</a> we came up with for the <a href="https://stacspec.org/">SpatioTemporal Asset Catalog</a>, summarized here:</p>

<ul>
  <li>Creation and evolution of specs in Github JSON + REST + HTTP at the core.</li>
  <li>Small reusable pieces loosely coupled.</li>
  <li>Focus on the developer.</li>
  <li>Working code required.</li>
  <li>Design for scale.</li>
</ul>

<p>It is in this spirit that fiboa will be built in public with many members of our community throughout the coming year and beyond. While fiboa is merely a metadata specification, we see it as the basis for a robust <a href="http://radar.oreilly.com/2006/07/four-big-ideas-about-open-sour.html">architecture of participation</a> that will allow many people and institutions to contribute the specifications, tools, and data that we need to improve our understanding of the global agricultural sector. For a deeper dive on what we’re up to see <a href="https://cloudnativegeo.org/blog/2024/04/fiboa-core-specification-extensions/">fiboa: Core Specification &amp; Extensions</a> and <a href="https://cloudnativegeo.org/blog/2024/05/fiboa-the-ecosystem/">fiboa: The Ecosystem</a>.</p>

<p>If you’re interested in getting involved, please feel free to contribute via the <a href="https://github.com/fiboa">fiboa GitHub</a>, join our Slack, or email us at <a href="mailto:hello@cloudnativegeo.org">hello@cloudnativegeo.org</a>. We also invite you to a live tutorial presented by <a href="https://www.linkedin.com/in/matthias-mohr-565748178">Matthias Mohr</a> on Thursday April 25 at 12 pm ET and on Monday, April 29 at 11 am EST. These sessions introduce you to the fiboa CLI and demonstrate how to create a fiboa extension, and the recordings are now available at <a href="https://github.com/fiboa/tutorials/">github.com/fiboa/tutorials/</a>.</p>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[We are excited to announce fiboa (Field Boundaries for Agriculture), a new project we’re collaborating on with the Taylor Geospatial Engine (TGE) focused on improving interoperability of farm field boundary data and other associated agriculture data. We’re excited about the enormous potential of this project, and we’ve already started a community of people who share our excitement.]]></summary></entry><entry><title type="html">The Importance of Common Data Schemas and Identifiers</title><link href="https://9eo.org/blog/the-importance-of-common-data-schemas-and-identifiers/" rel="alternate" type="text/html" title="The Importance of Common Data Schemas and Identifiers" /><published>2024-04-06T00:00:00+00:00</published><updated>2024-04-06T00:00:00+00:00</updated><id>https://9eo.org/blog/the-importance-of-common-data-schemas-and-identifiers</id><content type="html" xml:base="https://9eo.org/blog/the-importance-of-common-data-schemas-and-identifiers/"><![CDATA[<p>We created the Cloud-Native Geospatial Foundation because we’ve noticed rapid adoption of cloud-native geospatial formats, such as <a href="https://www.cogeo.org">Cloud-Optimized GeoTIFF (COG)</a>, <a href="https://stacspec.org/en">SpatioTemporal Asset Catalogs (STAC)</a>, <a href="https://zarr.dev">Zarr</a>, and <a href="https://geoparquet.org">GeoParquet</a>. Both data providers and users enjoy time and cost savings when using cloud-native formats, and we believe there’s a need to help more people learn how to benefit from them.</p>

<p>Despite that, creating more cloud-native formats is a <a href="https://en.wiktionary.org/wiki/non-goal">non-goal</a> for us. There are plenty of people within our community working on cloud-native formats such as <a href="https://copc.io">Cloud-Optimized Point Clouds (COPC)</a>, <a href="https://github.com/zarr-developers/geozarr-spec">GeoZarr</a>, and <a href="https://docs.protomaps.com/pmtiles/">PMTiles</a>. At this point, most use cases are covered by existing formats.<a href="#fn:1">1</a></p>

<p>In addition to the time and cost savings, one huge benefit of using cloud-native data formats is <em>interoperability</em> – the ability for different systems to share information easily. Common data formats are an essential part of interoperability, but we’re starting to explore a new dimension of data that is may be much more important to enabling interoperability: <em>common data schemas</em> and <em>common identifiers</em>.</p>

<p>This post is an effort to explain how common data schemas and identifiers can enable global cooperation and maximize the value of geospatial data.</p>

<h2 id="the-current-state-of-schemas-and-identifiers-in-geospatial">The current state of schemas and identifiers in geospatial</h2>

<p>Common data schemas refer to widely used ways to name and refer to the attributes and values within data products. Common identifiers are widely used ways to refer to unique entities in the world. To use a very simplistic example, a schema to describe a person could consist of <code class="language-plaintext highlighter-rouge">first_name</code>, <code class="language-plaintext highlighter-rouge">last_name</code>, <code class="language-plaintext highlighter-rouge">passport_issuing_country</code>, and <code class="language-plaintext highlighter-rouge">passport_number</code>. Because humans may share the same first and last names, we can’t use names as unique identifiers, but we can expect that countries will not issue the same passport number to multiple people. Therefore, a globally unique identifier for a person could be made up of a combination of the values of <code class="language-plaintext highlighter-rouge">passport_issuing_country</code> and <code class="language-plaintext highlighter-rouge">passport_number</code>.</p>

<p>While simple and imperfect in many ways, we have developed a several workable ways to describe and identify individual humans, which is foundational to things like travel, telecommunications, banking, and public safety. Let’s compare that to the present state of open geospatial data.</p>

<p>If you were to download parcel data from 3 different adjacent counties anywhere in the country today, the data you get would likely all have different names of attributes of those parcels. In Washington State, for example, King County shares data where parcel data is shared in a column named <a href="https://gis-kingcounty.opendata.arcgis.com/datasets/886d26db57aa4d2eb29bd50f4b385616_2598/explore?showTable=true"><code class="language-plaintext highlighter-rouge">PIN</code></a>, Pierce county parcels are in a column named <a href="https://gisdata-piercecowa.opendata.arcgis.com/datasets/piercecowa::development-engineering-formal-plats/explore?showTable=true"><code class="language-plaintext highlighter-rouge">parcel_num</code></a>, and Snohomish county’s header is named <a href="https://snohomish-county-open-data-portal-snoco-gis.hub.arcgis.com/datasets/f22302b98ddd48be9c7836a836a4c1b1_0/explore?location=48.036146%2C-121.695208%2C9.68&amp;showTable=true"><code class="language-plaintext highlighter-rouge">PARCEL_ID</code></a>. Likewise, each county uses different attributes with different names to describe those parcels. Because of this, if you wanted to combine the data into a single dataset containing parcels from different counties, you’d need to understand the meaning of each of their attributes and figure out how to translate them all to use consistent names.</p>

<p>Since parcel data is quite valuable, there are a number of companies who make it their business to acquire parcel data from official sources and transform it into a common data schema. At some level this makes sense – governments produce parcel data for their own local needs and have few incentives to spend time agreeing on schemas with other governments, and the market has found a way to solve the inefficiencies that come from this lack of coordination. But on another level, we think this this is something we should try to fix.</p>

<p>As we’ve written before, <a href="https://radiant.earth/blog/2023/05/we-dont-talk-about-open-data">merely opening data is not enough</a>. The current state of merely making geospatial data available for download does not amount to “infrastructure” if it fails to enable interoperability. Government agencies (and the citizens they serve) benefit when it’s easy for them to share data with their neighbors and other stakeholders. If we can lower the cost of consolidating disparate datasets, it will be easier for us to cooperate on shared challenges.</p>

<h2 id="cloud-native-spatial-data-infrastructure">Cloud-Native Spatial Data Infrastructure</h2>

<p>Because publishing cloud-native data is as simple as uploading files to a commodity cloud object service<a href="#fn:2">2</a>, it is now easier for data publishers to collaborate and experiment with new schemas. This ease of experimentation was a major contributor to the development and adoption of STAC. Contrast this with the state of numerous open data portals today that require rigid data models and are designed in ways that discourage experimentation at the schema level.</p>

<p>One way to solve this problem could be to create a platform that requires data providers to use the same data model rather than having them build their own. We have a great example of a collaborative effort to do just that: OpenStreetmap (OSM). Just like Wikipedia provides a consistent format and is loosely governed by <a href="https://en.wikipedia.org/wiki/Wikipedia:Five_pillars">a set of principles</a> to create one huge encyclopedia for the world, OSM has created a shared space for anyone to contribute to one huge map of the world. Despite the immense value created by OpenStreetMap, we believe that a better model for geospatial data beyond mapping data is the open source ecosystem.</p>

<p>Open source software doesn’t rely on one big repository with one set of rules governing one community. It’s incredibly diverse, made up of many different repositories, created by people with diverse needs, with different values embedded into their approach. Some projects are large and benefit from many contributors. Others are relatively small tools maintained by just a few people. Some projects are esoteric and others are foundational to the entire Internet. A robust cloud-native spatial data infrastructure can share a similar structure, emerging from contributions made by many communities that are cross-dependent with one another.</p>

<p>The way to enable collaboration across such a diverse community is by providing foundational datasets, identifying a few core identifiers and geometries that everyone relies upon, and providing flexible schemas that enable different communities to meet their unique needs while speaking a common language. From our perspective, enabling diversity isn’t merely a nice thing to have, but it’s core to maximizing the value of geospatial data.</p>

<p>Once a common data schema is established, everyone publishing data in that format is contributing towards a collective understanding of our world. That sounds grand, but it’s not impossible. It’s similar to how languages develop. To do this, we propose starting by focusing fundamental attributes of our environment that are easy to understand across different contexts.</p>

<p>We also don’t envision a single data schema that everyone has to align to. Instead, there’s a way to start with a small, common core of information that gives data providers the flexibility to use the pieces that are relevant to them and easily add their own. This approach is based on our experience building the SpatioTemporal Asset Catalog <a href="https://github.com/radiantearth/stac-api-spec/tree/release/v1.0.0/core">core</a> and <a href="https://github.com/radiantearth/stac-spec/blob/master/extensions/README.md">extensions</a> approach.</p>

<h2 id="enabling-new-applications-and-ai">Enabling new applications and AI</h2>

<p>If successful, this will not only make things easier for users who want to combine a few sets of data, but will enable the creation of new types of software and data-driven applications. One of the pitfalls of traditional GIS tools is that many GIS users have been satisfied as long as their data looked ok on a map. We love maps, but a map is an interface created to deliver data to human eyes. If we want to maximize the value of geospatial data, it’s no longer enough to display it on maps – we need to optimize it for training AI models.</p>

<p>Common schemas and identifiers will make it much cheaper to write software that brings together diverse data, runs models, makes predictions, and lets people try out different scenarios. The approach we encourage enables data to remain fully abstracted, allowing software developers to point their code or models at it and have it “just work” without needing to be a data engineer.</p>

<p>A clear example of such innovative software is to create AI-based interfaces, and to realize the vision for ‘Queryable Earth’.</p>

<p><img src="/assets/img/posts/the-importance-of-common-data-schemas-and-identifiers/20240222-ids-1.png" alt="Screenshot of ChatGPT responding to the question: How many buildings are there in San Francisco" /></p>

<p>Right now, ChatGPT doesn’t know how many buildings there are in San Francisco, but this query is quite easy with a geographic information system, after downloading the <a href="https://data.sfgov.org/Geographic-Locations-and-Boundaries/Building-Footprints/ynuv-fyni">building footprints dataset</a> from <a href="https://data.sfgov.org/">data.sfgov.org</a>.</p>

<p>Making geospatial data available in common schemas will make it easier for models like ChatGPT to answer questions about our environment, but it will also let us ask more challenging questions, like ‘How many buildings are there in San Francisco over 200 feet tall’? Or even ‘what percent of buildings in San Francisco are within 500 feet of a bus stop?’. These are questions that a common data schema makes possible and potentially even easy. The first question just needs a definition of ‘height’ in any building data set, and the second needs a definition of ‘bus stop’ datasets.</p>

<p>Thinking further, this approach would make it trivial to write a GPT that would work with any ‘building’ dataset, especially if the dataset used a data schema with well-defined fields.</p>

<p><img src="/assets/img/posts/the-importance-of-common-data-schemas-and-identifiers/20240222-ids-2.png" alt="" /></p>

<p>The above is a GPT made with the San Francisco dataset to illustrate the point. Yes, the GPT provided an answer when asked about the number of buildings over 200 feet tall in San Francisco, but the answer is not actually right. The attribute it used for “feet” was actually a shortened name for <code class="language-plaintext highlighter-rouge">P2010mass_ZmaxN88ft</code> which is defined in the <a href="https://data.sfgov.org/api/views/ynuv-fyni/files/e6e73cd0-15be-47a8-9463-9c9a725b72c3?download=true&amp;filename=SF_BldgFoot_2017-05_description.pdf">dataset’s PDF documentation</a> as ‘Input building mass (of 2010,) maximum Z vertex elevation, NAVD 1988 ft’. ChatGPT couldn’t find where to get the height of buildings, so it used another column that shows the mass of buildings, calculated by LiDAR. There are actually at least 11 potential height values in this dataset. Part of the challenge of defining common schemas will be to identify and prioritize sensible defaults, so we can create simpler tools that provide the results that most people expect, while allowing extensions for people who have more specific queries.</p>

<h2 id="supporting-climate-use-cases-with-common-identifiers">Supporting climate use cases with common identifiers</h2>

<p>This general pattern should work for any common type of data and creates opportunities to improve the usability of data for climate use cases. We can imagine common schemas used to describe land parcels, pollution, trees, demographics, waterways, ports, etc.<a href="#fn:3">3</a></p>

<p>In particular, we are already focusing on ways to enable interoperability of agricultural data, finding common schemas for things like farm field boundaries, normalized difference vegetation index (NDVI), leaf area index, soil water content, yield predictions, crop type, and more.</p>

<p><img src="/assets/img/posts/the-importance-of-common-data-schemas-and-identifiers/20240222-ids-4.png" alt="Screenshot of the Varda Global FieldID website" /></p>

<p>Varda’s <a href="https://www.varda.ag/global-field-id">Global FieldID</a></p>

<p>This is where the combination of common schemas and identifiers becomes powerful. We have been collaborating with <a href="https://varda.ag">Varda</a>, a group that has created a collaborative approach to creating Global FieldID, a service creates stable, globally unique identifiers for farm field boundaries. By merely providing a common way to refer to farm fields, Global FieldID creates more transparent agricultural supply chains and simplify regulation to encourage regenerative agriculture practices and prevent deforestation. Beyond those benefits, having a common way to refer to farm fields will dramatically lower the cost of collaboration on agricultural data.</p>

<p>Other great examples of pioneering work to create global identifiers include <a href="https://opensupplyhub.org">Open Supply Hub</a> which creates unique IDs for manufacturing sites, and the <a href="https://www.gleif.org/">Global Legal Entity Identifier Foundation</a> which issues unique identifiers for legal entities all over the world.</p>

<p>A powerful benefit of common identifiers is how they allow different databases to refer to the same thing. A commonly used identifier can be used as a ‘join key’ that users can use to combine (or <a href="https://en.wikipedia.org/wiki/Join_(SQL)">join</a>) disparate datasets. This opens up a possibility to distribute information that’s spatial in nature, without having to always include geometry or location data.</p>

<p>For example, <a href="https://www.planet.com/">Planet</a> provides data products that include <a href="https://www.planet.com/products/planetary-variables/">Planetary Variables</a>, like crop biomass and soil water content, that are updated daily. These data products are rasters, and many workflows involve downloading the full raster every day. But if we had a common schema and a common identifier for farm field boundaries, these variables could be easily summarized into a simple table that contains the variable value and the field ID. Rather than redundantly sharing or storing geometry data, users could just update soil water content as it relates to their field IDs each day.</p>

<p><img src="/assets/img/posts/the-importance-of-common-data-schemas-and-identifiers/20240222-ids-3.png" alt="Screenshot a map showing farm fields delineated by Varda" /></p>

<p>Screenshot taken from Varda’s <a href="https://fieldid.varda.ag">Global FieldID</a> service showing field boundaries and their identifiers in southern Brazil.</p>

<p>Taking this further, these common identifiers provide a shared framework for everyone to create all kinds of new agricultural data products that are interoperable with other systems. Imagine a Kenyan entrepreneur who has access to local data sources and insights that allow them to develop accurate yield predictions for maize in their region – common field boundary data and identifiers would allow them to create a data product that is as simple a table with predicted yield per field specified by the field’s ID.</p>

<p>Similarly, someone focused on <a href="https://docs.riskdatalibrary.org/en/latest/reference/schema/#exposure-metadata">exposure data for disaster risk assessment in supply chains</a> could data from OpenSupplyHub and create a table that adds information about building materials and occupants to OpenSupplyHub production facility IDs.</p>

<p>Full communities could form around adding attributes to globally defined datasets. The <a href="https://www.cgfi.ac.uk/spatial-finance-initiative/geoasset-project/">GeoAsset Project</a> could be streamlined by people collaborating globally to add ownership information to <a href="https://overturemaps.org/overture-buildings-theme-hits-2-3b-buildings-with-addition-of-google-open-buildings-data/">unique building identifiers in Overture</a>, unique farm fields in Global FieldID, production facility IDs in OpenSupplyHub, or any find of asset that can be assigned a unique identifier.<a href="#fn:4">4</a> This would allow someone to create a GPT that could answer questions like “Which suppliers in our supply chain are most exposed to flood risk?” and “Are there any development groups who we could work with to mitigate flood risk where we operate?”</p>

<h2 id="whats-next">What’s next</h2>

<p>We are going to be working out these ideas throughout the course of the year, diving deeper into use cases and showcasing examples of data products that put these ideas into practice on <a href="https://source.coop">Source Cooperative</a>.</p>

<p>We will specifically be working on issues related to air quality in collaboration with AWS and applying AI to agricultural data with the Taylor Geospatial Engine as part of <a href="https://www.linkedin.com/pulse/taylor-geospatial-engines-first-innovation-bridge-jennifer-marcus-jez8c/?trackingId=KCkabx9kQySPwaBn6kdefQ%3D%3D">their first Innovation Bridge program</a>.</p>

<p>If you know of any good examples of common data schemas or groups working on creating common identifiers, we’d love to hear about them. Please write to us at <a href="mailto:hello@cloudnativegeo.org">hello@cloudnativegeo.org</a>.</p>

<hr />

<p>If you enjoyed this, please consider watching Chris Holmes’s presentation at FOSS4G-NA 2023: <a href="https://www.youtube.com/watch?v=ovVb_uloM7U">Towards a Cloud Native Spatial Data Infrastructure</a>. Or you can just read the speaker notes in <a href="https://docs.google.com/presentation/d/15wi7XAWm2gP-7Gg0hjFeRaIxS18M-mG6DVh1F8j-lgM/edit">his slide deck</a>.</p>

<hr />

<ol>
  <li>This is not to say we believe the existing formats will live forever – we welcome more innovation in cloud-native formats and will support members of our community as they explore new formats. <a href="#fnref:1">↩︎</a></li>
  <li>And we’re working hard to make hosting data in the cloud as easy as possible through <a href="https://source.coop">Source Cooperative</a>. <a href="#fnref:2">↩︎</a></li>
  <li>We want to reiterate that we know none of this will be simple (n.b. these two great papers: <a href="https://link.springer.com/article/10.1007/s13280-016-0772-y">When is a forest a forest?</a> and <a href="https://academic.oup.com/jof/article/100/8/21/4608650">When is a forest not a forest?</a>), but we believe it is <em>possible</em>. <a href="#fnref:3">↩︎</a></li>
  <li>The Radiant Earth post <a href="https://radiant.earth/blog/2024/01/unicorns-show-ponies-and-gazelles/">Unicorns, Show Ponies, and Gazelles</a> argues that we need to create new kinds of organizations that can create and manage global unique identifiers to make this vision a reality. <a href="#fnref:4">↩︎</a></li>
</ol>]]></content><author><name>Chris Holmes</name></author><summary type="html"><![CDATA[We created the Cloud-Native Geospatial Foundation because we’ve noticed rapid adoption of cloud-native geospatial formats, such as Cloud-Optimized GeoTIFF (COG), SpatioTemporal Asset Catalogs (STAC), Zarr, and GeoParquet. Both data providers and users enjoy time and cost savings when using cloud-native formats, and we believe there’s a need to help more people learn how to benefit from them.]]></summary></entry></feed>