【问题标题】:How to join two matplotlib figures如何连接两个 matplotlib 图形
【发布时间】:2018-08-01 10:11:36
【问题描述】:

我有一个从数据生成 matplotlib 图形的脚本。这些图按如下方式保存到磁盘:

fig, ax = plt.subplots() # create the plot # ... pickle.dump(ax, open(of, 'wb'))

在另一个脚本中,我想加入其中的某些情节。我可以使用以下方法读回数据:

figures = [pickle.load(file) for file in files]

(FWIW,我读回的数字类型为AxesSubplot。)

到目前为止一切顺利。现在我想将两个(或更多)图形的数据放在一起,使用可用绘图的最大或最小比例。由于我缺乏经验,我完全不知道如何做到这一点。我确实发现了有关加入情节的问题,并且共识是首先在一个图中绘制。在我的情况下,这将是相当困难的,因为单个数据集的绘图逻辑已经很复杂。 (还有其他原因,为什么每个数据集都应该在第一步中单独绘制,然后才可能与其他数据集连接)。

我想加入的图以相同的方式表示它们的数据 - 即所有图都是线图或直方图(不确定如何有意义地加入这些图)或 QQPlots(参见 statsmodels.api)。它们可能具有或可能不具有相同大小的数据。

如何加入不同图形的图?

【问题讨论】:

    标签: python-3.x matplotlib


    【解决方案1】:

    我认为您会发现将数据保存到文件中更容易,您以后可以从中生成新的绘图。您甚至可以使用np.savez 不仅将数据保存在一个文件中,还可以将绘图方法及其参数保存在一个文件中。以下是您以后如何load 这些文件在新图中生成“连接”图的方法:

    import matplotlib.pyplot as plt
    import numpy as np
    
    def join(ax, files):
        data = [np.load(filename) for filename in files]
        for datum in data:
            method = getattr(ax, datum['method'].item())
            args = tuple(datum['args'])
            kwargs = datum['kwargs'].item()
            method(*args, **kwargs)
    
    x = np.linspace(-3, 3, 100)
    y = np.exp(-x**2/2)/np.sqrt(2*np.pi)
    a = np.random.normal(size=10000)
    
    fig, ax = plt.subplots()
    ax.plot(x, y)
    plt.show()
    np.savez('/tmp/a.npz', method='plot', args=(x, y), kwargs=dict())
    
    fig, ax = plt.subplots()
    ax.hist(a, bins=100, density=True)
    plt.show()
    np.savez('/tmp/b.npz', method='hist', args=(a,), 
             kwargs=dict(bins=100, density=True))
    
    fig, ax = plt.subplots()
    join(ax, ['/tmp/a.npz', '/tmp/b.npz'])
    plt.show()
    


    以上我使用np.saveznp.load 而不是pickle 来保存和恢复数据。或者,您可以腌制一个包含数据、方法及其参数的字典、元组或列表。但是,由于数据主要是数字,所以使用np.savezmore efficient and less of a security risk than pickle

    【讨论】:

    • 不可能克隆轴。但是,可以将轴从腌制图形移动到另一个,如here 所示。但这个问题并没有要求任何一个,而是要在轴内移动艺术家。
    • “数据”的 TIL 单数是“基准”
    【解决方案2】:

    创建函数以绘制到特定轴

    您通常会将绘图放入一个函数中,该函数将要绘制的轴作为参数。然后你可以在任何你喜欢的地方重复使用这个函数。

    import numpy as np
    import matplotlib.pyplot as plt
    
    def myplot1(data, ax=None, show=False):
        if not ax:
            _, ax = plt.subplots()
        ax.plot(data[0], data[1])
        if show:
            plt.show()
    
    def myplot2(data, ax=None, show=False):
        if not ax:
            _, ax = plt.subplots()
        ax.hist(data, bins=20, density=True)
        if show:
            plt.show()
    
    x = np.linspace(-3, 3, 100)
    y = np.exp(-x**2/2)/np.sqrt(2*np.pi)
    a = np.random.normal(size=10000)
    
    # create figure 1
    myplot1((x,y))
    #create figure 2
    myplot2(a)
    
    # create figure with both
    fig, ax = plt.subplots()
    myplot1((x,y), ax=ax)
    myplot2(a, ax=ax)
    
    plt.show()
    


    将艺术家转移到新形象

    要回答这个问题,是的,您可以将艺术家从未腌制的人物中移出,但这涉及一些黑客行为,并且可能导致不完美的结果:

    import matplotlib.pyplot as plt
    import numpy as np
    import pickle
    
    x = np.linspace(-3, 3, 100)
    y = np.exp(-x**2/2)/np.sqrt(2*np.pi)
    a = np.random.normal(size=10000)
    
    fig, ax = plt.subplots()
    ax.plot(x, y)
    
    pickle.dump(fig, open("figA.pickle","wb"))
    #plt.show()
    
    fig, ax = plt.subplots()
    ax.hist(a, bins=20, density=True, ec="k")
    
    pickle.dump(fig, open("figB.pickle","wb"))
    #plt.show()
    
    plt.close("all")
    
    #### No unpickle the figures and create a new figure
    #    then add artists to this new figure
    
    figA = pickle.load(open("figA.pickle","rb"))
    figB = pickle.load(open("figB.pickle","rb"))
    
    fig, ax = plt.subplots()
    
    for figO in [figA,figB]:
        lists = [figO.axes[0].lines, figO.axes[0].patches]
        addfunc = [ax.add_line, ax.add_patch]
        for lis, func in zip(lists,addfunc):
            for artist in lis[:]:
                artist.remove()
                artist.axes=ax
                artist.set_transform(ax.transData)
                artist.figure=fig
                func(artist)
    
    ax.relim()
    ax.autoscale_view()
    
    plt.close(figA)
    plt.close(figB)   
    plt.show()
    

    在这里,我们循环遍历未腌制图形中的所有线条和补丁,将它们从旧图形中删除并将它们添加到新图形中。为此,我们需要设置轴、变换和图形以正确匹配新图形。 这当然会随着图中不同类型的艺术家而变得越来越复杂,并且需要even more complex methods if those artists have transforms other than the data transform associated with them

    【讨论】:

    • @unutbu 是的,这是正确的,那是因为我忽略了在迭代列表时从不操作列表的基本原则。 ;-) 我更正了。
    • 我已经发布了一个关于移动收藏的后续问题here
    • @unutbu 我在写 时没有考虑后果......如果这些艺术家有与他们关联的数据转换以外的转换,则需要更复杂的方法" i> :-)
    • @ImportanceOfBeingErnest 非常感谢您的回答!它对我来说几乎是完美的——最后一个问题:我怎样才能改变绘图的颜色?我喜欢让每个单独的情节都有自己的颜色,以使它们可以区分。我尝试为每个艺术家设置颜色,但没有成功。
    • artist.set_color
    猜你喜欢
    • 1970-01-01
    • 2013-12-23
    • 2015-02-08
    • 1970-01-01
    • 2019-03-22
    • 2016-09-12
    • 2014-04-26
    • 2018-11-27
    相关资源
    最近更新 更多