Matplotlib - tight layout placement and adjusting padding - python

I am running a function that runs multiple sub-functions, each calling for an axis in a plot (for example, a 2x2 matplotlib subplot). While the figure is working out, I'd like to reduce some of the padding, notably for the x axis. Is there anything I can do to minimize some space and offer more room in the plots for the data to be seen?
Currently, I am calling plt.tight_layout(pad=0.1, w_pad=0.05, h_pad=0.05) at the end prior to calling plt.show() and plotting; should I opt to use for whenever an axis is established instead? I am also using the labelpad modifier when generated each axis title; however, this is done as part of each sub-function that works on its own axis and tight_layout() is called at the end, so perhaps it is pointless?
Finally, here is what I am able to get with the above padding settings, and I cannot seem to improve it. Any suggestions for alternative ideas?

Related

Matplotlib: increase distance between automatically generated tick labels

When generating a new figure or axis with matplotlib (or pyplot), there is (I assume) some sort of automated way to determine how many ticks are appropriate for each axis.
Unfortunately, this often results in labels which are too close to be read comfortably, or even overlap. I'm aware of the ways to specify tick locations and labels explicitly (e.g. ax.set_xticks, ax.set_xtick_labels, but I wonder if whatever does the automatic tick distribution if nothing is specified can be influenced by some global matplotlib parameter(s).
Do such global parameters exist, and what are they?
I'm generating lots of figures automatically and save them, and it can get a little annoying having to treat them all individually ...
In case there is no simple way to tell matplotlib to thin out the labels, is there some other workaround to achieve more generous spacing between them?
by reading the documentation of xticks matplotlib.pyplot.xticks there seems to be no such global arguments.
However it is very simple to get around it by using the explicit xticks and xticks_labels taking into account that you can:
change the font size (decrease it)
rotate the labels (by 45°) or make them vertical (less overlapping).
increase the fig size.
program a function that generates adaptif xticks based on your input.
and many other possible workarounds.

Re-adjusting (automatically) limits on plot in matplotlib

Is there a way to let matplotlib know to recompute the optimal bounds of a plot?
My problem is that, I am manually computing a bunch of boxplots, putting them at various locations in a plot. By the end, some boxplots extend beyond the plot frame. I could hard-code some xlim and ylim's for now, but I want a more general solution.
What I was thinking was a feature where you say "ok plt I am done plotting, now please adjust the bounds so that all my data is nicely within the bounds".
Is this possible?
EDIT:
The answer is yes.
Follow-up question: Can this be done for the ticks as well?
You want to use matplotlib's automatic axis scaling. You can do this with either axes.axis with the "auto" input or axes.set_autoscale_on
ax.axis('auto')
ax.set_autoscale_on()
If you want to auto-scale only the x or y axis, you can use set_autoscaley_on or set_autoscalex_on.

How to set the physical length from an axis in matplotlib?

Is there a command to set the length of an axis? I do not mean the range! Independently from the values, the range from the axis or other factors, I want to set its length. How can I do that?
Something like plt.yaxislenght(20)?
I'm not sure of a specific way to set an axis length of axes generated by e.g. plt.subplots. You can use ax.set_aspect(num), but this adjusts the aspect ratio, and therefore will change both axes in a dependent way.
You can however use ax = plt.axes([left,bottom,width,height]) to add individual subplots in whatever positions you like. This should allow you to achieve what you want, but will be tedious because you need to place each subplot manually.
What you want to do is tricky due to the way that mpl works underneath. Most of the artist are specified in units that are not on-screen units (data, axes, or figure space: see transfrom tutorial). This gives you a good deal of power/flexibility as most of the time you want to work in one of the relative sets of coordinates, however the cost is if you want to set 'absolute' sizes of things you end up having to do it indirectly.
If you want you axis to be a fixed length (in display units) between figures, then you need to control the size of you axes (in figure units) by hand (via fig.add_axes) and then use fig.set_size_inches to set the size of your over-all figure. By tweaking these values you can get what you want.

Matplotlib: make final figure dimensions match figsize with savefig() and bbox_extra_artists

I'm producing graphics for publication with matplotlib and want very precisely sized figure output. I need this so that I can be sure the figure won't need to be resized when inserted into the latex document, which would mess with the font size in the figure which I want to keep at a consistent ratio to the font size in the main document.
I need to use the bbox_extra_artists argument to savefig because I have a legend down the bottom that gets cut off the figure if I don't. The problem I am having is that I haven't found a way to have the original figure dimensions I specify with figsize when creating the plot honoured after calling savefig with bbox_extra_artists.
My call to savefig looks like this:
savefig(output_file, bbox_inches='tight', pad_inches=0.0,dpi=72.27,bbox_extra_artists=(lgd,tp,ur,hrs))
The figure width I specify with figsize is:
516.0 * (1/72.27) = 7.1398 inches = 181.3532 millimeters
The output PDF width I get using my savefig() call above is 171 millimeters (not the desired 181.3532 millimeters).
The solution I've seen proposed in other questions here on SO is to make a call to tight_layout(). So, immediately above my savefig() call, I put the following:
plt.tight_layout(pad=0.0,h_pad=0.0,w_pad=0.0)
This produces a figure with width 183 millimeters (again, not the 181.3532 millimeters I want). If I use tight_layout, and remove the bbox_extra_artists argument from my call to savefig(), I get a width of 190 millimeters (again, not 181.3532 millimeters that I want). This is besides the point that removing bbox_extra_artists in my case mangles up the figure by cutting things off.
So I guess this is a two part question:
When using tight_layout, even without bbox_extra_artists, why is the output figure incorrectly sized?
Is there any way to get a correctly sized figure when using bbox_extra_artists?
I know a few millimeters sounds like a trivial difference, but it's the fact that there is any difference at all that concerns me. It means there is some variable, which could change in my other figures which is causing a degree of error, and that error may well be magnified elsewhere.
The reason that you're getting a smaller plot is because you're specifying bbox_inches='tight'.
bbox_inches='tight' crops the plot down based on the extents of the artists in the plot. If you want the output to be exactly the size you specify, then just leave out the bbox_inches and bbox_extra_artists kwargs entirely.
If you just do savefig(output_file, dpi=72.72) without anything else the plot will be exactly the size you specified with creating the figure.

On adjusting margins in matplotlib

I am trying to minimize margins around a 1X2 figure, a figure which are two stacked subplots. I searched a lot and came up with commands like:
self.figure.subplots_adjust(left=0.01, bottom=0.01, top=0.99, right=0.99)
Which leaves a large gap on top and between the subplots. Playing with these parameters, much less understanding them was tough (things like ValueError: bottom cannot be >= top)
My questions :
What is the command to completely minimize the margins?
What do these numbers mean, and what coordinate system does this follow (the non-standard percent thing and origin point of this coordinate system)? What are the special rules on top of this coordinate system?
Where is the exact point this command needs to be called? From experiment, I figured out it works after you create subplots. What if you need to call it repeatedly after you resize a window and need to resize the figure to fit inside?
What are the other methods of adjusting layouts, especially for a single subplot?
They're in figure coordinates: http://matplotlib.sourceforge.net/users/transforms_tutorial.html
To remove gaps between subplots, use the wspace and hspace keywords to subplots_adjust.
If you want to have things adjusted automatically, have a look at tight_layout
Gridspec: http://matplotlib.sourceforge.net/users/gridspec.html

Categories