voxcity 0.3.14__py3-none-any.whl → 0.3.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of voxcity might be problematic. Click here for more details.
- voxcity/generator.py +4 -3
- voxcity/geoprocessor/draw.py +35 -25
- voxcity/geoprocessor/grid.py +97 -10
- voxcity/utils/visualization.py +135 -0
- {voxcity-0.3.14.dist-info → voxcity-0.3.16.dist-info}/METADATA +3 -3
- {voxcity-0.3.14.dist-info → voxcity-0.3.16.dist-info}/RECORD +10 -10
- {voxcity-0.3.14.dist-info → voxcity-0.3.16.dist-info}/AUTHORS.rst +0 -0
- {voxcity-0.3.14.dist-info → voxcity-0.3.16.dist-info}/LICENSE +0 -0
- {voxcity-0.3.14.dist-info → voxcity-0.3.16.dist-info}/WHEEL +0 -0
- {voxcity-0.3.14.dist-info → voxcity-0.3.16.dist-info}/top_level.txt +0 -0
voxcity/generator.py
CHANGED
|
@@ -185,11 +185,12 @@ def get_building_height_grid(rectangle_vertices, meshsize, source, output_dir, *
|
|
|
185
185
|
|
|
186
186
|
# Check for complementary building data source
|
|
187
187
|
building_complementary_source = kwargs.get("building_complementary_source")
|
|
188
|
+
building_complement_height = kwargs.get("building_complement_height")
|
|
188
189
|
|
|
189
190
|
if (building_complementary_source is None) or (building_complementary_source=='None'):
|
|
190
191
|
# Use only primary source
|
|
191
192
|
if source != "Open Building 2.5D Temporal":
|
|
192
|
-
building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices)
|
|
193
|
+
building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices, complement_height=building_complement_height)
|
|
193
194
|
else:
|
|
194
195
|
# Handle complementary source
|
|
195
196
|
if building_complementary_source == "Open Building 2.5D Temporal":
|
|
@@ -198,7 +199,7 @@ def get_building_height_grid(rectangle_vertices, meshsize, source, output_dir, *
|
|
|
198
199
|
os.makedirs(output_dir, exist_ok=True)
|
|
199
200
|
geotiff_path_comp = os.path.join(output_dir, "building_height.tif")
|
|
200
201
|
save_geotiff_open_buildings_temporal(roi, geotiff_path_comp)
|
|
201
|
-
building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices, geotiff_path_comp=geotiff_path_comp)
|
|
202
|
+
building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices, geotiff_path_comp=geotiff_path_comp, complement_height=building_complement_height)
|
|
202
203
|
else:
|
|
203
204
|
# Get complementary data from other sources
|
|
204
205
|
if building_complementary_source == 'Microsoft Building Footprints':
|
|
@@ -220,7 +221,7 @@ def get_building_height_grid(rectangle_vertices, meshsize, source, output_dir, *
|
|
|
220
221
|
|
|
221
222
|
# Option to complement footprints only or both footprints and heights
|
|
222
223
|
complement_building_footprints = kwargs.get("complement_building_footprints")
|
|
223
|
-
building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices, gdf_comp=gdf_comp, complement_building_footprints=complement_building_footprints)
|
|
224
|
+
building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings = create_building_height_grid_from_gdf_polygon(gdf, meshsize, rectangle_vertices, gdf_comp=gdf_comp, complement_building_footprints=complement_building_footprints, complement_height=building_complement_height)
|
|
224
225
|
|
|
225
226
|
# Visualize grid if requested
|
|
226
227
|
grid_vis = kwargs.get("gridvis", True)
|
voxcity/geoprocessor/draw.py
CHANGED
|
@@ -223,15 +223,16 @@ def center_location_map_cityname(cityname, east_west_length, north_south_length,
|
|
|
223
223
|
|
|
224
224
|
return m, rectangle_vertices
|
|
225
225
|
|
|
226
|
-
def display_buildings_and_draw_polygon(building_gdf, zoom=17):
|
|
226
|
+
def display_buildings_and_draw_polygon(building_gdf=None, rectangle_vertices=None, zoom=17):
|
|
227
227
|
"""
|
|
228
228
|
Displays building footprints (in Lon-Lat order) on an ipyleaflet map,
|
|
229
229
|
and allows the user to draw a polygon whose vertices are returned
|
|
230
230
|
in a Python list (also in Lon-Lat).
|
|
231
231
|
|
|
232
232
|
Args:
|
|
233
|
-
building_gdf (GeoDataFrame): A GeoDataFrame containing building footprints,
|
|
234
|
-
|
|
233
|
+
building_gdf (GeoDataFrame, optional): A GeoDataFrame containing building footprints,
|
|
234
|
+
with geometry in [lon, lat] order.
|
|
235
|
+
rectangle_vertices (list, optional): List of [lon, lat] coordinates defining rectangle corners.
|
|
235
236
|
zoom (int): Initial zoom level for the map. Default=17.
|
|
236
237
|
|
|
237
238
|
Returns:
|
|
@@ -243,39 +244,48 @@ def display_buildings_and_draw_polygon(building_gdf, zoom=17):
|
|
|
243
244
|
# ---------------------------------------------------------
|
|
244
245
|
# 1. Determine a suitable map center via bounding box logic
|
|
245
246
|
# ---------------------------------------------------------
|
|
246
|
-
if
|
|
247
|
-
#
|
|
248
|
-
|
|
249
|
-
|
|
247
|
+
if rectangle_vertices is not None:
|
|
248
|
+
# Get bounds from rectangle vertices
|
|
249
|
+
lons = [v[0] for v in rectangle_vertices]
|
|
250
|
+
lats = [v[1] for v in rectangle_vertices]
|
|
251
|
+
min_lon, max_lon = min(lons), max(lons)
|
|
252
|
+
min_lat, max_lat = min(lats), max(lats)
|
|
253
|
+
center_lon = (min_lon + max_lon) / 2
|
|
254
|
+
center_lat = (min_lat + max_lat) / 2
|
|
255
|
+
elif building_gdf is not None and len(building_gdf) > 0:
|
|
250
256
|
# Get bounds from GeoDataFrame
|
|
251
257
|
bounds = building_gdf.total_bounds # Returns [minx, miny, maxx, maxy]
|
|
252
258
|
min_lon, min_lat, max_lon, max_lat = bounds
|
|
253
259
|
center_lon = (min_lon + max_lon) / 2
|
|
254
260
|
center_lat = (min_lat + max_lat) / 2
|
|
261
|
+
else:
|
|
262
|
+
# Fallback: If no inputs or invalid data, pick a default
|
|
263
|
+
center_lon, center_lat = -100.0, 40.0
|
|
255
264
|
|
|
256
265
|
# Create the ipyleaflet map (needs lat,lon)
|
|
257
266
|
m = Map(center=(center_lat, center_lon), zoom=zoom, scroll_wheel_zoom=True)
|
|
258
267
|
|
|
259
268
|
# -----------------------------------------
|
|
260
|
-
# 2. Add
|
|
269
|
+
# 2. Add building footprints to the map if provided
|
|
261
270
|
# -----------------------------------------
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
271
|
+
if building_gdf is not None:
|
|
272
|
+
for idx, row in building_gdf.iterrows():
|
|
273
|
+
# Only handle simple Polygons
|
|
274
|
+
if isinstance(row.geometry, geom.Polygon):
|
|
275
|
+
# Get coordinates from geometry
|
|
276
|
+
coords = list(row.geometry.exterior.coords)
|
|
277
|
+
# Convert to (lat,lon) for ipyleaflet, skip last repeated coordinate
|
|
278
|
+
lat_lon_coords = [(c[1], c[0]) for c in coords[:-1]]
|
|
279
|
+
|
|
280
|
+
# Create the polygon layer
|
|
281
|
+
bldg_layer = LeafletPolygon(
|
|
282
|
+
locations=lat_lon_coords,
|
|
283
|
+
color="blue",
|
|
284
|
+
fill_color="blue",
|
|
285
|
+
fill_opacity=0.2,
|
|
286
|
+
weight=2
|
|
287
|
+
)
|
|
288
|
+
m.add_layer(bldg_layer)
|
|
279
289
|
|
|
280
290
|
# -----------------------------------------------------------------
|
|
281
291
|
# 3. Enable drawing of polygons, capturing the vertices in Lon-Lat
|
voxcity/geoprocessor/grid.py
CHANGED
|
@@ -480,7 +480,8 @@ def create_building_height_grid_from_gdf_polygon(
|
|
|
480
480
|
rectangle_vertices,
|
|
481
481
|
gdf_comp=None,
|
|
482
482
|
geotiff_path_comp=None,
|
|
483
|
-
complement_building_footprints=None
|
|
483
|
+
complement_building_footprints=None,
|
|
484
|
+
complement_height=None
|
|
484
485
|
):
|
|
485
486
|
"""
|
|
486
487
|
Create a building height grid from GeoDataFrame data within a polygon boundary.
|
|
@@ -492,6 +493,7 @@ def create_building_height_grid_from_gdf_polygon(
|
|
|
492
493
|
gdf_comp (geopandas.GeoDataFrame, optional): Complementary GeoDataFrame
|
|
493
494
|
geotiff_path_comp (str, optional): Path to complementary GeoTIFF file
|
|
494
495
|
complement_building_footprints (bool, optional): Whether to complement footprints
|
|
496
|
+
complement_height (float, optional): Height value to use for buildings with height=0
|
|
495
497
|
|
|
496
498
|
Returns:
|
|
497
499
|
tuple: (building_height_grid, building_min_height_grid, building_id_grid, filtered_buildings)
|
|
@@ -558,6 +560,11 @@ def create_building_height_grid_from_gdf_polygon(
|
|
|
558
560
|
for idx_b, row in filtered_gdf.iterrows():
|
|
559
561
|
polygon = row.geometry
|
|
560
562
|
height = row.get('height', None)
|
|
563
|
+
|
|
564
|
+
# Replace height=0 with complement_height if specified
|
|
565
|
+
if complement_height is not None and (height == 0 or height is None):
|
|
566
|
+
height = complement_height
|
|
567
|
+
|
|
561
568
|
min_height = row.get('min_height', 0)
|
|
562
569
|
is_inner = row.get('is_inner', False)
|
|
563
570
|
feature_id = row.get('id', idx_b)
|
|
@@ -883,10 +890,19 @@ def grid_to_geodataframe(grid_ori, rectangle_vertices, meshsize):
|
|
|
883
890
|
|
|
884
891
|
rows, cols = grid.shape
|
|
885
892
|
|
|
886
|
-
#
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
893
|
+
# Set up transformers for accurate coordinate calculations
|
|
894
|
+
wgs84 = CRS.from_epsg(4326)
|
|
895
|
+
web_mercator = CRS.from_epsg(3857)
|
|
896
|
+
transformer_to_mercator = Transformer.from_crs(wgs84, web_mercator, always_xy=True)
|
|
897
|
+
transformer_to_wgs84 = Transformer.from_crs(web_mercator, wgs84, always_xy=True)
|
|
898
|
+
|
|
899
|
+
# Convert bounds to Web Mercator for accurate distance calculations
|
|
900
|
+
min_x, min_y = transformer_to_mercator.transform(min_lon, min_lat)
|
|
901
|
+
max_x, max_y = transformer_to_mercator.transform(max_lon, max_lat)
|
|
902
|
+
|
|
903
|
+
# Calculate cell sizes in Web Mercator coordinates
|
|
904
|
+
cell_size_x = (max_x - min_x) / cols
|
|
905
|
+
cell_size_y = (max_y - min_y) / rows
|
|
890
906
|
|
|
891
907
|
# Create lists to store data
|
|
892
908
|
polygons = []
|
|
@@ -895,12 +911,16 @@ def grid_to_geodataframe(grid_ori, rectangle_vertices, meshsize):
|
|
|
895
911
|
# Create grid cells
|
|
896
912
|
for i in range(rows):
|
|
897
913
|
for j in range(cols):
|
|
898
|
-
# Calculate cell bounds
|
|
899
|
-
|
|
900
|
-
|
|
914
|
+
# Calculate cell bounds in Web Mercator
|
|
915
|
+
cell_min_x = min_x + j * cell_size_x
|
|
916
|
+
cell_max_x = min_x + (j + 1) * cell_size_x
|
|
901
917
|
# Flip vertical axis since grid is stored with origin at top-left
|
|
902
|
-
|
|
903
|
-
|
|
918
|
+
cell_min_y = max_y - (i + 1) * cell_size_y
|
|
919
|
+
cell_max_y = max_y - i * cell_size_y
|
|
920
|
+
|
|
921
|
+
# Convert cell corners back to WGS84
|
|
922
|
+
cell_min_lon, cell_min_lat = transformer_to_wgs84.transform(cell_min_x, cell_min_y)
|
|
923
|
+
cell_max_lon, cell_max_lat = transformer_to_wgs84.transform(cell_max_x, cell_max_y)
|
|
904
924
|
|
|
905
925
|
# Create polygon for cell
|
|
906
926
|
cell_poly = box(cell_min_lon, cell_min_lat, cell_max_lon, cell_max_lat)
|
|
@@ -914,4 +934,71 @@ def grid_to_geodataframe(grid_ori, rectangle_vertices, meshsize):
|
|
|
914
934
|
'value': values
|
|
915
935
|
}, crs=CRS.from_epsg(4326))
|
|
916
936
|
|
|
937
|
+
return gdf
|
|
938
|
+
|
|
939
|
+
def grid_to_point_geodataframe(grid_ori, rectangle_vertices, meshsize):
|
|
940
|
+
"""Converts a 2D grid to a GeoDataFrame with point geometries at cell centers and values.
|
|
941
|
+
|
|
942
|
+
Args:
|
|
943
|
+
grid: 2D numpy array containing grid values
|
|
944
|
+
rectangle_vertices: List of [lon, lat] coordinates defining area corners
|
|
945
|
+
meshsize: Size of each grid cell in meters
|
|
946
|
+
|
|
947
|
+
Returns:
|
|
948
|
+
GeoDataFrame with columns:
|
|
949
|
+
- geometry: Point geometry at center of each grid cell
|
|
950
|
+
- value: Value from the grid
|
|
951
|
+
"""
|
|
952
|
+
grid = np.flipud(grid_ori.copy())
|
|
953
|
+
|
|
954
|
+
# Extract bounds from rectangle vertices
|
|
955
|
+
min_lon = min(v[0] for v in rectangle_vertices)
|
|
956
|
+
max_lon = max(v[0] for v in rectangle_vertices)
|
|
957
|
+
min_lat = min(v[1] for v in rectangle_vertices)
|
|
958
|
+
max_lat = max(v[1] for v in rectangle_vertices)
|
|
959
|
+
|
|
960
|
+
rows, cols = grid.shape
|
|
961
|
+
|
|
962
|
+
# Set up transformers for accurate coordinate calculations
|
|
963
|
+
wgs84 = CRS.from_epsg(4326)
|
|
964
|
+
web_mercator = CRS.from_epsg(3857)
|
|
965
|
+
transformer_to_mercator = Transformer.from_crs(wgs84, web_mercator, always_xy=True)
|
|
966
|
+
transformer_to_wgs84 = Transformer.from_crs(web_mercator, wgs84, always_xy=True)
|
|
967
|
+
|
|
968
|
+
# Convert bounds to Web Mercator for accurate distance calculations
|
|
969
|
+
min_x, min_y = transformer_to_mercator.transform(min_lon, min_lat)
|
|
970
|
+
max_x, max_y = transformer_to_mercator.transform(max_lon, max_lat)
|
|
971
|
+
|
|
972
|
+
# Calculate cell sizes in Web Mercator coordinates
|
|
973
|
+
cell_size_x = (max_x - min_x) / cols
|
|
974
|
+
cell_size_y = (max_y - min_y) / rows
|
|
975
|
+
|
|
976
|
+
# Create lists to store data
|
|
977
|
+
points = []
|
|
978
|
+
values = []
|
|
979
|
+
|
|
980
|
+
# Create grid points at cell centers
|
|
981
|
+
for i in range(rows):
|
|
982
|
+
for j in range(cols):
|
|
983
|
+
# Calculate cell center in Web Mercator
|
|
984
|
+
cell_center_x = min_x + (j + 0.5) * cell_size_x
|
|
985
|
+
# Flip vertical axis since grid is stored with origin at top-left
|
|
986
|
+
cell_center_y = max_y - (i + 0.5) * cell_size_y
|
|
987
|
+
|
|
988
|
+
# Convert cell center back to WGS84
|
|
989
|
+
center_lon, center_lat = transformer_to_wgs84.transform(cell_center_x, cell_center_y)
|
|
990
|
+
|
|
991
|
+
# Create point for cell center
|
|
992
|
+
from shapely.geometry import Point
|
|
993
|
+
cell_point = Point(center_lon, center_lat)
|
|
994
|
+
|
|
995
|
+
points.append(cell_point)
|
|
996
|
+
values.append(grid[i, j])
|
|
997
|
+
|
|
998
|
+
# Create GeoDataFrame
|
|
999
|
+
gdf = gpd.GeoDataFrame({
|
|
1000
|
+
'geometry': points,
|
|
1001
|
+
'value': values
|
|
1002
|
+
}, crs=CRS.from_epsg(4326))
|
|
1003
|
+
|
|
917
1004
|
return gdf
|
voxcity/utils/visualization.py
CHANGED
|
@@ -775,5 +775,140 @@ def visualize_numerical_grid_on_basemap(grid, rectangle_vertices, meshsize, valu
|
|
|
775
775
|
# Set title and remove axes
|
|
776
776
|
ax.set_axis_off()
|
|
777
777
|
|
|
778
|
+
plt.tight_layout()
|
|
779
|
+
plt.show()
|
|
780
|
+
|
|
781
|
+
def visualize_numerical_grid_gdf_on_basemap(gdf, value_name="value", cmap='viridis', vmin=None, vmax=None,
|
|
782
|
+
alpha=0.6, figsize=(12, 8), basemap='CartoDB light',
|
|
783
|
+
show_edge=False, edge_color='black', edge_width=0.5):
|
|
784
|
+
"""Visualizes a GeoDataFrame with numerical values on a basemap.
|
|
785
|
+
|
|
786
|
+
Args:
|
|
787
|
+
gdf: GeoDataFrame containing grid cells with 'geometry' and 'value' columns
|
|
788
|
+
value_name: Name of the value column and legend label (default: "value")
|
|
789
|
+
cmap: Colormap to use (default: 'viridis')
|
|
790
|
+
vmin: Minimum value for colormap scaling (default: None)
|
|
791
|
+
vmax: Maximum value for colormap scaling (default: None)
|
|
792
|
+
alpha: Transparency of the grid overlay (default: 0.6)
|
|
793
|
+
figsize: Figure size in inches (default: (12, 8))
|
|
794
|
+
basemap: Basemap style (default: 'CartoDB light')
|
|
795
|
+
show_edge: Whether to show cell edges (default: False)
|
|
796
|
+
edge_color: Color of cell edges (default: 'black')
|
|
797
|
+
edge_width: Width of cell edges (default: 0.5)
|
|
798
|
+
"""
|
|
799
|
+
# Convert to Web Mercator if not already in that CRS
|
|
800
|
+
if gdf.crs != 'EPSG:3857':
|
|
801
|
+
gdf_web = gdf.to_crs(epsg=3857)
|
|
802
|
+
else:
|
|
803
|
+
gdf_web = gdf
|
|
804
|
+
|
|
805
|
+
# Create figure and axis
|
|
806
|
+
fig, ax = plt.subplots(figsize=figsize)
|
|
807
|
+
|
|
808
|
+
# Plot the GeoDataFrame
|
|
809
|
+
gdf_web.plot(column='value',
|
|
810
|
+
ax=ax,
|
|
811
|
+
alpha=alpha,
|
|
812
|
+
cmap=cmap,
|
|
813
|
+
vmin=vmin,
|
|
814
|
+
vmax=vmax,
|
|
815
|
+
legend=True,
|
|
816
|
+
legend_kwds={'label': value_name},
|
|
817
|
+
edgecolor=edge_color if show_edge else 'none',
|
|
818
|
+
linewidth=edge_width if show_edge else 0)
|
|
819
|
+
|
|
820
|
+
# Add basemap
|
|
821
|
+
basemaps = {
|
|
822
|
+
'CartoDB dark': ctx.providers.CartoDB.DarkMatter,
|
|
823
|
+
'CartoDB light': ctx.providers.CartoDB.Positron,
|
|
824
|
+
'CartoDB voyager': ctx.providers.CartoDB.Voyager,
|
|
825
|
+
'CartoDB light no labels': ctx.providers.CartoDB.PositronNoLabels,
|
|
826
|
+
'CartoDB dark no labels': ctx.providers.CartoDB.DarkMatterNoLabels,
|
|
827
|
+
}
|
|
828
|
+
ctx.add_basemap(ax, source=basemaps[basemap])
|
|
829
|
+
|
|
830
|
+
# Set title and remove axes
|
|
831
|
+
ax.set_axis_off()
|
|
832
|
+
|
|
833
|
+
plt.tight_layout()
|
|
834
|
+
plt.show()
|
|
835
|
+
|
|
836
|
+
def visualize_point_grid_on_basemap(point_gdf, value_name='value', **kwargs):
|
|
837
|
+
"""Visualizes a point GeoDataFrame on a basemap with colors based on values.
|
|
838
|
+
|
|
839
|
+
Args:
|
|
840
|
+
point_gdf: GeoDataFrame with point geometries and values
|
|
841
|
+
value_name: Name of the column containing values to visualize (default: 'value')
|
|
842
|
+
**kwargs: Optional visualization parameters including:
|
|
843
|
+
- figsize: Tuple for figure size (default: (12, 8))
|
|
844
|
+
- colormap: Matplotlib colormap name (default: 'viridis')
|
|
845
|
+
- markersize: Size of points (default: 20)
|
|
846
|
+
- alpha: Transparency of points (default: 0.7)
|
|
847
|
+
- vmin: Minimum value for colormap scaling (default: None)
|
|
848
|
+
- vmax: Maximum value for colormap scaling (default: None)
|
|
849
|
+
- title: Plot title (default: None)
|
|
850
|
+
- basemap_style: Contextily basemap style (default: CartoDB.Positron)
|
|
851
|
+
- zoom: Basemap zoom level (default: 15)
|
|
852
|
+
|
|
853
|
+
Returns:
|
|
854
|
+
matplotlib figure and axis objects
|
|
855
|
+
"""
|
|
856
|
+
import matplotlib.pyplot as plt
|
|
857
|
+
import contextily as ctx
|
|
858
|
+
|
|
859
|
+
# Set default parameters
|
|
860
|
+
defaults = {
|
|
861
|
+
'figsize': (12, 8),
|
|
862
|
+
'colormap': 'viridis',
|
|
863
|
+
'markersize': 20,
|
|
864
|
+
'alpha': 0.7,
|
|
865
|
+
'vmin': None,
|
|
866
|
+
'vmax': None,
|
|
867
|
+
'title': None,
|
|
868
|
+
'basemap_style': ctx.providers.CartoDB.Positron,
|
|
869
|
+
'zoom': 15
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
# Update defaults with provided kwargs
|
|
873
|
+
settings = {**defaults, **kwargs}
|
|
874
|
+
|
|
875
|
+
# Create figure and axis
|
|
876
|
+
fig, ax = plt.subplots(figsize=settings['figsize'])
|
|
877
|
+
|
|
878
|
+
# Convert to Web Mercator for basemap compatibility
|
|
879
|
+
point_gdf_web = point_gdf.to_crs(epsg=3857)
|
|
880
|
+
|
|
881
|
+
# Plot points
|
|
882
|
+
scatter = point_gdf_web.plot(
|
|
883
|
+
column=value_name,
|
|
884
|
+
ax=ax,
|
|
885
|
+
cmap=settings['colormap'],
|
|
886
|
+
markersize=settings['markersize'],
|
|
887
|
+
alpha=settings['alpha'],
|
|
888
|
+
vmin=settings['vmin'],
|
|
889
|
+
vmax=settings['vmax'],
|
|
890
|
+
legend=True,
|
|
891
|
+
legend_kwds={
|
|
892
|
+
'label': value_name,
|
|
893
|
+
'orientation': 'vertical',
|
|
894
|
+
'shrink': 0.8
|
|
895
|
+
}
|
|
896
|
+
)
|
|
897
|
+
|
|
898
|
+
# Add basemap
|
|
899
|
+
ctx.add_basemap(
|
|
900
|
+
ax,
|
|
901
|
+
source=settings['basemap_style'],
|
|
902
|
+
zoom=settings['zoom']
|
|
903
|
+
)
|
|
904
|
+
|
|
905
|
+
# Set title if provided
|
|
906
|
+
if settings['title']:
|
|
907
|
+
plt.title(settings['title'])
|
|
908
|
+
|
|
909
|
+
# Remove axes
|
|
910
|
+
ax.set_axis_off()
|
|
911
|
+
|
|
912
|
+
# Adjust layout to prevent colorbar cutoff
|
|
778
913
|
plt.tight_layout()
|
|
779
914
|
plt.show()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: voxcity
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.16
|
|
4
4
|
Summary: voxcity is an easy and one-stop tool to output 3d city models for microclimate simulation by integrating multiple geospatial open-data
|
|
5
5
|
Author-email: Kunihiko Fujiwara <kunihiko@nus.edu.sg>
|
|
6
6
|
Maintainer-email: Kunihiko Fujiwara <kunihiko@nus.edu.sg>
|
|
@@ -225,7 +225,7 @@ from voxcity import get_voxcity
|
|
|
225
225
|
|
|
226
226
|
voxcity_grid, building_height_grid, building_min_height_grid, \
|
|
227
227
|
building_id_grid, canopy_height_grid, land_cover_grid, dem_grid, \
|
|
228
|
-
|
|
228
|
+
building_gdf = get_voxcity(
|
|
229
229
|
rectangle_vertices,
|
|
230
230
|
building_source,
|
|
231
231
|
land_cover_source,
|
|
@@ -410,7 +410,7 @@ landmark_kwargs = {
|
|
|
410
410
|
"output_directory": "output", # Directory to save output files
|
|
411
411
|
"output_file_name": "landmark_visibility" # Base filename for outputs
|
|
412
412
|
}
|
|
413
|
-
landmark_vis_map = get_landmark_visibility_map(voxcity_grid, building_id_grid,
|
|
413
|
+
landmark_vis_map = get_landmark_visibility_map(voxcity_grid, building_id_grid, building_gdf, meshsize, **landmark_kwargs)
|
|
414
414
|
```
|
|
415
415
|
<p align="center">
|
|
416
416
|
<img src="https://raw.githubusercontent.com/kunifujiwara/VoxCity/main/images/landmark.png" alt="Landmark Visibility Map Rendered in Rhino" width="500">
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
voxcity/__init__.py,sha256=el9v3gfybHOF_GUYPeSOqN0-vCrTW0eU1mcvi0sEfeU,252
|
|
2
|
-
voxcity/generator.py,sha256=
|
|
2
|
+
voxcity/generator.py,sha256=3cr520doEAdoXasvdywiK0FOvIfh1YdALv4tlhFvbAk,33654
|
|
3
3
|
voxcity/downloader/__init__.py,sha256=OgGcGxOXF4tjcEL6DhOnt13DYPTvOigUelp5xIpTqM0,171
|
|
4
4
|
voxcity/downloader/eubucco.py,sha256=XCkkdEPNuWdrnuxzL80Ext37WsgiCiZGueb-aQV5rvI,14476
|
|
5
5
|
voxcity/downloader/gee.py,sha256=j7jmzp44T3M6j_4DwhU9Y8Y6gqbZo1zFIlduQPc0jvk,14339
|
|
@@ -14,8 +14,8 @@ voxcity/exporter/envimet.py,sha256=m-y2IYw-yp45AT2wN9UIlxvMjvDvupTKzyfRJl057fE,2
|
|
|
14
14
|
voxcity/exporter/magicavoxel.py,sha256=Fsv7yGRXeKmp82xcG3rOb0t_HtoqltNq2tHl08xVlqY,7500
|
|
15
15
|
voxcity/exporter/obj.py,sha256=oW-kPoZj53nfmO9tXP3Wvizq6Kkjh-QQR8UBexRuMiI,21609
|
|
16
16
|
voxcity/geoprocessor/__init_.py,sha256=FFJFf6idmAtmNkwfKPt3ERGSIzjb8tt35D1n9QQbCA8,112
|
|
17
|
-
voxcity/geoprocessor/draw.py,sha256=
|
|
18
|
-
voxcity/geoprocessor/grid.py,sha256=
|
|
17
|
+
voxcity/geoprocessor/draw.py,sha256=8Em2NvazFpYfFJUqG9LofNXaxdghKLL_rNuztmPwn8Q,13911
|
|
18
|
+
voxcity/geoprocessor/grid.py,sha256=aLb_iInDrhh5cacQOOtHPZ9IWFTWsQtF6hEgsA6TB2Y,43761
|
|
19
19
|
voxcity/geoprocessor/network.py,sha256=opb_kpUCAxDd1qtrWPStqR5reYZtVe96XxazNSen7Lk,18851
|
|
20
20
|
voxcity/geoprocessor/polygon.py,sha256=8fU2Ayu2Y_G1z7Mbj8KoSKVurdPuAVbASjGMVS36ftM,32249
|
|
21
21
|
voxcity/geoprocessor/utils.py,sha256=1BRHp-DDeOA8HG8jplY7Eo75G3oXkVGL6DGONL4BA8A,19815
|
|
@@ -26,11 +26,11 @@ voxcity/simulator/view.py,sha256=zNbfTLQ2Jo0V5-rFA3-xamRjOuw3H3MBrLKpQp8x3hY,367
|
|
|
26
26
|
voxcity/utils/__init_.py,sha256=nLYrj2huBbDBNMqfchCwexGP8Tlt9O_XluVDG7MoFkw,98
|
|
27
27
|
voxcity/utils/lc.py,sha256=RwPd-VY3POV3gTrBhM7TubgGb9MCd3nVah_G8iUEF7k,11562
|
|
28
28
|
voxcity/utils/material.py,sha256=Vt3IID5Ft54HNJcEC4zi31BCPqi_687X3CSp7rXaRVY,5907
|
|
29
|
-
voxcity/utils/visualization.py,sha256=
|
|
29
|
+
voxcity/utils/visualization.py,sha256=2bv3y-1zkUX0cm_YbMHwe_Vt9J2R3QhouaVAGNifQXg,36805
|
|
30
30
|
voxcity/utils/weather.py,sha256=P6s1y_EstBL1OGP_MR_6u3vr-t6Uawg8uDckJnoI7FI,21482
|
|
31
|
-
voxcity-0.3.
|
|
32
|
-
voxcity-0.3.
|
|
33
|
-
voxcity-0.3.
|
|
34
|
-
voxcity-0.3.
|
|
35
|
-
voxcity-0.3.
|
|
36
|
-
voxcity-0.3.
|
|
31
|
+
voxcity-0.3.16.dist-info/AUTHORS.rst,sha256=m82vkI5QokEGdcHof2OxK39lf81w1P58kG9ZNNAKS9U,175
|
|
32
|
+
voxcity-0.3.16.dist-info/LICENSE,sha256=-hGliOFiwUrUSoZiB5WF90xXGqinKyqiDI2t6hrnam8,1087
|
|
33
|
+
voxcity-0.3.16.dist-info/METADATA,sha256=d67Drf-UV5hy7212m7y3rPmqC-cZ8LwloyVYgwq3EsA,25114
|
|
34
|
+
voxcity-0.3.16.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
35
|
+
voxcity-0.3.16.dist-info/top_level.txt,sha256=00b2U-LKfDllt6RL1R33MXie5MvxzUFye0NGD96t_8I,8
|
|
36
|
+
voxcity-0.3.16.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|