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