3d / app.py
rishab1090's picture
Update app.py
2da3667 verified
import gradio as gr
import rasterio
import numpy as np
import matplotlib.pyplot as plt
import plotly.graph_objs as go
from gradio.exceptions import Error
from rasterio.errors import RasterioIOError
def process_dem(dem_file):
# dem_file can be a tempfile-like object, or a str path (depending on gr.File type)
if isinstance(dem_file, str):
path = dem_file
else:
# Gradio hands a TemporaryFile object; use its .name
path = getattr(dem_file, "name", None)
if not path:
raise Error("No file received. Please upload a GeoTIFF (.tif/.tiff).")
# Robust validation by CONTENT (not extension)
try:
with rasterio.open(path) as src:
# Accept common GeoTIFF drivers
if src.driver not in ("GTiff", "COG"):
raise Error(f"Unsupported raster driver: {src.driver}. Please upload a GeoTIFF.")
dem = src.read(1).astype(float)
except RasterioIOError as e:
raise Error(f"Could not read the file as a GeoTIFF. Details: {e}")
nrows, ncols = dem.shape
Z = dem
# --- SLOPE ---
dy, dx = np.gradient(Z)
slope = np.sqrt(dx**2 + dy**2)
# --- RISK MASK (top 5% steepest) ---
threshold = np.percentile(slope, 95)
risk_mask = slope > threshold
# --- 2D RISK MAP ---
fig2d, ax = plt.subplots(figsize=(8, 6))
c = ax.imshow(slope, cmap="hot", origin="upper")
ax.contour(risk_mask, levels=[0.5], colors="blue", linewidths=0.8)
plt.colorbar(c, ax=ax, label="Slope (steepness)")
ax.set_title("Slope Risk Map (Hot = Steep, Blue = Risk zones)")
ax.set_xlabel("Column Index (X)")
ax.set_ylabel("Row Index (Y)")
risk_map_path = "risk_map.png"
plt.savefig(risk_map_path, dpi=150, bbox_inches="tight")
plt.close(fig2d)
# --- INTERACTIVE 3D DEM (Plotly) ---
step = max(1, nrows // 200)
fig3d = go.Figure()
fig3d.add_trace(go.Surface(
z=Z[::step, ::step],
colorscale="Earth",
showscale=True,
opacity=0.9,
contours=dict(z=dict(show=True, usecolormap=True, highlightcolor="black", project_z=True))
))
fig3d.add_trace(go.Surface(
z=np.where(risk_mask[::step, ::step], Z[::step, ::step], np.nan),
surfacecolor=np.ones_like(Z[::step, ::step]),
colorscale=[[0, "purple"], [1, "purple"]],
showscale=False,
opacity=0.6
))
fig3d.update_layout(
title="Interactive 3D DEM with Contours & Steep Slope Highlight",
scene=dict(
xaxis_title="X (grid cols)",
yaxis_title="Y (grid rows)",
zaxis_title="Elevation (m)",
aspectmode="data"
)
)
return risk_map_path, fig3d
# --- GRADIO APP ---
demo = gr.Interface(
fn=process_dem,
# 🔑 Remove file_types to bypass extension-based rejection entirely
inputs=gr.File(label="Upload DEM (GeoTIFF .tif/.tiff)"),
outputs=[
gr.Image(type="filepath", label="2D Slope Risk Map"),
gr.Plot(label="Interactive 3D DEM (with Contours & Risk Zones)")
],
title="3D DEM & Landslide Risk Visualizer",
description="Upload a GeoTIFF DEM file to see a 2D slope risk map and an interactive 3D DEM with contours & steep slope zones highlighted."
)
if __name__ == "__main__":
demo.launch()