如何在matplotlib双对数坐标下绘制log y与log x满足线性关系的直线
核心错误
你之前的代码存在两个本质问题:
- 公式理解错误:拟合关系是log(y) 与 log(x/10^45) 呈线性关系,并非y和x/10^45线性相关,直接用原x代入线性式计算y完全不符合公式定义
- 对数坐标取值错误:对数尺度下0没有对应坐标,
np.linspace(0, 10**50, 100)生成的x序列包含0,会直接导致对数计算报错,且线性间隔采样的点在对数坐标上分布极不均匀,低光度段几乎没有采样点。
正确实现方法
首先明确公式:你给出的拟合关系默认以10为底(天文领域这类光度拟合均采用常用对数),原式为:
$\log_{10} y = 0.84 \times \log_{10}\left(\frac{x}{10^{45}}\right) + 44.06$
利用对数运算规则化简可得原变量关系:$y = 10^{44.06} \times \left(\frac{x}{10{45}}\right){0.84}$,绘图有两种等价实现,按需选择即可。
方法1:原变量空间计算,直接开启对数坐标
这是天文论文中最常用的写法,坐标轴直接展示物理量真值,仅通过坐标设置实现对数展示:
import numpy as np import matplotlib.pyplot as plt # 替换为你实测数据的x值范围,示例取类星体常见中红外光度区间1e42~1e49 erg/s x = np.logspace(42, 49, 100) # 对数等间隔生成采样点,适配对数坐标展示 # 计算最佳拟合线与1σ误差上下界 y = 10**44.06 * (x / 10**45)**0.84 y_upper = 10**(44.06 + 0.01) * (x / 10**45)**(0.84 + 0.03) y_lower = 10**(44.06 - 0.01) * (x / 10**45)**(0.84 - 0.03) # 先绘制实测数据点,替换为你自己的实测数据数组 # plt.scatter(x_obs, y_obs, label='实测样本', color='black', s=15, alpha=0.6) # 绘制拟合线与误差带 plt.plot(x, y, linestyle='-', color='crimson', label='最佳拟合关系') plt.fill_between(x, y_lower, y_upper, color='crimson', alpha=0.2, label='1σ置信区间') # 设置对数坐标与坐标轴标注 plt.xscale('log') plt.yscale('log') plt.xlabel('中红外光度 x (erg/s)') plt.ylabel('X射线光度 y (erg/s)') plt.legend() plt.show()
方法2:对数空间计算,完全匹配原式逻辑
如果担心公式化简出错,可以完全按照原式的对数变量逻辑计算,最终效果和方法1完全一致:
# 生成log(x)的等间隔序列,对应x范围1e42~1e49 logx = np.linspace(42, 49, 100) # 直接代入原式计算log(y),注意log(x/1e45) = logx - log10(1e45) = logx - 45 logy = 0.84 * (logx - 45) + 44.06 # 转换回原变量 x = 10**logx y = 10**logy # 后续绘图、坐标设置、误差带计算逻辑和方法1完全相同
注意事项
- 不要提前对x、y取对数后在线性坐标下绘图,除非你专门要展示log-log空间的线性拟合残差,常规光度相关图均采用原变量+对数坐标的形式,和上述代码输出效果一致
- 采样x必须用
np.logspace生成,不要用从0开始的np.linspace,既避免log(0)的数学错误,也能保证采样点在对数坐标上均匀分布,不会出现低光度段曲线失真的问题 - 误差带直接按拟合参数的±1σ范围计算上下包络即可,无需额外做误差传递近似,幂律关系在对数空间的线性误差直接对应原空间的包络范围。
内容的提问来源于stack exchange,提问作者zukofirenation
相关产品推荐
相关产品推荐

