Matplotlib子图绘制异常:第二个折线图无数据显示
问题解决:Matplotlib共享X轴时折线图无数据显示
问题背景
创建包含堆叠柱状图和折线图的子图布局,要求二者共享datetime类型的X轴,但折线图始终无数据渲染。
数据样例
| 日期 | Economizer | Economizer_plus_Mech | Not_Mechanical | OaTemp |
|---|---|---|---|---|
| 2023-10-01 | 1.680672 | 1.680672 | 1.680672 | 84.317815 |
| 2023-10-02 | 17.127072 | 5.524862 | 1.657459 | 76.263536 |
| 2023-10-03 | 31.481481 | 5.092593 | 0.000000 | 73.407407 |
原实现代码
import matplotlib.pyplot as plt import os import pandas as pd PLOTS_DIR = 'path/to/plots' def save_mode_plot_with_oat(combined_data, title, ylabel, filename): # 确保索引为datetime类型 combined_data.index = pd.to_datetime(combined_data.index) # 创建2行子图,共享X轴 fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12), sharex=True) # 第一个子图:堆叠柱状图 combined_data.iloc[:, :-1].plot(kind='bar', stacked=True, ax=ax1, colormap='viridis') ax1.set_title(title) ax1.set_ylabel(ylabel) ax1.set_xlabel('') ax1.tick_params(axis='x', labelbottom=False) # 隐藏第一个子图的X轴标签 # 第二个子图:折线图(无数据显示) ax2.plot(combined_data.index, combined_data['OaTemp'], color='red', linestyle='-', marker='o') ax2.set_title('Average Outside Air Temperature Over Time') ax2.set_ylabel('Average Outside Air Temperature (°F)') ax2.set_xlabel('Date') ax2.tick_params(axis='x', rotation=90) ax2.grid(True) plt.tight_layout() plt.savefig(os.path.join(PLOTS_DIR, filename)) plt.close() # 调用示例 save_mode_plot_with_oat(month_df, 'Mode Percentages and OAT', 'Percentage (%)', 'mode_oat_plot.png')
问题原因
pandas的plot(kind='bar')会自动将datetime类型的索引转换为**整数位置(0,1,2...)**作为X轴坐标,开启sharex=True后,第二个子图的X轴会继承这个整数刻度体系。此时用datetime索引绘制折线图,数据的X坐标是实际日期值,和子图的整数刻度不匹配,导致折线图数据不在可见范围内。
解决方案
方法一:折线图用整数位置对齐(最简方案)
将折线图的X轴替换为数据行的整数位置,和柱状图的X轴刻度对齐,同时手动设置日期标签:
# 修改折线图绘制代码 ax2.plot(range(len(combined_data)), combined_data['OaTemp'], color='red', linestyle='-', marker='o') # 设置正确的日期标签 ax2.set_xticks(range(len(combined_data))) ax2.set_xticklabels(combined_data.index.strftime('%Y-%m-%d'))
修改后的完整代码
import matplotlib.pyplot as plt import os import pandas as pd PLOTS_DIR = 'path/to/plots' def save_mode_plot_with_oat(combined_data, title, ylabel, filename): combined_data.index = pd.to_datetime(combined_data.index) fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12), sharex=True) # 堆叠柱状图 combined_data.iloc[:, :-1].plot(kind='bar', stacked=True, ax=ax1, colormap='viridis') ax1.set_title(title) ax1.set_ylabel(ylabel) ax1.set_xlabel('') ax1.tick_params(axis='x', labelbottom=False) # 折线图:用整数位置对齐X轴 ax2.plot(range(len(combined_data)), combined_data['OaTemp'], color='red', linestyle='-', marker='o') ax2.set_title('Average Outside Air Temperature Over Time') ax2.set_ylabel('Average Outside Air Temperature (°F)') ax2.set_xlabel('Date') # 设置日期标签 ax2.set_xticks(range(len(combined_data))) ax2.set_xticklabels(combined_data.index.strftime('%Y-%m-%d')) ax2.tick_params(axis='x', rotation=90) ax2.grid(True) plt.tight_layout() plt.savefig(os.path.join(PLOTS_DIR, filename)) plt.close() # 调用示例 save_mode_plot_with_oat(month_df, 'Mode Percentages and OAT', 'Percentage (%)', 'mode_oat_plot.png')
方法二:用Matplotlib原生bar绘制柱状图(保留datetime轴)
若希望X轴始终为datetime类型,可放弃pandas的plot方法,用Matplotlib原生bar函数手动绘制堆叠柱状图:
# 替换柱状图绘制部分 columns = combined_data.iloc[:, :-1].columns bottom = 0 for col in columns: ax1.bar(combined_data.index, combined_data[col], bottom=bottom, label=col) bottom += combined_data[col] ax1.legend()
这种方式下,折线图代码无需修改,X轴始终为datetime类型,共享后可正常对齐。
内容的提问来源于stack exchange,提问作者bbartling
相关产品推荐
相关产品推荐

