如何使用动态变量为不同Matplotlib图表设置不同FuncFormatter
循环生成多图时动态绑定Y轴缩放比例的问题解决
我需要在循环中生成多个图表,每个图表展示同一条曲线,同时右侧Y轴使用不同的缩放比例,且缩放比例依赖循环变量。
固定缩放因子的代码可以正常运行:
import numpy as np import matplotlib.pyplot as plt from matplotlib.ticker import FuncFormatter data = np.random.normal(0, 0.01, (20)) # 这段代码正常工作,两个图表的右侧Y轴分别按2倍和10倍缩放 for right_scale in [2, 10]: fig, ax = plt.subplots() ax.plot(data) ax2 = ax.twinx() ax2.set_ylim(ax.get_ylim()) if right_scale == 2: formatter = FuncFormatter(lambda x, pos: '{:.2f}'.format(x * 2)) else: formatter = FuncFormatter(lambda x, pos: '{:.3f}'.format(x * 10)) ax2.yaxis.set_major_formatter(formatter) plt.show()
但改用动态循环变量时,所有图表的右侧Y轴都按最后一个缩放因子(10倍)显示,问题出在lambda函数绑定的是变量引用而非定义时的具体值。
问题原因
Python的lambda函数在定义时不会立即捕获变量的当前值,而是保留对变量的引用。当循环执行完毕,right_scale的最终值为10,所有之前创建的lambda函数都会使用这个最终值。
解决方案
方法1:用默认参数捕获当前值
在lambda中添加默认参数,将当前的right_scale值作为默认值传入,让lambda捕获定义时的具体值而非变量引用:
import numpy as np import matplotlib.pyplot as plt from matplotlib.ticker import FuncFormatter data = np.random.normal(0, 0.01, (20)) for right_scale in [2, 10]: fig, ax = plt.subplots() ax.plot(data) ax2 = ax.twinx() ax2.set_ylim(ax.get_ylim()) if right_scale == 2: # 通过默认参数s=right_scale捕获当前循环的缩放值 formatter = FuncFormatter(lambda x, pos, s=right_scale: '{:.2f}'.format(x * s)) else: formatter = FuncFormatter(lambda x, pos, s=right_scale: '{:.3f}'.format(x * s)) ax2.yaxis.set_major_formatter(formatter) plt.show()
方法2:用工厂函数生成格式化器
定义专门的工厂函数,利用函数局部作用域保存当前的缩放因子值:
import numpy as np import matplotlib.pyplot as plt from matplotlib.ticker import FuncFormatter data = np.random.normal(0, 0.01, (20)) def create_formatter(scale): # 函数局部作用域会保存当前传入的scale值 if scale == 2: return FuncFormatter(lambda x, pos: '{:.2f}'.format(x * scale)) else: return FuncFormatter(lambda x, pos: '{:.3f}'.format(x * scale)) for right_scale in [2, 10]: fig, ax = plt.subplots() ax.plot(data) ax2 = ax.twinx() ax2.set_ylim(ax.get_ylim()) formatter = create_formatter(right_scale) ax2.yaxis.set_major_formatter(formatter) plt.show()
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

