如何使用matplotlib优化多系列曲线图表的可读性与标记展示效果
一、可视化优化方案
- 首选「主图+局部嵌入放大子图」方案
该方案比断轴的可读性更强,兼顾全局趋势和局部细节:主图展示00.55s的全范围数据,呈现三组不同时间区间的序列分布;在主图空白处嵌入子图专门放大00.15s的密集区间,同时在主图上用矩形框标注放大区域,和子图做视觉关联,完全避免断轴带来的轴连续性割裂问题。 - 断轴方案优化(如果优先选用断轴)
给断轴位置添加标准的斜线截断标记,同时调整两段x轴的刻度密度:左侧00.2s区间每0.02s设置一个刻度,右侧0.50.55s区间每0.01s设置一个刻度,避免刻度混淆;把marker说明移动到断轴的空白区域,不要遮挡曲线。 - 细节优化
把原E序列的黄色替换为对比度更高的颜色(如tab:purple),避免浅色在白底上辨识度低的问题;调整marker的边框颜色为黑色,进一步提升密集区域的marker区分度。
二、标记点绘制与说明的规范实现
原有代码冗余度很高,且手动生成的说明样式不可控,可通过以下方式优化:
- 把所有序列的配置整理为结构化数据,用循环批量绘制曲线和标记,避免重复代码
- 用matplotlib原生的哑元图例对象生成marker说明,样式和主图例统一,自动对齐不需要手动调整位置
下面是集成了「主图+局部放大」效果的优化代码:
import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1.inset_locator import inset_axes, mark_inset from matplotlib.lines import Line2D # 结构化整理所有序列数据 series_config = [ {"label": "A", "time": [0.0990, 0.1021, 0.1097, 0.1109, 0.1321], "value": [0.807, 0.633, 0.416, 0.274, 0.188], "color": "tab:blue"}, {"label": "B", "time": [0.1727, 0.1742, 0.1772, 0.1869, 0.1765], "value": [0.764, 0.753, 0.716, 0.576, 0.516], "color": "tab:red"}, {"label": "C", "time": [0.5295, 0.5368, 0.5431, 0.5391, 0.5443], "value": [0.729, 0.719, 0.674, 0.631, 0.616], "color": "tab:orange"}, {"label": "D", "time": [0.0740, 0.0792, 0.0819, 0.0837, 0.0858], "value": [0.703, 0.541, 0.174, 0.062, 0.020], "color": "tab:green"}, {"label": "E", "time": [0.0829, 0.0929, 0.0910, 0.0950, 0.0972], "value": [0.709, 0.605, 0.390, 0.259, 0.155], "color": "tab:purple"}, {"label": "F", "time": [0.0885, 0.0936, 0.09621, 0.0974, 0.0999], "value": [0.748, 0.566, 0.366, 0.198, 0.168], "color": "tab:cyan"}, ] markers = ["s", "^", "o", 'p', '*'] marker_labels = ["1", "2", "3", "4", "5"] fig, ax = plt.subplots(figsize=(8, 5)) # 批量绘制所有序列和标记 for series in series_config: # 绘制曲线 ax.plot(series["time"], series["value"], c=series["color"], label=series["label"], zorder=2) # 绘制每个点的对应marker,加黑边提升辨识度 for i in range(5): ax.scatter(series["time"][i], series["value"][i], c=series["color"], marker=markers[i], s=40, edgecolor="k", zorder=3) # 生成marker图例的哑元对象 marker_legend_elements = [Line2D([0], [0], marker=markers[i], color='w', markerfacecolor='gray', markeredgecolor='k', markersize=8, label=marker_labels[i]) for i in range(5)] # 添加两个图例,一个是序列颜色图例,一个是marker编号图例 legend1 = ax.legend(loc="lower left", fontsize=9) ax.add_artist(legend1) ax.legend(handles=marker_legend_elements, loc="lower right", fontsize=9, title="点编号") ax.set_xlabel('time (s)') ax.set_ylabel('score') # 添加局部放大子图,位置在右上角 ax_inset = inset_axes(ax, width="35%", height="35%", loc="upper right", borderpad=2) # 子图绘制同样的数据 for series in series_config: ax_inset.plot(series["time"], series["value"], c=series["color"], zorder=2) for i in range(5): ax_inset.scatter(series["time"][i], series["value"][i], c=series["color"], marker=markers[i], s=30, edgecolor="k", zorder=3) # 设置子图的x、y范围为密集区间 ax_inset.set_xlim(0.07, 0.14) ax_inset.set_ylim(0, 0.9) # 标记主图上的放大区域 mark_inset(ax, ax_inset, loc1=2, loc2=4, fc="none", ec="0.5") plt.show()
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

