Thursday, April 9, 2026

Comparison of AI Generated Cartographic Webmap

 In this post, I will provide a simple request in plain English to four AI tools (namely: Gemini, ChatGPT, DeepSeek and Grok) to compare the results we get.

Generate html webmap with all the necessary cartographic elements

Note that the request statement isn't detailed, as no specific location and technical functionality were provided. This is delibrate to see how each AI tool thinker and solve the problem.


Gemini


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Professional Web Map Interface</title>
    
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
    
    <style>
        body { margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
        #map { height: 100vh; width: 100vw; }

        /* Map Legend Styling */
        .legend {
            padding: 10px;
            background: white;
            line-height: 1.5;
            color: #333;
            border-radius: 5px;
            box-shadow: 0 0 15px rgba(0,0,0,0.2);
        }
        .legend i {
            width: 18px;
            height: 18px;
            float: left;
            margin-right: 8px;
            opacity: 0.7;
        }

        /* Header Overlay */
        .map-header {
            position: absolute;
            top: 10px;
            left: 50px;
            z-index: 1000;
            background: rgba(255, 255, 255, 0.9);
            padding: 5px 15px;
            border-radius: 4px;
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>

<div class="map-header">
    <h2>City Infrastructure Overview</h2>
</div>

<div id="map"></div>

<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>

<script>
    // 1. Initialize the Map
    const map = L.map('map').setView([45.523062, -122.676482], 13);

    // 2. Base Layers (Cartography Element: Reference Frame)
    const osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors'
    }).addTo(map);

    const satellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
        attribution: 'Tiles &copy; Esri'
    });

    // 3. Data Layers (Thematic Elements)
    const parks = L.layerGroup();
    L.marker([45.528, -122.662]).bindPopup("<b>Holladay Park</b><br>Public Green Space").addTo(parks);
    L.marker([45.515, -122.684]).bindPopup("<b>Portland Art Museum</b><br>Cultural Center").addTo(parks);

    // 4. Layer Control (Interactivity)
    const baseMaps = {
        "Street Map": osm,
        "Satellite": satellite
    };
    const overlayMaps = {
        "Points of Interest": parks
    };
    L.control.layers(baseMaps, overlayMaps, {collapsed: false}).addTo(map);

    // 5. Scale Bar (Cartography Element: Measurement)
    L.control.scale({ imperial: true, metric: true, position: 'bottomleft' }).addTo(map);

    // 6. Custom Legend (Cartography Element: Symbology)
    const legend = L.control({position: 'bottomright'});
    legend.onAdd = function (map) {
        const div = L.DomUtil.create('div', 'legend');
        div.innerHTML += '<h4>Map Legend</h4>';
        div.innerHTML += '<i style="background: #2196F3"></i><span>Commercial</span><br>';
        div.innerHTML += '<i style="background: #4CAF50"></i><span>Parks</span><br>';
        div.innerHTML += '<i style="background: #F44336"></i><span>Critical Infrastructure</span><br>';
        return div;
    };
    legend.addTo(map);

</script>
</body>
</html>



ChatGPT




<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Smart Campus Web Map</title>
  <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
  <style>
    html, body { margin: 0; padding: 0; height: 100%; font-family: Arial, sans-serif; }
    #map { width: 100%; height: 100vh; }
    .map-title {
      position: absolute;
      top: 10px;
      left: 50%;
      transform: translateX(-50%);
      z-index: 1000;
      background: white;
      padding: 10px 18px;
      border-radius: 10px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.2);
      font-weight: bold;
      font-size: 18px;
    }
    .north-arrow {
      position: absolute;
      top: 70px;
      right: 15px;
      z-index: 1000;
      background: white;
      padding: 8px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.2);
      text-align: center;
      font-weight: bold;
    }
    .legend {
      position: absolute;
      bottom: 30px;
      right: 15px;
      z-index: 1000;
      background: white;
      padding: 10px;
      border-radius: 10px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.2);
      line-height: 1.6;
      font-size: 14px;
    }
    .legend i {
      width: 14px;
      height: 14px;
      float: left;
      margin-right: 8px;
      opacity: 0.8;
    }
    .coords {
      position: absolute;
      bottom: 10px;
      left: 10px;
      z-index: 1000;
      background: rgba(255,255,255,0.9);
      padding: 6px 10px;
      border-radius: 6px;
      font-size: 12px;
      box-shadow: 0 2px 6px rgba(0,0,0,0.15);
    }
  </style>
</head>
<body>
  <div class="map-title">Smart Campus Web Map</div>
  <div class="north-arrow">N<br>⬆</div>
  <div id="map"></div>
  <div class="coords" id="coords">Lat: 0, Lng: 0</div>
  <div class="legend">
    <strong>Legend</strong><br>
    <i style="background:#1f78b4"></i> Academic Buildings<br>
    <i style="background:#33a02c"></i> Hostels<br>
    <i style="background:#e31a1c"></i> Health Facilities<br>
    <i style="background:#ff7f00"></i> Roads
  </div>

  <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
  <script>
    const map = L.map('map').setView([9.0579, 7.4951], 16);

    const osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '&copy; OpenStreetMap contributors'
    }).addTo(map);

    const satellite = L.tileLayer('https://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', {
      maxZoom: 20,
      subdomains:['mt0','mt1','mt2','mt3']
    });

    const academic = L.layerGroup([
      L.marker([9.0585, 7.4955]).bindPopup('Faculty of Science'),
      L.marker([9.0575, 7.4960]).bindPopup('Engineering Block')
    ]).addTo(map);

    const hostels = L.layerGroup([
      L.marker([9.0569, 7.4945]).bindPopup('Male Hostel'),
      L.marker([9.0564, 7.4964]).bindPopup('Female Hostel')
    ]).addTo(map);

    const health = L.layerGroup([
      L.marker([9.0580, 7.4940]).bindPopup('Campus Clinic')
    ]).addTo(map);

    const roads = L.polyline([
      [9.0560, 7.4940],
      [9.0588, 7.4965]
    ], {color: '#ff7f00'}).addTo(map);

    const baseMaps = {
      'OpenStreetMap': osm,
      'Satellite': satellite
    };

    const overlayMaps = {
      'Academic Buildings': academic,
      'Hostels': hostels,
      'Health Facilities': health,
      'Roads': roads
    };

    L.control.layers(baseMaps, overlayMaps).addTo(map);
    L.control.scale().addTo(map);

    map.on('mousemove', function(e) {
      document.getElementById('coords').innerHTML =
        `Lat: ${e.latlng.lat.toFixed(5)}, Lng: ${e.latlng.lng.toFixed(5)}`;
    });
  </script>
</body>
</html>



DeepSeek


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Professional PLSS Section Locator</title>
    
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
    
    <style>
        body { background-color: #f4f7f6; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
        #map { height: 600px; width: 100%; border-radius: 12px; box-shadow: 0 4px 15px rgba(0,0,0,0.2); border: 2px solid white; }
        .card { border: none; border-radius: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
        .form-label { font-weight: 600; font-size: 0.8rem; color: #555; text-transform: uppercase; }
        .btn-search { background-color: #2e7d32; color: white; border: none; }
        .btn-search:hover { background-color: #1b5e20; color: white; }
        .btn-clear { background-color: #78909c; color: white; }
        .copy-btn { padding: 2px 8px; font-size: 0.7rem; cursor: pointer; }
    </style>
</head>
<body>

<div class="container-fluid py-4">
    <div class="row">
        <div class="col-md-4 col-lg-3">
            <div class="card p-4 mb-3">
                <h5 class="text-success mb-3 border-bottom pb-2">PLSS Locator</h5>
                
                <form id="plssForm">
                    <div class="mb-3">
                        <label class="form-label">State</label>
                        <select id="state" class="form-select" onchange="updateMeridians()" required>
                            <option value="">Select State...</option>
                            <option value="AL">Alabama</option><option value="AK">Alaska</option>
                            <option value="AZ">Arizona</option><option value="AR">Arkansas</option>
                            <option value="CA">California</option><option value="CO">Colorado</option>
                            <option value="FL">Florida</option><option value="ID">Idaho</option>
                            <option value="IL">Illinois</option><option value="IN">Indiana</option>
                            <option value="IA">Iowa</option><option value="KS">Kansas</option>
                            <option value="LA">Louisiana</option><option value="MI">Michigan</option>
                            <option value="MN">Minnesota</option><option value="MS">Mississippi</option>
                            <option value="MO">Missouri</option><option value="MT">Montana</option>
                            <option value="NE">Nebraska</option><option value="NV">Nevada</option>
                            <option value="NM">New Mexico</option><option value="ND">North Dakota</option>
                            <option value="OH">Ohio</option><option value="OK">Oklahoma</option>
                            <option value="OR">Oregon</option><option value="SD">South Dakota</option>
                            <option value="UT">Utah</option><option value="WA">Washington</option>
                            <option value="WI">Wisconsin</option><option value="WY">Wyoming</option>
                        </select>
                    </div>

                    <div class="mb-3">
                        <label class="form-label">Principal Meridian</label>
                        <select id="meridian" class="form-select" required>
                            <option value="">Choose State First</option>
                        </select>
                    </div>

                    <div class="row g-2">
                        <div class="col-8 mb-3">
                            <label class="form-label">Township</label>
                            <input type="number" id="twp" class="form-control" placeholder="38" required>
                        </div>
                        <div class="col-4 mb-3">
                            <label class="form-label">Dir</label>
                            <select id="twpDir" class="form-select">
                                <option value="N">N</option><option value="S">S</option>
                            </select>
                        </div>
                    </div>

                    <div class="row g-2">
                        <div class="col-8 mb-3">
                            <label class="form-label">Range</label>
                            <input type="number" id="rng" class="form-control" placeholder="56" required>
                        </div>
                        <div class="col-4 mb-3">
                            <label class="form-label">Dir</label>
                            <select id="rngDir" class="form-select">
                                <option value="E">E</option><option value="W">W</option>
                            </select>
                        </div>
                    </div>

                    <div class="mb-4">
                        <label class="form-label">Section</label>
                        <input type="number" id="sec" class="form-control" placeholder="10" required>
                    </div>

                    <div class="d-grid gap-2">
                        <button type="submit" class="btn btn-search">Find on Map</button>
                        <button type="button" class="btn btn-clear" onclick="clearMap()">Clear Map</button>
                    </div>
                </form>
            </div>
            <div id="statusBox" class="alert d-none"></div>
        </div>

        <div class="col-md-8 col-lg-9">
            <div id="map"></div>
        </div>
    </div>
</div>

<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>

<script>
    // 1. Data Mapping for all 30 PLSS States
    const meridianData = {
        "AL": [{ code: "10", name: "Huntsville" }, { code: "31", name: "St. Stephens" }],
        "AK": [{ code: "11", name: "Copper River" }, { code: "12", name: "Fairbanks" }, { code: "13", name: "Seward" }, { code: "14", name: "Kateel River" }, { code: "15", name: "Umiat" }],
        "AZ": [{ code: "33", name: "Gila and Salt River" }],
        "AR": [{ code: "05", name: "5th Principal" }],
        "CA": [{ code: "21", name: "Mount Diablo" }, { code: "22", name: "Humboldt" }, { code: "23", name: "San Bernardino" }],
        "CO": [{ code: "06", name: "6th Principal" }, { code: "07", name: "New Mexico" }, { code: "08", name: "Ute" }],
        "FL": [{ code: "26", name: "Tallahassee" }],
        "ID": [{ code: "09", name: "Boise" }],
        "IL": [{ code: "02", name: "2nd Principal" }, { code: "03", name: "3rd Principal" }, { code: "04", name: "4th Principal" }],
        "IN": [{ code: "02", name: "2nd Principal" }],
        "IA": [{ code: "05", name: "5th Principal" }],
        "KS": [{ code: "06", name: "6th Principal" }],
        "LA": [{ code: "30", name: "Louisiana" }, { code: "31", name: "St. Helena" }],
        "MI": [{ code: "19", name: "Michigan" }],
        "MN": [{ code: "04", name: "4th Principal" }, { code: "05", name: "5th Principal" }],
        "MS": [{ code: "28", name: "Chickasaw" }, { code: "29", name: "Choctaw" }, { code: "31", name: "St. Stephens" }, { code: "32", name: "Washington" }],
        "MO": [{ code: "05", name: "5th Principal" }],
        "MT": [{ code: "20", name: "Montana" }],
        "NE": [{ code: "06", name: "6th Principal" }],
        "NV": [{ code: "21", name: "Mount Diablo" }],
        "NM": [{ code: "07", name: "New Mexico" }],
        "ND": [{ code: "05", name: "5th Principal" }],
        "OH": [{ code: "16", name: "1st Principal" }, { code: "17", name: "Ohio River" }, { code: "18", name: "Muskingum" }],
        "OK": [{ code: "24", name: "Indian" }, { code: "25", name: "Cimarron" }],
        "OR": [{ code: "34", name: "Willamette" }],
        "SD": [{ code: "05", name: "5th Principal" }, { code: "06", name: "6th Principal" }, { code: "27", name: "Black Hills" }],
        "UT": [{ code: "26", name: "Salt Lake" }, { code: "37", name: "Uintah" }],
        "WA": [{ code: "34", name: "Willamette" }],
        "WI": [{ code: "04", name: "4th Principal" }],
        "WY": [{ code: "06", name: "6th Principal" }, { code: "38", name: "Wind River" }]
    };

    // 2. Map Setup
    const map = L.map('map').setView([39.8283, -98.5795], 4);
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
    let activeMarker;

    // 3. Functions
    function updateMeridians() {
        const stateSelect = document.getElementById('state');
        const meridianSelect = document.getElementById('meridian');
        const selectedState = stateSelect.value;
        
        meridianSelect.innerHTML = '<option value="">Choose Meridian...</option>';
        
        if (meridianData[selectedState]) {
            meridianData[selectedState].forEach(m => {
                const opt = document.createElement('option');
                opt.value = m.code;
                opt.innerText = `${m.code} - ${m.name}`;
                meridianSelect.appendChild(opt);
            });
        }
    }

    function clearMap() {
        if (activeMarker) map.removeLayer(activeMarker);
        document.getElementById('plssForm').reset();
        document.getElementById('meridian').innerHTML = '<option value="">Choose State First</option>';
        document.getElementById('statusBox').classList.add('d-none');
        map.flyTo([39.8283, -98.5795], 4);
    }

    function copyToClipboard(text) {
        navigator.clipboard.writeText(text).then(() => {
            alert("Coordinates copied to clipboard!");
        });
    }

    // 4. Submission
    document.getElementById('plssForm').addEventListener('submit', async (e) => {
        e.preventDefault();
        const status = document.getElementById('statusBox');
        
        const state = document.getElementById('state').value;
        const meridian = document.getElementById('meridian').value;
        const twp = document.getElementById('twp').value;
        const twpDir = document.getElementById('twpDir').value;
        const rng = document.getElementById('rng').value;
        const rngDir = document.getElementById('rngDir').value;
        const sec = document.getElementById('sec').value;

        const legalDesc = `${state} ${meridian} T${twp}${twpDir} R${rng}${rngDir} SEC ${sec}`;
        const encodedDesc = encodeURIComponent(legalDesc).replace(/%20/g, '+');
        
        const url = `https://gis.blm.gov/arcgis/rest/services/Cadastral/BLM_Natl_PLSS_CadNSDI/MapServer/exts/CadastralSpecialServices/FindLD?legaldescription=${encodedDesc}&returnalllevels=false&f=pjson`;

        status.className = "alert alert-info mt-2 d-block";
        status.innerText = "Searching BLM Database...";

        try {
            const response = await fetch(url);
            const data = await response.json();

            if (data.features && data.features.length > 0) {
                const rings = data.features[0].geometry.rings[0];
                const lats = rings.map(p => p[1]);
                const lons = rings.map(p => p[0]);
                const lat = (Math.max(...lats) + Math.min(...lats)) / 2;
                const lon = (Math.max(...lons) + Math.min(...lons)) / 2;
                const coordString = `${lat.toFixed(6)}, ${lon.toFixed(6)}`;

                if (activeMarker) map.removeLayer(activeMarker);
                
                // Add Marker with Copy Button in Popup
                activeMarker = L.marker([lat, lon]).addTo(map)
                    .bindPopup(`
                        <strong>${legalDesc}</strong><br>
                        Coords: ${coordString}<br><br>
                        <button class="btn btn-sm btn-outline-primary" onclick="copyToClipboard('${coordString}')">Copy Coordinates</button>
                    `).openPopup();

                map.flyTo([lat, lon], 14);
                status.className = "alert alert-success mt-2";
                status.innerText = `Success: Found ${legalDesc}`;
            } else {
                status.className = "alert alert-warning mt-2";
                status.innerText = "No results. Check your Meridian or Section number.";
            }
        } catch (err) {
            status.className = "alert alert-danger mt-2";
            status.innerText = "Error connecting to service.";
        }
    });
</script>
</body>
</html>




Grok


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>World Cities Web Map - Complete Cartographic Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
    <style>
        body { margin: 0; padding: 0; font-family: Arial, sans-serif; }
        #map { height: 100vh; width: 100%; }
        .title {
            position: absolute; top: 10px; left: 50%; transform: translateX(-50%);
            background: rgba(255,255,255,0.9); padding: 8px 16px; border-radius: 4px;
            box-shadow: 0 2px 6px rgba(0,0,0,0.3); z-index: 1000; font-size: 1.4em; font-weight: bold;
            text-align: center;
        }
        .credits {
            position: absolute; bottom: 10px; left: 10px; background: rgba(255,255,255,0.8);
            padding: 5px 10px; border-radius: 4px; font-size: 0.8em; z-index: 1000;
        }
        .north-arrow {
            position: absolute; bottom: 80px; right: 20px; z-index: 1000;
            background: rgba(255,255,255,0.8); padding: 5px; border-radius: 4px;
            font-size: 1.2em; text-align: center; box-shadow: 0 2px 6px rgba(0,0,0,0.3);
        }
    </style>
</head>
<body>

<div id="map"></div>

<div class="title">World Major Cities Web Map<br><small>Interactive Example with Full Cartographic Elements</small></div>

<div class="north-arrow">↑<br><small>NORTH</small></div>

<div class="credits">
    Data: Sample cities | Basemap: © OpenStreetMap contributors<br>
    Created with Leaflet | Projection: Web Mercator (EPSG:3857)
</div>

<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet-control-scale@0.1.0/leaflet.control.scale.min.js"></script> <!-- Optional, but Leaflet has built-in now -->

<script>
// Initialize the map
var map = L.map('map', {
    center: [20, 0],  // Global view
    zoom: 2,
    zoomControl: true,
    attributionControl: true
});

// Add OpenStreetMap basemap (standard tile layer)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 19,
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

// Sample thematic data: Major cities with population-based sizing and categories
var cities = [
    {name: "Tokyo", lat: 35.6762, lng: 139.6503, pop: 37400000, category: "Asia"},
    {name: "Delhi", lat: 28.6139, lng: 77.2090, pop: 32000000, category: "Asia"},
    {name: "Shanghai", lat: 31.2304, lng: 121.4737, pop: 29000000, category: "Asia"},
    {name: "São Paulo", lat: -23.5505, lng: -46.6333, pop: 22000000, category: "Americas"},
    {name: "Mexico City", lat: 19.4326, lng: -99.1332, pop: 22000000, category: "Americas"},
    {name: "New York", lat: 40.7128, lng: -74.0060, pop: 20000000, category: "Americas"},
    {name: "Cairo", lat: 30.0444, lng: 31.2357, pop: 21000000, category: "Africa"},
    {name: "Mumbai", lat: 19.0760, lng: 72.8777, pop: 20000000, category: "Asia"}
];

// Color function by category
function getColor(category) {
    return category === "Asia" ? "#e41a1c" :
           category === "Americas" ? "#377eb8" : "#4daf4a";
}

// Add circle markers (thematic layer)
var cityLayer = L.layerGroup().addTo(map);
cities.forEach(function(city) {
    var radius = Math.sqrt(city.pop) / 300; // Scaled by population
    L.circleMarker([city.lat, city.lng], {
        radius: radius,
        fillColor: getColor(city.category),
        color: "#fff",
        weight: 2,
        opacity: 1,
        fillOpacity: 0.8
    }).bindPopup(`
        <b>${city.name}</b><br>
        Population: ~${city.pop.toLocaleString()}<br>
        Category: ${city.category}<br>
        Coordinates: ${city.lat.toFixed(2)}°N, ${city.lng.toFixed(2)}°E
    `).addTo(cityLayer);
});

// Add scale bar (built-in Leaflet control)
L.control.scale({
    position: 'bottomleft',
    maxWidth: 200,
    metric: true,
    imperial: true
}).addTo(map);

// Custom Legend control
var legend = L.control({position: 'bottomright'});
legend.onAdd = function(map) {
    var div = L.DomUtil.create('div', 'info legend');
    div.style.background = 'rgba(255,255,255,0.9)';
    div.style.padding = '10px';
    div.style.borderRadius = '4px';
    div.style.boxShadow = '0 2px 6px rgba(0,0,0,0.3)';
    div.innerHTML = `
        <b>City Categories</b><br>
        <i style="background:#e41a1c; width:12px; height:12px; display:inline-block;"></i> Asia<br>
        <i style="background:#377eb8; width:12px; height:12px; display:inline-block;"></i> Americas<br>
        <i style="background:#4daf4a; width:12px; height:12px; display:inline-block;"></i> Africa<br>
        <small>Circle size ≈ population</small>
    `;
    return div;
};
legend.addTo(map);

// Layer control (for toggling basemap or overlays if extended)
L.control.layers(null, {
    "Major Cities": cityLayer
}, {position: 'topright'}).addTo(map);

</script>
</body>
</html>




Saturday, February 7, 2026

Visualizing Common GIS Digitizing Errors

 To help visualize common GIS digitizing errors, I have created a comprehensive SVG graphic using Inkscape software. Each error is isolated and labeled to demonstrate the specific topological or geometric issue it represents.


The SVG file is here below, copy the SVG code into a text editor and save it with .svg extension.

<svg viewBox="0 0 800 600" xmlns="http://www.w3.org/2000/svg">
  <rect width="800" height="600" fill="#f8f9fa" />
  
  <style>
    .label { font-family: sans-serif; font-size: 12px; font-weight: bold; fill: #333; }
    .error-mark { fill: #e74c3c; stroke: #c0392b; stroke-width: 2; fill-opacity: 0.6; }
    .base-geo { fill: #3498db; stroke: #2980b9; stroke-width: 2; fill-opacity: 0.4; }
    .point { fill: #2c3e50; }
    .highlight { stroke: #e67e22; stroke-width: 3; stroke-dasharray: 4; }
  </style>

  <g transform="translate(50, 50)">
    <path d="M 0,0 L 100,0 L 0,80 L 100,80 Z" class="error-mark" />
    <text x="0" y="110" class="label">Self Intersection</text>
  </g>

  <g transform="translate(200, 50)">
    <path d="M 0,80 L 50,20 L 100,80" fill="none" stroke="#2980b9" stroke-width="2" />
    <circle cx="50" cy="20" r="4" class="point" />
    <circle cx="52" cy="22" r="4" fill="red" opacity="0.7" />
    <text x="0" y="110" class="label">Duplicate Nodes</text>
  </g>

  <g transform="translate(350, 50)">
    <path d="M 0,0 H 100 V 80 H 0 Z M 30,30 V 50 H 70 V 30 Z" class="base-geo" fill-rule="evenodd" />
    <text x="0" y="110" class="label">Hole (Undesired)</text>
  </g>

  <g transform="translate(500, 50)">
    <path d="M 0,80 L 45,80 L 48,78 L 100,80" fill="none" stroke="#2980b9" stroke-width="2" />
    <circle cx="46.5" cy="79" r="8" fill="none" stroke="red" />
    <text x="0" y="110" class="label">Short Segment</text>
  </g>

  <g transform="translate(650, 50)">
    <path d="M 0,80 L 100,75 L 0,70" fill="none" stroke="red" stroke-width="2" />
    <text x="0" y="110" class="label">Minimum Angle</text>
  </g>

  <g transform="translate(50, 200)">
    <rect x="40" y="40" width="10" height="10" class="error-mark" />
    <text x="0" y="110" class="label">Minimum Area</text>
  </g>

  <g transform="translate(200, 200)">
    <path d="M 0,40 Q 50,35 100,40 Q 50,42 0,40" class="error-mark" />
    <text x="0" y="110" class="label">Sliver Polygon</text>
  </g>

  <g transform="translate(350, 200)">
    <rect x="10" y="10" width="80" height="60" class="base-geo" />
    <rect x="15" y="15" width="80" height="60" class="error-mark" opacity="0.4" />
    <text x="0" y="110" class="label">Duplicate Features</text>
  </g>

  <g transform="translate(500, 200)">
    <rect x="0" y="0" width="100" height="80" class="base-geo" />
    <circle cx="50" cy="40" r="20" class="error-mark" />
    <text x="0" y="110" class="label">Feature in Feature</text>
  </g>

  <g transform="translate(200, 350)">
    <rect x="0" y="0" width="80" height="80" class="base-geo" />
    <rect x="60" y="20" width="80" height="80" fill="#e74c3c" fill-opacity="0.5" stroke="#c0392b" />
    <text x="30" y="120" class="label">Overlap</text>
  </g>

  <g transform="translate(450, 350)">
    <path d="M 0,0 L 70,0 L 65,80 L 0,80 Z" class="base-geo" />
    <path d="M 80,0 L 150,0 L 150,80 L 85,80 Z" class="base-geo" />
    <text x="45" y="120" class="label">Gap (Sliver)</text>
  </g>
</svg>


Self Intersection:- A polygon boundary crosses over itself. Breaks validity in OGC standards; creates "figure-eight" shapes.



Sliver Polygons:- Long, thin polygons often created by overlapping boundaries. Inflates feature count and messes up area calculations. This error come from very small polygon (with small area) with a large perimeter



Gaps & Overlaps:- Polygons that should be adjacent have space between them or sit on top of each other. Leads to "double counting" or "missing data" in spatial joins.



Minimum Angle:- Vertices are too close, creating a sharp "spike." Causes rendering artifacts and issues with offset/buffer tools.



Duplicate Nodes:- Multiple vertices at the same coordinates. Increases file size and slows down processing without adding detail.



Thank you for reading.

Monday, February 2, 2026

List of USGS EROS data portals

 The USGS Earth Resources Observation and Science (EROS) Center provides access to extensive satellite, aerial, and land surface data through several key portals. The primary platforms for searching and downloading imagery are EarthExplorer and GloVis. 

As of the year 2026, the USGS Earth Resources Observation and Science (EROS) Center continues to provide specialized portals for accessing satellite imagery and geospatial datasets. Accessing most of these services requires an account via the EROS Registration System (ERS).


Portal website links are provided below;-

1) EarthExplorer (EE) - https://earthexplorer.usgs.gov/
2) Global Visualization Viewer (GloVis) - https://glovis.usgs.gov/
3) LP DAAC (Land Data) - https://lpdaac.usgs.gov/
4) EROS Science Processing (ESPA) - https://espa.cr.usgs.gov/
5) Commercial Cloud Data (AWS) - https://registry.opendata.aws/
6) Machine-to-Machine (M2M) API - https://m2m.cr.usgs.gov/
7) Bulk Download Application (BDWA) - https://ebulk.cr.usgs.gov/
8) HDDS Explorer (Hazards/Disasters) - https://hdds.usgs.gov/
9) EarthNow! Landsat Viewer - https://earthnow.usgs.gov/
10) LANDFIRE Map Viewer - https://www.landfire.gov/viewer/
11) Multi-Resolution Land Characteristics (NLCD) - https://www.mrlc.gov/viewer/
12) Coastal Elevation Database (CoNED) - https://www.topotools.cr.usgs.gov
13) Monitoring Trends in Burn Severity (MTBS) - https://www.mtbs.gov/
14) AppEEARS (Data Subsetting) - https://appeears.earthdatacloud.nasa.gov/
15) IntELiMon Viewer (Interagency Ecosystem LiDAR Monitoring) - https://dmsdata.cr.usgs.gov/lidar-monitoring/viewer/
16) LRESA (Landsat Reprocessing Events Search Application) - https://lresa.cr.usgs.gov/
17) Spectral Characteristics Viewer - https://landsat.usgs.gov/spectral-characteristics-viewer
18) Fire Danger Viewer - https://fire-danger-viewer.cr.usgs.gov/
19) EROS Registration System (ERS) - https://ers.cr.usgs.gov/


That is it!

Tuesday, January 27, 2026

Bluepark upload custom HTML/CSS/JS webpage

 Bluepark is a powerful UK based ecommerce platform. Bluepark is a powerful ecommerce software, hosted on fast and reliable UK servers, provides scalable shopping cart solutions for small to large businesses. I helps you create your own online shop and sell online with the UK's leading all-in-one ecommerce platform, backed by our 5-star-rated Support Team.

In Bluepark, you do not "upload" a standalone HTML file in the traditional sense of FTP; instead, you add or edit HTML code through the admin panel to customize existing themes or content blocks.

If your HTML refers to external assets like custom scripts or specialized images:

  • Use the File Manager by navigating to Admin > Files.
  • Upload your assets here to host them on Bluepark's servers.
  • Note that for interactive elements, Bluepark variables and classes are often required to ensure functionality within their CMS environment. 


That is it!

Wednesday, January 14, 2026

How to Trust a JupyterLab Notebook

 If you have ever encountered the "JupyterLab is not trusted" message, that is a security warning feature designed to prevent malicious code like JavaScript or HTML in a notebook cell from automatically executing.



However, in some cases it is not a malicious code but JupyterLab erroniously classified it as one. In this post, I will guide you on how to fix it. That is how to trust the code in the JupyterLab Notebook.

You can mark a notebook as trusted using the GUI (the browser user interface) or the command line. I will focus on using the user interface for this guide.

Using the user interface (JupyterLab) to Trust a Notebook

Step 1: Open the notebook in JupyterLab

Step 2: Open the Command Palette by going to View >> Activate Command Palette



Step 3: Type 'trust' and select the "Trust Notebook" command as seen below.


That is it. Now re-start the JupyterLab server and re-run all the code cells.

Thank you for following.

Wednesday, December 17, 2025

Delete a table or layer from GeoPackage within QGIS

 To delete a table (layer) from a GeoPackage within QGIS, you can use either the Browser panel or the DB Manager.


Method 1: Using the Browser Panel

  1. This is the simplest and most direct way to delete a single table.
  2. Open the Browser panel: If it's not already visible, go to the top menu and select View > Panels > Browser Panel.
  3. Navigate to the GeoPackage: In the Browser panel tree, find the GeoPackage file (.gpkg) you are working with.
  4. Expand the GeoPackage: Click the arrow next to the GeoPackage name to view all the layers (tables) it contains.
  5. Delete the layer: Right-click on the specific layer/table you want to remove and select Delete Layer.
  6. Confirm the deletion: A confirmation window will appear; confirm that you want to delete the layer. 


Method 2: Using the DB Manager

The DB Manager provides a more database-oriented interface and is useful for managing multiple tables or running SQL commands. 

  1. Open the DB Manager: Go to the top menu and select Database > DB Manager.
  2. Connect to the GeoPackage: In the left-hand tree, expand GeoPackage. Right-click on GeoPackage and select New Connection, then browse to your .gpkg file.
  3. Find the table: Expand the connection to your GeoPackage and locate the desired table under Tables or Spatial tables.
  4. Delete the table: Right-click on the table name and select Delete.

That is it!

Saturday, December 6, 2025

CASE expression in QGIS

Understanding QGIS Expressions

A QGIS Expression is a combination of one or more values, operators, and functions that is evaluated dynamically within the context of a QGIS project.

The syntax for the QGIS Expression language is derived from Structured Query Language (SQL).

QGIS Expressions are utilized extensively throughout the QGIS environment, making familiarity with them essential for a wide range of geospatial tasks. Their applications include, but are not limited to:-

  1. Mapping and Symbology: Manipulating symbology and labels to create sophisticated, data-driven visual representations.
  2. Data Analysis and Management: Selecting features based on specific criteria, and generating new columns or updating existing ones in the attribute table.
  3. Feature Management: Creating new geometries using the Geometry Generator tool or calculating spatial attributes.
  4. Data Exploration: Filtering and querying data for rapid exploration and analysis.


The Syntax

  • (1) 'name' means a string text name
  • (2) "name" means a attribute column called name for the curent feature
  • (3) @name means a variable value called name. This used to be $name in older version of QGIS.
  • (4) name() means a function called name





The CASE expression in QGIS provides conditional logic, allowing the assignment of different values or the execution of different actions based on whether specified conditions are met. This is particularly useful in the Field Calculator, for data-defined properties, or within expressions used for labeling and symbology.


CASE

WHEN "NAME" IN ('New Caledonia', 'Jamaica', 'Bolivia', 'Suriname', 'Dem. Rep. Congo', 'Iraq') THEN "WB_A3" 

END















Wednesday, November 26, 2025

How to Open QGIS Attribute Table as a docked window

 If you don't want your layers attribute table been displayed as a regular window that is movable on screen, then you ca make it docked/fixed by following this guide.

When you open an attribute table of any vector layer by default, it will appear to cover the map canvas justr like the image below.

Even if you tried to move the attribute table window, it won't be of much help in having it docked like in the image below. 


To achieve this docked window, you need to make use of the 'Settings Menu' as follow;-

Settings ► Options ► Data sources ► Feature Attributes and Table. Then check the box for 'Open attribute table in a docked window'


You can also make the column size fit to content by checking the 'Autosize all columns by default when opening attribute table' check-box.


That is it!

Thursday, November 20, 2025

Mapping Inter-confederation, European playoffs fixtures for the 2026 World Cup

 As of November 20, 2025, 42 spots for the 48-team 2026 FIFA World Cup have been secured through direct qualification. The remaining six spots will be decided through two separate playoff tournaments in March 2026. 

In this post, I will create a map showing the teams that will participate in the playoff tournaments.

Teams for Inter-confederation playoff: New Caledonia, Jamaica, Bolivia, Suriname, DR Congo, and Iraq



Teams for European playoff: Italy, Northern Ireland, Wales, Bosnia-Herzegovina, Ukraine, Sweden, Poland, Albania, Turkey, Romania, Slovakia, Kosovo, Denmark, North Macedonia, Czech Republic and Republic of Ireland




Goodluck to the playoff teams

Monday, November 10, 2025

Reproducing the "Map of Nigerian Languages"

 I needed a softcopy of the 'Map of Nigerian Languages' by the National Library of Nigeria. Unfortunately, all the softcopies I found where not useful to me because the image resolution was poor (see images below). So I decided to re-produce one from scratch.

Radio Nigeria has a copy of the map here but it is of low resultion for my use. Although it served as a reference for the new map i intend to reproduce. I also referenced this video on National Library of Nigeria facebook page.

For the list of languages, I utilized this source from National Institute for Cultural Orientation (NICO) to prepare the list below in JSON format:-

'[{"STATES":"ABIA","LANGUAGES":"Igbo"},{"STATES":"ADAMAWA","LANGUAGES":"Bachama, Bali, Bare, Batta, Bena, Bille, Boga, Baba, Bura, Chamba, Chobbo, Dangsa, Dadiya, Dera, Dijim-Bwilim, Dirim, Dibanci, Dong, Doso, Fali, Fulfude, Gaa, Ga’anda, Gbaya-Northeast, Gola, Gengle, Gira, Gongla, Gorobi, Gude, Gudu, Gwaba, Hide, Higgi, Holma, Hona, Huba, Hwana, Hya, Jenjo, Kaan, Kanakuru, Kamwe, Kofa, Koma, Korna, Kpasam, Kugama, Jango, Jkumba, Kilba, Kwa, Kwak, Koma, Laka, Lala, Lak-Roba, Lamang, Libbo, Lunguda, Loo, Matakam, Mobas, Mafa, Marghi South, Mboi, Mbongno, Mbula-Bwazza, Mingang Mumuye, Muchala, Mwana,Ngoshe, Ngwaba, Njayi, Njerep, Nona, Nyong, Nzanyi, Psikye, Samba Leko, Sate, Sukur, Tambo,Tangale, Teme, The, Tso, Vemgo, Verre, Volma, Voro, Waja, Wom, Wula, Yandang, Yundur, Zizilivakan"},{"STATES":"AKWA IBOM","LANGUAGES":"Anang, Efai, Eki, Ekit, Etebi, Ibibio, Ibino, Ibuoro, Idere, Iko, Ilue, Itu Mbon Uzo, Okobo, Uda"},{"STATES":"ANAMBRA","LANGUAGES":"Igbo, Igala"},{"STATES":"BAUCHI STATE","LANGUAGES":"Ajawa, Beele, Bure, Ciwogai, Dass, Daza, Deno, Diri, Duguri, Galambu, Gamo-Ningi, Fulfude, Geji, Gera, Giiwo, Gwa, Gyem, Izere, Jimi, Ju, Karekare, Kariya Kir-Balar, Kubi Kudu, Kudu Camo, Kutto, Kwaami, Labir, Lame Lenoro, Lere, Luri, Mangas, Mburku, Miya Pa’a,-Kwonci, Sanga, Saya, Shau, Shiki, Shuva-Siri, Sur, Tala Tunzuii, Vaghat-Ya-Bijin-Legeri, Warji, Zangwal, Zari, Zeem, Ziriya"},{"STATES":"BAYELSA","LANGUAGES":"Abureni, Epie, Do Southeast, Kirike, Odual, Ogbia, Okochia, Kugbo, Izon"},{"STATES":"BENUE","LANGUAGES":"Agatu, Akpa, Basa, Edumoga, Eloyi, Etulo, Igede, Igbo, Idoma, Iyala, Kukele, Koring, Otank, Odual, Otukpo, Otukpa, Orokam, Peere, Samba-Daka, Tite, Tiv Wanna, Surubu, Utonkon"},{"STATES":"BORNO","LANGUAGES":"Afade, Arabic, Shuwa, Bure-Pabir, Ciback, Aghwede, Fullfude, Glauda, Guduf-Gara, Gvoko Hide, Jara, Jilbe, Kanuri, Lamang, Kurama, Mafa, Marghi South, Tadaga, Tera, Wandda, Yedina Cinen, Babur-Bura."},{"STATES":"CROSS RIVER","LANGUAGES":"Awgagwune, Alege, Bakpinka, Bekwarra, Betc-Bendi, Bokyi, Bumaji, Doko Uyanga, Ebughu, Efik, Efutop, Ejagham, Evant, Kevemaci, Ito, Kiong, Kohumono, Korop, Kukele, Lenyima, Leyigha, Lokaa Lubila, Mbembe, Nde-Nsele-Nta, Ndoe, Nkem-Nkum, Nkukoli, Nnam, Obanlinku, Obolo, Odut Olulomo, Ikom, Oring, Oro Otank, Putukwan, Tamajag, Ubaghara, Ubangi Ukpe-Bayobiri, Ukpet-Ehom, Umon, Usaghade, Uzekwe, Tacc, Yaka"},{"STATES":"DELTA","LANGUAGES":"Eruwa, Isekiri, Isoko Izon, Kalabari, Ogboronuagum, Okpe, Urhobo, Vubie, Ika, Ukwani-Aboh-Ndoni"},{"STATES":"EDO","LANGUAGES":"Edo, Emai-Luleha-Ora, Enwan, Esan, Ghotuo, Ibilo, Idesa, Igwe, Ihevbe, Ika, Ikpeshi, Ivebe-North-Okpela-Arhe, Ososo, Sasaru, Ukaan, Uneme, Uokha Yekhee"},{"STATES":"EKITI","LANGUAGES":"Yoruba"},{"STATES":"EBONYI","LANGUAGES":"Igbo"},{"STATES":"ENUGU STATE","LANGUAGES":"Igbo, Igala"},{"STATES":"GOMBE","LANGUAGES":"Awak, Bangunji, Bolewa, Boh, Burak, Cham, Dadiya, Deji Fulani, Gasi, Ggizim, Hausa, Hone, Jara, Jukun, Kamo, Kana-Kuru, Kanuri, Koma, Kare-Kare, Kushi, Lunguda, Marghi South, Ngamo Pero, Tangale, Tera, Tso, Tula, Tuk, Kamo, Waja, Wurkum"},{"STATES":"IMO","LANGUAGES":"Igbo"},{"STATES":"JIGAWA","LANGUAGES":"Auyokawa, Fulfude, Kanuri, Teshenawa, Kurama, Hausa"},{"STATES":"KADUNA","LANGUAGES":"Amo, Ashe, Atsam, Ayu, Begbere-Ejar, Bina, Cinder-Regi-Tiyal, Cori, Doka, Dungu, Dza, Gbagyi, Gbiri-Niragu, Fulfude, Hyam Idon,M Idun, Iku-Gora-An-Kwa, Izere, Jere, Jiu, Kadara, Kaningkom-Nindem, Kanufi, Kataf, Kinuku, Kono, Kuturmi, Mada, Mala, Ndun, Ningye, Ninzo, Nungu, Nyeng, Piti, Rogo, Ruma, Saya, Sha, Shamang, Tumi Zhire"},{"STATES":"KANO","LANGUAGES":"Fulfude, Gibannawa, Hausa, Kurama, Amo"},{"STATES":"KATSINA","LANGUAGES":"Fulfude, Hausa"},{"STATES":"KEBBI","LANGUAGES":"Acipa, Cinda-Regi, Fulfude, Tital, C’lela, Dendi, Hunsaare, Kyenga, Peshe, Tsikimba, Ut-Ma’in, Hausa,"},{"STATES":"KOGI","LANGUAGES":"Alere, Basa, Ebira, Eggan, Gwari, Igala, Kakanda, Koto, Kupa, Oko-Eni-Osayeri, Okun, Okpamheri, Saya, Ogori"},{"STATES":"KWARA","LANGUAGES":"Batonu, Bagobiri, Bokobaru, Fulfude, Hausa, Nupe, Yoruba"},{"STATES":"LAGOS","LANGUAGES":"Yoruba, Awori"},{"STATES":"NASARAWA","LANGUAGES":"Afo, Agatu, Agoi, Ake, Alago, Alumutesu, Arum, Ashe, Basa-Gumna, Buh, Duhwa, Eggo, Fulani, Gade, Gbagyi, Goemai, Gwandara, Ham, Hausa, Hasha, Jukun, Kantana, Kofyar, Koro, Kulere, Lijili, Migili, Mada, Mama, Ninzo-Nungu, Nyankpa, Saya, Yeskwa"},{"STATES":"NIGER","LANGUAGES":"Asu, Baangi, Basa-Gumna, Basa-Gurmana, Basa-Kon Tagora, Busa, Gishinginni, C’ida, Dendi, Dibo, Fungwa Gbari, Gurmana, Gwandara, Hungworo, Hun-Saare, Ija-Zuba, Kadara, Kakanda, Kakihum, Laru, Lopa, Nepe-Nope-Tako, Pongu, Rogo, Shama-Sambuga, Tsikimba, Tsishinginni, Tsuvadi"},{"STATES":"OGUN","LANGUAGES":"Gun, Yoruba, Egba, Ijebu, Owu, Awori, Yewa."},{"STATES":"ONDO","LANGUAGES":"Ahan, Akpes, Arigidi, Ayere, Ehuem, Iyayu, Uhami, Ukaan, Ukue, Yoruba, Okpamher"},{"STATES":"OSUN","LANGUAGES":"Yoruba"},{"STATES":"OYO","LANGUAGES":"Yoruba"},{"STATES":"PLATEAU","LANGUAGES":"Atsam, Bada, Berom, Boghom, Bo-Rukul, Cakfem-Mushere, Casacen, Centum, Che, Como Karim, Dibo, Duguri, Etem, Fulfude, Fyaam, Fyer, Ganang, Goemai, Horom, Iguta, Irigwe, Izora, Janji, Jorto, Koenoem, Kotyar, Kulere, Lemoro, Kurama, Miship, Montol, Mundet, Mwaghavul, Ngas, Numan, Panawa, Pe, Pyapun, Ron, Sambe, Saya, Shakara, Shalkl-Zwall, Sheni, Sur, Tal, Tanjijili, Tarok, Toro, Tunzuii, Tyap, Vaghotya-Bijim-Legeri, Wapan, Wapha, Yangkam, Yiwom, Yukumben, Zumb."},{"STATES":"RIVERS","LANGUAGES":"Baan, Biseni, Defaka, Degema, Ekpeye, Eleme, Engenni, Gokana, Ibani, Ikwere, Izon, Kalabari, Khana, Kugbo, Obulom, Olchichi, Ogbah, Ogbogolo, Okochia, Ukwani-Aboh-Ndoni."},{"STATES":"SOKOTO","LANGUAGES":"Fulfude, Hausa"},{"STATES":"TARABA","LANGUAGES":"Abon, Akum, Ambo, Anca, Batu, Bête, Bitare, Bukwen, Buru, Como Karim, Dadiya, Dong, Dzodinka, Esimbi, Ettywan, Feli Of Baissa, Fam, Fulfude, Fum, Jiba, Jibu, Jiru, Jukun-Takkum, Kam, Kapya, Kholok, Kpan, Kpati, Kulung, Kutep, Kpak, Lamja-Dengsa-Tola, Lamnso, Leeelau, Limbum, Lufu, Maghadi, Mak, Mambilla, Marghi Central, Marghi South, Mbembe, Tijan, Mingang Doso, Moo, Mvanip Ned-Gbite, Ndoola, Ndunda, Nshi, Nyam, Rangishoo-Mindanye, Somyev, Viti, Waka, Wapan, Yamba."},{"STATES":"YOBE","LANGUAGES":"Fulfude, Kanuri, Bade, Hausa, Ngamo, Shuwa Kanuri, Manga, Karekare, Marghi Central, Marghi South."},{"STATES":"ZAMFARA","LANGUAGES":"Fulfude, Hausa"},{"STATES":"FCT","LANGUAGES":"Bassa, Gbagyi, Hausa, Gwandara, Gade"}]'
The following states have more than ten (10) major and minor spoken indigenous languages: ADAMAWA, PLATEAU, TARABA, BAUCHI, CROSS RIVER, KADUNA, NASARAWA, GOMBE, NIGER, BENUE, BORNO, RIVERS, EDO, AKWA IBOM, KOGI, KEBBI, ONDO, DELTA, and YOBE. The table below shows the total number languages for each state. 


To prepare the map, I made use of Inkscape vector graphics software since the map is not a GIS specific task without scientific cartography elements such as scale, north arrow, grid, projection etc.
"Scientific maps adhere strictly to the principles of cartography and geospatial information science (GIS). On the other hand, Non-scientific maps often sacrifice technical accuracy for ease of use, aesthetic appeal, or conceptual clarity".

The map is more of a conceptual communication map not a measured scientific map that requires the use of GIS tool.