specific location for inset axes

前端 未结 2 1471
太阳男子
太阳男子 2020-12-15 09:51

I want to create a set of axes to form an inset at a specific location in the parent set of axes. It is therefore not appropriate to just use the parameter loc=1,2,3<

相关标签:
2条回答
  • 2020-12-15 10:08

    Using the answer from ImportanceOfBeingErnest and several of the suggested links from the unreleased matplotlib documentation like the locator demo and the inset_axes docs, it still took me some time to figure out how all the parameters behaved. 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 lower left corner of the bounding box in the parent axis coordinates (that is the meaning of the bbox_transform input)

    bbox_ll_y is the y location of the lower left corner of the bounding box in the parent axis coordinates

    bbox_w is the width of the bounding box in parent axis coordinates

    bbox_h is the height of the bounding box in parent axis coordinates

    eps is a small number to get the rectangles to show up from under axes when drawing the rectangular bounding box.

    I used the add_patch call in order to put a cyan dashed line that represents the inner edge of the bounding box that is drawn.

    The trickiest part for me was realizing that the height and width inputs (when specified as percents) are relative to the bounding box size. That's why (as noted in the links and the answer below) you must specify a 4-tuple for the bbox_to_anchor parameter if you specify the size of the inset axes in percents. If you specify the size of the inset axes as percents and don't supply bbox_w or bbox_h how can matplotlib get the absolute size of the inset?

    Another thing was that the loc parameter specifies where to anchor the inset axes within the bounding box. As far as I can tell that's the only function of that parameter.

    0 讨论(0)
  • The approach you took is in principle correct. However, just like when placing a legend with bbox_to_anchor, the location is determined as an interplay between bbox_to_anchor and loc. Most of the explanation in the above linked answer applies here as well.

    The default loc for inset_axes is loc=1 ("upper right"). This means that if you you specify bbox_to_anchor=(0.4,0.1), those will be the coordinates of the upper right corner, not the lower left one.
    You would therefore need to specify loc=3 to have the lower left corner of the inset positionned at (0.4,0.1).

    However, specifying a bounding as a 2-tuple only makes sense if not specifying the width and height in relative units ("30%"). Or in other words, in order to use relative units you need to use a 4-tuple notation for the bbox_to_anchor.

    In case of specifying the bbox_to_anchor in axes units one needs to use the bbox_transform argument, again, just as with legends 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 the matplotlib page: Inset Locator Demo

    Another option is to use InsetPosition instead of inset_axes and to give an existing axes a new position. InsetPosition takes the x and y coordinates of the lower left corner of the axes in normalized axes coordinates, as well as 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 one should mention 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 roughly the same, except that mpl_toolkits.axes_grid1.inset_locator.inset_axes allows for a padding around the axes (and applies it by default), while Axes.inset_axes does not have this kind of padding.

    0 讨论(0)
提交回复
热议问题