0

I am mapping some data, weather stations across London, and want to label each data point (the green points) with the names of the weather stations, for example, Bow, Westminster.
The map is created from a Geopandas dataframe, from the geometry column. Using this post: https://stackoverflow.com/questions/14432557/matplotlib-scatter-plot-with-different-text-at-each-data-point I tried to annotate the text, but get the following error:
TypeError: 'Point' object is not iterable.

Here is the map as it currently looks:

Weather station data - green points

and here is the code:

f, ax = plt.subplots(1, figsize=(12, 12))
ax.set_title('Plot of London Grid for Learning weather stations with London boroughs and locations of Urban Mind datapoints', fontsize = 15)

boroughs.plot(alpha=1,edgecolor='w', facecolor='gray', linewidth=0.1, ax=ax)
london_umdata_geo.plot(ax=ax, marker="o",color="red",markersize=10.0,alpha=1.0, legend=True) #1,015 UM datapoints in London
stations_geo.plot(ax=ax, marker="X",color='green',markersize=20.0,alpha=1.0,legend=True)


n = stations_geo['Station Name'].tolist()
for i, txt in enumerate(n):
    ax.annotate(txt, xy = stations_geo.loc[i,'geometry'])

plt.show()

The stations are the green points, other data points (which will not be labelled) are in red.

stations_geo is a GeoPandas dataframe, which contains a geometry column from which the points are plotted using matplotlib.

I am using a loop for the annotate method, supposedly to loop through the points in the geometry column and use these as the co-ordinates for the annotations, but matplotlib seems not to like the Point objects (which are Shapely points). However, these points are being used directly to create the green points in the first place, so I am not sure where I am going wrong.

Any help appreciated, thanks!

LucieCBurgess
  • 759
  • 5
  • 12
  • 26
  • Any chance this can be made reproducible ([mcve])? – ImportanceOfBeingErnest Aug 04 '18 at 12:18
  • Hello, not sure quite how to send you the stations data which would make it so ... stations_geo is a GeoPandas dataframe with 4 columns: Station_Name, latitude (float), longitude (float) and geometry, which is a Shapely point in BNG coordinates. e.g. Station_Name Latitude Longitude geometry 0 Bellingham 51.436 -0.009 POINT (538488.73396071 172657.9218037352) 1 Belmont 51.346 -0.203 POINT (525250.3766155766 162301.1070065825) 2 Bow 51.528 -0.028 POINT (536892.6139878684 182852.743870542) 3 Brent 51.552 -0.231 POINT (522747.2053606602 185161.702351622) – LucieCBurgess Aug 04 '18 at 13:43
  • Sorry, I have never been able to work out how to format data nicely in StackOverflow. Tables seem to be difficult. You don't need to worry about the data that generates the red points, (london_umdata_geo) as I don't need to annotate these. All help very much appreciated – LucieCBurgess Aug 04 '18 at 13:45
  • I suppose the problem is unrelated to the actual stations, so it should be easily reproducible within a short snippet within the question. – ImportanceOfBeingErnest Aug 04 '18 at 13:45
  • @ImportanceOfBeingErnest, yes, please see above. Hope this helps. BNG = British National Grid whereas the latitude, longitude points in stations_geo are in UTC co-ordinates – LucieCBurgess Aug 04 '18 at 13:46
  • This will require pandas, geopandas, and shapely libraries as well as matplotlib to work. – LucieCBurgess Aug 04 '18 at 13:49
  • The above does not allow me to run the code. But I would try with something like `xy = stations_geo.loc[i,'geometry'].coords[0]`. – ImportanceOfBeingErnest Aug 04 '18 at 13:53
  • Hi @ImportanceOfBeingErnest this works, thank you :-) I'm not sure I understand though - please can you explain, or point me to the right section of the docs? I don't find matplotlib particularly user friendly, unfortunately. Thanks for your help! – LucieCBurgess Aug 04 '18 at 19:47
  • @ImportanceOfBeingErnest please add this as an answer rather than a comment, and then I can mark it as answered. Thanks :-) – LucieCBurgess Aug 04 '18 at 19:51
  • This is not really a matplotlib problem. Matplotlib supports pure python ints and floats, lists of those and numpy arrays. For everything else you need to make sure to convert it to one of the aforementionned datatypes. Matplotlib cannot know what users have as datatypes, so not sure what we should change. But if you have any suggestion concerning user-friendlyness, I'm all ear. – ImportanceOfBeingErnest Aug 04 '18 at 20:04
  • But I updated the answer to give you a guideline on how to potentially solve such problems in the future. Hope that helps. – ImportanceOfBeingErnest Aug 04 '18 at 20:20

1 Answers1

2

You already found the problem yourself ("matplotlib seems not to like the Point objects (which are Shapely points)").

So when confronted with such a problem, you may use the documentation as follows.

  1. Look at the matplotlib documentation about what you may supply to the xy argument of annotate.

    xy : iterable
    Length 2 sequence specifying the (x,y) point to annotate

  2. Look at the object you have. In cause of doubt, use print(type(stations_geo.loc[i,'geometry'])). It will show something like shapely.geometry.Point. Look at the documentation of that object.

  3. Identify a way to convert the one to the other. In this case you'll find

    Coordinate values are accessed via coords, x, y, and z properties.

  4. Print stations_geo.loc[i,'geometry'].coords, it will be a list of (a single) tuple(s). So in order to convert a single shapely Point to a python tuple, you would use its .coords attribute and take the first (and only) element from that list.

    xy = stations_geo.loc[i,'geometry'].coords[0]
    
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712