问题
I'm trying to obtain the coordinates of the features of a map using Cartopy but I would like to obtain the map projected coordinates instead of the data from the original projection.
For instance:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection=ccrs.epsg(3857))
fig.add_axes(ax)
ax.coastlines()
ax.set_global()
lines = ax.plot((0, 360), (-85.06, 85.06), transform=ccrs.PlateCarree())
fig.show()
The previous code shows a map with two lines using the map projection but lines
(a list with matplotlib.lines.Line2D
instances) is just only one object with the coordinates in the original projection of the data (lines[0].get_data()
---> (array([ 0, 360]), array([-85.06, 85.06])))
.
On an interactive plot, a Qt5 backend obtained after fig.show()
, I can see coordinates in EPSG:3857
and in PlateCarree
when the cursor is over the map so I wonder if there is an easy way to get lines
in EPSG:3857
coordinates.
EDIT: The example above is quite simplified. I've tried to do it simple for better understanding but maybe is better to show the real problem.
I have a grid of data with longitudes in the range [0, 360]. I can modify the arrays in order to have inputs in the range [-180, 180] and I'm using Cartopy/Matplotlib to plot contours. From the contours I'm obtaining a matplotlib.contour.QuadContourSet
with several matplotlib.collections.LineCollection
. From each matplotlib.collections.LineCollection
I can obtain the matplotlib.path.Path
s and I would like to have the coordinates of each Path in EPSG:3857
instead of in the original PlateCarree
so I can use cartopy.mpl.patch.path_to_geos
to convert each Path to a shapely geometry object in the EPSG:3857
projection without having to extract vertices
from each Path, convert them from PlateCarree
to EPSG:3857
and then create a new Path with the converted coordinates to use cartopy.mpl.patch.path_to_geos
to obtain geometries in the crs I need.
回答1:
The question asks for a coordinate transformation using Cartopy's feature, and maybe something else. Here I provide the code that performs coordinate transformation and computation check.
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import numpy as np
# Test data in geographic lon, lat (degrees)
lons = np.array((0, 360.01)) # any number of longitude
lats = np.array((-85.06, 85.06)) # .. longitude
# define all CRS
crs_longlat = ccrs.PlateCarree()
crs_3857 = ccrs.epsg(3857)
# Transformation function
def coordXform(orig_crs, target_crs, x, y):
"""
Converts array of (y,x) from orig_crs -> target_crs
y, x: numpy array of float values
orig_crs: source CRS
target_crs: target CRS
"""
# original code is one-liner
# it leaves an open axes that need to plt.close() later
# return plt.axes( projection = target_crs ).projection.transform_points( orig_crs, x, y )
# new improved code follows
xys = plt.axes( projection = target_crs ).projection.transform_points( orig_crs, x, y )
# print(plt.gca()) # current axes: GeoAxes: _EPSGProjection(3857)
plt.close() # Kill GeoAxes
# print(plt.gca()) # AxesSubplot (new current axes)
return xys
# Transform geographic (lon-lat) to (x, y) of epsg(3857)
xys = coordXform(crs_longlat, crs_3857, lons, lats)
for ea in xys:
print("(x, y) meters: " + str(ea[0]) + ', ' + str(ea[1]))
#Output(1)
#(x, y) meters: 0.0, -20006332.4374
#(x, y) meters: 1113.19490794, 20006332.4374
# Computation check
# Transform (x, y) of epsg(3857) to geographic (lon-lat), degrees
xs = xys[:,0] # all x's
ys = xys[:,1] # all y's
lls = coordXform(crs_3857, crs_longlat, xs, ys)
for ea in lls:
print("(lon, lat) degrees: " + str(ea[0]) + ', ' + str(ea[1]))
#Output(2)
#(lon, lat) degrees: 0.0, -85.06
#(lon, lat) degrees: 0.01, 85.06
# plt.close() # no need now
Edit 2
According to the constructive comments, the transformation function above can be written as follows:
def coordXform(orig_crs, target_crs, x, y):
return target_crs.transform_points( orig_crs, x, y )
来源:https://stackoverflow.com/questions/48196797/obtaining-coordinates-in-projected-map-using-cartopy