Issue
I have 2d lon/lat arrays and am trying to check the land type like this:
import numpy as np
from shapely.geometry import Polygon
import cartopy.io.shapereader as shpreader
from shapely.ops import unary_union
lon = np.arange(-180, 181, .1)
lat = np.arange(-90, 91, .1)
lons, lats = np.meshgrid(lon, lat)
land_shp_fname = shpreader.natural_earth(resolution='110m',
category='physical', name='land')
land_geom = unary_union(list(shpreader.Reader(land_shp_fname).geometries()))
grid_names = np.empty_like(lons, dtype=int)
for i in range(len(lon)-1):
for j in range(len(lat)-1):
poly = Polygon([(lon[i], lat[j]), (lon[i+1], lat[j]),
(lon[i+1], lat[j+1]), (lon[i], lat[j+1])])
if poly.intersects(land_geom):
grid_names[j,i] = 1 # Land
else:
grid_names[j,i] = 0 # Ocean
The speed is slow for creating the high-resolution one for 1000x1000 pixels. Any suggestions for improvement?
Solution
I find the roaring_landmask package is really fast:
import numpy as np
from roaring_landmask import RoaringLandmask
lon = np.arange(-180, 180, .1)
lat = np.arange(-90, 90, .1)
lons, lats = np.meshgrid(lon, lat)
l = RoaringLandmask.new()
mask = l.contains_many(lons.ravel(), lats.ravel())
It costs around 5s on my laptop ;)
Update
I find it's better to use geopandas and cartopy do this, because roaring_landmask
doesn't consider lake as not_land type.
Here's an example of checking points. It should be similar for polygons.
import numpy as np
import geopandas as gpd
from geopandas import GeoSeries
import cartopy.feature as cfeature
def random_lon_lat(n=1, lat_min=-90., lat_max=90., lon_min=-180., lon_max=180.):
"""
this code produces an array with pairs lat, lon
"""
lat = np.random.uniform(lat_min, lat_max, n)
lon = np.random.uniform(lon_min, lon_max, n)
points = GeoSeries(gpd.points_from_xy(lon, lat))
points_gdf = gpd.GeoDataFrame(geometry=points, crs="EPSG:4326")
return points_gdf
points_gdf = random_lon_lat(int(1e6))
land_50m = cfeature.NaturalEarthFeature('physical','land','50m')
land_polygons_cartopy = list(land_50m.geometries())
land_gdf = gpd.GeoDataFrame(crs='epsg:4326', geometry=land_polygons_cartopy)
# Spatially join the points with the land polygons
joined = gpd.sjoin(points_gdf, land_gdf, how='left', op='within')
# Check if each point is within a land polygon
is_within_land = joined['index_right'].notnull()
It takes less than 1 second to check all point types.
Answered By - zxdawn
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.