Python matplotlib plt.plot传入*args时出现重复绘图异常
问题描述
向plt.plot()传递任意数量参数时出现重复绘图问题:通过*args传入可选参数时,会生成重复曲线。编写的read_n_plot函数用于读取数据文件、返回列表格式数据并绘制对应曲线,绘制晶体XRD标准谱时需要与对比的实验数据有明显视觉区分。
已知*args是存储传入函数所有位置参数的元组,但始终无法找到将*args内参数原样整体传入的方法,避免出现plt.plot(arg1) -> plt.plot(arg2)这类逐个传参触发多次绘图的情况。
测试时传入的linestyle参数'--'完全未生效,图例显示存在两个绘图条目,出现曲线重复问题,效果如下:
现有代码如下:
import matplotlib.pyplot as plt #def read_n_plot(datafile, color, thickness, style = '-', *args): def read_n_plot(datafile, *args, **kwargs): vinkel = [] intensitet = [] with open(datafile, encoding='utf8', errors='ignore') as f: if datafile.endswith('.int'): next(f); next(f) lines = f.readlines() for line in lines: if line and line[0].isalpha(): continue data = line.split() theta, counts = float(data[0]), float(data[1]) vinkel.append(theta) intensitet.append(counts) intensitet_norm = [i/max(intensitet) for i in intensitet] plt.plot(vinkel, intensitet_norm, label = datafile, *args, **kwargs) return vinkel, intensitet_norm plt.figure(figsize=(16,9)) read_n_plot('NaCl_data.xy', 'k', '--', lw = 1.0) plt.legend(loc='best') plt.xlabel(r'$2\theta$') plt.xlim(0, 65) plt.ylabel('Intensitet (a.u.)') plt.tick_params(left=None) plt.yticks([]) plt.show()
问题原因
plt.plot()支持多组数据连续传入绘图,会按顺序将位置参数解析为(x, y, fmt)的绘图组,其中fmt(控制颜色、线型、标记的格式字符串)必须是单个字符串,不能拆分为多个独立位置参数传入。- 代码中拆分传入了
'k'和'--'两个独立字符串,plt.plot()会将第一个字符串'k'识别为第一组数据的格式参数,将第二个字符串'--'识别为第二组绘图的y轴数据(字符串为可迭代对象,会被自动转换为数值序列),因此触发重复绘图,且'--'没有被识别为线型参数,导致虚线样式不生效。 - 函数内调用
plt.plot()时,将关键字参数label=datafile写在了*args位置参数解包之前,不符合参数传递的规范,容易加剧解析混乱。
解决方法
两种方案任选即可:
- 格式字符串合并传参:将颜色、线型等格式符合并为单个fmt字符串传入,同时调整
plt.plot()的参数顺序,将所有位置参数放在关键字参数之前:
修正后的完整代码:
import matplotlib.pyplot as plt def read_n_plot(datafile, *args, **kwargs): vinkel = [] intensitet = [] with open(datafile, encoding='utf8', errors='ignore') as f: if datafile.endswith('.int'): next(f); next(f) lines = f.readlines() for line in lines: if line and line[0].isalpha(): continue data = line.split() theta, counts = float(data[0]), float(data[1]) vinkel.append(theta) intensitet.append(counts) intensitet_norm = [i/max(intensitet) for i in intensitet] # 调整参数顺序:*args位置参数全部放在显式关键字参数之前 plt.plot(vinkel, intensitet_norm, *args, label=datafile, **kwargs) return vinkel, intensitet_norm plt.figure(figsize=(16,9)) # 将颜色和线型合并为单个fmt字符串'k--'传入 read_n_plot('NaCl_data.xy', 'k--', lw = 1.0) plt.legend(loc='best') plt.xlabel(r'$2\theta$') plt.xlim(0, 65) plt.ylabel('Intensitet (a.u.)') plt.tick_params(left=False) plt.yticks([]) plt.show()
- 样式全部用关键字参数传递:不使用位置格式传样式,将颜色、线型等参数全部以关键字形式传入,完全避免位置参数被误识别为新数据集:
调用时写法改为:
read_n_plot('NaCl_data.xy', color='k', linestyle='--', lw=1.0)
这种写法可读性更强,也不会出现参数解析错误,更推荐在参数较多时使用。
内容的提问来源于stack exchange,提问作者Andreas
相关产品推荐
相关产品推荐

