diff --git a/docs/tutorials/intro_tutorial.ipynb b/docs/tutorials/intro_tutorial.ipynb index 48aac386..5087d017 100644 --- a/docs/tutorials/intro_tutorial.ipynb +++ b/docs/tutorials/intro_tutorial.ipynb @@ -49,8 +49,8 @@ "metadata": {}, "outputs": [], "source": [ - "#Run this if in colab or if you need to install mesa and mesa-geo in your local environment. \n", - "!pip install mesa-geo --quiet\n", + "# Run this if in colab or if you need to install mesa and mesa-geo in your local environment.\n", + "!pip install -U --pre mesa-geo --quiet\n", "!mkdir -p data\n", "!wget -P data https://raw.githubusercontent.com/projectmesa/mesa-geo/main/docs/tutorials/data/TorontoNeighbourhoods.geojson" ] @@ -97,8 +97,9 @@ "from shapely.geometry import Point\n", "\n", "import mesa\n", + "from mesa.visualization import SolaraViz, make_plot_measure\n", "import mesa_geo as mg\n", - "import mesa_geo.visualization as mgv # the warning that appears from Solara is fixed in Mesa 3.0 you can install the pre-release with pip install -U --pre-mesa\n" + "from mesa_geo.visualization import make_geospace_leaflet" ] }, { @@ -166,21 +167,21 @@ " mobility_range,\n", " infection_risk,\n", " recovery_rate,\n", - " death_risk\n", + " death_risk,\n", " ):\n", " super().__init__(model, geometry, crs)\n", " # Agent attributes\n", " self.atype = agent_type\n", " self.mobility_range = mobility_range\n", - " self.infection_risk=infection_risk,\n", + " self.infection_risk = infection_risk\n", " self.recovery_rate = recovery_rate\n", " self.death_risk = death_risk\n", "\n", " def __repr__(self):\n", " return f\"Person {self.unique_id}\"\n", "\n", - " def step(self): \n", - " print (repr(self))\n", + " def step(self):\n", + " print(repr(self))\n", " print(self.atype, self.death_risk, self.recovery_rate)" ] }, @@ -239,9 +240,7 @@ "class NeighbourhoodAgent(mg.GeoAgent):\n", " \"\"\"Neighbourhood agent. Changes color according to number of infected inside it.\"\"\"\n", "\n", - " def __init__(\n", - " self, model, geometry, crs, agent_type=\"safe\", hotspot_threshold=1\n", - " ):\n", + " def __init__(self, model, geometry, crs, agent_type=\"safe\", hotspot_threshold=1):\n", " super().__init__(model, geometry, crs)\n", " self.atype = agent_type\n", " self.hotspot_threshold = (\n", @@ -250,12 +249,10 @@ "\n", " def __repr__(self):\n", " return f\"Neighbourhood {self.HOODNUM}\"\n", - " \n", + "\n", " def step(self):\n", " \"\"\"Advance agent one step.\"\"\"\n", - " print(repr(self))\n", - " \n", - " " + " print(repr(self))" ] }, { @@ -334,13 +331,18 @@ " geojson_regions = \"data/TorontoNeighbourhoods.geojson\"\n", "\n", " def __init__(\n", - " self, pop_size=30, mobility_range=500, init_infection=0.2, exposure_dist=500, max_infection_risk=0.2,\n", - " max_recovery_time=5\n", + " self,\n", + " pop_size=30,\n", + " mobility_range=500,\n", + " init_infection=0.2,\n", + " exposure_dist=500,\n", + " max_infection_risk=0.2,\n", + " max_recovery_time=5,\n", " ):\n", " super().__init__()\n", " self.schedule = mesa.time.RandomActivationByType(self)\n", " self.space = mg.GeoSpace(warn_crs_conversion=False)\n", - " \n", + "\n", " # SIR model parameters\n", " self.pop_size = pop_size\n", " self.mobility_range = mobility_range\n", @@ -352,56 +354,54 @@ " # Set up the Neighbourhood patches for every region in file\n", " ac = mg.AgentCreator(NeighbourhoodAgent, model=self)\n", " neighbourhood_agents = ac.from_file(self.geojson_regions)\n", - " \n", - " #Add neighbourhood agents to space\n", + "\n", + " # Add neighbourhood agents to space\n", " self.space.add_agents(neighbourhood_agents)\n", - " \n", - " #Add neighbourhood agents to scheduler \n", + "\n", + " # Add neighbourhood agents to scheduler\n", " for agent in neighbourhood_agents:\n", " self.schedule.add(agent)\n", - " \n", - " \n", + "\n", " # Generate random location, add agent to grid and scheduler\n", " for i in range(pop_size):\n", - " #assess if they are infected\n", - " if self.random.random() < self.initial_infection: \n", + " # assess if they are infected\n", + " if self.random.random() < self.initial_infection:\n", " agent_type = \"infected\"\n", - " else: \n", + " else:\n", " agent_type = \"susceptible\"\n", - " #determine movement range\n", - " mobility_range = self.random.randint(0,self.mobility_range) \n", - " #determine agent recovery rate\n", - " recover = self.random.randint(1,self.recovery_rate)\n", - " #determine agents infection risk\n", - " infection_risk = self.random.uniform(0,self.infection_risk)\n", - " #determine agent death probability \n", - " death_risk= self.random.random()\n", + " # determine movement range\n", + " mobility_range = self.random.randint(0, self.mobility_range)\n", + " # determine agent recovery rate\n", + " recover = self.random.randint(1, self.recovery_rate)\n", + " # determine agents infection risk\n", + " infection_risk = self.random.uniform(0, self.infection_risk)\n", + " # determine agent death probability\n", + " death_risk = self.random.random()\n", "\n", " # Generate PersonAgent population\n", " unique_person = mg.AgentCreator(\n", - " PersonAgent,\n", - " model=self,\n", - " crs=self.space.crs,\n", - " agent_kwargs={\"agent_type\": agent_type, \n", - " \"mobility_range\":mobility_range,\n", - " \"recovery_rate\":recover,\n", - " \"infection_risk\": infection_risk,\n", - " \"death_risk\": death_risk\n", - " }\n", + " PersonAgent,\n", + " model=self,\n", + " crs=self.space.crs,\n", + " agent_kwargs={\n", + " \"agent_type\": agent_type,\n", + " \"mobility_range\": mobility_range,\n", + " \"recovery_rate\": recover,\n", + " \"infection_risk\": infection_risk,\n", + " \"death_risk\": death_risk,\n", + " },\n", " )\n", - " \n", - " \n", + "\n", " x_home, y_home = self.find_home(neighbourhood_agents)\n", - " \n", + "\n", " this_person = unique_person.create_agent(Point(x_home, y_home))\n", " self.space.add_agents(this_person)\n", " self.schedule.add(this_person)\n", - " \n", - " \n", - " def find_home(self, neighbourhood_agents): \n", - " \"\"\" Find start location of agent \"\"\"\n", "\n", - " #identify location\n", + " def find_home(self, neighbourhood_agents):\n", + " \"\"\"Find start location of agent\"\"\"\n", + "\n", + " # identify location\n", " this_neighbourhood = self.random.randint(\n", " 0, len(neighbourhood_agents) - 1\n", " ) # Region where agent starts\n", @@ -418,10 +418,9 @@ "\n", " return this_x, this_y\n", "\n", - " \n", " def step(self):\n", " \"\"\"Run one step of the model.\"\"\"\n", - " self.schedule.step()\n" + " self.schedule.step()" ] }, { @@ -536,22 +535,22 @@ " mobility_range,\n", " infection_risk,\n", " recovery_rate,\n", - " death_risk\n", + " death_risk,\n", " ):\n", " super().__init__(model, geometry, crs)\n", " # Agent attributes\n", " self.atype = agent_type\n", " self.mobility_range = mobility_range\n", - " self.infection_risk=infection_risk,\n", + " self.infection_risk = (infection_risk,)\n", " self.recovery_rate = recovery_rate\n", " self.death_risk = death_risk\n", - " self.steps_infected=0\n", + " self.steps_infected = 0\n", " self.steps_recovered = 0\n", "\n", " def __repr__(self):\n", " return f\"Person {self.unique_id}\"\n", "\n", - " #Helper function for moving agent\n", + " # Helper function for moving agent\n", " def move_point(self, dx, dy):\n", " \"\"\"\n", " Move a point by creating a new one\n", @@ -559,11 +558,10 @@ " :param dy: Distance to move in y-axis\n", " \"\"\"\n", " return Point(self.geometry.x + dx, self.geometry.y + dy)\n", - " \n", - " \n", - " def step(self): \n", "\n", - " #Part 1 - find neighbors based on infection distance\n", + " def step(self):\n", + "\n", + " # Part 1 - find neighbors based on infection distance\n", " if self.atype == \"susceptible\":\n", " neighbors = self.model.space.get_neighbors_within_distance(\n", " self, self.model.exposure_distance\n", @@ -574,9 +572,9 @@ " and self.random.random() < self.model.infection_risk\n", " ):\n", " self.atype = \"infected\"\n", - " break #stop process if agent becomes infected\n", + " break # stop process if agent becomes infected\n", "\n", - " #Part -2 If infected, check if agent recovers or agent dies\n", + " # Part -2 If infected, check if agent recovers or agent dies\n", " elif self.atype == \"infected\":\n", " if self.steps_infected >= self.recovery_rate:\n", " self.atype = \"recovered\"\n", @@ -587,12 +585,12 @@ " self.steps_infected += 1\n", "\n", " elif self.atype == \"recovered\":\n", - " self.steps_recovered+=1\n", - " if self.steps_recovered >=2: \n", - " self.atype= \"susceptible\"\n", + " self.steps_recovered += 1\n", + " if self.steps_recovered >= 2:\n", + " self.atype = \"susceptible\"\n", " self.steps_recovered = 0\n", - " \n", - " #Part 3 - If not dead, move\n", + "\n", + " # Part 3 - If not dead, move\n", " if self.atype != \"dead\":\n", " move_x = self.random.randint(-self.mobility_range, self.mobility_range)\n", " move_y = self.random.randint(-self.mobility_range, self.mobility_range)\n", @@ -636,9 +634,7 @@ "class NeighbourhoodAgent(mg.GeoAgent):\n", " \"\"\"Neighbourhood agent. Changes color according to number of infected inside it.\"\"\"\n", "\n", - " def __init__(\n", - " self, model, geometry, crs, agent_type=\"safe\", hotspot_threshold=1\n", - " ):\n", + " def __init__(self, model, geometry, crs, agent_type=\"safe\", hotspot_threshold=1):\n", " super().__init__(model, geometry, crs)\n", " self.atype = agent_type\n", " self.hotspot_threshold = (\n", @@ -647,7 +643,7 @@ "\n", " def __repr__(self):\n", " return f\"Neighbourhood {self.unique_id}\"\n", - " \n", + "\n", " def color_hotspot(self):\n", " # Decide if this region agent is a hot-spot\n", " # (if more than threshold person agents are infected)\n", @@ -659,7 +655,7 @@ " self.atype = \"hotspot\"\n", " else:\n", " self.atype = \"safe\"\n", - " \n", + "\n", " def step(self):\n", " \"\"\"Advance agent one step.\"\"\"\n", " self.color_hotspot()\n", @@ -716,10 +712,12 @@ "def get_dead_count(model):\n", " return model.counts[\"dead\"]\n", "\n", - "def get_hotspot_count(model): \n", + "\n", + "def get_hotspot_count(model):\n", " return model.counts[\"hotspot\"]\n", "\n", - "def get_safe_count(model): \n", + "\n", + "def get_safe_count(model):\n", " return model.counts[\"safe\"]" ] }, @@ -759,18 +757,23 @@ " geojson_regions = \"data/TorontoNeighbourhoods.geojson\"\n", "\n", " def __init__(\n", - " self, pop_size=30, mobility_range=500, init_infection=0.2, exposure_dist=500, max_infection_risk=0.2,\n", - " max_recovery_time=5\n", + " self,\n", + " pop_size=30,\n", + " mobility_range=500,\n", + " init_infection=0.2,\n", + " exposure_dist=500,\n", + " max_infection_risk=0.2,\n", + " max_recovery_time=5,\n", " ):\n", " super().__init__()\n", - " #Scheduler\n", + " # Scheduler\n", " self.schedule = mesa.time.RandomActivationByType(self)\n", - " #Space\n", + " # Space\n", " self.space = mg.GeoSpace(warn_crs_conversion=False)\n", " # Data Collection\n", - " self.counts = None #added\n", - " self.reset_counts() #added\n", - " \n", + " self.counts = None # added\n", + " self.reset_counts() # added\n", + "\n", " # SIR model parameters\n", " self.pop_size = pop_size\n", " self.mobility_range = mobility_range\n", @@ -778,72 +781,70 @@ " self.exposure_distance = exposure_dist\n", " self.infection_risk = max_infection_risk\n", " self.recovery_rate = max_recovery_time\n", - " self.running = True #added\n", - " #added\n", + " self.running = True # added\n", + " # added\n", " self.datacollector = mesa.DataCollector(\n", " {\n", " \"infected\": get_infected_count,\n", " \"susceptible\": get_susceptible_count,\n", " \"recovered\": get_recovered_count,\n", " \"dead\": get_dead_count,\n", - " \"safe\": get_safe_count, \n", - " \"hotspot\": get_hotspot_count\n", + " \"safe\": get_safe_count,\n", + " \"hotspot\": get_hotspot_count,\n", " }\n", " )\n", - " \n", + "\n", " # Set up the Neighbourhood patches for every region in file\n", " ac = mg.AgentCreator(NeighbourhoodAgent, model=self)\n", " neighbourhood_agents = ac.from_file(self.geojson_regions)\n", - " \n", - " #Add neighbourhood agents to space\n", + "\n", + " # Add neighbourhood agents to space\n", " self.space.add_agents(neighbourhood_agents)\n", - " \n", - " #Add neighbourhood agents to scheduler \n", + "\n", + " # Add neighbourhood agents to scheduler\n", " for agent in neighbourhood_agents:\n", " self.schedule.add(agent)\n", - " \n", - " \n", + "\n", " # Generate random location, add agent to grid and scheduler\n", " for i in range(pop_size):\n", - " #assess if they are infected\n", - " if self.random.random() < self.initial_infection: \n", + " # assess if they are infected\n", + " if self.random.random() < self.initial_infection:\n", " agent_type = \"infected\"\n", - " else: \n", + " else:\n", " agent_type = \"susceptible\"\n", - " #determine movement range\n", - " mobility_range = self.random.randint(0,self.mobility_range) \n", - " #determine agent recovery rate\n", - " recover = self.random.randint(1,self.recovery_rate)\n", - " #determine agents infection risk\n", - " infection_risk = self.random.uniform(0,self.infection_risk)\n", - " #determine agent death probability \n", - " death_risk= self.random.uniform(0,0.05)\n", + " # determine movement range\n", + " mobility_range = self.random.randint(0, self.mobility_range)\n", + " # determine agent recovery rate\n", + " recover = self.random.randint(1, self.recovery_rate)\n", + " # determine agents infection risk\n", + " infection_risk = self.random.uniform(0, self.infection_risk)\n", + " # determine agent death probability\n", + " death_risk = self.random.uniform(0, 0.05)\n", "\n", " # Generate PersonAgent population\n", " unique_person = mg.AgentCreator(\n", - " PersonAgent,\n", - " model=self,\n", - " crs=self.space.crs,\n", - " agent_kwargs={\"agent_type\": agent_type, \n", - " \"mobility_range\":mobility_range,\n", - " \"recovery_rate\":recover,\n", - " \"infection_risk\": infection_risk,\n", - " \"death_risk\": death_risk\n", - " }\n", + " PersonAgent,\n", + " model=self,\n", + " crs=self.space.crs,\n", + " agent_kwargs={\n", + " \"agent_type\": agent_type,\n", + " \"mobility_range\": mobility_range,\n", + " \"recovery_rate\": recover,\n", + " \"infection_risk\": infection_risk,\n", + " \"death_risk\": death_risk,\n", + " },\n", " )\n", - " \n", - " \n", + "\n", " x_home, y_home = self.find_home(neighbourhood_agents)\n", - " \n", + "\n", " this_person = unique_person.create_agent(Point(x_home, y_home))\n", " self.space.add_agents(this_person)\n", " self.schedule.add(this_person)\n", - " \n", - " \n", - " def find_home(self, neighbourhood_agents): \n", - " \"\"\" Find start location of agent \"\"\"\n", "\n", - " #identify location\n", + " def find_home(self, neighbourhood_agents):\n", + " \"\"\"Find start location of agent\"\"\"\n", + "\n", + " # identify location\n", " this_neighbourhood = self.random.randint(\n", " 0, len(neighbourhood_agents) - 1\n", " ) # Region where agent starts\n", @@ -859,8 +860,8 @@ " this_y = center_y[0] + self.random.randint(0, spread_y) - spread_y / 2\n", "\n", " return this_x, this_y\n", - " \n", - " #added\n", + "\n", + " # added\n", " def reset_counts(self):\n", " self.counts = {\n", " \"susceptible\": 0,\n", @@ -869,22 +870,19 @@ " \"dead\": 0,\n", " \"safe\": 0,\n", " \"hotspot\": 0,\n", - " }\n", - " \n", - " \n", + " }\n", + "\n", " def step(self):\n", " \"\"\"Run one step of the model.\"\"\"\n", - " \n", - " self.reset_counts() #added\n", + "\n", + " self.reset_counts() # added\n", " self.schedule.step()\n", - " self.datacollector.collect(self) #added\n", + " self.datacollector.collect(self) # added\n", "\n", " # Run until no one is infected\n", - " if self.counts[\"infected\"] == 0 :\n", - " self.running = False\n" - ], - "outputs": [], - "execution_count": null + " if self.counts[\"infected\"] == 0:\n", + " self.running = False" + ] }, { "cell_type": "markdown", @@ -907,7 +905,7 @@ "outputs": [], "source": [ "model = GeoSIR()\n", - "for i in range(5): \n", + "for i in range(5):\n", " model.step()\n", "\n", "model.datacollector.get_model_vars_dataframe()" @@ -969,26 +967,27 @@ " Portrayal Method for canvas\n", " \"\"\"\n", " portrayal = {}\n", - " if isinstance(agent, PersonAgent): \n", + " if isinstance(agent, PersonAgent):\n", " if agent.atype == \"susceptible\":\n", " portrayal[\"color\"] = \"Green\"\n", " elif agent.atype == \"infected\":\n", " portrayal[\"color\"] = \"Red\"\n", " elif agent.atype == \"recovered\":\n", " portrayal[\"color\"] = \"Blue\"\n", - " else: \n", + " else:\n", " portrayal[\"marker_type\"] = \"AwesomeIcon\"\n", " portrayal[\"name\"] = \"times\"\n", " portrayal[\"icon_properties\"] = {\n", - " \"marker_color\": 'black',\n", - " \"icon_color\":'white'}\n", - " \n", + " \"marker_color\": \"black\",\n", + " \"icon_color\": \"white\",\n", + " }\n", + "\n", " if isinstance(agent, NeighbourhoodAgent):\n", " if agent.atype == \"hotspot\":\n", " portrayal[\"color\"] = \"Red\"\n", - " else: \n", + " else:\n", " portrayal[\"color\"] = \"Green\"\n", - " \n", + "\n", " return portrayal\n", "\n", "\n", @@ -998,17 +997,17 @@ " \"value\": 80,\n", " \"label\": \"Population Size\",\n", " \"min\": 0,\n", - " \"max\": 100, \n", + " \"max\": 100,\n", " \"step\": 1,\n", " },\n", - " \"mobility_range\": {\n", + " \"mobility_range\": {\n", " \"type\": \"SliderInt\",\n", " \"value\": 500,\n", " \"label\": \"Max Possible Agent Movement\",\n", " \"min\": 100,\n", - " \"max\": 1000, \n", + " \"max\": 1000,\n", " \"step\": 50,\n", - " },\n", + " },\n", " \"init_infection\": {\n", " \"type\": \"SliderFloat\",\n", " \"value\": 0.4,\n", @@ -1022,7 +1021,7 @@ " \"value\": 800,\n", " \"label\": \"Exposure Distance\",\n", " \"min\": 100,\n", - " \"max\": 1000, \n", + " \"max\": 1000,\n", " \"step\": 50,\n", " },\n", " \"max_infection_risk\": {\n", @@ -1031,16 +1030,17 @@ " \"label\": \"Maximum Infection Risk\",\n", " \"min\": 0.0,\n", " \"max\": 1.0,\n", - " \"step\": 0.1\n", + " \"step\": 0.1,\n", " },\n", - " \"max_recovery_time\": {\n", - " \"type\": \"SliderInt\",\n", - " \"value\": 7,\n", + " \"max_recovery_time\": {\n", + " \"type\": \"SliderInt\",\n", + " \"value\": 7,\n", " \"label\": \"Maximum Number of Steps to Recover\",\n", " \"min\": 1,\n", - " \"max\": 10, \n", - " \"step\": 1, \n", - " }}" + " \"max\": 10,\n", + " \"step\": 1,\n", + " },\n", + "}" ] }, { @@ -1056,37 +1056,24 @@ { "cell_type": "code", "execution_count": null, - "id": "daf1d216-0001-45c6-9527-450036d42764", - "metadata": { - "editable": true, - "has_explanation": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, + "id": "324cabe0-68be-4aab-a70d-10ffcd328114", + "metadata": {}, "outputs": [], "source": [ - "page = mgv.GeoJupyterViz(\n", - " GeoSIR,\n", - " model_params,\n", - " measures= [[\"infected\", \"susceptible\", \"recovered\", \"dead\"], [\"safe\", \"hotspot\"]],\n", + "model = GeoSIR()\n", + "page = SolaraViz(\n", + " model,\n", " name=\"GeoSIR\",\n", - " agent_portrayal=SIR_draw,\n", - " zoom=12,\n", - " scroll_wheel_zoom=False\n", + " model_params=model_params,\n", + " components=[\n", + " make_geospace_leaflet(SIR_draw, zoom=12, scroll_wheel_zoom=False),\n", + " make_plot_measure([\"infected\", \"susceptible\", \"recovered\", \"dead\"]),\n", + " make_plot_measure([\"safe\", \"hotspot\"]),\n", + " ],\n", ")\n", "# This is required to render the visualization in the Jupyter notebook\n", "page" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "324cabe0-68be-4aab-a70d-10ffcd328114", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -1105,7 +1092,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.5" + "version": "3.10.14" } }, "nbformat": 4,