pyplot - copy an axes content and show it in a new figure

后端 未结 2 868
一个人的身影
一个人的身影 2020-11-27 20:34

let say I have this code:

num_rows = 10
num_cols = 1
fig, axs = plt.subplots(num_rows, num_cols, sharex=True)
for i in xrange(num_rows):
     ax = axs[i]
            


        
相关标签:
2条回答
  • 2020-11-27 20:51

    If you have, for example, a plot with three lines generated by the function plot_something, you can do something like this:

    fig, axs = plot_something()
    ax = axs[2]
    l = list(ax.get_lines())[0]
    l2 = list(ax.get_lines())[1]
    l3 = list(ax.get_lines())[2]
    plot(l.get_data()[0], l.get_data()[1])
    plot(l2.get_data()[0], l2.get_data()[1])
    plot(l3.get_data()[0], l3.get_data()[1])
    ylim(0,1)
    

    0 讨论(0)
  • 2020-11-27 21:00

    Copying the axes

    The inital answer here does not work, we keep it for future reference and also to see why a more sophisticated approach is needed.

    #There are some pitfalls on the way with the initial approach. 
    #Adding an `axes` to a figure can be done via `fig.add_axes(axes)`. However, at this point, 
    #the axes' figure needs to be the figure the axes should be added to. 
    #This may sound a bit like running in circles but we can actually set the axes' 
    #figure as `axes.figure = fig2` and hence break out of this.
    
    #One might then also position the axes in the new figure to take the usual dimensions. 
    #For this a dummy axes can be added first, the axes can change its position to the position 
    #of the dummy axes and then the dummy axes is removed again. In total, this would look as follows.
    
    import matplotlib.pyplot as plt
    import numpy as np
    
    num_rows = 10
    num_cols = 1
    fig, axs = plt.subplots(num_rows, num_cols, sharex=True)
    for i in xrange(num_rows):
         ax = axs[i]
         ax.plot(np.arange(10), np.arange(10)**i)
         
         
    def on_click(event):
        axes = event.inaxes
        if not axes: return   
        fig2 = plt.figure()
        axes.figure=fig2
        fig2.axes.append(axes)
        fig2.add_axes(axes)
        
        dummy = fig2.add_subplot(111)
        axes.set_position(dummy.get_position())
        dummy.remove()
        fig2.show()
    
    fig.canvas.mpl_connect('button_press_event', on_click)
    
    
    plt.show()
    
    #So far so good, however, be aware that now after a click the axes is somehow 
    #residing in both figures, which can cause all sorts of problems, e.g. if you
    # want to resize or save the initial figure.

    Instead, the following will work:

    Pickling the figure

    The problem is that axes cannot be copied (even deepcopy will fail). Hence to obtain a true copy of an axes, you may need to use pickle. The following will work. It pickles the complete figure and removes all but the one axes to show.

    import matplotlib.pyplot as plt
    import numpy as np
    import pickle
    import io
    
    num_rows = 10
    num_cols = 1
    fig, axs = plt.subplots(num_rows, num_cols, sharex=True)
    for i in range(num_rows):
         ax = axs[i]
         ax.plot(np.arange(10), np.arange(10)**i)
    
    def on_click(event):
    
        if not event.inaxes: return
        inx = list(fig.axes).index(event.inaxes)
        buf = io.BytesIO()
        pickle.dump(fig, buf)
        buf.seek(0)
        fig2 = pickle.load(buf) 
    
        for i, ax in enumerate(fig2.axes):
            if i != inx:
                fig2.delaxes(ax)
            else:
                axes=ax
    
        axes.change_geometry(1,1,1)
        fig2.show()
    
    fig.canvas.mpl_connect('button_press_event', on_click)
    
    plt.show()
    

    Recreate plots

    The alternative to the above is of course to recreate the plot in a new figure each time the axes is clicked. To this end one may use a function that creates a plot on a specified axes and with a specified index as input. Using this function during figure creation as well as later for replicating the plot in another figure ensures to have the same plot in all cases.

    import matplotlib.pyplot as plt
    import numpy as np
    
    num_rows = 10
    num_cols = 1
    colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
    labels = ["Label {}".format(i+1) for i in range(num_rows)]
    
    def myplot(i, ax):
        ax.plot(np.arange(10), np.arange(10)**i, color=colors[i])
        ax.set_ylabel(labels[i])
    
    
    fig, axs = plt.subplots(num_rows, num_cols, sharex=True)
    for i in xrange(num_rows):
         myplot(i, axs[i])
    
    
    def on_click(event):
        axes = event.inaxes
        if not axes: return
        inx = list(fig.axes).index(axes)
        fig2 = plt.figure()
        ax = fig2.add_subplot(111)
        myplot(inx, ax)
        fig2.show()
    
    fig.canvas.mpl_connect('button_press_event', on_click)
    
    plt.show()
    
    0 讨论(0)
提交回复
热议问题