How to convert lat/lon points in pandas and see whether they fall in some boundary polygons?
<p>I have a Pandas dataframe <code>df</code> like this:</p>

<pre><code> id   lat  lon
 jhg  2.7  3.5
 ytr  3.1  3.5
 ...
</code></pre>

<p>I also have a Geopandas dataframe <code>poly</code> with some polygons. Now, I would like to only plot the points in <code>df</code> that are <em>inside</em> some polygon. So I should be able to do something like <code>poly.intersects(p)</code>, where <code>p</code> is a Shapely <code>Point</code>. But I'm doing something wrong;</p>

<pre><code>from shapely.geometry import Point
for index, row in df.iterrows():
    t = poly.intersects(Point(row.lon, row.lat))
</code></pre>

<p>What would be the best way to pass a dataframe with lat/lon points and plot them overlayed to <code>poly</code>? Notice that I could define a range of min/max lat/lon, but that also prints dots outside <code>poly</code> but inside the (bigger) bounding box.</p>

<p>Your starting point:</p>

<pre><code>import pandas as pd
from shapely.geometry import box
import matplotlib.pyplot as plt

from matplotlib.collections import PatchCollection
from matplotlib.patches import Polygon
from shapely.geometry import Point
import seaborn as sns
import numpy as np

# some pretend data
data = {'lat':[2.7,3.5,1.4,2.3,.9,1.9], 'lon':[1.2,.9,1.9,2.2,3,1.1]}
df = pd.DataFrame(data)

# the 'bounding' polygon
poly = box(1,1,2,2)
patches  = PatchCollection([Polygon(poly.exterior)], facecolor='red', linewidth=.5, alpha=.5)


# plot the bounding box 
fig, ax = sns.plt.subplots(1, figsize=(4,4))
ax.add_collection(patches, autolim=True)

# plot the lat/lon points
df.plot(x='lat',y='lon', kind='scatter',ax=ax)
plt.show()
</code></pre>

<p>The figures looks something like this:</p>

<p><a href="http://i.stack.imgur.com/vXVsG.png" rel="nofollow"><img src="http://i.stack.imgur.com/vXVsG.png" alt="enter image description here"></a></p>

<p>One way to get rid of the unwanted points would be to use a boolean mask:</p>

<pre><code>#probably more efficient ways to do this, but this works
mask = [poly.intersects(Point(lat,lon)) for lat,lon in zip(df.lat,df.lon)]
df = df[mask]

# make new plot (must make a new 'patch' object)
patches1  = PatchCollection([Polygon(poly.exterior)], facecolor='red', linewidth=.5, alpha=.5)
fig1, ax1 = sns.plt.subplots(1, figsize=(4,4))
ax1.add_collection(patches1, autolim=True)

# make the axis bounds the same
ax1.set_xlim(ax.get_xlim())
ax1.set_ylim(ax.get_ylim())

# plot the lat/lon points
df.plot(x='lat',y='lon', kind='scatter',ax=ax1)
plt.show()
</code></pre>

<p>Gives me this image.</p>

<p><a href="http://i.stack.imgur.com/Rn4o5.png" rel="nofollow"><img src="http://i.stack.imgur.com/Rn4o5.png" alt="enter image description here"></a></p>

<p>Note that you could make a boolean mask in other, faster ways such whether lat is above the highest point in the polygon. Those might not be perfect by themselves, but could reduce the problem so you don't have call <code>intersects()</code> as many times.</p>

<p>[edit:If your polygon is a rectangle,] another way (as you suggested in your question) would be to just 'crop' the image around the bounding polygon. This is a much faster solution since you won't have to call that <code>intersects()</code> function over and over. To trim the image based on the bounding polygon, you can insert this right before <code>plt.plot()</code>:</p>

<pre><code>ax.set_xlim((np.min(poly.exterior.xy[0]),np.max(poly.exterior.xy[0])) )
ax.set_ylim((np.min(poly.exterior.xy[1]),np.max(poly.exterior.xy[1])) )
</code></pre>

<p>Gives the following:</p>

<p><a href="http://i.stack.imgur.com/R4Y6j.png" rel="nofollow"><img src="http://i.stack.imgur.com/R4Y6j.png" alt="enter image description here"></a></p>

python pandas matplotlib geopandas