17

I ́d like to construct a shapefile from a Pandas DataFrame using the lon & lat rows.

I have got a CSV file and I process it with pandas to make a data frame, which is easier to handle

Is it possible to do that without making a line-by-line loop?

Taras
35.7k5 gold badges77 silver badges151 bronze badges
asked May 13, 2015 at 18:45
2
  • So it is point data or? Add a sample of the csv as text to your question Commented Sep 11 at 13:46
  • Question from 10 years ago, and @kamome was last seen Dec 12, 2024 Commented Sep 11 at 16:43

4 Answers 4

27

Yes, that can be done with shapely and geopandas.

Supposed that your pandas dataframe kind of looks like this:

import pandas as pd
data = [
 {'some_attribute': 'abc', 'lat': '50.1234', 'lon': '10.4023'},
 {'some_attribute': 'def', 'lat': '40.5678', 'lon': '8.3365'},
 {'some_attribute': 'ghi', 'lat': '60.9012', 'lon': '6.2541'},
 {'some_attribute': 'jkl', 'lat': '45.3456', 'lon': '12.5478'},
 {'some_attribute': 'mno', 'lat': '35.7890', 'lon': '14.3957'},
 ]
df = pd.DataFrame(data)
print(df)
=>
 lat lon some_attribute
0 50.1234 10.4023 abc
1 40.5678 8.3365 def
2 60.9012 6.2541 ghi
3 45.3456 12.5478 jkl
4 35.7890 14.3957 mno

First, make sure that geopandas and shapely are installed properly which sometimes is not easy because they come with some dependencies (e.g. GEOS and GDAL). If does not work at first try via pip install geopandas shapely, search for the error on Google or StackOverflow/Gis.Stackexchange because most probably there will be an answer available solving that problem for you.

Then, it is just a matter of creating a new geometry column in your dataframe which combines the lat and lon values into a shapely Point() object. Note that the Point() constructor expects a tuple of float values, so conversion must be included if the dataframe's column dtypes are not already set to float.

from shapely.geometry import Point
# combine lat and lon column to a shapely Point() object
df['geometry'] = df.apply(lambda x: Point((float(x.lon), float(x.lat))), axis=1)

Now, convert the pandas DataFrame into a GeoDataFrame. The geopandas constructor expects a geometry column which can consist of shapely geometry objects, so the column we created is just fine:

import geopandas
df = geopandas.GeoDataFrame(df, geometry='geometry')

To dump this GeoDataFrame into a shapefile, use geopandas' to_file() method (other drivers supported by Fiona such as GeoJSON should also work):

df.to_file('MyGeometries.shp', driver='ESRI Shapefile')

And that is what the resulting shapefile looks like when visualized with QGIS:

Resulting shapefile

PolyGeo
65.5k29 gold badges115 silver badges350 bronze badges
answered Feb 25, 2016 at 15:08
2
  • 2
    Hi, I have a similar situation,but instead of points, I have polygons. It is possible to do something similar df['geometry'] = df.apply(lambda x: Point((float(x.lon), float(x.lat))), axis=1) but with polygons? Commented Aug 23, 2016 at 17:48
  • df.to_file no longer works. Commented Sep 10 at 18:43
8

If you haven't done so already, install GeoPandas (e.g. one of either pip install geopandas or conda install geopandas for Anaconda/Miniconda users).

Here is how to read a CSV file with pandas, then use the geopandas.points_from_xy helper function to create a geometry column, then write a shapefile:

import pandas
import geopandas
from io import StringIO
# example CSV file
csv_input = StringIO("""\
Name,Lat,Long
Kingston,18,-76.8
Lima,-12.05,-77.05
Reykjavik,64.15,-21.95
""")
gdf = geopandas.GeoDataFrame(pandas.read_csv(csv_input))
gdf.set_geometry(
 geopandas.points_from_xy(gdf['Long'], gdf['Lat']),
 inplace=True, crs='EPSG:4326')
gdf.drop(['Lat', 'Long'], axis=1, inplace=True) # optional
gdf.to_file('some_capitals.shp')
answered Jul 6, 2020 at 1:12
1
  • Definitely faster! same data: - this method " 56.2 ms ± 2.13 ms per loop " vs accepted answer + assign crs "1.75 s ± 41.6 ms per loop " Commented Feb 17, 2023 at 6:06
7

For ArcMap you need to define the Projection before exporting to Shapefile.

import geopandas
df = geopandas.GeoDataFrame(df, geometry='geometry')
# proj WGS84
df.crs= "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"
df.to_file('MyGeometries.shp', driver='ESRI Shapefile')
tinlyx
11.3k18 gold badges78 silver badges130 bronze badges
answered Nov 24, 2016 at 21:25
1
  • I did something similar, using df.crs= "+init=epsg:27700" to project my shapefile according to the British National Grid. However, when I open it in ArcGIS, the coordinate system is unknown. What am I doing wrong? Commented Sep 18, 2017 at 18:27
1

I have a similar answer to @Mike T. However, my answer deals with a file that has addresses instead of coordinates. It works something like this:

  • .csv file > dataframe > geodataframe > shapefile

My .csv file has two columns: Name and Address. First, read .csv file into pandas dataframe. Second, geocode (this will give you coordinates). Third, put coords into df. Fourth, generate gdf from df. Lastly, write gdf to shapefile.

Note: you can skip the second instances of df and gdf and just write the geocode gdf instance to a shapefile (i.e. comment out steps 3 and 4), but you will lose your original fields in the csv.

import pandas as pd
import geopandas as gpd
# 1 read csv file
f = r'path\to\.csv'
file = pd.read_csv(f)
# convert to dataframe
df = pd.DataFrame(file)
# 2 geocode the Address field
gdf = gpd.tools.geocode(df['Address'])
# 3 extract lat long from geometry and put into dataframe.
df['latitude'],df['longitude'],df['geometry'] = gdf.geometry.y, gdf.geometry.x, gdf.geometry
# 4 generate GeometryArray of shapely Point geometries from x, y(, z) coordinates.
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.longitude, df.latitude), crs="EPSG:4326") #crs is optional
# 5 write to shapefile
gdf.to_file(r'path\to\.shp')
answered Sep 10 at 19:59

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.