Matplotlib - changing plot size within rectangular grid - python

I have 4 subplots (created by using add_subplot) organised in a 2x2 rectangular grid. The two in the second row do not need to take up as much space and I wish to change it such that the top row takes up two thirds of the space and the bottom row takes up the remaining third.
I've found that you can arbitrarily place subplots by creating them with the axes function that takes a list of [top, left, width, height], but this would make the code a little messy and arbitrary.
Is there a "nice" way to do it? Or will I have to resort to individually placing each subplot?

Use subplot2grid, where you specify a 3x3 grid but make subplots in the first row have rowspan=2.

Maybe AxisGrid toolkit will help. It seems to offer more control than subplot()

Related

Possible to matplotlib's constrained_layout ignore axis tick labels?

I have a reasonably complicated grid of subplots that involves two sets (one on the left and another on the right) of columns plotting a set of quantities for each row, separated by a common legend to label the entries in each row.
Here is a sample of what I want to accomplish
Using matplotlib with constrained_layout = True works 95% perfectly for applying the out optimal sizes & spacing for the columns, down to the tricky case of having the legend run down the middle. The remaining 5% is highlighted in red, where the wordy x-axis tick labels seem to push away the columns: it would be perfect if there was a way to make the layout engine "ignore" the tick labels in determining the spacing.
Methods using other libraries are also appreciated. Thank you in advance.
What I tried:
subplots_adjust
GridSpec
The main difficulty with those attempts:
constrained_layout is incompatible with those settings, so one must sacrifice the optimized legend spacing at the cost of getting the column spacing right, or vice versa.

Matplotlib savefig bbox_inches='tight' along a single direction only?

I have two plots, each with multiple subplots (panels), i.e. multiple rows and columns. Each row shows the same type of data as images with colorbars on the right side. The first plot has, say, 8 rows and 4 columns. The second one has, say, 3 rows and 4 columns. The two plots are inserted into a LaTeX pdf document on two consecutive pages, with the same width (\includegraphics[width=\hsize]{fig1.pdf}). For layout reasons, I want the panels to have exactly the same width and height when flipping between pages in a pdf reader. To guarantee this, I thus used the same subplot layout of 8 x 4 panels for the second plot and made the panels (axes) for the 5 rows where there are no data invisible.
Since the second plot has only 3 rows of data, I use fig.savefig(bbox_inches='tight') to clip the white space below those rows. Unfortunately, as the ticks on the colorbar on the right side of the last column have a different maximum number of digits (on the first and second plot, say 1 and 2 decimal digits), with bbox_inches='tight' the resulting figure width (after saving and thus also when included into the LaTeX pdf) becomes different between the two plots.
I would like to not have to use a different layout of 3 x 4 subplots for the second plot, where I have to manually adjust the figure height (and likely still don't get exactly the same panel sizes). I could adjust both the tick formatters and tick locators on the colorbars to the same maximum number of digits for the two plots, but I would prefer to let matplotlib use the default ScalarFormatter() and AutoLocator().
Optimally, I would like to clip the white space below the 3 rows for the y-direction using bbox_inches='tight', but leave the bbox untouched for the x-direction and manually adjust the right figure border via fig.subplot_params(fig_right) to the same value for the two plots.
Questions: Is it possible to use bbox_inches='tight' only for the y-direction of a figure, but use the default bbox_inches (rcParams['savefig.bbox'], defaults to None) for the x-direction? Should such a feature (accepted values 'tight_x' and 'tight_y' for bbox_inches) maybe be implemented to matplotlib (I assume (but don't know) that this would not be too difficult)? Do you have alternative ideas how I can obtain exactly the same panel sizes for the two plots?
Update from original poster: As noted by #Jody Klymak, it is not possible to use a tight bounding box for one direction (or one border) only, but custom bounding boxes may be used. In my case, I pass bbox_inches=None for the first plot, and bbox_inches=Bbox([[0,fig.get_tightbbox(fig.canvas.get_renderer())._bbox.y0/fig.dpi - 0.1],[fig.get_figwidth(),fig.get_figheight()]]) for the second plot. This solves the question.

Matplotlib imshow()

I am stuck with python and matplotlib imshow(). Aim is it to show a twodimensonal color map which represents three dimensions.
My x-axis is represented by an array'TG'(93 entries). My y-axis is a set of arrays dependend of my 'TG' To be precise we have 93 different arrays with the length of 340. My z-axis is also a set of arrays depended of my 'TG' equally sized then y (93x340).
Basically what I have is a set of two-dimensonal measurements which I want to plot in color dependend on a third array. Is there a clever way to do that. I was trying to find out on my own first, but all I found is that most common is the problem with just a z-plane(two-dimensonal plot). So I have two matrices of the order of (93x340) and one array(93). Do you know a helpful advise.
Without more detail on your specific problem, it's hard to guess what is the best way to represent your data. I am going to give an example, hopefully it is relevant.
Suppose we are collecting height and weight of a group of people. Maybe the index of the person is your first dimension, and the height and weight depends on who it is. Then one way to represent this data is use height and weight as the x and y axes, and plot each person as a dot in that two dimensional space.
In this example, the person index doesn't really have much meaning, thus no color is needed.

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.

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