{ "cells": [ { "cell_type": "markdown", "id": "164926e0", "metadata": { "id": "6d0b0da0" }, "source": [ "## Spatial Data Science with CityJSON\n", "\n", "The purpose of this Notebook is to ***work with*** the product of [osm_LoD1_3DCityModel](https://github.com/AdrianKriger/osm_LoD1_3DCityModel); a previously created CityJSON city model." ] }, { "cell_type": "markdown", "id": "305f3f23", "metadata": { "id": "91998c9b" }, "source": [ "
This notebook will:\n", "\n", "> **1. allow the user to execute an application of Spatial Data Science** \n", ">\n", ">> **a) [population estimation](#Section1a)** _--with a previous census metric population growth rate and projected (future) population are also possible_ **and** \n", ">> **b) a measure of [Building Volume per Capita](#Section1b)**\n", ">\n", "> **2. produce [an interactive visualization](#Section1b)** *-via [pydeck](https://deckgl.readthedocs.io/en/latest/)- which a user can navigate, query and share* **that**;\n", "> > **a) [colour buildings by type](#Section2a)** *(to easily visualize building stock)* \n", ">\n", "> **3. propose several [Geography and Sustainable Development Education *conversation starters*](#Section3) for Secondary and Tertiary level students**\n", "
" ] }, { "cell_type": "markdown", "id": "af30e4b2-5af9-49f2-9362-1d604000bec9", "metadata": {}, "source": [ "
Please Note:\n", "\n", "***The [village](https://github.com/AdrianKriger/geo3D/tree/main/village)*** processing option is meant for areas with no more than for **2 500 buildings**.
" ] }, { "cell_type": "code", "execution_count": 1, "id": "5dd597d7", "metadata": { "id": "a4ea1fcc" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Users/adriankriger/miniconda3/envs/geo3D_gthbRepo07/lib/python3.9/site-packages/cjio/cityjson.py:12: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.\n", " from pkg_resources import resource_filename\n" ] } ], "source": [ "#- load the magic\n", "\n", "%matplotlib inline\n", "import os\n", "from pathlib import Path\n", "\n", "import numpy as np\n", "import pandas as pd\n", "import shapely\n", "from shapely.geometry import Polygon, shape, mapping\n", "import json\n", "import geojson\n", "\n", "from cjio import cityjson\n", "\n", "import city3D\n", "\n", "import matplotlib.pyplot as plt\n", "import pydeck as pdk" ] }, { "cell_type": "code", "execution_count": 2, "id": "f8d278a7-e16d-4afd-802c-d4d2b48b8e2a", "metadata": {}, "outputs": [], "source": [ "import warnings\n", "warnings.filterwarnings('ignore')" ] }, { "cell_type": "markdown", "id": "b1988f7d", "metadata": { "id": "d19acf91" }, "source": [ "**The area under investigation is [Mamre, Cape Town. South Africa](https://en.wikipedia.org/wiki/Mamre,_South_Africa).**" ] }, { "cell_type": "code", "execution_count": 3, "id": "5557ef08", "metadata": { "id": "529536e5" }, "outputs": [], "source": [ "#- change to harvest the appropriate CityJSON\n", "\n", "#jparams = json.load(open('uEstate_param.json'))\n", "#jparams = json.load(open('cput_param.json'))\n", "#jparams = json.load(open('saao_param.json'))\n", "jparams = json.load(open('mamre_param.json'))\n", "#jparams = json.load(open('sRiver_param.json'))" ] }, { "cell_type": "code", "execution_count": 4, "id": "d9717ddd", "metadata": { "id": "c45a674c" }, "outputs": [], "source": [ "cm = cityjson.load(path=jparams['cjsn_solid']) #-- citjsnClean_rural3D.json in the result folder" ] }, { "cell_type": "code", "execution_count": 5, "id": "0360987e", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CityJSON version = 1.1\n", "EPSG = 32734\n", "bbox = [263859.53151571925, 6287898.265465543, 145.1199951171875, 266646.4893499555, 6290185.027937451, 254.5399932861328]\n", "=== CityObjects ===\n", "|-- TINRelief (1)\n", "|-- Building (2275)\n", "===================\n", "materials = False\n", "textures = False\n" ] } ], "source": [ "print(cm)" ] }, { "cell_type": "code", "execution_count": 6, "id": "f8e0fa63", "metadata": { "id": "c7ec404d" }, "outputs": [], "source": [ "df = cm.to_dataframe()\n", "#- remove the first feature: the terrain\n", "df = df[1:] \n", "\n", "#- harvest the crs\n", "theinfo = cm.get_info()\n", "crs = theinfo[1]\n", "\n", "# account for holes\n", "def coords_to_polygon(rings):\n", " outer = rings[0] # first ring is the shell\n", " holes = rings[1:] if len(rings) > 1 else None\n", " return Polygon(shell=outer, holes=holes)\n", "\n", "# Convert JSON string to Python list\n", "df['footprint_coords_list'] = df['footprint'].apply(json.loads)\n", "\n", "# create home-baked gdf\n", "gdf = city3D.GeoDataFrameLite(df)\n", "gdf['geometry'] = gdf['footprint_coords_list'].apply(coords_to_polygon)\n", "gdf.crs = crs[7:]\n", "# Drop columns inplace\n", "gdf.drop(columns=['footprint', 'footprint_coords_list'], inplace=True)\n", "#gdf.head(2)" ] }, { "cell_type": "markdown", "id": "17ae2c91", "metadata": { "id": "b87c1769" }, "source": [ "## 1. Spatial Data Science" ] }, { "cell_type": "markdown", "id": "61389a02", "metadata": { "id": "7d170bdc" }, "source": [ "
We start with basic spatial analysis \n", " \n", " \n", "- We'll [estimate the population](#Section1a), within our area of interest, and then \n", "- calculate the [Building Volume Per Capita (BVPC)](#Section1b).\n", "
" ] }, { "cell_type": "markdown", "id": "88f9c7f0", "metadata": { "id": "1bae2eb7" }, "source": [ "While estimating population is well documented; recent investigations to **understand overcrowding** have led to newer measurements. \n", "\n", "The most noteable of these is **Building Volume Per Capita (BVPC)** [(Ghosh, T; et al. 2020)](https://www.researchgate.net/publication/343185735_Building_Volume_Per_Capita_BVPC_A_Spatially_Explicit_Measure_of_Inequality_Relevant_to_the_SDGs). BVPC is the cubic meters of building per person. **BVPC tells us how much space one person has per residential living unit** (a house / apartment / etc.). It is ***a proxy measure of economic inequality and a direct measure of housing inequality***.\n", "\n", "BVPC builds on the work of [(Reddy, A and Leslie, T.F., 2013)](https://www.tandfonline.com/doi/abs/10.1080/02723638.2015.1060696?journalCode=rurb20) and attempts to integrate with several **[Sustainable Development Goals](https://sdgs.un.org/goals)** (most noteably: **[SDG 11: Developing sustainable cities and communities](https://sdgs.un.org/goals/goal11)**) and captures the average ***'living space'*** each person has in their home." ] }, { "cell_type": "markdown", "id": "693b09b6", "metadata": { "id": "28084941" }, "source": [ "
These analysis expect the user to have some basic knowledge about the environment under inquiry / investigation
" ] }, { "cell_type": "code", "execution_count": 7, "id": "a44108b5", "metadata": { "id": "9b5be780", "outputId": "fdc6bce5-8012-49fd-d999-4eb6ef7eb015" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idosm_idbuildingbuilding:levelsbuilding_heightroof_heightground_heightplus_codeaddressamenityoperatorresidentialbottom_roof_heightbuilding:usegeometry
3281184460328118446.0yes14.1183.53179.4299934FRWFFVC+P79NaNNaNNaNNaNNaNNaNPOLYGON ((265041.6351569728 6289775.0592048075...
3281184471328118447.0church26.9185.94179.0399934FRWFFVC+H9QMamre Moravian Church Kerk Street Mamre 7347 C...place_of_worshipNaNNaNNaNNaNPOLYGON ((265070.9766813367 6289761.325392997,...
\n", "
" ], "text/plain": [ " id osm_id building building:levels building_height \\\n", "328118446 0 328118446.0 yes 1 4.1 \n", "328118447 1 328118447.0 church 2 6.9 \n", "\n", " roof_height ground_height plus_code \\\n", "328118446 183.53 179.429993 4FRWFFVC+P79 \n", "328118447 185.94 179.039993 4FRWFFVC+H9Q \n", "\n", " address \\\n", "328118446 NaN \n", "328118447 Mamre Moravian Church Kerk Street Mamre 7347 C... \n", "\n", " amenity operator residential bottom_roof_height \\\n", "328118446 NaN NaN NaN NaN \n", "328118447 place_of_worship NaN NaN NaN \n", "\n", " building:use geometry \n", "328118446 NaN POLYGON ((265041.6351569728 6289775.0592048075... \n", "328118447 NaN POLYGON ((265070.9766813367 6289761.325392997,... " ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gdf.head(2)" ] }, { "cell_type": "code", "execution_count": 8, "id": "1c87ffcf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(['yes', 'church', 'house', 'cabin', 'public', 'civic', 'office',\n", " 'retail', 'clinic', 'school', 'garage', 'greenhouse', 'roof',\n", " 'kindergarten', 'clubhouse', 'guest_house', 'service', 'detached',\n", " 'shed'], dtype=object)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#gdf.plot()\n", "# have a look at the building type and amenities available\n", "gdf['building'].unique()" ] }, { "cell_type": "markdown", "id": "931cdc34-fed5-4b13-880e-4f6c35753f39", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "id": "aeb2a0d7", "metadata": { "id": "49f5c85e" }, "source": [ "
1. a) Estimate Population: \n", " \n", "_(with population growth rate and population projection possible too)_
" ] }, { "cell_type": "code", "execution_count": 9, "id": "842acc96", "metadata": { "id": "1bc556e3" }, "outputs": [], "source": [ "#--we only want building=house or =apartment or =residential\n", "gdf2 = gdf[gdf[\"building\"].isin(['house', 'semidetached_house', 'terrace', 'terraced', 'apartments', 'residential', 'dormitory', 'cabin'])].copy()" ] }, { "cell_type": "code", "execution_count": 10, "id": "901aaf60-25d2-4307-b2be-1b4cdeff061c", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idosm_idbuildingbuilding:levelsbuilding_heightroof_heightground_heightplus_codeaddressamenityoperatorresidentialbottom_roof_heightbuilding:usegeometry
6568409747656840974.0house14.1174.78170.6799934FRWFFM9+X9839 Dove Lane Mamre 7347 Cape TownNaNNaNNaNNaNNaNPOLYGON ((264864.98193212313 6288741.008398377...
6568409758656840975.0house14.1174.78170.6799934FRWFFM9+X9X37 Dove Lane Mamre 7347 Cape TownNaNNaNNaNNaNNaNPOLYGON ((264865.3504529182 6288749.140981195,...
\n", "
" ], "text/plain": [ " id osm_id building building:levels building_height \\\n", "656840974 7 656840974.0 house 1 4.1 \n", "656840975 8 656840975.0 house 1 4.1 \n", "\n", " roof_height ground_height plus_code \\\n", "656840974 174.78 170.679993 4FRWFFM9+X98 \n", "656840975 174.78 170.679993 4FRWFFM9+X9X \n", "\n", " address amenity operator residential \\\n", "656840974 39 Dove Lane Mamre 7347 Cape Town NaN NaN NaN \n", "656840975 37 Dove Lane Mamre 7347 Cape Town NaN NaN NaN \n", "\n", " bottom_roof_height building:use \\\n", "656840974 NaN NaN \n", "656840975 NaN NaN \n", "\n", " geometry \n", "656840974 POLYGON ((264864.98193212313 6288741.008398377... \n", "656840975 POLYGON ((264865.3504529182 6288749.140981195,... " ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#- some data wrangling to replace 'bld:residential' to 'bld:student' if 'residential:student'\n", "gdf_pop = gdf2.copy()\n", "\n", "if 'residential' in gdf_pop.columns:\n", " df_res = gdf_pop[gdf_pop['residential'] == 'student']\n", " #df_res = df2[df2['building:use'] != None]\n", " df_res = df_res[~df_res['residential'].isna()]\n", " gdf_pop.loc[df_res.index, 'building'] = df_res['residential'] \n", "\n", "#- some more data wrangling\n", "with pd.option_context(\"future.no_silent_downcasting\", True):\n", " if 'building:flats' in gdf_pop.columns: \n", " gdf_pop['building:flats'] = pd.to_numeric(gdf_pop['building:flats'].fillna(0).infer_objects(copy=False))\n", " if 'building:units' in gdf_pop.columns: \n", " gdf_pop['building:units'] = pd.to_numeric(gdf_pop['building:units'].fillna(0).infer_objects(copy=False))\n", " if 'beds' in gdf_pop.columns: \n", " gdf_pop['beds'] = pd.to_numeric(gdf_pop['beds'].fillna(0).infer_objects(copy=False))\n", " if 'rooms' in gdf_pop.columns: \n", " gdf_pop['rooms'] = pd.to_numeric(gdf_pop['rooms'].fillna(0).infer_objects(copy=False))\n", "\n", "gdf_pop[\"building:levels\"] = pd.to_numeric(gdf_pop[\"building:levels\"])\n", "\n", "gdf_pop.head(2)" ] }, { "cell_type": "code", "execution_count": 11, "id": "68efc119-6ee7-4f26-9717-916dabe57874", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "building\n", "house 1644\n", "cabin 333\n", "Name: count, dtype: int64" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gdf_pop['building'].value_counts()" ] }, { "cell_type": "markdown", "id": "0af2ad75-60bf-49f7-986f-30a5d6d59bd6", "metadata": {}, "source": [ "**This area** (Mamre) **is peri-urban with single level housing units. To estimate population is thus pretty straight forward.**\n", "\n", "
We start with local knowledge.
\n", "\n", "**On average there are roughly `6` people per `building:house` in this area.** \n", "\n", "An ***informal*** structure ([shack](https://en.wikipedia.org/wiki/Shack)) is tagged [building:cabin](https://wiki.openstreetmap.org/wiki/Tag:building%3Dcabin) and houses `4` people." ] }, { "cell_type": "markdown", "id": "83e4191e-2a53-4589-b123-c3096dfa85e6", "metadata": {}, "source": [ "
Your Participation! \n", " \n", "\n", "We will execute the calculation programmatically. **Fill in the relevant variables in the _`cell`_ below**
" ] }, { "cell_type": "code", "execution_count": 12, "id": "c148b87f-9d71-4cc8-8486-29f7b81c8def", "metadata": {}, "outputs": [], "source": [ "#- average number of residents per formal house\n", "f_house = 6\n", "#- average number of residents per informal structure\n", "inf_structure = 4" ] }, { "cell_type": "markdown", "id": "d2a7b8f4", "metadata": { "id": "c162ade5" }, "source": [ "
\n", " \n", "**Furthermore:** \n", " - **[social housing](https://en.wikipedia.org/wiki/Public_housing)** is tagged `building:residential` with the number of occupants iether *the number of informal structure occupants* or `building:flats * inf_structure` \n", " - A `social_facility` (carehome, shelter, etc.) harvests the `beds` *'key:value'* pair. \n", " - `building:apartment` harvests the `building:flats` *'key:value'* pair *(the number of units)* to calculate `*3` people per apartment. \n", " - ***Student accomodation***: \n", "> - University owed: is tagged `building:dormitory` with `residential:university` and harvests the `beds` *'key:value'* pair.\n", "> - Private for-profit: is tagged `building:residential` or `:dormitory` with `residential:student` and then harvests the `building:flats` or `:rooms` *'key:value'* pair *(the number of units)* to calculate `*1` people per apartment; if `level: > 1` else `*3` people in a house share.\n", " \n", "**The tagging scheme and numbers is based on *how your community is mapped* and local knowledge**\n", "
" ] }, { "cell_type": "code", "execution_count": 13, "id": "4f626da0-d852-4414-b9de-077542e5a1ce", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The estimated population is: 11196\n" ] } ], "source": [ "c = gdf_pop.columns\n", "\n", "def pop(row):\n", " #- formal house\n", " if row['building'] == 'house' or row['building'] == 'semidetached_house':\n", " return f_house\n", " if row['building'] == 'terrace' and 'building:units' in c or row['building'] == 'terraced' and 'building:units' in c:\n", " return row['building:units'] * f_house\n", "\n", " #- informal structure (shack)\n", " if row['building'] == 'cabin':\n", " return inf_structure\n", "\n", " #- in this case social housing\n", " if row['building'] == 'residential' and 'social_facility' in c and row['social_facility'] is np.nan:\n", " if row['building:levels'] > 1:\n", " if 'rooms' in c and row['rooms'] != 0:\n", " return row['rooms']\n", " if 'building:flats' in c and row['building:flats'] != 0:\n", " return row['building:flats'] * inf_structure\n", " else:\n", " return inf_structure\n", "\n", " #-- social facility [shelter / carehome]\n", " if row['building'] == 'residential' and 'social_facility' in c and row['social_facility'] is not np.nan:\n", " if row['building:levels'] > 1:\n", " if 'building:units' in c and row['building:units'] != 0:\n", " return row['building:units'] \n", " if 'beds' in c and row['beds'] != 0:\n", " return row['beds']\n", " else:\n", " return inf_structure\n", "\n", " #- formal apartment\n", " if row['building'] == 'apartments':\n", " if 'rooms' in c and row['rooms'] != 0:\n", " return row['rooms']\n", " else:\n", " return row['building:flats'] * 3\n", " \n", " #- private student residence \n", " if row['building'] == 'student':\n", " if row['building:levels'] > 1:\n", " if 'rooms' in c and row['rooms'] != 0:\n", " return row['rooms']\n", " else:\n", " return row['building:flats']\n", " else:\n", " return 3\n", " \n", " # university owned student residence\n", " if row['building'] == 'dormitory' and row['residential'] == 'university':\n", " if row['building:levels'] > 1:\n", " if 'rooms' in c and row['rooms'] != 0:\n", " return row['rooms']\n", " if 'beds' in c and row['beds'] != 0:\n", " return row['beds']\n", " else:\n", " return 3\n", "\n", "gdf_pop['pop'] = gdf_pop.apply(lambda x: pop(x), axis=1)\n", "\n", "est_pop = gdf_pop['pop'].sum()\n", "print('The estimated population is:', est_pop)" ] }, { "cell_type": "markdown", "id": "48fe80cb", "metadata": { "id": "01f52225" }, "source": [ "**The official [STATSSA 2011 census figure](https://www.statssa.gov.za/?page_id=4286&id=291), for this community, is 9048.**\n", "\n", "We can calculate the annual population growth rate using the formula for **[Annual population growth](https://databank.worldbank.org/metadataglossary/health-nutrition-and-population-statistics/series/SP.POP.GROW):**\n", "\n", "$$r = \\frac{\\ln{[\\frac{End Population}{Start Population}}]}{n} * 100 = \\frac{\\ln{[\\frac{11 120^{*}}{9048}}]}{12} * 100 = 1.43\\%$$\n", "
\n", "* ***Notice!*** The estimated population (11176) is **NOT** the number in the formula (11 120). This community is frequently updated on OpenStreetMap and variations are common. " ] }, { "cell_type": "markdown", "id": "9ae85954-dd0a-43e2-9160-d0f6285a6ad1", "metadata": {}, "source": [ "
Your Participation! \n", " \n", "\n", "It is possible to execute the calculation programmatically. **Fill in the relevant variables in the _`cell`_ below**
" ] }, { "cell_type": "code", "execution_count": 14, "id": "471c0219-00c6-4b06-a67c-b2cdf30df942", "metadata": {}, "outputs": [], "source": [ "#- previous population\n", "start_population = 9048 #- Salt River: 6 577\n", "\n", "#- period in years from the previous census\n", "years = 12" ] }, { "cell_type": "code", "execution_count": 15, "id": "8efec5c3-9266-44f0-bc44-202b83ff6f2c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "population growth rate of approximately: 1.78 %\n" ] } ], "source": [ "#-execute\n", "r = (np.log(est_pop/start_population)/years) * 100\n", "print('population growth rate of approximately:', round(r, 2), '%')" ] }, { "cell_type": "markdown", "id": "d77014f9-70da-4ebc-91e9-ea1888230ab8", "metadata": {}, "source": [ "To conclude; we can project into the future with a very basic formula to estimate the population _x_-years from now: \n", "\n", "$$p = P_o * (1 + r)^{t} = p = 10736 * (1 + 0.0143)^{10} = 12 368$$" ] }, { "cell_type": "markdown", "id": "fe147a37-0bf0-4a67-8e3f-0d7de83eae75", "metadata": {}, "source": [ "
Your Participation! \n", " \n", "\n", "It is possible to execute the calculation programmatically. **Fill in the variables in the _`cell`_ below**
" ] }, { "cell_type": "code", "execution_count": 16, "id": "bb306d3c-351c-45fb-b75c-f3831a676466", "metadata": {}, "outputs": [], "source": [ "#- period in years from now\n", "years = 10" ] }, { "cell_type": "code", "execution_count": 17, "id": "34876cd3-8660-4971-a600-818d6aabd7dd", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "estimated population 10 years from now: 13349\n" ] } ], "source": [ "#- account for non-residential areas without failure\n", "#- helper function\n", "def safe_population_estimate(est_pop, r, years):\n", " try:\n", " p = est_pop * (1 + (r / 100))**years\n", " return int(p)\n", " except Exception as e:\n", " print(f\"Population estimate failed: {e}\")\n", " return None # keeps notebook running\n", "\n", "#- execute function\n", "p = safe_population_estimate(est_pop, r, years)\n", "\n", "#- shows error and moves on\n", "if p is not None:\n", " print(f\"estimated population {years} years from now: {p}\")" ] }, { "cell_type": "markdown", "id": "a4946db7-90ad-46a7-8a0b-166f8d3694ca", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "id": "954226c4", "metadata": { "id": "395e1ac4" }, "source": [ "
1. b) Building Volume Per Capita (BVPC): \n", "BVPC = total population of a community divided by sum of building volume
" ] }, { "cell_type": "code", "execution_count": 18, "id": "538cc014-8002-4f1c-8b92-77890f4bed8c", "metadata": {}, "outputs": [], "source": [ "#gdf_pop.head(3)" ] }, { "cell_type": "code", "execution_count": 19, "id": "94d28d52", "metadata": { "id": "d9a75295", "outputId": "a4db8ecc-c9b3-4ce1-f638-312b2e82006e" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idosm_idbuildingbuilding:levelsbuilding_heightroof_heightground_heightplus_codeaddressamenityoperatorresidentialbottom_roof_heightbuilding:usegeometrypopareavolumebvpc
12289266230212289266.0house14.1189.86185.7599954FRWFFMF+W7J22 Clarkeson Street Mamre 7347 Cape TownNaNNaNNaNNaNNaNPOLYGON ((265302.8715881496 6288753.930217357,...6344.6797591413.187012235.531169
12357148230312357148.0house14.1197.36193.2599954FRWFFPJ+P7W2 Tol Street Mamre 7347 Cape TownNaNNaNNaNNaNNaNPOLYGON ((265989.6485932828 6288995.734908563,...6329.1894351349.676685224.946114
\n", "
" ], "text/plain": [ " id osm_id building building:levels building_height \\\n", "12289266 2302 12289266.0 house 1 4.1 \n", "12357148 2303 12357148.0 house 1 4.1 \n", "\n", " roof_height ground_height plus_code \\\n", "12289266 189.86 185.759995 4FRWFFMF+W7J \n", "12357148 197.36 193.259995 4FRWFFPJ+P7W \n", "\n", " address amenity operator \\\n", "12289266 22 Clarkeson Street Mamre 7347 Cape Town NaN NaN \n", "12357148 2 Tol Street Mamre 7347 Cape Town NaN NaN \n", "\n", " residential bottom_roof_height building:use \\\n", "12289266 NaN NaN NaN \n", "12357148 NaN NaN NaN \n", "\n", " geometry pop area \\\n", "12289266 POLYGON ((265302.8715881496 6288753.930217357,... 6 344.679759 \n", "12357148 POLYGON ((265989.6485932828 6288995.734908563,... 6 329.189435 \n", "\n", " volume bvpc \n", "12289266 1413.187012 235.531169 \n", "12357148 1349.676685 224.946114 " ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#gdf_pop['area'] = gdf_pop['geometry'].area#\\.map(lambda p: p.area)\n", "gdf_pop['area'] = gdf_pop['geometry'].apply(lambda geom: geom.area if geom else 0)\n", "gdf_pop['volume'] = gdf_pop['area'] * gdf_pop['building_height']\n", "\n", "#- remove the volume of the ground floor (unoccupied) when building:levels > 7 [this is an arbitrary number based on local knowledge]\n", "#- typically the space is reserved for some other function: retail, etc. \n", "gdf_pop['volume'] = [\n", " (row['volume'] - row['area'] * 2.8) if (\n", " 'social_facility' in row and row['social_facility'] is np.nan and row['building:levels'] > 7 and\n", " row['building'] in ['residential', 'apartments', 'student']\n", " ) else row['volume']\n", " for _, row in gdf_pop.iterrows()\n", "]\n", "\n", "gdf_pop['bvpc'] = gdf_pop['volume'] / gdf_pop['pop']\n", "\n", "gdf_pop.tail(2)" ] }, { "cell_type": "code", "execution_count": 20, "id": "ce47ce5e", "metadata": { "id": "6d44d125", "outputId": "2d3355f4-5870-492a-d2db-4ad3a7dfedc8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "count 1977.000000\n", "mean 76.075547\n", "std 50.348933\n", "min 11.089562\n", "25% 34.480285\n", "50% 66.734589\n", "75% 102.864767\n", "max 400.313316\n", "Name: bvpc, dtype: float64\n" ] } ], "source": [ "print(gdf_pop['bvpc'].describe())" ] }, { "cell_type": "code", "execution_count": 21, "id": "e0abe768", "metadata": { "id": "c98dafa0", "outputId": "d2b038a0-fddb-4fae-9b34-ad020453140d" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Building Volume Per Capita (BVPC): 78.32\n" ] } ], "source": [ "bvpc = round(gdf_pop['volume'].sum() / est_pop, 3)\n", "\n", "print('Building Volume Per Capita (BVPC):', bvpc)" ] }, { "cell_type": "markdown", "id": "05e8659c", "metadata": { "id": "f6576dc6" }, "source": [ "
\n", "\n", "**This BVPC value is general.** \n", "\n", "We can seperate `building:house` from `building:cabin` and `building:residential` to undertand the differences between ***formal and informal*** housing in this area.\n", " \n", "**We want to understand the living space *(the cubic-meter BVPC value)* each person has in thier home**\n", "
" ] }, { "cell_type": "code", "execution_count": 22, "id": "29ac68f3-d8ec-4e78-82ba-746d8f050033", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "FORMAL: Population: 9864 with Building Volume Per Capita (BVPC): 83.717\n", "\n", "STUDENT RESIDENCE: Population: 0 with Building Volume Per Capita (BVPC): 0\n", "\n", "INFORMAL: Population: 1332 with Building Volume Per Capita (BVPC) 38.349\n" ] } ], "source": [ "formal = gdf_pop[gdf_pop[\"building\"].isin(['house', 'semidetached_house', 'terrace', 'terraced', 'apartments'])].copy()\n", "f_pop = formal['pop'].sum()\n", "\n", "informal = gdf_pop[gdf_pop[\"building\"].isin(['residential', 'cabin'])].copy()\n", "inf_pop = informal['pop'].sum()\n", "\n", "#- student\n", "stu = gdf_pop[gdf_pop[\"building\"].isin(['student', 'dormitory'])].copy()\n", "stu_pop = stu['pop'].sum()\n", "\n", "bvpc_formal = round(formal['volume'].sum() / formal['pop'].sum()if formal['pop'].sum() != 0 else 0, 3)\n", "bvpc_informal = round(informal['volume'].sum() / informal['pop'].sum() if informal['pop'].sum() != 0 else 0, 3)\n", "bvpc_stu = round(stu['volume'].sum() / stu['pop'].sum() if stu['pop'].sum() != 0 else 0, 3)\n", "\n", "print('FORMAL: Population: ', f_pop, ' with Building Volume Per Capita (BVPC):', bvpc_formal)\n", "print('')\n", "print('STUDENT RESIDENCE: Population: ', stu_pop, ' with Building Volume Per Capita (BVPC):', bvpc_stu)\n", "print('')\n", "print('INFORMAL: Population: ', inf_pop, ' with Building Volume Per Capita (BVPC)', bvpc_informal)" ] }, { "cell_type": "markdown", "id": "e2d29b09-6b5e-481d-a208-52bb27dea51c", "metadata": {}, "source": [ "
Warning: \n", " \n", "\n", "These are LoD1 3D City Models and works well in these types of areas. \n", "LoD2 would offer a more representative BVpC [(Ghosh, T; et al. 2020)](https://www.researchgate.net/publication/343185735_Building_Volume_Per_Capita_BVPC_A_Spatially_Explicit_Measure_of_Inequality_Relevant_to_the_SDGs) value; when the complexity of the built environment increases. \n", "\n", "Think about a `house` with living space in the roof structure, so called *'attic living'*, or an `apartment` / `residential` building with different levels, loft apartments and/or units in the turrets of a `building`. \n", "\n", "***consider***: this area seperates [building:cabin](https://wiki.openstreetmap.org/wiki/Tag:building%3Dcabin) from `building:residential` to more precisely represent informal structures without typical roof trussess but account for [social housing](https://en.wikipedia.org/wiki/Public_housing) that does
" ] }, { "cell_type": "markdown", "id": "5e87cbea-932d-465c-8dfe-f954c11d4600", "metadata": {}, "source": [ "
\n", " \n", "**To understand the performance in an [Urban setting](https://en.wikipedia.org/wiki/Urban_area) change `cell [2]` above:**\n", "\n", "**jparams** = uEstate (['University Estate'](https://en.wikipedia.org/wiki/University_Estate)) or sRiver (['Salt River'](https://en.wikipedia.org/wiki/Salt_River,_Cape_Town)) or obs (['Observatory'](https://en.wikipedia.org/wiki/Observatory,_Cape_Town)) *(with residents per formal house = 4 | 5 in Salt River and residents per informal structure = 3)* and cput ('Cape Peninsula University of Technology (Bellville Campus)') \n", "\n", "**osm_type** = 'relation' with CPUT (Bellville Campus) as 'way'\n", "\n", "
\n", " \n", " " ] }, { "cell_type": "markdown", "id": "bbb64ecc", "metadata": { "id": "c0daa088" }, "source": [ "## 2. Interactive Visualization\n", "\n", "You might want to create and share an `html` visualization.\n", "\n", "
\n", " \n", "_In this example we identify building stock by **color** but you are limited only through your imagination and the data you have access too_\n", "
" ] }, { "cell_type": "code", "execution_count": 23, "id": "ad6fa443-4a22-41ce-b7a0-28d69886173c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\n", "Name: WGS 84 / UTM zone 34S\n", "Axis Info [cartesian]:\n", "- E[east]: Easting (metre)\n", "- N[north]: Northing (metre)\n", "Area of Use:\n", "- name: Between 18°E and 24°E, southern hemisphere between 80°S and equator, onshore and offshore. Angola. Botswana. Democratic Republic of the Congo (Zaire). Namibia. South Africa. Zambia.\n", "- bounds: (18.0, -80.0, 24.0, 0.0)\n", "Coordinate Operation:\n", "- name: UTM zone 34S\n", "- method: Transverse Mercator\n", "Datum: World Geodetic System 1984 ensemble\n", "- Ellipsoid: WGS 84\n", "- Prime Meridian: Greenwich" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gdf.crs" ] }, { "cell_type": "markdown", "id": "c5a64b72-e1f0-4ee8-a346-8bbab4eae03f", "metadata": {}, "source": [ "\"proj\"\n", "
\n", "
\n", "\n", "We need a ***Geographic*** Coordinate Reference System.\n", "\n", " \n", " Name: WGS 84\n", " Axis Info [ellipsoidal]:\n", " - Lat[north]: Geodetic latitude (degree)\n", " - Lon[east]: Geodetic longitude (degree)\n", " Area of Use:\n", " - name: World.\n", " - bounds: (-180.0, -90.0, 180.0, 90.0)\n", " Datum: World Geodetic System 1984 ensemble\n", " - Ellipsoid: WGS 84\n", " - Prime Meridian: Greenwich" ] }, { "cell_type": "code", "execution_count": 24, "id": "50bb7efc-54cf-4688-b5cc-95761d607759", "metadata": {}, "outputs": [], "source": [ "gdf = gdf.to_crs(4326)" ] }, { "cell_type": "code", "execution_count": 25, "id": "ebffd46f", "metadata": {}, "outputs": [], "source": [ "# -- get the location for pydeck\n", "\n", "# combine all geometries\n", "geom = shapely.unary_union(gdf['geometry'])\n", "# centroid\n", "xy = (geom.centroid.x, geom.centroid.y)\n", "\n", "# bounding box\n", "minx, miny, maxx, maxy = geom.bounds\n", "bbox = [minx, miny, maxx, maxy]" ] }, { "cell_type": "code", "execution_count": 26, "id": "6d620069", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(['yes', 'church', 'house', 'cabin', 'public', 'civic', 'office',\n", " 'retail', 'clinic', 'school', 'garage', 'greenhouse', 'roof',\n", " 'kindergarten', 'clubhouse', 'guest_house', 'service', 'detached',\n", " 'shed'], dtype=object)" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# have a look at the building type and amenities available\n", "gdf['building'].unique()" ] }, { "cell_type": "markdown", "id": "95db7a64-6670-4b1d-86ae-a1476ef72f78", "metadata": {}, "source": [ "\n", "
Building Stock: To differentiate a school, housing, retail, healthcare and community focused facilities (library, municipal office, community centre) we color the buildings - we harvest the osm tags [amenity and building type] directly.
" ] }, { "cell_type": "code", "execution_count": 27, "id": "f777c749", "metadata": {}, "outputs": [], "source": [ "# colour buildings based on use / amenity\n", "def color(bld):\n", " #- formal house\n", " if bld == 'house' or bld == 'semidetached_house' or bld == 'terrace': #- add maisonette, duplex, etc. \n", " return [255, 255, 204] #-grey\n", " if bld == 'apartments':\n", " return [252, 194, 3] #-orange \n", " #- informal structure / social housing / student\n", " if bld == 'residential' or bld == 'dormitory' or bld == 'student' or bld == 'cabin':\n", " return [119, 3, 252] #-purple\n", " \n", " if bld == 'garage' or bld == 'parking':\n", " return [3, 132, 252] #-blue \n", " if bld == 'retail' or bld == 'supermarket':\n", " return [253, 141, 60]\n", " if bld == 'office' or bld == 'commercial':\n", " return [185, 206, 37]\n", " if bld == 'school' or bld == 'kindergarten' or bld == 'university' or bld == 'college':\n", " return [128, 0, 38]\n", " if bld == 'clinic' or bld == 'doctors' or bld == 'hospital':\n", " return [89, 182, 178]\n", " if bld == 'community_centre' or bld == 'service' or bld == 'post_office' or bld == 'hall' \\\n", " or bld == 'townhall' or bld == 'police' or bld == 'library' or bld == 'fire_station' :\n", " return [181, 182, 89]\n", " if bld == 'warehouse' or bld == 'industrial':\n", " return [193, 255, 193]\n", " if bld == 'hotel':\n", " return [139, 117, 0]\n", " if bld == 'church' or bld == 'mosque' or bld == 'synagogue':\n", " return [225, 225, 51]\n", " else:\n", " return [255, 255, 204]\n", "\n", "gdf[\"fill_color\"] = gdf['building'].apply(lambda x: color(x))" ] }, { "cell_type": "code", "execution_count": 28, "id": "5e88b1da", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idosm_idbuildingbuilding:levelsbuilding_heightroof_heightground_heightplus_codeaddressamenityoperatorresidentialbottom_roof_heightbuilding:usegeometryfill_color
3281184460328118446.0yes14.1183.53179.4299934FRWFFVC+P79NaNNaNNaNNaNNaNNaNPOLYGON ((18.4706033 -33.505787600000005, 18.4...[255, 255, 204]
3281184471328118447.0church26.9185.94179.0399934FRWFFVC+H9QMamre Moravian Church Kerk Street Mamre 7347 C...place_of_worshipNaNNaNNaNNaNPOLYGON ((18.4709153 -33.5059178, 18.4709287 -...[225, 225, 51]
\n", "
" ], "text/plain": [ " id osm_id building building:levels building_height \\\n", "328118446 0 328118446.0 yes 1 4.1 \n", "328118447 1 328118447.0 church 2 6.9 \n", "\n", " roof_height ground_height plus_code \\\n", "328118446 183.53 179.429993 4FRWFFVC+P79 \n", "328118447 185.94 179.039993 4FRWFFVC+H9Q \n", "\n", " address \\\n", "328118446 NaN \n", "328118447 Mamre Moravian Church Kerk Street Mamre 7347 C... \n", "\n", " amenity operator residential bottom_roof_height \\\n", "328118446 NaN NaN NaN NaN \n", "328118447 place_of_worship NaN NaN NaN \n", "\n", " building:use geometry \\\n", "328118446 NaN POLYGON ((18.4706033 -33.505787600000005, 18.4... \n", "328118447 NaN POLYGON ((18.4709153 -33.5059178, 18.4709287 -... \n", "\n", " fill_color \n", "328118446 [255, 255, 204] \n", "328118447 [225, 225, 51] " ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#- look\n", "gdf.head(2)" ] }, { "cell_type": "code", "execution_count": 29, "id": "953ef059", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "## ~ (x, y) - bl, tl, tr, br ~~ or ~~ sw, nw, ne, se\n", "#area = [[[18.4377, -33.9307], [18.4377, -33.9283], [18.4418, -33.9283], [18.4418, -33.9307]]]\n", "area = [[[bbox[0], bbox[1]], [bbox[0], bbox[3]], \n", " [bbox[2], bbox[3]], [bbox[2], bbox[1]]]]\n", "\n", "builds = city3D.gdf_to_geojson(gdf)\n", "\n", "## ~ (y, x)\n", "view_state = pdk.ViewState(latitude=xy[1], longitude=xy[0], zoom=16.5, max_zoom=19, pitch=72, \n", " bearing=80)\n", "\n", "land = pdk.Layer(\n", " \"PolygonLayer\",\n", " area,\n", " stroked=False,\n", " # processes the data as a flat longitude-latitude pair\n", " get_polygon=\"-\",\n", " get_fill_color=[0, 0, 0, 1],\n", " #material = True,\n", " #shadowEnabled = True\n", ")\n", "building_layer = pdk.Layer(\n", " #\"PolygonLayer\",\n", " \"GeoJsonLayer\",\n", " builds,\n", " #id=\"geojson\",\n", " opacity=0.3,\n", " stroked=False,\n", " get_polygon=\"geometry.coordinates\",\n", " filled=True,\n", " extruded=True,\n", " wireframe=False,\n", " get_elevation=\"properties.building_height\",\n", " #get_fill_color=\"[255, 255, 255]\", #255, 255, 255\n", " get_fill_color=\"properties.fill_color\",\n", " get_line_color=\"properties.fill_color\",#[255, 255, 255],\n", " #material = True, \n", " #shadowEnabled = True, \n", " auto_highlight=True,\n", " pickable=True,\n", ")\n", "\n", "tooltip = {\"html\": \"Levels: {building:levels}
Address: {address}\\\n", "
Plus Code: {plus_code}
Building Type: {building}\"}\n", "\n", "#change the tooltip to show bus routes and comment out the previous\n", "#tooltip = {\"html\": \"Route: {name}
\"}\n", "\n", "r = pdk.Deck(layers=[land, building_layer],#, greenspaces_layer, p_layer, water_layer, r_layer], #\n", " #views=[{\"@@type\": \"MapView\", \"controller\": True}],\n", " initial_view_state=view_state,\n", " map_style = 'dark_no_labels', #pdk.map_styles.LIGHT,\n", " tooltip=tooltip)\n", "#save\n", "r.to_html(\"./result/interactiveAlt.html\", offline=True)" ] }, { "cell_type": "markdown", "id": "7addad28", "metadata": {}, "source": [ "**on a laptop without a mouse:**\n", "\n", "- `trackpad left-click drag-left` and `-right`;\n", "- `Ctrl left-click drag-up`, `-down`, `-left` and `-right` to rotate and so-on and\n", "- `+` next to Backspace zoom-in and `-` next to `+` zoom-out.\n", "\n", "**Now you do your community.** ~ If your area needs [OpenStreetMap](https://en.wikipedia.org/wiki/OpenStreetMap) data and you want to contribute please follow the [Guide](https://wiki.openstreetmap.org/wiki/Beginners%27_guide)." ] }, { "cell_type": "markdown", "id": "46520c64-812d-43d8-8733-a2c2a8a5f724", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "id": "b3d0d0d0-8712-4f5a-a992-5e6d7a9e741d", "metadata": {}, "source": [ "
3. Possible Secondary and Tertiary level conversations starters:
" ] }, { "cell_type": "markdown", "id": "3d476cd9-7749-4d8c-836c-f990ad292f09", "metadata": {}, "source": [ "
\n", " \n", "**To understand the performance in an [Urban setting](https://en.wikipedia.org/wiki/Urban_area) change `cell [2]` above:**\n", "\n", "**jparams** = uEstate (['University Estate'](https://en.wikipedia.org/wiki/University_Estate)) or sRiver (['Salt River'](https://en.wikipedia.org/wiki/Salt_River,_Cape_Town)) or obs (['Observatory'](https://en.wikipedia.org/wiki/Observatory,_Cape_Town)) *(with residents per formal house = 4 | 5 in Salt River and residents per informal structure = 3)* and cput ('Cape Peninsula University of Technology (Bellville Campus)') \n", "
" ] }, { "cell_type": "markdown", "id": "e82860fd-6821-44b8-b3e3-1d5ddddc94c8", "metadata": {}, "source": [ "| **Topic** | **Secondary Level Questions** | **Tertiary Level Questions** |\n", "|------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n", "| **Basic Understanding and Observations** | - What types of buildings are most common in the area (houses, apartments, retail, etc.)?
- Can you identify any patterns in the distribution of different types of buildings (e.g., are retail stores concentrated in certain areas)? | - How does the building stock composition (e.g., ratio of houses) correlate with the population? *demographics (e.g., age distribution, household size) for the area will strengthen the analysis!*
- Analyze the relationship between building density and population. What urban planning theories can explain this relationship? |\n", "| **Spatial Relationships and Impacts** | - How does the location of residential areas compare to the location of retail and commercial areas?
- What impact might the density and distribution of buildings have on local traffic and transportation?
- How might the population distribution affect the demand for local services such as schools, hospitals, and parks? | - Evaluate the accessibility of essential services (e.g., healthcare, education) in relation to the population and building types.
- Assess the potential social and economic impacts of a proposed new residential or commercial development in the area. |\n", "| **Socioeconomic and Environmental Considerations** | - Are there any correlations between the types of housing available and the household size? *additional demographics (e.g., income level) for the area will strengthen the analysis!*
- How might the current building stock and population influence the local economy? *demographics (e.g., age distribution, household size) for the area will strengthen the analysis!*
- What are some potential environmental impacts of the current building distribution, such as green space availability or pollution levels? | - How does the current building stock support or hinder sustainable development goals (e.g., energy efficiency, reduced carbon footprint)?
- What strategies could be implemented to increase the resilience of the community to environmental or economic changes? |\n", "| **Future Planning and Development** | - Based on the current building stock and population metrics, what areas might benefit from additional housing or commercial development?
- How could urban planners use this information to improve the quality of life in the area?
- What changes would you recommend to better balance residential, commercial, and recreational spaces? | - How might different zoning regulations impact the distribution of residential, commercial, and industrial buildings in the future?
- Propose urban design solutions that could improve the sustainability and livability of the area, considering both current metrics and future projections. |\n", "| **Quantitative and Qualitative Research** | |- Design a research study to investigate the impact of building type diversity on community wellbeing. What methodologies would you use?
- Analyze historical data to understand trends in building development and population growth. How have these trends shaped the current urban landscape?
- Conduct a SWOT analysis (Strengths, Weaknesses, Opportunities, Threats) of the area based on the building stock and population metrics. |" ] }, { "cell_type": "markdown", "id": "7e1f3216-30fd-425c-add9-3291969387f6", "metadata": {}, "source": [ "***\n", "\n", "**Now you do your community.** ~ If your area needs [OpenStreetMap](https://en.wikipedia.org/wiki/OpenStreetMap) data and you want to contribute please follow the [Guide](https://wiki.openstreetmap.org/wiki/Beginners%27_guide). " ] }, { "cell_type": "code", "execution_count": null, "id": "f60ffdff-8ca5-42f7-a1a5-3e67c5d7868b", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "colab": { "provenance": [] }, "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.9.23" } }, "nbformat": 4, "nbformat_minor": 5 }