如何绘制按年份区分、横轴为年月纵轴为数值的时序散点图
问题:绘制按年份上色的年月横轴能耗图表
我想要绘制横轴为所有年份-月份、纵轴为月度能耗均值的图表,同时按数据所属年份为数据点上色。使用小时能耗数据集尝试后未得到预期效果。
现有代码
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import matplotlib.colors as mcolors colors_list = list(mcolors.XKCD_COLORS.keys()) df = pd.read_csv('/kaggle/input/hourly-energy-consumption/DOM_hourly.csv') df.set_index('Datetime', inplace=True, drop=True) df.index = pd.to_datetime(df.index, format='%Y-%m-%d %H:%M:%S') # 去除重复索引 df = df[~df.index.duplicated(keep='first')] # 月度均值数据框 mdf = df.resample(rule='M', kind='interval').mean()#.to_period('M').mean() # 绘图 mdf['Year'] = mdf.index.year mdf['Month'] = mdf.index.month fig, ax = plt.subplots(figsize=(10, 6)) sns.scatterplot(x='Month', y=mdf.columns[0], data=mdf, hue='Year',ax=ax) plt.show()
当前输出

期望输出
我希望得到类似下图的效果,这样可以观察年度间的模式,也能查看多个月份的共性模式:
尝试的代码(含警告)
我尝试了以下代码来实现期望效果,但出现了SettingWithCopyWarning警告:
# 绘制年度间同月变化图表 years_list = mdf['Year'].unique() years_color = colors_list[:len(years_list)] # 为主数据框添加颜色列 mdf['year_color'] = mdf['Year'].map(dict(zip(years_list,years_color))) for one_month in range(1,13,1): one_month_all_years_data = mdf[mdf['Month']==one_month] x_ticks = np.linspace(0,1,len(one_month_all_years_data)+1,endpoint=False)[1:len(one_month_all_years_data)+1] one_month_all_years_data['All years-months'] = None one_month_all_years_data.loc[:,'All years-months'] = x_ticks + one_month ax = sns.scatterplot(x='All years-months',y=mdf.columns[0],data=one_month_all_years_data, hue = one_month_all_years_data.index, hue_order = one_month_all_years_data['year_color']) sns.move_legend(ax, one_month_all_years_data.index) plt.show()
警告信息
/tmp/ipykernel_32/2084798528.py:74: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy one_month_all_years_data['All years-months'] = None /tmp/ipykernel_32/2084798528.py:75: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead ........
当前接近期望的输出

解决方案
问题分析
- 原代码用
Month作为x轴,导致所有年份的同月数据堆叠在同一位置,无法体现时间顺序 - 尝试代码中的切片赋值引发警告,且x轴处理逻辑复杂、图例设置错误
修正后的代码
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # 读取并预处理数据 df = pd.read_csv('/kaggle/input/hourly-energy-consumption/DOM_hourly.csv') df['Datetime'] = pd.to_datetime(df['Datetime']) df = df.drop_duplicates(subset='Datetime', keep='first').set_index('Datetime') # 计算月度均值,提取年月信息 mdf = df.resample('M').mean().reset_index() mdf['Year'] = mdf['Datetime'].dt.year mdf['Month'] = mdf['Datetime'].dt.month # 生成连续的x轴数值:年份 + 月份占比(比如2015-01对应2015.0,2015-02对应2015.0833) mdf['x_value'] = mdf['Datetime'].dt.year + (mdf['Datetime'].dt.month - 1)/12 # 绘图 fig, ax = plt.subplots(figsize=(12, 6)) sns.scatterplot(x='x_value', y=df.columns[0], data=mdf, hue='Year', palette='tab10', s=80, ax=ax) # 设置x轴刻度:仅显示每年1月的年份标签 year_ticks = mdf.groupby('Year')['x_value'].first() ax.set_xticks(year_ticks) ax.set_xticklabels(year_ticks.index.astype(str)) # 添加月份分隔线,方便对比同月位置 for month in range(1, 13): ax.axvline(x=year_ticks.min() + (month-1)/12, color='lightgray', linestyle='--', alpha=0.5) ax.set_xlabel('年份-月份') ax.set_ylabel('月度能耗均值') ax.set_title('年度月度能耗变化对比') plt.tight_layout() plt.show()
代码说明
- 数据预处理:简化日期转换逻辑,直接用
resample('M')生成月度均值,避免索引类型问题 - x轴优化:将年月转换为连续数值,确保横轴按时间顺序排列,同一年的月份连续分布
- 可视化优化:使用内置配色方案
tab10区分年份,添加月份分隔线方便观察年度间同月模式,同时解决了原代码的堆叠问题与赋值警告
内容的提问来源于stack exchange,提问作者Mainland
相关产品推荐
相关产品推荐

