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()1 回だけ呼び出すことです。その後、データセットをシリアル化し、任意の形式で (たとえば 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 で問題を提起してお知らせください。

HTH

于 2012-10-04T19:41:42.777 に答える
-1

documentationを見るとfig.add_axes()、タプルを引数として取り、リストを渡しているように見えます。そのため、Axesオブジェクトが返されないため (作成されていないため)、ax 自体に関数が割り当てられます。

于 2012-05-04T05:32:55.987 に答える