diff --git a/docs/source/_contents/intro_tutorial.ipynb b/docs/source/_contents/intro_tutorial.ipynb deleted file mode 100644 index fa1e5ac7..00000000 --- a/docs/source/_contents/intro_tutorial.ipynb +++ /dev/null @@ -1,442 +0,0 @@ -{ - "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", - "\n", - "This tutorial also uses [Jupyter Bridge](https://pypi.org/project/jupyter-bridge/) so users can see more detailed explanations of each code cell if desired by clicking the book icon. " - ] - }, - { - "cell_type": "markdown", - "id": "f42df443-f544-4bf8-bc6e-29c9ca6c3eae", - "metadata": { - "explanatory": true - }, - "source": [ - "#explanatory\n", - "\n", - "For the import cell we use three libraries: \n", - "\n", - "* **random** this is a standard python library and used in this model to randomize the country (agents) behavior and preferences\n", - "* **mesa** this is the core ABM library that provides basic ABM functionality for `mesa-geo`\n", - "* **mesa_geo** this library add GIS features to Mesa to allow for GIS integration into Agent Based Models\n", - "* **mesa_geo.visualization** is a sub_module of mesa_geo, we import this module to make the code more concise so we we do not have to type mg.visualization every time we use this visualization module" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "37528711-4873-42e7-be7f-926130026dd8", - "metadata": { - "has_explanation": true - }, - "outputs": [], - "source": [ - "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": "markdown", - "id": "36adf141-4f86-4c33-978a-954c4001d222", - "metadata": { - "explanatory": true - }, - "source": [ - "#explanatory\n", - "\n", - "**Agent Class and Initialization** \n", - "To create numerous agents with different attributes, we instantiate a Agent class (i.e. Schelling Agent), this is the common Mesa approach and it inherits from Mesa-Geo's GeoAgent class.\n", - "\n", - "The GeoAgent always has four attributes: \n", - "1. The unique ID\n", - "2. The model so the agents can reference it\n", - "3. The geometry\n", - "4. The projection or crs\n", - "\n", - "In this simulation there is one additonal attribute agent_type which identifies if the agent is a minority or majority agents.\n", - "\n", - "**Step Function**\n", - "The step function is Mesa syntax and required for each agent. In the model class, discussed next, the step function for each agent is called by the model step function and represents what each agent does for each time step. \n", - "\n", - "In this case the agent first identifies all its neighbors and determines if they are the same (minority or majority) if the neighbors who are not the same type as the agent are greater than those who are similar than the agent moves. \n", - "\n", - "If the number of neighbors who are similar is greater than those who are different than agent is happy and does not move. " - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "27cac12c-515e-4ef4-83cc-d06918921c70", - "metadata": { - "has_explanation": true, - "jupyter": { - "source_hidden": true - } - }, - "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": "markdown", - "id": "e3053304-a512-425c-806f-e7ebf73e1d52", - "metadata": { - "explanatory": true - }, - "source": [ - "#explanatory\n", - "\n", - "The model class initiates the \"manager\" for the simulation. Initiatiang the initial parameters and inheriting core attributes from Mesa's models class. In this case there are three parameters, density of agents (how many of the existing countries are agents), what percent are minority, and whether or not to export the data. \n", - "\n", - "Then there are three main parts: \n", - "1. The schedule which in this case uses random activation, this is just a list of agent objects, who's order is randomly reordered after each step.\n", - "2. The space which uses geomesa space module and has a keyword argument of the projection conversion\n", - "3. The datacollector which in this case collects the number of agent who are happy with their location (neighbors are more similar than different)\n", - "\n", - "The model class step function then calls\n", - " * each agent's step through the `self.schedule.step()`\n", - " * the datacollector to collect each step `self.datacollector.collect(self)`" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "9c9a9738-7e8f-458c-b0aa-cfc69c04ee87", - "metadata": { - "has_explanation": true, - "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": "markdown", - "id": "8b3bac67-45d6-42ca-8e40-b8f44d749b3a", - "metadata": { - "explanatory": true - }, - "source": [ - "#explanatory\n", - "\n", - "Mesa-Geo's `GeoJupyterviz`requires users to pass in a function through `agent_portrayal` for agent visualization. This function then allows the agent to updates its representation based on user settings. In this case, the agent's color updates a dictionary that determines its color with the key \"color\" and the value being the agents color based on their affiliation (minority, majority, or none). \n", - "\n", - "`model_params` is then a dictionary with the parameters for the geoschelling model. `GeoSchelling` then takes three parameters and these parameters use Mesa's `UserParam` module to create tools users can employ to set model parameters. \n", - "1. \"density\" is a slider tool (\"SliderFloat\") that takes a value from 0.0 to 1.0 with a step or accuracy at one tenth\n", - "2. \"minority_pc\" is also a slider tool (\"SliderFloat\") that the minority percent which takes a value of 0.0 to 1.0 with an accuracy of 5- 100th of a percent\n", - "3. \"export_data\" is then a binary tool (\"checkbox\") that allows user to turn the value to True by checking the book and exporting the data" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "0bf74b4c-36ab-416c-a4db-ab5104189d92", - "metadata": { - "has_explanation": true, - "jupyter": { - "source_hidden": true - } - }, - "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": "markdown", - "id": "e6e26b92-5ca8-4038-90a0-259f11dac69a", - "metadata": { - "explanatory": true - }, - "source": [ - "#explanatory\n", - "\n", - "This cell then uses the previous cell to create a visualization of the model. In this case there are seven parameters. Two parameters being required. \n", - "\n", - "1. model: this passes in the model class which in this case is the `GeoSchelling` class model.\n", - "2. model_params: this takes the dictionary we built in the previous cell and passes in the parameters with the model types\n", - "3. measures: this is a kwarg (key word argument) which is not required but takes a list of measures users want to observe in this case the happy metric\n", - "4. name: also a kwarg for the name which shows in the model bar\n", - "5. agent_portrayal: a kwarg that allows us to pass in the function `schelling_draw` which determines agent representation based on their specific condition\n", - "6. zoom: a kwarg for the mapping function which determines what level the user should zoom on the map and takes an integer\n", - "7. center_point: a kwarg for telling the visualization what center point to use when portraying the map " - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "c8a2533e-95ba-4a2b-b21a-56e05fe3b7b2", - "metadata": { - "has_explanation": true, - "jupyter": { - "source_hidden": true - } - }, - "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" - } - ], - "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 - } - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python (Mesa Geo)", - "language": "python", - "name": "mesageodev" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/source/_static/jupyter-lite.json b/docs/source/_static/jupyter-lite.json deleted file mode 100644 index 90a8f2ee..00000000 --- a/docs/source/_static/jupyter-lite.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "jupyterConfigData": { - "litePlugins": [ - "@jupyterlite/xeus-python-kernel" - ] - } -}