Plotly绘制金融数据时X轴出现缺口的解决求助
问题描述
我在绘制泰国股市(SET)的市场宽度指标时,最后一个堆叠柱状图的X轴出现了股市休市日期的缺口,但我的DataFrame里根本没有这些日期。求去除X轴缺口的方法,相关代码如下:
import plotly.graph_objects as go import pandas as pd from tvDatafeed import TvDatafeed, Interval from plotly.subplots import make_subplots # Create TV Datafeed instance tv = TvDatafeed() # 1) Create Main CandleStick Chart data_feed = tv.get_hist(symbol="SET", exchange='SET', interval=Interval.in_daily, n_bars=250) # 6) Advance Decline Unchanged Chart file_path_advance_decline_unchanged = "/content/drive/MyDrive/Stock Python/AdvanceDeclineUnchanged.csv" AdvanceDeclineUnchanged_df = pd.read_csv(file_path_advance_decline_unchanged, index_col='Unnamed: 0') last_250_days_data = AdvanceDeclineUnchanged_df.iloc[:, 0:250] valid_dates = AdvanceDeclineUnchanged_df.loc["Advance", AdvanceDeclineUnchanged_df.loc["Advance"].notna()].index plot_data = pd.DataFrame({ 'Date': data_feed.index, 'Advance%': last_250_days_data.loc['Advance%', :].values, 'Unchanged%': last_250_days_data.loc['Unchanged%', :].values, 'Decline%': last_250_days_data.loc['Decline%', :].values }) # Get only valid dates for x-axis valid_dates = list(map(str, valid_dates)) plot_data = plot_data[plot_data['Date'].isin(valid_dates)] # Create subplots fig = make_subplots(rows=6, cols=1, shared_xaxes=True, vertical_spacing=0.04) # Add traces to subplots fig.add_trace(go.Candlestick(x=data_feed.index, open=data_feed.open, high=data_feed.high, low=data_feed.low, close=data_feed.close), row=1, col=1) # 52Wks NHNL-Line Chart _52WksNHNL_line = go.Scatter(x=_52WksNHNL_df.columns[0:249], y=_52WksNHNL_df.iloc[2, 0:250], mode='lines', name='52WksNewHighNewLow', line=dict(color='maroon')) fig.add_trace(_52WksNHNL_line, row=2, col=1) # 20Days NHNL-Line Chart _20DaysNHNL_line = go.Scatter(x=_20DaysNHNL_df.columns[0:250], y=_20DaysNHNL_df.iloc[2, 0:250], mode='lines', name='20DaysNewHighNewLow', line=dict(color='green')) fig.add_trace(_20DaysNHNL_line, row=3, col=1) # 4% Gainer Chart _4percent_line = go.Scatter(x=x_values_4percent, y=y_values_4percent, mode='lines', name='Amount of 4% Gainer', line=dict(color='blue')) fig.add_trace(_4percent_line, row=4, col=1) # EMA Breadth Chart fig.add_trace(go.Scatter(x=_20EMA_Breadth_df.columns[0:250], y=_20EMA_Breadth_df.loc['Percent Above EMA', :].iloc[0:250], mode='lines', name='EMA20', line=dict(color='orange')), row=5, col=1) fig.add_trace(go.Scatter(x=_50EMA_Breadth_df.columns[0:250], y=_50EMA_Breadth_df.loc['Percent Above EMA', :].iloc[0:250], mode='lines', name='EMA50', line=dict(color='red')), row=5, col=1) fig.add_trace(go.Scatter(x=_200EMA_Breadth_df.columns[0:250], y=_200EMA_Breadth_df.loc['Percent Above EMA', :].iloc[0:250], mode='lines', name='EMA200', line=dict(color='purple')), row=5, col=1) # Stacked bar chart for Advance Decline Unchanged Chart (Chart 6) fig.add_trace(go.Bar(x=plot_data['Date'], y=plot_data['Decline%'], name='Decline%', marker_color='red'), row=6, col=1) fig.add_trace(go.Bar(x=plot_data['Date'], y=plot_data['Unchanged%'], name='Unchanged%', marker_color='grey', base=plot_data['Decline%']), row=6, col=1) fig.add_trace(go.Bar(x=plot_data['Date'], y=plot_data['Advance%'], name='Advance%', marker_color='green', base=plot_data['Unchanged%'] + plot_data['Decline%']), row=6, col=1) # Update layout fig.update_layout(xaxis_rangeslider_visible=False, height=2000, title_text="Thai StockMarket Market Breadth", xaxis=dict(type='category'))

解决方法
这个问题的核心是子图共享X轴时,第一个蜡烛图的X轴默认是时间序列类型(type='date'),哪怕你全局设置了xaxis=dict(type='category'),共享轴的子图会继承第一个轴的类型,导致休市日期被自动填充出缺口。下面两种方法可以解决:
方法1:统一所有子图的X轴为类别类型
把所有子图的X轴数据都转成字符串格式,同时明确设置每个X轴的类型为category:
# 创建子图(保持原有配置) fig = make_subplots(rows=6, cols=1, shared_xaxes=True, vertical_spacing=0.04) # 把蜡烛图的日期转成字符串 data_feed_str_dates = data_feed.index.astype(str) fig.add_trace(go.Candlestick(x=data_feed_str_dates, open=data_feed.open, high=data_feed.high, low=data_feed.low, close=data_feed.close), row=1, col=1) # 其他子图的X轴数据也统一转成字符串(比如_52WksNHNL_df.columns等,要和plot_data的Date格式一致) # 示例:_52WksNHNL_line的x参数修改为字符串日期 _52WksNHNL_line = go.Scatter(x=_52WksNHNL_df.columns[0:249].astype(str), y=_52WksNHNL_df.iloc[2, 0:250], mode='lines', name='52WksNewHighNewLow', line=dict(color='maroon')) fig.add_trace(_52WksNHNL_line, row=2, col=1) # ...其他子图都做类似修改... # 最后更新布局,给所有X轴设置类别类型 fig.update_layout( xaxis_rangeslider_visible=False, height=2000, title_text="泰国股市市场宽度指标", xaxis=dict(type='category'), xaxis2=dict(type='category'), xaxis3=dict(type='category'), xaxis4=dict(type='category'), xaxis5=dict(type='category'), xaxis6=dict(type='category') )
方法2:保留时间轴但跳过休市日期
如果想保留时间序列类型的X轴,直接设置rangebreaks跳过周末和法定节假日即可:
fig.update_layout( xaxis_rangeslider_visible=False, height=2000, title_text="泰国股市市场宽度指标", xaxis=dict( type='date', rangebreaks=[ dict(bounds=['sat', 'mon']), # 跳过周末 # 手动添加泰国股市的法定节假日,比如宋干节等,根据实际日期调整 dict(values=['2024-04-13', '2024-04-14', '2024-05-01']) ] ) )
这种方式适合需要保留时间刻度的场景,要是能通过API获取泰国股市的休市日历,还能自动生成values列表,不用手动维护。
注意事项
- 所有共享X轴的子图,日期格式必须完全一致(要么全是datetime,要么全是字符串)
- 共享轴时,全局的
xaxis设置不会覆盖所有子轴,得单独指定每个xaxisN的参数
内容的提问来源于stack exchange,提问作者Phasin Opaspilai
相关产品推荐
相关产品推荐

