2013-01-15 2 views
4

누구든지 플롯 기능을 파이썬으로 최적화하는 방법을 도울 수 있습니까? 나는 Matplotlib을 사용하여 재무 데이터를 플롯합니다. OHLC 데이터 플로팅을위한 작은 함수입니다. 표시기 나 다른 데이터를 추가하면 시간이 크게 늘어납니다.Matlpotlib로 매우 느린 플롯

import numpy as np 
import datetime 
from matplotlib.collections import LineCollection 
from pylab import * 
import urllib2 

def test_plot(OHLCV): 

    bar_width = 1.3 
    date_offset = 0.5 
    fig = figure(figsize=(50, 20), facecolor='w') 
    ax = fig.add_subplot(1, 1, 1) 
    labels = ax.get_xmajorticklabels() 
    setp(labels, rotation=0) 

    month = MonthLocator() 
    day = DayLocator() 
    timeFmt = DateFormatter('%Y-%m-%d') 

    colormap = OHLCV[:,1] < OHLCV[:,4] 
    color = np.zeros(colormap.__len__(), dtype = np.dtype('|S5')) 
    color[:] = 'red' 
    color[np.where(colormap)] = 'green' 
    dates = date2num(OHLCV[:,0]) 

    lines_hl = LineCollection(zip(zip(dates, OHLCV[:,2]), zip(dates, OHLCV[:,3]))) 
    lines_hl.set_color(color) 
    lines_hl.set_linewidth(bar_width) 
    lines_op = LineCollection(zip(zip((np.array(dates) - date_offset).tolist(), OHLCV[:,1]), zip((np.array(dates)).tolist(), parsed_table[:,1]))) 
    lines_op.set_color(color) 
    lines_op.set_linewidth(bar_width) 
    lines_cl = LineCollection(zip(zip((np.array(dates) + date_offset).tolist(), OHLCV[:,4]), zip((np.array(dates)).tolist(), parsed_table[:,4]))) 
    lines_cl.set_color(color) 
    lines_cl.set_linewidth(bar_width) 
    ax.add_collection(lines_hl, autolim=True) 
    ax.add_collection(lines_cl, autolim=True) 
    ax.add_collection(lines_op, autolim=True) 

    ax.xaxis.set_major_locator(month) 
    ax.xaxis.set_major_formatter(timeFmt) 
    ax.xaxis.set_minor_locator(day) 

    ax.autoscale_view() 

    ax.xaxis.grid(True, 'major') 
    ax.grid(True) 

    ax.set_title('EOD test plot') 
    ax.set_xlabel('Date') 
    ax.set_ylabel('Price , $') 
    fig.savefig('test.png', dpi = 50, bbox_inches='tight') 
    close() 

if __name__=='__main__': 

    data_table = urllib2.urlopen(r"http://ichart.finance.yahoo.com/table.csv?s=IBM&a=00&b=1&c=2012&d=00&e=15&f=2013&g=d&ignore=.csv").readlines()[1:][::-1] 
    parsed_table = [] 
    #Format: Date, Open, High, Low, Close, Volume 
    dtype = (lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(),float, float, float, float, int) 

    for row in data_table: 

     field = row.strip().split(',')[:-1] 
     data_tmp = [i(j) for i,j in zip(dtype, field)] 
     parsed_table.append(data_tmp) 

    parsed_table = np.array(parsed_table) 

    import time 
    bf = time.time() 
    count = 100 
    for i in xrange(count): 
     test_plot(parsed_table) 
    print('Plot time: %s' %(time.time() - bf)/count) 

결과이 같은 것입니다. 각 플롯의 평균 실행 시간은 약 2.6 초입니다. R에서 차트를 작성하는 것이 성능을 측정하지 못했고 사용하지 않으려 고했습니다. Rpy, 그래서 저는 코드가 비효율적이라고 말합니다. enter image description here

+0

당신은 많은 그것을 달성 무슨 요로 의견을하지으로이가는 zip's 및 접합'의 많은이 - 간결한 코드의 이름이 같은 모든 시간을 다 할하는 데 사용되는 사람으로, 그리고 반대하라. 돌아와서 나중에 이것을보고 빨아들이는 것입니다 ... – will

+0

[this] (http://docs.python.org/2/library/profile.html)을 시도하는 것이 좋습니다. 나는 데모로 질문에 답할 것이지만, 나는 나의 전화에서 대답하고있다. 악몽 일 것이다. – will

+0

나의 제안은 'FinanceChart' 클래스를 만들어서 그림, 축, 라인 콜렉션과 라벨을 재사용하는 것이다. 이렇게하면 차트 개체를 100 번 재사용 할 수 있으므로 매번 차트 개체를 파괴하고 다시 만들 수 있습니다. 각 linecollections에 대해'set_segments'를 사용하여 데이터를 변경할 수 있습니다. – jozzas

답변

4

이 솔루션은 Figure 인스턴스를 재사용하고 플롯을 비동기 적으로 저장합니다. 이것을 변경하여 프로세서가있는 숫자만큼 비동기 적으로 많은 그림을 그릴 수 있으며, 속도를 더욱 높여야합니다. 그것이 그렇듯이, 이것은 내 컴퓨터의 2.6에서 플롯 당 1 초 정도 걸립니다.

import numpy as np 
import datetime 
import urllib2 
import time 
import multiprocessing as mp 
import matplotlib 
matplotlib.use('Agg') 
import matplotlib.pyplot as plt 
from pylab import * 
from matplotlib.collections import LineCollection 

class AsyncPlotter(): 
    def __init__(self, processes=mp.cpu_count()): 
     self.manager = mp.Manager() 
     self.nc = self.manager.Value('i', 0) 
     self.pids = [] 
     self.processes = processes 

    def async_plotter(self, nc, fig, filename, processes): 
     while nc.value >= processes: 
      time.sleep(0.1) 
     nc.value += 1 
     print "Plotting " + filename 
     fig.savefig(filename) 
     plt.close(fig) 
     nc.value -= 1 

    def save(self, fig, filename): 
     p = mp.Process(target=self.async_plotter, 
         args=(self.nc, fig, filename, self.processes)) 
     p.start() 
     self.pids.append(p) 

    def join(self): 
     for p in self.pids: 
      p.join() 

class FinanceChart(): 
    def __init__(self, async_plotter): 
     self.async_plotter = async_plotter 
     self.bar_width = 1.3 
     self.date_offset = 0.5 
     self.fig = plt.figure(figsize=(50, 20), facecolor='w') 
     self.ax = self.fig.add_subplot(1, 1, 1) 
     self.labels = self.ax.get_xmajorticklabels() 
     setp(self.labels, rotation=0) 
     line_hl = LineCollection(([[(734881,1), (734882,5), (734883,9), (734889,5)]])) 
     line_op = LineCollection(([[(734881,1), (734882,5), (734883,9), (734889,5)]])) 
     line_cl = LineCollection(([[(734881,1), (734882,5), (734883,9), (734889,5)]])) 

     self.lines_hl = self.ax.add_collection(line_hl, autolim=True) 
     self.lines_op = self.ax.add_collection(line_cl, autolim=True) 
     self.lines_cl = self.ax.add_collection(line_op, autolim=True) 

     self.ax.set_title('EOD test plot') 
     self.ax.set_xlabel('Date') 
     self.ax.set_ylabel('Price , $') 

     month = MonthLocator() 
     day = DayLocator() 
     timeFmt = DateFormatter('%Y-%m-%d') 
     self.ax.xaxis.set_major_locator(month) 
     self.ax.xaxis.set_major_formatter(timeFmt) 
     self.ax.xaxis.set_minor_locator(day) 

    def test_plot(self, OHLCV, i): 
     colormap = OHLCV[:,1] < OHLCV[:,4] 
     color = np.zeros(colormap.__len__(), dtype = np.dtype('|S5')) 
     color[:] = 'red' 
     color[np.where(colormap)] = 'green' 
     dates = date2num(OHLCV[:,0]) 
     date_array = np.array(dates) 
     xmin = min(dates) 
     xmax = max(dates) 
     ymin = min(OHLCV[:,1]) 
     ymax = max(OHLCV[:,1]) 

     self.lines_hl.set_segments(zip(zip(dates, OHLCV[:,2]), zip(dates, OHLCV[:,3]))) 
     self.lines_hl.set_color(color) 
     self.lines_hl.set_linewidth(self.bar_width) 
     self.lines_op.set_segments(zip(zip((date_array - self.date_offset).tolist(), OHLCV[:,1]), zip(date_array.tolist(), OHLCV[:,1]))) 
     self.lines_op.set_color(color) 
     self.lines_op.set_linewidth(self.bar_width) 
     self.lines_cl.set_segments(zip(zip((date_array + self.date_offset).tolist(), OHLCV[:,4]), zip(date_array.tolist(), OHLCV[:,4]))) 
     self.lines_cl.set_color(color) 
     self.lines_cl.set_linewidth(self.bar_width) 

     self.ax.set_xlim(xmin,xmax) 
     self.ax.set_ylim(ymin,ymax) 

     self.ax.xaxis.grid(True, 'major') 
     self.ax.grid(True) 
     self.async_plotter.save(self.fig, '%04i.png'%i) 

if __name__=='__main__': 
    print "Starting" 
    data_table = urllib2.urlopen(r"http://ichart.finance.yahoo.com/table.csv?s=IBM&a=00&b=1&c=2012&d=00&e=15&f=2013&g=d&ignore=.csv").readlines()[1:][::-1] 
    parsed_table = [] 
    #Format: Date, Open, High, Low, Close, Volume 
    dtype = (lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(),float, float, float, float, int) 

    for row in data_table: 
     field = row.strip().split(',')[:-1] 
     data_tmp = [i(j) for i,j in zip(dtype, field)] 
     parsed_table.append(data_tmp) 

    parsed_table = np.array(parsed_table) 
    import time 
    bf = time.time() 
    count = 10 

    a = AsyncPlotter() 
    _chart = FinanceChart(a) 

    print "Done with startup tasks" 
    for i in xrange(count): 
     _chart.test_plot(parsed_table, i) 

a.join() 
print('Plot time: %.2f' %(float(time.time() - bf)/float(count)))