python-3.xmatplotlibmultiple-axes

Matplotlib pick event with multiple axes


I am working on plot with two axes which supports picking the lines. I am using matplotlib and the the twinx() command. Unfortunately the pick event is only called for the artists in the top-most axes (see example below).

import matplotlib.pyplot as plt
import numpy as np

def onPick(event):
    print(event.artist.get_label())
    
def pick():
    fig=plt.figure(figsize=(5, 4), dpi=100, tight_layout=True)
    axis_1=fig.add_subplot(111)
    axis_2=axis_1.twinx()

    axis_1.set_ylim(0, 10)
    axis_2.set_ylim(0, 10)

    x=np.array([1,2,3,4])
    y_1=np.array([1,1,1,1])
    y_2=y_1+4
    
    axis_1.plot(x, y_1, picker=5, label='line_1')
    axis_2.plot(x, y_2, picker=5, label='line_2')
    
    fig.canvas.mpl_connect('pick_event', onPick)
    plt.show()

if __name__=='__main__':
    pick()

Is there a way to pick the lines from the axis below?


Solution

  • Impossible. ^^ I found a solution. I do not pick from the axes, I pick from the legend.
    I think this is a good compromise.

    import matplotlib.pyplot as plt
    import numpy as np
    from numpy.random import rand
    
    
    def onpick(event):
            print(event.artist.get_label())
    
    
    if __name__ == '__main__':
        t=np.linspace(1, 10, 100)
        y1, y2=1*t, 2*t
        y3, y4=3*t, 4*t
    
        fig, ax1=plt.subplots()
        ax2=ax1.twinx()
        ax2._get_lines.prop_cycler = ax1._get_lines.prop_cycler # Send Color cycle state to second axis.
        
        line1, = ax1.plot(t, y1, lw=2, label='1 HZ')
        line2, = ax1.plot(t, y2, lw=2, label='2 HZ')
        line3, = ax2.plot(t, y3, lw=2, label='3 HZ')
        line4, = ax2.plot(t, y4, lw=2, label='4 HZ')
        
        leg=ax1.legend(handles=[line1, line2, line3, line4], bbox_to_anchor=(0,1.02,1,0.2), loc="lower left", mode="expand", borderaxespad=0, ncol=3)
        for line in leg.get_lines(): line.set_picker(5)
        
        fig.canvas.mpl_connect('pick_event', onpick)
        plt.show()