{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Spatial join\n",
"\n",
"[Spatial join](http://wiki.gis.com/wiki/index.php/Spatial_Join) is\n",
"yet another classic GIS problem. Getting attributes from one layer and\n",
"transferring them into another layer based on their spatial relationship\n",
"is something you most likely need to do on a regular basis.\n",
"\n",
"In the previous section we learned how to perform **a Point in Polygon query**.\n",
"We can now use the same logic to conduct **a spatial join** between two layers based on their\n",
"spatial relationship. We could, for example, join the attributes of a polygon layer into a point layer where each point would get the\n",
"attributes of a polygon that ``contains`` the point.\n",
"\n",
"Luckily, [spatial join is already implemented in Geopandas](http://geopandas.org/mergingdata.html#spatial-joins), thus we do not need to create our own function for doing it. There are three possible types of\n",
"join that can be applied in spatial join that are determined with ``op`` -parameter in the ``gpd.sjoin()`` -function:\n",
"\n",
"- ``\"intersects\"``\n",
"- ``\"within\"``\n",
"- ``\"contains\"``\n",
"\n",
"Sounds familiar? Yep, all of those spatial relationships were discussed\n",
"in the [Point in Polygon lesson](point-in-polygon.ipynb), thus you should know how they work. \n",
"\n",
"Furthermore, pay attention to the different options for the type of join via the `how` parameter; \"left\", \"right\" and \"inner\". You can read more about these options in the [geopandas sjoin documentation](http://geopandas.org/mergingdata.html#sjoin-arguments) and pandas guide for [merge, join and concatenate](https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html)\n",
"\n",
"Let's perform a spatial join between these two layers:\n",
"- **Addresses:** the geocoded address-point (we created this Shapefile in the geocoding tutorial)\n",
"- **Population grid:** 250m x 250m grid polygon layer that contains population information from the Helsinki Region.\n",
" - The population grid a dataset is produced by the **Helsinki Region Environmental\n",
"Services Authority (HSY)** (see [this page](https://www.hsy.fi/fi/asiantuntijalle/avoindata/Sivut/AvoinData.aspx?dataID=7) to access data from different years).\n",
" - You can download the data from [from this link](https://www.hsy.fi/sites/AvoinData/AvoinData/SYT/Tietoyhteistyoyksikko/Shape%20(Esri)/V%C3%A4est%C3%B6tietoruudukko/Vaestotietoruudukko_2018_SHP.zip) in the [Helsinki Region Infroshare\n",
"(HRI) open data portal](https://hri.fi/en_gb/).\n",
"\n",
"\n",
"\n",
"- Here, we will access the data directly from the HSY wfs:\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/aagesenh/.conda/envs/python-gis/lib/python3.8/site-packages/geopandas/_compat.py:111: UserWarning: The Shapely GEOS version (3.9.1dev-CAPI-1.14.1) is incompatible with the GEOS version PyGEOS was compiled with (3.9.1-CAPI-1.14.2). Conversions between both will be slow.\n",
" warnings.warn(\n"
]
}
],
"source": [
"import geopandas as gpd\n",
"from pyproj import CRS\n",
"import requests\n",
"import geojson\n",
"\n",
"# Specify the url for web feature service\n",
"url = 'https://kartta.hsy.fi/geoserver/wfs'\n",
"\n",
"# Specify parameters (read data in json format). \n",
"# Available feature types in this particular data source: http://geo.stat.fi/geoserver/vaestoruutu/wfs?service=wfs&version=2.0.0&request=describeFeatureType\n",
"params = dict(service='WFS', \n",
" version='2.0.0', \n",
" request='GetFeature', \n",
" typeName='asuminen_ja_maankaytto:Vaestotietoruudukko_2018', \n",
" outputFormat='json')\n",
"\n",
"# Fetch data from WFS using requests\n",
"r = requests.get(url, params=params)\n",
"\n",
"# Create GeoDataFrame from geojson\n",
"pop = gpd.GeoDataFrame.from_features(geojson.loads(r.content))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Check the result: "
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
geometry
\n",
"
index
\n",
"
asukkaita
\n",
"
asvaljyys
\n",
"
ika0_9
\n",
"
ika10_19
\n",
"
ika20_29
\n",
"
ika30_39
\n",
"
ika40_49
\n",
"
ika50_59
\n",
"
ika60_69
\n",
"
ika70_79
\n",
"
ika_yli80
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
POLYGON ((25472499.995 6689749.005, 25472499.9...
\n",
"
688
\n",
"
9
\n",
"
28.0
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
\n",
"
\n",
"
1
\n",
"
POLYGON ((25472499.995 6685998.998, 25472499.9...
\n",
"
703
\n",
"
5
\n",
"
51.0
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
\n",
"
\n",
"
2
\n",
"
POLYGON ((25472499.995 6684249.004, 25472499.9...
\n",
"
710
\n",
"
8
\n",
"
44.0
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
\n",
"
\n",
"
3
\n",
"
POLYGON ((25472499.995 6683999.005, 25472499.9...
\n",
"
711
\n",
"
5
\n",
"
90.0
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
\n",
"
\n",
"
4
\n",
"
POLYGON ((25472499.995 6682998.998, 25472499.9...
\n",
"
715
\n",
"
11
\n",
"
41.0
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
99
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" geometry index asukkaita \\\n",
"0 POLYGON ((25472499.995 6689749.005, 25472499.9... 688 9 \n",
"1 POLYGON ((25472499.995 6685998.998, 25472499.9... 703 5 \n",
"2 POLYGON ((25472499.995 6684249.004, 25472499.9... 710 8 \n",
"3 POLYGON ((25472499.995 6683999.005, 25472499.9... 711 5 \n",
"4 POLYGON ((25472499.995 6682998.998, 25472499.9... 715 11 \n",
"\n",
" asvaljyys ika0_9 ika10_19 ika20_29 ika30_39 ika40_49 ika50_59 \\\n",
"0 28.0 99 99 99 99 99 99 \n",
"1 51.0 99 99 99 99 99 99 \n",
"2 44.0 99 99 99 99 99 99 \n",
"3 90.0 99 99 99 99 99 99 \n",
"4 41.0 99 99 99 99 99 99 \n",
"\n",
" ika60_69 ika70_79 ika_yli80 \n",
"0 99 99 99 \n",
"1 99 99 99 \n",
"2 99 99 99 \n",
"3 99 99 99 \n",
"4 99 99 99 "
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pop.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Okey so we have multiple columns in the dataset but the most important\n",
"one here is the column `asukkaita` (\"population\" in Finnish) that\n",
"tells the amount of inhabitants living under that polygon.\n",
"\n",
"- Let's change the name of that column into `pop18` so that it is\n",
" more intuitive. As you might remember, we can easily rename (Geo)DataFrame column names using the ``rename()`` function where we pass a dictionary of new column names like this: ``columns={'oldname': 'newname'}``."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Index(['geometry', 'index', 'pop18', 'asvaljyys', 'ika0_9', 'ika10_19',\n",
" 'ika20_29', 'ika30_39', 'ika40_49', 'ika50_59', 'ika60_69', 'ika70_79',\n",
" 'ika_yli80'],\n",
" dtype='object')"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Change the name of a column\n",
"pop = pop.rename(columns={'asukkaita': 'pop18'})\n",
"\n",
"# Check the column names\n",
"pop.columns"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's also get rid of all unnecessary columns by selecting only columns that we need i.e. ``pop18`` and ``geometry``"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Subset columns\n",
"pop = pop[[\"pop18\", \"geometry\"]]"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
pop18
\n",
"
geometry
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
9
\n",
"
POLYGON ((25472499.995 6689749.005, 25472499.9...
\n",
"
\n",
"
\n",
"
1
\n",
"
5
\n",
"
POLYGON ((25472499.995 6685998.998, 25472499.9...
\n",
"
\n",
"
\n",
"
2
\n",
"
8
\n",
"
POLYGON ((25472499.995 6684249.004, 25472499.9...
\n",
"
\n",
"
\n",
"
3
\n",
"
5
\n",
"
POLYGON ((25472499.995 6683999.005, 25472499.9...
\n",
"
\n",
"
\n",
"
4
\n",
"
11
\n",
"
POLYGON ((25472499.995 6682998.998, 25472499.9...
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" pop18 geometry\n",
"0 9 POLYGON ((25472499.995 6689749.005, 25472499.9...\n",
"1 5 POLYGON ((25472499.995 6685998.998, 25472499.9...\n",
"2 8 POLYGON ((25472499.995 6684249.004, 25472499.9...\n",
"3 5 POLYGON ((25472499.995 6683999.005, 25472499.9...\n",
"4 11 POLYGON ((25472499.995 6682998.998, 25472499.9..."
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pop.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we have cleaned the data and have only those columns that we need\n",
"for our analysis."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Join the layers\n",
"\n",
"Now we are ready to perform the spatial join between the two layers that\n",
"we have. The aim here is to get information about **how many people live\n",
"in a polygon that contains an individual address-point** . Thus, we want\n",
"to join attributes from the population layer we just modified into the\n",
"addresses point layer ``addresses.shp`` that we created trough gecoding in the previous section.\n",
"\n",
"- Read the addresses layer into memory:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Addresses filpath\n",
"addr_fp = r\"data/addresses.shp\"\n",
"\n",
"# Read data\n",
"addresses = gpd.read_file(addr_fp)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
address
\n",
"
id
\n",
"
addr
\n",
"
geometry
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
Ruoholahti, 14, Itämerenkatu, Ruoholahti, Läns...
\n",
"
1000
\n",
"
Itämerenkatu 14, 00101 Helsinki, Finland
\n",
"
POINT (24.91556 60.16320)
\n",
"
\n",
"
\n",
"
1
\n",
"
Kamppi, 1, Kampinkuja, Kamppi, Eteläinen suurp...
\n",
"
1001
\n",
"
Kampinkuja 1, 00100 Helsinki, Finland
\n",
"
POINT (24.93169 60.16902)
\n",
"
\n",
"
\n",
"
2
\n",
"
Kauppakeskus Citycenter, 8, Kaivokatu, Keskust...
\n",
"
1002
\n",
"
Kaivokatu 8, 00101 Helsinki, Finland
\n",
"
POINT (24.94179 60.16989)
\n",
"
\n",
"
\n",
"
3
\n",
"
Hermannin rantatie, Verkkosaari, Kalasatama, S...
\n",
"
1003
\n",
"
Hermannin rantatie 1, 00580 Helsinki, Finland
\n",
"
POINT (24.97783 60.18892)
\n",
"
\n",
"
\n",
"
4
\n",
"
Hesburger, 9, Tyynenmerenkatu, Jätkäsaari, Län...
\n",
"
1005
\n",
"
Tyynenmerenkatu 9, 00220 Helsinki, Finland
\n",
"
POINT (24.92160 60.15665)
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" address id \\\n",
"0 Ruoholahti, 14, Itämerenkatu, Ruoholahti, Läns... 1000 \n",
"1 Kamppi, 1, Kampinkuja, Kamppi, Eteläinen suurp... 1001 \n",
"2 Kauppakeskus Citycenter, 8, Kaivokatu, Keskust... 1002 \n",
"3 Hermannin rantatie, Verkkosaari, Kalasatama, S... 1003 \n",
"4 Hesburger, 9, Tyynenmerenkatu, Jätkäsaari, Län... 1005 \n",
"\n",
" addr geometry \n",
"0 Itämerenkatu 14, 00101 Helsinki, Finland POINT (24.91556 60.16320) \n",
"1 Kampinkuja 1, 00100 Helsinki, Finland POINT (24.93169 60.16902) \n",
"2 Kaivokatu 8, 00101 Helsinki, Finland POINT (24.94179 60.16989) \n",
"3 Hermannin rantatie 1, 00580 Helsinki, Finland POINT (24.97783 60.18892) \n",
"4 Tyynenmerenkatu 9, 00220 Helsinki, Finland POINT (24.92160 60.15665) "
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Check the head of the file\n",
"addresses.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In order to do a spatial join, the layers need to be in the same projection\n",
"\n",
"- Check the crs of input layers:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\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"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"addresses.crs"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"pop.crs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If the crs information is missing from the population grid, we can **define the coordinate reference system** as **ETRS GK-25 (EPSG:3879)** because we know what it is based on the [population grid metadata](https://hri.fi/data/dataset/vaestotietoruudukko). "
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# Define crs\n",
"pop.crs = CRS.from_epsg(3879).to_wkt()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\n",
"Name: ETRS89 / GK25FIN\n",
"Axis Info [cartesian]:\n",
"- N[north]: Northing (metre)\n",
"- E[east]: Easting (metre)\n",
"Area of Use:\n",
"- name: Finland - nominally onshore between 24°30'E and 25°30'E but may be used in adjacent areas if a municipality chooses to use one zone over its whole extent.\n",
"- bounds: (24.5, 59.94, 25.5, 68.9)\n",
"Coordinate Operation:\n",
"- name: Finland Gauss-Kruger zone 25\n",
"- method: Transverse Mercator\n",
"Datum: European Terrestrial Reference System 1989 ensemble\n",
"- Ellipsoid: GRS 1980\n",
"- Prime Meridian: Greenwich"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pop.crs"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Are the layers in the same projection?\n",
"addresses.crs == pop.crs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's re-project addresses to the projection of the population layer:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"addresses = addresses.to_crs(pop.crs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Let's make sure that the coordinate reference system of the layers\n",
"are identical"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"PROJCRS[\"ETRS89 / GK25FIN\",BASEGEOGCRS[\"ETRS89\",ENSEMBLE[\"European Terrestrial Reference System 1989 ensemble\",MEMBER[\"European Terrestrial Reference Frame 1989\"],MEMBER[\"European Terrestrial Reference Frame 1990\"],MEMBER[\"European Terrestrial Reference Frame 1991\"],MEMBER[\"European Terrestrial Reference Frame 1992\"],MEMBER[\"European Terrestrial Reference Frame 1993\"],MEMBER[\"European Terrestrial Reference Frame 1994\"],MEMBER[\"European Terrestrial Reference Frame 1996\"],MEMBER[\"European Terrestrial Reference Frame 1997\"],MEMBER[\"European Terrestrial Reference Frame 2000\"],MEMBER[\"European Terrestrial Reference Frame 2005\"],MEMBER[\"European Terrestrial Reference Frame 2014\"],ELLIPSOID[\"GRS 1980\",6378137,298.257222101,LENGTHUNIT[\"metre\",1]],ENSEMBLEACCURACY[0.1]],PRIMEM[\"Greenwich\",0,ANGLEUNIT[\"degree\",0.0174532925199433]],ID[\"EPSG\",4258]],CONVERSION[\"Finland Gauss-Kruger zone 25\",METHOD[\"Transverse Mercator\",ID[\"EPSG\",9807]],PARAMETER[\"Latitude of natural origin\",0,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8801]],PARAMETER[\"Longitude of natural origin\",25,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8802]],PARAMETER[\"Scale factor at natural origin\",1,SCALEUNIT[\"unity\",1],ID[\"EPSG\",8805]],PARAMETER[\"False easting\",25500000,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8806]],PARAMETER[\"False northing\",0,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8807]]],CS[Cartesian,2],AXIS[\"northing (N)\",north,ORDER[1],LENGTHUNIT[\"metre\",1]],AXIS[\"easting (E)\",east,ORDER[2],LENGTHUNIT[\"metre\",1]],USAGE[SCOPE[\"Cadastre, engineering survey, topographic mapping (large scale).\"],AREA[\"Finland - nominally onshore between 24°30'E and 25°30'E but may be used in adjacent areas if a municipality chooses to use one zone over its whole extent.\"],BBOX[59.94,24.5,68.9,25.5]],ID[\"EPSG\",3879]]\n",
"PROJCRS[\"ETRS89 / GK25FIN\",BASEGEOGCRS[\"ETRS89\",ENSEMBLE[\"European Terrestrial Reference System 1989 ensemble\",MEMBER[\"European Terrestrial Reference Frame 1989\"],MEMBER[\"European Terrestrial Reference Frame 1990\"],MEMBER[\"European Terrestrial Reference Frame 1991\"],MEMBER[\"European Terrestrial Reference Frame 1992\"],MEMBER[\"European Terrestrial Reference Frame 1993\"],MEMBER[\"European Terrestrial Reference Frame 1994\"],MEMBER[\"European Terrestrial Reference Frame 1996\"],MEMBER[\"European Terrestrial Reference Frame 1997\"],MEMBER[\"European Terrestrial Reference Frame 2000\"],MEMBER[\"European Terrestrial Reference Frame 2005\"],MEMBER[\"European Terrestrial Reference Frame 2014\"],ELLIPSOID[\"GRS 1980\",6378137,298.257222101,LENGTHUNIT[\"metre\",1]],ENSEMBLEACCURACY[0.1]],PRIMEM[\"Greenwich\",0,ANGLEUNIT[\"degree\",0.0174532925199433]],ID[\"EPSG\",4258]],CONVERSION[\"Finland Gauss-Kruger zone 25\",METHOD[\"Transverse Mercator\",ID[\"EPSG\",9807]],PARAMETER[\"Latitude of natural origin\",0,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8801]],PARAMETER[\"Longitude of natural origin\",25,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8802]],PARAMETER[\"Scale factor at natural origin\",1,SCALEUNIT[\"unity\",1],ID[\"EPSG\",8805]],PARAMETER[\"False easting\",25500000,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8806]],PARAMETER[\"False northing\",0,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8807]]],CS[Cartesian,2],AXIS[\"northing (N)\",north,ORDER[1],LENGTHUNIT[\"metre\",1]],AXIS[\"easting (E)\",east,ORDER[2],LENGTHUNIT[\"metre\",1]],USAGE[SCOPE[\"Cadastre, engineering survey, topographic mapping (large scale).\"],AREA[\"Finland - nominally onshore between 24°30'E and 25°30'E but may be used in adjacent areas if a municipality chooses to use one zone over its whole extent.\"],BBOX[59.94,24.5,68.9,25.5]],ID[\"EPSG\",3879]]\n"
]
},
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Check the crs of address points\n",
"print(addresses.crs)\n",
"\n",
"# Check the crs of population layer\n",
"print(pop.crs)\n",
"\n",
"# Do they match now?\n",
"addresses.crs == pop.crs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now they should be identical. Thus, we can be sure that when doing spatial\n",
"queries between layers the locations match and we get the right results\n",
"e.g. from the spatial join that we are conducting here.\n",
"\n",
"- Let's now join the attributes from ``pop`` GeoDataFrame into\n",
" ``addresses`` GeoDataFrame by using ``gpd.sjoin()`` -function:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/aagesenh/.conda/envs/python-gis/lib/python3.8/site-packages/IPython/core/interactiveshell.py:3361: FutureWarning: The `op` parameter is deprecated and will be removed in a future release. Please use the `predicate` parameter instead.\n",
" if (await self.run_code(code, result, async_=asy)):\n"
]
}
],
"source": [
"# Make a spatial join\n",
"join = gpd.sjoin(addresses, pop, how=\"inner\", op=\"within\")"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
address
\n",
"
id
\n",
"
addr
\n",
"
geometry
\n",
"
index_right
\n",
"
pop18
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
Ruoholahti, 14, Itämerenkatu, Ruoholahti, Läns...
\n",
"
1000
\n",
"
Itämerenkatu 14, 00101 Helsinki, Finland
\n",
"
POINT (25495311.608 6672258.695)
\n",
"
3252
\n",
"
515
\n",
"
\n",
"
\n",
"
1
\n",
"
Kamppi, 1, Kampinkuja, Kamppi, Eteläinen suurp...
\n",
"
1001
\n",
"
Kampinkuja 1, 00100 Helsinki, Finland
\n",
"
POINT (25496207.840 6672906.173)
\n",
"
3364
\n",
"
182
\n",
"
\n",
"
\n",
"
2
\n",
"
Kauppakeskus Citycenter, 8, Kaivokatu, Keskust...
\n",
"
1002
\n",
"
Kaivokatu 8, 00101 Helsinki, Finland
\n",
"
POINT (25496768.622 6673002.004)
\n",
"
3488
\n",
"
38
\n",
"
\n",
"
\n",
"
10
\n",
"
Rautatientori, Kaisaniemi, Kluuvi, Eteläinen s...
\n",
"
1011
\n",
"
Rautatientori 1, 00100 Helsinki, Finland
\n",
"
POINT (25496896.734 6673162.114)
\n",
"
3488
\n",
"
38
\n",
"
\n",
"
\n",
"
3
\n",
"
Hermannin rantatie, Verkkosaari, Kalasatama, S...
\n",
"
1003
\n",
"
Hermannin rantatie 1, 00580 Helsinki, Finland
\n",
"
POINT (25498769.713 6675121.127)
\n",
"
3822
\n",
"
61
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" address id \\\n",
"0 Ruoholahti, 14, Itämerenkatu, Ruoholahti, Läns... 1000 \n",
"1 Kamppi, 1, Kampinkuja, Kamppi, Eteläinen suurp... 1001 \n",
"2 Kauppakeskus Citycenter, 8, Kaivokatu, Keskust... 1002 \n",
"10 Rautatientori, Kaisaniemi, Kluuvi, Eteläinen s... 1011 \n",
"3 Hermannin rantatie, Verkkosaari, Kalasatama, S... 1003 \n",
"\n",
" addr \\\n",
"0 Itämerenkatu 14, 00101 Helsinki, Finland \n",
"1 Kampinkuja 1, 00100 Helsinki, Finland \n",
"2 Kaivokatu 8, 00101 Helsinki, Finland \n",
"10 Rautatientori 1, 00100 Helsinki, Finland \n",
"3 Hermannin rantatie 1, 00580 Helsinki, Finland \n",
"\n",
" geometry index_right pop18 \n",
"0 POINT (25495311.608 6672258.695) 3252 515 \n",
"1 POINT (25496207.840 6672906.173) 3364 182 \n",
"2 POINT (25496768.622 6673002.004) 3488 38 \n",
"10 POINT (25496896.734 6673162.114) 3488 38 \n",
"3 POINT (25498769.713 6675121.127) 3822 61 "
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"join.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Awesome! Now we have performed a successful spatial join where we got\n",
"two new columns into our ``join`` GeoDataFrame, i.e. ``index_right``\n",
"that tells the index of the matching polygon in the population grid and\n",
"``pop18`` which is the population in the cell where the address-point is\n",
"located.\n",
"\n",
"- Let's still check how many rows of data we have now:"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"31"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(join)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Did we lose some data here? \n",
"\n",
"- Check how many addresses we had originally:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"34"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(addresses)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we plot the layers on top of each other, we can observe that some of the points are located outside the populated grid squares (increase figure size if you can't see this properly!)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"