【问题标题】:Matplotlib - mark_inset with different edges for axesMatplotlib - mark_inset 具有不同的轴边缘
【发布时间】:2017-07-13 09:42:34
【问题描述】:

我想在一个子图中绘制一个阻尼随机游走的时间序列,然后在第二个子图中放大它。我从 matplotlib 知道mark_inset,它工作得很好。我到目前为止的代码是:

from mpl_toolkits.axes_grid1.inset_locator import mark_inset
from astroML.time_series import generate_damped_RW

fig = plt.figure()
ax = fig.add_subplot(111)
ax0 = fig.add_subplot(211)
ax1 = fig.add_subplot(212)

ax.set_ylabel('Brightness[mag]')
ax.yaxis.labelpad=30
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_color('none')
ax.spines['left'].set_color('none')
ax.spines['right'].set_color('none')
ax.tick_params(labelcolor='w', top='off', bottom='off', left='off',
               right='off')

t = np.linspace(0, 5000, 100000)
data = generate_damped_RW(t, tau=100, xmean=20, z=0, SFinf=0.3,
                          random_state=1)
ax0.scatter(t, data, s=0.5)
ax0.text(1, 1, r'$E(m) = %.2f, \sigma(m) = %.2f$'%(np.mean(data),
                                                   np.std(data)),
         verticalalignment='top', horizontalalignment='right',
         transform=ax0.transAxes, fontsize=23)

mask = (t > 370) & (t < 470)
ax1.set_xlabel('Time[years]')
ax1.scatter(t[mask], data[mask], s=0.5)

mark_inset(ax0, ax1, loc1=2, loc=1, fc='none')

创建这样的情节:

这几乎是我想要的,除了连接 2 个子图的线从第一个子图中框的上边缘开始。是否有可能让它们从下两个边缘开始,而它们仍然在第二个子图中的上两个边缘结束?我需要做什么才能实现这一目标?

【问题讨论】:

    标签: python matplotlib figure


    【解决方案1】:

    mark_inset 有两个参数 loc1loc2 来设置两个连接器的位置。这些位置对于框和插入轴都是相同的。

    不过,我们可以向mark_inset 函数添加两个新参数,以设置连接器的开始和结束位置的不同位置。

    import matplotlib.pyplot as plt
    from mpl_toolkits.axes_grid1.inset_locator import TransformedBbox, BboxPatch, BboxConnector 
    import numpy as np
    
    fig, (ax, axins) = plt.subplots(nrows=2)
    
    x = np.linspace(0,6*np.pi)
    y = np.sin(x)
    ax.plot(x,y)
    axins.plot(x,y)
    axins.set_xlim((2*np.pi, 2.5*np.pi))
    axins.set_ylim((0, 1))
    
    # draw a bbox of the region of the inset axes in the parent axes and
    # connecting lines between the bbox and the inset axes area
    # loc1, loc2 : {1, 2, 3, 4} 
    def mark_inset(parent_axes, inset_axes, loc1a=1, loc1b=1, loc2a=2, loc2b=2, **kwargs):
        rect = TransformedBbox(inset_axes.viewLim, parent_axes.transData)
    
        pp = BboxPatch(rect, fill=False, **kwargs)
        parent_axes.add_patch(pp)
    
        p1 = BboxConnector(inset_axes.bbox, rect, loc1=loc1a, loc2=loc1b, **kwargs)
        inset_axes.add_patch(p1)
        p1.set_clip_on(False)
        p2 = BboxConnector(inset_axes.bbox, rect, loc1=loc2a, loc2=loc2b, **kwargs)
        inset_axes.add_patch(p2)
        p2.set_clip_on(False)
    
        return pp, p1, p2
    
    mark_inset(ax, axins, loc1a=1, loc1b=4, loc2a=2, loc2b=3, fc="none", ec="crimson") 
    
    plt.draw()
    plt.show()
    

    【讨论】:

      【解决方案2】:

      不幸的是,mark_inset 总是必须连接相同的角(即右下角总是必须连接到右下角,等等)。

      我们可以创建自己的函数来模仿mark_inset 函数,将两个底角与插图中的两个顶角连接起来(下面代码中的custom_mark_inset)。

      这利用Rectangle 补丁在主轴上绘制框,并使用ConnectionPatch 实例绘制轴之间的连接线。

      from mpl_toolkits.axes_grid1.inset_locator import mark_inset
      #from astroML.time_series import generate_damped_RW
      import matplotlib.pyplot as plt
      import matplotlib.patches as patches
      import numpy as np
      
      fig = plt.figure()
      ax = fig.add_subplot(111)
      ax0 = fig.add_subplot(211)
      ax1 = fig.add_subplot(212)
      
      ax.set_ylabel('Brightness[mag]')
      ax.yaxis.labelpad=30
      ax.spines['top'].set_color('none')
      ax.spines['bottom'].set_color('none')
      ax.spines['left'].set_color('none')
      ax.spines['right'].set_color('none')
      ax.tick_params(labelcolor='w', top='off', bottom='off', left='off',
                     right='off')
      
      t = np.linspace(0, 5000, 10000)
      #data = generate_damped_RW(t, tau=100, xmean=20, z=0, SFinf=0.3,
      #                          random_state=1)
      ## Fake some data
      data = np.sin(t/800.) + 20.
      
      ax0.scatter(t, data, s=0.5)
      ax0.text(1, 1, r'$E(m) = %.2f, \sigma(m) = %.2f$'%(np.mean(data),
                                                         np.std(data)),
               verticalalignment='top', horizontalalignment='right',
               transform=ax0.transAxes, fontsize=23)
      
      mask = (t > 370) & (t < 470)
      ax1.set_xlabel('Time[years]')
      ax1.scatter(t[mask], data[mask], s=0.5)
      
      def custom_mark_inset(axA, axB, fc='None', ec='k'):
          xx = axB.get_xlim()
          yy = axB.get_ylim()
      
          xy = (xx[0], yy[0])
          width = xx[1] - xx[0]
          height = yy[1] - yy[0]
      
          pp = axA.add_patch(patches.Rectangle(xy, width, height, fc=fc, ec=ec))
      
          p1 = axA.add_patch(patches.ConnectionPatch(
              xyA=(xx[0], yy[0]), xyB=(xx[0], yy[1]),
              coordsA='data', coordsB='data',
              axesA=axA, axesB=axB))
      
          p2 = axA.add_patch(patches.ConnectionPatch(
              xyA=(xx[1], yy[0]), xyB=(xx[1], yy[1]),
              coordsA='data', coordsB='data',
              axesA=axA, axesB=axB))
      
          return pp, p1, p2
      
      pp, p1, p2 = custom_mark_inset(ax0, ax1)
      
      plt.show()
      

      【讨论】:

        猜你喜欢
        • 2020-06-15
        • 1970-01-01
        • 2012-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多