如何在Y轴范围受限的时间线上居中叠加保留原始值的折线子图
时间线叠加销量折线图适配方案
实现逻辑
用Matplotlib双Y轴方案即可实现需求,无需大幅修改原有时间线绘制逻辑:
- 第一个Y轴专门绘制事件时间线,固定Y轴范围为[-6,6],从根源避免事件标注被挤压变形
- 新建共享X轴的第二个Y轴用于绘制销量折线,将销量原始值线性缩放到[-5,5]区间内,适配时间线的垂直展示范围
- 第二个Y轴的刻度直接映射为原始销量数值,用户看到的就是真实销量,无需手动换算
修改后完整代码
import numpy as np import matplotlib.pyplot as plt import matplotlib.dates as mdates import pandas as pd def GenerateTimeLine2(data, data02, title="Timeline", xaxis_format="%d %b", day_interval=5, figsize=(8, 5)): levels = np.array([-5, 5, -3, 3, -1, 1]) fig, ax1 = plt.subplots(figsize=figsize) # 绘制基准时间线 start = min(data.index) stop = max(data.index) ax1.plot((start, stop), (0, 0), 'k', alpha=.5) # 遍历标注所有事件 for ii, (idate, iname) in enumerate(data.itertuples()): level = levels[ii % 6] vert = 'top' if level < 0 else 'bottom' ax1.scatter(idate, 0, s=100, facecolor='w', edgecolor='k', zorder=9999) ax1.plot((idate, idate), (0, level), c='r', alpha=.7) ax1.text(idate, level, iname, ha='right', va=vert, fontsize=14, backgroundcolor=(1., 1., 1., .3)) ax1.set(title=title) # X轴日期格式设置 ax1.get_xaxis().set_major_locator(mdates.DayLocator(interval=day_interval)) ax1.get_xaxis().set_major_formatter(mdates.DateFormatter(xaxis_format)) fig.autofmt_xdate() # 固定左侧Y轴范围,保证时间线布局不会变化 ax1.set_ylim(-6, 6) # 隐藏左侧Y轴刻度和所有边框保持简洁 plt.setp((ax1.get_yticklabels() + list(ax1.spines.values())), visible=False) # 新建右侧Y轴显示销量原始值 ax2 = ax1.twinx() sales_min = data02.iloc[:,0].min() sales_max = data02.iloc[:,0].max() # 将销量值映射到时间线的Y轴区间[-5,5]内绘制 norm_sales = 10 * (data02.iloc[:,0] - sales_min) / (sales_max - sales_min) - 5 ax2.plot(data02.index, norm_sales) # 右侧Y轴刻度映射为原始销量值 ax2.set_ylim(-5,5) ax2.set_yticks(np.linspace(-5,5,5)) ax2.set_yticklabels(np.linspace(sales_min, sales_max,5).astype(int)) ax2.set_ylabel('销量') ax2.yaxis.set_label_position("right") # 隐藏右侧Y轴边框 ax2.spines[['top','bottom','left','right']].set_visible(False) return ax1, ax2 # 数据读取 data = pd.read_csv(r'testdata01.txt', parse_dates=True, index_col=0) data02 = pd.read_csv(r'rap_a.txt', parse_dates=True, index_col=0) ax1, ax2 = GenerateTimeLine2(data,data02,title='事件时间线', day_interval=1,figsize=(8,5)) plt.show()
内容的提问来源于stack exchange,提问作者John Johnson
相关产品推荐
相关产品推荐

