<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>webgeods</title>
<link>https://webgeods.com/</link>
<atom:link href="https://webgeods.com/index.xml" rel="self" type="application/rss+xml"/>
<description>Bilingual (Python/R) spatial data science — interactive articles and tools running entirely in your browser via WebAssembly.</description>
<generator>quarto-1.7.29</generator>
<lastBuildDate>Mon, 31 Aug 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>Topology Errors in a GeoJSON: Detect Without Fixing</title>
  <link>https://webgeods.com/posts/topology-errors.html</link>
  <description><![CDATA[ 




<p>In <a href="../posts/geometry-validity.html">Geometry validity of a GeoJSON</a> we repaired polygons that were <strong>individually</strong> invalid with <code>make_valid()</code>/<code>st_make_valid()</code>. Here the problem is different: every single feature’s geometry can be perfectly valid, and the dataset can still be <strong>broken</strong> — two polygons that overlap, a gap between two areas that should touch, a line that ends a millimeter from another without connecting.</p>
<p><strong>This tool doesn’t fix anything.</strong> It detects, describes and locates the errors — closing a gap or assigning an overlap is a semantic decision (which polygon is the “correct” one?) that no algorithm can make for you. It’s a data-quality report, not an automatic repair tool.</p>
<p>On load, the code detects whether your data is <strong>polygons</strong> or <strong>lines</strong> and runs only the checks that make sense for that type:</p>
<ul>
<li><strong>Polygons</strong> → overlap, gap, sliver, duplicates</li>
<li><strong>Lines</strong> → dangle, duplicates</li>
</ul>
<p>Just want to quickly check a file, without the rest of the reading? Use the <a href="../tools/topology-checker.html">standalone tool</a> — same engine, less prose.</p>
<section id="upload-your-file" class="level2">
<h2 class="anchored" data-anchor-id="upload-your-file">1. Upload your file</h2>
<p>A <code>.geojson</code>, or a shapefile: either as a single <code>.zip</code>, or as the individual <code>.shp</code>/<code>.dbf</code>/<code>.shx</code> files (and optionally <code>.prj</code>) selected together.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb1" data-startfrom="39" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 38;"><span id="cb1-39"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// The input and the writing logic into the virtual filesystem live in</span></span>
<span id="cb1-40"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// shared/upload.js (WebGeoDS.Upload) — same helper used in</span></span>
<span id="cb1-41"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// geometry-validity.qmd, not rewritten here.</span></span>
<span id="cb1-42">viewof uploadedFiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Upload</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">createInput</span>()</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb2" data-startfrom="47" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 46;"><span id="cb2-47">mutable uploadStatus <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Upload</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">defaultStatus</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-2" data-nodetype="declaration">

</div>
</div>
</div>
<p><span><span id="ojs-element-id-1"></span></span></p>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb3" data-startfrom="55" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 54;"><span id="cb3-55">{</span>
<span id="cb3-56">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Upload</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">load</span>(uploadedFiles)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-57">  mutable uploadStatus <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> result<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">message</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-58">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div id="ojs-cell-3" data-nodetype="expression">

</div>
</div>
</div>
</section>
<section id="what-we-look-for" class="level2">
<h2 class="anchored" data-anchor-id="what-we-look-for">2. What we look for</h2>
<p>Five recurring categories, drawn from the <a href="https://www.usgs.gov/ngp-standards-and-specifications/topology-and-network-errors">USGS</a> catalog and from the <a href="https://docs.qgis.org/3.44/en/docs/user_manual/plugins/core_plugins/plugins_topology_checker.html">QGIS Topology Checker</a>:</p>
<ul>
<li><strong>Overlap</strong> — two polygons that should be adjacent instead overlap over a portion of surface.</li>
<li><strong>Gap</strong> — a gap remains between polygons that should continuously cover an area.</li>
<li><strong>Sliver</strong> — a leftover polygon, thin and with no real geographic meaning, often the result of an overlay.</li>
<li><strong>Duplicates</strong> — two features with identical geometry (applies to both polygons and lines).</li>
<li><strong>Dangle</strong> — the end of a line that should connect to another line stays isolated.</li>
</ul>
</section>
<section id="shared-map-and-table" class="level2">
<h2 class="anchored" data-anchor-id="shared-map-and-table">3. Shared map and table</h2>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb4" data-startfrom="84" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 83;"><span id="cb4-84">sharedMap <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb4-85">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> map <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">window</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">WebGeoDS</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Map</span>({ <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">center</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">12.5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">41.9</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">zoom</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">height</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"480px"</span> })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-86">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> map<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ready</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-87">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> map<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-88">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div id="ojs-cell-4" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb5" data-startfrom="93" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 92;"><span id="cb5-93">sharedMapEl <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">element</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-5" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb6" data-startfrom="99" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 98;"><span id="cb6-99"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// The color is decided by JS, not by Python/R: the Python/R cells</span></span>
<span id="cb6-100"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// only return GeoJSON with properties like "has_error" — neither</span></span>
<span id="cb6-101"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// language knows or needs to know who's going to draw it.</span></span>
<span id="cb6-102"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span></span>
<span id="cb6-103"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Unlike geometry-validity.qmd (always polygons, a single static</span></span>
<span id="cb6-104"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// VALIDITY_PAINT), here the geometry type changes from one example to</span></span>
<span id="cb6-105"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// the next (polygons for overlap/gap/sliver/duplicates, lines for</span></span>
<span id="cb6-106"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// dangle) — so the paint itself depends on the data: setGeoJSON()</span></span>
<span id="cb6-107"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// (shared/map.js) detects on its own when the layer's TYPE needs to</span></span>
<span id="cb6-108"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// change and recreates the layer, but the color/style for that type</span></span>
<span id="cb6-109"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// remains a presentation choice, so it stays here.</span></span>
<span id="cb6-110">errorPaint <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (data) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb6-111">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> geometryType <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">features</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find</span>((f) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> f<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">geometry</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">geometry</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">??</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-112">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> colorExpr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"case"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"=="</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"get"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"has_error"</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#e05252"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#3d5a73"</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-113">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (geometryType <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"LineString"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">||</span> geometryType <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MultiLineString"</span>) {</span>
<span id="cb6-114">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> { <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"line-color"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> colorExpr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"line-width"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span> }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-115">  }</span>
<span id="cb6-116">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (geometryType <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Point"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">||</span> geometryType <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"MultiPoint"</span>) {</span>
<span id="cb6-117">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> { <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"circle-color"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> colorExpr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"circle-radius"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span> }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-118">  }</span>
<span id="cb6-119">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> { <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fill-color"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> colorExpr<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fill-opacity"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span> }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-120">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div id="ojs-cell-6" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb7" data-startfrom="125" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 124;"><span id="cb7-125"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// tableCell() is already reactive to the layer we pass it — no need</span></span>
<span id="cb7-126"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// to build a separate listener cell here (see shared/map.js).</span></span>
<span id="cb7-127"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// rowClassName colors every row with has_error red, whether it's an</span></span>
<span id="cb7-128"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// original feature or the synthetic geometry of a gap.</span></span>
<span id="cb7-129"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span></span>
<span id="cb7-130"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// No explicit containerId: tableCell() creates its own `&lt;div&gt;` and</span></span>
<span id="cb7-131"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// returns it - this cell is NOT `output: false`, Observable shows it</span></span>
<span id="cb7-132"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// here automatically, with no hand-written &lt;div&gt; in the markdown.</span></span>
<span id="cb7-133">topologyErrorsTable <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tableCell</span>(</span>
<span id="cb7-134">  [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-r"</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb7-135">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb7-136">  Generators<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb7-137">  {</span>
<span id="cb7-138">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">rowClassName</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (row) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">has_error</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"true"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"webgeods-row-invalid"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span></span>
<span id="cb7-139">  }</span>
<span id="cb7-140">)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-7" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb8" data-startfrom="145" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 144;"><span id="cb8-145">resetTopologyErrors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">async</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb8-146">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> id <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">of</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-r"</span>]) {</span>
<span id="cb8-147">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getGeoJSON</span>(id)) {</span>
<span id="cb8-148">      <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGeoJSON</span>(id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> { <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">type</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"FeatureCollection"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">features</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [] })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-149">    }</span>
<span id="cb8-150">  }</span>
<span id="cb8-151">}</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-8" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb9" data-startfrom="156" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 155;"><span id="cb9-156">resetMapButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb9-157">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> button <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">document</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">createElement</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"button"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-158">  button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">textContent</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"🔄 Reset map and table"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-159">  button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">onclick</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">resetTopologyErrors</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-160">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-161">}</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-9" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb10" data-startfrom="166" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 165;"><span id="cb10-166">loadExampleButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rCode) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb10-167">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> button <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">document</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">createElement</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"button"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-168">  button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">textContent</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-169">  button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">onclick</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">async</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb10-170">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Promise</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all</span>([</span>
<span id="cb10-171">      <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">window</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">WebGeoDS</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">CodeCell</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-example-py"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setCode</span>(pyCode)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb10-172">      <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">window</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">WebGeoDS</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">CodeCell</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-example-r"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setCode</span>(rCode)</span>
<span id="cb10-173">    ])<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-174">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">document</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getElementById</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-example-py"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scrollIntoView</span>({ <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">behavior</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smooth"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">block</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span> })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-175">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-176">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-177">}</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-10" data-nodetype="declaration">

</div>
</div>
</div>
<section id="first-run-once-only" class="level3">
<h3 class="anchored" data-anchor-id="first-run-once-only">3.1 First run (once only)</h3>
<p>Defines all the detection functions — no Python/R map here, that’s already ready above and knows nothing about these calculations. Run it once before the examples below.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true">Python</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false">R</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<div id="topology-errors-setup-py"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
  new window.WebGeoDS.CodeCell("topology-errors-setup-py", {
    language: "python",
    initialCode: "import math\nfrom shapely.geometry import mapping\n\ndef geom_family(gdf):\n    types = set(gdf.geometry.geom_type)\n    if types <= {\"Polygon\", \"MultiPolygon\"}:\n        return \"polygon\"\n    if types <= {\"LineString\", \"MultiLineString\"}:\n        return \"line\"\n    if types <= {\"Point\", \"MultiPoint\"}:\n        return \"point\"\n    return \"mixed\"\n\ndef check_overlap(gdf):\n    n = len(gdf)\n    results = [[] for _ in range(n)]\n    for i in range(n):\n        for j in range(i + 1, n):\n            gi, gj = gdf.geometry.iloc[i], gdf.geometry.iloc[j]\n            if gi.overlaps(gj):\n                area = gi.intersection(gj).area\n                results[i].append((\"overlap\", j, area))\n                results[j].append((\"overlap\", i, area))\n    return results\n\ndef check_duplicate(gdf):\n    n = len(gdf)\n    results = [[] for _ in range(n)]\n    for i in range(n):\n        for j in range(i + 1, n):\n            if gdf.geometry.iloc[i].equals(gdf.geometry.iloc[j]):\n                results[i].append((\"duplicate\", j, 0))\n                results[j].append((\"duplicate\", i, 0))\n    return results\n\ndef check_sliver(gdf, compactness_threshold=0.15):\n    results = [[] for _ in range(len(gdf))]\n    for i, geom in enumerate(gdf.geometry):\n        perim = geom.length\n        area = geom.area\n        if perim > 0:\n            compactness = 4 * math.pi * area / (perim ** 2)\n            if compactness < compactness_threshold:\n                results[i].append((\"sliver\", None, compactness))\n    return results\n\ndef check_gap(gdf, min_area=1e-6, proximity=0.06):\n    # Per pair, not on the whole dataset: a single convex hull over\n    # all features would flag as \"gap\" even the simple fact that two\n    # unaligned shapes leave space outside their union (false positive\n    # verified empirically on the overlap/sliver examples). Here we\n    # only look at pairs that are CLOSE (within `proximity`) and not\n    # already overlapping, and use the convex hull of the pair alone.\n    n = len(gdf)\n    gaps = []\n    for i in range(n):\n        for j in range(i + 1, n):\n            gi, gj = gdf.geometry.iloc[i], gdf.geometry.iloc[j]\n            if gi.overlaps(gj):\n                continue\n            if gi.equals(gj):\n                # Identical geometries (e.g. a duplicate): difference\n                # always empty, and some GEOS convex_hull/difference\n                # combinations on a degenerate pair can raise an error\n                # instead of returning a clean empty result — verified\n                # empirically on the R side, avoided here upstream.\n                continue\n            if gi.distance(gj) > proximity:\n                continue\n            pair_union = gi.union(gj)\n            gap_geom = pair_union.convex_hull.difference(pair_union)\n            if not gap_geom.is_empty:\n                parts = gap_geom.geoms if hasattr(gap_geom, \"geoms\") else [gap_geom]\n                for part in parts:\n                    if part.area > min_area:\n                        gaps.append(part)\n    return gaps\n\ndef check_dangle(gdf, tolerance=1e-9):\n    endpoints = []\n    for i, geom in enumerate(gdf.geometry):\n        coords = list(geom.coords)\n        endpoints.append((i, \"start\", coords[0]))\n        endpoints.append((i, \"end\", coords[-1]))\n    results = [[] for _ in range(len(gdf))]\n    for i, which, (x, y) in endpoints:\n        connected = False\n        for j, which2, (x2, y2) in endpoints:\n            if j == i:\n                continue\n            if ((x - x2) ** 2 + (y - y2) ** 2) ** 0.5 <= tolerance:\n                connected = True\n                break\n        if not connected:\n            results[i].append((\"dangle\", which, 0))\n    return results\n\ndef detect_and_check(gdf):\n    family = geom_family(gdf)\n    n = len(gdf)\n    per_feature = [[] for _ in range(n)]\n    extra_features = []\n\n    dup = check_duplicate(gdf)\n    for i in range(n):\n        per_feature[i].extend(dup[i])\n\n    if family == \"polygon\":\n        ov = check_overlap(gdf)\n        sl = check_sliver(gdf)\n        for i in range(n):\n            per_feature[i].extend(ov[i])\n            per_feature[i].extend(sl[i])\n        for gap_geom in check_gap(gdf):\n            extra_features.append({\n                \"type\": \"Feature\",\n                \"properties\": {\n                    \"name\": \"gap\", \"error_type\": \"gap\", \"has_error\": True,\n                    \"partner\": \"\", \"metric\": round(gap_geom.area, 6), \"severity\": \"warning\"\n                },\n                \"geometry\": mapping(gap_geom)\n            })\n    elif family == \"line\":\n        dg = check_dangle(gdf)\n        for i in range(n):\n            per_feature[i].extend(dg[i])\n\n    names = gdf[\"name\"] if \"name\" in gdf.columns else [f\"geometry {i+1}\" for i in range(n)]\n    features = []\n    for i in range(n):\n        errs = per_feature[i]\n        has_error = len(errs) > 0\n        error_type = errs[0][0] if has_error else \"\"\n        partner_idx = errs[0][1] if has_error and isinstance(errs[0][1], int) else None\n        partner = str(names.iloc[partner_idx] if hasattr(names, \"iloc\") else names[partner_idx]) if partner_idx is not None else \"\"\n        metric = round(errs[0][2], 6) if has_error else 0\n        features.append({\n            \"type\": \"Feature\",\n            \"properties\": {\n                \"name\": names.iloc[i] if hasattr(names, \"iloc\") else names[i],\n                \"error_type\": error_type, \"has_error\": has_error,\n                \"partner\": partner, \"metric\": metric,\n                \"severity\": \"error\" if has_error else \"\"\n            },\n            \"geometry\": mapping(gdf.geometry.iloc[i])\n        })\n    features.extend(extra_features)\n    return {\"type\": \"FeatureCollection\", \"features\": features}\n\n\"detect_and_check() ready — run the examples below\"",
    onRun: async (code, output) => {
      output.waiting("Running...");
      return output.result(await window.WebGeoDS.Python.run(code, { packages: ["geopandas","shapely"] }));
    }
  });
});
</script>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<div id="topology-errors-setup-r"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
  new window.WebGeoDS.CodeCell("topology-errors-setup-r", {
    language: "r",
    initialCode: "\ngeom_family <- function(data) {\n  types <- unique(as.character(sf::st_geometry_type(data)))\n  if (all(types %in% c(\"POLYGON\", \"MULTIPOLYGON\"))) return(\"polygon\")\n  if (all(types %in% c(\"LINESTRING\", \"MULTILINESTRING\"))) return(\"line\")\n  if (all(types %in% c(\"POINT\", \"MULTIPOINT\"))) return(\"point\")\n  \"mixed\"\n}\n\ncheck_overlap <- function(data) {\n  n <- nrow(data)\n  results <- vector(\"list\", n)\n  for (i in seq_len(n)) results[[i]] <- list()\n  if (n > 1) {\n    for (i in 1:(n - 1)) {\n      for (j in (i + 1):n) {\n        if (isTRUE(sf::st_overlaps(data[i, ], data[j, ], sparse = FALSE)[1, 1])) {\n          inter <- sf::st_intersection(sf::st_geometry(data)[i], sf::st_geometry(data)[j])\n          area <- as.numeric(sf::st_area(inter))\n          results[[i]] <- append(results[[i]], list(list(type = \"overlap\", partner = j, metric = area)))\n          results[[j]] <- append(results[[j]], list(list(type = \"overlap\", partner = i, metric = area)))\n        }\n      }\n    }\n  }\n  results\n}\n\ncheck_duplicate <- function(data) {\n  n <- nrow(data)\n  results <- vector(\"list\", n)\n  for (i in seq_len(n)) results[[i]] <- list()\n  if (n > 1) {\n    for (i in 1:(n - 1)) {\n      for (j in (i + 1):n) {\n        if (isTRUE(sf::st_equals(data[i, ], data[j, ], sparse = FALSE)[1, 1])) {\n          results[[i]] <- append(results[[i]], list(list(type = \"duplicate\", partner = j, metric = 0)))\n          results[[j]] <- append(results[[j]], list(list(type = \"duplicate\", partner = i, metric = 0)))\n        }\n      }\n    }\n  }\n  results\n}\n\ncheck_sliver <- function(data, compactness_threshold = 0.15) {\n  # Per feature, with tryCatch: st_area()/st_length() on a\n  # geometrically INVALID geometry (self-intersecting — this check\n  # doesn't assume valid input, only correct relationships between\n  # valid features) can raise a real GEOS/s2 error (\"Loop 0 is not\n  # valid\") instead of returning a number — verified empirically by\n  # uploading a shapefile with a bowtie geometry. A feature like that\n  # is skipped for this check, it doesn't crash the whole cell.\n  n <- nrow(data)\n  results <- vector(\"list\", n)\n  for (i in seq_len(n)) {\n    results[[i]] <- list()\n    metrics <- tryCatch({\n      area <- as.numeric(sf::st_area(data[i, ]))\n      perim <- as.numeric(sf::st_length(sf::st_boundary(data[i, ])))\n      list(area = area, perim = perim)\n    }, error = function(e) NULL)\n    if (is.null(metrics) || metrics$perim <= 0) next\n    compactness <- 4 * pi * metrics$area / (metrics$perim^2)\n    if (compactness < compactness_threshold) {\n      results[[i]] <- append(results[[i]], list(list(type = \"sliver\", partner = NA, metric = compactness)))\n    }\n  }\n  results\n}\n\ncheck_gap <- function(data, min_area = 1e-6, proximity = 8000) {\n  # Per pair, not on the whole dataset — same reason as the Python\n  # side: a single convex hull over all features gives false positives\n  # for pairs that are simply not aligned with each other (overlap,\n  # sliver).\n  #\n  # `proximity` here is in METERS, not degrees: unlike shapely (which\n  # operates \"planar\" on raw lon/lat coordinates, in degrees), sf with\n  # s2 active (the default for a geographic CRS) computes st_distance\n  # geodetically, in meters — different thresholds per language, same\n  # practical meaning (\"close enough to look like an oversight\").\n  n <- nrow(data)\n  gaps <- list()\n  if (n > 1) {\n    for (i in 1:(n - 1)) {\n      for (j in (i + 1):n) {\n        if (isTRUE(sf::st_overlaps(data[i, ], data[j, ], sparse = FALSE)[1, 1])) next\n        if (isTRUE(sf::st_equals(data[i, ], data[j, ], sparse = FALSE)[1, 1])) next\n        # Identical geometries (e.g. a duplicate): difference always\n        # empty, and the st_convex_hull/st_difference combination on a\n        # degenerate pair can raise a GEOS error (\"Edge is\n        # degenerate\") instead of returning a clean empty result —\n        # verified empirically, avoided here upstream.\n        d <- as.numeric(sf::st_distance(data[i, ], data[j, ]))\n        if (d > proximity) next\n        # BARE geometries (sf::st_geometry(...)[i], not data[i, ]) for\n        # union/convex_hull/difference: calling these functions on sf\n        # objects (data.frame) instead of plain sfc triggers the *.sf\n        # methods, which try to rebuild the attribute columns and fail\n        # here with a row-realignment error — verified empirically by\n        # isolating each step. Same pattern already used correctly in\n        # check_overlap() above.\n        gi <- sf::st_geometry(data)[i]\n        gj <- sf::st_geometry(data)[j]\n        pair_union <- sf::st_union(gi, gj)\n        hull <- sf::st_convex_hull(pair_union)\n        gap_geom <- sf::st_difference(hull, pair_union)\n        if (length(gap_geom) > 0 && !isTRUE(sf::st_is_empty(gap_geom)[1])) {\n          # st_difference between a hull and a union with nearly\n          # coincident edges can return a mixed GEOMETRYCOLLECTION (a\n          # tiny linear residue alongside the real polygon, due to\n          # GEOS imprecision) — st_collection_extract reliably isolates\n          # only the polygonal part, unlike st_cast (verified\n          # empirically: st_cast here produced a mixed-type object\n          # that broke the following assignment).\n          polys <- sf::st_collection_extract(sf::st_sfc(gap_geom, crs = sf::st_crs(data)), \"POLYGON\", warn = FALSE)\n          for (k in seq_along(polys)) {\n            a <- as.numeric(sf::st_area(polys[k]))\n            if (a > min_area) gaps[[length(gaps) + 1]] <- polys[k]\n          }\n        }\n      }\n    }\n  }\n  gaps\n}\n\ncheck_dangle <- function(data, tolerance = 1e-9) {\n  n <- nrow(data)\n  results <- vector(\"list\", n)\n  for (i in seq_len(n)) results[[i]] <- list()\n  endpoints <- list()\n  for (i in seq_len(n)) {\n    p <- sf::st_cast(sf::st_geometry(data)[i], \"POINT\", warn = FALSE)\n    coords <- sf::st_coordinates(p)\n    endpoints[[length(endpoints) + 1]] <- list(feature = i, which = \"start\", x = coords[1, 1], y = coords[1, 2])\n    endpoints[[length(endpoints) + 1]] <- list(feature = i, which = \"end\", x = coords[nrow(coords), 1], y = coords[nrow(coords), 2])\n  }\n  for (a in endpoints) {\n    connected <- FALSE\n    for (b in endpoints) {\n      if (b$feature == a$feature) next\n      d <- sqrt((a$x - b$x)^2 + (a$y - b$y)^2)\n      if (d <= tolerance) { connected <- TRUE; break }\n    }\n    if (!connected) {\n      results[[a$feature]] <- append(results[[a$feature]], list(list(type = \"dangle\", partner = a$which, metric = 0)))\n    }\n  }\n  results\n}\n\ndetect_and_check <- function(data) {\n  family <- geom_family(data)\n  n <- nrow(data)\n  per_feature <- vector(\"list\", n)\n  for (i in seq_len(n)) per_feature[[i]] <- list()\n  extra_features <- list()\n\n  dup <- check_duplicate(data)\n  for (i in seq_len(n)) per_feature[[i]] <- append(per_feature[[i]], dup[[i]])\n\n  if (family == \"polygon\") {\n    ov <- check_overlap(data)\n    sl <- check_sliver(data)\n    for (i in seq_len(n)) {\n      per_feature[[i]] <- append(per_feature[[i]], ov[[i]])\n      per_feature[[i]] <- append(per_feature[[i]], sl[[i]])\n    }\n    for (gap_geom in check_gap(data)) {\n      extra_features[[length(extra_features) + 1]] <- list(\n        type = \"Feature\",\n        properties = list(\n          name = \"gap\", error_type = \"gap\", has_error = TRUE,\n          partner = \"\", metric = round(as.numeric(sf::st_area(gap_geom)), 6), severity = \"warning\"\n        ),\n        geometry = jsonlite::fromJSON(geojsonsf::sf_geojson(sf::st_sf(geometry = gap_geom)), simplifyVector = FALSE)$features[[1]]$geometry\n      )\n    }\n  } else if (family == \"line\") {\n    dg <- check_dangle(data)\n    for (i in seq_len(n)) per_feature[[i]] <- append(per_feature[[i]], dg[[i]])\n  }\n\n  names_col <- if (\"name\" %in% names(data)) data$name else paste(\"geometry\", seq_len(n))\n  features <- list()\n  for (i in seq_len(n)) {\n    errs <- per_feature[[i]]\n    has_error <- length(errs) > 0\n    first <- if (has_error) errs[[1]] else NULL\n    error_type <- if (has_error) first$type else \"\"\n    partner_val <- if (has_error && is.numeric(first$partner)) as.character(names_col[first$partner]) else \"\"\n    metric_val <- if (has_error) round(first$metric, 6) else 0\n    geom_json <- jsonlite::fromJSON(geojsonsf::sf_geojson(data[i, ]), simplifyVector = FALSE)$features[[1]]$geometry\n    features[[length(features) + 1]] <- list(\n      type = \"Feature\",\n      properties = list(\n        name = names_col[i], error_type = error_type, has_error = has_error,\n        partner = partner_val, metric = metric_val, severity = if (has_error) \"error\" else \"\"\n      ),\n      geometry = geom_json\n    )\n  }\n  features <- c(features, extra_features)\n  list(type = \"FeatureCollection\", features = features)\n}\n\n\"detect_and_check() ready — run the examples below\"",
    onRun: async (code, output) => {
      output.waiting("Running...");
      return output.result(await window.WebGeoDS.R.run(code, { packages: ["sf","geojsonsf","jsonlite"] }));
    }
  });
});
</script>
</div>
</div>
</div>
</section>
<section id="reusable-cell-pair" class="level3">
<h3 class="anchored" data-anchor-id="reusable-cell-pair">3.2 Reusable cell pair</h3>
<p>The code below changes with every “Load this example” button further down.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-2-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-1" aria-controls="tabset-2-1" aria-selected="true">Python</a></li><li class="nav-item"><a class="nav-link" id="tabset-2-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-2" aria-controls="tabset-2-2" aria-selected="false">R</a></li></ul>
<div class="tab-content">
<div id="tabset-2-1" class="tab-pane active" aria-labelledby="tabset-2-1-tab">
<div id="topology-errors-example-py"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
  new window.WebGeoDS.CodeCell("topology-errors-example-py", {
    language: "python",
    initialCode: "import geopandas as gpd\nfrom shapely.geometry import shape\n\na = {\"type\": \"Polygon\", \"coordinates\": [[[12.45, 41.85], [12.52, 41.85], [12.52, 41.92], [12.45, 41.92], [12.45, 41.85]]]}\nb = {\"type\": \"Polygon\", \"coordinates\": [[[12.50, 41.87], [12.57, 41.87], [12.57, 41.94], [12.50, 41.94], [12.50, 41.87]]]}\ngdf = gpd.GeoDataFrame({\"name\": [\"A\", \"B\"]}, geometry=[shape(a), shape(b)], crs=\"EPSG:4326\")\n\ndetect_and_check(gdf)",
    onRun: async (code, output) => {
      output.waiting("Running...");
      return output.result(await window.WebGeoDS.Python.run(code, {}));
    }
  });
});
</script>
</div>
<div id="tabset-2-2" class="tab-pane" aria-labelledby="tabset-2-2-tab">
<div id="topology-errors-example-r"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
  new window.WebGeoDS.CodeCell("topology-errors-example-r", {
    language: "r",
    initialCode: "a <- sf::st_polygon(list(rbind(c(12.45, 41.85), c(12.52, 41.85), c(12.52, 41.92), c(12.45, 41.92), c(12.45, 41.85))))\nb <- sf::st_polygon(list(rbind(c(12.50, 41.87), c(12.57, 41.87), c(12.57, 41.94), c(12.50, 41.94), c(12.50, 41.87))))\ndata <- sf::st_sf(name = c(\"A\", \"B\"), geometry = sf::st_sfc(a, b, crs = 4326))\n\ndetect_and_check(data)",
    onRun: async (code, output) => {
      output.waiting("Running...");
      return output.result(await window.WebGeoDS.R.run(code, {}));
    }
  });
});
</script>
</div>
</div>
</div>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb11" data-startfrom="604" data-source-offset="-440" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 603;"><span id="cb11-604">pyErrors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCellValue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-example-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Generators)</span>
<span id="cb11-605">{</span>
<span id="cb11-606">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (pyErrors) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGeoJSON</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyErrors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> { <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">paint</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">errorPaint</span>(pyErrors) })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-607">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-11-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-11-2" data-nodetype="expression">

</div>
</div>
</div>
</div>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb12" data-startfrom="613" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 612;"><span id="cb12-613">rErrors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCellValue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-example-r"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Generators)</span>
<span id="cb12-614">{</span>
<span id="cb12-615">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (rErrors) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGeoJSON</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-r"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rErrors<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> { <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">paint</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">errorPaint</span>(rErrors) })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb12-616">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-12-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-12-2" data-nodetype="expression">

</div>
</div>
</div>
</div>
</section>
</section>
<section id="five-errors-five-examples" class="level2">
<h2 class="anchored" data-anchor-id="five-errors-five-examples">4. Five errors, five examples</h2>
<section id="overlap" class="level3">
<h3 class="anchored" data-anchor-id="overlap">4.1 Overlap</h3>
<p>Two polygons that should be adjacent instead overlap over a portion of surface — the example already loaded by default in the cell pair above.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb13" data-startfrom="629" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 628;"><span id="cb13-629">pyOverlapCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`import geopandas as gpd</span></span>
<span id="cb13-630"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.geometry import shape</span></span>
<span id="cb13-631"></span>
<span id="cb13-632"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">a = {"type": "Polygon", "coordinates": [[[12.45, 41.85], [12.52, 41.85], [12.52, 41.92], [12.45, 41.92], [12.45, 41.85]]]}</span></span>
<span id="cb13-633"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">b = {"type": "Polygon", "coordinates": [[[12.50, 41.87], [12.57, 41.87], [12.57, 41.94], [12.50, 41.94], [12.50, 41.87]]]}</span></span>
<span id="cb13-634"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">gdf = gpd.GeoDataFrame({"name": ["A", "B"]}, geometry=[shape(a), shape(b)], crs="EPSG:4326")</span></span>
<span id="cb13-635"></span>
<span id="cb13-636"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">detect_and_check(gdf)`</span></span>
<span id="cb13-637">rOverlapCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`a &lt;- sf::st_polygon(list(rbind(c(12.45, 41.85), c(12.52, 41.85), c(12.52, 41.92), c(12.45, 41.92), c(12.45, 41.85))))</span></span>
<span id="cb13-638"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">b &lt;- sf::st_polygon(list(rbind(c(12.50, 41.87), c(12.57, 41.87), c(12.57, 41.94), c(12.50, 41.94), c(12.50, 41.87))))</span></span>
<span id="cb13-639"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data &lt;- sf::st_sf(name = c("A", "B"), geometry = sf::st_sfc(a, b, crs = 4326))</span></span>
<span id="cb13-640"></span>
<span id="cb13-641"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">detect_and_check(data)`</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-13-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-13-2" data-nodetype="declaration">

</div>
</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb14" data-startfrom="645" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 644;"><span id="cb14-645">loadOverlapButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loadExampleButton</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Load the overlap example"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyOverlapCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rOverlapCode)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-14" data-nodetype="declaration">

</div>
</div>
</div>
</section>
<section id="gap" class="level3">
<h3 class="anchored" data-anchor-id="gap">4.2 Gap</h3>
<p>Two aligned polygons that should cover a single continuous area instead leave a gap between them — detected by comparing the union of the polygons with the convex hull containing both.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb15" data-startfrom="657" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 656;"><span id="cb15-657">pyGapCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`import geopandas as gpd</span></span>
<span id="cb15-658"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.geometry import shape</span></span>
<span id="cb15-659"></span>
<span id="cb15-660"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">a = {"type": "Polygon", "coordinates": [[[12.40, 41.85], [12.46, 41.85], [12.46, 41.92], [12.40, 41.92], [12.40, 41.85]]]}</span></span>
<span id="cb15-661"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">b = {"type": "Polygon", "coordinates": [[[12.50, 41.85], [12.56, 41.85], [12.56, 41.92], [12.50, 41.92], [12.50, 41.85]]]}</span></span>
<span id="cb15-662"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">gdf = gpd.GeoDataFrame({"name": ["A", "B"]}, geometry=[shape(a), shape(b)], crs="EPSG:4326")</span></span>
<span id="cb15-663"></span>
<span id="cb15-664"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">detect_and_check(gdf)`</span></span>
<span id="cb15-665">rGapCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`a &lt;- sf::st_polygon(list(rbind(c(12.40, 41.85), c(12.46, 41.85), c(12.46, 41.92), c(12.40, 41.92), c(12.40, 41.85))))</span></span>
<span id="cb15-666"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">b &lt;- sf::st_polygon(list(rbind(c(12.50, 41.85), c(12.56, 41.85), c(12.56, 41.92), c(12.50, 41.92), c(12.50, 41.85))))</span></span>
<span id="cb15-667"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data &lt;- sf::st_sf(name = c("A", "B"), geometry = sf::st_sfc(a, b, crs = 4326))</span></span>
<span id="cb15-668"></span>
<span id="cb15-669"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">detect_and_check(data)`</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-15-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-15-2" data-nodetype="declaration">

</div>
</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb16" data-startfrom="673" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 672;"><span id="cb16-673">loadGapButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loadExampleButton</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Load the gap example"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyGapCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rGapCode)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-16" data-nodetype="declaration">

</div>
</div>
</div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>The gap is shown as its own feature (a synthetic geometry, not one of yours), colored like the other error rows. The check only looks at polygon pairs that are <strong>close and not already overlapping</strong>, using the convex hull of the single pair — not of the whole dataset, which would flag as “gap” even the simple fact that two distant or overlapping shapes aren’t aligned with each other. For a real dataset with a known study area, that area is still the more correct reference, not a convex hull.</p>
</div>
</div>
</section>
<section id="sliver" class="level3">
<h3 class="anchored" data-anchor-id="sliver">4.3 Sliver</h3>
<p>An extremely thin polygon — 0.1° wide, 0.001° tall — a typical leftover from an overlay between nearly coincident boundaries. Detected with the Polsby-Popper compactness index (4π·area/perimeter²): below 0.15 is considered a sliver.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb17" data-startfrom="697" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 696;"><span id="cb17-697">pySliverCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`import geopandas as gpd</span></span>
<span id="cb17-698"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.geometry import shape</span></span>
<span id="cb17-699"></span>
<span id="cb17-700"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">clean = {"type": "Polygon", "coordinates": [[[12.45, 41.85], [12.50, 41.85], [12.50, 41.90], [12.45, 41.90], [12.45, 41.85]]]}</span></span>
<span id="cb17-701"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">sliver = {"type": "Polygon", "coordinates": [[[12.75, 41.87], [12.85, 41.87], [12.85, 41.871], [12.75, 41.871], [12.75, 41.87]]]}</span></span>
<span id="cb17-702"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">gdf = gpd.GeoDataFrame({"name": ["regular polygon", "sliver"]}, geometry=[shape(clean), shape(sliver)], crs="EPSG:4326")</span></span>
<span id="cb17-703"></span>
<span id="cb17-704"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">detect_and_check(gdf)`</span></span>
<span id="cb17-705">rSliverCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`clean &lt;- sf::st_polygon(list(rbind(c(12.45, 41.85), c(12.50, 41.85), c(12.50, 41.90), c(12.45, 41.90), c(12.45, 41.85))))</span></span>
<span id="cb17-706"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">sliver &lt;- sf::st_polygon(list(rbind(c(12.75, 41.87), c(12.85, 41.87), c(12.85, 41.871), c(12.75, 41.871), c(12.75, 41.87))))</span></span>
<span id="cb17-707"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data &lt;- sf::st_sf(name = c("regular polygon", "sliver"), geometry = sf::st_sfc(clean, sliver, crs = 4326))</span></span>
<span id="cb17-708"></span>
<span id="cb17-709"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">detect_and_check(data)`</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-17-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-17-2" data-nodetype="declaration">

</div>
</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb18" data-startfrom="713" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 712;"><span id="cb18-713">loadSliverButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loadExampleButton</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Load the sliver example"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pySliverCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rSliverCode)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-18" data-nodetype="declaration">

</div>
</div>
</div>
</section>
<section id="duplicates" class="level3">
<h3 class="anchored" data-anchor-id="duplicates">4.4 Duplicates</h3>
<p>Two features with identical geometry — happens often during merges or repeated imports. The check applies the same way to polygons and lines (topological equality), shown here on polygons.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb19" data-startfrom="725" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 724;"><span id="cb19-725">pyDuplicateCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`import geopandas as gpd</span></span>
<span id="cb19-726"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.geometry import shape</span></span>
<span id="cb19-727"></span>
<span id="cb19-728"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">a = {"type": "Polygon", "coordinates": [[[12.45, 41.85], [12.50, 41.85], [12.50, 41.90], [12.45, 41.90], [12.45, 41.85]]]}</span></span>
<span id="cb19-729"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">c = {"type": "Polygon", "coordinates": [[[12.75, 41.85], [12.80, 41.85], [12.80, 41.90], [12.75, 41.90], [12.75, 41.85]]]}</span></span>
<span id="cb19-730"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">gdf = gpd.GeoDataFrame({"name": ["A", "copy of A", "C"]}, geometry=[shape(a), shape(a), shape(c)], crs="EPSG:4326")</span></span>
<span id="cb19-731"></span>
<span id="cb19-732"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">detect_and_check(gdf)`</span></span>
<span id="cb19-733">rDuplicateCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`a &lt;- sf::st_polygon(list(rbind(c(12.45, 41.85), c(12.50, 41.85), c(12.50, 41.90), c(12.45, 41.90), c(12.45, 41.85))))</span></span>
<span id="cb19-734"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">c &lt;- sf::st_polygon(list(rbind(c(12.75, 41.85), c(12.80, 41.85), c(12.80, 41.90), c(12.75, 41.90), c(12.75, 41.85))))</span></span>
<span id="cb19-735"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data &lt;- sf::st_sf(name = c("A", "copy of A", "C"), geometry = sf::st_sfc(a, a, c, crs = 4326))</span></span>
<span id="cb19-736"></span>
<span id="cb19-737"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">detect_and_check(data)`</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-19-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-19-2" data-nodetype="declaration">

</div>
</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb20" data-startfrom="741" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 740;"><span id="cb20-741">loadDuplicateButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loadExampleButton</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Load the duplicates example"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyDuplicateCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rDuplicateCode)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-20" data-nodetype="declaration">

</div>
</div>
</div>
</section>
<section id="dangle" class="level3">
<h3 class="anchored" data-anchor-id="dangle">4.5 Dangle</h3>
<p>A line network where three segments form a closed loop — each end touches exactly the next segment’s end, no dangle — and a fourth stays isolated, with both ends “dangling”. Notice how the layer on the map switches from fill to line: the code itself decides that, based on the geometry type you feed it.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb21" data-startfrom="755" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 754;"><span id="cb21-755">pyDangleCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`import geopandas as gpd</span></span>
<span id="cb21-756"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.geometry import shape</span></span>
<span id="cb21-757"></span>
<span id="cb21-758"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"># L1-L2-L3 form a closed loop (each end touches the next one): no</span></span>
<span id="cb21-759"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"># dangle. An OPEN path would still have two free ends by definition —</span></span>
<span id="cb21-760"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"># it wouldn't be a clean example of "everything connected".</span></span>
<span id="cb21-761"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">l1 = {"type": "LineString", "coordinates": [[12.45, 41.85], [12.50, 41.85]]}</span></span>
<span id="cb21-762"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">l2 = {"type": "LineString", "coordinates": [[12.50, 41.85], [12.50, 41.90]]}</span></span>
<span id="cb21-763"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">l3 = {"type": "LineString", "coordinates": [[12.50, 41.90], [12.45, 41.85]]}</span></span>
<span id="cb21-764"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">l4 = {"type": "LineString", "coordinates": [[12.52, 41.87], [12.56, 41.87]]}</span></span>
<span id="cb21-765"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">gdf = gpd.GeoDataFrame({"name": ["L1", "L2", "L3", "L4 isolated"]}, geometry=[shape(l1), shape(l2), shape(l3), shape(l4)], crs="EPSG:4326")</span></span>
<span id="cb21-766"></span>
<span id="cb21-767"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">detect_and_check(gdf)`</span></span>
<span id="cb21-768">rDangleCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`l1 &lt;- sf::st_linestring(rbind(c(12.45, 41.85), c(12.50, 41.85)))</span></span>
<span id="cb21-769"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">l2 &lt;- sf::st_linestring(rbind(c(12.50, 41.85), c(12.50, 41.90)))</span></span>
<span id="cb21-770"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">l3 &lt;- sf::st_linestring(rbind(c(12.50, 41.90), c(12.45, 41.85)))</span></span>
<span id="cb21-771"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">l4 &lt;- sf::st_linestring(rbind(c(12.52, 41.87), c(12.56, 41.87)))</span></span>
<span id="cb21-772"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data &lt;- sf::st_sf(name = c("L1", "L2", "L3", "L4 isolated"), geometry = sf::st_sfc(l1, l2, l3, l4, crs = 4326))</span></span>
<span id="cb21-773"></span>
<span id="cb21-774"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">detect_and_check(data)`</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-21-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-21-2" data-nodetype="declaration">

</div>
</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb22" data-startfrom="778" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 777;"><span id="cb22-778">loadDangleButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loadExampleButton</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Load the dangle example"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyDangleCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rDangleCode)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-22" data-nodetype="declaration">

</div>
</div>
</div>
</section>
</section>
<section id="apply-to-your-file" class="level2">
<h2 class="anchored" data-anchor-id="apply-to-your-file">5. Apply to your file</h2>
<p>The cells below try to read <code>/uploaded.geojson</code>, then an uploaded shapefile (<code>/uploaded.shp</code>), then a zipped shapefile (or, without an upload, use the overlap example as test data), detect the geometry type and automatically apply only the relevant checks — same <code>detect_and_check()</code> function as every example above, no duplicated logic.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-3-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-1" aria-controls="tabset-3-1" aria-selected="true">Python</a></li><li class="nav-item"><a class="nav-link" id="tabset-3-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-2" aria-controls="tabset-3-2" aria-selected="false">R</a></li></ul>
<div class="tab-content">
<div id="tabset-3-1" class="tab-pane active" aria-labelledby="tabset-3-1-tab">
<div id="topology-errors-uploaded-py"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
  new window.WebGeoDS.CodeCell("topology-errors-uploaded-py", {
    language: "python",
    initialCode: "import geopandas as gpd\nfrom shapely.geometry import shape\n\ngdf = None\nfor path in [\"/uploaded.geojson\", \"/uploaded.shp\", \"/vsizip//uploaded.zip\"]:\n    try:\n        gdf = gpd.read_file(path)\n        break\n    except Exception:\n        pass\n\nif gdf is not None and \"name\" not in gdf.columns:\n    gdf[\"name\"] = [f\"geometry {i+1}\" for i in range(len(gdf))]\n\nif gdf is None:\n    a = {\"type\": \"Polygon\", \"coordinates\": [[[12.45, 41.85], [12.52, 41.85], [12.52, 41.92], [12.45, 41.92], [12.45, 41.85]]]}\n    b = {\"type\": \"Polygon\", \"coordinates\": [[[12.50, 41.87], [12.57, 41.87], [12.57, 41.94], [12.50, 41.94], [12.50, 41.87]]]}\n    gdf = gpd.GeoDataFrame({\"name\": [\"A (example)\", \"B (example)\"]}, geometry=[shape(a), shape(b)], crs=\"EPSG:4326\")\n\ndetect_and_check(gdf)",
    onRun: async (code, output) => {
      output.waiting("Running...");
      return output.result(await window.WebGeoDS.Python.run(code, {}));
    }
  });
});
</script>
</div>
<div id="tabset-3-2" class="tab-pane" aria-labelledby="tabset-3-2-tab">
<div id="topology-errors-uploaded-r"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
  new window.WebGeoDS.CodeCell("topology-errors-uploaded-r", {
    language: "r",
    initialCode: "data <- NULL\nfor (path in c(\"/uploaded.geojson\", \"/uploaded.shp\", \"/vsizip//uploaded.zip\")) {\n  data <- tryCatch(sf::st_read(path, quiet = TRUE), error = function(e) NULL)\n  if (!is.null(data)) break\n}\n\nif (!is.null(data) && !(\"name\" %in% names(data))) {\n  data$name <- paste(\"geometry\", seq_len(nrow(data)))\n}\n\nif (is.null(data)) {\n  a <- sf::st_polygon(list(rbind(c(12.45, 41.85), c(12.52, 41.85), c(12.52, 41.92), c(12.45, 41.92), c(12.45, 41.85))))\n  b <- sf::st_polygon(list(rbind(c(12.50, 41.87), c(12.57, 41.87), c(12.57, 41.94), c(12.50, 41.94), c(12.50, 41.87))))\n  data <- sf::st_sf(name = c(\"A (example)\", \"B (example)\"), geometry = sf::st_sfc(a, b, crs = 4326))\n}\n\ndetect_and_check(data)",
    onRun: async (code, output) => {
      output.waiting("Running...");
      return output.result(await window.WebGeoDS.R.run(code, {}));
    }
  });
});
</script>
</div>
</div>
</div>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb23" data-startfrom="845" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 844;"><span id="cb23-845">pyErrorsUploaded <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCellValue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-uploaded-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Generators)</span>
<span id="cb23-846">{</span>
<span id="cb23-847">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (pyErrorsUploaded) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGeoJSON</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyErrorsUploaded<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> { <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">paint</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">errorPaint</span>(pyErrorsUploaded) })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb23-848">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-23-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-23-2" data-nodetype="expression">

</div>
</div>
</div>
</div>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb24" data-startfrom="854" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 853;"><span id="cb24-854">rErrorsUploaded <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCellValue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-uploaded-r"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Generators)</span>
<span id="cb24-855">{</span>
<span id="cb24-856">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (rErrorsUploaded) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGeoJSON</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topology-errors-r"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rErrorsUploaded<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> { <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">paint</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">errorPaint</span>(rErrorsUploaded) })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb24-857">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-24-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-24-2" data-nodetype="expression">

</div>
</div>
</div>
</div>
</section>
<section id="knowing-whats-broken-is-already-a-result" class="level2">
<h2 class="anchored" data-anchor-id="knowing-whats-broken-is-already-a-result">6. Knowing what’s broken is already a result</h2>
<p>A report that says “23 overlaps, 8 gaps, 4 slivers” isn’t half a tool: it’s a legitimate, complete quality-assurance step in its own right. Fixing these errors almost always requires a human decision — which polygon to move, who to assign a gap to, whether a 2 m² sliver is noise or a real island. A future article may cover repair strategies; this one deliberately stops before that, where geometry alone can no longer answer the question.</p>
<script async="" data-uid="31051e3ca1" src="https://webgeods.kit.com/31051e3ca1/index.js"></script>


<div class="ojs-auto-generated hidden">
<script type="ojs-module-contents">
eyJjb250ZW50cyI6WyAgeyJtZXRob2ROYW1lIjoiaW50ZXJwcmV0IiwiaW5saW5lIjoidHJ1ZSIsInNvdXJjZSI6Imh0bC5odG1sYDxzcGFuPiR7dXBsb2FkU3RhdHVzfTwvc3Bhbj5gIiwgImNlbGxOYW1lIjoib2pzLWVsZW1lbnQtaWQtMSJ9XX0=
</script>
</div>
</section>

 ]]></description>
  <category>tool</category>
  <category>geometry</category>
  <category>bilingual</category>
  <guid>https://webgeods.com/posts/topology-errors.html</guid>
  <pubDate>Mon, 31 Aug 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Geometry validity: find and understand invalid geometries</title>
  <link>https://webgeods.com/posts/geometry-validity.html</link>
  <description><![CDATA[ 




<p>Upload a GeoJSON, find out which geometries are invalid and why, and run the same diagnosis in Python and in R on the same map — repair (<code>make_valid()</code>/<code>st_make_valid()</code>) is a separate, optional step, at the bottom of the page.</p>
<p>A <code>.geojson</code>, or a shapefile (either as a single <code>.zip</code>, or as <code>.shp</code>/<code>.dbf</code>/<code>.shx</code> selected together) — see the section below.</p>
<p>Just want to quickly validate or fix a file, without the rest of the reading? Use the <a href="../tools/geojson-shapefile-validator.html">standalone tool</a> — same engine, less prose.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb1" data-startfrom="22" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 21;"><span id="cb1-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// The input and the writing logic into the virtual filesystem live in</span></span>
<span id="cb1-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// shared/upload.js (WebGeoDS.Upload) — same helper used in</span></span>
<span id="cb1-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// topology-errors.qmd, not rewritten here.</span></span>
<span id="cb1-25">viewof uploadedFiles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Upload</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">createInput</span>()</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb2" data-startfrom="30" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 29;"><span id="cb2-30">mutable uploadStatus <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Upload</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">defaultStatus</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-2" data-nodetype="declaration">

</div>
</div>
</div>
<p><span><span id="ojs-element-id-1"></span></span></p>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb3" data-startfrom="38" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 37;"><span id="cb3-38">{</span>
<span id="cb3-39">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Upload</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">load</span>(uploadedFiles)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-40">  mutable uploadStatus <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> result<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">message</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-41">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div id="ojs-cell-3" data-nodetype="expression">

</div>
</div>
</div>
<section id="can-a-polygon-look-normal-and-still-be-invalid" class="level2">
<h2 class="anchored" data-anchor-id="can-a-polygon-look-normal-and-still-be-invalid">Can a polygon look normal and still be invalid?</h2>
<div class="cell" data-layout-align="default">
<div class="cell-output-display">
<div>
<p></p><figure class="figure"><p></p>
<div>
<pre class="mermaid mermaid-js">flowchart TD
    A["Looks fine on the map"] --&gt; B["Polygon"]
    B --&gt; C["Geometry validator"]
    C --&gt; D["❌ INVALID"]
    D --&gt; E["Why?"]
</pre>
</div>
<p></p></figure><p></p>
</div>
</div>
</div>
<p>Yes — a polygon can have a boundary that crosses itself, a hole that extends outside the outer boundary, or two holes that overlap, and it’s not uncommon for the shape on the map to look perfectly fine. Below you can find out exactly what to look for, in your own file or in one of the four ready-made examples further down.</p>
</section>
<section id="shared-map-and-table" class="level2">
<h2 class="anchored" data-anchor-id="shared-map-and-table">Shared map and table</h2>
<p>A single map and table, shared by every example on the page: run the same diagnosis in Python or R and compare the result here.</p>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb4" data-startfrom="68" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 67;"><span id="cb4-68">sharedMap <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb4-69">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> map <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">window</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">WebGeoDS</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Map</span>({ <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">center</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">12.5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">41.9</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">zoom</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">height</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"480px"</span> })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-70">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> map<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ready</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-71">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> map<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-72">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div id="ojs-cell-4" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb5" data-startfrom="77" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 76;"><span id="cb5-77">sharedMapEl <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">element</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-5" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb6" data-startfrom="83" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 82;"><span id="cb6-83"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// The color is decided by JS, not by Python/R: the Python/R cells only</span></span>
<span id="cb6-84"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// return GeoJSON with properties like "valid" — neither language knows</span></span>
<span id="cb6-85"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// or needs to know who's going to draw it red or green.</span></span>
<span id="cb6-86"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span></span>
<span id="cb6-87"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Used ONLY on the first setGeoJSON() call on a source (when it</span></span>
<span id="cb6-88"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// creates the layer — setGeoJSON() on an already-existing source only</span></span>
<span id="cb6-89"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// calls setData(), never setPaintProperty): the paint chosen at</span></span>
<span id="cb6-90"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// diagnosis time stays fixed for the layer's whole lifetime, even</span></span>
<span id="cb6-91"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// after Repair replaces the data with different properties</span></span>
<span id="cb6-92"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// (valid_before/valid_after, no longer "valid"). That's why it checks</span></span>
<span id="cb6-93"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// BOTH possible keys — not just "valid" — otherwise the color would</span></span>
<span id="cb6-94"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// stay red forever after the repair (verified empirically: a real</span></span>
<span id="cb6-95"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// bug, not a theoretical one).</span></span>
<span id="cb6-96">VALIDITY_PAINT <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ({</span>
<span id="cb6-97">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fill-color"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [</span>
<span id="cb6-98">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"case"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-99">    [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"any"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"=="</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"get"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"valid"</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"=="</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"get"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"valid_after"</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span>]]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-100">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#2ea44f"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-101">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#e05252"</span></span>
<span id="cb6-102">  ]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb6-103">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fill-opacity"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.55</span></span>
<span id="cb6-104">})</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div id="ojs-cell-6" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb7" data-startfrom="109" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 108;"><span id="cb7-109">topologyTable <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tableCell</span>([<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-r"</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Generators<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {</span>
<span id="cb7-110">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">rowClassName</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (row) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb7-111">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">valid_after</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"false"</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"webgeods-row-invalid"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-112">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">valid_before</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"false"</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"webgeods-row-fixed"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-113">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (row<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">valid</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"false"</span>) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"webgeods-row-invalid"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-114">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-115">  }</span>
<span id="cb7-116">})</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-7" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb8" data-startfrom="122" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 121;"><span id="cb8-122"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Reactive report above the table: totals + valid/invalid count,</span></span>
<span id="cb8-123"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// recomputed every time the content of one of the two sources</span></span>
<span id="cb8-124"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// actually changes (same 'sourcedata'/'content' event tableCell()</span></span>
<span id="cb8-125"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// already uses internally, listened to directly here because this</span></span>
<span id="cb8-126"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// needs a count, not a table). Reads both the diagnosis property</span></span>
<span id="cb8-127"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ("valid") and the post-repair one ("valid_after"), so it stays</span></span>
<span id="cb8-128"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// correct even after the Repair section further down has run.</span></span>
<span id="cb8-129">validationStats <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Generators<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">observe</span>((change) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb8-130">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> isInvalid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (feature) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb8-131">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> feature<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">properties</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">??</span> {}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-132">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"valid_after"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?</span> p<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">valid_after</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> p<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">valid</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-133">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-134">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> compute <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb8-135">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> features <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-r"</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">flatMap</span>((id) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getGeoJSON</span>(id)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">features</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">??</span> [])<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-136">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> total <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> features<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-137">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> invalid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> features<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(isInvalid)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-138">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">change</span>({ total<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">valid</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> total <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> invalid<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> invalid })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-139">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-140">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">compute</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-141">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> handler <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (e) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb8-142">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">dataType</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"source"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sourceDataType</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"content"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> (e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sourceId</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-py"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">||</span> e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sourceId</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-r"</span>)) {</span>
<span id="cb8-143">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">compute</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-144">    }</span>
<span id="cb8-145">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-146">  sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">map</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">on</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sourcedata"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> handler)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-147">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">map</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">off</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sourcedata"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> handler)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-148">})</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div id="ojs-cell-8" data-nodetype="declaration">

</div>
</div>
</div>
<p><strong>Geometry validity</strong> — <span><span id="ojs-element-id-2"></span></span> feature, <span><span id="ojs-element-id-3"></span></span> valid, <span><span id="ojs-element-id-4"></span></span> invalid.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb9" data-startfrom="155" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 154;"><span id="cb9-155">resetTopology <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">async</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb9-156">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> id <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">of</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-r"</span>]) {</span>
<span id="cb9-157">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getGeoJSON</span>(id)) {</span>
<span id="cb9-158">      <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGeoJSON</span>(id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> { <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">type</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"FeatureCollection"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">features</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [] })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-159">    }</span>
<span id="cb9-160">  }</span>
<span id="cb9-161">}</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-9" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb10" data-startfrom="166" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 165;"><span id="cb10-166">resetMapButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb10-167">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> button <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">document</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">createElement</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"button"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-168">  button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">textContent</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"🔄 Reset map and table"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-169">  button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">onclick</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">resetTopology</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-170">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-171">}</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-10" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb11" data-startfrom="176" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 175;"><span id="cb11-176"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Factory for the "Load this example" buttons: replaces the code of</span></span>
<span id="cb11-177"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// the diagnosis cell pair via WebGeoDS.CodeCell.find() + setCode() —</span></span>
<span id="cb11-178"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// doesn't run anything on its own, leaves the "Run" click to the</span></span>
<span id="cb11-179"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// student.</span></span>
<span id="cb11-180">loadExampleButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rCode) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb11-181">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> button <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">document</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">createElement</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"button"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-182">  button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">textContent</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-183">  button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">onclick</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">async</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb11-184">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Promise</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">all</span>([</span>
<span id="cb11-185">      <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">window</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">WebGeoDS</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">CodeCell</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-diagnose-py"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setCode</span>(pyCode)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-186">      <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">window</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">WebGeoDS</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">CodeCell</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-diagnose-r"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setCode</span>(rCode)</span>
<span id="cb11-187">    ])<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-188">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">document</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getElementById</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-diagnose-py"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scrollIntoView</span>({ <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">behavior</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"smooth"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">block</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"center"</span> })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-189">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-190">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-191">}</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-11" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb12" data-startfrom="197" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 196;"><span id="cb12-197">pyBowtieCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`import geopandas as gpd</span></span>
<span id="cb12-198"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.geometry import shape, mapping</span></span>
<span id="cb12-199"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.validation import explain_validity</span></span>
<span id="cb12-200"></span>
<span id="cb12-201"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">gdf = None</span></span>
<span id="cb12-202"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">for path in ["/uploaded.geojson", "/uploaded.shp", "/vsizip//uploaded.zip"]:</span></span>
<span id="cb12-203"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    try:</span></span>
<span id="cb12-204"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        gdf = gpd.read_file(path)</span></span>
<span id="cb12-205"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        break</span></span>
<span id="cb12-206"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    except Exception:</span></span>
<span id="cb12-207"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        pass</span></span>
<span id="cb12-208"></span>
<span id="cb12-209"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">if gdf is None:</span></span>
<span id="cb12-210"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    bowtie = {"type": "Polygon", "coordinates": [[[12.45, 41.85], [12.55, 41.95], [12.45, 41.95], [12.55, 41.85], [12.45, 41.85]]]}</span></span>
<span id="cb12-211"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    gdf = gpd.GeoDataFrame({"name": ["bowtie"]}, geometry=[shape(bowtie)], crs="EPSG:4326")</span></span>
<span id="cb12-212"></span>
<span id="cb12-213"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">if "name" not in gdf.columns:</span></span>
<span id="cb12-214"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    gdf["name"] = [f"geometry {i+1}" for i in range(len(gdf))]</span></span>
<span id="cb12-215"></span>
<span id="cb12-216"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">gdf["valid"] = gdf.geometry.is_valid</span></span>
<span id="cb12-217"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">gdf["reason"] = gdf.geometry.apply(lambda g: None if g.is_valid else explain_validity(g))</span></span>
<span id="cb12-218"></span>
<span id="cb12-219"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb12-220"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    "type": "FeatureCollection",</span></span>
<span id="cb12-221"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    "features": [</span></span>
<span id="cb12-222"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        {"type": "Feature", "properties": {"name": row["name"], "valid": bool(row["valid"]), "reason": row["reason"]}, "geometry": mapping(row.geometry)}</span></span>
<span id="cb12-223"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        for _, row in gdf.iterrows()</span></span>
<span id="cb12-224"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    ]</span></span>
<span id="cb12-225"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">}`</span></span>
<span id="cb12-226">rBowtieCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`data &lt;- NULL</span></span>
<span id="cb12-227"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">for (path in c("/uploaded.geojson", "/uploaded.shp", "/vsizip//uploaded.zip")) {</span></span>
<span id="cb12-228"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  data &lt;- tryCatch(sf::st_read(path, quiet = TRUE), error = function(e) NULL)</span></span>
<span id="cb12-229"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  if (!is.null(data)) break</span></span>
<span id="cb12-230"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb12-231"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">if (is.null(data)) {</span></span>
<span id="cb12-232"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  wkt &lt;- "POLYGON((12.45 41.85, 12.55 41.95, 12.45 41.95, 12.55 41.85, 12.45 41.85))"</span></span>
<span id="cb12-233"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  data &lt;- sf::st_sf(name = "bowtie", geometry = sf::st_as_sfc(wkt, crs = 4326))</span></span>
<span id="cb12-234"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb12-235"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">if (!("name" %in% names(data))) {</span></span>
<span id="cb12-236"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  data$name &lt;- paste("geometry", seq_len(nrow(data)))</span></span>
<span id="cb12-237"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb12-238"></span>
<span id="cb12-239"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$valid &lt;- sf::st_is_valid(data)</span></span>
<span id="cb12-240"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$reason &lt;- sf::st_is_valid(data, reason = TRUE)</span></span>
<span id="cb12-241"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$reason[data$valid] &lt;- NA</span></span>
<span id="cb12-242"></span>
<span id="cb12-243"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">jsonlite::fromJSON(geojsonsf::sf_geojson(data), simplifyVector = FALSE)`</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-12-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-12-2" data-nodetype="declaration">

</div>
</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb13" data-startfrom="247" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 246;"><span id="cb13-247">tryExampleButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loadExampleButton</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"▶ Try an example (bowtie polygon)"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyBowtieCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rBowtieCode)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-13" data-nodetype="declaration">

</div>
</div>
</div>
</section>
<section id="diagnose-validate-your-geometry" class="level2">
<h2 class="anchored" data-anchor-id="diagnose-validate-your-geometry">Diagnose: validate your geometry</h2>
<p>Run the same check in Python or R on the current data (your file uploaded above, or the example already loaded below) — no repair yet, just diagnosis: is the geometry valid? If not, why?</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true">Python</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false">R</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<div id="geometry-diagnose-py"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
  new window.WebGeoDS.CodeCell("geometry-diagnose-py", {
    language: "python",
    initialCode: "import geopandas as gpd\nfrom shapely.geometry import shape, mapping\nfrom shapely.validation import explain_validity\n\ngdf = None\nfor path in [\"/uploaded.geojson\", \"/uploaded.shp\", \"/vsizip//uploaded.zip\"]:\n    try:\n        gdf = gpd.read_file(path)\n        break\n    except Exception:\n        pass\n\nif gdf is None:\n    bowtie = {\"type\": \"Polygon\", \"coordinates\": [[[12.45, 41.85], [12.55, 41.95], [12.45, 41.95], [12.55, 41.85], [12.45, 41.85]]]}\n    gdf = gpd.GeoDataFrame({\"name\": [\"bowtie\"]}, geometry=[shape(bowtie)], crs=\"EPSG:4326\")\n\nif \"name\" not in gdf.columns:\n    gdf[\"name\"] = [f\"geometry {i+1}\" for i in range(len(gdf))]\n\ngdf[\"valid\"] = gdf.geometry.is_valid\ngdf[\"reason\"] = gdf.geometry.apply(lambda g: None if g.is_valid else explain_validity(g))\n\n{\n    \"type\": \"FeatureCollection\",\n    \"features\": [\n        {\"type\": \"Feature\", \"properties\": {\"name\": row[\"name\"], \"valid\": bool(row[\"valid\"]), \"reason\": row[\"reason\"]}, \"geometry\": mapping(row.geometry)}\n        for _, row in gdf.iterrows()\n    ]\n}",
    onRun: async (code, output) => {
      output.waiting("Running...");
      return output.result(await window.WebGeoDS.Python.run(code, { packages: ["geopandas","shapely"] }));
    }
  });
});
</script>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<div id="geometry-diagnose-r"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
  new window.WebGeoDS.CodeCell("geometry-diagnose-r", {
    language: "r",
    initialCode: "data <- NULL\nfor (path in c(\"/uploaded.geojson\", \"/uploaded.shp\", \"/vsizip//uploaded.zip\")) {\n  data <- tryCatch(sf::st_read(path, quiet = TRUE), error = function(e) NULL)\n  if (!is.null(data)) break\n}\nif (is.null(data)) {\n  wkt <- \"POLYGON((12.45 41.85, 12.55 41.95, 12.45 41.95, 12.55 41.85, 12.45 41.85))\"\n  data <- sf::st_sf(name = \"bowtie\", geometry = sf::st_as_sfc(wkt, crs = 4326))\n}\nif (!(\"name\" %in% names(data))) {\n  data$name <- paste(\"geometry\", seq_len(nrow(data)))\n}\n\ndata$valid <- sf::st_is_valid(data)\ndata$reason <- sf::st_is_valid(data, reason = TRUE)\ndata$reason[data$valid] <- NA\n\njsonlite::fromJSON(geojsonsf::sf_geojson(data), simplifyVector = FALSE)",
    onRun: async (code, output) => {
      output.waiting("Running...");
      return output.result(await window.WebGeoDS.R.run(code, { packages: ["sf","geojsonsf","jsonlite"] }));
    }
  });
});
</script>
</div>
</div>
</div>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb14" data-startfrom="330" data-source-offset="-421" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 329;"><span id="cb14-330">pyDiagnose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCellValue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-diagnose-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Generators)</span>
<span id="cb14-331">{</span>
<span id="cb14-332">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (pyDiagnose) {</span>
<span id="cb14-333">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGeoJSON</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyDiagnose<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> { <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">paint</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> VALIDITY_PAINT })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb14-334">  }</span>
<span id="cb14-335">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-14-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-14-2" data-nodetype="expression">

</div>
</div>
</div>
</div>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb15" data-startfrom="341" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 340;"><span id="cb15-341">rDiagnose <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCellValue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-diagnose-r"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Generators)</span>
<span id="cb15-342">{</span>
<span id="cb15-343">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (rDiagnose) {</span>
<span id="cb15-344">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGeoJSON</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-r"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rDiagnose<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> { <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">paint</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> VALIDITY_PAINT })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb15-345">  }</span>
<span id="cb15-346">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-15-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-15-2" data-nodetype="expression">

</div>
</div>
</div>
</div>
</section>
<section id="same-spatial-question-two-languages" class="level2">
<h2 class="anchored" data-anchor-id="same-spatial-question-two-languages">Same spatial question, two languages</h2>
<p>Python and R answer the same question with one line each:</p>
<p><strong>Python</strong></p>
<div class="sourceCode" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1">gdf.geometry.is_valid</span></code></pre></div>
<p><strong>R</strong></p>
<div class="sourceCode" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb17-1">sf<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">st_is_valid</span>(data)</span></code></pre></div>
<p>Both go through the same geometry engine, GEOS, for this calculation — but don’t expect the exact same text when you ask <em>why</em> a geometry is invalid: <code>explain_validity()</code> in Python includes the coordinates of the problem (e.g.&nbsp;<code>"Self-intersection[12.5 41.9]"</code>), while <code>st_is_valid(reason = TRUE)</code> in R describes the edges involved without coordinates (e.g.&nbsp;<code>"Edge 0 crosses edge 2"</code>) — same calculation, different vocabulary. It’s exactly the kind of detail that distinguishes one spatial ecosystem from the other, not a bug in either one.</p>
</section>
<section id="valid-according-to-whom" class="level2">
<h2 class="anchored" data-anchor-id="valid-according-to-whom">Valid according to whom?</h2>
<p>“Valid” isn’t absolute: it depends on the geometric model and the engine checking it.</p>
<ul>
<li><strong>Python</strong> → <code>shapely</code> → always GEOS.</li>
<li><strong>R</strong> → <code>sf</code> → GEOS or S2, depending on <code>sf::sf_use_s2()</code>.</li>
</ul>
<p>For the diagnosis above the difference doesn’t show. It becomes concrete in the repair, below:</p>
<div class="callout callout-style-default callout-important callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Important
</div>
</div>
<div class="callout-body-container callout-body">
<p><strong>Why <code>sf_use_s2(FALSE)</code> before <code>st_make_valid()</code>?</strong> With geographic coordinates (lon/lat) and <code>sf_use_s2(TRUE)</code> (the default), <code>st_make_valid()</code> in R dispatches to <code>s2::s2_rebuild()</code> instead of GEOS — a different algorithm that, on these cases, <strong>fixes nothing</strong>, returning the geometry unchanged without an error. Verified not just on webR but also on real R 4.3.3 with sf 1.0.15: this isn’t a bug in this project, it’s documented <code>sf</code> behavior (see issues #1985 and #1771 on <a href="https://github.com/r-spatial/sf/issues/1985">r-spatial/sf</a>). Forcing <code>sf_use_s2(FALSE)</code> routes the call through GEOS, which works correctly here; it’s turned back on right after, because other operations (distances, areas) on geographic coordinates benefit from S2. <code>shapely</code> in Python doesn’t have this problem because it has no alternative S2 engine: it always goes through GEOS.</p>
</div>
</div>
</section>
<section id="gallery-of-geometric-errors" class="level2">
<h2 class="anchored" data-anchor-id="gallery-of-geometric-errors">Gallery of geometric errors</h2>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Error</th>
<th>What happens</th>
<th>Detect</th>
<th>Fix</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Self-intersection</td>
<td>The boundary crosses itself</td>
<td>✓</td>
<td>✓</td>
</tr>
<tr class="even">
<td>Hole outside the boundary</td>
<td>An inner ring extends outside</td>
<td>✓</td>
<td>✓</td>
</tr>
<tr class="odd">
<td>Self-touching ring</td>
<td>The boundary touches itself at a point</td>
<td>✓</td>
<td>✓</td>
</tr>
<tr class="even">
<td>Overlapping holes</td>
<td>Two inner rings intersect</td>
<td>✓</td>
<td>✓</td>
</tr>
</tbody>
</table>
<p>Each example below loads its own data into the diagnosis cell pair above — no repair here, that’s in the Repair section at the bottom of the page.</p>
<section id="self-intersection-bowtie" class="level3">
<h3 class="anchored" data-anchor-id="self-intersection-bowtie">Self-intersection (“bowtie”)</h3>
<svg viewbox="0 0 220 170" style="max-width: 320px; height: auto; display: block; margin: 1.5rem auto;" aria-label="Bowtie polygon: the boundary crosses itself at the center">
<rect x="1" y="1" width="218" height="168" fill="#f3ede1" stroke="#5a4f3e" stroke-width="1"></rect> <path d="M 20 140 L 200 20 L 20 20 L 200 140 Z" fill="#e05252" fill-opacity="0.35" stroke="#2a2117" stroke-width="2"></path> <circle cx="110" cy="80" r="5" fill="#e05252" stroke="#2a2117" stroke-width="1.5"></circle> <text x="110" y="105" text-anchor="middle" font-family="monospace" font-size="12" fill="#2a2117">self-intersection</text>
</svg>
<p>The polygon’s boundary crosses itself, forming a bowtie shape instead of a single closed area — the most common case in practice, often the result of imprecise manual digitizing.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb18" data-startfrom="429" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 428;"><span id="cb18-429">loadBowtieButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loadExampleButton</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"📋 Load this example"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyBowtieCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rBowtieCode)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-16" data-nodetype="declaration">

</div>
</div>
</div>
<p>Scroll to the <strong>Repair</strong> section at the bottom of the page to see how it’s fixed.</p>
</section>
<section id="hole-extending-outside-the-boundary" class="level3">
<h3 class="anchored" data-anchor-id="hole-extending-outside-the-boundary">Hole extending outside the boundary</h3>
<svg viewbox="0 0 260 220" style="max-width: 320px; height: auto; display: block; margin: 1.5rem auto;" aria-label="Polygon with a hole extending outside the outer boundary">
<rect x="1" y="1" width="258" height="218" fill="#f3ede1" stroke="#5a4f3e" stroke-width="1"></rect> <rect x="40" y="40" width="160" height="160" fill="#42583c" fill-opacity="0.3" stroke="#2a2117" stroke-width="2"></rect> <rect x="140" y="40" width="60" height="80" fill="#f3ede1"></rect> <rect x="140" y="20" width="100" height="20" fill="#e05252" fill-opacity="0.7"></rect> <rect x="200" y="40" width="40" height="80" fill="#e05252" fill-opacity="0.7"></rect> <rect x="140" y="20" width="100" height="100" fill="none" stroke="#2a2117" stroke-width="2" stroke-dasharray="4 3"></rect> <text x="130" y="205" text-anchor="middle" font-family="monospace" font-size="11" fill="#2a2117">hole extends past the boundary</text>
</svg>
<p>A “hole” (inner ring, e.g.&nbsp;a lake inside a land polygon) must lie entirely within the outer boundary. If even part of the hole extends outside it, the geometry violates the Simple Features validity rules.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb19" data-startfrom="454" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 453;"><span id="cb19-454">pyHoleCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`import geopandas as gpd</span></span>
<span id="cb19-455"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.geometry import shape, mapping</span></span>
<span id="cb19-456"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.validation import explain_validity</span></span>
<span id="cb19-457"></span>
<span id="cb19-458"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">geom = shape({</span></span>
<span id="cb19-459"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  "type": "Polygon",</span></span>
<span id="cb19-460"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  "coordinates": [</span></span>
<span id="cb19-461"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    [[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]],</span></span>
<span id="cb19-462"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    [[3, 3], [5, 3], [5, 5], [3, 5], [3, 3]]</span></span>
<span id="cb19-463"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  ]</span></span>
<span id="cb19-464"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb19-465"></span>
<span id="cb19-466"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb19-467"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    "type": "FeatureCollection",</span></span>
<span id="cb19-468"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    "features": [{</span></span>
<span id="cb19-469"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        "type": "Feature",</span></span>
<span id="cb19-470"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        "properties": {"name": "hole-outside-boundary", "valid": geom.is_valid, "reason": None if geom.is_valid else explain_validity(geom)},</span></span>
<span id="cb19-471"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        "geometry": mapping(geom)</span></span>
<span id="cb19-472"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    }]</span></span>
<span id="cb19-473"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">}`</span></span>
<span id="cb19-474">rHoleCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`wkt &lt;- "POLYGON((0 0, 4 0, 4 4, 0 4, 0 0), (3 3, 5 3, 5 5, 3 5, 3 3))"</span></span>
<span id="cb19-475"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">geom &lt;- sf::st_as_sfc(wkt, crs = 4326)</span></span>
<span id="cb19-476"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data &lt;- sf::st_sf(name = "hole-outside-boundary", geometry = geom)</span></span>
<span id="cb19-477"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$valid &lt;- sf::st_is_valid(data)</span></span>
<span id="cb19-478"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$reason &lt;- sf::st_is_valid(data, reason = TRUE)</span></span>
<span id="cb19-479"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$reason[data$valid] &lt;- NA</span></span>
<span id="cb19-480"></span>
<span id="cb19-481"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">jsonlite::fromJSON(geojsonsf::sf_geojson(data), simplifyVector = FALSE)`</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-17-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-17-2" data-nodetype="declaration">

</div>
</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb20" data-startfrom="485" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 484;"><span id="cb20-485">loadHoleButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loadExampleButton</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"📋 Load this example"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyHoleCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rHoleCode)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-18" data-nodetype="declaration">

</div>
</div>
</div>
<p>Scroll to the <strong>Repair</strong> section at the bottom of the page to see how it’s fixed.</p>
</section>
<section id="ring-touching-itself-hourglass" class="level3">
<h3 class="anchored" data-anchor-id="ring-touching-itself-hourglass">Ring touching itself (hourglass)</h3>
<svg viewbox="0 0 220 220" style="max-width: 320px; height: auto; display: block; margin: 1.5rem auto;" aria-label="Two lobes of a polygon touching at a single vertex, without crossing">
<rect x="1" y="1" width="218" height="218" fill="#f3ede1" stroke="#5a4f3e" stroke-width="1"></rect> <path d="M 20 20 L 200 20 L 110 110 Z" fill="#e05252" fill-opacity="0.35" stroke="#2a2117" stroke-width="2"></path> <path d="M 110 110 L 20 200 L 200 200 Z" fill="#e05252" fill-opacity="0.35" stroke="#2a2117" stroke-width="2"></path> <circle cx="110" cy="110" r="5" fill="#e05252" stroke="#2a2117" stroke-width="1.5"></circle> <text x="110" y="135" text-anchor="middle" font-family="monospace" font-size="12" fill="#2a2117">a single shared vertex</text>
</svg>
<p>The polygon’s boundary touches itself at one point, without crossing, effectively splitting the shape into two lobes joined by a single vertex — not cleanly connected, so invalid.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb21" data-startfrom="508" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 507;"><span id="cb21-508">pyTouchCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`import geopandas as gpd</span></span>
<span id="cb21-509"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.geometry import shape, mapping</span></span>
<span id="cb21-510"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.validation import explain_validity</span></span>
<span id="cb21-511"></span>
<span id="cb21-512"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">geom = shape({"type": "Polygon", "coordinates": [[[0, 0], [2, 2], [4, 0], [4, 4], [2, 2], [0, 4], [0, 0]]]})</span></span>
<span id="cb21-513"></span>
<span id="cb21-514"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb21-515"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    "type": "FeatureCollection",</span></span>
<span id="cb21-516"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    "features": [{</span></span>
<span id="cb21-517"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        "type": "Feature",</span></span>
<span id="cb21-518"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        "properties": {"name": "hourglass", "valid": geom.is_valid, "reason": None if geom.is_valid else explain_validity(geom)},</span></span>
<span id="cb21-519"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        "geometry": mapping(geom)</span></span>
<span id="cb21-520"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    }]</span></span>
<span id="cb21-521"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">}`</span></span>
<span id="cb21-522">rTouchCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`wkt &lt;- "POLYGON((0 0, 2 2, 4 0, 4 4, 2 2, 0 4, 0 0))"</span></span>
<span id="cb21-523"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">geom &lt;- sf::st_as_sfc(wkt, crs = 4326)</span></span>
<span id="cb21-524"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data &lt;- sf::st_sf(name = "hourglass", geometry = geom)</span></span>
<span id="cb21-525"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$valid &lt;- sf::st_is_valid(data)</span></span>
<span id="cb21-526"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$reason &lt;- sf::st_is_valid(data, reason = TRUE)</span></span>
<span id="cb21-527"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$reason[data$valid] &lt;- NA</span></span>
<span id="cb21-528"></span>
<span id="cb21-529"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">jsonlite::fromJSON(geojsonsf::sf_geojson(data), simplifyVector = FALSE)`</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-19-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-19-2" data-nodetype="declaration">

</div>
</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb22" data-startfrom="533" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 532;"><span id="cb22-533">loadTouchButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loadExampleButton</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"📋 Load this example"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyTouchCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rTouchCode)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-20" data-nodetype="declaration">

</div>
</div>
</div>
<p>Scroll to the <strong>Repair</strong> section at the bottom of the page to see how it’s fixed.</p>
</section>
<section id="overlapping-holes" class="level3">
<h3 class="anchored" data-anchor-id="overlapping-holes">Overlapping holes</h3>
<svg viewbox="0 0 260 260" style="max-width: 320px; height: auto; display: block; margin: 1.5rem auto;" aria-label="Two holes overlapping inside the same polygon, like a Venn diagram">
<defs> <clippath id="holeA-clip"><circle cx="105" cy="130" r="55"></circle></clippath> </defs> <rect x="1" y="1" width="258" height="258" fill="#f3ede1" stroke="#5a4f3e" stroke-width="1"></rect> <rect x="20" y="20" width="220" height="220" fill="#42583c" fill-opacity="0.15" stroke="#2a2117" stroke-width="2"></rect> <circle cx="105" cy="130" r="55" fill="#42583c" fill-opacity="0.3" stroke="#2a2117" stroke-width="2"></circle> <circle cx="155" cy="130" r="55" fill="#42583c" fill-opacity="0.3" stroke="#2a2117" stroke-width="2"></circle> <circle cx="155" cy="130" r="55" fill="#e05252" fill-opacity="0.85" clip-path="url(#holeA-clip)"></circle> <text x="130" y="230" text-anchor="middle" font-family="monospace" font-size="12" fill="#2a2117">the two holes overlap</text>
</svg>
<p>If a polygon has more than one hole, they can’t overlap each other: two intersecting holes create an ambiguous area — inside or outside the polygon? — which the model doesn’t allow.</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb23" data-startfrom="560" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 559;"><span id="cb23-560">pyOverlapHolesCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`import geopandas as gpd</span></span>
<span id="cb23-561"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.geometry import shape, mapping</span></span>
<span id="cb23-562"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">from shapely.validation import explain_validity</span></span>
<span id="cb23-563"></span>
<span id="cb23-564"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">geom = shape({</span></span>
<span id="cb23-565"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  "type": "Polygon",</span></span>
<span id="cb23-566"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  "coordinates": [</span></span>
<span id="cb23-567"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    [[0, 0], [6, 0], [6, 6], [0, 6], [0, 0]],</span></span>
<span id="cb23-568"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    [[1, 1], [3, 1], [3, 3], [1, 3], [1, 1]],</span></span>
<span id="cb23-569"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    [[2, 2], [4, 2], [4, 4], [2, 4], [2, 2]]</span></span>
<span id="cb23-570"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  ]</span></span>
<span id="cb23-571"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb23-572"></span>
<span id="cb23-573"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb23-574"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    "type": "FeatureCollection",</span></span>
<span id="cb23-575"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    "features": [{</span></span>
<span id="cb23-576"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        "type": "Feature",</span></span>
<span id="cb23-577"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        "properties": {"name": "overlapping-holes", "valid": geom.is_valid, "reason": None if geom.is_valid else explain_validity(geom)},</span></span>
<span id="cb23-578"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">        "geometry": mapping(geom)</span></span>
<span id="cb23-579"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">    }]</span></span>
<span id="cb23-580"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">}`</span></span>
<span id="cb23-581">rOverlapHolesCode <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`wkt &lt;- "POLYGON((0 0, 6 0, 6 6, 0 6, 0 0), (1 1, 3 1, 3 3, 1 3, 1 1), (2 2, 4 2, 4 4, 2 4, 2 2))"</span></span>
<span id="cb23-582"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">geom &lt;- sf::st_as_sfc(wkt, crs = 4326)</span></span>
<span id="cb23-583"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data &lt;- sf::st_sf(name = "overlapping-holes", geometry = geom)</span></span>
<span id="cb23-584"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$valid &lt;- sf::st_is_valid(data)</span></span>
<span id="cb23-585"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$reason &lt;- sf::st_is_valid(data, reason = TRUE)</span></span>
<span id="cb23-586"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">data$reason[data$valid] &lt;- NA</span></span>
<span id="cb23-587"></span>
<span id="cb23-588"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">jsonlite::fromJSON(geojsonsf::sf_geojson(data), simplifyVector = FALSE)`</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-21-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-21-2" data-nodetype="declaration">

</div>
</div>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb24" data-startfrom="592" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 591;"><span id="cb24-592">loadOverlapHolesButton <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">loadExampleButton</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"📋 Load this example"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyOverlapHolesCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rOverlapHolesCode)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-22" data-nodetype="declaration">

</div>
</div>
</div>
<p>Scroll to the <strong>Repair</strong> section below to see how it’s fixed.</p>
</section>
</section>
<section id="repair-optional" class="level2">
<h2 class="anchored" data-anchor-id="repair-optional">Repair (optional)</h2>
<p>The diagnosis tells you what’s wrong. Repair changes the data — <code>make_valid()</code>/<code>st_make_valid()</code> rebuild the geometry into an equivalent, valid form. <strong>Requires having run the diagnosis above at least once</strong>: it reuses exactly the same data just diagnosed (<code>gdf</code> in Python, <code>data</code> in R stay in the session between one cell and the next, like in a notebook) — no new reading of the file.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-2-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-1" aria-controls="tabset-2-1" aria-selected="true">Python</a></li><li class="nav-item"><a class="nav-link" id="tabset-2-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-2" aria-controls="tabset-2-2" aria-selected="false">R</a></li></ul>
<div class="tab-content">
<div id="tabset-2-1" class="tab-pane active" aria-labelledby="tabset-2-1-tab">
<div id="geometry-repair-py"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
  new window.WebGeoDS.CodeCell("geometry-repair-py", {
    language: "python",
    initialCode: "from shapely.geometry import mapping\nfrom shapely.validation import make_valid\n\ngdf[\"valid_before\"] = gdf[\"valid\"]\ngdf[\"geometry\"] = gdf.geometry.apply(lambda g: make_valid(g) if not g.is_valid else g)\ngdf[\"valid_after\"] = gdf.geometry.is_valid\n\n{\n    \"type\": \"FeatureCollection\",\n    \"features\": [\n        {\"type\": \"Feature\", \"properties\": {\"name\": row[\"name\"], \"valid_before\": bool(row[\"valid_before\"]), \"valid_after\": bool(row[\"valid_after\"])}, \"geometry\": mapping(row.geometry)}\n        for _, row in gdf.iterrows()\n    ]\n}",
    onRun: async (code, output) => {
      output.waiting("Running...");
      return output.result(await window.WebGeoDS.Python.run(code, {}));
    }
  });
});
</script>
</div>
<div id="tabset-2-2" class="tab-pane" aria-labelledby="tabset-2-2-tab">
<div id="geometry-repair-r"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
  new window.WebGeoDS.CodeCell("geometry-repair-r", {
    language: "r",
    initialCode: "data$valid_before <- data$valid\n\nsf::sf_use_s2(FALSE)\ndata <- sf::st_make_valid(data)\nsf::sf_use_s2(TRUE)\n\ndata$valid_after <- sf::st_is_valid(data)\n\njsonlite::fromJSON(geojsonsf::sf_geojson(data), simplifyVector = FALSE)",
    onRun: async (code, output) => {
      output.waiting("Running...");
      return output.result(await window.WebGeoDS.R.run(code, {}));
    }
  });
});
</script>
</div>
</div>
</div>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb25" data-startfrom="651" data-source-offset="-238" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 650;"><span id="cb25-651">pyRepair <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCellValue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-repair-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Generators)</span>
<span id="cb25-652">{</span>
<span id="cb25-653">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (pyRepair) {</span>
<span id="cb25-654">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGeoJSON</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-py"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> pyRepair)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb25-655">  }</span>
<span id="cb25-656">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-23-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-23-2" data-nodetype="expression">

</div>
</div>
</div>
</div>
<div class="cell hidden">
<div class="sourceCode cell-code hidden" id="cb26" data-startfrom="662" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 661;"><span id="cb26-662">rRepair <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> WebGeoDS<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCellValue</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-repair-r"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Generators)</span>
<span id="cb26-663">{</span>
<span id="cb26-664">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (rRepair) {</span>
<span id="cb26-665">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> sharedMap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setGeoJSON</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"geometry-r"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> rRepair)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb26-666">  }</span>
<span id="cb26-667">}</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-24-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-24-2" data-nodetype="expression">

</div>
</div>
</div>
</div>
<p>The table and the report above update themselves — the <code>valid_before</code>/<code>valid_after</code> columns automatically appear next to the diagnosis ones.</p>
</section>
<section id="what-about-relationships-between-geometries" class="level2">
<h2 class="anchored" data-anchor-id="what-about-relationships-between-geometries">What about relationships between geometries?</h2>
<p>A geometry can be perfectly valid on its own and still be wrong in relation to other geometries — two valid polygons overlapping when they shouldn’t, a gap between areas that should touch. That’s a different problem: topology. It’s covered in <a href="../posts/topology-errors.html">Topology Errors in a GeoJSON</a>.</p>
<script async="" data-uid="31051e3ca1" src="https://webgeods.kit.com/31051e3ca1/index.js"></script>


<div class="ojs-auto-generated hidden">
<script type="ojs-module-contents">
eyJjb250ZW50cyI6WyAgeyJtZXRob2ROYW1lIjoiaW50ZXJwcmV0IiwiaW5saW5lIjoidHJ1ZSIsInNvdXJjZSI6Imh0bC5odG1sYDxzcGFuPiR7dXBsb2FkU3RhdHVzfTwvc3Bhbj5gIiwgImNlbGxOYW1lIjoib2pzLWVsZW1lbnQtaWQtMSJ9LCAgeyJtZXRob2ROYW1lIjoiaW50ZXJwcmV0IiwiaW5saW5lIjoidHJ1ZSIsInNvdXJjZSI6Imh0bC5odG1sYDxzcGFuPiR7dmFsaWRhdGlvblN0YXRzLnRvdGFsfTwvc3Bhbj5gIiwgImNlbGxOYW1lIjoib2pzLWVsZW1lbnQtaWQtMiJ9LCAgeyJtZXRob2ROYW1lIjoiaW50ZXJwcmV0IiwiaW5saW5lIjoidHJ1ZSIsInNvdXJjZSI6Imh0bC5odG1sYDxzcGFuPiR7dmFsaWRhdGlvblN0YXRzLnZhbGlkfTwvc3Bhbj5gIiwgImNlbGxOYW1lIjoib2pzLWVsZW1lbnQtaWQtMyJ9LCAgeyJtZXRob2ROYW1lIjoiaW50ZXJwcmV0IiwiaW5saW5lIjoidHJ1ZSIsInNvdXJjZSI6Imh0bC5odG1sYDxzcGFuPiR7dmFsaWRhdGlvblN0YXRzLmludmFsaWR9PC9zcGFuPmAiLCAiY2VsbE5hbWUiOiJvanMtZWxlbWVudC1pZC00In1dfQ==
</script>
</div>
</section>

 ]]></description>
  <category>tool</category>
  <category>geometry</category>
  <category>bilingual</category>
  <guid>https://webgeods.com/posts/geometry-validity.html</guid>
  <pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
