pythonmatplotlibstatistics

matplotlib: precise inset plot location and size with transformations


I have created a plot with several "inset" axes in matplotlib with the intent of visualizing the meaning of error bars. Please consider the following example:

import matplotlib.pyplot as plt
from numpy import linspace, random
from scipy.stats import norm
from mpl_toolkits.axes_grid1.inset_locator import inset_axes

num_experiments = 10
data_points = random.randn(num_experiments)
x_values = range(num_experiments)

fig, ax = plt.subplots(figsize=(12, 6))
ax.set_ylim(-5,5)
ax.set_xticks(x_values, ["Experiment {:d}".format(i+1) for i in range(num_experiments)], rotation='vertical')
ax.errorbar(x_values, data_points, yerr=1, fmt='o', capsize=5)
ax.axhline(y=0, color='gray', linestyle='--')
ax.set_ylabel('Measured Value')

inset_width = 2.5

for i, (x, y) in enumerate(zip(x_values, data_points)):
    # Calculate inset position
    trans_x, trans_y = fig.transFigure.inverted().transform(ax.transData.transform((x, y)))
    trans_h, trans_w = fig.transFigure.inverted().transform(ax.transData.transform((0.5, inset_width))) - fig.transFigure.inverted().transform(ax.transData.transform((0, 0)))
    inset_ax = fig.add_axes([trans_x, trans_y - trans_w, trans_h, 2*trans_w])
    x_gauss = linspace(-inset_width, inset_width, 100)
    y_gauss = norm.pdf(x_gauss)
    inset_ax.plot(y_gauss, x_gauss, color='blue')
    inset_ax.fill_betweenx(x_gauss, y_gauss, where=(x_gauss >= -1) & (x_gauss <= 1), color='blue', alpha=0.3)
    inset_ax.axis('off')

plt.xticks(rotation=45)
plt.show()

The result looks like this: illustration

As you might be able to see, the shown 67% confidence intervals on the little gaussians don't exactly agree with the +/-1 error bands I plot in the main part of the plot.

Why is that? Is there a better, more elegant way to get the transformation right? Is this a bug? Am I just missing some hidden padding somewhere that I need to disable?

Any suggestions are highly appreciated!


Solution

  • I was able to resolve the issue using this line:

    inset_ax.margins(x=0,y=0)