交互式股票图表,带键盘箭头的逐步动画,使用 Matplotlib
Interactive Stock Chart, step by step animation with keyboard arrows, with Matplolib
我正在尝试使用 matplotlib 绘制交互式股票图表。它应该像这样工作:
- 最初它在图中显示 60 个柱(从数据帧的第一个柱到第 60 个柱)
- 在键盘上按向右箭头后,它显示第 61 个柱,第一个柱消失(因此,现在绘图显示数据框的第二个到第 61 个)。如果我再次按向右箭头,绘图会显示第三到第 62 个,依此类推。这里的想法是在我按向右箭头前进的日子里,在图中显示固定数量的条。
- 按向左箭头后退一步(例如,如果图表在第 2 到第 61 位,按向左箭头后将返回到第 1 到第 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
干得好。
您只需添加两件事即可使您的代码正常工作:
plt.draw()
在 on_keyboard
函数的末尾:这是更新绘图所必需的
ax.cla()
和 ax2.cla()
在 on_keyboard
函数中的 for 循环之前:这是清除先前绘图中的轴所必需的
但是 ax.cla()
擦除网格,因此我建议您对代码进行一些编辑:
将所有绘图调用(为循环绘图和布局管理)移动到 on_keyboard
函数中,因此用户按下 [=60 时不仅会更新绘图,还会更新布局管理=] 或 。这使您可以避免在 on_keyboard
的外部和内部重复 for 循环(和布局管理)
去掉外面的on_keybaord
for循环作图,无用的重复
在布局管理中添加ax.set_xlim
和ax2.set_xlim
以修复x轴限制
在 plt.show()
之前添加对 on_keyboard
的调用以绘制绘图
之前的调用需要传递给 on_keyboard
一个 event
参数:你可以只传递 0
并在 on_keyboard
中捕获它if 语句
话虽如此,工作代码:
(我删除了 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 次拍摄后:
我正在尝试使用 matplotlib 绘制交互式股票图表。它应该像这样工作:
- 最初它在图中显示 60 个柱(从数据帧的第一个柱到第 60 个柱)
- 在键盘上按向右箭头后,它显示第 61 个柱,第一个柱消失(因此,现在绘图显示数据框的第二个到第 61 个)。如果我再次按向右箭头,绘图会显示第三到第 62 个,依此类推。这里的想法是在我按向右箭头前进的日子里,在图中显示固定数量的条。
- 按向左箭头后退一步(例如,如果图表在第 2 到第 61 位,按向左箭头后将返回到第 1 到第 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
干得好。
您只需添加两件事即可使您的代码正常工作:
plt.draw()
在on_keyboard
函数的末尾:这是更新绘图所必需的ax.cla()
和ax2.cla()
在on_keyboard
函数中的 for 循环之前:这是清除先前绘图中的轴所必需的
但是 ax.cla()
擦除网格,因此我建议您对代码进行一些编辑:
将所有绘图调用(为循环绘图和布局管理)移动到
的外部和内部重复 for 循环(和布局管理)on_keyboard
函数中,因此用户按下 [=60 时不仅会更新绘图,还会更新布局管理=] 或 。这使您可以避免在on_keyboard
去掉外面的
on_keybaord
for循环作图,无用的重复在布局管理中添加
ax.set_xlim
和ax2.set_xlim
以修复x轴限制在
plt.show()
之前添加对on_keyboard
的调用以绘制绘图之前的调用需要传递给
on_keyboard
一个event
参数:你可以只传递0
并在on_keyboard
中捕获它if 语句
话虽如此,工作代码:
(我删除了 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 次拍摄后: