Matplotlib-创建多个子图的快速方法? [英] Matplotlib - Fast way to create many subplots?

查看:73
本文介绍了Matplotlib-创建多个子图的快速方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用matplotlib创建具有许多小子图的图形(例如4行,8列).我尝试了几种不同的方法,使matplotlib制作轴的最快速度是2秒左右.我看到这篇文章关于只使用一个轴对象来显示许多小图像,但我希望能够在轴上有刻度和标题.有没有办法加快这个过程,或者在 matplotlib 中制作轴是否需要相当长的时间?

I'm using matplotlib to create a figure with many small subplots (something like 4 rows, 8 columns). I've tried a few different ways, and the fastest that I can get matplotlib to make the axes is ~2 seconds. I saw this post about just using one axes object to display many small images, but I would like to be able to have ticks and titles on the axes. Is there any way to speed this process up, or does making axes in matplotlib just take a reasonably long time?

这是我到目前为止尝试过的:

Here is what I have tried so far:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid
import time

fig = plt.figure(figsize=(10,6))

plt.clf(); t = time.time()
grid = ImageGrid(fig, 111, 
                nrows_ncols = (4, 8))
print 'Time using ImageGrid: %.2f seconds'%(time.time()-t)

plt.clf(); t = time.time()
axes = plt.subplots(4,8)
print 'Time using plt.subplots: %.2f seconds'%(time.time()-t)

plt.clf(); t = time.time()
axes = []
for row in range(0,4):
    for col in range(1,9):
        ax = plt.subplot(4,8,row*8+col)
        axes.append(ax)
print 'Time using ptl.subplot loop: %.2f seconds'%(time.time()-t)

输出:

Time using ImageGrid: 4.25 seconds
Time using plt.subplots: 2.11 seconds
Time using ptl.subplot loop: 2.34 seconds

<小时>

根据乔·肯顿(Joe Kington)的建议,我尝试使图形和坐标轴腌制,以便至少在每次运行脚本时都不需要创建图形和坐标轴.但是,加载文件实际上需要更长的时间:


Taking Joe Kington's suggestion, I tried to pickle the figure and axes so that I would at least not need to create them every time that I run the script. However, loading the file actually takes longer:

import matplotlib.pyplot as plt
import pickle
import time

t = time.time()
fig,axes = plt.subplots(4,8,figsize=(10,6))
print 'Time using plt.subplots: %.2f seconds'%(time.time()-t)

pickle.dump((fig,axes),open('fig.p','wb'))

t = time.time()
fig,axes = pickle.load(open('fig.p','rb'))

print 'Time to load pickled figure: %.2f seconds'%(time.time()-t)

输出:

Time using plt.subplots: 2.01 seconds
Time to load pickled figure: 3.09 seconds

推荐答案

subplots 你不会以任何实质性的方式击败subplots.创建新轴是一项相当昂贵的操作,您每次要创建 32 个.然而,它只完成一次.

You're not going to beat subplots by any substantial amount. Creating new axes is a fairly expensive operation, and you're creating 32 of them each time. However it's only done once.

创建新图形和轴真的是您的瓶颈吗?如果是这样,您可能做错了什么.

Is creating a new figure and axes really your bottleneck? If so, you're probably doing something wrong.

如果您要创建动画,只需更新艺术家(例如 image.set_data 等)并重新绘制,而不是每次都绘制新的图形和轴.

If you're trying to create an animation, just update the artists (e.g. image.set_data, etc) and redraw rather than making a new figure and axes each time.

(此外, axes = plt.subplots(4,8)是不正确的. axes 将是一个元组,而不是您当前使用的轴对象序列 subplots 返回一个图形实例和一个轴数组,它应该是 fig,axes = plt.subplots(...).)

(Also, axes = plt.subplots(4, 8) is incorrect. axes will be a tuple instead of a sequence of axes objects as you've currently written it. subplots returns a figure instance and an array of axes. It should be fig, axes = plt.subplots(...).)

仅在下面我对酸洗的评论中进行扩展:

Just to expand on my comment below about pickling:

更改不相关的参数时,通常很方便地缓存昂贵"的结果.这在科学脚本"中尤为常见,在这些脚本中,您通常会进行一些相当缓慢的数据解析或中间计算,以及您以半交互方式调整"一组相关参数.

It's often handy to cache "expensive" results when you're changing un-related parameters. This is particularly common in scientific "scripts", where you'll often have some fairly slow data parsing or intermediate calculation and a dependent set of parameters that you're semi-interactively "tweaking".

仅仅注释掉几行并明确保存/加载腌制结果并没有错.

There's nothing wrong with just commenting out a few lines and explicitly saving/loading the pickled results.

但是,我发现保留一个自动执行此操作的装饰器很方便.在许多情况下,有更好的方法可以执行此操作,但是对于一种一刀切"的解决方案,它非常方便:

However, I've found it handy to keep a decorator around that does this automatically. There are better ways to do this in many cases, but for a one-size-fits-all solution, it's quite handy:

import os
import cPickle as pickle
from functools import wraps

class Cached(object):
    def __init__(self, filename):
        self.filename = filename

    def __call__(self, func):
        @wraps(func)
        def new_func(*args, **kwargs):
            if not os.path.exists(self.filename):
                results = func(*args, **kwargs)
                with open(self.filename, 'w') as outfile:
                    pickle.dump(results, outfile, pickle.HIGHEST_PROTOCOL)
            else:
                with open(self.filename, 'r') as infile:
                    results = pickle.load(infile)
            return results
        return new_func

然后你可以做一些类似的事情(假设上面的类在 utilities.py 中):

Then you can just do something like (presuming that the class above is in utilities.py):

import matplotlib.pyplot as plt
from utilities import Cached

@Cached('temp.pkl')
def setup():
    fig, axes = plt.subplots(8, 4)
    # And perhaps some other data parsing/whatever
    return fig, axes

fig, axes = setup()
for ax in axes.flat:
    ax.plot(range(10))
plt.show()

仅当给定的文件名("temp.pkl" )不存在时,修饰函数才会运行,并且存储在 temp.pkl 中的缓存结果将否则加载.这适用于任何可以腌制的东西,而不仅仅是 matplotlib 数字.

The decorated function will only be run if the given filename ("temp.pkl") isn't present, and the cached results stored in temp.pkl will be loaded otherwise. This will work for anything that can be pickled, not just matplotlib figures.

不过,请注意使用已保存的状态.如果您更改 setup 所做的并重新运行,将返回旧"结果!!如果您更改包装函数的作用,请务必手动删除缓存文件.

Beware of working with a saved state, though. If you change what setup does and re-run, the "old" results will be returned!! Be sure to manually delete the cached file if you change what the wrapped function does.

当然,如果你只是在一个地方做这件事,那就有点矫枉过正了.不过,如果您发现自己经常缓存中间结果,它会很方便.

Of course, this is overkill if you're just doing it in one place. It can be handy to have around if you find yourself caching intermediate results frequently, though.

这篇关于Matplotlib-创建多个子图的快速方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆