如何正确绘制含零值与DateTimeIndex的Pandas Series?
解决Pandas DateTimeIndex序列绘图:保留非零值前后零值并隐藏空白日期间隔
需求说明
有一个以DateTimeIndex为索引的Pandas Series,其中包含大量零值,仅少数日期为非零值。绘图时希望:
- 仅保留非零值前后的少量零值(比如前后2天),避免显示过多无关零值
- 自动识别需要保留的日期,无需手动设置
- 隐藏无数据的空白日期间隔,让图表更紧凑
示例数据
import pandas as pd import numpy as np import matplotlib.pyplot as plt # 生成示例序列 ser_tmp = pd.Series(0, index=pd.date_range('2020-01-01', '2020-01-30')) ser_tmp.loc[[pd.Timestamp('2020-01-03'), pd.Timestamp('2020-01-04'), pd.Timestamp('2020-01-23'), pd.Timestamp('2020-01-24')]] = 1
解决方案
1. 自动筛选需要保留的日期
编写函数自动识别非零值位置,保留每个非零值前后指定天数的所有数据,其余零值转为NaN后删除:
def keep_around_nonzero(series, keep_days=2): # 获取所有非零值的索引 nonzero_indices = series[series != 0].index # 初始化需要保留的索引集合 keep_indices = set() for idx in nonzero_indices: # 计算当前非零值前后keep_days的日期范围 start_date = idx - pd.Timedelta(days=keep_days) end_date = idx + pd.Timedelta(days=keep_days) # 将该范围内的所有索引加入保留集合 keep_indices.update(series.index[(series.index >= start_date) & (series.index <= end_date)]) # 复制原序列,将不在保留集合中的零值设为NaN processed_series = series.copy() processed_series.loc[(processed_series == 0) & (~processed_series.index.isin(keep_indices))] = np.nan # 删除NaN值,得到最终需要的序列 processed_series = processed_series.dropna() return processed_series # 处理序列,保留非零值前后2天的数据 ser_processed = keep_around_nonzero(ser_tmp, keep_days=2)
2. 绘制紧凑图表,隐藏空白间隔
直接用Pandas的plot()会默认按连续时间轴绘图,导致空白间隔仍显示。改用Matplotlib手动绘制,将x轴设为数据点的位置,刻度标签对应实际日期:
plt.figure(figsize=(10, 5)) # 绘制折线图,x轴用数据点的索引位置 plt.plot(range(len(ser_processed)), ser_processed.values, marker='o') # 设置x轴刻度为对应的日期,旋转45度避免重叠 plt.xticks(range(len(ser_processed)), ser_processed.index.strftime('%Y-%m-%d'), rotation=45) # 调整布局,防止标签被截断 plt.tight_layout() plt.show()
效果说明
- 自动保留了非零值(2020-01-03/04、2020-01-23/24)前后2天的零值,其余零值被过滤
- 图表x轴仅显示存在数据的日期,中间的空白间隔(2020-01-06至2020-01-21)被隐藏,图表更紧凑
内容的提问来源于stack exchange,提问作者Lei Hao
相关产品推荐
相关产品推荐

