Periodic Axes class in matplotlib? - python

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.

Related

How to draw a plot by using python

I am implementing the Fastdtw algorithm to find the optimal path to align two time-series data. I hope to output a plot like this:
However, I've never tried such kind of plot before. I guess maybe I need to use the imshow() function in matplotlib, but I don't know how to draw the extra trajectory in the plot.
I wish somebody coould give a similar example about drawing like such style. I will modify the parameters by myself.

What is the matplotlib equivalent of MATLAB Figure.Position?

I am working on converting some MATLAB plotting code to Python / matplotlib. The original MATLAB code contains this:
F = figure;
% ... create subplots and draw on one of them ...
F.Position = [400 80 650 10];
I am trying to determine the matplotlib equivalent of the assignment to F.Position.
MATLAB docs describe this property as conveying the location and size of the drawable area, but matplotlib.figure.Figure does not appear to have a corresponding property.
matplotlib.axes.Axes does seem to have such position -- at least two positions, in fact -- but I'm uncertain whether this is the corresponding property, in part because MATLAB Axes also have their own positions. If this is the right place to look then which Axes should be affected? The current ones? Those of all subplots? Those of the not-yet-drawn subplots? Something else? And which of the positions of those Axes should be affected? Or am I barking up the wrong tree?
Update:
I am aware of the matplotlib figure size property. I take the figure offsets expressed in the MATLAB version to be important, so I don't think that adjusting the figure size alone will be adequate.
If you don't care about exactly where on your screen it shows up, then it might be good enough to set the size of the figure:
fig = plt.figure(figsize=(width,height))
The default units are inches, but that can be changed: https://matplotlib.org/stable/gallery/subplots_axes_and_figures/figure_size_units.html
If you do care about the position, it looks like it's described in more detail here: How do you set the absolute position of figure windows with matplotlib?

Matplotlib plot function output differs from seaborn's lineplot

I want to plot a PDF function given data which follows a normal distribution. Mainly I followed this link.
Now, if I am working on the data created like on that website (x=np.linspace()) and I plot it with either seaborn.lineplot() or matplotlib.pyplot.plot(), I get a normal curve as shown on the website linked above. But when I do this with my own data (which I believe is normal, but with a lot more data points) instead of initializing it with np.linspace I get a clear normal curve with seaborn's lineplot and a messy normal curve with matplotlib's plot function.
I have tried to look for default arguments on both functions but couldn't find any (except estimator) which would cause this behavior. The estimator argument of Seaborn's lineplot was the only argument that looked like it could do something like this but setting it to None did not make any difference (and it kind of makes sense I think since the y value is always same for a specific x so averaging out will produce the same value).
I used to think both functions are the same, but then why do they have different output?
The Seaborn lineplot function has the default parameter sort=True.
So unless you tell it not to, it'll order the data for you. This is not something which pyplot.plot() does, instead it'll draw lines between the points in the order provided.
If you want to order the data before plotting it using Pyplot, there's a good solution for how to do that.

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.

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.

Categories

Resources