Cartopy subplot ticks & axes box line formatting - python

I'm using cartopy to plot several areas of very different sizes in different subplot arrangements (1x2, 3x4 etc.), which makes it quite difficult to find consistent layout parameters. One issue is that longitude tick labels are overlapping for small areas. Is there a way to rotate them? I'm creating the grid and ticks as follows:
gridlines = map.gridlines(crs=crs, draw_labels=True, linewidth=linewidth, color='black', alpha=1.0, linestyle=':', zorder=13)
The other issue is that by downscaling the Geoaxes in the subplot arrangement, the bounding box' line thickness appears very wide. Is there a way to set it explicitely? Here's the command I'm using to add each Geoaxes subplot:
map = fig.add_subplot(nrows, ncols, 1 + nth_col + (ncols * nth_row), projection=ccrs.Mercator())

Unfortunately, I don't think there is any control provided for either of these.
Regarding rotated ticks: With some care you can add axis ticks, and rotate those with usual "axes.set_ticklabels(... rotation=X)". But the gridline labels are not ticks, and you can't do this -- you can only control the position and formatting (via the exposed ticker and formatter objects).
Regarding the outline: again this does not appear to be the normal axes outline, and does not respond to the usual axes.set_frame_on() control.
I do find that "plt.gca().outline_path.set_linewidth" can be used. I guess this is useful but probably not a futureproof solution.

Related

Adjust legend to several graphs (Pyplot)

There are several questions in StackOverflow regarding the position of the legend in Python's matplotlib.pyplot. For a single graph, the problem can often be solved by tweaking parameters location and bbox_to_anchor. In the following example, the legend can be placed above the graph with bbox_to_anchor = (0.5,1.3).
industry_capm_df.plot.bar
ax = plt.axes()
ax.legend(bbox_to_anchor=(0.5,1.3))
Yet, for this other graph, the same parameters (0.5,1.3) result in a legend slightly out of alignment.
industry_raw_df.plot.bar
ax = plt.axes()
ax.legend(bbox_to_anchor=(0.5,1.3))
Since I got several graphs to plot, I would like legend alignment to be automatic, without having to tweak bbox_to_anchor every time. How could I solve this?
You should add loc='lower left' to specify that the coordinates in bbox_to_anchor refer to the lower left corner of the legend:
ax.legend(loc='lower left', bbox_to_anchor=(0, 1.03), borderaxespad=0)
borderaxespad is to disable padding outside the box, so that the left edge is perfectly aligned with the axis. Then we add a bit of padding (0.03) so that the bottom edge is slightly above the top of the chart.
Reference: https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.legend.html

How to define ylabel position relative to axis with matplotlib?

I need to precisely control the position of my ylabel independently of my yticklabels with matplotlib. This is because I have a matplotlib animation that currently has the ylabel jumping around as I change yticklabels. This is undesirable.
The docs seem to only allow me to specify distance from the leftmost part of my yticklabels. (which does not solve the problem, and indeed is causing it)
One solution would be to manually put the label. But is there a simpler way?
You can emulate the behavior of a normal y-label by adding text explicitly to the axes. If the y-limits are changing quite a bit, this is best done by placing the text in axes coordinates, rather than data coordinates. This is done with the transform keyword-argument, like so:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
t = ax.text(-0.1, 0.5, 'Y label', rotation=90,
verticalalignment='center', horizontalalignment='right',
transform=ax.transAxes)
ax.set_ylim(-10, 10) # Change y-limits, label position won't change.
This places the text halfway up the axes, and slightly to the left. Changes to the data limits of the axes have no effect on the text, as it is always defined in axes coordinates. Similarly, scaling the plot or axes (resizing the window with the mouse, using fig.set_size_inches, etc) will keep the y-label in position relative to the axes box itself, exactly what you want for a label.
You may have to play with the x-position of the label, to make sure it doesn't overlap the tickmarks as they change during animation.

How do I set the size of the axes patch so that the plot labels aren't clipped (matplotlib)

I have a graph in which I've set the axis labels to scientific notation using
formatter = mpl.ticker.FormatStrFormatter('%4.2e')
axis2.yaxis.set_major_formatter(formatter)
However, the axes.patch (or whatever is the right way to express the 'canvas' extent of the plot) doesn't adjust so the tick labels and axis label are clipped:
How do I adjust the extent of the axes portion of the plot. Changing the page size (figsize = ...) doesn't do it, since that just scales the overall plot area, resulting in the same clipping problem.
You can use the method tight_layout, which will accommodate the plot in the figure available space.
Example
from pylab import *
f = figure()
f.add_subplot(111)
f.tight_layout()
show()
Hope it helps.
Cheers
Just call fig.tight_layout() (assuming you have a Figure object defined).

L-shaped Gridspec using matplotlib gs.update

This one is a quick and easy one for the matplotlib community. I was looking to plot an L-shaped gridspec layout, which I have done:
Ignoring a few layout issues I have for the moment, what I have is that the x-axis in the gs[0] plot (top left) shares the x-axis with the gs[2] plot (bottom left) and the gs[2] shares its y axis with the gs[3] plot. Now, what I was hoping to do was update the w-space and h-space to be tighter. So that the axes are almost touching, so perhaps wspace=0.02, hspace=0.02 or something similar.
I was also hoping that the bottom right hand plot was to be longer in the horizontal orientation, keeping the two left hand plots square in shape. Or as close to square as possible. If someone could run through all of the parameters I would be very appreciative. I can tinker then in my own time.
To change the spacings of the plot with grid spec:
gs = gridspec.GridSpec(2, 2,width_ratios=[1,1.5],height_ratios=[1,1])
This changes the relative size of plot gs[0] and gs[2] to gs1 and gs[3], whereas something like:
gs = gridspec.GridSpec(2, 2,width_ratios=[1,1],height_ratios=[1,2])
will change the relative sizes of plot gs[0] and gs1 to gs[2] and gs[3].
The following will tighten up the plots:
gs.update(hspace=0.01, wspace=0.01)
This gave me the following plot:
I also used the following to remove the axis labels where needed:
nullfmt = plt.NullFormatter()
ax.yaxis.set_major_formatter(nullfmt)
ax.xaxis.set_major_formatter(nullfmt)

Preventing xticks from overlapping yticks

How can I prevent the labels of xticks from overlapping with the labels of yticks when using hist (or other plotting commands) in matplotlib?
There are several ways.
One is to use the tight_layout method of the figure you are drawing, which will automatically try to optimize the appareance of the labels.
fig, ax = subplots(1)
ax.plot(arange(10),rand(10))
fig.tight_layout()
An other way is to modify the rcParams values for the ticks formatting:
rcParams['xtick.major.pad'] = 6
This will draw the ticks a little farter from the axes. after modifying the rcparams (this of any other, you can find the complete list on your matplotlibrc configuration file), remember to set it back to deafult with the rcdefaults function.
A third way is to tamper with the axes locator_params telling it to not draw the label in the corner:
fig, ax = subplots(1)
ax.plot(arange(10),rand(10))
ax.locator_params(prune='lower',axis='both')
the axis keywords tell the locator on which axis it should work and the prune keyword tell it to remove the lowest value of the tick
Try increasing the padding between the ticks on the labels
import matplotlib
matplotlib.rcParams['xtick.major.pad'] = 8 # defaults are 4
matplotlib.rcParams['ytick.major.pad'] = 8
same goes for [x|y]tick.minor.pad.
Also, try setting: [x|y]tick.direction to 'out'. That gives you a little more room and helps makes the ticks a little more visible -- especially on histograms with dark bars.

Categories

Resources