diff --git a/docs/source/tutorials/intro_tutorial_colab.ipynb b/docs/source/tutorials/intro_tutorial_colab.ipynb index 2f735e6f..943d974f 100644 --- a/docs/source/tutorials/intro_tutorial_colab.ipynb +++ b/docs/source/tutorials/intro_tutorial_colab.ipynb @@ -1,324 +1,332 @@ { - "cells": [ - { - "cell_type": "markdown", - "id": "60542812-8cbe-498b-b689-b0d01c80c148", - "metadata": { - "explanatory": true - }, - "source": [ - "#explanatory\n", - "\n", - "This cell imports the necessary libraries we will need for this demonstration\n", - "\n", - "* **random** is imported for ...\n", - "* **mesa** imports core mesa to give us basic agentbased model functionality\n", - "* **mesa_geo** imports GIS functionality for agent based models\n", - "* **mesa_geo.experimental** is a sub-module of `mesa_geo` that will will import as mge so we do not have to write out `mesa_geo.experimental` everytime" - ] - }, - { - "cell_type": "markdown", - "id": "e72b67b0-df4a-42b8-be21-207911e0d04d", - "metadata": {}, - "source": [ - "# Introductory Tutorial\n", - "\n", - "This tutorial introduces Mesa-Geo, a GIS integrated Agent Based model platform that is part of the [Mesa ABM Ecosystem](https://mesa.readthedocs.io/en/stable/) \n", - "\n", - "In this tutorial we will build a Geo-Schelling model, which takes the seminal [Schelling Segregation model](https://en.wikipedia.org/wiki/Schelling%27s_model_of_segregation) and replicates with the countries of Europe, were the countries \"move\" their preference similar to the Schelling Model. \n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "35dbfaed-26a6-463a-a0f2-b26989e7e824", - "metadata": { - "has_explanation": false - }, - "outputs": [], - "source": [ - "!pip install mesa-geo --quiet\n", - "\n", - "import random\n", - "\n", - "import mesa\n", - "import mesa_geo as mg\n", - "import mesa_geo.visualization as mgv" - ] - }, - { - "cell_type": "markdown", - "id": "e5e2bee2-d440-43c7-81fb-01e6a817e5e5", - "metadata": {}, - "source": [ - "## Create the Agents\n", - "\n", - "The next cell creates the GeoAgents, in which European country is randomly assigned a preference of minority or majority and then if the agent is unhappy moves. " - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "27cac12c-515e-4ef4-83cc-d06918921c70", - "metadata": { - "has_explanation": false - }, - "outputs": [], - "source": [ - "class SchellingAgent(mg.GeoAgent):\n", - " \"\"\"Schelling segregation agent.\"\"\"\n", - "\n", - " def __init__(self, unique_id, model, geometry, crs, agent_type=None):\n", - " \"\"\"Create a new Schelling agent.\n", - "\n", - " Args:\n", - " unique_id: Unique identifier for the agent.\n", - " agent_type: Indicator for the agent's type (minority=1, majority=0)\n", - " \"\"\"\n", - " super().__init__(unique_id, model, geometry, crs)\n", - " self.atype = agent_type\n", - "\n", - " def step(self):\n", - " \"\"\"Advance agent one step.\"\"\"\n", - " similar = 0\n", - " different = 0\n", - " neighbors = self.model.space.get_neighbors(self)\n", - " if neighbors:\n", - " for neighbor in neighbors:\n", - " if neighbor.atype is None:\n", - " continue\n", - " elif neighbor.atype == self.atype:\n", - " similar += 1\n", - " else:\n", - " different += 1\n", - "\n", - " # If unhappy, move:\n", - " if similar < different:\n", - " # Select an empty region\n", - " empties = [a for a in self.model.space.agents if a.atype is None]\n", - " # Switch atypes and add/remove from scheduler\n", - " new_region = random.choice(empties)\n", - " new_region.atype = self.atype\n", - " self.model.schedule.add(new_region)\n", - " self.atype = None\n", - " self.model.schedule.remove(self)\n", - " else:\n", - " self.model.happy += 1\n", - "\n", - " def __repr__(self):\n", - " return \"Agent \" + str(self.unique_id)" - ] - }, - { - "cell_type": "markdown", - "id": "6eac24f2-af00-40bd-b146-1be7a66b1644", - "metadata": {}, - "source": [ - "## Model Class\n", - "\n", - "This class initiates the model class, which acts as a \"manager\" for the simulation, it holds the geo-spatial space. It holds the schedule of agents and their order, and the data collector to collect information from the model." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "9c9a9738-7e8f-458c-b0aa-cfc69c04ee87", - "metadata": { - "has_explanation": false, - "jupyter": { - "source_hidden": true - } - }, - "outputs": [], - "source": [ - "class GeoSchelling(mesa.Model):\n", - " \"\"\"Model class for the Schelling segregation model.\"\"\"\n", - "\n", - " def __init__(self, density=0.6, minority_pc=0.2, export_data=False):\n", - " super().__init__()\n", - " self.density = density\n", - " self.minority_pc = minority_pc\n", - " self.export_data = export_data\n", - "\n", - " self.schedule = mesa.time.RandomActivation(self)\n", - " self.space = mg.GeoSpace(crs=\"EPSG:4326\", warn_crs_conversion=True)\n", - "\n", - " self.happy = 0\n", - " self.datacollector = mesa.DataCollector({\"happy\": \"happy\"})\n", - "\n", - " self.running = True\n", - "\n", - " # Set up the grid with patches for every NUTS region\n", - " ac = mg.AgentCreator(SchellingAgent, model=self)\n", - " agents = ac.from_file(\"data/nuts_rg_60M_2013_lvl_2.geojson\")\n", - " self.space.add_agents(agents)\n", - "\n", - " # Set up agents\n", - " for agent in agents:\n", - " if random.random() < self.density:\n", - " if random.random() < self.minority_pc:\n", - " agent.atype = 1\n", - " else:\n", - " agent.atype = 0\n", - " self.schedule.add(agent)\n", - "\n", - " def export_agents_to_file(self) -> None:\n", - " self.space.get_agents_as_GeoDataFrame(agent_cls=SchellingAgent).to_crs(\n", - " \"epsg:4326\"\n", - " ).to_file(\"data/schelling_agents.geojson\", driver=\"GeoJSON\")\n", - "\n", - " def step(self):\n", - " \"\"\"Run one step of the model.\n", - "\n", - " If All agents are happy, halt the model.\n", - " \"\"\"\n", - "\n", - " self.happy = 0 # Reset counter of happy agents\n", - " self.schedule.step()\n", - " self.datacollector.collect(self)\n", - "\n", - " if self.happy == self.schedule.get_agent_count():\n", - " self.running = False\n", - "\n", - " if not self.running and self.export_data:\n", - " self.export_agents_to_file()" - ] - }, - { - "cell_type": "markdown", - "id": "3ed4ea12-4417-476e-bf6c-4a5f95871005", - "metadata": {}, - "source": [ - "## Build the Visual\n", - "\n", - "This section of code set ups the conditions for drawing the agents and defining the model parameters. The next cell passes the `schelling_draw` function and model parameters into Mesa Geo's `GeoJupyterViz` so we can see a visual for our simulation. " - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "0bf74b4c-36ab-416c-a4db-ab5104189d92", - "metadata": { - "has_explanation": false - }, - "outputs": [], - "source": [ - "def schelling_draw(agent):\n", - " \"\"\"\n", - " Portrayal Method for canvas\n", - " \"\"\"\n", - " portrayal = {}\n", - " if agent.atype is None:\n", - " portrayal[\"color\"] = \"Grey\"\n", - " elif agent.atype == 0:\n", - " portrayal[\"color\"] = \"Orange\"\n", - " else:\n", - " portrayal[\"color\"] = \"Blue\"\n", - " return portrayal\n", - "\n", - "\n", - "model_params = {\n", - " \"density\": {\n", - " \"type\": \"SliderFloat\",\n", - " \"value\": 0.6,\n", - " \"label\": \"Population Density\",\n", - " \"min\": 0.0,\n", - " \"max\": 0.9, #there must be an empty space for the agent to move\n", - " \"step\": 0.1,\n", - " },\n", - " \"minority_pc\": {\n", - " \"type\": \"SliderFloat\",\n", - " \"value\": 0.2,\n", - " \"label\": \"Fraction Minority\",\n", - " \"min\": 0.0,\n", - " \"max\": 1.0,\n", - " \"step\": 0.05,\n", - " },\n", - " \"export_data\": {\n", - " \"type\": \"Checkbox\",\n", - " \"value\": False,\n", - " \"description\": \"Export Data\",\n", - " \"disabled\": False,\n", - " },\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "d247f4be-6edd-42b5-8e1a-88ce3604ec09", - "metadata": {}, - "source": [ - "## Run the Model" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "c8a2533e-95ba-4a2b-b21a-56e05fe3b7b2", - "metadata": { - "has_explanation": false - }, - "outputs": [ + "cells": [ { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "5024c6fa891f4dc4b559e6ae23db8f16", - "version_major": 2, - "version_minor": 0 + "cell_type": "markdown", + "id": "e72b67b0-df4a-42b8-be21-207911e0d04d", + "metadata": { + "id": "e72b67b0-df4a-42b8-be21-207911e0d04d" }, - "text/html": [ - "Cannot show widget. You probably want to rerun the code cell above (Click in the code cell, and press Shift+Enter +)." + "source": [ + "# Introductory Tutorial\n", + "\n", + "This tutorial introduces Mesa-Geo, a GIS integrated Agent Based model platform that is part of the [Mesa ABM Ecosystem](https://mesa.readthedocs.io/en/stable/)\n", + "\n", + "In this tutorial we will build a Geo-Schelling model, which takes the seminal [Schelling Segregation model](https://en.wikipedia.org/wiki/Schelling%27s_model_of_segregation) and replicates with the countries of Europe, were the countries \"move\" their preference similar to the Schelling Model.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35dbfaed-26a6-463a-a0f2-b26989e7e824", + "metadata": { + "has_explanation": false, + "id": "35dbfaed-26a6-463a-a0f2-b26989e7e824" + }, + "outputs": [], + "source": [ + "!pip install mesa-geo --quiet\n", + "\n", + "import random\n", + "\n", + "import mesa\n", + "import mesa_geo as mg\n", + "import mesa_geo.visualization as mgv" + ] + }, + { + "cell_type": "markdown", + "id": "e5e2bee2-d440-43c7-81fb-01e6a817e5e5", + "metadata": { + "id": "e5e2bee2-d440-43c7-81fb-01e6a817e5e5" + }, + "source": [ + "## Create the Agents\n", + "\n", + "The next cell creates the GeoAgents, in which European country is randomly assigned a preference of minority or majority and then if the agent is unhappy moves. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27cac12c-515e-4ef4-83cc-d06918921c70", + "metadata": { + "has_explanation": false, + "id": "27cac12c-515e-4ef4-83cc-d06918921c70" + }, + "outputs": [], + "source": [ + "class SchellingAgent(mg.GeoAgent):\n", + " \"\"\"Schelling segregation agent.\"\"\"\n", + "\n", + " def __init__(self, unique_id, model, geometry, crs, agent_type=None):\n", + " \"\"\"Create a new Schelling agent.\n", + "\n", + " Args:\n", + " unique_id: Unique identifier for the agent.\n", + " agent_type: Indicator for the agent's type (minority=1, majority=0)\n", + " \"\"\"\n", + " super().__init__(unique_id, model, geometry, crs)\n", + " self.atype = agent_type\n", + "\n", + " def step(self):\n", + " \"\"\"Advance agent one step.\"\"\"\n", + " similar = 0\n", + " different = 0\n", + " neighbors = self.model.space.get_neighbors(self)\n", + " if neighbors:\n", + " for neighbor in neighbors:\n", + " if neighbor.atype is None:\n", + " continue\n", + " elif neighbor.atype == self.atype:\n", + " similar += 1\n", + " else:\n", + " different += 1\n", + "\n", + " # If unhappy, move:\n", + " if similar < different:\n", + " # Select an empty region\n", + " empties = [a for a in self.model.space.agents if a.atype is None]\n", + " # Switch atypes and add/remove from scheduler\n", + " new_region = random.choice(empties)\n", + " new_region.atype = self.atype\n", + " self.model.schedule.add(new_region)\n", + " self.atype = None\n", + " self.model.schedule.remove(self)\n", + " else:\n", + " self.model.happy += 1\n", + "\n", + " def __repr__(self):\n", + " return \"Agent \" + str(self.unique_id)" + ] + }, + { + "cell_type": "markdown", + "id": "6eac24f2-af00-40bd-b146-1be7a66b1644", + "metadata": { + "id": "6eac24f2-af00-40bd-b146-1be7a66b1644" + }, + "source": [ + "## Model Class\n", + "\n", + "This class initiates the model class, which acts as a \"manager\" for the simulation, it holds the geo-spatial space. It holds the schedule of agents and their order, and the data collector to collect information from the model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c9a9738-7e8f-458c-b0aa-cfc69c04ee87", + "metadata": { + "has_explanation": false, + "jupyter": { + "source_hidden": true + }, + "id": "9c9a9738-7e8f-458c-b0aa-cfc69c04ee87" + }, + "outputs": [], + "source": [ + "class GeoSchelling(mesa.Model):\n", + " \"\"\"Model class for the Schelling segregation model.\"\"\"\n", + "\n", + " def __init__(self, density=0.6, minority_pc=0.2, export_data=False):\n", + " super().__init__()\n", + " self.density = density\n", + " self.minority_pc = minority_pc\n", + " self.export_data = export_data\n", + "\n", + " self.schedule = mesa.time.RandomActivation(self)\n", + " self.space = mg.GeoSpace(crs=\"EPSG:4326\", warn_crs_conversion=True)\n", + "\n", + " self.happy = 0\n", + " self.datacollector = mesa.DataCollector({\"happy\": \"happy\"})\n", + "\n", + " self.running = True\n", + "\n", + " # Set up the grid with patches for every NUTS region\n", + " ac = mg.AgentCreator(SchellingAgent, model=self)\n", + " agents = ac.from_file(\"data/nuts_rg_60M_2013_lvl_2.geojson\")\n", + " self.space.add_agents(agents)\n", + "\n", + " # Set up agents\n", + " for agent in agents:\n", + " if random.random() < self.density:\n", + " if random.random() < self.minority_pc:\n", + " agent.atype = 1\n", + " else:\n", + " agent.atype = 0\n", + " self.schedule.add(agent)\n", + "\n", + " def export_agents_to_file(self) -> None:\n", + " self.space.get_agents_as_GeoDataFrame(agent_cls=SchellingAgent).to_crs(\n", + " \"epsg:4326\"\n", + " ).to_file(\"data/schelling_agents.geojson\", driver=\"GeoJSON\")\n", + "\n", + " def step(self):\n", + " \"\"\"Run one step of the model.\n", + "\n", + " If All agents are happy, halt the model.\n", + " \"\"\"\n", + "\n", + " self.happy = 0 # Reset counter of happy agents\n", + " self.schedule.step()\n", + " self.datacollector.collect(self)\n", + "\n", + " if self.happy == self.schedule.get_agent_count():\n", + " self.running = False\n", + "\n", + " if not self.running and self.export_data:\n", + " self.export_agents_to_file()" + ] + }, + { + "cell_type": "markdown", + "id": "3ed4ea12-4417-476e-bf6c-4a5f95871005", + "metadata": { + "id": "3ed4ea12-4417-476e-bf6c-4a5f95871005" + }, + "source": [ + "## Build the Visual\n", + "\n", + "This section of code set ups the conditions for drawing the agents and defining the model parameters. The next cell passes the `schelling_draw` function and model parameters into Mesa Geo's `GeoJupyterViz` so we can see a visual for our simulation. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0bf74b4c-36ab-416c-a4db-ab5104189d92", + "metadata": { + "has_explanation": false, + "id": "0bf74b4c-36ab-416c-a4db-ab5104189d92" + }, + "outputs": [], + "source": [ + "def schelling_draw(agent):\n", + " \"\"\"\n", + " Portrayal Method for canvas\n", + " \"\"\"\n", + " portrayal = {}\n", + " if agent.atype is None:\n", + " portrayal[\"color\"] = \"Grey\"\n", + " elif agent.atype == 0:\n", + " portrayal[\"color\"] = \"Orange\"\n", + " else:\n", + " portrayal[\"color\"] = \"Blue\"\n", + " return portrayal\n", + "\n", + "\n", + "model_params = {\n", + " \"density\": {\n", + " \"type\": \"SliderFloat\",\n", + " \"value\": 0.6,\n", + " \"label\": \"Population Density\",\n", + " \"min\": 0.0,\n", + " \"max\": 0.9, #there must be an empty space for the agent to move\n", + " \"step\": 0.1,\n", + " },\n", + " \"minority_pc\": {\n", + " \"type\": \"SliderFloat\",\n", + " \"value\": 0.2,\n", + " \"label\": \"Fraction Minority\",\n", + " \"min\": 0.0,\n", + " \"max\": 1.0,\n", + " \"step\": 0.05,\n", + " },\n", + " \"export_data\": {\n", + " \"type\": \"Checkbox\",\n", + " \"value\": False,\n", + " \"description\": \"Export Data\",\n", + " \"disabled\": False,\n", + " },\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "d247f4be-6edd-42b5-8e1a-88ce3604ec09", + "metadata": { + "id": "d247f4be-6edd-42b5-8e1a-88ce3604ec09" + }, + "source": [ + "## Run the Model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8a2533e-95ba-4a2b-b21a-56e05fe3b7b2", + "metadata": { + "has_explanation": false, + "id": "c8a2533e-95ba-4a2b-b21a-56e05fe3b7b2", + "outputId": "67c4a042-8ad3-4d44-ee15-931c5d5d01ac", + "colab": { + "referenced_widgets": [ + "5024c6fa891f4dc4b559e6ae23db8f16" + ] + } + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "5024c6fa891f4dc4b559e6ae23db8f16", + "version_major": 2, + "version_minor": 0 + }, + "text/html": [ + "Cannot show widget. You probably want to rerun the code cell above (Click in the code cell, and press Shift+Enter +)." + ], + "text/plain": [ + "Cannot show ipywidgets in text" + ] + }, + "metadata": {}, + "output_type": "display_data" + } ], - "text/plain": [ - "Cannot show ipywidgets in text" + "source": [ + "page = mgv.GeoJupyterViz(\n", + " GeoSchelling,\n", + " model_params,\n", + " measures=[\"happy\"],\n", + " name=\"Geo-Schelling Model\",\n", + " agent_portrayal=schelling_draw,\n", + " zoom=3,\n", + " center_point=[52, 12],\n", + ")\n", + "# This is required to render the visualization in the Jupyter notebook\n", + "page" ] - }, - "metadata": {}, - "output_type": "display_data" + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7cbb2272-b33d-4f1d-9c90-1abbdc876723", + "metadata": { + "has_explanation": false, + "jupyter": { + "source_hidden": true + }, + "id": "7cbb2272-b33d-4f1d-9c90-1abbdc876723" + }, + "outputs": [], + "source": [] } - ], - "source": [ - "page = mgv.GeoJupyterViz(\n", - " GeoSchelling,\n", - " model_params,\n", - " measures=[\"happy\"],\n", - " name=\"Geo-Schelling Model\",\n", - " agent_portrayal=schelling_draw,\n", - " zoom=3,\n", - " center_point=[52, 12],\n", - ")\n", - "# This is required to render the visualization in the Jupyter notebook\n", - "page" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7cbb2272-b33d-4f1d-9c90-1abbdc876723", - "metadata": { - "has_explanation": false, - "jupyter": { - "source_hidden": true + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.12 (XPython)", + "language": "python", + "name": "xpython" + }, + "language_info": { + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "version": "3.12.2" + }, + "colab": { + "provenance": [] } - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.12 (XPython)", - "language": "python", - "name": "xpython" }, - "language_info": { - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "version": "3.12.2" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file