<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Medical Consortium Documentation Blog</title>
        <link>https://MEDICONSORTIUM.github.io/Med_documentation/blog</link>
        <description>Medical Consortium Documentation Blog</description>
        <lastBuildDate>Wed, 01 Apr 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Milestone 2: Building the EOHA Prototype]]></title>
            <link>https://MEDICONSORTIUM.github.io/Med_documentation/blog/milestone-2-prototype-kickoff</link>
            <guid>https://MEDICONSORTIUM.github.io/Med_documentation/blog/milestone-2-prototype-kickoff</guid>
            <pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Milestone 1 laid the architectural foundation — every service zone mapped, every data store specified, every use case documented. Now we build.]]></description>
            <content:encoded><![CDATA[<p>Milestone 1 laid the architectural foundation — every service zone mapped, every data store specified, every use case documented. Now we build.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="what-milestone-2-means">What Milestone 2 means<a href="https://mediconsortium.github.io/Med_documentation/blog/milestone-2-prototype-kickoff#what-milestone-2-means" class="hash-link" aria-label="Direct link to What Milestone 2 means" title="Direct link to What Milestone 2 means" translate="no">​</a></h2>
<p>The prototype phase (March–August 2026) is where the EOHA platform transitions from a design artefact into a running system. The core deliverables are:</p>
<ul>
<li class=""><strong>Automated GEE pipeline</strong> — a Python-triggered Cloud Function that pulls Sentinel-2 and MODIS imagery on an 8-day cycle, runs zonal statistics against ward boundaries, and writes directly to the Ward Risk store without manual intervention.</li>
<li class=""><strong>Server-side risk scoring</strong> — <code>calculateDynamicRisk()</code> moves from the browser to a Cloud Run service, enabling real-time scoring for all 9 Limpopo municipalities and laying the groundwork for multi-country expansion.</li>
<li class=""><strong>XGBoost ML forecasting</strong> — the first live run of the Malaria Risk Forecast pipeline against the baseline dataset, producing <code>outbreak_probability_score</code> values per zone per prediction period.</li>
<li class=""><strong>NCD live data</strong> — replacing the static NCD baseline with live GEE-computed scores using Copernicus/Sentinel atmospheric data (NO2, SO2, aerosol index, UV radiation).</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="design-artefacts-carried-into-m2">Design artefacts carried into M2<a href="https://mediconsortium.github.io/Med_documentation/blog/milestone-2-prototype-kickoff#design-artefacts-carried-into-m2" class="hash-link" aria-label="Direct link to Design artefacts carried into M2" title="Direct link to Design artefacts carried into M2" translate="no">​</a></h2>
<p>The Design Specification Document (v2) produced in M1 defines the full entity model the prototype must implement:</p>
<table><thead><tr><th>Entity</th><th>Key fields</th><th>M2 target</th></tr></thead><tbody><tr><td><code>Zone</code></td><td><code>zone_id</code>, <code>boundary_polygon</code>, <code>base_population</code></td><td>GeoJSON sync automated</td></tr><tr><td><code>Malaria_Observation</code></td><td><code>lst_surface_temp_c</code>, <code>soil_moisture_pct</code>, <code>ndwi_water_index</code></td><td>GEE pipeline live</td></tr><tr><td><code>Malaria_Risk_Forecast</code></td><td><code>outbreak_probability_score</code>, <code>environmental_lag_days</code></td><td>XGBoost v1 deployed</td></tr><tr><td><code>NCD_Observation</code></td><td><code>no2_density</code>, <code>so2_density</code>, <code>aerosol_index</code></td><td>Copernicus pipeline live</td></tr><tr><td><code>User_Risk_Alert</code></td><td><code>alert_status</code>, <code>forecast_id</code></td><td>Alert engine wired to forecasts</td></tr></tbody></table>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="whats-shipping-first">What's shipping first<a href="https://mediconsortium.github.io/Med_documentation/blog/milestone-2-prototype-kickoff#whats-shipping-first" class="hash-link" aria-label="Direct link to What's shipping first" title="Direct link to What's shipping first" translate="no">​</a></h2>
<p>Our first sprint targets the Malaria pipeline end-to-end: GEE ingest → zonal statistics → XGBoost score → alert threshold check → <code>USER_RISK_ALERT</code> insert. Once that loop is closed on Limpopo data, we extend to NCD and begin multi-country boundary ingestion.</p>
<p>Follow progress on the <a class="" href="https://mediconsortium.github.io/Med_documentation/docs/milestones/overview">Milestones page</a> and in the <a href="https://main.d1jko0jkg4m7f.amplifyapp.com/" target="_blank" rel="noopener noreferrer" class="">live platform</a>.</p>]]></content:encoded>
            <category>Milestone</category>
            <category>Prototype</category>
            <category>GEE</category>
            <category>Machine Learning</category>
            <category>EOHA</category>
        </item>
        <item>
            <title><![CDATA[Mapping NCD risk across Southern Africa with satellite data]]></title>
            <link>https://MEDICONSORTIUM.github.io/Med_documentation/blog/ncd-module-southern-africa</link>
            <guid>https://MEDICONSORTIUM.github.io/Med_documentation/blog/ncd-module-southern-africa</guid>
            <pubDate>Thu, 15 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Non-communicable diseases kill more people in Southern Africa than any infectious disease. Here's how we're using EO data to map the environmental risk factors that drive them.]]></description>
            <content:encoded><![CDATA[<p>Non-communicable diseases kill more people in Southern Africa than any infectious disease. Here's how we're using EO data to map the environmental risk factors that drive them.</p>
<p>Malaria gets the satellite imagery attention. But cardiovascular disease, diabetes, and chronic respiratory conditions kill far more people annually across Southern Africa — and their environmental drivers (air quality, heat stress, urban sprawl, lack of green space) are all measurable from orbit.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="what-were-tracking">What we're tracking<a href="https://mediconsortium.github.io/Med_documentation/blog/ncd-module-southern-africa#what-were-tracking" class="hash-link" aria-label="Direct link to What we're tracking" title="Direct link to What we're tracking" translate="no">​</a></h2>
<p>The NCD risk module currently maps four countries: South Africa, Botswana, Zimbabwe, and Lesotho. The variables we pull from GEE are:</p>
<p><strong>Air quality</strong> — We use Sentinel-5P TROPOMI's tropospheric NO₂ column as a proxy for ambient air pollution. In the Gauteng region and Bulawayo corridor, concentrations are consistently elevated compared to rural areas.</p>
<p><strong>Urban heat stress</strong> — Land surface temperature deviation from the seasonal baseline. Cities absorb and retain heat; high chronic heat exposure correlates with hypertensive and cardiovascular outcomes.</p>
<p><strong>Green space access</strong> — Sentinel-2 NDVI as a proxy for access to parks and vegetated areas. Low NDVI in high-density urban areas signals limited green space — a risk factor for sedentary lifestyle and mental health outcomes.</p>
<p><strong>Built-up density</strong> — ESA WorldCover Class 50 (built-up) as a proportion of the ward area. This directly maps urban sprawl and the shift toward car-dependent, sedentary lifestyles.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-challenge-scale">The challenge: scale<a href="https://mediconsortium.github.io/Med_documentation/blog/ncd-module-southern-africa#the-challenge-scale" class="hash-link" aria-label="Direct link to The challenge: scale" title="Direct link to The challenge: scale" translate="no">​</a></h2>
<p>Malaria risk is meaningful at ward level. For NCDs, the relevant unit of analysis shifts depending on what you're measuring. Air quality needs a city-region level because pollution disperses. Healthcare access is highly local — a single clinic can serve a community of 10,000 within 5 km but nothing beyond. Obesity prevalence comes from surveys, not satellites.</p>
<p>Our current prototype solves this by working at the country → province → municipality hierarchy, with the understanding that finer-grained NCD data will be layered in as Milestone 2 progresses.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="what-the-prototype-shows">What the prototype shows<a href="https://mediconsortium.github.io/Med_documentation/blog/ncd-module-southern-africa#what-the-prototype-shows" class="hash-link" aria-label="Direct link to What the prototype shows" title="Direct link to What the prototype shows" translate="no">​</a></h2>
<p>The four-country choropleth already reveals some expected patterns. Zimbabwe's composite NCD risk score (63%) is driven largely by air quality issues in Harare and Bulawayo combined with limited formal healthcare infrastructure. South Africa's 58% reflects high urban density and lifestyle risk in metros offset by relatively stronger healthcare access. Lesotho and Botswana both sit in the moderate range.</p>
<p>These are rough starting values for the prototype. They'll be replaced by computed, ward-level scores in Milestone 2.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-interactive-map">The interactive map<a href="https://mediconsortium.github.io/Med_documentation/blog/ncd-module-southern-africa#the-interactive-map" class="hash-link" aria-label="Direct link to The interactive map" title="Direct link to The interactive map" translate="no">​</a></h2>
<p>The NCD dashboard lets you click into South Africa, select a province, and zoom to municipality level. The current data shown in the environmental panel (population density, AQI, healthcare access, obesity prevalence) is illustrative — static values while we wait for the full GEE extraction pipeline to be wired up.</p>
<p>But the infrastructure is working: the GADM ADM1 and ADM3 GeoJSON files are loading, the Leaflet layers are toggling correctly, and the dropdown sync is functioning.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="whats-coming-in-milestone-2">What's coming in Milestone 2<a href="https://mediconsortium.github.io/Med_documentation/blog/ncd-module-southern-africa#whats-coming-in-milestone-2" class="hash-link" aria-label="Direct link to What's coming in Milestone 2" title="Direct link to What's coming in Milestone 2" translate="no">​</a></h2>
<ul>
<li class="">Live GEE-computed NCD scores at ward level for all four countries</li>
<li class="">Sentinel-5P TROPOMI NO₂ layer visualised directly on the map</li>
<li class="">Time slider for NCD trend analysis (2023–2026)</li>
<li class="">Validation layer showing SADHS survey-derived prevalence data alongside the EO-derived risk scores</li>
</ul>
<p>The goal is a tool that a provincial health department can actually use to prioritise where to deploy NCD screening programmes — not just another nice map.</p>]]></content:encoded>
            <category>NCD</category>
            <category>Air Quality</category>
            <category>Southern Africa</category>
            <category>Leaflet</category>
        </item>
        <item>
            <title><![CDATA[Milestone 1 update: system design and our first 7,000 ward records]]></title>
            <link>https://MEDICONSORTIUM.github.io/Med_documentation/blog/milestone-1-progress</link>
            <guid>https://MEDICONSORTIUM.github.io/Med_documentation/blog/milestone-1-progress</guid>
            <pubDate>Wed, 10 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[We're now six weeks into Milestone 1 of the MED Consortium project, and we have something concrete to show: 7,384 ward-level records covering Limpopo Province from January 2025 to January 2026, extracted entirely from Google Earth Engine.]]></description>
            <content:encoded><![CDATA[<p>We're now six weeks into Milestone 1 of the MED Consortium project, and we have something concrete to show: <strong>7,384 ward-level records</strong> covering Limpopo Province from January 2025 to January 2026, extracted entirely from Google Earth Engine.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="what-we-built">What we built<a href="https://mediconsortium.github.io/Med_documentation/blog/milestone-1-progress#what-we-built" class="hash-link" aria-label="Direct link to What we built" title="Direct link to What we built" translate="no">​</a></h2>
<p>The core of Milestone 1 is proving that a satellite-to-dashboard pipeline actually works — not in theory, but with real data, real boundaries, and real health-relevant indices. Here's what we have:</p>
<ul>
<li class="">Monthly snapshots for every ward in Limpopo's 9 municipalities</li>
<li class="">13 variables per ward per month: surface temperature, soil moisture, NDWI, NDVI, agricultural coverage, population density, and habitat class</li>
<li class="">A live Leaflet dashboard that lets you drill down from province → municipality → ward and see a composite malaria risk score</li>
</ul>
<p>The risk engine is straightforward but grounded in the epidemiology: <em>Anopheles</em> mosquitoes need moisture, warm temperatures (25–30°C), and standing water. If a ward has all three, it gets flagged high. If the soil is dry, it stays green.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="the-gee-extraction-process">The GEE extraction process<a href="https://mediconsortium.github.io/Med_documentation/blog/milestone-1-progress#the-gee-extraction-process" class="hash-link" aria-label="Direct link to The GEE extraction process" title="Direct link to The GEE extraction process" translate="no">​</a></h2>
<p>The honest version: the first extraction attempt produced a dataset with mismatched column names, coordinate precision issues, and a few municipalities where the ward centroids fell slightly outside the boundary polygons. We fixed all of that before the data hit the dashboard.</p>
<p>The key decisions we made:</p>
<ol>
<li class=""><strong>Monthly median composites</strong> — single dates are too noisy in Limpopo's rainy season. Medians of all cloud-free scenes per month are much more stable.</li>
<li class=""><strong>ADM3-level aggregation</strong> — we're using GADM ward polygons as the unit of analysis. This keeps the data at a resolution that's meaningful for district health offices.</li>
<li class=""><strong>Safe CSV export</strong> — we named the file <code>_Safe</code> for a reason. We removed any columns that could indirectly identify individuals when combined with external data.</li>
</ol>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="what-the-data-shows">What the data shows<a href="https://mediconsortium.github.io/Med_documentation/blog/milestone-1-progress#what-the-data-shows" class="hash-link" aria-label="Direct link to What the data shows" title="Direct link to What the data shows" translate="no">​</a></h2>
<p>Even at this early stage, some patterns are clear. January and February 2025 show markedly higher soil moisture across Greater Giyani and Thulamela wards — which matches the historical malaria burden in those areas. Surface temperatures peak in October–November 2025, right on schedule.</p>
<p>We're not making causal claims yet. The validation work happens in Milestone 3. But the EO signals are picking up the right seasonal patterns, which is encouraging.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="whats-next">What's next<a href="https://mediconsortium.github.io/Med_documentation/blog/milestone-1-progress#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next" translate="no">​</a></h2>
<p>Before Milestone 1 closes in March 2026, we need to:</p>
<ul>
<li class="">Finalise the architecture documents (Annexure A and B) for submission to TuksNovation</li>
<li class="">Complete a wireframe review session with the NICD team</li>
<li class="">Begin scoping the live GEE → API pipeline for Milestone 2</li>
</ul>
<p>The NCD module is also taking shape — the Southern Africa choropleth is working and the province drill-down for South Africa is functional. Expanding to real ward-level NCD data is a Milestone 2 task.</p>
<p>If you're working with EO data for health applications in Southern Africa and want to compare notes, <a href="https://github.com/mediconsortium/Med_documentation" target="_blank" rel="noopener noreferrer" class="">open an issue on GitHub</a> or reach out directly.</p>]]></content:encoded>
            <category>Milestone</category>
            <category>Earth Observation</category>
            <category>Limpopo</category>
            <category>Data</category>
        </item>
        <item>
            <title><![CDATA[How we extracted malaria risk variables from Google Earth Engine]]></title>
            <link>https://MEDICONSORTIUM.github.io/Med_documentation/blog/extracting-malaria-risk-data-gee</link>
            <guid>https://MEDICONSORTIUM.github.io/Med_documentation/blog/extracting-malaria-risk-data-gee</guid>
            <pubDate>Thu, 20 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[A practical walkthrough of how we pull NDWI, LST, soil moisture and land cover from GEE and aggregate it to ward level for the Limpopo malaria risk model.]]></description>
            <content:encoded><![CDATA[<p>A practical walkthrough of how we pull NDWI, LST, soil moisture and land cover from GEE and aggregate it to ward level for the Limpopo malaria risk model.</p>
<p>Google Earth Engine gives you petabyte-scale access to satellite imagery. The challenge isn't getting the data — it's getting the <em>right</em> data at the right spatial and temporal resolution, then wrangling it into something a health surveillance dashboard can actually use.</p>
<p>Here's exactly what we did.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="setting-up-the-boundary">Setting up the boundary<a href="https://mediconsortium.github.io/Med_documentation/blog/extracting-malaria-risk-data-gee#setting-up-the-boundary" class="hash-link" aria-label="Direct link to Setting up the boundary" title="Direct link to Setting up the boundary" translate="no">​</a></h2>
<p>Everything aggregates up to GADM ADM3 ward polygons. We load Limpopo's wards directly from the FAO GAUL dataset in GEE:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> ee</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ee</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Initialize</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">project</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">'your-project-id'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">limpopo </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ee</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FeatureCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'FAO/GAUL/2015/level2'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ee</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">eq</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'ADM1_NAME'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'Limpopo'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>This gives you ~567 ward polygons. We add a <code>WardLabel</code> property by concatenating the ADM2 code with a sequential ward number — that becomes the primary key throughout the dataset.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="ndwi-from-sentinel-2">NDWI from Sentinel-2<a href="https://mediconsortium.github.io/Med_documentation/blog/extracting-malaria-risk-data-gee#ndwi-from-sentinel-2" class="hash-link" aria-label="Direct link to NDWI from Sentinel-2" title="Direct link to NDWI from Sentinel-2" translate="no">​</a></h2>
<p>The Normalised Difference Water Index picks up surface water and waterlogged soils:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">add_ndwi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">image</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ndwi </span><span class="token operator">=</span><span class="token plain"> image</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">normalizedDifference</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">'B3'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'B8'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rename</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'NDWI'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> image</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">addBands</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ndwi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">s2 </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ee</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ImageCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'COPERNICUS/S2_SR_HARMONIZED'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">filterDate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'2025-01-01'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'2025-01-31'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">filterBounds</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">limpopo</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">geometry</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ee</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">lt</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'CLOUDY_PIXEL_PERCENTAGE'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">20</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">map</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">add_ndwi</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ndwi_monthly </span><span class="token operator">=</span><span class="token plain"> s2</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">select</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'NDWI'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">median</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Values above −0.1 suggest meaningful surface water presence — a key condition for <em>Anopheles</em> breeding habitat.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="land-surface-temperature-from-modis">Land surface temperature from MODIS<a href="https://mediconsortium.github.io/Med_documentation/blog/extracting-malaria-risk-data-gee#land-surface-temperature-from-modis" class="hash-link" aria-label="Direct link to Land surface temperature from MODIS" title="Direct link to Land surface temperature from MODIS" translate="no">​</a></h2>
<p>MODIS MOD11A2 gives us 8-day composites at 1 km. We take the monthly mean and convert from the raw DN to Celsius:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">lst </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ee</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ImageCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'MODIS/061/MOD11A2'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">filterDate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'2025-01-01'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'2025-01-31'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">select</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'LST_Day_1km'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">mean</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">multiply</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">0.02</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">subtract</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">273.15</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rename</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'LST_Surface_C'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>The 25–30°C window is where <em>Anopheles gambiae</em> and <em>A. arabiensis</em> thrive. LST values outside that range contribute 0 to the risk score.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="soil-moisture-from-smap">Soil moisture from SMAP<a href="https://mediconsortium.github.io/Med_documentation/blog/extracting-malaria-risk-data-gee#soil-moisture-from-smap" class="hash-link" aria-label="Direct link to Soil moisture from SMAP" title="Direct link to Soil moisture from SMAP" translate="no">​</a></h2>
<p>The SMAP 10 km product gives us a direct volumetric soil moisture estimate:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">smap </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ee</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ImageCollection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'NASA/USDA/HSL/SMAP10KM_soil_moisture'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">filterDate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'2025-01-01'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'2025-01-31'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">select</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'ssm'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">mean</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rename</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">'Soil_Moisture'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Soil moisture above 0.35 m³/m³ is our high-risk threshold (+40 points in the risk model). This is the single highest-weighted variable because saturated soils are where larvae actually develop.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="aggregating-to-ward-level">Aggregating to ward level<a href="https://mediconsortium.github.io/Med_documentation/blog/extracting-malaria-risk-data-gee#aggregating-to-ward-level" class="hash-link" aria-label="Direct link to Aggregating to ward level" title="Direct link to Aggregating to ward level" translate="no">​</a></h2>
<p>Once we have all the band composites, we stack them and run <code>reduceRegions</code>:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">composite </span><span class="token operator">=</span><span class="token plain"> ndwi_monthly</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">addBands</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">lst</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">addBands</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">smap</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">ward_stats </span><span class="token operator">=</span><span class="token plain"> composite</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">reduceRegions</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    collection</span><span class="token operator">=</span><span class="token plain">limpopo</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    reducer</span><span class="token operator">=</span><span class="token plain">ee</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Reducer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">mean</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    scale</span><span class="token operator">=</span><span class="token number">1000</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)"># matches MODIS resolution</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Then export to Drive:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">task </span><span class="token operator">=</span><span class="token plain"> ee</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Export</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">table</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">toDrive</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    collection</span><span class="token operator">=</span><span class="token plain">ward_stats</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    description</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">'limpopo_jan2025'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    fileFormat</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">'CSV'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    selectors</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">'WardLabel'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'ADM2_NAME'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'NDWI'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'LST_Surface_C'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'Soil_Moisture'</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">task</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">start</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="one-thing-that-tripped-us-up">One thing that tripped us up<a href="https://mediconsortium.github.io/Med_documentation/blog/extracting-malaria-risk-data-gee#one-thing-that-tripped-us-up" class="hash-link" aria-label="Direct link to One thing that tripped us up" title="Direct link to One thing that tripped us up" translate="no">​</a></h2>
<p>The <code>scale</code> parameter in <code>reduceRegions</code> matters a lot. If you're mixing Sentinel-2 (10 m) and MODIS (1 km) bands in the same composite, GEE will resample everything to your chosen scale. We use 1000 m because SMAP is coarse — running at 10 m scale would be false precision and would time out on the export anyway.</p>
<p>For the ESA WorldCover land cover layer (10 m native), we run a separate reduction at scale=10 and join it in afterward.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="what-we-do-with-the-output">What we do with the output<a href="https://mediconsortium.github.io/Med_documentation/blog/extracting-malaria-risk-data-gee#what-we-do-with-the-output" class="hash-link" aria-label="Direct link to What we do with the output" title="Direct link to What we do with the output" translate="no">​</a></h2>
<p>The exported CSV gets light post-processing in Python (fixing column names, computing <code>Agric_Percentage</code> as the fraction of Class 40 pixels, clipping any implausible LST values) and then lands in the platform's <code>/data/</code> directory as <code>Limpopo_Risk_Jan25_Jan26_Safe.csv</code>.</p>
<p>PapaParse loads it at runtime in the browser. No backend required — at least for the prototype.</p>
<p>In Milestone 2, this export → post-process → upload cycle will be replaced by a Cloud Function that runs automatically when a new month's worth of GEE data is ready.</p>]]></content:encoded>
            <category>Google Earth Engine</category>
            <category>Python</category>
            <category>Tutorial</category>
            <category>Malaria</category>
            <category>Remote Sensing</category>
        </item>
    </channel>
</rss>