Aniket2006 commited on
Commit
2ca56f0
·
1 Parent(s): 1125b60

Add bbox coordinates and colorbar for geo-aligned overlay

Browse files
Files changed (1) hide show
  1. app.py +57 -0
app.py CHANGED
@@ -150,6 +150,10 @@ class HeatmapResponse(BaseModel):
150
  timestamp: str
151
  image_date: Optional[str] = None
152
  image_size: Optional[str] = None
 
 
 
 
153
  # Patch analysis (for pixel-wise)
154
  num_patches: Optional[int] = None
155
  health_summary: Optional[dict] = None
@@ -175,6 +179,37 @@ def get_stress_colormap():
175
  colors = [(0.2, 0.7, 0.2), (0.8, 0.8, 0.2), (0.9, 0.5, 0.1), (0.8, 0.2, 0.2)]
176
  return LinearSegmentedColormap.from_list('stress', colors, N=256)
177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  # ============================================================================
179
  # EVALSCRIPT
180
  # ============================================================================
@@ -423,6 +458,14 @@ async def generate_heatmap(request: HeatmapRequest):
423
  request.center_lon + lon_off, request.center_lat + lat_off
424
  ), crs=CRS.WGS84)
425
 
 
 
 
 
 
 
 
 
426
  size = bbox_to_dimensions(bbox, resolution=10)
427
  log_detail("Image Size", f"{size[0]}×{size[1]} pixels")
428
 
@@ -476,6 +519,11 @@ async def generate_heatmap(request: HeatmapRequest):
476
 
477
  log_section(f"SUCCESS [{req_id}]")
478
 
 
 
 
 
 
479
  return HeatmapResponse(
480
  success=True,
481
  metric=request.metric,
@@ -488,6 +536,8 @@ async def generate_heatmap(request: HeatmapRequest):
488
  timestamp=datetime.now().isoformat(),
489
  image_date=end_date.strftime('%Y-%m-%d'),
490
  image_size=f"{size[0]}x{size[1]}",
 
 
491
  num_patches=len(patches_list),
492
  health_summary=health_summary
493
  )
@@ -557,6 +607,11 @@ async def generate_heatmap(request: HeatmapRequest):
557
 
558
  log_section(f"SUCCESS [{req_id}]")
559
 
 
 
 
 
 
560
  return HeatmapResponse(
561
  success=True,
562
  metric=request.metric,
@@ -569,6 +624,8 @@ async def generate_heatmap(request: HeatmapRequest):
569
  timestamp=datetime.now().isoformat(),
570
  image_date=end_date.strftime('%Y-%m-%d'),
571
  image_size=f"{size[0]}x{size[1]}",
 
 
572
  level=llm_result.get('level', 'Unknown'),
573
  analysis=llm_result.get('analysis', ''),
574
  stress_score=float(stress_results['stress_scores'].mean()),
 
150
  timestamp: str
151
  image_date: Optional[str] = None
152
  image_size: Optional[str] = None
153
+ # Bounding box for geo-alignment [sw_lon, sw_lat, ne_lon, ne_lat]
154
+ bbox: Optional[List[float]] = None
155
+ # Separate colorbar image (horizontal) for UI display
156
+ colorbar_base64: Optional[str] = None
157
  # Patch analysis (for pixel-wise)
158
  num_patches: Optional[int] = None
159
  health_summary: Optional[dict] = None
 
179
  colors = [(0.2, 0.7, 0.2), (0.8, 0.8, 0.2), (0.9, 0.5, 0.1), (0.8, 0.2, 0.2)]
180
  return LinearSegmentedColormap.from_list('stress', colors, N=256)
181
 
182
+ def generate_colorbar_image(min_val: float, max_val: float, index_type: str, is_stress: bool = False) -> str:
183
+ """Generate a separate horizontal colorbar image for UI display."""
184
+ if is_stress:
185
+ cmap = get_stress_colormap()
186
+ label = 'Stress Level'
187
+ elif index_type in ['NDWI', 'SMI']:
188
+ cmap = get_water_colormap()
189
+ label = index_type
190
+ else:
191
+ cmap = get_vegetation_colormap()
192
+ label = index_type
193
+
194
+ fig, ax = plt.subplots(figsize=(6, 0.5), dpi=100)
195
+
196
+ # Create gradient
197
+ gradient = np.linspace(0, 1, 256).reshape(1, -1)
198
+ ax.imshow(gradient, aspect='auto', cmap=cmap)
199
+
200
+ # Labels
201
+ ax.set_xticks([0, 127, 255])
202
+ ax.set_xticklabels([f'{min_val:.2f}', f'{(min_val+max_val)/2:.2f}', f'{max_val:.2f}'], fontsize=8)
203
+ ax.set_yticks([])
204
+ ax.set_xlabel(label, fontsize=9)
205
+
206
+ buf = io.BytesIO()
207
+ plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.1, facecolor='white')
208
+ plt.close(fig)
209
+ buf.seek(0)
210
+
211
+ return base64.b64encode(buf.getvalue()).decode('utf-8')
212
+
213
  # ============================================================================
214
  # EVALSCRIPT
215
  # ============================================================================
 
458
  request.center_lon + lon_off, request.center_lat + lat_off
459
  ), crs=CRS.WGS84)
460
 
461
+ # Store bbox coordinates for response [sw_lon, sw_lat, ne_lon, ne_lat]
462
+ bbox_coords = [
463
+ request.center_lon - lon_off, # SW lon
464
+ request.center_lat - lat_off, # SW lat
465
+ request.center_lon + lon_off, # NE lon
466
+ request.center_lat + lat_off # NE lat
467
+ ]
468
+
469
  size = bbox_to_dimensions(bbox, resolution=10)
470
  log_detail("Image Size", f"{size[0]}×{size[1]} pixels")
471
 
 
519
 
520
  log_section(f"SUCCESS [{req_id}]")
521
 
522
+ # Generate colorbar if in overlay mode
523
+ colorbar_b64 = None
524
+ if request.overlay_mode:
525
+ colorbar_b64 = generate_colorbar_image(min_v, max_v, index_type, is_stress=False)
526
+
527
  return HeatmapResponse(
528
  success=True,
529
  metric=request.metric,
 
536
  timestamp=datetime.now().isoformat(),
537
  image_date=end_date.strftime('%Y-%m-%d'),
538
  image_size=f"{size[0]}x{size[1]}",
539
+ bbox=bbox_coords,
540
+ colorbar_base64=colorbar_b64,
541
  num_patches=len(patches_list),
542
  health_summary=health_summary
543
  )
 
607
 
608
  log_section(f"SUCCESS [{req_id}]")
609
 
610
+ # Generate colorbar if in overlay mode
611
+ colorbar_b64 = None
612
+ if request.overlay_mode:
613
+ colorbar_b64 = generate_colorbar_image(min_v, max_v, "Stress", is_stress=True)
614
+
615
  return HeatmapResponse(
616
  success=True,
617
  metric=request.metric,
 
624
  timestamp=datetime.now().isoformat(),
625
  image_date=end_date.strftime('%Y-%m-%d'),
626
  image_size=f"{size[0]}x{size[1]}",
627
+ bbox=bbox_coords,
628
+ colorbar_base64=colorbar_b64,
629
  level=llm_result.get('level', 'Unknown'),
630
  analysis=llm_result.get('analysis', ''),
631
  stress_score=float(stress_results['stress_scores'].mean()),