Matplotlib:第二轴上的twinx()错误值

时间:2017-08-01 14:22:48

标签: python numpy matplotlib plot

当我尝试为主要plt.twinx()绘制辅助x轴时,我遇到了matplotlib.pyplot ln(x)-axis函数的问题。它们应显示相应的值,但具有不同的刻度。为清楚起见,这是我迄今为止在MWE中所尝试的内容:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator

fig = plt.figure(1)
ax1 = fig.add_subplot(111)

ax1.set_xlabel(r'$ln(\sigma)$')
ax1.set_xticks([5.2,5.3,5.4,5.5,5.6,5.7,5.8])
ax1.set_xlim([5.2,5.8])
ax1.plot(5.6,0.5,'o')

ax2 = ax1.twiny()
ax2.set_xlabel(r'$\sigma$')
ax2.set_xlim(np.exp(ax1.get_xlim()))
ax2.xaxis.set_major_locator(MultipleLocator(base=25))

plt.show()

这会生成以下图表,该图表首先看起来像需要但有问题,即辅助x-ticks是错误的。

plot with wrong secondary x-values

该点位于x1 = 0.5,但相应的辅助x值位于x2 =~ 280,但毕竟应位于x2 = math.exp(5.6) =~ 270

我不确定这是一个绘图问题还是一个不同尺度的深度数学问题。

当我没有设置ax2.xlim()但只是将主要x-tick加倍并使用matplotlib.ticker.FuncFormatter将辅助x-tick格式化为np.exp(ax1.get_xticlocs())时,它可以正常工作次要蜱是奇怪的"值。

1 个答案:

答案 0 :(得分:1)

这里出了什么问题

这是因为两个x标度之间的映射是非线性的(它是指数/对数)。实际上,您将一个轴作为对数刻度,另一个轴作为正常刻度。根据您如何定义限制,两者在端点上重合,但不在两者之间。这个想法如下所示。 "映射值"在y轴上绘制x2与x1值的关系。我标记的蓝线"仅端点"是你所期望的,但是"完整的域名"映射是现实中发生的事情。

import matplotlib.pyplot as plt
import numpy as np

# Endpoints only
x01 = np.array([5.2,5.8])
y01 = np.exp(x01)

# Full domain
x = np.linspace(5.2,5.8,100)
y = np.exp(x)

plt.plot(x01,y01,label='endpoints only')
plt.plot(x,y, label='full domain')
plt.legend()
plt.show()

enter image description here

这里有一条路

在日志刻度上实例化两个轴。在您的情况下,您需要自然日志,因此我们传递basex=np.e。然后,您需要在两个轴上手动指定刻度线位置。在ax1中,我们只使用预先指定的位置;对于ax2,您可以使用指定MultipleLocator后生成的位置。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator

fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.set_xscale('log', basex=np.e)

# Array of tick locations...use the true value (not log value)
locs = np.exp(np.array([5.2,5.3,5.4,5.5,5.6,5.7,5.8]))

ax1.set_xlabel(r'$ln(\sigma)$')
ax1.set_xlim([locs[0],locs[-1]])
ax1.set_xticks(locs)
ax1.set_xticklabels(np.log(locs))

ax2 = ax1.twiny()
ax2.set_xscale('log', basex=np.e)
ax2.set_xlabel(r'$\sigma$')
ax2.set_xlim((ax1.get_xlim()))
ax2.xaxis.set_major_locator(MultipleLocator(base=25))
# Manually set the tick labels to match the positions your set with the locator
ax2.set_xticklabels(['{:.0f}'.format(k) for k in ax2.get_xticks()])  

ax1.plot(locs,locs*0+.4,'o')
ax2.plot(locs,locs*0+.6,'o',color='C1')
ax1.set_ylim([0,1])

plt.show()

enter image description here