使用 Memcache 缓存 Matplotlib(Wont Pickle)
Posted
技术标签:
【中文标题】使用 Memcache 缓存 Matplotlib(Wont Pickle)【英文标题】:Caching Matplotlib with Memcache (Wont Pickle) 【发布时间】:2012-04-30 21:00:27 【问题描述】:我有一个渲染图表需要 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
无论如何我可以让它工作吗?
【问题讨论】:
数据结构是需要 3 秒的部分还是 matplotlib 的实际绘图?之前已经讨论过这个问题,显然在使 matplotlib 可序列化方面没有做任何事情。 Matplotlib 绘图。由于他们的烛台图很烂,我正在使用单独的条形图绘制烛台图。而且由于我无法通过列表(差异颜色、值、误差线)使条形图工作,因此我将通过一个循环(大约 400 个项目)单独添加每个条形图,这可能会导致它花费这么长时间。此处的示例脚本:pastebin.com/6aD8YZfM。如果我可以缓存最后一组条形图,时间就不会那么重要了。 那么在那个示例循环中,轴的创建需要时间吗?而你这样做 400 次以生成需要 3 秒的轴集合? 该循环中的每次大约需要 0.01 到 0.03 秒 x 400 使我在大约 4-5 秒内将所有条形放置在图像上。其他一切都很快。如果我可以缓存条形集合或加快添加条形(可能批量添加),我会很高兴。 【参考方案1】:关于 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
【讨论】:
非常感谢。图表从 5 秒变为 1.7 秒,非常感谢!从长远来看,仍然希望有一个 matplotlib 缓存机制!【参考方案2】:从 matplotlib 1.2 开始,您应该能够腌制和取消腌制图形。
这是一个非常“实验性”的功能,但如果您确实发现任何问题,请通过 mpl 邮件列表或通过在 github.com/matplotlib/matplotlib 上提出问题告诉我们
HTH
【讨论】:
【参考方案3】:查看documentation,fig.add_axes()
似乎将一个元组作为参数,您正在传递一个列表。因此,它没有返回 Axes
对象(因为它没有被创建),所以 ax 被分配了函数本身。
【讨论】:
这是不正确的。各种方法可以采用一个序列,无论是列表还是元组。无论哪种方式。add_axes()
正在返回一个 Axis
对象。问题是 OP 正试图通过线路将 Axis 实例发送到 memcached,它希望能够序列化对象。 matplotlib 对象不能被序列化。它基本上窒息在轴的各种内部。看看ax.__dict__
的值。您将看到它对其他 matplotlib 对象的巨大引用,包括图形等。以上是关于使用 Memcache 缓存 Matplotlib(Wont Pickle)的主要内容,如果未能解决你的问题,请参考以下文章