tight_layout cannot make axes height small enough to accommodate all axes decorations

Gio picture Gio · Apr 2, 2019 · Viewed 10.7k times · Source

Is not the first time I encounter this problem and my usual workaround is to explicitly define the figure size and avoid using tight_layout all along (see second code example).
However, I find this solution not practical and I would simply like to have the figure getting automatically resized according to its content, taking into consideration also the labels, axis ticks, axis labels, etc. etc..

Below is an example of what I get using tight_layout (Just mimicking a qqplot)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#mock data
df = pd.DataFrame(np.random.randn(500, 200), columns=['var_0', 'var_1','var_2', 'var_3', 'var_4', 
   'var_5', 'var_6', 'var_7','var_8','var_9','var_10', 'var_11', 'var_12',
   'var_13', 'var_14', 'var_15','var_16','var_17', 'var_18','var_19',
   'var_20', 'var_21', 'var_22', 'var_23','var_24', 'var_25', 'var_26',
   'var_27', 'var_28', 'var_29', 'var_30', 'var_31', 'var_32', 'var_33',
   'var_34', 'var_35', 'var_36', 'var_37', 'var_38', 'var_39', 'var_40',
   'var_41', 'var_42', 'var_43', 'var_44', 'var_45', 'var_46', 'var_47',
   'var_48', 'var_49', 'var_50', 'var_51', 'var_52', 'var_53', 'var_54',
   'var_55', 'var_56', 'var_57', 'var_58', 'var_59', 'var_60', 'var_61',
   'var_62', 'var_63', 'var_64', 'var_65', 'var_66', 'var_67', 'var_68',
   'var_69', 'var_70', 'var_71', 'var_72', 'var_73', 'var_74', 'var_75',
   'var_76', 'var_77', 'var_78', 'var_79', 'var_80', 'var_81', 'var_82',
   'var_83', 'var_84', 'var_85', 'var_86', 'var_87', 'var_88', 'var_89',
   'var_90', 'var_91', 'var_92', 'var_93', 'var_94', 'var_95', 'var_96',
   'var_97', 'var_98', 'var_99',
   'var_100', 'var_101', 'var_102', 'var_103', 'var_104', 'var_105',
   'var_106', 'var_107', 'var_108', 'var_109', 'var_110', 'var_111',
   'var_112', 'var_113', 'var_114', 'var_115', 'var_116', 'var_117',
   'var_118', 'var_119', 'var_120', 'var_121', 'var_122', 'var_123',
   'var_124', 'var_125', 'var_126', 'var_127', 'var_128', 'var_129',
   'var_130', 'var_131', 'var_132', 'var_133', 'var_134', 'var_135',
   'var_136', 'var_137', 'var_138', 'var_139', 'var_140', 'var_141',
   'var_142', 'var_143', 'var_144', 'var_145', 'var_146', 'var_147',
   'var_148', 'var_149', 'var_150', 'var_151', 'var_152', 'var_153',
   'var_154', 'var_155', 'var_156', 'var_157', 'var_158', 'var_159',
   'var_160', 'var_161', 'var_162', 'var_163', 'var_164', 'var_165',
   'var_166', 'var_167', 'var_168', 'var_169', 'var_170', 'var_171',
   'var_172', 'var_173', 'var_174', 'var_175', 'var_176', 'var_177',
   'var_178', 'var_179', 'var_180', 'var_181', 'var_182', 'var_183',
   'var_184', 'var_185', 'var_186', 'var_187', 'var_188', 'var_189',
   'var_190', 'var_191', 'var_192', 'var_193', 'var_194', 'var_195',
   'var_196', 'var_197', 'var_198', 'var_199'])
y=np.random.randint(0,2, (500,1))

#something to plot
dfquantiles1=df[y==1].quantile(np.linspace(0,1,101))
dfquantiles0=df[y==0].quantile(np.linspace(0,1,101))

fig,ax = plt.subplots(figsize=(12,12))
for i, var in enumerate(df.iloc[:,:100]):
    plt.subplot(25, 4, i+1)
    ax=plt.gca()
    ax.set_title(var)
    plt.plot(dfquantiles0.loc[:][var],dfquantiles0.loc[:][var])
    plt.plot(dfquantiles0.loc[:][var],dfquantiles1.loc[:][var])
plt.tight_layout()

brokenfigure

The following code produces the figure as I would like to get it.

fig,ax = plt.subplots(25,4,figsize=(14,98))

for i, var in enumerate(df.iloc[:,:100]):
    plt.subplot(25, 4, i+1)
    ax=plt.gca()
    ax.set_title(var)
    ax.plot(dfquantiles0.loc[:][var],dfquantiles0.loc[:][var])
    ax.plot(dfquantiles0.loc[:][var],dfquantiles1.loc[:][var])

But it has a main drawbacks:

I have to explicitly define the figure size (this is mostly with trial and error and repeated generation of the figure, which is time consuming).

okfigure

Answer