2014-01-06 4 views
3

Я использую matplotlib для создания фигуры со многими небольшими подзаголовками (что-то вроде 4 строк, 8 столбцов). Я пробовал несколько разных способов, и самое быстрое, что я могу получить matplotlib для создания осей, составляет ~ 2 секунды. Я видел this post о простом объекте с одной осью, чтобы отображать много маленьких изображений, но я хотел бы иметь тики и названия на осях. Есть ли способ ускорить этот процесс или сделать топоры в matplotlib достаточно долго?Matplotlib - Быстрый способ создания множества подзаголовков?

Вот что я пытался до сих пор:

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 

Принимая предложение Джо Kington, я попытался засолить фигуру и оси так, что я бы на по крайней мере, не нужно создавать их каждый раз, когда я запускаю скрипт. Тем не менее, загрузка файла на самом деле занимает больше времени:

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 

ответ

5

Вы не собираетесь бить subplots по какой-либо существенной суммы. Создание новых осей - довольно дорогостоящая операция, и вы создаете 32 из них каждый раз. Однако это делается только один раз.

Создает новую фигуру и оси, действительно ли это узкое место? Если это так, вы, вероятно, делаете что-то неправильно.

Если вы пытаетесь создать анимацию, просто обновите художников (например, image.set_data и т. Д.) И переделайте, а не создавайте новую фигуру и оси каждый раз.

(Кроме того, axes = plt.subplots(4, 8) неверен. axes будет кортеж вместо последовательности осей объектов, как вы в настоящее время письменными его. subplots возвращает экземпляр фигуры и массив осей. Она должна быть fig, axes = plt.subplots(...).)


Просто расширить на мой комментарий ниже о засолки:

Это часто удобно кэшировать «дорогих» результатов, когда вы меняете связанных с ООН параметров. Это особенно характерно для научных «скриптов», где вы часто будете иметь довольно медленный синтаксический анализ данных или промежуточный расчет и зависимый набор параметров, которые вы полуинформативно «настраиваете».

Нет ничего плохого в том, чтобы просто прокомментировать несколько строк и явно сохранить/загрузить маринованные результаты.

Однако, я нашел удобным держать декоратор вокруг, что делает это автоматически.Есть лучшие способы сделать это во многих случаях, но один размер подходит всем решение, это очень удобно:

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):

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.

Остерегайтесь работы с сохраненным состоянием. Если вы измените то, что делает setup, и повторный запуск, «старые» результаты будут возвращены! Обязательно вручную удалите кешированный файл, если вы измените то, что делает завершенная функция.

Конечно, это излишне, если вы просто делаете это в одном месте. Это может быть удобно, если вы часто используете кеширование промежуточных результатов.

+0

Хорошо, хорошо знать, что я не могу сделать намного лучше, чем plt.subplots(). Я не делаю анимацию, просто фигуру с большим количеством небольших сюжетов. Поэтому, когда я делаю изменения фигуры, мне нужно перезапустить скрипт и подождать несколько секунд, чтобы настроить подзаголовки. Возможно, это не будет узким местом, но все же раздражает несколько секунд, что мне нужно подождать. Спасибо за Ваш ответ! – DanHickstein

+0

Это имеет смысл. Пара-второе отставание, конечно, вызывает раздражение, когда вы пытаетесь настроить различные вещи и повторно запустить. Одна вещь, которую вы можете сделать, - это попробовать «чистую» фигуру с сеткой подзаголовков, а затем загружать маринованную версию, а не создавать новую. В этом конкретном случае это довольно быстро. –

+0

Я пробовал метод травления, но на самом деле это занимает больше времени, чем создание подзаговоров. Но, возможно, я неправильно использую модуль рассола. Я добавил это в нижнюю часть вопроса. – DanHickstein

Смежные вопросы