如何(重新)缩放 x 轴以适合图中的某些点?

How to (re)scale the x-axis to fit certain points in the graph?

我想重新调整我的(定性)x 轴,使两个峰值(图中可见)与其实际值(即 500 keV 和 1274 MeV)相关。 我该怎么做?

import numpy as np
import matplotlib.pyplot as plt

def read_from_file(filename):
    return np.loadtxt(filename)

data = list(read_from_file("calibration.txt"))

print(data.index(max(data[:2000])))#x value 500kev
print(data.index(max(data[2000:])))#x value 1274

fig = plt.figure()
ax = fig.add_subplot(111)
x = range(len(data))
plt.plot(x, data)
plt.xlim(0, 5000)
plt.ylim(0, 7000)
plt.title("$^{22}$Na Spectrum")
plt.xlabel("Energy")
plt.ylabel("Amount of Photons")
plt.grid()
ax.annotate("500 keV", xy = (1450, 6541), xytext = (1600, 6500))
ax.annotate("1274 MeV", xy = (3500, 950), xytext = (3700, 1100))
plt.show()

使用numpy,你可以使用argmax.

找到两个尖峰的索引(即不需要将数据转换为列表)

然后,您可以使用以下方法缩放 x 值:

xnew = val1 + (x - max1) / (max2 - max1) * (val2 - val1)

其中 val1val2 是峰值的值,max1max2 是这些峰值的索引。

下面是一些应该有效的代码:

import numpy as np
import matplotlib.pyplot as plt

# Fake some data approximately in your range. You can ignore this bit!
# Random numbers for noise
data = 1000. + np.random.rand(5000) * 100.
x = np.arange(len(data))
# Add the first spike
mu1, sd1 = 1450., 300.
pdf1 = (1./(sd1*2.*np.pi) * np.exp(-(x - mu1)**2 / sd1**2)) * 1e7
data += pdf1
# Add the second spike
mu2, sd2 = 3500., 200.
pdf2 = (1./(sd2*2.*np.pi) * np.exp(-(x - mu2)**2 / sd2**2)) * 1e6
data += pdf2
# End of fake data generation

# Find the index of the first maximum (using your '2000' cutoff)
cutoff = 2000
max1 = float(np.argmax(data[:cutoff]))
# Find the index of the second cutoff
max2 = float(np.argmax(data[cutoff:]) + cutoff)

# The actual values of the two spikes
val1, val2 = 500., 1274

# Scale the xvalues
xnew = val1 + (x - max1) / (max2 - max1) * (val2 - val1)

# Plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xnew, data)
ax.set_ylim(0, 7000)
ax.set_title("$^{22}$Na Spectrum")
ax.set_xlabel("Energy")
ax.set_ylabel("Number of Photons")
ax.grid()

# Add some lines at the actual spikes to check scaling worked
ax.axvline(val1)
ax.axvline(val2)

plt.show()

有趣的是你应该问这个问题。我目前正在尝试将一个示例推送到 MatPlotLib 中,以准确显示如何执行此操作。您可以在这里查看食谱:https://github.com/madphysicist/matplotlib/blob/7b05223c85741120019b81e1248c20f9bc090c61/examples/ticks_and_spines/tick_transform_formatter.py

您不需要示例中的整个代码(或使用它的刻度格式化程序),但映射函数将帮助您创建缩放的 x-array(另外,使用 np.argmax 而不是index(max(...)):

ind500 = np.argmaxmax(data[:2000]))
ind1274 = np.argmax(data[2000:])) + 2000
x_scaled = (x - ind500) * (1274 - 500) / (ind1274 - ind500) + 500

您可以像往常一样使用x_scaled绘图:

plt.plot(x_scaled, data)
...

将它们组合在一起(并进行一些调整以使用 OO API 而不是 pyplot):

import numpy as np
from matplotlib import pyplot as plt

data = np.loadtxt("calibration.txt") # Don't convert this back to a list

ind500 = np.argmaxmax(data[:2000]))
ind1274 = np.argmax(data[2000:])) + 2000
x = (np.arange(len(data)) - ind500) * (1274 - 500) / (ind1274 - ind500) + 500

fig, ax = plt.subplots()
ax.plot(x, data)
plt.title("$^{22}$Na Spectrum")
plt.xlabel("Energy")
plt.ylabel("Photons Counts")
plt.grid()
ax.annotate("500 keV", xy = (500, data[ind500]), xytext = (550, data[ind500] + 100))
ax.annotate("1274 keV", xy = (1274, data[ind1274]), xytext = (1324, data[ind1274] + 100))
plt.show()

我链接到的示例将允许您以完全不同的单位显示 x-axis,而无需实际修改您的 x-array。