{ "cells": [ { "cell_type": "markdown", "id": "670cf30d", "metadata": {}, "source": [ "# Introductory Tutorial" ] }, { "cell_type": "markdown", "id": "1482bfa9", "metadata": {}, "source": [ "## Getting started\n", "\n", "You should be familiar with how [Mesa](https://github.com/projectmesa/mesa) works.\n", "\n", "So let's get started with some geometries! We will work with [records of US states](http://eric.clst.org/Stuff/USGeoJSON). We use the `requests` library to retrieve the data, but of course you can work with local data." ] }, { "cell_type": "code", "execution_count": 1, "id": "6c026625", "metadata": { "ExecuteTime": { "end_time": "2022-10-17T18:18:56.247846Z", "start_time": "2022-10-17T18:18:29.927694Z" } }, "outputs": [], "source": [ "import warnings\n", "\n", "warnings.filterwarnings(\"ignore\")\n", "\n", "import mesa\n", "import mesa_geo as mg\n", "import requests\n", "\n", "\n", "url = \"http://eric.clst.org/assets/wiki/uploads/Stuff/gz_2010_us_040_00_20m.json\"\n", "r = requests.get(url)\n", "geojson_states = r.json()" ] }, { "cell_type": "markdown", "id": "c5599433", "metadata": { "ExecuteTime": { "end_time": "2022-08-31T13:29:13.715839Z", "start_time": "2022-08-31T13:29:13.710995Z" } }, "source": [ "First we create a `State` Agent and a `GeoModel`. Both should look familiar if you have worked with Mesa before." ] }, { "cell_type": "code", "execution_count": 2, "id": "c07e7a9a", "metadata": { "ExecuteTime": { "end_time": "2022-10-17T18:18:56.256884Z", "start_time": "2022-10-17T18:18:56.251192Z" } }, "outputs": [], "source": [ "class State(mg.GeoAgent):\n", " def __init__(self, unique_id, model, geometry, crs):\n", " super().__init__(unique_id, model, geometry, crs)\n", "\n", "\n", "class GeoModel(mesa.Model):\n", " def __init__(self):\n", " self.space = mg.GeoSpace()\n", "\n", " ac = mg.AgentCreator(agent_class=State, model=self)\n", " agents = ac.from_GeoJSON(GeoJSON=geojson_states, unique_id=\"NAME\")\n", " self.space.add_agents(agents)" ] }, { "cell_type": "markdown", "id": "c806fc00", "metadata": {}, "source": [ "In the `GeoModel` we first create an instance of AgentCreator, where we provide the Agent class (State) and its required arguments, except geometry and unique_id. We then use the `.from_GeoJSON` function to create our agents from the geometries in the GeoJSON file. We provide the feature \"name\" as the key from which the agents get their unique_ids.\n", "Finally, we add the agents to the GeoSpace\n", "\n", "Let's instantiate our model and look at one of the agents:" ] }, { "cell_type": "code", "execution_count": 3, "id": "ebee624a", "metadata": { "ExecuteTime": { "end_time": "2022-10-17T18:18:56.466576Z", "start_time": "2022-10-17T18:18:56.260255Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Arizona\n" ] }, { "data": { "image/svg+xml": [ "" ], "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = GeoModel()\n", "\n", "agent = m.space.agents[0]\n", "print(agent.unique_id)\n", "agent.geometry" ] }, { "cell_type": "markdown", "id": "983dad91", "metadata": {}, "source": [ "If you work in the Jupyter Notebook your output should give you the name of the state and a visual representation of the geometry.\n", "\n", "By default the AgentCreator also sets further agent attributes from the Feature properties." ] }, { "cell_type": "code", "execution_count": 4, "id": "0f7c0ee6", "metadata": { "ExecuteTime": { "end_time": "2022-10-17T18:18:56.473375Z", "start_time": "2022-10-17T18:18:56.469477Z" } }, "outputs": [ { "data": { "text/plain": [ "113594.084" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "agent.CENSUSAREA" ] }, { "cell_type": "markdown", "id": "6a843f67", "metadata": {}, "source": [ "Let's start to do some spatial analysis. We can use usual Mesa function names to get neighboring states." ] }, { "cell_type": "code", "execution_count": 5, "id": "154e56b2", "metadata": { "ExecuteTime": { "end_time": "2022-10-17T18:18:56.759515Z", "start_time": "2022-10-17T18:18:56.475418Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['California', 'Colorado', 'Utah', 'Nevada', 'New Mexico']\n" ] } ], "source": [ "neighbors = m.space.get_neighbors(agent)\n", "print([a.unique_id for a in neighbors])" ] }, { "cell_type": "markdown", "id": "6b5d5c9d", "metadata": {}, "source": [ "To get a list of all states within a certain distance you can use the following:" ] }, { "cell_type": "code", "execution_count": 6, "id": "63b36a85", "metadata": { "ExecuteTime": { "end_time": "2022-10-17T18:18:56.769281Z", "start_time": "2022-10-17T18:18:56.761925Z" } }, "outputs": [ { "data": { "text/plain": [ "['California',\n", " 'Nevada',\n", " 'Arizona',\n", " 'Utah',\n", " 'Wyoming',\n", " 'New Mexico',\n", " 'Colorado',\n", " 'Texas']" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[a.unique_id for a in m.space.get_neighbors_within_distance(agent, 600000)]" ] }, { "cell_type": "markdown", "id": "78744f63", "metadata": {}, "source": [ "The unit for the distance depends on the coordinate reference system (CRS) of the GeoSpace. Since we did not specify the CRS, Mesa-Geo defaults to the 'Web Mercator' projection (in meters). If you want to do some serious measurements you should always set an appropriate CRS, since the accuracy of Web Mercator declines with distance from the equator. We can achieve this by initializing the AgentCreator and the GeoSpace with the `crs` keyword `crs=\"epsg:2163\"`. Mesa-Geo then transforms all coordinates from the GeoJSON geographic coordinates into the set crs." ] }, { "cell_type": "markdown", "id": "d56743c5", "metadata": {}, "source": [ "## Going further\n", "\n", "To get a deeper understanding of Mesa-Geo you should check out the [GeoSchelling](https://github.com/projectmesa/mesa-examples/tree/main/gis/geo_schelling) example. It implements a Leaflet visualization which is similar to use as the CanvasGridVisualization of Mesa.\n", "\n", "To add further functionality, I need feedback on which functionality is desired by users. Please post a message at [Mesa-Geo discussions](https://github.com/projectmesa/mesa-geo/discussions) or open an [issue](https://github.com/projectmesa/mesa-geo/issues) if you have any ideas or recommendations." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "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.8.12" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": true } }, "nbformat": 4, "nbformat_minor": 5 }