Python matplotlib为烛台绘制动画

时间:2014-02-01 20:47:30

标签: python animation matplotlib

我一直试图找到一种方法来使用烛台数据的animate函数。在大多数示例中,我看到类需要一个生成器函数来返回pyplot对象,但是如何使用烛台执行此操作?

这是我制作的动画示例,每次调用时都会更新绘图。我想改变它以使用动画,但我一直无法弄清楚如何做到这一点。

import time
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.dates import DateFormatter, epoch2num, num2epoch, MinuteLocator
from matplotlib.finance import candlestick

class Chart3(object):
    def __init__(self,testData, maxt=10):
        self.maxt=maxt
        self.testData=testData
        self.result=testData[:self.maxt]
        self.dataCount=0

        self.tdata=[r[0] for r in self.result]
        self.sdata=[r[4] for r in self.result]
        self.mdata=[r[3] for r in self.result]

        # plot the data
        xfmt = DateFormatter('%Y-%m-%d %H:%M')
        self.fig, self.ax = plt.subplots()
        self.fig.subplots_adjust(bottom=0.2)
        self.ax.xaxis.set_major_formatter(xfmt)
        self.plot()

    def plot(self):
        if len(self.tdata) > self.maxt: # roll the arrays
            self.tdata = self.tdata[-self.maxt:]
            self.sdata = self.sdata[-self.maxt:]
            self.mdata = self.mdata[-self.maxt:]
            self.result = self.result[-self.maxt:]

        self.lineMin = Line2D(self.tdata, self.sdata, color='r')
        self.ax.add_line(self.lineMin)
        self.lineMax = Line2D(self.tdata, self.mdata, color='g')
        self.ax.add_line(self.lineMax)

        candlestick(self.ax, self.result, width=60 / 86400.0,  colorup='g', colordown='r')
        self.ax.xaxis_date()
        if len(self.tdata) > 1:
            self.ax.set_xlim(self.tdata[0], self.tdata[-1])
        self.ax.set_ylim(min(self.sdata) * 0.99, max(self.mdata) * 1.01)
        self.ax.figure.canvas.draw()

        plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='center')
        plt.show(block=False)

    def updatePrices(self):
        '''
        adds a data point from testData to result list for plotting
        @return:
        '''
        self.dataCount+=1
        results=self.testData[self.maxt+self.dataCount] # add another point of data
        t=(results[0])
        if self.tdata[-1]!=t:
            trade=results
            self.result.append([t, trade[1], trade[2], trade[3], trade[4],
                           trade[5], trade[6]])
            self.tdata.append(self.result[-1][0])
            self.sdata.append(self.result[-1][4])
            self.mdata.append(self.result[-1][3])

        self.plot()

    def animate(self):
        ani = animation.FuncAnimation(self.fig, frames=self.updatePrices, interval=1000, blit=True)
        plt.show()

if __name__ == "__main__":

    testData=[[735265.79166666663, 21.901, 21.901, 21.901, 21.901, 21.901, 0],
[735265.79236111115, 21.901, 21.901, 21.901, 21.901, 21.901, 0],
[735265.79305555555, 21.901, 21.901, 21.901, 21.901, 21.901, 0],
[735265.79374999995, 21.9, 21.901, 21.901, 21.9, 21.9005, 11.65],
[735265.79444444447, 21.901, 21.939, 21.939, 21.901, 21.91525, 23.23606],
[735265.79513888888, 21.94, 21.95, 21.9703, 21.94, 21.953781250000002, 172.91374199999998],
[735265.79583333328, 21.96, 21.99, 21.99, 21.96, 21.973333333333336, 142.974981],
[735265.7965277778, 21.995, 21.995, 21.997, 21.995, 21.995533333333338, 36.541180000000004],
[735265.7972222222, 21.9703, 21.995, 22.0, 21.9703, 21.993162500000004, 18.305711],
[735265.79791666672, 21.9999, 21.86, 22.0, 21.86, 21.93492, 103.2468273],
[735265.79861111112, 21.9045, 21.9045, 21.9045, 21.9045, 21.9045, 2.43879],
[735265.79930555553, 21.929, 21.861, 21.99, 21.86, 21.92566666666666, 2.838343],
[735265.80000000005, 21.9241, 21.899, 21.9241, 21.899, 21.907366666666665, 10.0],
[735265.80069444445, 21.861, 21.86, 21.861, 21.86, 21.860888888888887, 111.367172],
[735265.80138888885, 21.86, 21.861, 21.861, 21.86, 21.8604, 78.36582],
[735265.80208333337, 21.861, 21.862, 21.862, 21.859, 21.860483333333335, 112.842532],
[735265.80277777778, 21.862, 21.863, 21.88, 21.862, 21.8694, 83.64361899999999],
[735265.80347222218, 21.88, 21.88, 21.88, 21.88, 21.88, 7.46027],
[735265.8041666667, 21.88, 21.9256, 21.9256, 21.88, 21.9104, 7.06897],
[735265.8048611111, 21.9256, 21.9256, 21.9256, 21.9256, 21.9256, 0.339032],
[735265.8055555555, 21.9256, 21.9256, 21.9256, 21.9256, 21.9256, 2.024438],
[735265.80625000002, 21.88, 21.88, 21.881, 21.88, 21.880249999999997, 25.00003],
[735265.80694444443, 21.92, 21.92, 21.92, 21.92, 21.92, 0],
[735265.80763888895, 21.92, 21.92, 21.92, 21.92, 21.92, 0],
[735265.80833333335, 21.91, 21.92, 21.92, 21.91, 21.915, 80.0],
[735265.80902777775, 21.881, 21.92, 21.92, 21.881, 21.907, 43.913890200000004],
[735265.80972222227, 21.914, 22.0, 22.0, 21.914, 21.973115625, 368.000066],
[735265.81041666667, 21.93, 21.93, 21.93, 21.93, 21.93, 0],
[735265.81111111108, 21.9, 21.93, 21.93, 21.9, 21.9225, 15.475088999999999],
[735265.8118055556, 21.93, 22.0, 22.0, 21.91, 21.97401, 56.620048589999996]
]

    chart=Chart3(testData)
    while True:
        time.sleep(10)
        chart.updatePrices()

现在,此示例从测试数据中绘制了10个点,并且每次调用updatePrice时,它会一步一步地移动数据,直到数据用完为止。我更愿意设置aninamation并调用updatePrice并消除循环updatePrice的需要。我试图创建的动画方法不正确,虽然我可以使用:

self.lineMin.set_data(self.tdata, self.sdata)
self.lineMax.set_data(self.tdata, self.mdata)

要为FuncAnimate生成数据,我不知道如何传回新的蜡烛数据。如何修改此示例以使用动画?

1 个答案:

答案 0 :(得分:1)

user6972,请参阅附带的代码,以获得问题的完整解决方案。这是在Windows 7上使用WinPython x64 2.7.6.2测试的。我通过一些重组,删除未使用/冗余元素,注释和PEP8合规性来更新了您的代码。请根据自己的需要进行重组。

以下是有关更新的一些注意事项:

  1. 我相信您遇到的主要问题是animation.FuncAnimation(func)需要一个具有迭代器的函数来生成动画的新帧。通过这样,您可以有效地摆脱Class3.dataCount实例变量并让动画处理滚动数据的业务。

  2. 我们需要明确地告诉动画运行多长时间,以便它不会迭代数据数组导致IndexError: list out of range,或者将update_plot()函数包装在try ... except中}子句。两者都可以工作,但由于我不知道你的程序的最终目标,我为你提供了两种选项的语义。我想如果你有实时数据,你可能不知道动画的数据数组的长度,所以你可能需要后面的解决方案,虽然我个人觉得前者更优雅。

  3. 感谢有趣的挑战!这是我应该做的一个很好的分心。


    from matplotlib.lines import Line2D
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    from matplotlib.dates import DateFormatter
    from matplotlib.finance import candlestick
    
    
    class Chart3(object):
        def __init__(self, data, maxt=10):
            self.maxt = maxt
            self.data = data
            self.result = data[:self.maxt]
    
            # Parse the data columns
            self.tdata = [r[0] for r in self.result]
            self.sdata = [r[4] for r in self.result]
            self.mdata = [r[3] for r in self.result]
    
            # Initialize plot frame
            xfmt = DateFormatter('%Y-%m-%d %H:%M')
            self.fig, self.ax = plt.subplots()
            self.fig.subplots_adjust(bottom=0.2)
            self.ax.xaxis.set_major_formatter(xfmt)
            self.ax.xaxis_date()
            plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='center')
            self.animate()
    
        def plot(self):
            if len(self.tdata) > self.maxt:  # roll the arrays
                self.tdata = self.tdata[-self.maxt:]
                self.sdata = self.sdata[-self.maxt:]
                self.mdata = self.mdata[-self.maxt:]
                self.result = self.result[-self.maxt:]
    
            # Plot the next set of line data
            line_min = Line2D(self.tdata, self.sdata, color='r')
            self.ax.add_line(line_min)
            line_max = Line2D(self.tdata, self.mdata, color='g')
            self.ax.add_line(line_max)
    
            # Plot the next set of candlestick data
            candlestick(self.ax, self.result, width=60 / 86400.0,  colorup='g', colordown='r')
    
            # Update the x-axis time date and limits
            if len(self.tdata) > 1:
                self.ax.set_xlim(self.tdata[0], self.tdata[-1])
    
            # Update the y-axis limits
            self.ax.set_ylim(min(self.sdata) * 0.99, max(self.mdata) * 1.01)
    
        def update_prices(self, cnt):
            """
            adds a data point from data to result list for plotting
            @return:
            """
            results = self.data[self.maxt + cnt]  # add another point of data
            t = (results[0])
            if self.tdata[-1] != t:
                trade = results
                self.result.append([t, trade[1], trade[2], trade[3], trade[4], trade[5], trade[6]])
                self.tdata.append(self.result[-1][0])
                self.sdata.append(self.result[-1][4])
                self.mdata.append(self.result[-1][3])
    
        def update_plot(self, i):
            try:
                self.update_prices(cnt=i)
                self.plot()
            except:
                pass
    
        def animate(self):
            # With try ... except in update_plot()
            # anim = animation.FuncAnimation(fig=self.fig, func=self.update_plot, interval=1000)
    
            # Without try ... except in update_plot()
            anim = animation.FuncAnimation(fig=self.fig, func=self.update_plot, interval=1000,
                                           frames=len(self.data)-self.maxt, repeat=False)
            plt.show()
    
    if __name__ == "__main__":
        testData = [
            [735265.79166666663, 21.901, 21.901, 21.901, 21.901, 21.901, 0],
            [735265.79305555555, 21.901, 21.901, 21.901, 21.901, 21.901, 0],
            [735265.79236111115, 21.901, 21.901, 21.901, 21.901, 21.901, 0],
            [735265.79374999995, 21.9, 21.901, 21.901, 21.9, 21.9005, 11.65],
            [735265.79444444447, 21.901, 21.939, 21.939, 21.901, 21.91525, 23.23606],
            [735265.79513888888, 21.94, 21.95, 21.9703, 21.94, 21.953781250000002, 172.91374199999998],
            [735265.79583333328, 21.96, 21.99, 21.99, 21.96, 21.973333333333336, 142.974981],
            [735265.7965277778, 21.995, 21.995, 21.997, 21.995, 21.995533333333338, 36.541180000000004],
            [735265.7972222222, 21.9703, 21.995, 22.0, 21.9703, 21.993162500000004, 18.305711],
            [735265.79791666672, 21.9999, 21.86, 22.0, 21.86, 21.93492, 103.2468273],
            [735265.79861111112, 21.9045, 21.9045, 21.9045, 21.9045, 21.9045, 2.43879],
            [735265.79930555553, 21.929, 21.861, 21.99, 21.86, 21.92566666666666, 2.838343],
            [735265.80000000005, 21.9241, 21.899, 21.9241, 21.899, 21.907366666666665, 10.0],
            [735265.80069444445, 21.861, 21.86, 21.861, 21.86, 21.860888888888887, 111.367172],
            [735265.80138888885, 21.86, 21.861, 21.861, 21.86, 21.8604, 78.36582],
            [735265.80208333337, 21.861, 21.862, 21.862, 21.859, 21.860483333333335, 112.842532],
            [735265.80277777778, 21.862, 21.863, 21.88, 21.862, 21.8694, 83.64361899999999],
            [735265.80347222218, 21.88, 21.88, 21.88, 21.88, 21.88, 7.46027],
            [735265.8041666667, 21.88, 21.9256, 21.9256, 21.88, 21.9104, 7.06897],
            [735265.8048611111, 21.9256, 21.9256, 21.9256, 21.9256, 21.9256, 0.339032],
            [735265.8055555555, 21.9256, 21.9256, 21.9256, 21.9256, 21.9256, 2.024438],
            [735265.80625000002, 21.88, 21.88, 21.881, 21.88, 21.880249999999997, 25.00003],
            [735265.80694444443, 21.92, 21.92, 21.92, 21.92, 21.92, 0],
            [735265.80763888895, 21.92, 21.92, 21.92, 21.92, 21.92, 0],
            [735265.80833333335, 21.91, 21.92, 21.92, 21.91, 21.915, 80.0],
            [735265.80902777775, 21.881, 21.92, 21.92, 21.881, 21.907, 43.913890200000004],
            [735265.80972222227, 21.914, 22.0, 22.0, 21.914, 21.973115625, 368.000066],
            [735265.81041666667, 21.93, 21.93, 21.93, 21.93, 21.93, 0],
            [735265.81111111108, 21.9, 21.93, 21.93, 21.9, 21.9225, 15.475088999999999],
            [735265.8118055556, 21.93, 22.0, 22.0, 21.91, 21.97401, 56.620048589999996]
        ]
    
        chart = Chart3(data=testData)