fix
Browse files- map_tab/map_logic.py +33 -25
map_tab/map_logic.py
CHANGED
|
@@ -6,7 +6,7 @@ import pandas as pd
|
|
| 6 |
import rasterio
|
| 7 |
import pyproj
|
| 8 |
import matplotlib.pyplot as plt
|
| 9 |
-
from matplotlib import
|
| 10 |
from geopy.geocoders import Nominatim
|
| 11 |
from config import OUTPUT_DIR
|
| 12 |
import plotly.graph_objects as go
|
|
@@ -14,6 +14,7 @@ from PIL import Image
|
|
| 14 |
|
| 15 |
CELL_SIZE_M = 100 # meters
|
| 16 |
|
|
|
|
| 17 |
def make_map(city, show_grid=True, show_georef=True):
|
| 18 |
city = city.strip()
|
| 19 |
if not city:
|
|
@@ -97,7 +98,7 @@ def make_map(city, show_grid=True, show_georef=True):
|
|
| 97 |
|
| 98 |
# --- Optional grid overlay ---
|
| 99 |
if show_grid:
|
| 100 |
-
_add_grid_overlay_plotly(fig, transformer)
|
| 101 |
|
| 102 |
# --- Layout ---
|
| 103 |
fig.update_layout(
|
|
@@ -110,37 +111,43 @@ def make_map(city, show_grid=True, show_georef=True):
|
|
| 110 |
return fig
|
| 111 |
|
| 112 |
|
| 113 |
-
def _add_grid_overlay_plotly(fig, transformer):
|
|
|
|
| 114 |
grid_values = []
|
| 115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
for fname in os.listdir(OUTPUT_DIR):
|
| 117 |
if fname.startswith("street_matches_tile") and fname.endswith(".csv"):
|
| 118 |
df = pd.read_csv(os.path.join(OUTPUT_DIR, fname))
|
| 119 |
-
if df.empty:
|
| 120 |
continue
|
| 121 |
|
| 122 |
tile_xmin, tile_xmax = df['x'].min(), df['x'].max()
|
| 123 |
tile_ymin, tile_ymax = df['y'].min(), df['y'].max()
|
| 124 |
-
n_cols = int(np.ceil((tile_xmax - tile_xmin) /
|
| 125 |
-
n_rows = int(np.ceil((tile_ymax - tile_ymin) /
|
| 126 |
|
| 127 |
grid = np.zeros((n_rows, n_cols))
|
| 128 |
counts = np.zeros((n_rows, n_cols))
|
| 129 |
|
| 130 |
for _, row in df.iterrows():
|
| 131 |
-
col = int((row['x'] - tile_xmin) //
|
| 132 |
-
row_idx = int((row['y']
|
| 133 |
if 0 <= col < n_cols and 0 <= row_idx < n_rows:
|
| 134 |
grid[row_idx, col] += row['osm_match_score']
|
| 135 |
counts[row_idx, col] += 1
|
| 136 |
|
| 137 |
mask = counts > 0
|
| 138 |
grid[mask] /= counts[mask]
|
| 139 |
-
|
| 140 |
-
grid_values.append((grid, tile_xmin, tile_ymin, n_rows, n_cols))
|
| 141 |
|
| 142 |
if not grid_values:
|
| 143 |
-
print("No
|
| 144 |
return
|
| 145 |
|
| 146 |
all_scores = np.concatenate([g[0].flatten() for g in grid_values])
|
|
@@ -150,7 +157,7 @@ def _add_grid_overlay_plotly(fig, transformer):
|
|
| 150 |
|
| 151 |
cmap = plt.get_cmap("Reds")
|
| 152 |
|
| 153 |
-
for grid, tile_xmin,
|
| 154 |
for r in range(n_rows):
|
| 155 |
for c in range(n_cols):
|
| 156 |
val = grid[r, c]
|
|
@@ -159,20 +166,22 @@ def _add_grid_overlay_plotly(fig, transformer):
|
|
| 159 |
norm_val = (val - min_val) / (max_val - min_val)
|
| 160 |
color = colors.to_hex(cmap(norm_val))
|
| 161 |
|
| 162 |
-
#
|
| 163 |
-
x0 = tile_xmin + c *
|
| 164 |
-
x1 = x0 +
|
| 165 |
-
|
| 166 |
-
|
| 167 |
|
| 168 |
# Convert to lon/lat
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
|
|
|
|
|
|
| 176 |
fig.add_trace(go.Scattermapbox(
|
| 177 |
lon=lons,
|
| 178 |
lat=lats,
|
|
@@ -183,4 +192,3 @@ def _add_grid_overlay_plotly(fig, transformer):
|
|
| 183 |
hoverinfo="text",
|
| 184 |
text=f"{val:.2f}"
|
| 185 |
))
|
| 186 |
-
|
|
|
|
| 6 |
import rasterio
|
| 7 |
import pyproj
|
| 8 |
import matplotlib.pyplot as plt
|
| 9 |
+
from matplotlib import colors
|
| 10 |
from geopy.geocoders import Nominatim
|
| 11 |
from config import OUTPUT_DIR
|
| 12 |
import plotly.graph_objects as go
|
|
|
|
| 14 |
|
| 15 |
CELL_SIZE_M = 100 # meters
|
| 16 |
|
| 17 |
+
|
| 18 |
def make_map(city, show_grid=True, show_georef=True):
|
| 19 |
city = city.strip()
|
| 20 |
if not city:
|
|
|
|
| 98 |
|
| 99 |
# --- Optional grid overlay ---
|
| 100 |
if show_grid:
|
| 101 |
+
_add_grid_overlay_plotly(fig, transformer, crs)
|
| 102 |
|
| 103 |
# --- Layout ---
|
| 104 |
fig.update_layout(
|
|
|
|
| 111 |
return fig
|
| 112 |
|
| 113 |
|
| 114 |
+
def _add_grid_overlay_plotly(fig, transformer, raster_crs):
|
| 115 |
+
"""Add grid overlay as colored cells, works for any CRS."""
|
| 116 |
grid_values = []
|
| 117 |
|
| 118 |
+
# Adapt grid size if CRS uses degrees instead of meters
|
| 119 |
+
if raster_crs.is_geographic:
|
| 120 |
+
cell_size = 0.001 # roughly 100m at equator
|
| 121 |
+
else:
|
| 122 |
+
cell_size = CELL_SIZE_M
|
| 123 |
+
|
| 124 |
for fname in os.listdir(OUTPUT_DIR):
|
| 125 |
if fname.startswith("street_matches_tile") and fname.endswith(".csv"):
|
| 126 |
df = pd.read_csv(os.path.join(OUTPUT_DIR, fname))
|
| 127 |
+
if df.empty or "x" not in df.columns or "y" not in df.columns:
|
| 128 |
continue
|
| 129 |
|
| 130 |
tile_xmin, tile_xmax = df['x'].min(), df['x'].max()
|
| 131 |
tile_ymin, tile_ymax = df['y'].min(), df['y'].max()
|
| 132 |
+
n_cols = int(np.ceil((tile_xmax - tile_xmin) / cell_size))
|
| 133 |
+
n_rows = int(np.ceil((tile_ymax - tile_ymin) / cell_size))
|
| 134 |
|
| 135 |
grid = np.zeros((n_rows, n_cols))
|
| 136 |
counts = np.zeros((n_rows, n_cols))
|
| 137 |
|
| 138 |
for _, row in df.iterrows():
|
| 139 |
+
col = int((row['x'] - tile_xmin) // cell_size)
|
| 140 |
+
row_idx = int((tile_ymax - row['y']) // cell_size) # origin top-left
|
| 141 |
if 0 <= col < n_cols and 0 <= row_idx < n_rows:
|
| 142 |
grid[row_idx, col] += row['osm_match_score']
|
| 143 |
counts[row_idx, col] += 1
|
| 144 |
|
| 145 |
mask = counts > 0
|
| 146 |
grid[mask] /= counts[mask]
|
| 147 |
+
grid_values.append((grid, tile_xmin, tile_ymax, n_rows, n_cols, cell_size))
|
|
|
|
| 148 |
|
| 149 |
if not grid_values:
|
| 150 |
+
print("No valid CSV grids found.")
|
| 151 |
return
|
| 152 |
|
| 153 |
all_scores = np.concatenate([g[0].flatten() for g in grid_values])
|
|
|
|
| 157 |
|
| 158 |
cmap = plt.get_cmap("Reds")
|
| 159 |
|
| 160 |
+
for grid, tile_xmin, tile_ymax, n_rows, n_cols, cell_size in grid_values:
|
| 161 |
for r in range(n_rows):
|
| 162 |
for c in range(n_cols):
|
| 163 |
val = grid[r, c]
|
|
|
|
| 166 |
norm_val = (val - min_val) / (max_val - min_val)
|
| 167 |
color = colors.to_hex(cmap(norm_val))
|
| 168 |
|
| 169 |
+
# Compute rectangle in projected CRS
|
| 170 |
+
x0 = tile_xmin + c * cell_size
|
| 171 |
+
x1 = x0 + cell_size
|
| 172 |
+
y1 = tile_ymax - r * cell_size
|
| 173 |
+
y0 = y1 - cell_size
|
| 174 |
|
| 175 |
# Convert to lon/lat
|
| 176 |
+
lons, lats = zip(*[
|
| 177 |
+
transformer.transform(x0, y0),
|
| 178 |
+
transformer.transform(x1, y0),
|
| 179 |
+
transformer.transform(x1, y1),
|
| 180 |
+
transformer.transform(x0, y1),
|
| 181 |
+
transformer.transform(x0, y0),
|
| 182 |
+
])
|
| 183 |
+
|
| 184 |
+
# Add to Plotly map
|
| 185 |
fig.add_trace(go.Scattermapbox(
|
| 186 |
lon=lons,
|
| 187 |
lat=lats,
|
|
|
|
| 192 |
hoverinfo="text",
|
| 193 |
text=f"{val:.2f}"
|
| 194 |
))
|
|
|