4

我有一个渲染的图表需要 3 秒,然后可以从所述图表制作子图表,其中添加了一些东西。我想缓存主图表中的轴,以便稍后在渲染子图表时检索并修改它。我怎样才能克服这个错误?

下面是一个示例测试代码:

import pylibmc
cache = pylibmc.Client(["127.0.0.1"], binary=True, behaviors={"tcp_nodelay": True, "ketama": True})
import matplotlib.pyplot as plt


cache_name = 'test'
fig = plt.figure(figsize=(20, 7))
ax = fig.add_axes([0, 0.15, 0.98, 0.85])
cache.set(cache_name, ax, 300)

这给出了以下错误:

cPickle.PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed

无论如何我可以让它工作吗?

4

3 回答 3

3

那里有关于 matplotlib 图形能够被序列化的愿望的讨论。我还没有看到任何报告这已被解决甚至被接受为目标。因此,如果您尝试通过网络将它们发送到 memcached,它显然会失败。我在搜索时发现的讨论表明,matplotlib 的当前设计不能轻易满足这个目标,它需要对内部进行重构。参考: http: //old.nabble.com/matplotlib-figure-serialization-td28016714.html

为了显着减少执行时间,您可以做的是将数据重新组织到数据集中,并且只调用ax.bar()一次。然后可以将数据集序列化并以您想要的任何格式存储(例如,存储到 memcached 中)。

这是一个代码示例,显示了您的方法之间的测试,以及将它们组合成数据集的方法。如果需要,您可以更轻松地在此处查看:https ://gist.github.com/2597804

import matplotlib.pyplot as plt
from random import randint 
from time import time 

DATA = [
    (i, randint(5,30), randint(5,30), randint(30,35), randint(1,5)) \
    for i in xrange(1, 401)
]

def mapValues(group):
    ind, open_, close, high, low = group
    if open_ > close: # if open is higher then close
        height = open_ - close # heigth is drawn at bottom+height
        bottom = close
        yerr = (open_ - low, high - open_)
        color = 'r' # plot as a white barr
    else:
        height = close - open_ # heigth is drawn at bottom+height
        bottom = open_
        yerr = (close - low, high - close)
        color = 'g' # plot as a black bar

    return (ind, height, bottom, yerr, color)

#
# Test 1
#
def test1():
    fig = plt.figure()
    ax = fig.add_subplot(111)

    data = map(mapValues, DATA)

    start = time()

    for group in data: 

        ind, height, bottom, yerr, color = group

        ax.bar(left=ind, height=height, bottom=bottom, yerr=zip(yerr), 
                color=color, ecolor='k', zorder=10,
                error_kw={'barsabove': False, 'zorder': 0, 'capsize': 0}, 
                alpha=1)

    return time()-start

#
# Test 2
#
def test2():
    fig = plt.figure()
    ax = fig.add_subplot(111)

    # plotData can be serialized
    plotData = zip(*map(mapValues, DATA))

    ind, height, bottom, yerr, color = plotData

    start = time()

    ax.bar(left=ind, height=height, bottom=bottom, yerr=zip(*yerr), 
            color=color, ecolor='k', zorder=10,
            error_kw={'barsabove': False, 'zorder': 0, 'capsize': 0}, 
            alpha=1)

    return time()-start


def doTest(fn):
    end = fn()
    print "%s - Sec: %0.3f, ms: %0d" % (fn.__name__, end, end*1000)



if __name__ == "__main__":
    doTest(test1)
    doTest(test2)

    # plt.show()

结果:

python plot.py 
test1 - Sec: 1.592, ms: 1592
test2 - Sec: 0.358, ms: 357
于 2012-05-04T21:34:29.310 回答
1

从 matplotlib 1.2 开始,您应该能够腌制和取消腌制数字。

这是一个非常“实验性”的功能,但是如果您确实发现任何问题,请在 mpl 邮件列表中告知我们或在 github.com/matplotlib/matplotlib 上提出问题

高温高压

于 2012-10-04T19:41:42.777 回答
-1

查看文档,它似乎fig.add_axes()需要一个元组作为参数,您正在传递一个列表。因此,它没有返回Axes对象(因为它没有被创建),所以 ax 被分配了函数本身。

于 2012-05-04T05:32:55.987 回答