Specific location for inputs
I want to create an axis set to create an insert at a specific location in the parent axis set. Therefore it is impractical to use the parameter loc=1,2,3
in inset_axes
as shown below:
inset_axes = inset_axes(parent_axes,
width="30%", # width = 30% of parent_bbox
height=1., # height : 1 inch
loc=3)
However, I would like something close to this. And the answers here and here seem to be answers to questions somewhat more complex than mine.
So the question is, is there a parameter that I can replace in the above code that will allow customizing the position of the insertion axes within the parent axes? I tried to use bbox_to_anchor
but don't understand its specification or behavior from the documentation . Specifically, I've tried:
inset_axes = inset_axes(parent_axes,
width="30%", # width = 30% of parent_bbox
height=1., # height : 1 inch
bbox_to_anchor=(0.4,0.1))
to try and anchor the left and bottom of the insert to 40% and 10% from the x and y axis respectively. Or I tried to put it in absolute coordinates:
inset_axes = inset_axes(parent_axes,
width="30%", # width = 30% of parent_bbox
height=1., # height : 1 inch
bbox_to_anchor=(-4,-100))
None of them worked correctly and gave me a warning that I could not interpret.
All in all, it seems to be loc
a pretty standard setting in many of the functions owned matplotlib
, so is there a general solution to this problem that can be used anywhere? It seems that bbox_to_anchor
, but again, I can't figure out how to use it correctly.
source to share
The approach you have taken is, in principle, correct. However, as with placing a legend with using bbox_to_anchor
, location is defined as the interaction between bbox_to_anchor
and loc
. Most of the explanations in the above answer also apply here.
The default loc
for is ("top right"). This means that if you specify , it will be the coordinates of the top right corner, not the bottom left. Therefore, you need to specify that the lower left corner of the insert is in position . inset_axes
loc=1
bbox_to_anchor=(0.4,0.1)
loc=3
(0.4,0.1)
However, specifying the bounding tuple as a 2-tuple makes sense if you don't specify the width and height in relative units ( "30%"
). Or, in other words, to use relative units, you need to use 4- bbox_to_anchor
notation for bbox_to_anchor
.
In the case of specifying bbox_to_anchor
in units of axes, you must reuse the argument bbox_transform
, as explained here , and set it to ax.transAxes
.
plt.figure(figsize=(6,3))
ax = plt.subplot(221)
ax.set_title("100%, (0.5,1-0.3,.3,.3)")
ax.plot(xdata, ydata)
axins = inset_axes(ax, width="100%", height="100%", loc='upper left',
bbox_to_anchor=(0.5,1-0.3,.3,.3), bbox_transform=ax.transAxes)
ax = plt.subplot(222)
ax.set_title("30%, (0.5,0,1,1)")
ax.plot(xdata, ydata)
axins = inset_axes(ax, width="30%", height="30%", loc='upper left',
bbox_to_anchor=(0.5,0,1,1), bbox_transform=ax.transAxes)
Find a complete example on matplotlib page: Demo version Inset Locator
Another option is to use InsetPosition
instead of inset_axes
and give the existing axes a new position. InsetPosition
takes the x and y coordinates of the lower left corner of the axes in normalized axis coordinates, and the width and height as input.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import InsetPosition
fig, ax= plt.subplots()
iax = plt.axes([0, 0, 1, 1])
ip = InsetPosition(ax, [0.4, 0.1, 0.3, 0.7]) #posx, posy, width, height
iax.set_axes_locator(ip)
iax.plot([1,2,4])
plt.show()
Finally, it should be mentioned that from matplotlib 3.0 on you can use matplotlib.axes.Axes.inset_axes
import matplotlib.pyplot as plt
plt.figure(figsize=(6,3))
ax = plt.subplot(221)
ax.set_title("ax.inset_axes, (0.5,1-0.3,.3,.3)")
ax.plot([0,4], [0,10])
axins = ax.inset_axes((0.5,1-0.3,.3,.3))
plt.show()
The result is about the same, except that it mpl_toolkits.axes_grid1.inset_locator.inset_axes
allows mpl_toolkits.axes_grid1.inset_locator.inset_axes
around the axes (and applies it by default), while Axes.inset_axes
it has no such padding.
source to share
Using the answer from ImportanceOfBeingErnest and a few suggested links from unreleased documentation matplotlib
like the locator demo and inset_axes
docs , it still took me a while to figure out how all the parameters behave. So I will repeat my understanding here for clarity. I ended up using:
bbox_ll_x = 0.2
bbox_ll_y = 0
bbox_w = 1
bbox_h = 1
eps = 0.01
inset_axes = inset_axes(parent_axes,
height="30%", #height of inset axes as frac of bounding box
width="70%", #width of inset axes as frac of bounding box
bbox_to_anchor=(bbox_ll_x,bbox_ll_y,bbox_w-bbox_ll_x,bbox_h),
loc='upper left',
bbox_transform=parent_axes.transAxes)
parent_axes.add_patch(plt.Rectangle((bbox_ll_x, bbox_ll_y+eps),
bbox_w-eps-bbox_ll_x,
bbox_h-eps,
ls="--",
ec="c",
fc="None",
transform=parent_axes.transAxes))
bbox_ll_x
is the x location of the bottom left corner of the bounding rectangle in parent axis coordinates (i.e. the input value bbox_transform
)
bbox_ll_y
- this is the y-position of the bottom-left corner of the bounding box in parent axis coordinates
bbox_w
- the width of the bounding box in the coordinates of the parent axis
bbox_h
- the height of the bounding box in the coordinates of the parent axis
eps
- a small number to display rectangles from below the axes when drawing a rectangular bounding rectangle.
I used a call add_patch
to place the blue dotted line that represents the inner edge of the hand-drawn frame.
The hardest part for me was understanding that the inputs height
and width
(when specified as percentages) refer to the size of the bounding box. Therefore (as mentioned in the links and below) you must specify a 4-tuple for the parameter bbox_to_anchor
if you specify the size of the insertion axes in percent. If you give the size of the insertion axes in percentage and don't supply bbox_w
or bbox_h
how matplotlib
to get the absolute size of the insertion?
Another thing is that the parameter loc
specifies where to bind the insertion axes in the bounding box. As far as I can tell, the only function of this parameter.
source to share