This commit is contained in:
Felix Delattre 2026-02-08 21:48:17 +01:00
parent 903bdc2598
commit bf2a5bc5d1
3 changed files with 100 additions and 5 deletions

View file

@ -334,8 +334,11 @@ def _get_gcc_from_original(input_file, site_position):
# Calculate GCC for each pixel in window
total = red_window + green_window + blue_window
mask = (total > 0) & ~np.isnan(total)
mask = (total > 0) & ~np.isnan(total) & (blue_window >= 0) & (green_window >= 0) & (red_window >= 0)
if not np.any(mask):
negative_pixels = np.sum((blue_window < 0) | (green_window < 0) | (red_window < 0))
if negative_pixels > 0:
print(f"Warning: {input_file.name} excluded - all pixels have negative band values ({negative_pixels} negative pixels in window)")
return None
gcc_window = np.zeros_like(green_window, dtype=np.float32)

8
run.py
View file

@ -28,10 +28,10 @@ def run_pipeline(season, site_position, site_name):
# print(f"Running EFAST fusion for all scenarios: {site_name}, {season}")
# run_all_efast_scenarios(season, site_position, site_name)
print(f"Post-processing data: {site_name}, {season}")
process_all_scenarios(season, site_position, site_name)
print(f"Generating NDVI for final outputs: {site_name}, {season}")
create_ndvi_timeseries_post_process(season, site_position, site_name)
# print(f"Post-processing data: {site_name}, {season}")
# process_all_scenarios(season, site_position, site_name) # Already done
# print(f"Generating NDVI for final outputs: {site_name}, {season}")
# create_ndvi_timeseries_post_process(season, site_position, site_name) # Already done
print(f"Generating GCC for final outputs: {site_name}, {season}")
# generate_gcc_post_process(season, site_position, site_name) # No-op function
create_gcc_timeseries_post_process(season, site_position, site_name)

View file

@ -105,6 +105,10 @@
<div class="combined-plot-label">Greenness Index Timeseries (S2 & Fusion)</div>
<canvas id="combinedgcctimeseries" class="combined-plot-canvas"></canvas>
</div>
<div class="combined-plot">
<div class="combined-plot-label">GCC Comparison: All Scenarios</div>
<canvas id="scenariosgcctimeseries" class="combined-plot-canvas"></canvas>
</div>
</div>
<script>
proj4.defs("EPSG:32632", "+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs");
@ -127,6 +131,8 @@
function getFusionPath() {
return `processed_${strategy}_sigma${sigma}`;
}
let allScenariosGCC = {};
const siteMap = L.map("sitemap", { zoomControl: false }).setView(sitePosition, 4).addLayer(L.tileLayer(osmUrl, { attribution: "OpenStreetMap", opacity: 1 }));
L.marker(sitePosition, { icon: L.divIcon({ className: "site-marker", html: "<div style='width:8px;height:8px;background:red;border:2px solid white;border-radius:50%;box-shadow:0 0 2px rgba(0,0,0,0.5);'></div>", iconSize: [8, 8] }) }).addTo(siteMap);
const maps = {
@ -175,10 +181,25 @@
timeseries = { s2, fusion, s3 };
greennessTimeseries = { s2: s2gcc, fusion: fusiongcc, s3: s3gcc };
phenocamGreennessTimeseries = phenocam;
// Load all scenario GCC timeseries for comparison
const scenarios = [
{ name: "Aggressive σ20", path: "processed_aggressive_sigma20" },
{ name: "Aggressive σ30", path: "processed_aggressive_sigma30" },
{ name: "Non-aggressive σ20", path: "processed_nonaggressive_sigma20" },
{ name: "Non-aggressive σ30", path: "processed_nonaggressive_sigma30" }
];
const scenarioPromises = scenarios.map(s =>
fetch(`../data/${siteName}/${season}/${s.path}/gcc/fusion/timeseries.json`).then(r => r.json()).catch(() => [])
);
const scenarioData = await Promise.all(scenarioPromises);
scenarios.forEach((s, i) => { allScenariosGCC[s.name] = scenarioData[i]; });
drawTimeseries();
drawGreennessTimeseries();
drawPhenocamGreennessTimeseries();
drawCombinedGreennessTimeseries();
drawScenariosComparison();
}
function drawGreennessTimeseries() {
@ -421,6 +442,76 @@
ctx.stroke();
}
function drawScenariosComparison() {
const canvas = document.getElementById("scenariosgcctimeseries");
const ctx = canvas.getContext("2d");
canvas.width = canvas.offsetWidth;
canvas.height = 120;
const w = canvas.width, h = canvas.height;
const pad = 30;
const plotW = w - pad * 2, plotH = h - pad * 2;
ctx.clearRect(0, 0, w, h);
const scenarios = Object.keys(allScenariosGCC);
const allData = scenarios.map(name => allScenariosGCC[name].filter(t => t.date && t.greenness_index !== null && t.greenness_index !== undefined));
if (!allData.some(d => d.length)) return;
const allDates = allData.flatMap(d => d.map(t => new Date(t.date)));
const minDate = new Date(Math.min(...allDates));
const maxDate = new Date(Math.max(...allDates));
const dateRange = maxDate - minDate || 1;
const allValues = allData.flatMap(d => d.map(t => t.greenness_index));
const minVal = Math.min(...allValues);
const maxVal = Math.max(...allValues);
const valRange = maxVal - minVal || 1;
const x = (d) => pad + ((new Date(d) - minDate) / dateRange) * plotW;
const y = (v) => pad + plotH - ((v - minVal) / valRange) * plotH;
ctx.strokeStyle = "#ccc";
ctx.beginPath();
ctx.moveTo(pad, pad);
ctx.lineTo(pad, pad + plotH);
ctx.lineTo(pad + plotW, pad + plotH);
ctx.stroke();
ctx.fillStyle = "#000";
ctx.font = "9px sans-serif";
ctx.fillText(minVal.toFixed(3), 2, pad + plotH + 10);
ctx.fillText(maxVal.toFixed(3), 2, pad + 3);
const colors = ["#ff6600", "#9900cc", "#0066ff", "#00aa00"];
scenarios.forEach((name, i) => {
const data = allData[i];
if (data.length) {
ctx.strokeStyle = colors[i];
ctx.beginPath();
let first = true;
for (const t of data) {
const px = x(t.date), py = y(t.greenness_index);
if (first) { ctx.moveTo(px, py); first = false; }
else ctx.lineTo(px, py);
}
ctx.stroke();
}
});
const legendX = pad + plotW - 120, legendY = pad + 5;
ctx.font = "9px sans-serif";
scenarios.forEach((name, i) => {
if (allData[i].length) {
ctx.strokeStyle = colors[i];
ctx.beginPath();
ctx.moveTo(legendX, legendY + i * 12);
ctx.lineTo(legendX + 15, legendY + i * 12);
ctx.stroke();
ctx.fillStyle = "#000";
ctx.fillText(name, legendX + 18, legendY + i * 12 + 3);
}
});
}
function drawTimeseries() {
const currentDate = dateFromDays(parseInt(slider.value));
for (const source of ["s2", "fusion", "s3"]) {
@ -638,6 +729,7 @@
drawGreennessTimeseries();
drawPhenocamGreennessTimeseries();
drawCombinedGreennessTimeseries();
drawScenariosComparison();
for (const source of ["s2", "fusion", "s3"]) {
const filename = await findFile(date, source);
if (filename) {