loglog图中的寄生x轴

时间:2019-02-11 23:00:14

标签: python matplotlib axis loglog

我有一个图,其中x轴是GeV中的温度,但是我还需要以开尔文为单位引用温度,因此我想到了将寄生虫轴以K为温度。回答How to add a second x-axis in matplotlib,这是代码示例。我在图形的顶部获得了第二个轴,但这并不是我需要的以K为单位的温度。

import numpy as np
import matplotlib.pyplot as plt

tt = np.logspace(-14,10,100)
yy = np.logspace(-10,-2,100)

fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()

ax1.loglog(tt,yy)
ax1.set_xlabel('Temperature (GeV')

new_tick_locations = np.array([.2, .5, .9])

def tick_function(X):
    V = X*1.16e13
    return ["%.1f" % z for z in V]

ax2.set_xlim(ax1.get_xlim())
ax2.set_xticks(new_tick_locations)
ax2.set_xticklabels(tick_function(ax1Xs))
ax2.set_xlabel('Temp (Kelvin)')
plt.show()

这是我运行代码时得到的。

loglog图 loglog plot

我需要将寄生轴与原始x轴成比例。而且,当有人看到图表时,可以很容易地读取开尔文中的温度。预先感谢。

2 个答案:

答案 0 :(得分:1)

问题似乎是由于以下原因:当您使用ax2.set_xlim(ax1.get_xlim())时,基本上是将上x轴的限制设置为与下x轴的限制相同。现在,如果您这样做

print(ax1.get_xlim()) 
print(ax2.get_xlim()) 

两个轴的值都与

相同
(6.309573444801943e-16, 158489319246.11108) 
(6.309573444801943e-16, 158489319246.11108) 

,但是您的下部x轴具有对数比例尺。当您使用ax2.set_xlim()分配限制时,ax2的限制相同,但是比例仍然是 linear 。这就是为什么在[.2, .5, .9]处设置刻度时,这些值在图中的x轴最左端显示为刻度的原因。

解决方案是将上部x轴也设置为对数刻度。这是必需的,因为您的new_tick_locations对应于下部x轴上的实际值。您只想重命名这些值以在开尔文中显示刻度标签。从变量名可以清楚地看出new_tick_locations对应于新的刻度位置。我使用new_tick_locations的一些修改后的值来突出问题。

我正在使用科学格式'%.0e',因为1 GeV = 1.16e13 K,所以0.5 GeV是一个非常大的值,有很多零。

下面是一个示例答案:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick

tt = np.logspace(-14,10,100)
yy = np.logspace(-10,-2,100)

fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()

ax1.loglog(tt,yy)
ax1.set_xlabel('Temperature (GeV)')

new_tick_locations = np.array([0.000002, 0.05, 9000])

def tick_function(X):
    V = X*1.16e13
    return ["%.1f" % z for z in V]

ax2.set_xscale('log') # Setting the logarithmic scale
ax2.set_xlim(ax1.get_xlim())

ax2.set_xticks(new_tick_locations)
ax2.set_xticklabels(tick_function(new_tick_locations))
ax2.xaxis.set_major_formatter(mtick.FormatStrFormatter('%.0e'))

ax2.set_xlabel('Temp (Kelvin)')
plt.show()

enter image description here

答案 1 :(得分:1)

通用解决方案可能如下所示。由于您具有非线性刻度,因此可以在开尔文中找到漂亮刻度线的位置,转换为GeV,以GeV为单位设置位置,但以开尔文为单位标记它们。这听起来很复杂,但是优点是您不需要自己找到刻度线,只需依靠matplotlib即可找到刻度线。 不过,这需要两个量表之间的函数依赖性,即GeV和Kelvin之间的转换及其反函数。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker

tt = np.logspace(-14,10,100)
yy = np.logspace(-10,-2,100)

fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()

plt.setp([ax1,ax2], xscale="log", yscale="log")
ax1.get_shared_x_axes().join(ax1, ax2)

ax1.plot(tt,yy)

ax1.set_xlabel('Temperature (GeV)')
ax2.set_xlabel('Temp (Kelvin)')

fig.canvas.draw()

# 1 GeV == 1.16 × 10^13 Kelvin
Kelvin2GeV = lambda k:  k / 1.16e13
GeV2Kelvin = lambda gev: gev * 1.16e13

loc = mticker.LogLocator()
locs = loc.tick_values(*GeV2Kelvin(np.array(ax1.get_xlim())))

ax2.set_xticks(Kelvin2GeV(locs))
ax2.set_xlim(ax1.get_xlim())

f = mticker.ScalarFormatter(useOffset=False, useMathText=True)
g = lambda x,pos : "${}$".format(f._formatSciNotation('%1.10e' % GeV2Kelvin(x)))
fmt = mticker.FuncFormatter(g)
ax2.xaxis.set_major_formatter(mticker.FuncFormatter(fmt))

plt.show()

enter image description here