【问题标题】:Interactive Stock Chart, step by step animation with keyboard arrows, with Matplolib交互式股票图表,带键盘箭头的分步动画,使用 Matplotlib
【发布时间】:2021-10-27 18:46:12
【问题描述】:

我正在尝试使用 matplotlib 绘制交互式股票图表。它应该像这样工作:

  1. 最初它在图中显示 60 个条形图(从数据框的第一个到第 60 个条形图)
  2. 按键盘上的右箭头后,它显示第 61 个条形图,第一个条形图消失(因此,现在该图显示从数据帧的第二个到第 61 个)。如果我再次按右箭头,则绘图显示第三到第 62,依此类推。这里的想法是在我按向右箭头前进时在图中显示固定数量的条形图。
  3. 按左箭头会后退一步(例如,如果图表在第二个到第 61 个,按左箭头后它会返回第一个到第 60 个)

我在下面编写了代码,但不幸的是,当我按下右箭头时,它只会在绘图中增加一个条形,第一个条形永远不会消失。此外,当我按下左箭头时,什么也没有发生。有人可以帮忙吗?代码:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd


df = pd.read_csv('all_stocks_5yr.csv')
df_apple = df[df['Name'] == 'AAPL'].copy()
df_apple['date'] = pd.to_datetime(df_apple['date'])
df_apple.reset_index(inplace=True)

bars_to_display = 60
step = 0

#Chart Commands

x = np.arange(0,len(df_apple))
fig, (ax, ax2) = plt.subplots(2, figsize=(12,8), gridspec_kw={'height_ratios': [4, 1]}, sharex = True)
val_array = []
for idx, val in df_apple.iterrows():
    val_array.append(val)

# ticks top plot
ax2.set_xticks(x[::3])
#ax2.set_xticklabels(df_apple.date.dt.date[::3])
ax.set_xticks(x, minor=True)
# labels
ax.set_ylabel('USD')
ax2.set_ylabel('Volume')
# grid
ax.xaxis.grid(color='black', linestyle='dashed', which='both', alpha=0.1)
ax2.set_axisbelow(True)
ax2.yaxis.grid(color='black', linestyle='dashed', which='both', alpha=0.1)
# remove spines
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['top'].set_visible(False)
ax2.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
# get max volume + 10%
mx = df_apple['volume'].max()*1.1
# define tick locations - 0 to max in 4 steps
yticks_ax2 = np.arange(0, mx+1, mx/4)
# create labels for ticks. Replace 1.000.000 by 'mi'
yticks_labels_ax2 = ['{:.2f} mi'.format(i/1000000) for i in yticks_ax2]
ax2.yaxis.tick_right() # Move ticks to the left side
# plot y ticks / skip first and last values (0 and max)
plt.yticks(yticks_ax2[1:-1], yticks_labels_ax2[1:-1])
plt.ylim(0,mx)
# title
ax.set_title('Apple Stock Price\n', loc='left', fontsize=20)

#Plot the chart, displaying the bars from 0 to bars_to_display

for i in range(0,bars_to_display):
    color = '#2CA453'
    if val_array[i]['open'] > val_array[i]['close']: color= '#F04730'
    ax.plot([x[i], x[i]], [val_array[i]['low'], val_array[i]['high']], color=color)
    ax.plot([x[i], x[i]-0.1], [val_array[i]['open'], val_array[i]['open']], color=color)
    ax.plot([x[i], x[i]+0.1], [val_array[i]['close'], val_array[i]['close']], color=color)
    ax2.bar(x[i], val_array[i]['volume'] , color='lightgrey')


plt.ion()

def on_keyboard(event):
    global step
    if event.key == 'right':
        step += 1
    elif event.key == 'left':
        step -= 1
        if step <= 0: step=0

    #Plot the chart, displaying the bars from 1: bars_to_display +1; then 2: bars_to_display +2, etc...
        
    for i in range(step,bars_to_display+step):

        color = '#2CA453'
        if val_array[i]['open'] > val_array[i]['close']: color= '#F04730'
        ax.plot([x[i], x[i]], [val_array[i]['low'], val_array[i]['high']], color=color)
        ax.plot([x[i], x[i]-0.1], [val_array[i]['open'], val_array[i]['open']], color=color)
        ax.plot([x[i], x[i]+0.1], [val_array[i]['close'], val_array[i]['close']], color=color)
        ax2.bar(x[i], val_array[i]['volume'] , color='lightgrey')
    

plt.gcf().canvas.mpl_connect('key_press_event', on_keyboard)

plt.show()

obs:我使用的数据框格式如下:

      index       date      open      high       low     close     volume  Name
0      1259 2013-02-08   67.7142   68.4014   66.8928   67.8542  158168416  AAPL
1      1260 2013-02-11   68.0714   69.2771   67.6071   68.5614  129029425  AAPL
2      1261 2013-02-12   68.5014   68.9114   66.8205   66.8428  151829363  AAPL
3      1262 2013-02-13   66.7442   67.6628   66.1742   66.7156  118721995  AAPL
4      1263 2013-02-14   66.3599   67.3771   66.2885   66.6556   88809154  AAPL

【问题讨论】:

    标签: python matplotlib plot data-visualization visualization


    【解决方案1】:

    干得好。
    您只需要添加两件事即可使您的代码正常工作:

    • plt.draw()on_keyboard 函数的末尾:这是更新绘图所必需的
    • ax.cla()ax2.cla()on_keyboard 函数中的 for 循环之前:这是从以前的图中清除轴所必需的

    然而ax.cla()擦除网格,所以我建议你对你的代码进行一些编辑:

    • on_keyboard 函数中移动所有绘图调用(为循环和布局管理绘图),因此用户按下 ? 后,不仅绘图而且布局管理都会更新?。这使您可以避免在 on_keyboard 外部和内部重复 for 循环(和布局管理)

    • 去掉on_keybaord外的for循环作图,没用的重复

    • 在布局管理中添加ax.set_xlimax2.set_xlim以修复x轴限制

    • plt.show() 之前添加对on_keyboard 的调用以绘制绘图

    • 上一个调用需要传递给on_keyboard 一个event 参数:您可以只传递0 并在if 语句中将其捕获到on_keyboard

    也就是说,工作代码:
    (我删除了plt.ion() 并为我工作,你可能需要恢复它)

    import matplotlib.pyplot as plt
    import numpy as np
    import pandas as pd
    
    df = pd.read_csv('all_stocks_5yr.csv')
    df_apple = df[df['Name'] == 'AAPL'].copy()
    df_apple['date'] = pd.to_datetime(df_apple['date'])
    df_apple.reset_index(inplace = True)
    
    bars_to_display = 60
    step = 0
    
    # Chart Commands
    
    x = np.arange(0, len(df_apple))
    fig, (ax, ax2) = plt.subplots(2, figsize = (12, 8), gridspec_kw = {'height_ratios': [4, 1]}, sharex = True)
    val_array = []
    for idx, val in df_apple.iterrows():
        val_array.append(val)
    
    
    def on_keyboard(event):
    
        global step
        if event != 0:
            if event.key == 'right':
                step += 1
            elif event.key == 'left':
                step -= 1
                if step <= 0: step = 0
    
        # Plot the chart, displaying the bars from 1: bars_to_display +1; then 2: bars_to_display +2, etc...
    
        ax.cla()
        ax2.cla()
    
        for i in range(step, bars_to_display + step):
    
            color = '#2CA453'
            if val_array[i]['open'] > val_array[i]['close']: color = '#F04730'
            ax.plot([x[i], x[i]], [val_array[i]['low'], val_array[i]['high']], color = color)
            ax.plot([x[i], x[i] - 0.1], [val_array[i]['open'], val_array[i]['open']], color = color)
            ax.plot([x[i], x[i] + 0.1], [val_array[i]['close'], val_array[i]['close']], color = color)
            ax2.bar(x[i], val_array[i]['volume'], color = 'lightgrey')
    
        # ticks top plot
        ax2.set_xticks(x[::3])
        # ax2.set_xticklabels(df_apple.date.dt.date[::3])
        ax.set_xticks(x, minor = True)
        # labels
        ax.set_ylabel('USD')
        ax2.set_ylabel('Volume')
        # grid
        ax.xaxis.grid(color = 'black', linestyle = 'dashed', which = 'both', alpha = 0.1)
        ax2.set_axisbelow(True)
        ax2.yaxis.grid(color = 'black', linestyle = 'dashed', which = 'both', alpha = 0.1)
        # remove spines
        ax.spines['right'].set_visible(False)
        ax.spines['left'].set_visible(False)
        ax.spines['top'].set_visible(False)
        ax2.spines['right'].set_visible(False)
        ax2.spines['left'].set_visible(False)
        # get max volume + 10%
        mx = df_apple['volume'].max()*1.1
        # define tick locations - 0 to max in 4 steps
        yticks_ax2 = np.arange(0, mx + 1, mx/4)
        # create labels for ticks. Replace 1.000.000 by 'mi'
        yticks_labels_ax2 = ['{:.2f} mi'.format(i/1000000) for i in yticks_ax2]
        ax2.yaxis.tick_right()  # Move ticks to the left side
        # plot y ticks / skip first and last values (0 and max)
        plt.yticks(yticks_ax2[1:-1], yticks_labels_ax2[1:-1])
        plt.ylim(0, mx)
        # title
        ax.set_title('Apple Stock Price\n', loc = 'left', fontsize = 20)
    
        ax.set_xlim(x[step] - 1, x[bars_to_display + step] + 1)
        ax2.set_xlim(x[step] - 1, x[bars_to_display + step] + 1)
    
        plt.draw()
    
    
    plt.gcf().canvas.mpl_connect('key_press_event', on_keyboard)
    
    on_keyboard(0)
    
    plt.show()
    

    20 次 ? 射击后:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-03
      • 2018-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多