Cartopy behavior when plotting projected data - python

I am using cartopy to draw my maps. Its a great tool!
For some of my data I have the problem that the data is not properly mapped around 0deg or the dateline. See the example below.
I know the same feature from matplotlib.basemap, where it can be solved by using the add_cyclic routine. I wondered if somebody can recommend how to best fix this problem in cartopy.
Thanks!
Alex

When plotting global data like this you will always need to add a cyclic point to your input data and coordinate. I don't believe Cartopy currently includes a function to do this for you, but you can do it yourself quite simply for the time being. Assuming you have a 1d array of longitudes and a 2d array of data where the first dimension is latitude and the second is longitude:
import numpy as np
dlon = lons[1] - lons[0]
new_lons = np.concatenate((lons, lons[-1:] + dlon))
new_data = np.concatenate((data, data[:, 0:1]), axis=1)
If you have different shaped data or coordinates then you will need to adjust this to your needs.

The cartopy development team has included the required feature in the developoment branch. For details see here

Related

Array Interpolation Optimization

My problem is mainly about python optimization. I want to create a Geotiff file from an unstructured point cloud. Until now, I could create my tiff file from a 2D array of my points.
Only, it is an array of size (10000, 9300), which contains too many NaN values that I would like to interpolate.
The values to interpolate are in white on the capture.
Another constraint, I must not interpolate the values outside the project area, by extrapolation. Outside the convex area.
I have already managed to produce a result using griddata from scipy but the processing time is not viable (~15min) as I have to repeat this on a hundred files.
The piece of code I use to perform the interpolation:
import numpy as np
zi=np.load(Array.npy)
x, y = np.indices(zi.shape)
zi_i=griddata((x[~np.isnan(zi)], y[~np.isnan(zi)]), zi[~np.isnan(zi)(x[np.isnan(zi)],y[np.isnan(zi)]))
The result:
I put in link the array on which I work: https://drive.google.com/file/d/1KvEomI3H-gow2yoF6e2zpv5OwkriG7TQ/view?usp=sharing.
Thank you for your help. I hope I have provided enough information.

xarray add cyclic point to unstructured grid

Has someone already added an cyclic point to an unstructured grid? I have an xarray with a lon lat grid and data points and I need to add an cyclic point in an certain intervall. Sadly cartopy needs equally spaced data points and now I'm struggling to find a way to do it on my own.
In the clon/clat are my coordinates and I need to add the cyclic point together with the corresponding datapoints.
I can't think of any easy way to do that. I'd appreciate any help.

Slicing a multidimensional numpy array -> 3D point clusters at different time instances

I have a numpy-array, who's shape is:
(30,40,100,200)
Those are 3D points (30(x-axis)x40(y-axis)x100(z-axis)) for different times (200 in total):
For visualization only (this is not my dataset, the picture comes from here: http://15462.courses.cs.cmu.edu/fall2016/article/35)
Now, I have issues with understanding how I can slice it:
How do I extract a 3D cluster for one specific time, i.e. 140?
From that extracted 3D cluster, how can I plot a 2D x-z cross-section for a specific y-position, i.e.45?
You should read up on basic numpy slicing: https://numpy.org/doc/stable/reference/arrays.indexing.html
How do I extract a 3D cluster for one specific time, i.e. 140?
Just specify the time index, i.e. data[:, :, :, 140]. Be aware that Python indexing starts from 0.
From that extracted 3D cluster, how can I plot a 2D x-z cross-section for a specific y-position, i.e.45?
You can acquire a 2D cross-section by a similar slicing operation, i.e. cluster[:, 45, :]. It can be plotted in various ways depending on the plotting library. imshow() from matplotlib might be one possibility.
Is your question about the data set (how does data categorize and how to get a 3D cluster at a specific time), or about the coding?
If it is about "How to get a cluster at a specific time" it means that your problem is about your particular dataset, which Stackoverflow is not a correct place for these types of question.
If it is about "coding" then define clearly your question and provide us with your code and the problem with it.
Based on your explanation, I think that for each time step, you have a complete set of xyz data, and so the solution is very strait.

Cartopy: Can't plot vector field with uncertainties (and related questions)

I've been trying for a while now to plot vector field with uncertainty ellipses in Cartopy. The idea is that if I have a location (lat/lon) and a vector (wind speed, for example), but that vector has an uncertainty (measured in standard deviation, for example), then I'd like to plot an ellipses around the tip of the arrow indicating that uncertainty. In GMT, psvelo does the trick, my goal is something like this.
This is the same question as has been asked before here - I'm reopening it because I think that if someone can help me understand transforms better and I can find the location of the tip of the arrow, I can plot the error ellipse myself. Plus, some Matplotlib/Cartopy functionality might have changed in the last 4 years.
So, here's what I tried so far:
Making a map, using quiver to plot the vectors, and then trying to access some sort of scale parameter in the returned Quiver object. I couldn't find anything useful, and even though the scale attribute looked like it would've been the right thing, it turned out never to be set unless I set it myself.
If I do set the scaling myself, I don't know how to do this if my location and vector have different units, and both are obviously not related to the axis width. For example, if I decided that I want to have a 50 m/s long vector at 10°E, 40°N, to be a certain fraction of the width of the axis, what would my scale parameter be? Me trying out random combinations of transformations has not gotten any results. (The idea here then being, if I can figure out that relation, then I am one step closer to knowing where to put the ellipse.)
I've tried to figure out quiver 's autoscaling to see how I can "predict" what it's going to do internally, and then use that to know where the tip of the arrow is. Sadly, it's not as straightforward as the Matlab variant, so I failed at that as well.
Lastly, I also don't understand why I can't use cartopy.crs.Geodetic() as my source coordinate system. The error I get is invalid transform: Spherical quiver is not supported - consider using PlateCarree/RotatedPole. From reading the Cartopy documentation, wouldn't that be the appropriate one if my vector's location is measured in latitude, longitude and altitude?
Here's an MWE:
# imports
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
# data
lon, lat = np.array([10, 10.5]), np.array([40, 40])
east, north = np.array([0, 50]), np.array([50, 0])
# map
fig, ax = plt.subplots(subplot_kw={"projection": ccrs.Mercator()})
ax.set_extent([7, 13, 38, 42], ccrs.Geodetic())
ax.coastlines("50m")
q = ax.quiver(lon, lat, east, north, transform=ccrs.PlateCarree())
plt.show()
I really think this is a feature that Cartopy should have, as it is one of the biggest hurdles I've encountered so far when using Python for geoscience applications. Currently, the only approach I know is to write a GMT script file from within my Python program, and run GMT with a Python system call, and that's really a pain.
I know that GMT is developing their own Python interface, but they haven't even incorporated all the basic functionality, so it's anyone's guess when they will get to psvelo...
Thanks for all your help and tips,
PBB
Well the hard part about this is the matplotlib part. If I were trying to make this, I'd focus on that before making it work in Cartopy. Technically, the point you need is somewhere in the set of paths generated by the quiver command (located in q._paths in your MWE). A simpler solution would be to use pivot='tip' so that the point of the arrow is always located at the (x,y) point.
The error you're getting from Cartopy when you try to use Geodetic is because doing everying correctly when working on a sphere involves more complicated math--thus not everything works with Geodetic. If instead you use PlateCarree, it will treat lon/lat as Cartesian coordinates on a plane.

Coordinates in Basemap don't match the real ones

For my team project I'm trying to obtain a map of my city using Python and plot a heatmap on it. I'm using Basemap and matplotlib.
I found that selecting epsg=3003 gives sufficient graphic results, but the problem is that if I want to visualize a precise coordinate on the map, for example lat=45.0306 and long=7.42, it shows a different point with respect to the one I get with Google Earth.
Since I need to plot data with very precise and near coordinates, getting an accurate map is essential.
Can anyone help me with my code?
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
map = Basemap(llcrnrlat=45,urcrnrlat=45.4,
llcrnrlon=7.41,urcrnrlon=7.8,resolution='h', epsg=3003)
map.arcgisimage(service='ESRI_StreetMap_World_2D', xpixels = 3000, verbose= True)
plt.show()
The problem is that you are using two different projection systems. Google Earth uses WGS84, whose epsg code is: 3857 but you set up your map using EPSG:3003. The best would simply be to change the projection of your map when you define your basemap. Alternatively, if you really want to use EPSG:3003 then you have to reproject the coordinate you get from Google Earth (you may want to have a look at this answer)
Here a small example to show that by using the proper projection you can nicely match google map results:
map = Basemap(llcrnrlat=45.245,urcrnrlat=45.255,
llcrnrlon=7.54,urcrnrlon=7.55,resolution='h', epsg=4326)
map.arcgisimage(service='ESRI_StreetMap_World_2D', xpixels = 3000, verbose= True)
plt.plot(7.544335,45.250423,marker='+',markersize=15,color='Red')
Here the map from basemap with a google map screenshot:

Categories

Resources