Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <title>UK Farm Embeddings (synthetic sample)</title> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" /> | |
| <style> | |
| html, body, #map { height: 100%; margin: 0; } | |
| .banner { | |
| position:absolute; top:10px; left:10px; z-index:1000; | |
| background:#ffffff; padding:10px 12px; border:1px solid #bbb; border-radius:8px; | |
| font:14px/1.3 system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; | |
| box-shadow:0 2px 8px rgba(0,0,0,0.08); | |
| max-width: 400px; | |
| } | |
| .legend { | |
| position:absolute; bottom:12px; left:10px; z-index:1000; | |
| background:#ffffff; padding:8px 10px; border:1px solid #bbb; border-radius:6px; | |
| font:12px/1.2 system-ui, sans-serif; box-shadow:0 2px 8px rgba(0,0,0,0.08); | |
| } | |
| a { color:#0b69ff; text-decoration:none; } | |
| a:hover { text-decoration:underline; } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="map"></div> | |
| <!-- Info banner --> | |
| <div class="banner"> | |
| <div><b>UK Farm Embeddings</b></div> | |
| <div style="margin-top:6px;"> | |
| This demo shows <i>synthetic</i> parcel points, colored by | |
| <b>confidence</b> of attribution to the displayed <code>farm_id</code>. | |
| Explore the dataset: | |
| <a href="https://huggingface.co/datasets/EmbeddingsOG/uk-farm-assets-embeddings-v1" target="_blank" rel="noopener"> | |
| EmbeddingsOG/uk-farm-assets-embeddings-v1 | |
| </a>. | |
| </div> | |
| </div> | |
| <!-- Legend --> | |
| <div class="legend" id="legend"> | |
| <b>Color: confidence</b><br/> | |
| <span id="legendMin">low</span> | |
| <span style="display:inline-block;width:140px;height:10px;background:linear-gradient(90deg,#2f4b7c,#ff7c43,#d45087);margin:0 6px;"></span> | |
| <span id="legendMax">high</span> | |
| </div> | |
| <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> | |
| <script> | |
| // ---- Satellite basemap only ---- | |
| const satellite = L.tileLayer( | |
| 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', | |
| { maxZoom: 19, attribution: 'Tiles © Esri — Sources: Esri, Garmin, NOAA NGDC, GEBCO, and others' } | |
| ); | |
| const map = L.map('map', { | |
| center: [54.5, -3.2], zoom: 6, layers: [satellite] | |
| }); | |
| // ---- Utility: color scale for confidence ---- | |
| function lerp(a,b,t){ return a.map((ai,i)=>Math.round(ai + (b[i]-ai)*t)); } | |
| function makeScale(values) { | |
| const v = values.filter(x => Number.isFinite(x)).sort((a,b)=>a-b); | |
| const p = (q) => v[Math.floor((q/100) * (v.length - 1))]; | |
| const vmin = v.length ? p(5) : 0.5, vmax = v.length ? p(95) : 0.99; | |
| function grad(x){ | |
| if (!Number.isFinite(x)) return "#aaaaaa"; | |
| let t = (x - vmin) / (vmax - vmin + 1e-9); | |
| t = Math.max(0, Math.min(1, t)); | |
| const c = (t < 0.5) | |
| ? lerp([0x2f,0x4b,0x7c],[0xff,0x7c,0x43], t/0.5) // blue→orange | |
| : lerp([0xff,0x7c,0x43],[0xd4,0x50,0x87], (t-0.5)/0.5); // orange→red | |
| return "#" + c.map(n => n.toString(16).padStart(2,"0")).join(""); | |
| } | |
| return {vmin, vmax, fn: grad}; | |
| } | |
| // ---- Load GeoJSON and plot ---- | |
| fetch("data/parcels_sample.geojson") | |
| .then(r => r.json()) | |
| .then(data => { | |
| const confs = data.features.map(f => (f.properties||{}).confidence ?? NaN); | |
| const scale = makeScale(confs); | |
| const layer = L.geoJSON(data, { | |
| pointToLayer: (feat, latlng) => { | |
| const c = (feat.properties||{}).confidence; | |
| const color = scale.fn(c); | |
| return L.circleMarker(latlng, { radius:6, weight:2, color, fillColor:color, fillOpacity:0.85 }); | |
| }, | |
| onEachFeature: (feat, lyr) => { | |
| const p = feat.properties || {}; | |
| lyr.bindPopup( | |
| `<b>${p.parcel_id||""}</b><br/>farm: ${p.farm_id||""}<br/>confidence: ${Number(p.confidence).toFixed(3)}` | |
| ); | |
| } | |
| }).addTo(map); | |
| try { | |
| const bounds = layer.getBounds(); | |
| if (bounds.isValid()) map.fitBounds(bounds, {padding:[20,20]}); | |
| } catch(e){ /* keep default view if no bounds */ } | |
| document.getElementById("legendMin").textContent = (scale.vmin ?? 0.5).toFixed(2); | |
| document.getElementById("legendMax").textContent = (scale.vmax ?? 0.99).toFixed(2); | |
| }) | |
| .catch(err => console.error("Failed to load GeoJSON:", err)); | |
| </script> | |
| </body> | |
| </html> | |