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

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.

Related

Fixing dihedral angles beyond 180 degrees limit to create smooth curves

I have an output from a commercial program that contains the dihedral angles of a molecule in time. The problem comes from apparently a known quadrant issue when taking cosines, that your interval is -180 to 180, and I am not familiar with. If the dihedral would be bigger than 180, this commercial program (SHARC, for molecular dynamics simulations) understands that it is bigger than -180, creating jumps on the plots (you can see an example in the figure bellow).
Is there a correct mathematical way to convert these plots to smooth curves, even if it means to go to dihedrals higher than 180?
What I am trying is to create an python program to deal with each special case, when going from 180 to -180 or vice versa, how to deal with cases near 90 or 0 degrees, by using sines and cosines... But it is becoming extremely complex, with more than 12 nested if commands inside a for loop running through the X axis.
If it was only one figure, I could do it by hand, but I will have dozens of similar plots.
I attach an ascii file with the that for plotting this figure.
What I would like it to look like is this:
Thank you very much,
Cayo Gonçalves
Ok, I've found a pretty easy solution.
Numpy has the unwrap function. I just need to feed the function with a vector with the angles in radians.
Thank you Yves for giving me the name of the problem. This helped me find the solution.
This is called phase unwrapping.
As your curves are smooth and slowly varying, every time you see a large negative (positive) jump, add (subtract) 360. This will restore the original curve. (For the jump threshold, 170 should be good, I guess).

Creating a packed bubble / scatter plot in python (jitter based on size to avoid overlapping)

I have come across a number of plots (end of page) that are very similar to scatter / swarm plots which jitter the y-axis in order avoid overlapping dots / bubbles.
How can I get the y values (ideally in an array) based on a given set of x and z values (dot sizes)?
I found the python circlify library but it's not quite what I am looking for.
Example of what I am trying to create
EDIT: For this project I need to be able to output the x, y and z values so that they can be plotted in the user's tool of choice. Therefore I am more interested in solutions that generate the y-coords rather than the actual plot.
Answer:
What you describe in your text is known as a swarm plot (or beeswarm plot) and there are python implementations of these (esp see seaborn), but also, eg, in R. That is, these plots allow adjustment of the y-position of each data point so they don't overlap, but otherwise are closely packed.
Seaborn swarm plot:
Discussion:
But the plots that you show aren't standard swarm plots (which almost always have the weird looking "arms"), but instead seem to be driven by some type of physics engine which allows for motion along x as well as y, which produces the well packed structures you see in the plots (eg, like a water drop on a spiders web).
That is, in the plot above, by imagining moving points only along the vertical axis so that it packs better, you can see that, for the most part, you can't really do it. (Honestly, maybe the data shown could be packed a bit better, but not dramatically so -- eg, the first arm from the left couldn't be improved, and if any of them could, it's only by moving one or two points inward). Instead, to get the plot like you show, you'll need some motion in x, like would be given by some type of physics engine, which hopefully is holding x close to its original value, but also allows for some variation. But that's a trade-off that needs to be decided on a data level, not a programming level.
For example, here's a plotting library, RAWGraphs, which produces a compact beeswarm plot like the Politico graphs in the question:
But critically, they give the warning:
"It’s important to keep in mind that a Beeswarm plot uses forces to avoid collision between the single elements of the visual model. While this helps to see all the circles in the visualization, it also creates some cases where circles are not placed in the exact position they should be on the linear scale of the X Axis."
Or, similarly, in notes from this this D3 package: "Other implementations use force layout, but the force layout simulation naturally tries to reach its equilibrium by pushing data points along both axes, which can be disruptive to the ordering of the data." And here's a nice demo based on D3 force layout where sliders adjust the relative forces pulling the points to their correct values.
Therefore, this plot is a compromise between a swarm plot and a violin plot (which shows a smoothed average for the distribution envelope), but both of those plots give an honest representation of the data, and in these plots, these closely packed plots representation comes at a cost of a misrepresentation of the x-position of the individual data points. Their advantage seems to be that you can color and click on the individual points (where, if you wanted you could give the actual x-data, although that's not done in the linked plots).
Seaborn violin plot:
Personally, I'm really hesitant to misrepresent the data in some unknown way (that's the outcome of a physics engine calculation but not obvious to the reader). Maybe a better compromise would be a violin filled with non-circular patches, or something like a Raincloud plot.
I created an Observable notebook to calculate the y values of a beeswarm plot with variable-sized circles. The image below gives an example of the results.
If you need to use the JavaScript code in a script, it should be straightforward to copy and paste the code for the AccurateBeeswarm class.
The algorithm simply places the points one by one, as close as possible to the x=0 line while avoiding overlaps. There are also options to add a little randomness to improve the appearance. x values are never altered; this is the one big advantage of this approach over force-directed algorithms such as the one used by RAWGraphs.

Can someone explain how mypoly is used in Python with GPS coordinates?

I understand I can define a polygon in Python using "mypoly".
myPoly = Polygon(p1,p2,p3,…) #list of points
However, what I really want to do is to find a way to use Python to work with polygons that I define with GPS coordinates. The coordinates would show shapes similar to the following:
multiple polygons http://www.jvanderhook.info/images/slabs/drawing_1.png
(the image came from this question on Robotics Stack Exchange
I understand I should be able to work with a polygon once I have it defined, but this is new to me. How can I define one with GPS coordinates? Do I simply replace p1, p2, p3, ... above with the GPS coordinates?
Yes, you can use the gps coordinates to define your polygons. However, understand that these coordinates are typically in degrees (+/- 0-90 lat, +/- 0-180 lon).
Unfortunately, these things aren't as simple as they initially seem they should be. It might help to get comfortable with map projections, here's a good start:
http://kartoweb.itc.nl/geometrics/map%20projections/mappro.html
Then, you may be better off converting to a projection like 900913 (google maps projection) that is in meters and makes points easier to manage.
I tend to use django (which uses geos/gdal/proj4 and is a bit of a pain to get everything working right) for geometry manipulation and transforms. (shapely and pyproj seem like good alternatives if your not using django already)

Periodic Axes class in matplotlib?

I have a collection of latitude/longitude points that straddle the longitude=0 line. I'd like to plot these using a matplotlib Axes class that "wraps" the horizontal dimension such that, when looking towards l=360, points at l=1 are plotted at the equivalent of l=361. Ideally, I'd also like something that defines the pan/zoom actions so I can use the plot interactively.
I know that it is possible to define custom projections in matplotlib, but I haven't found the equivalent of a Cylindrical projection that implements all of this functionality. I'd rather not use basemap. Does anyone know if something like this exists somewhere?
You can get exactly what you are asking for by modifying the mathplotlib exapmle - api example code: custom_projection_example.py you just need to decide if you would like a spherical representation or cylindrical - if the latter then you may find more useful code in the custom_scale_example.py which also includes panning and zooming but in the example deliberatly limits the data to +-90 degrees - you will need to wrap instead.

How do I convert (or scale) axis values and redefine the tick frequency in matplotlib?

I am displaying a jpg image (I rotate this by 90 degrees, if this is relevant) and of course
the axes display the pixel coordinates. I would like to convert the axis so that instead of displaying the pixel number, it will display my unit of choice - be it radians, degrees, or in my case an astronomical coordinate. I know the conversion from pixel to (eg) degree. Here is a snippet of what my code looks like currently:
import matplotlib.pyplot as plt
import Image
import matplotlib
thumb = Image.open(self.image)
thumb = thumb.rotate(90)
dpi = plt.rcParams['figure.dpi']
figsize = thumb.size[0]/dpi, thumb.size[1]/dpi
fig = plt.figure(figsize=figsize)
plt.imshow(thumb, origin='lower',aspect='equal')
plt.show()
...so following on from this, can I take each value that matplotlib would print on the axis, and change/replace it with a string to output instead? I would want to do this for a specific coordinate format - eg, rather than an angle of 10.44 (degrees), I would like it to read 10 26' 24'' (ie, degrees, arcmins, arcsecs)
Finally on this theme, I'd want control over the tick frequency, on the plot. Matplotlib might print the axis value every 50 pixels, but I'd really want it every (for example) degree.
It sounds like I would like to define some kind of array with the pixel values and their converted values (degrees etc) that I want to be displayed, having control over the sampling frequency over the range xmin/xmax range.
Are there any matplotlib experts on Stack Overflow? If so, thanks very much in advance for your help! To make this a more learning experience, I'd really appreciate being prodded in the direction of tutorials etc on this kind of matplotlib problem. I've found myself getting very confused with axes, axis, figures, artists etc!
Cheers,
Dave
It looks like you're dealing with the matplotlib.pyplot interface, which means that you'll be able to bypass most of the dealing with artists, axes, and the like. You can control the values and labels of the tick marks by using the matplotlib.pyplot.xticks command, as follows:
tick_locs = [list of locations where you want your tick marks placed]
tick_lbls = [list of corresponding labels for each of the tick marks]
plt.xticks(tick_locs, tick_lbls)
For your particular example, you'll have to compute what the tick marks are relative to the units (i.e. pixels) of your original plot (since you're using imshow) - you said you know how to do this, though.
I haven't dealt with images much, but you may be able to use a different plotting method (e.g. pcolor) that allows you to supply x and y information. That may give you a few more options for specifying the units of your image.
For tutorials, you would do well to look through the matplotlib gallery - find something you like, and read the code that produced it. One of the guys in our office recently bought a book on Python visualization - that may be worthwhile looking at.
The way that I generally think of all the various pieces is as follows:
A Figure is a container for all the Axes
An Axes is the space where what you draw (i.e. your plot) actually shows up
An Axis is the actual x and y axes
Artists? That's too deep in the interface for me: I've never had to worry about those yet, even though I rarely use the pyplot module in production plots.

Categories

Resources