foo
This commit is contained in:
parent
903bdc2598
commit
bf2a5bc5d1
3 changed files with 100 additions and 5 deletions
|
|
@ -334,8 +334,11 @@ def _get_gcc_from_original(input_file, site_position):
|
||||||
|
|
||||||
# Calculate GCC for each pixel in window
|
# Calculate GCC for each pixel in window
|
||||||
total = red_window + green_window + blue_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):
|
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
|
return None
|
||||||
|
|
||||||
gcc_window = np.zeros_like(green_window, dtype=np.float32)
|
gcc_window = np.zeros_like(green_window, dtype=np.float32)
|
||||||
|
|
|
||||||
8
run.py
8
run.py
|
|
@ -28,10 +28,10 @@ def run_pipeline(season, site_position, site_name):
|
||||||
# print(f"Running EFAST fusion for all scenarios: {site_name}, {season}")
|
# print(f"Running EFAST fusion for all scenarios: {site_name}, {season}")
|
||||||
# run_all_efast_scenarios(season, site_position, site_name)
|
# run_all_efast_scenarios(season, site_position, site_name)
|
||||||
|
|
||||||
print(f"Post-processing data: {site_name}, {season}")
|
# print(f"Post-processing data: {site_name}, {season}")
|
||||||
process_all_scenarios(season, site_position, site_name)
|
# process_all_scenarios(season, site_position, site_name) # Already done
|
||||||
print(f"Generating NDVI for final outputs: {site_name}, {season}")
|
# print(f"Generating NDVI for final outputs: {site_name}, {season}")
|
||||||
create_ndvi_timeseries_post_process(season, site_position, site_name)
|
# create_ndvi_timeseries_post_process(season, site_position, site_name) # Already done
|
||||||
print(f"Generating GCC for final outputs: {site_name}, {season}")
|
print(f"Generating GCC for final outputs: {site_name}, {season}")
|
||||||
# generate_gcc_post_process(season, site_position, site_name) # No-op function
|
# generate_gcc_post_process(season, site_position, site_name) # No-op function
|
||||||
create_gcc_timeseries_post_process(season, site_position, site_name)
|
create_gcc_timeseries_post_process(season, site_position, site_name)
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,10 @@
|
||||||
<div class="combined-plot-label">Greenness Index Timeseries (S2 & Fusion)</div>
|
<div class="combined-plot-label">Greenness Index Timeseries (S2 & Fusion)</div>
|
||||||
<canvas id="combinedgcctimeseries" class="combined-plot-canvas"></canvas>
|
<canvas id="combinedgcctimeseries" class="combined-plot-canvas"></canvas>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
proj4.defs("EPSG:32632", "+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs");
|
proj4.defs("EPSG:32632", "+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs");
|
||||||
|
|
@ -127,6 +131,8 @@
|
||||||
function getFusionPath() {
|
function getFusionPath() {
|
||||||
return `processed_${strategy}_sigma${sigma}`;
|
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 }));
|
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);
|
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 = {
|
const maps = {
|
||||||
|
|
@ -175,10 +181,25 @@
|
||||||
timeseries = { s2, fusion, s3 };
|
timeseries = { s2, fusion, s3 };
|
||||||
greennessTimeseries = { s2: s2gcc, fusion: fusiongcc, s3: s3gcc };
|
greennessTimeseries = { s2: s2gcc, fusion: fusiongcc, s3: s3gcc };
|
||||||
phenocamGreennessTimeseries = phenocam;
|
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();
|
drawTimeseries();
|
||||||
drawGreennessTimeseries();
|
drawGreennessTimeseries();
|
||||||
drawPhenocamGreennessTimeseries();
|
drawPhenocamGreennessTimeseries();
|
||||||
drawCombinedGreennessTimeseries();
|
drawCombinedGreennessTimeseries();
|
||||||
|
drawScenariosComparison();
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawGreennessTimeseries() {
|
function drawGreennessTimeseries() {
|
||||||
|
|
@ -421,6 +442,76 @@
|
||||||
ctx.stroke();
|
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() {
|
function drawTimeseries() {
|
||||||
const currentDate = dateFromDays(parseInt(slider.value));
|
const currentDate = dateFromDays(parseInt(slider.value));
|
||||||
for (const source of ["s2", "fusion", "s3"]) {
|
for (const source of ["s2", "fusion", "s3"]) {
|
||||||
|
|
@ -638,6 +729,7 @@
|
||||||
drawGreennessTimeseries();
|
drawGreennessTimeseries();
|
||||||
drawPhenocamGreennessTimeseries();
|
drawPhenocamGreennessTimeseries();
|
||||||
drawCombinedGreennessTimeseries();
|
drawCombinedGreennessTimeseries();
|
||||||
|
drawScenariosComparison();
|
||||||
for (const source of ["s2", "fusion", "s3"]) {
|
for (const source of ["s2", "fusion", "s3"]) {
|
||||||
const filename = await findFile(date, source);
|
const filename = await findFile(date, source);
|
||||||
if (filename) {
|
if (filename) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue