2010-02-09 5 views
2

Google Finance 조회 차트를 만들기 위해 Matplotlib의 애니메이션 기능을 시작했습니다.Matplotlib의 Google Finance 차트와 유사한 애니메이션을 만드시겠습니까?

내가 프로젝트 웹 사이트 (Draggable rectangle exercise, api example code: date_demo.py)에서 찾은 두 가지 예를 결합하고 하단에 나열된 코드를 제안하기 위해 약간 수정했습니다.

너무 좋지는 않지만 맨 아래 차트 (슬레이브) 선택 항목이 이동하고 하단 선택 항목이 해제 될 때뿐만 아니라 상위 차트 (마스터) 업데이트가 동적으로 업데이트되기를 바랍니다. 어떻게해야합니까? on_motion 메서드로 self.rect.figure.canvas.draw() 비트를 이동하려했지만 아래쪽 선택이 제대로 렌더링되지 않으므로 blit 물건을 방해하는 것 같습니다.

따라서 상위 차트가 다시 그려지는 동안 하단 차트, 즉 blit-ing 비트에 대한 지능형 애니메이션을 수행하는 것이 해결책이라고 가정합니다. 문제는 내가 다시 그릴 수있는 유일한 방법은 전체 캔버스를 다시 그리는 것입니다. 그러면 아래쪽 차트가 포함됩니다. 나는 matplotlib.axes에 대한 draw() 방법을 찾았지만 제대로 작동하지 않습니다. 위에서 말했듯이, 선호하는 것은 맨 위의 차트를 다시 그리는 것입니다. 맨 아래의 차트는 영리한 방법으로 blit-ed입니다. 누구든지이 작업을 수행하는 방법을 알고 있습니까?

여기 내 코드가 있습니다. 코드를 변명 해주세요, 조금 어수선해요.

import datetime 
import numpy as np 
import sys 
import time 
import wx 
import matplotlib 
from matplotlib.figure import Figure 
import matplotlib.dates as mdates 
import matplotlib.ticker as mtickers 
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas 
import matplotlib.patches as mpatches 

class DraggableRectangle: 
    lock = None 
    def __init__(self, rect, master, xMin, xMax):  
     self.rect = rect   
     self.press = None 
     self.background = None 
     self.xMax = xMax 
     self.xMin = xMin 
     self.master = master 
    def connect(self):  
     self.cidpress = self.rect.figure.canvas.mpl_connect('button_press_event', self.on_press) 
     self.cidrelease = self.rect.figure.canvas.mpl_connect('button_release_event', self.on_release) 
     self.cidmotion = self.rect.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) 
    def on_press(self, event):  
     if event.inaxes != self.rect.axes: return 
     if DraggableRectangle.lock is not None: return 
     contains, attrd = self.rect.contains(event) 
     if not contains: return  
     x0, y0 = self.rect.xy 
     self.press = x0, y0, event.xdata, event.ydata 
     DraggableRectangle.lock = self 
     canvas = self.rect.figure.canvas 
     axes = self.rect.axes 
     self.rect.set_animated(True) 
     canvas.draw() 
     self.background = canvas.copy_from_bbox(self.rect.axes.bbox) 
     axes.draw_artist(self.rect) 
     canvas.blit(axes.bbox) 
    def on_motion(self, event): 
     if DraggableRectangle.lock is not self: return 
     if event.inaxes != self.rect.axes: return 
     x0, y0, xpress, ypress = self.press 
     dx = event.xdata - xpress 
     dy = 0 
     if x0+dx > self.xMax: 
      self.rect.set_x(self.xMax) 
     elif x0+dx < self.xMin: 
      self.rect.set_x(self.xMin) 
     else: 
      self.rect.set_x(x0+dx) 
     self.rect.set_y(y0+dy) 
     canvas = self.rect.figure.canvas 
     axes = self.rect.axes 
     canvas.restore_region(self.background) 
     self.master.set_xlim(self.rect.get_x(), self.rect.get_x() + 92) 
     axes.draw_artist(self.rect) 
     canvas.blit(axes.bbox) 
    def on_release(self, event):   
     if DraggableRectangle.lock is not self: return 
     self.press = None 
     DraggableRectangle.lock = None 
     self.rect.set_animated(False) 
     self.background = None 
     self.rect.figure.canvas.draw() 
    def disconnect(self): 
     self.rect.figure.canvas.mpl_disconnect(self.cidpress) 
     self.rect.figure.canvas.mpl_disconnect(self.cidrelease) 
     self.rect.figure.canvas.mpl_disconnect(self.cidmotion) 

class MplCanvasFrame(wx.Frame): 
    def __init__(self): 
     wx.Frame.__init__(self, None, wx.ID_ANY, title='First Chart', size=(800, 700)) 
     datafile = matplotlib.get_example_data('goog.npy') 
     r = np.load(datafile).view(np.recarray) 
     datesFloat = matplotlib.dates.date2num(r.date) 
     figure = Figure() 
     xMaxDatetime = r.date[len(r.date)-1] 
     xMinDatetime = r.date[0] 
     xMaxFloat = datesFloat[len(datesFloat)-1] 
     xMinFloat = datesFloat[0] 
     yMin = min(r.adj_close) // 5 * 5 
     yMax = (1 + max(r.adj_close) // 5) * 5  
     master = figure.add_subplot(211) 
     master.plot(datesFloat, r.adj_close) 
     master.xaxis.set_minor_locator(mdates.MonthLocator()) 
     master.xaxis.set_major_locator(mdates.MonthLocator(bymonth=(1,4,7,10))) 
     master.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y')) 
     master.set_xlim(datesFloat[120], datesFloat[120]+92) 
     master.yaxis.set_minor_locator(mtickers.MultipleLocator(50)) 
     master.yaxis.set_major_locator(mtickers.MultipleLocator(100)) 
     master.set_ylim(yMin, yMax) 
     master.set_position([0.05,0.20,0.92,0.75]) 
     master.xaxis.grid(True, which='minor') 
     master.yaxis.grid(True, which='minor') 
     slave = figure.add_subplot(212, yticks=[]) 
     slave.plot(datesFloat, r.adj_close) 
     slave.xaxis.set_minor_locator(mdates.MonthLocator()) 
     slave.xaxis.set_major_locator(mdates.YearLocator()) 
     slave.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y')) 
     slave.set_xlim(xMinDatetime, xMaxDatetime) 
     slave.set_ylim(yMin, yMax) 
     slave.set_position([0.05,0.05,0.92,0.10]) 
     rectangle = mpatches.Rectangle((datesFloat[120], yMin), 92, yMax-yMin, facecolor='yellow', alpha = 0.4)  
     slave.add_patch(rectangle) 
     canvas = FigureCanvas(self, -1, figure) 
     drag = DraggableRectangle(rectangle, master, xMinFloat, xMaxFloat - 92) 
     drag.connect() 

app = wx.PySimpleApp() 
frame = MplCanvasFrame() 
frame.Show(True) 
app.MainLoop() 
+0

내가 대답하지만 멋진 플롯이 없습니다! – Mark

+0

그렇다면 Matplotlib에서 전체 애니메이션 작품이 놀랍도록 잘 작동합니다. 이 마지막 부분을 알아낼 수만 있다면 더 좋아할 것입니다.) – c00kiemonster

답변

1

나는 오늘 아침에 작업 할 기회가있었습니다 (지난 3 일 동안 2 번째 블리자드가 있습니다). 맞습니다. on_motion에서 전체 그림을 다시 그리면 노란색 사각형의 애니메이션이 엉망입니다. 핵심은 마스터 하위 플롯의 선을 블 리팅하는 것입니다.

이 코드를 사용해보십시오 :

import datetime 
import numpy as np 
import sys 
import time 
import wx 
import matplotlib 
from matplotlib.figure import Figure 
import matplotlib.dates as mdates 
import matplotlib.ticker as mtickers 
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas 
import matplotlib.patches as mpatches 

class DraggableRectangle: 
    lock = None 
    def __init__(self, rect, master, xMin, xMax):  
     self.rect = rect   
     self.press = None 
     self.slave_background = None 
     self.master_background = None 
     self.xMax = xMax 
     self.xMin = xMin 
     self.master = master 
     self.master_line, = self.master.get_lines() 

    def connect(self):  
     self.cidpress = self.rect.figure.canvas.mpl_connect('button_press_event', self.on_press) 
     self.cidrelease = self.rect.figure.canvas.mpl_connect('button_release_event', self.on_release) 
     self.cidmotion = self.rect.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) 

    def on_press(self, event):  
     if event.inaxes != self.rect.axes: return 
     if DraggableRectangle.lock is not None: return 
     contains, attrd = self.rect.contains(event) 
     if not contains: return  
     x0, y0 = self.rect.xy 
     self.press = x0, y0, event.xdata, event.ydata 
     DraggableRectangle.lock = self 
     canvas = self.rect.figure.canvas 
     axes = self.rect.axes 

     # set up our animated elements 
     self.rect.set_animated(True) 
     self.master_line.set_animated(True) 
     self.master.xaxis.set_visible(False) #we are not animating this 

     canvas.draw() 

     # backgrounds for restoring on animation 
     self.slave_background = canvas.copy_from_bbox(self.rect.axes.bbox) 
     self.master_background = canvas.copy_from_bbox(self.master.axes.bbox) 

     axes.draw_artist(self.rect) 
     canvas.blit(axes.bbox) 

    def on_motion(self, event): 
     if DraggableRectangle.lock is not self: return 
     if event.inaxes != self.rect.axes: return 
     x0, y0, xpress, ypress = self.press 
     dx = event.xdata - xpress 
     dy = 0 
     if x0+dx > self.xMax: 
      self.rect.set_x(self.xMax) 
     elif x0+dx < self.xMin: 
      self.rect.set_x(self.xMin) 
     else: 
      self.rect.set_x(x0+dx) 
     self.rect.set_y(y0+dy) 
     canvas = self.rect.figure.canvas 
     axes = self.rect.axes 

     # restore backgrounds 
     canvas.restore_region(self.slave_background) 
     canvas.restore_region(self.master_background) 

     # set our limits for animated line 
     self.master.set_xlim(self.rect.get_x(), self.rect.get_x() + 92) 

     # draw yellow box 
     axes.draw_artist(self.rect) 
     canvas.blit(axes.bbox) 

     #draw line 
     self.master.axes.draw_artist(self.master_line) 
     canvas.blit(self.master.axes.bbox) 

    def on_release(self, event):   
     if DraggableRectangle.lock is not self: return 
     self.press = None 
     DraggableRectangle.lock = None 

     # unanimate rect and lines 
     self.rect.set_animated(False) 
     self.master_line.set_animated(False) 

     self.slave_background = None 
     self.master_background = None 

     # redraw whole figure 
     self.master.xaxis.set_visible(True) 
     self.rect.figure.canvas.draw() 

    def disconnect(self): 
     self.rect.figure.canvas.mpl_disconnect(self.cidpress) 
     self.rect.figure.canvas.mpl_disconnect(self.cidrelease) 
     self.rect.figure.canvas.mpl_disconnect(self.cidmotion) 

class MplCanvasFrame(wx.Frame): 
    def __init__(self): 
     wx.Frame.__init__(self, None, wx.ID_ANY, title='First Chart', size=(800, 700)) 
     datafile = matplotlib.get_example_data('goog.npy') 
     r = np.load(datafile).view(np.recarray) 
     datesFloat = matplotlib.dates.date2num(r.date) 
     figure = Figure() 
     xMaxDatetime = r.date[len(r.date)-1] 
     xMinDatetime = r.date[0] 
     xMaxFloat = datesFloat[len(datesFloat)-1] 
     xMinFloat = datesFloat[0] 
     yMin = min(r.adj_close) // 5 * 5 
     yMax = (1 + max(r.adj_close) // 5) * 5  
     master = figure.add_subplot(211) 
     master.plot(datesFloat, r.adj_close) 
     master.xaxis.set_minor_locator(mdates.MonthLocator()) 
     master.xaxis.set_major_locator(mdates.MonthLocator(bymonth=(1,4,7,10))) 
     master.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y')) 
     master.set_xlim(datesFloat[120], datesFloat[120]+92) 
     master.yaxis.set_minor_locator(mtickers.MultipleLocator(50)) 
     master.yaxis.set_major_locator(mtickers.MultipleLocator(100)) 
     master.set_ylim(yMin, yMax) 
     master.set_position([0.05,0.20,0.92,0.75]) 
     master.xaxis.grid(True, which='minor') 
     master.yaxis.grid(True, which='minor') 
     slave = figure.add_subplot(212, yticks=[]) 
     slave.plot(datesFloat, r.adj_close) 
     slave.xaxis.set_minor_locator(mdates.MonthLocator()) 
     slave.xaxis.set_major_locator(mdates.YearLocator()) 
     slave.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y')) 
     slave.set_xlim(xMinDatetime, xMaxDatetime) 
     slave.set_ylim(yMin, yMax) 
     slave.set_position([0.05,0.05,0.92,0.10]) 
     rectangle = mpatches.Rectangle((datesFloat[120], yMin), 92, yMax-yMin, facecolor='yellow', alpha = 0.4)  
     slave.add_patch(rectangle) 
     canvas = FigureCanvas(self, -1, figure) 
     drag = DraggableRectangle(rectangle, master, xMinFloat, xMaxFloat - 92) 
     drag.connect() 

app = wx.PySimpleApp() 
frame = MplCanvasFrame() 
frame.Show(True) 
app.MainLoop() 
+0

흥미 롭습니다. 나는 이것에 대해 나중에 나중에 바라 볼 것이다. 나는 master.get_lines() 메소드로 주위를 고민해 보았습니다. 그래도 제대로 된 것 같아. – c00kiemonster

+0

나는 xaxis를 blit하여 그리드 선을 애니메이션으로 만들었습니다. xticklabels에 애니메이션을 적용 할 수 있습니까? 나는 get_majorticklables() 메소드를 사용하여 그것들을 얻으려고했지만 꽤 잘 작동하지 않았다 ... – c00kiemonster