What is the matplotlib equivalent of MATLAB Figure.Position? - python

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?

Related

Controlling resolution of full domain pcolormesh cells

I'm not sure whether this is a Cartopy or Matplotlib question, so I apologize if this would have been better suited for Matplotlib.
I am transitioning from NCL (NCAR Command Language https://www.ncl.ucar.edu/) to Python. Previously, I was using NCL to contour with a method of "CellFill" (https://www.ncl.ucar.edu/Document/Graphics/Resources/cn.shtml#cnFillMode). In Python, I am using pcolormesh to render a gridded dataset with a horizontal grid spacing of 3-km. In NCL, regardless of whether I am plotting the full domain or an area zoom, the resolution of the resulting image appears to be consistent using a PNG output. In Python however, if I use pcolormesh with an area zoom it looks identical to my NCL plot but if I try and plot the full domain, it looks different.
I've traced this down to the figure resolution. At the full domain view in Python, however I have my figure settings configured causes the 3-km cells in certain areas to become "blurred together" making it appear as if the entire region is a certain contour value when in actuality there are areas with no values in between.
Here is a CONUS example of pcolormesh:
And here is a full CONUS version from NCL:
There are several areas of note, but one obvious area is the NM/AZ region. If I zoom in very closely in both Python and NCL in this region, the resulting images look identical. But at the CONUS view it looks like there's much more shading in this area than there actually should be in the Python version.
crs = ccrs.PlateCarree() # Lat/Lon
fig = plt.figure(1, figsize=(15, 15))
ax.add_feature(cfeature.COASTLINE.with_scale('50m'), linewidth=BORDERWIDTH,edgecolor=BORDERCOLOR)
ax.add_feature(cfeature.STATES, linewidth=BORDERWIDTH,edgecolor=BORDERCOLOR)
ax.add_feature(cfeature.BORDERS, linewidth=BORDERWIDTH,edgecolor=BORDERCOLOR)
ax1 = plt.subplot(111,projection=crs)
norm = BoundaryNorm(LEVELS,ncolors=plt.get_cmap('plasma').N,clip=False)
cf1 = ax1.pcolormesh(diffsum.lon0,diffsum.lat0,diffsum,cmap='plasma',transform=ccrs.PlateCarree(),norm=norm)
plt.savefig('testing%s.png' % (DSTRING))
Note that if I manually increase the DPI used in the resulting image to something rediculous like 1000, or increase the figure size to 100x100 inches, it also looks OK but the resulting image is so gigantic it makes it cumbersome to view on the screen.
Is there something I am missing about pcolormesh that I should be doing to help better adapt the resolution of the cells being shaded with respect to the resolution of the actual figure itself?

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.

Set colorbar range for an mlab surface

I've looked around on the internet but I haven't found a solution.
I'm plotting different surfaces in the same figure with mlab.pipeline.surface(mesh). I'd like to plot them with the same colorbar.
In this figure the right part of the surfaces is at the same temerature, but since the colorbar range is different for each surface the color is different.
I think there should be something like matplotlib.tricontourf(...,levels=...) to fix the colorbar range.
How can I set the colorbar range using mlab?
You can take a look at the built-in documentation of mlab. From help(mlab.pipeline.surface):
:vmax: vmax is used to scale the colormap.
If None, the max of the data will be used
:vmin: vmin is used to scale the colormap.
If None, the min of the data will be used
In other words, you need to compute the global minimum and global maximum of your data across every dataset, and set the same extrema for every surface of yours. Note that you can do the exact same (with the exact same keywords even) with matplotlib's 3d plotting methods.
Tangential note: your use case might also benefit from some transparency, since your surfaces are likely to overlap one another which might hinder the visualization. The two keywords that come to mind are opacity and perhaps (albeit less likely) transparent:
:opacity: The overall opacity of the vtk object. Must be a float.
Default: 1.0
:transparent: make the opacity of the actor depend on the
scalar.

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