Generic xlabel / ylabel for matplotlib subtitles

I have the following graph:

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size) 

and now I would like to give this graph common x-axis labels and Y-axis labels. With “common”, I mean that there should be one large x-axis label under the entire subtitle grid, and one large Y-axis label on the right. I can't find anything about this in the documentation for plt.subplots , and my googlings suggest that I need to make a big plt.subplot(111) to start with, but as I then put my 5 * 2 substrings in it using plt.subplots ?

+62
python matplotlib
Apr 22 '13 at 15:25
source share
5 answers

This is similar to what you really want. He takes the same approach of this answer to your specific case:

 import matplotlib.pyplot as plt fig, ax = plt.subplots(nrows=3, ncols=3, sharex=True, sharey=True, figsize=(6, 6)) fig.text(0.5, 0.04, 'common X', ha='center') fig.text(0.04, 0.5, 'common Y', va='center', rotation='vertical') 

Multiple plots with common axes label

+96
Nov 12 '14 at
source share

Without sharex=True, sharey=True you will get:

enter image description here

With it you should get it better:

 fig, axes2d = plt.subplots(nrows=3, ncols=3, sharex=True, sharey=True, figsize=(6,6)) for i, row in enumerate(axes2d): for j, cell in enumerate(row): cell.imshow(np.random.rand(32,32)) plt.tight_layout() 

enter image description here

But if you want to add additional labels, you should add them only to the boundary graphs:

 fig, axes2d = plt.subplots(nrows=3, ncols=3, sharex=True, sharey=True, figsize=(6,6)) for i, row in enumerate(axes2d): for j, cell in enumerate(row): cell.imshow(np.random.rand(32,32)) if i == len(axes2d) - 1: cell.set_xlabel("noise column: {0:d}".format(j + 1)) if j == 0: cell.set_ylabel("noise row: {0:d}".format(i + 1)) plt.tight_layout() 

enter image description here

Adding a label for each chart will ruin it (maybe there is a way to automatically detect duplicate labels, but I don't know about that).

+21
May 13 '14 at 18:21
source share

Since the command:

 fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size) 

which you used returns a tuple consisting of a figure and a list of axis instances, it’s enough to do something like this (remember that I changed fig,ax to fig,axes ):

 fig,axes = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size) for ax in axes: ax.set_xlabel('Common x-label') ax.set_ylabel('Common y-label') 

If you want to change some details on a specific subtitle, you can access it through axes[i] , where i iterates over your subtitles.

It can also be very useful to enable

 fig.tight_layout() 

at the end of the file before plt.show() to avoid overlapping labels.

+13
Apr 22 '13 at 17:49
source share

I had a similar problem when plotting a graph grid. The graphs consisted of two parts (top and bottom). The y-tag was supposed to be centered on both sides.

I did not want to use a solution that depends on knowing the position on the external figure (for example, fig.text ()), so I manipulated the y position of the set_ylabel () function. This is usually 0.5, the middle of the chart to which it is added. Since the filling between the parts (hspace) in my code was zero, I could calculate the middle of the two parts relative to the top.

 import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec # Create outer and inner grid outerGrid = gridspec.GridSpec(2, 3, width_ratios=[1,1,1], height_ratios=[1,1]) somePlot = gridspec.GridSpecFromSubplotSpec(2, 1, subplot_spec=outerGrid[3], height_ratios=[1,3], hspace = 0) # Add two partial plots partA = plt.subplot(somePlot[0]) partB = plt.subplot(somePlot[1]) # No x-ticks for the upper plot plt.setp(partA.get_xticklabels(), visible=False) # The center is (height(top)-height(bottom))/(2*height(top)) # Simplified to 0.5 - height(bottom)/(2*height(top)) mid = 0.5-somePlot.get_height_ratios()[1]/(2.*somePlot.get_height_ratios()[0]) # Place the y-label partA.set_ylabel('shared label', y = mid) plt.show() 

picture

Downsides:

  • The horizontal distance to the chart is based on the top, lower ticks can extend to the mark.

  • The formula does not take into account the gap between the parts.

  • Throws an exception if the height of the upper part is 0.

Perhaps there is a general solution that takes into account the indentation between the shapes.

+2
Jul 27 '16 at 16:35
source share

I discovered an alternative method; if you know the bottom and top kwargs that went into GridSpec initialization, or you otherwise know the position of the edges of your axes in the Figure coordinates, you can also specify the position label in the Figure coordinates with some fantastic "conversion" magic. For example:

 import matplotlib.transforms as mtransforms bottom, top = .1, .9 f, a = plt.subplots(nrows=2, ncols=1, bottom=bottom, top=top) avepos = (bottom+top)/2 a[0].yaxis.label.set_transform(mtransforms.blended_transform_factory( mtransforms.IdentityTransform(), f.transFigure # specify x, y transform )) # changed from default blend (IdentityTransform(), a[0].transAxes) a[0].yaxis.label.set_position((0, avepos)) a[0].set_ylabel('Hello, world!') 

... and you should see that the tag still adjusts left-right accordingly so as not to overlap the tags with tags, as usual, but now it will always be adjusted exactly between the desired subtitles.

Also, if you don’t even use set_position , ylabel will be displayed by default exactly halfway up the figure . I assume this is because when the shortcut is finally drawn, matplotlib uses 0.5 for the y coordinate, without checking if the base coordinate transformation has changed.

0
May 17 '17 at 9:07
source share



All Articles