6

I would like to return the lat and lon or x and y from the point object in the following series as I plan to link them with an API I built that links OSM and NetworkX. The centroids will be added as new nodes for network analysis.

gp.GeoSeries(zones.centroid).x, and gp.GeoSeries(zones.centroid).y as outlined in docs raise AttributeError: 'GeoSeries' object has no attribute 'x' error.

Modifying things a bit and printing list(gp.GeoSeries(zones.centroid)) return thousands of shapely points of the following format:

[... <shapely.geometry.point.Point object at 0x0000000024035940>,
<shapely.geometry.point.Point object at 0x0000000024035978>, 
<shapely.geometry.point.Point object at 0x00000000240359B0>, 
<shapely.geometry.point.Point object at 0x00000000240359E8>, 
<shapely.geometry.point.Point object at 0x0000000024035A20>, 
<shapely.geometry.point.Point object at 0x0000000024035A58>, 
<shapely.geometry.point.Point object at 0x0000000024035A90>, 
<shapely.geometry.point.Point object at 0x0000000024035AC8>]

The code I'm using is the following:

import geopandas as gp

zones = gp.GeoDataFrame.from_file(shp_file)

for index, row in zones.iterrows():
    print index, gp.GeoSeries(zones.centroid)

# result:
# 9700022.00    POINT (-122.8196050489696 54.00617624128658)
# 9700023.00    POINT (-122.7474362519174 53.99998921974029)
# 9700100.00    POINT (-121.4904983300892 53.98447191612864)
# 9700101.00    POINT (-122.5513619751679 53.73999791511078)
# 9700102.00    POINT (-123.0624037191615 53.62317549646422)
# 9700103.00    POINT (-123.0848175548173 54.05921695782788)

How can I return the x and y from the GeoPandas POINT object?

7

Leaving the rest below, but the main thing was accessing the geometry properly. If iterating over rows, e.g. for index, row in zones.iterrows(): you can simply use row.geometry.centroid.x and row.geometry.centroid.y. Geometry is a special column included in a GeoDataFrame, so every row has a geometry attribute.
You are accessing that attribute, which contains a shapely object. That shapely object will have an attribute, centroid that, in turn contains a shapely.geometry.Point, which has attributes x and y, finally giving you the properties you want.


(This part was the original effort to get to x,y with map and shapely.geometry.Point.)
I am going to assume you want a list of (x, y) tuples? Create a quick accessor function for the x and y attributes on a Point and use map.

Edit: Okay, figured out that you may be accessing the geometry in the GeoDataFrame in an incorrect way. Geometry is a column in your GeoDataFrame, which by itself produces a series. Calling centroid on that column should give you a new GeoSeries of only those centroids. I suspect the way you were going about things was taking the centroid of every vertex in each polygon. Still cannot test this since I cannot install GeoPandas right now.

def getXY(pt):
    return (pt.x, pt.y)
centroidseries = zones['geometry'].centroid
centroidlist = map(getXY, centroidseries)

or if you want two separate lists of x and y coordinates

def getXY(pt):
    return (pt.x, pt.y)
centroidseries = zones['geometry'].centroid
x,y = [list(t) for t in zip(*map(getXY, centroidseries))]

Alternately, you should also be able to use zones.geometry.centroid instead of zones['geometry'].centroid. Either way, I think calling zones.centroid may be returning a GeoDataFrame instead of a GeoSeries, giving you the unexpected output when you wrap it in another GeoSeries.

  • 1
    Whoops, I wrote my maps backwards. Fixing now. I just got geopandas.org unblocked, since clearly GeoSeries is interating more than just the centroids. – blord-castillo Oct 16 '15 at 19:59
  • 1
    Although the code works, it seems that list(...) is returning a lot more points than what I need. I have 30 zones so I should only have 30 centroids. when expanding to list(...) it's returning thousands of points – dassouki Oct 16 '15 at 20:11
  • 1
    Tried some work on this. Still tricky without being able to install geopandas, but trying to follow the documentation examples. – blord-castillo Oct 16 '15 at 20:24
  • Sounds good. The reason I'm using a dataframe is that i'm grouping my centroids by a field in my shape file as follows: for index, row in zones.iterrows(): if row['CMANAME'] == u'zone_name': – dassouki Oct 16 '15 at 20:26
  • 1
    Got it... well, (row.geometry.centroid.x, row.geometry.centroid.y) should get you the x, y values if you are iterating over all the rows anyway. Basically that is taking the geometry column of the row (a polygon), accessing the centroid (a point), and then getting the x and y attributes of that point. Not as pretty as mapping everything, but could get the job done. – blord-castillo Oct 16 '15 at 20:31
9

Ran into this problem myself. If you want the x and y as separate GeoDataFrame columns, then this works nicely:

gdf["x"] = gdf.centroid.map(lambda p: p.x)
gdf["y"] = gdf.centroid.map(lambda p: p.y)
1

This has been made easier as of GeoPandas 0.3.0.

You can now access x and y of shapely Points inside a geopandas GeoSeries using your_GeoDataFrame.geometry.x and your_GeoDataFrame.geometry.y

(Note : I'm using python 3.6.1, not sure about behavior in 2.7, sorry)

Source on github

0

I ran into a similar problem, only using polygon geometries and found this solution worked well for me, mind you it's using Python-3.6 so it may not work for Python-2.7.

import geopandas as gpd

zones = gpd.read_file('file_to_read.shp')

for i in range(0,len(zones)):
    zones.loc[i,'centroid_lon'] = zones.geometry.centroid.x.iloc[i]
    zones.loc[i,'centroid_lat'] = zones.geometry.centroid.y.iloc[i]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.