File size: 4,523 Bytes
6fd2dfb
20a2ed7
 
 
ee7b607
20a2ed7
 
 
 
 
 
 
540b625
20a2ed7
540b625
20a2ed7
 
 
 
540b625
20a2ed7
540b625
 
20a2ed7
 
 
 
 
540b625
20a2ed7
0e9e118
20a2ed7
 
 
540b625
 
 
 
20a2ed7
 
 
540b625
20a2ed7
 
 
 
 
 
 
 
 
540b625
 
 
 
 
20a2ed7
540b625
 
 
20a2ed7
540b625
 
20a2ed7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
540b625
 
 
 
 
 
20a2ed7
540b625
 
 
 
 
 
 
 
 
 
 
 
 
20a2ed7
540b625
 
 
 
20a2ed7
540b625
 
 
 
20a2ed7
 
6fd2dfb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<!doctype html>
<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>