{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Example of Simple Geocoding in `geopandas`\n", "\n", "`geopandas` provides native access to the [`geopy`](https://geopy.readthedocs.io/en/latest/#usage-with-pandas) Pyhton package, which in turn provides access to a wide range of geocoding services.\n", "\n", "Some of these services require and API key, some don't. The *Nominatim* OpenStreetMap geocoder doesn't require an API key but does require a user-agent string (which can be anything...).\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can do simple geocoding directly on a *pandas* dataframe:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Location(Milton Keynes, South East, England, MK9 3PD, UK, (52.0429797, -0.7589607, 0.0))" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#Nominatim is the openstreetmap geocoder\n", "from geopy.geocoders import Nominatim\n", "\n", "#It doesn't need an API key, bit it likes to know who's calling\n", "geolocator = Nominatim(user_agent=\"TM351 demo\")\n", "\n", "location = geolocator.geocode(\"Milton Keynes\")\n", "location" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "('Milton Keynes, South East, England, MK9 3PD, UK',\n", " 52.0429797,\n", " -0.7589607,\n", " Point(52.0429797, -0.7589607, 0.0))" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#dir(location)\n", "#The point is a shapely object. Shapely types play nice with lots of geo things...\n", "location.address, location.latitude, location.longitude, location.point" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We could geocode items in a *panda* dataframe using something like this:" ] }, { "cell_type": "code", "execution_count": 3, "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", "
towns
0Milton Keynes
1London
2Newport, Isle of WIght
\n", "
" ], "text/plain": [ " towns\n", "0 Milton Keynes\n", "1 London\n", "2 Newport, Isle of WIght" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "df = pd.DataFrame({'towns':['Milton Keynes', 'London','Newport, Isle of WIght']})\n", "df" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 (Milton Keynes, South East, England, MK9 3PD, ...\n", "1 (London, Greater London, England, SW1A 2DX, UK...\n", "2 (Newport, Carisbrooke, Isle of Wight, South Ea...\n", "Name: towns, dtype: object" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df['towns'].apply(geolocator.geocode)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now do the geocoding:" ] }, { "cell_type": "code", "execution_count": 5, "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", "
townslocation
0Milton Keynes(Milton Keynes, South East, England, MK9 3PD, ...
1London(London, Greater London, England, SW1A 2DX, UK...
2Newport, Isle of WIght(Newport, Carisbrooke, Isle of Wight, South Ea...
\n", "
" ], "text/plain": [ " towns location\n", "0 Milton Keynes (Milton Keynes, South East, England, MK9 3PD, ...\n", "1 London (London, Greater London, England, SW1A 2DX, UK...\n", "2 Newport, Isle of WIght (Newport, Carisbrooke, Isle of Wight, South Ea..." ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df['location']=df['towns'].apply(geolocator.geocode)\n", "df" ] }, { "cell_type": "code", "execution_count": 6, "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", "
townslocationaddresslatitudelongitudepoint
0Milton Keynes(Milton Keynes, South East, England, MK9 3PD, ...Milton Keynes, South East, England, MK9 3PD, UK52.0429797-0.758960752 2m 34.7269s N, 0 45m 32.2585s W
1London(London, Greater London, England, SW1A 2DX, UK...London, Greater London, England, SW1A 2DX, UK51.5073219-0.127647451 30m 26.3588s N, 0 7m 39.5306s W
2Newport, Isle of WIght(Newport, Carisbrooke, Isle of Wight, South Ea...Newport, Carisbrooke, Isle of Wight, South Eas...50.6913105-1.316355650 41m 28.7178s N, 1 18m 58.8802s W
\n", "
" ], "text/plain": [ " towns location \\\n", "0 Milton Keynes (Milton Keynes, South East, England, MK9 3PD, ... \n", "1 London (London, Greater London, England, SW1A 2DX, UK... \n", "2 Newport, Isle of WIght (Newport, Carisbrooke, Isle of Wight, South Ea... \n", "\n", " address latitude longitude \\\n", "0 Milton Keynes, South East, England, MK9 3PD, UK 52.0429797 -0.7589607 \n", "1 London, Greater London, England, SW1A 2DX, UK 51.5073219 -0.1276474 \n", "2 Newport, Carisbrooke, Isle of Wight, South Eas... 50.6913105 -1.3163556 \n", "\n", " point \n", "0 52 2m 34.7269s N, 0 45m 32.2585s W \n", "1 51 30m 26.3588s N, 0 7m 39.5306s W \n", "2 50 41m 28.7178s N, 1 18m 58.8802s W " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#Here's how we could pull state out the the return object\n", "df['address'] = df['location'].apply(lambda x: x.address)\n", "df['latitude'] = df['location'].apply(lambda x: x.latitude)\n", "df['longitude'] = df['location'].apply(lambda x: x.longitude)\n", "df['point'] = df['location'].apply(lambda x: x.point)\n", "df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can then variously plot things on a map. Having a *shapely* `Point` object to hand, we might as well make use of that." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import folium\n", "\n", "mymap = folium.Map([51,0],zoom_start=6, tiles='openstreetmap')\n", "\n", "for point in df['point']:\n", " folium.Marker(point).add_to(mymap)\n", "\n", "mymap" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using `geopandas`\n", "\n", "We can also work with *geopandas*, an extended *pandas* dataframe format that has support for spatial objects and manipulations.\n", "\n", "Let's create a simple *geopandas* dataframe:" ] }, { "cell_type": "code", "execution_count": 8, "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", "
towns
0Milton Keynes
1London
2Newport, Isle of WIght
\n", "
" ], "text/plain": [ " towns\n", "0 Milton Keynes\n", "1 London\n", "2 Newport, Isle of WIght" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import geopandas as gpd\n", "\n", "gdf = gpd.GeoDataFrame({'towns':['Milton Keynes', 'London','Newport, Isle of WIght']})\n", "#Or we could cast from pandas using: gpd.GeoDataFrame(df)\n", "\n", "gdf" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The *geopandas* [docs](https://geopandas.readthedocs.io/en/latest/geocoding.html) suggest the geocoder lives in `gpd.tools.geocode`, so let's have a quick look at its docs:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "gpd.tools.geocode?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also look up docs for the service providers supported by `geopy`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import geopy\n", "dir(geopy)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "geopy.Nominatim?" ] }, { "cell_type": "code", "execution_count": 12, "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", "
addressgeometry
0Milton Keynes, South East, England, MK9 3PD, UKPOINT (-0.7589607 52.0429797)
1London, Greater London, England, SW1A 2DX, UKPOINT (-0.1276474 51.5073219)
2Newport, Carisbrooke, Isle of Wight, South Eas...POINT (-1.31635559782082 50.6913105)
\n", "
" ], "text/plain": [ " address \\\n", "0 Milton Keynes, South East, England, MK9 3PD, UK \n", "1 London, Greater London, England, SW1A 2DX, UK \n", "2 Newport, Carisbrooke, Isle of Wight, South Eas... \n", "\n", " geometry \n", "0 POINT (-0.7589607 52.0429797) \n", "1 POINT (-0.1276474 51.5073219) \n", "2 POINT (-1.31635559782082 50.6913105) " ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#Nominatim requires a user agent\n", "#Not sure offhand how to expicitly make this play nice? Maybe it does anyway?\n", "gpd.tools.geocode(gdf['towns'], provider='nominatim', user_agent='TM351 demo')" ] }, { "cell_type": "code", "execution_count": 13, "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", "
townsaddressgeometry
0Milton KeynesMilton Keynes, South East, England, MK9 3PD, UKPOINT (-0.7589607 52.0429797)
1LondonLondon, Greater London, England, SW1A 2DX, UKPOINT (-0.1276474 51.5073219)
2Newport, Isle of WIghtNewport, Carisbrooke, Isle of Wight, South Eas...POINT (-1.31635559782082 50.6913105)
\n", "
" ], "text/plain": [ " towns address \\\n", "0 Milton Keynes Milton Keynes, South East, England, MK9 3PD, UK \n", "1 London London, Greater London, England, SW1A 2DX, UK \n", "2 Newport, Isle of WIght Newport, Carisbrooke, Isle of Wight, South Eas... \n", "\n", " geometry \n", "0 POINT (-0.7589607 52.0429797) \n", "1 POINT (-0.1276474 51.5073219) \n", "2 POINT (-1.31635559782082 50.6913105) " ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gdf[['address','geometry']] = gpd.tools.geocode(gdf['towns'], provider='nominatim', user_agent='TM351 demo')\n", "gdf" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can plot these on a *folium* map easily enough by extracting the points as *geojson*, converting them to a format *folium* is happy with, and plotting that..." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "#Get a geojson export of the point locations\n", "geojson = gdf.to_json()" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mymap = folium.Map([51,0],zoom_start=6, tiles='openstreetmap')\n", "\n", "#Create an element from the geojson that folium can plot as a map layer\n", "points = folium.features.GeoJson(geojson)\n", "\n", "#Add the layer\n", "mymap.add_child(points)\n", "\n", "#Preview the map\n", "mymap" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.5.2" } }, "nbformat": 4, "nbformat_minor": 2 }