{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Generating spatial weights\n", "\n", "`momepy` is using `libpysal` to handle spatial weights, but also builds on top of it. This notebook will show how to use different weights." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import momepy\n", "import geopandas as gpd\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will again use `osmnx` to get the data for our example and after preprocessing of building layer will generate tessellation layer. " ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "tags": [ "hide_output" ] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Inward offset...\n", "Generating input point array...\n", "Generating Voronoi diagram...\n", "Generating GeoDataFrame...\n", "Dissolving Voronoi polygons...\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/Users/martin/Git/geopandas/geopandas/geoseries.py:190: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.\n", " s = pd.Series(data, index=index, name=name, **kwargs)\n" ] } ], "source": [ "import osmnx as ox\n", "\n", "gdf = ox.geometries.geometries_from_place('Kahla, Germany', tags={'building':True})\n", "buildings = ox.projection.project_gdf(gdf)\n", "\n", "buildings['uID'] = momepy.unique_id(buildings)\n", "limit = momepy.buffered_limit(buildings)\n", "tessellation = momepy.Tessellation(buildings, unique_id='uID', limit=limit).tessellation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Queen contiguity\n", "\n", "Morphological tessellation allows using contiguity-based weights matrix. While `libpysal.weights.contiguity.Queen` will do the standard Queen contiguity matrix of the first order; it might not be enough to capture proper context. For that reason, we can use `momepy.sw_high` to capture all neighbours within set topological distance `k`. It generates spatial weights of higher orders under the hood and joins them together." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "sw3 = momepy.sw_high(k=3, gdf=tessellation, ids='uID')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Queen contiguity of morphological tessellation can capture the comparable level of information across the study area - the number of the neighbour is relatively similar and depends on the morphology of urban form. We can visualize it by counting the number of neighbours (as captured by `sw3`)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "e1408211f44e424abdce5f84c733f28b", "version_major": 2, "version_minor": 0 }, "text/plain": [ " 0%| | 0/2947 [00:00" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "f, ax = plt.subplots(figsize=(10, 10))\n", "tessellation.plot(ax=ax, column='neighbours', legend=True, cmap='Spectral_r')\n", "buildings.plot(ax=ax, color=\"white\", alpha=0.4)\n", "ax.set_axis_off()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Distance\n", "\n", "Often we want to define the neighbours based on metric distance. We will look at two options - distance band and k-nearest neighbour.\n", "\n", "### Distance band\n", "\n", "We can imagine distance band as a buffer of a set radius around centroid of each object, for example, 400 meters. For that, we can use `libpysal.weights.DistanceBand`:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "tags": [ "hide_output" ] }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/opt/miniconda3/envs/geo_dev/lib/python3.9/site-packages/libpysal/weights/weights.py:172: UserWarning: The weights matrix is not fully connected: \n", " There are 2 disconnected components.\n", " There is 1 island with id: 330.\n", " warnings.warn(message)\n" ] } ], "source": [ "import libpysal\n", "dist400 = libpysal.weights.DistanceBand.from_dataframe(buildings, 400,\n", " ids='uID')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because we have defined spatial weights using uID, we can use `dist400` generated on buildings and use it on tessellation:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "17287248958c4b86acb93cf0c6179128", "version_major": 2, "version_minor": 0 }, "text/plain": [ " 0%| | 0/2947 [00:00" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "f, ax = plt.subplots(figsize=(10, 10))\n", "tessellation.plot(ax=ax, column='neighbours400', legend=True, cmap='Spectral_r')\n", "buildings.plot(ax=ax, color=\"white\", alpha=0.4)\n", "ax.set_axis_off()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### K nearest neighbor\n", "\n", "If we want fixed number of neighbours, we can use `libpysal.weights.KNN`:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "ddd95ab36ed242e9a5dce4a67fce475d", "version_major": 2, "version_minor": 0 }, "text/plain": [ " 0%| | 0/2947 [00:00" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "f, ax = plt.subplots(figsize=(10, 10))\n", "tessellation.plot(ax=ax, column='neighboursKNN', legend=True, cmap='Spectral_r')\n", "buildings.plot(ax=ax, color=\"white\", alpha=0.4)\n", "ax.set_axis_off()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All of them can be used within morphometric analysis. Theoretical and practical differences are discussed in Fleischmann, Romice and Porta (2019).\n", "\n", "For the other options on generating spatial weights see [lipysal API](https://pysal.org/libpysal/api.html)." ] } ], "metadata": { "celltoolbar": "Tags", "kernelspec": { "display_name": "geo_dev", "language": "python", "name": "geo_dev" }, "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.9.2" } }, "nbformat": 4, "nbformat_minor": 4 }