Skip to content

Commit 269ff1a

Browse files
authored
Fix data paths and model passing in GIS examples (#177)
This commit addresses several of the remaining issues across the GIS examples: - Corrects data file paths in the population, rainfall, and urban growth models to use relative paths from the script directory. - Fixes the urban growth model by passing the model object to City and UrbanCell classes, as required by mesa-geo 0.8.0. - Updates the population model to pass the model object when creating agents, ensuring they can access Model variables and properties. - Corrects the use of `/vsigzip/` paths for GDAL compatibility. The `/vsigzip/` situation is super weird. It isn't part of the file path, but it's a "marker" a GDAL convention. See the PR message, mesa-geo#235 and https://gdal.org/user/virtual_file_systems.html#vsigzip-gzipped-file for more details.
1 parent bbf5ad2 commit 269ff1a

File tree

9 files changed

+51
-35
lines changed

9 files changed

+51
-35
lines changed

gis/geo_schelling/model.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import os
21
import random
2+
from pathlib import Path
33

44
import mesa
55
import mesa_geo as mg
66

7-
script_directory = os.path.dirname(os.path.abspath(__file__))
7+
script_directory = Path(__file__).resolve().parent
88

99

1010
class SchellingAgent(mg.GeoAgent):
@@ -70,9 +70,7 @@ def __init__(self, density=0.6, minority_pc=0.2, export_data=False):
7070

7171
# Set up the grid with patches for every NUTS region
7272
ac = mg.AgentCreator(SchellingAgent, model=self)
73-
data_path = os.path.join(
74-
script_directory, "data/nuts_rg_60M_2013_lvl_2.geojson"
75-
)
73+
data_path = script_directory / "data/nuts_rg_60M_2013_lvl_2.geojson"
7674
agents = ac.from_file(filename=data_path)
7775
self.space.add_agents(agents)
7876

gis/geo_schelling_points/geo_schelling_points/model.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import os
21
import random
32
import uuid
3+
from pathlib import Path
44

55
import mesa
66
import mesa_geo as mg
77

88
from .agents import PersonAgent, RegionAgent
99
from .space import Nuts2Eu
1010

11-
script_directory = os.path.dirname(os.path.abspath(__file__))
11+
script_directory = Path(__file__).resolve().parent
1212

1313

1414
class GeoSchellingPoints(mesa.Model):
@@ -27,9 +27,7 @@ def __init__(self, red_percentage=0.5, similarity_threshold=0.5):
2727

2828
# Set up the grid with patches for every NUTS region
2929
ac = mg.AgentCreator(RegionAgent, model=self)
30-
data_path = os.path.join(
31-
script_directory, "../data/nuts_rg_60M_2013_lvl_2.geojson"
32-
)
30+
data_path = script_directory / "../data/nuts_rg_60M_2013_lvl_2.geojson"
3331
regions = ac.from_file(data_path, unique_id="NUTS_ID")
3432
self.space.add_regions(regions)
3533

gis/geo_sir/model.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
import os
1+
from pathlib import Path
22

33
import mesa
44
import mesa_geo as mg
55
from shapely.geometry import Point
66

77
from .agents import NeighbourhoodAgent, PersonAgent
88

9-
script_directory = os.path.dirname(os.path.abspath(__file__))
9+
script_directory = Path(__file__).resolve().parent
1010

1111

1212
class GeoSir(mesa.Model):
1313
"""Model class for a simplistic infection model."""
1414

1515
# Geographical parameters for desired map
16-
geojson_regions = os.path.join(
17-
script_directory, "data/TorontoNeighbourhoods.geojson"
18-
)
16+
geojson_regions = script_directory / "data/TorontoNeighbourhoods.geojson"
1917
unique_id = "HOODNUM"
2018

2119
def __init__(

gis/population/population/model.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import math
22
import random
33
import uuid
4+
from pathlib import Path
45

56
import mesa
67
import mesa_geo as mg
@@ -9,6 +10,8 @@
910

1011
from .space import UgandaArea
1112

13+
script_directory = Path(__file__).resolve().parent
14+
1215

1316
class Person(mg.GeoAgent):
1417
MOBILITY_RANGE_X = 0.0
@@ -52,13 +55,18 @@ def step(self):
5255
class Population(mesa.Model):
5356
def __init__(
5457
self,
55-
population_gzip_file="data/popu.asc.gz",
56-
lake_zip_file="data/lake.zip",
57-
world_zip_file="data/clip.zip",
58+
population_gzip_file="../data/popu.asc.gz",
59+
lake_zip_file="../data/lake.zip",
60+
world_zip_file="../data/clip.zip",
5861
):
5962
super().__init__()
6063
self.space = UgandaArea(crs="epsg:4326")
61-
self.space.load_data(population_gzip_file, lake_zip_file, world_zip_file)
64+
self.space.load_data(
65+
script_directory / population_gzip_file,
66+
script_directory / lake_zip_file,
67+
script_directory / world_zip_file,
68+
model=self,
69+
)
6270
pixel_size_x, pixel_size_y = self.space.population_layer.resolution
6371
Person.MOBILITY_RANGE_X = pixel_size_x / 2.0
6472
Person.MOBILITY_RANGE_Y = pixel_size_y / 2.0

gis/population/population/space.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ class UgandaCell(Cell):
1414

1515
def __init__(
1616
self,
17+
model,
1718
pos: mesa.space.Coordinate | None = None,
1819
indices: mesa.space.Coordinate | None = None,
1920
):
20-
super().__init__(pos, indices)
21+
super().__init__(model, pos, indices)
2122
self.population = None
2223

2324
def step(self):
@@ -32,7 +33,7 @@ class UgandaArea(GeoSpace):
3233
def __init__(self, crs):
3334
super().__init__(crs=crs)
3435

35-
def load_data(self, population_gzip_file, lake_zip_file, world_zip_file):
36+
def load_data(self, population_gzip_file, lake_zip_file, world_zip_file, model):
3637
world_size = gpd.GeoDataFrame.from_file(world_zip_file)
3738
raster_layer = RasterLayer.from_file(
3839
f"/vsigzip/{population_gzip_file}",
@@ -43,7 +44,7 @@ def load_data(self, population_gzip_file, lake_zip_file, world_zip_file):
4344
raster_layer.total_bounds = world_size.total_bounds
4445
self.add_layer(raster_layer)
4546
self.lake = gpd.GeoDataFrame.from_file(lake_zip_file).geometry[0]
46-
self.add_agents(GeoAgent(uuid.uuid4().int, None, self.lake, self.crs))
47+
self.add_agents(GeoAgent(uuid.uuid4().int, model, self.lake, self.crs))
4748

4849
@property
4950
def population_layer(self):

gis/rainfall/rainfall/model.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import uuid
2+
from pathlib import Path
23

34
import mesa
45
import mesa_geo as mg
@@ -7,6 +8,8 @@
78

89
from .space import CraterLake
910

11+
script_directory = Path(__file__).resolve().parent
12+
1013

1114
class RaindropAgent(mg.GeoAgent):
1215
def __init__(self, unique_id, model, pos):
@@ -63,7 +66,7 @@ def __init__(self, rain_rate=500, water_height=5, export_data=False, num_steps=2
6366
self.export_data = export_data
6467
self.num_steps = num_steps
6568

66-
self.space = CraterLake(crs="epsg:4326", water_height=water_height)
69+
self.space = CraterLake(crs="epsg:4326", water_height=water_height, model=self)
6770
self.schedule = mesa.time.RandomActivation(self)
6871
self.datacollector = mesa.DataCollector(
6972
{
@@ -73,7 +76,8 @@ def __init__(self, rain_rate=500, water_height=5, export_data=False, num_steps=2
7376
}
7477
)
7578

76-
self.space.set_elevation_layer("data/elevation.asc.gz", crs="epsg:4326")
79+
data_path = script_directory / "../data/elevation.asc.gz"
80+
self.space.set_elevation_layer(data_path, crs="epsg:4326")
7781

7882
@property
7983
def contained(self):

gis/rainfall/rainfall/space.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ class LakeCell(mg.Cell):
1212

1313
def __init__(
1414
self,
15+
model,
1516
pos: mesa.space.Coordinate | None = None,
1617
indices: mesa.space.Coordinate | None = None,
1718
):
18-
super().__init__(pos, indices)
19+
super().__init__(model, pos, indices)
1920
self.elevation = None
2021
self.water_level = None
2122
self.water_level_normalized = None
@@ -25,14 +26,17 @@ def step(self):
2526

2627

2728
class CraterLake(mg.GeoSpace):
28-
def __init__(self, crs, water_height):
29+
def __init__(self, crs, water_height, model):
2930
super().__init__(crs=crs)
31+
self.model = model
3032
self.water_height = water_height
3133
self.outflow = 0
3234

3335
def set_elevation_layer(self, elevation_gzip_file, crs):
3436
raster_layer = mg.RasterLayer.from_file(
35-
f"/vsigzip/{elevation_gzip_file}", cell_cls=LakeCell, attr_name="elevation"
37+
f"/vsigzip/{elevation_gzip_file}",
38+
cell_cls=LakeCell,
39+
attr_name="elevation",
3640
)
3741
raster_layer.crs = crs
3842
raster_layer.apply_raster(

gis/urban_growth/urban_growth/model.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
from pathlib import Path
2+
13
import mesa
24
import numpy as np
35

46
from .space import City
57

8+
script_directory = Path(__file__).resolve().parent
9+
610

711
class UrbanGrowth(mesa.Model):
812
def __init__(
@@ -64,14 +68,14 @@ def _load_data(self) -> None:
6468
width=self.world_width,
6569
height=self.world_height,
6670
crs="epsg:3857",
71+
model=self,
6772
total_bounds=[-901575.0, 1442925.0, -885645.0, 1454745.0],
6873
)
74+
75+
labels = ["urban", "slope", "road1", "excluded", "landuse"]
76+
6977
self.space.load_datasets(
70-
urban_data="data/urban_santafe.asc.gz",
71-
slope_data="data/slope_santafe.asc.gz",
72-
road_data="data/road1_santafe.asc.gz",
73-
excluded_data="data/excluded_santafe.asc.gz",
74-
land_use_data="data/landuse_santafe.asc.gz",
78+
*(script_directory / f"../data/{label}_santafe.asc.gz" for label in labels)
7579
)
7680

7781
def _check_suitability(self) -> None:

gis/urban_growth/urban_growth/space.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ class UrbanCell(mg.Cell):
2626

2727
def __init__(
2828
self,
29+
model: mesa.Model | None = None,
2930
pos: mesa.space.Coordinate | None = None,
3031
indices: mesa.space.Coordinate | None = None,
3132
):
32-
super().__init__(pos, indices)
33+
super().__init__(model, pos, indices)
3334
self.urban = None
3435
self.slope = None
3536
self.road_1 = None
@@ -78,10 +79,10 @@ def _edge_growth(self) -> None:
7879

7980

8081
class City(mg.GeoSpace):
81-
def __init__(self, width, height, crs, total_bounds):
82+
def __init__(self, width, height, crs, total_bounds, model):
8283
super().__init__(crs=crs)
8384
self.add_layer(
84-
mg.RasterLayer(width, height, crs, total_bounds, cell_cls=UrbanCell)
85+
mg.RasterLayer(width, height, crs, total_bounds, model, cell_cls=UrbanCell)
8586
)
8687

8788
def load_datasets(

0 commit comments

Comments
 (0)