You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()

代码逻辑说明

  1. 计算幂次:通过np.log2(x)得到数值的2进制对数,取整后找到10的倍数幂次,这样就能对应到1k(1024)、1M(1048576)这类2进制工程单位。
  2. 计算系数:把原始数值除以对应的2exp_10,得到单位前的系数——比如32768除以210(1024)得到32,所以显示为32k。
  3. 单位映射:预设常用的2进制工程单位,遇到超出范围的幂次就直接显示2^xx的形式,保证兼容性。

这样运行后,你的X轴刻度就会准确显示2、4、8、...、32k、64k、128k这些符合2进制逻辑的工程符号啦!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 10:23:08