2012-04-30 2 views
4

У меня есть диаграмма, которая отображается, занимает 3 секунды, а затем подзаголовки, которые могут быть сделаны из указанной диаграммы, где вещи добавляются к ней. Я хочу, чтобы кешировать оси из основной диаграммы, чтобы я мог ее восстановить и позже изменить при рендеринге подматричек. Как я могу пройти мимо этой ошибки?Кэширование Matplotlib с Memcache (Wont Pickle)

Heres код тестовый образец:

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 

есть в любом случае я мог бы получить эту работу?

+1

Является ли структура данных частью, занимающей 3 секунды или фактическим графиком matplotlib? Об этом раньше говорили, и, по-видимому, ничего не сделано в плане создания matplotlib сериализуемого. – jdi

+0

Matplotlib Построение. Поскольку их подсвечники подходят, я рисую график подсвечника, используя отдельные бары. И так как я не могу получить бар, чтобы работать через список (цвета, значения, бары ошибок), я добавляю каждый бар индивидуально тщательным циклом (около 400 элементов), что, вероятно, заставляет его занять это долго. Пример скрипта здесь: http://pastebin.com/6aD8YZfM. Если бы я мог кэшировать последний набор баров, время не было бы таким важным. – NoviceCoding

+0

Итак, в этом цикле выборки создание оси требует времени? И вы делаете это 400 раз, чтобы создать коллекцию оси, которая занимает 3 секунды? – jdi

ответ

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 
+0

Благодарим кучу. Большое спасибо за диаграмму от 5 до 1,7. Все еще надеемся на механизм кэширования matplotlib в долгосрочной перспективе! – NoviceCoding

-1

Глядя на documentation, оказалось, что fig.add_axes() принимает кортеж в качестве аргумента, где вы передаете список. Таким образом, он не возвращает объект Axes (поскольку он не создается), так что ax присваивается самой функции.

+1

Неверное изображение.Различные методы могут принимать последовательность, будь то список или кортеж. Так или иначе. 'add_axes()' возвращает объект 'Axis'. Проблема в том, что OP пытается отправить экземпляр Axis через провод к memcached, который хочет иметь возможность сериализовать объект. Объекты matplotlib не могут быть сериализованы. Он в основном задыхается от различных внутренних элементов оси. Взгляните на значение 'ax .__ dict__'. Вы увидите его огромную ссылку на другие объекты matplotlib, включая фигуру и т. Д. – jdi

1

По состоянию на Matplotlib 1.2 вы должны быть в состоянии мариновать и unpickle цифры.

Это очень «экспериментальная» особенность, но если вы обнаружите какие-либо вопросы, пожалуйста, сообщите нам об этом в списке рассылки MPL или поднимая вопрос о github.com/matplotlib/matplotlib

НТН