Matplotlib中如何让EngFormatter适配以2为底数的对数X轴
Matplotlib中如何让EngFormatter适配以2为底数的对数X轴
嘿,这个问题我之前折腾过好一会儿!EngFormatter本身是为10进制的工程符号设计的,所以在2进制对数轴上自然会出现这种“差一点”的显示问题——比如2^15明明是32768,它却显示33k,确实挺闹心的。不过我们可以自己写个自定义的格式器来搞定这个需求~
核心思路是:我们需要按照2的幂次来划分工程单位(比如210=1024对应“k”,220=1048576对应“M”),而不是默认的103、106。用Matplotlib的FuncFormatter就能轻松实现这个自定义逻辑。
完整修改后的代码示例
import numpy as np import matplotlib.pyplot as plt import matplotlib.ticker as mticker def binary_eng_formatter(x, pos): # 处理x=0的特殊情况 if x == 0: return '0' # 计算数值以2为底的对数,取整数部分得到幂次 exp = np.floor(np.log2(x)) # 找到最接近的10的倍数幂次(对应2^10、2^20这类工程单位分界) exp_10 = (exp // 10) * 10 # 计算系数:x除以2^exp_10,得到对应单位下的数值 coeff = x / (2 ** exp_10) # 定义2进制工程单位映射 units = {0: '', 10: 'k', 20: 'M', 30: 'G', 40: 'T'} # 如果幂次不在预设字典里,直接显示2^xx的形式 unit = units.get(exp_10, f'2^{exp_10}') # 按整数格式返回(对应你需要的places=0) return f'{int(coeff)}{unit}' # 你的原始数据 sizes = np.array([2**i for i in range(1, 18)]) times = np.array([2**i*np.random.uniform(0.4, 1.6) for i in range(1, 18)]) # Example times in milliseconds fig, ax = plt.subplots(figsize=(10, 6)) plt.plot(sizes, times, marker='o') ax.set_xscale('log', base=2) ax.set_xlabel('size') ax.set_ylabel('time') # 替换原来的EngFormatter为我们自定义的二进制工程格式器 ax.xaxis.set_major_formatter(mticker.FuncFormatter(binary_eng_formatter)) plt.show()
代码逻辑说明
- 计算幂次:通过
np.log2(x)得到数值的2进制对数,取整后找到10的倍数幂次,这样就能对应到1k(1024)、1M(1048576)这类2进制工程单位。 - 计算系数:把原始数值除以对应的2exp_10,得到单位前的系数——比如32768除以210(1024)得到32,所以显示为32k。
- 单位映射:预设常用的2进制工程单位,遇到超出范围的幂次就直接显示2^xx的形式,保证兼容性。
这样运行后,你的X轴刻度就会准确显示2、4、8、...、32k、64k、128k这些符合2进制逻辑的工程符号啦!
内容来源于stack exchange
相关产品推荐
相关产品推荐

