如何使用固定的 pandas 数据框进行动态matplotlib绘图? [英] How to do dynamic matplotlib plotting with a fixed pandas dataframe?

查看:47
本文介绍了如何使用固定的 pandas 数据框进行动态matplotlib绘图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为benchmark_returnsstrategy_returns的数据框.两者具有相同的时间跨度.我想找到一种以漂亮的动画样式绘制数据点的方法,以便它显示逐渐加载的所有点.我知道有一个matplotlib.animation.FuncAnimation(),但是它通常仅用于csv文件等的实时更新,但就我而言,我知道我要使用的所有数据.

I have a dataframe called benchmark_returns and strategy_returns. Both have the same timespan. I want to find a way to plot the datapoints in a nice animation style so that it shows all the points loading in gradually. I am aware that there is a matplotlib.animation.FuncAnimation(), however this typically is only used for a real-time updating of csv files etc but in my case I know all the data I want to use.

我也尝试过使用粗糙的plt.pause(0.01)方法,但是随着绘制点的数量,这种方法大大降低了速度.

I have also tried using the crude plt.pause(0.01) method, however this drastically slows down as the number of points get plotted.

到目前为止,这是我的代码

Here is my code so far

x = benchmark_returns.index
y = benchmark_returns['Crypto 30'] 
y2 = benchmark_returns['Dow Jones 30']
y3 = benchmark_returns['NASDAQ'] 
y4 = benchmark_returns['S&P 500']


fig, ax = plt.subplots()
line, = ax.plot(x, y, color='k')
line2, = ax.plot(x, y2, color = 'b')
line3, = ax.plot(x, y3, color = 'r')
line4, = ax.plot(x, y4, color = 'g')

def update(num, x, y, y2, y3, y4, line): 
    line.set_data(x[:num], y[:num])
    line2.set_data(x[:num], y2[:num])
    line3.set_data(x[:num], y3[:num])
    line4.set_data(x[:num], y4[:num])

    return line, line2, line3, line4,

ani = animation.FuncAnimation(fig, update, fargs=[x, y, y2, y3, y4, line], 
                              interval = 1, blit = True)
plt.show()

推荐答案

您可以尝试 matplotlib.animation.ArtistAnimation .它的操作类似于FuncAnimation,因为您可以指定帧间隔,循环行为等,但是所有绘制都在动画步骤之前立即完成.这是一个示例

You could try matplotlib.animation.ArtistAnimation. It operates similar to FuncAnimation in that you can specify the frame interval, looping behavior, etc, but all the plotting is done at once, before the animation step. Here is an example

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib.animation import ArtistAnimation

n = 150
x = np.linspace(0, np.pi*4, n)
df = pd.DataFrame({'cos(x)' : np.cos(x), 
                   'sin(x)' : np.sin(x),
                   'tan(x)' : np.tan(x),
                   'sin(cos(x))' : np.sin(np.cos(x))})

fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(10,10))
lines = []
artists = [[]]
for ax, col in zip(axs.flatten(), df.columns.values):
    lines.append(ax.plot(df[col])[0])
    artists.append(lines.copy())

anim = ArtistAnimation(fig, artists, interval=500, repeat_delay=1000)

这里的缺点是每个艺术家都可以绘制,也可以不绘制,即,如果不进行剪裁,就不能只绘制Line2D对象的一部分.如果这与您的用例不兼容,那么您可以尝试将FuncAnimationblit=True结合使用,并对每次要绘制的数据进行分块,以及使用set_data(),而不是在每次迭代时都进行清除和重绘.一个使用上面相同数据的示例:

The drawback here is that each artist is either drawn or not, i.e. you can't draw only part of a Line2D object without doing clipping. If this is not compatible with your use case then you can try using FuncAnimation with blit=True and chunking the data to be plotted each time as well as using set_data() instead of clearing and redrawing on every iteration. An example of this using the same data from above:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib.animation import FuncAnimation

n = 500
nf = 100
x = np.linspace(0, np.pi*4, n)
df = pd.DataFrame({'cos(x)' : np.cos(x), 
                   'sin(x)' : np.sin(x),
                   'tan(x)' : np.tan(x),
                   'sin(cos(x))' : np.sin(np.cos(x))})

fig, axs = plt.subplots(2, 2, figsize=(5,5), dpi=50)
lines = []
for ax, col in zip(axs.flatten(), df.columns):
    lines.append(ax.plot([], lw=0.5)[0])
    ax.set_xlim(x[0] - x[-1]*0.05, x[-1]*1.05)
    ax.set_ylim([min(df[col].values)*1.05, max(df[col].values)*1.05])
    ax.tick_params(labelbottom=False, bottom=False, left=False, labelleft=False)
plt.subplots_adjust(hspace=0, wspace=0, left=0.02, right=0.98, bottom=0.02, top=0.98)
plt.margins(1, 1)
c = int(n / nf)
def animate(i):
    if (i != nf - 1):
        for line, col in zip(lines, df.columns):
            line.set_data(x[:(i+1)*c], df[col].values[:(i+1)*c])
    else:
        for line, col in zip(lines, df.columns):
            line.set_data(x, df[col].values)        
    return lines

anim = FuncAnimation(fig, animate, interval=2000/nf, frames=nf, blit=True)

为回应评论,这是使用问题中的更新代码实现分块方案的方法:

In response to the comments, here is the implementation of a chunking scheme using the updated code in the question:

x = benchmark_returns.index
y = benchmark_returns['Crypto 30'] 
y2 = benchmark_returns['Dow Jones 30']
y3 = benchmark_returns['NASDAQ'] 
y4 = benchmark_returns['S&P 500']

line, = ax.plot(x, y, color='k')
line2, = ax.plot(x, y2, color = 'b')
line3, = ax.plot(x, y3, color = 'r')
line4, = ax.plot(x, y4, color = 'g')

n = len(x)  # Total number of rows
c = 50      # Chunk size
def update(num):
    end = num * c if num * c < n else n - 1
    line.set_data(x[:end], y[:end])
    line2.set_data(x[:end], y2[:end])
    line3.set_data(x[:end], y3[:end])
    line4.set_data(x[:end], y4[:end])

    return line, line2, line3, line4,

ani = animation.FuncAnimation(fig, update, interval = c, blit = True)
plt.show()

或更简洁

cols = benchmark_returns.columns.values
# or, for only a subset of the columns
# cols = ['Crypto 30', 'Dow Jones 30', 'NASDAQ', 'S&P 500']
colors = ['k', 'b', 'r', 'g']
lines = []
for c, col in zip(cols, colors):
    lines.append(ax.plot(benchmark_returns.index, benchmark_returns[col].values, c=c)[0])

n = len(benchmark_returns.index)
c = 50  # Chunk size
def update(num):
    end = num * c if num * c < n else n - 1
    for line, col in zip(lines, cols):
        line.set_data(benchmark_returns.index, benchmark_returns[col].values[:end])

    return lines

anim = animation.FuncAnimation(fig, update, interval = c, blit=True)
plt.show()

,如果您需要它在一段时间后停止更新,只需在FuncAnimation()中设置frames参数和repeat=False.

and if you need it to stop updating after a certain time simply set the frames argument and repeat=False in FuncAnimation().

这篇关于如何使用固定的 pandas 数据框进行动态matplotlib绘图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆