{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Data in/out: Preparing GeoDataFrames from spatial data \n", "\n", "Reading data into Python is usually the first step of an analysis workflow. There are various different GIS data formats available such as [Shapefile](https://en.wikipedia.org/wiki/Shapefile), [GeoJSON](https://en.wikipedia.org/wiki/GeoJSON), [KML](https://en.wikipedia.org/wiki/Keyhole_Markup_Language), and [GPKG](https://en.wikipedia.org/wiki/GeoPackage). Geopandas is capable of reading data from all of these formats (plus many more). \n", "\n", "This tutorial will show some typical examples how to read (and write) data from different sources. The main point in this section is to demonstrate the basic syntax for reading and writing data using short code snippets. You can find the example data sets in the data-folder. However, most of the example databases do not exists, but you can use and modify the example syntax according to your own setup.\n", "\n", "## Creating new GeoDataFrame from scratch\n", "\n", "Since geopandas takes advantage of Shapely geometric objects, it is possible to create spatial data from scratch by passing Shapely's geometric objects into the GeoDataFrame. This is useful as it makes it easy to convert e.g. a text file that contains coordinates into spatial data layers. Next we will see how to create a new GeoDataFrame from scratch and save it into a file. Our goal is to define a geometry that represents the outlines of the [Senate square in Helsinki, Finland](https://fi.wikipedia.org/wiki/Senaatintori).\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's start by creating a new empty `GeoDataFrame` object." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import geopandas as gpd" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "newdata = gpd.GeoDataFrame()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "geopandas.geodataframe.GeoDataFrame" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(newdata)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We have an empty GeoDataFrame! A geodataframe is basically a pandas DataFrame that should have one column dedicated for geometries. By default, the geometry-column should be named `geometry` (geopandas looks for geometries from this column). \n", "\n", "Let's create the `geometry` column:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "# Create a new column called 'geometry' to the GeoDataFrame\n", "newdata[\"geometry\"] = None" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Empty GeoDataFrame\n", "Columns: [geometry]\n", "Index: []\n" ] } ], "source": [ "print(newdata)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we have a `geometry` column in our GeoDataFrame but we still don't have any data.\n", "\n", "Let's create a Shapely `Polygon` repsenting the Helsinki Senate square that we can later insert to our GeoDataFrame:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "from shapely.geometry import Polygon" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "# Coordinates of the Helsinki Senate square in decimal degrees\n", "coordinates = [\n", " (24.950899, 60.169158),\n", " (24.953492, 60.169158),\n", " (24.953510, 60.170104),\n", " (24.950958, 60.169990),\n", "]" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "# Create a Shapely polygon from the coordinate-tuple list\n", "poly = Polygon(coordinates)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "POLYGON ((24.950899 60.169158, 24.953492 60.169158, 24.95351 60.170104, 24.950958 60.16999, 24.950899 60.169158))\n" ] } ], "source": [ "# Check the polyogon\n", "print(poly)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Okay, now we have an appropriate `Polygon` -object.\n", "\n", "Let's insert the polygon into our 'geometry' column of our GeoDataFrame on the first row:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [], "source": [ "# Insert the polygon into 'geometry' -column at row 0\n", "newdata.at[0, \"geometry\"] = poly" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " geometry\n", "0 POLYGON ((24.95090 60.16916, 24.95349 60.16916...\n" ] } ], "source": [ "# Let's see what we have now\n", "print(newdata)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Great, now we have a GeoDataFrame with a Polygon that we could already now export to a Shapefile. However, typically you might want to include some attribute information with the geometry. \n", "\n", "Let's add another column to our GeoDataFrame called `location` with text `Senaatintori` that describes the location of the feature." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " geometry location\n", "0 POLYGON ((24.95090 60.16916, 24.95349 60.16916... Senaatintori\n" ] } ], "source": [ "# Add a new column and insert data\n", "newdata.at[0, \"location\"] = \"Senaatintori\"\n", "\n", "# Let's check the data\n", "print(newdata)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Okay, now we have additional information that is useful for recognicing what the feature represents. \n", "\n", "The next step would be to **determine the coordinate reference system (CRS) for the GeoDataFrame.** GeoDataFrame has an attribute called `.crs` that shows the coordinate system of the data (we will discuss more about CRS in next chapter). In our case, the layer doesn't yet have any crs definition:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false, "jupyter": { "outputs_hidden": false } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "None\n" ] } ], "source": [ "print(newdata.crs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We passed the coordinates as latitude and longitude decimal degrees, so the correct CRS is WGS84 (epsg code: 4326). In this case, we can simply re-build the geodataframe and pass the correct crs information to the GeoDataFrame constructor. You will learn more about how to handle coordinate reference systems using pyproj CRS objects later in this chapter. \n", "\n", "Re-create the GeoDataFrame with correct crs definition: " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "newdata = gpd.GeoDataFrame(newdata, crs=4326)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "newdata.crs.name" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see, now we have added coordinate reference system information into our `GeoDataFrame`. The CRS information is necessary for creating a valid projection information for the output file. \n", "\n", "Finally, we can export the GeoDataFrame using `.to_file()` -function. The function works quite similarly as the export functions in pandas, but here we only need to provide the output path for the Shapefile. Easy isn't it!:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Determine the output path for the Shapefile\n", "outfp = \"L2_data/Senaatintori.shp\"\n", "\n", "# Write the data into that Shapefile\n", "newdata.to_file(outfp)" ] }, { "cell_type": "markdown", "metadata": { "lines_to_next_cell": 2 }, "source": [ "Now we have successfully created a Shapefile from scratch using geopandas. Similar approach can be used to for example to read coordinates from a text file (e.g. points) and turn that information into a spatial layer.\n", "\n", "\n", "#### Check your understanding\n", "\n", "\n", "