mplfinance实时绘图vlines索引异常:垂直线偏移右侧问题
问题:mplfinance实时绘图中垂直线偏移至右侧的原因及解决方法
我在mplfinance的实时绘图上尝试绘制垂直线,当前绘制水平线的代码运行正常:
def animate(ival): df = pd.read_pickle("/Users/user/Workfiles/Python/rp/0.72.0.0/df.pkl") ax1.clear() mpf.plot(df, ax=ax1, type='candle', ylabel='p', warn_too_much_data=999999999999) try: ax1.hlines(y=price, xmin=df.shape[0]-10, xmax=df.shape[0], color='r', linewidth=1) except UnboundLocalError: pass ani = FuncAnimation(fig, animate, interval=100) mpf.show()
我已获取需标记行的索引存入变量lows_peaks,对应行的时间戳正确,但执行以下代码绘制垂直线时,线条出现在绘图右侧:
for i in df.iloc[lows_peaks].index: ax1.vlines(x=i, ymin=df.low.min(), ymax=df.high.max(), color='r', linewidth=1)
附可复现代码:
import pandas as pd import numpy as np from matplotlib.animation import FuncAnimation import mplfinance as mpf times = pd.date_range(start='2022-01-01', periods=50, freq='ms') df = pd.DataFrame(np.random.randint(3000, 3100, (50, 1)), columns=['open']) df['high'] = df.open+5 df['low'] = df.open-2 df['close'] = df.open df.set_index(times, inplace=True) lows_peaks = df.low.nsmallest(5).index print(lows_peaks) fig = mpf.figure(style="charles",figsize=(7,8)) ax1 = fig.add_subplot(1,1,1) def animate(ival): ax1.clear() for i in lows_peaks: ax1.vlines(x=i, ymin=df.low.min(), ymax=df.high.max(), color='blue', linewidth=3) mpf.plot(df, ax=ax1) ani = FuncAnimation(fig, animate, interval=100) mpf.show()
原因分析
问题核心在于绘图顺序和mplfinance的坐标轴逻辑:
- mplfinance绘制K线时,会将x轴转换为从0开始的整数行号,而非原始的时间戳格式。但你先绘制垂直线时用的是原始时间戳,这些时间戳的数值远大于mplfinance实际使用的x轴范围,导致线条被挤到绘图右侧。
- 其次,
mpf.plot()执行时会重置坐标轴的刻度和范围,覆盖你之前绘制的垂直线的坐标映射关系。
解决方案
调整绘图顺序,先让mplfinance完成K线绘制,再基于它生成的x轴坐标绘制垂直线,两种可靠实现方式如下:
方式一:直接获取时间戳对应的行号
利用df.index.get_loc()直接获取目标时间戳在DataFrame中的行位置(即mplfinance使用的x轴坐标):
import pandas as pd import numpy as np from matplotlib.animation import FuncAnimation import mplfinance as mpf times = pd.date_range(start='2022-01-01', periods=50, freq='ms') df = pd.DataFrame(np.random.randint(3000, 3100, (50, 1)), columns=['open']) df['high'] = df.open+5 df['low'] = df.open-2 df['close'] = df.open df.set_index(times, inplace=True) lows_peaks = df.low.nsmallest(5).index fig = mpf.figure(style="charles",figsize=(7,8)) ax1 = fig.add_subplot(1,1,1) def animate(ival): ax1.clear() # 先绘制K线,让mplfinance初始化坐标轴 mpf.plot(df, ax=ax1) y_min = df.low.min() y_max = df.high.max() # 获取目标时间戳对应的行号,绘制垂直线 for date in lows_peaks: x_pos = df.index.get_loc(date) ax1.vlines(x=x_pos, ymin=y_min, ymax=y_max, color='blue', linewidth=3) ani = FuncAnimation(fig, animate, interval=100) mpf.show()
方式二:建立时间戳与x坐标的映射
通过坐标轴的刻度标签建立时间戳到x坐标的映射,适合需要自定义刻度的场景:
import pandas as pd import numpy as np from matplotlib.animation import FuncAnimation import mplfinance as mpf times = pd.date_range(start='2022-01-01', periods=50, freq='ms') df = pd.DataFrame(np.random.randint(3000, 3100, (50, 1)), columns=['open']) df['high'] = df.open+5 df['low'] = df.open-2 df['close'] = df.open df.set_index(times, inplace=True) lows_peaks = df.low.nsmallest(5).index fig = mpf.figure(style="charles",figsize=(7,8)) ax1 = fig.add_subplot(1,1,1) def animate(ival): ax1.clear() # 先绘制K线 mpf.plot(df, ax=ax1) # 建立时间戳到x坐标的映射 xtick_labels = [label.get_text() for label in ax1.get_xticklabels()] xtick_dates = pd.to_datetime(xtick_labels, errors='coerce') x_pos_map = {date: pos for pos, date in enumerate(df.index) if date in xtick_dates} y_min = df.low.min() y_max = df.high.max() # 遍历目标时间戳绘制垂直线 for date in lows_peaks: if date in x_pos_map: ax1.vlines(x=x_pos_map[date], ymin=y_min, ymax=y_max, color='blue', linewidth=3) ani = FuncAnimation(fig, animate, interval=100) mpf.show()
内容的提问来源于stack exchange,提问作者stanvooz
相关产品推荐
相关产品推荐

