voxcity 0.4.1__tar.gz → 0.4.2__tar.gz

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.
Files changed (53) hide show
  1. {voxcity-0.4.1 → voxcity-0.4.2}/PKG-INFO +1 -1
  2. {voxcity-0.4.1 → voxcity-0.4.2}/pyproject.toml +1 -1
  3. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/utils/visualization.py +23 -10
  4. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/utils/weather.py +98 -5
  5. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity.egg-info/PKG-INFO +1 -1
  6. {voxcity-0.4.1 → voxcity-0.4.2}/AUTHORS.rst +0 -0
  7. {voxcity-0.4.1 → voxcity-0.4.2}/CONTRIBUTING.rst +0 -0
  8. {voxcity-0.4.1 → voxcity-0.4.2}/HISTORY.rst +0 -0
  9. {voxcity-0.4.1 → voxcity-0.4.2}/LICENSE +0 -0
  10. {voxcity-0.4.1 → voxcity-0.4.2}/MANIFEST.in +0 -0
  11. {voxcity-0.4.1 → voxcity-0.4.2}/README.md +0 -0
  12. {voxcity-0.4.1 → voxcity-0.4.2}/docs/Makefile +0 -0
  13. {voxcity-0.4.1 → voxcity-0.4.2}/docs/archive/README.rst +0 -0
  14. {voxcity-0.4.1 → voxcity-0.4.2}/docs/authors.rst +0 -0
  15. {voxcity-0.4.1 → voxcity-0.4.2}/docs/conf.py +0 -0
  16. {voxcity-0.4.1 → voxcity-0.4.2}/docs/index.rst +0 -0
  17. {voxcity-0.4.1 → voxcity-0.4.2}/docs/make.bat +0 -0
  18. {voxcity-0.4.1 → voxcity-0.4.2}/setup.cfg +0 -0
  19. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/__init__.py +0 -0
  20. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/__init__.py +0 -0
  21. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/eubucco.py +0 -0
  22. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/gee.py +0 -0
  23. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/mbfp.py +0 -0
  24. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/oemj.py +0 -0
  25. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/omt.py +0 -0
  26. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/osm.py +0 -0
  27. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/overture.py +0 -0
  28. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/downloader/utils.py +0 -0
  29. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/exporter/__init_.py +0 -0
  30. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/exporter/envimet.py +0 -0
  31. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/exporter/magicavoxel.py +0 -0
  32. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/exporter/obj.py +0 -0
  33. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/generator.py +0 -0
  34. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/__init_.py +0 -0
  35. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/draw.py +0 -0
  36. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/grid.py +0 -0
  37. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/mesh.py +0 -0
  38. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/network.py +0 -0
  39. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/polygon.py +0 -0
  40. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/geoprocessor/utils.py +0 -0
  41. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/simulator/__init_.py +0 -0
  42. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/simulator/solar.py +0 -0
  43. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/simulator/utils.py +0 -0
  44. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/simulator/view.py +0 -0
  45. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/utils/__init_.py +0 -0
  46. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/utils/lc.py +0 -0
  47. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity/utils/material.py +0 -0
  48. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity.egg-info/SOURCES.txt +0 -0
  49. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity.egg-info/dependency_links.txt +0 -0
  50. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity.egg-info/requires.txt +0 -0
  51. {voxcity-0.4.1 → voxcity-0.4.2}/src/voxcity.egg-info/top_level.txt +0 -0
  52. {voxcity-0.4.1 → voxcity-0.4.2}/tests/__init__.py +0 -0
  53. {voxcity-0.4.1 → voxcity-0.4.2}/tests/voxelcity.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: voxcity
3
- Version: 0.4.1
3
+ Version: 0.4.2
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>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "voxcity"
3
- version = "0.4.01"
3
+ version = "0.4.02"
4
4
  requires-python = ">=3.10,<3.13"
5
5
  classifiers = [
6
6
  "Programming Language :: Python :: 3.10",
@@ -1811,6 +1811,18 @@ def visualize_voxcity_with_sim_meshes(voxel_array, meshsize, custom_meshes=None,
1811
1811
  # Create a copy with colors
1812
1812
  vis_mesh = custom_mesh.copy()
1813
1813
  vis_mesh.visual.face_colors = face_colors
1814
+
1815
+ # Prepare the colormap and create colorbar
1816
+ norm = mcolors.Normalize(vmin=local_vmin, vmax=local_vmax)
1817
+ scalar_map = cm.ScalarMappable(norm=norm, cmap=cmap_name)
1818
+
1819
+ # Create a figure and axis for the colorbar but don't display
1820
+ fig, ax = plt.subplots(figsize=(6, 1))
1821
+ cbar = plt.colorbar(scalar_map, cax=ax, orientation='horizontal')
1822
+ if colorbar_title:
1823
+ cbar.set_label(colorbar_title)
1824
+ plt.tight_layout()
1825
+ plt.show()
1814
1826
 
1815
1827
  if class_id in meshes:
1816
1828
  print(f"Replacing voxel class {class_id} with colored custom simulation mesh")
@@ -1849,17 +1861,17 @@ def visualize_voxcity_with_sim_meshes(voxel_array, meshsize, custom_meshes=None,
1849
1861
  if sim_mesh is not None:
1850
1862
  meshes["sim_surface"] = sim_mesh
1851
1863
 
1852
- # Prepare the colormap and create colorbar
1853
- norm = mcolors.Normalize(vmin=vmin, vmax=vmax)
1854
- scalar_map = cm.ScalarMappable(norm=norm, cmap=cmap_name)
1864
+ # # Prepare the colormap and create colorbar
1865
+ # norm = mcolors.Normalize(vmin=vmin, vmax=vmax)
1866
+ # scalar_map = cm.ScalarMappable(norm=norm, cmap=cmap_name)
1855
1867
 
1856
- # Create a figure and axis for the colorbar but don't display
1857
- fig, ax = plt.subplots(figsize=(6, 1))
1858
- cbar = plt.colorbar(scalar_map, cax=ax, orientation='horizontal')
1859
- if colorbar_title:
1860
- cbar.set_label(colorbar_title)
1861
- plt.tight_layout()
1862
- plt.show()
1868
+ # # Create a figure and axis for the colorbar but don't display
1869
+ # fig, ax = plt.subplots(figsize=(6, 1))
1870
+ # cbar = plt.colorbar(scalar_map, cax=ax, orientation='horizontal')
1871
+ # if colorbar_title:
1872
+ # cbar.set_label(colorbar_title)
1873
+ # plt.tight_layout()
1874
+ # plt.show()
1863
1875
 
1864
1876
  # Export if filename provided
1865
1877
  if base_filename is not None:
@@ -1868,6 +1880,7 @@ def visualize_voxcity_with_sim_meshes(voxel_array, meshsize, custom_meshes=None,
1868
1880
  os.makedirs(output_directory, exist_ok=True)
1869
1881
  export_meshes(meshes, output_directory, base_filename)
1870
1882
 
1883
+
1871
1884
  # Create and save multiple views
1872
1885
  print("Creating multiple views...")
1873
1886
  # Create output directory if it doesn't exist
@@ -164,7 +164,7 @@ def process_epw(epw_path: Union[str, Path]) -> Tuple[pd.DataFrame, Dict]:
164
164
  return df, headers
165
165
 
166
166
  def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float, output_dir: str = "./", max_distance: Optional[float] = None,
167
- extract_zip: bool = True, load_data: bool = True) -> Tuple[Optional[str], Optional[pd.DataFrame], Optional[Dict]]:
167
+ extract_zip: bool = True, load_data: bool = True, region: Optional[Union[str, List[str]]] = None) -> Tuple[Optional[str], Optional[pd.DataFrame], Optional[Dict]]:
168
168
  """
169
169
  Download and process EPW weather file from Climate.OneBuilding.Org based on coordinates.
170
170
 
@@ -175,6 +175,8 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
175
175
  max_distance (float, optional): Maximum distance in kilometers to search for stations
176
176
  extract_zip (bool): Whether to extract the ZIP file (default True)
177
177
  load_data (bool): Whether to load the EPW data into a DataFrame (default True)
178
+ region (str or List[str], optional): Specific region(s) to scan for stations (e.g., "Asia", ["Europe", "Africa"])
179
+ If None, will auto-detect region based on coordinates.
178
180
 
179
181
  Returns:
180
182
  Tuple containing:
@@ -197,6 +199,66 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
197
199
  "Europe": "https://climate.onebuilding.org/sources/Region6_Europe_TMYx_EPW_Processing_locations.kml",
198
200
  "Antarctica": "https://climate.onebuilding.org/sources/Region7_Antarctica_TMYx_EPW_Processing_locations.kml"
199
201
  }
202
+
203
+ # Define approximate geographical boundaries for regions
204
+ REGION_BOUNDS = {
205
+ "Africa": {"lon_min": -20, "lon_max": 55, "lat_min": -35, "lat_max": 40},
206
+ "Asia": {"lon_min": 25, "lon_max": 150, "lat_min": 0, "lat_max": 55},
207
+ "Japan": {"lon_min": 127, "lon_max": 146, "lat_min": 24, "lat_max": 46},
208
+ "India": {"lon_min": 68, "lon_max": 97, "lat_min": 6, "lat_max": 36},
209
+ "Argentina": {"lon_min": -75, "lon_max": -53, "lat_min": -55, "lat_max": -22},
210
+ "Canada": {"lon_min": -141, "lon_max": -52, "lat_min": 42, "lat_max": 83},
211
+ "USA": {"lon_min": -170, "lon_max": -65, "lat_min": 20, "lat_max": 72},
212
+ "Caribbean": {"lon_min": -90, "lon_max": -59, "lat_min": 10, "lat_max": 27},
213
+ "Southwest_Pacific": {"lon_min": 110, "lon_max": 180, "lat_min": -50, "lat_max": 0},
214
+ "Europe": {"lon_min": -25, "lon_max": 40, "lat_min": 35, "lat_max": 72},
215
+ "Antarctica": {"lon_min": -180, "lon_max": 180, "lat_min": -90, "lat_max": -60}
216
+ }
217
+
218
+ def detect_regions(lon: float, lat: float) -> List[str]:
219
+ """Detect which region(s) the coordinates belong to."""
220
+ matching_regions = []
221
+
222
+ # Handle special case of longitude wrap around 180/-180
223
+ lon_adjusted = lon
224
+ if lon < -180:
225
+ lon_adjusted = lon + 360
226
+ elif lon > 180:
227
+ lon_adjusted = lon - 360
228
+
229
+ for region_name, bounds in REGION_BOUNDS.items():
230
+ # Check if point is within region bounds
231
+ if (bounds["lon_min"] <= lon_adjusted <= bounds["lon_max"] and
232
+ bounds["lat_min"] <= lat <= bounds["lat_max"]):
233
+ matching_regions.append(region_name)
234
+
235
+ # If no regions matched, check the closest regions
236
+ if not matching_regions:
237
+ # Calculate "distance" to each region's boundary (simplified)
238
+ region_distances = []
239
+ for region_name, bounds in REGION_BOUNDS.items():
240
+ # Calculate distance to closest edge of region bounds
241
+ lon_dist = 0
242
+ if lon_adjusted < bounds["lon_min"]:
243
+ lon_dist = bounds["lon_min"] - lon_adjusted
244
+ elif lon_adjusted > bounds["lon_max"]:
245
+ lon_dist = lon_adjusted - bounds["lon_max"]
246
+
247
+ lat_dist = 0
248
+ if lat < bounds["lat_min"]:
249
+ lat_dist = bounds["lat_min"] - lat
250
+ elif lat > bounds["lat_max"]:
251
+ lat_dist = lat - bounds["lat_max"]
252
+
253
+ # Simple distance metric (not actual distance)
254
+ distance = (lon_dist**2 + lat_dist**2)**0.5
255
+ region_distances.append((region_name, distance))
256
+
257
+ # Get 3 closest regions
258
+ closest_regions = sorted(region_distances, key=lambda x: x[1])[:3]
259
+ matching_regions = [r[0] for r in closest_regions]
260
+
261
+ return matching_regions
200
262
 
201
263
  def try_decode(content: bytes) -> str:
202
264
  """Try different encodings to decode content."""
@@ -353,15 +415,46 @@ def get_nearest_epw_from_climate_onebuilding(longitude: float, latitude: float,
353
415
  # Create output directory if it doesn't exist
354
416
  Path(output_dir).mkdir(parents=True, exist_ok=True)
355
417
 
356
- # Get stations from all KML sources
418
+ # Determine which regions to scan
419
+ regions_to_scan = {}
420
+ if region is None:
421
+ # Auto-detect regions based on coordinates
422
+ detected_regions = detect_regions(longitude, latitude)
423
+
424
+ if detected_regions:
425
+ print(f"Auto-detected regions: {', '.join(detected_regions)}")
426
+ for r in detected_regions:
427
+ regions_to_scan[r] = KML_SOURCES[r]
428
+ else:
429
+ # Fallback to all regions if detection fails
430
+ print("Could not determine region from coordinates. Scanning all regions.")
431
+ regions_to_scan = KML_SOURCES
432
+ elif isinstance(region, str):
433
+ # Handle string input
434
+ if region.lower() == "all":
435
+ regions_to_scan = KML_SOURCES
436
+ elif region in KML_SOURCES:
437
+ regions_to_scan[region] = KML_SOURCES[region]
438
+ else:
439
+ valid_regions = ", ".join(KML_SOURCES.keys())
440
+ raise ValueError(f"Invalid region: '{region}'. Valid regions are: {valid_regions}")
441
+ else:
442
+ # Handle list input
443
+ for r in region:
444
+ if r not in KML_SOURCES:
445
+ valid_regions = ", ".join(KML_SOURCES.keys())
446
+ raise ValueError(f"Invalid region: '{r}'. Valid regions are: {valid_regions}")
447
+ regions_to_scan[r] = KML_SOURCES[r]
448
+
449
+ # Get stations from selected KML sources
357
450
  print("Fetching weather station data from Climate.OneBuilding.Org...")
358
451
  all_stations = []
359
452
 
360
- for region, url in KML_SOURCES.items():
361
- print(f"Scanning {region}...")
453
+ for region_name, url in regions_to_scan.items():
454
+ print(f"Scanning {region_name}...")
362
455
  stations = get_stations_from_kml(url)
363
456
  all_stations.extend(stations)
364
- print(f"Found {len(stations)} stations in {region}")
457
+ print(f"Found {len(stations)} stations in {region_name}")
365
458
 
366
459
  print(f"\nTotal stations found: {len(all_stations)}")
367
460
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: voxcity
3
- Version: 0.4.1
3
+ Version: 0.4.2
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>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes