My solution does not seem to detect the mark, but takes care of the label labels, axis labels, and shape names. I hope this is enough, since the fixed value of the pad should be good to take into account the tick marks.
Use axes.get_tightbbox to get a rectangle that fits around the axes, including labels.
from matplotlib import tight_layout renderer = tight_layout.get_renderer(fig) inset_tight_bbox = inset.get_tightbbox(renderer)
While your original rectangle defines the bbox axis, inset.bbox . Find the rectangles in the axis coordinates for these two bboxes:
inv_transform = axis.transAxes.inverted() xmin, ymin = inv_transform.transform(inset.bbox.min) xmin_tight, ymin_tight = inv_transform.transform(inset_tight_bbox.min) xmax, ymax = inv_transform.transform(inset.bbox.max) xmax_tight, ymax_tight = inv_transform.transform(inset_tight_bbox.max)
Now calculate a new rectangle for the axis itself, so that the external hard bbox will be reduced in size to the old bbox axis:
xmin_new = xmin + (xmin - xmin_tight) ymin_new = ymin + (ymin - ymin_tight) xmax_new = xmax - (xmax_tight - xmax) ymax_new = ymax - (ymax_tight - ymax)
Now just go back to the curly coordinates and move the insert axis:
[x_fig,y_fig] = axis_to_figure_transform([xmin_new, ymin_new]) [x2_fig,y2_fig] = axis_to_figure_transform([xmax_new, ymax_new]) inset.set_position ([x_fig, y_fig, x2_fig - x_fig, y2_fig - y_fig])
The axis_to_figure_transform function axis_to_figure_transform based on your transform function from add_inset_to_axis :
def axis_to_figure_transform(coord, axis): return fig.transFigure.inverted().transform( axis.transAxes.transform(coord))
Note: this does not work with fig.show() , at least on my system; tight_layout.get_renderer(fig) throws an error. However, it works great if you only use savefig() and don't display the graph interactively.
Finally, here is your complete code with my changes and additions:
import math from matplotlib import pyplot, rcParams, tight_layout rcParams['xtick.direction'] = 'out' rcParams['ytick.direction'] = 'out' INSET_DEFAULT_WIDTH = 0.35 INSET_DEFAULT_HEIGHT = 0.25 INSET_PADDING = 0.05 INSET_TICK_FONTSIZE = 8 def axis_data_transform(axis, xin, yin, inverse=False): """Translate between axis and data coordinates. If 'inverse' is True, data coordinates are translated to axis coordinates, otherwise the transformation is reversed. Code by Covich, from: http://stackoverflow.com/questions/29107800/ """ xlim, ylim = axis.get_xlim(), axis.get_ylim() xdelta, ydelta = xlim[1] - xlim[0], ylim[1] - ylim[0] if not inverse: xout, yout = xlim[0] + xin * xdelta, ylim[0] + yin * ydelta else: xdelta2, ydelta2 = xin - xlim[0], yin - ylim[0] xout, yout = xdelta2 / xdelta, ydelta2 / ydelta return xout, yout def axis_to_figure_transform(coord, axis): return fig.transFigure.inverted().transform( axis.transAxes.transform(coord)) def add_inset_to_axis(fig, axis, rect): left, bottom, width, height = rect fig_left, fig_bottom = axis_to_figure_transform((left, bottom), axis) fig_width, fig_height = axis_to_figure_transform([width, height], axis) \ - axis_to_figure_transform([0, 0], axis) return fig.add_axes([fig_left, fig_bottom, fig_width, fig_height], frameon=True) def collide_rect((left, bottom, width, height), fig, axis, data):