【问题标题】:Matplotlib: how to set ticks of twinned axis in log plotMatplotlib:如何在对数图中设置孪生轴的刻度
【发布时间】:2013-12-05 09:32:39
【问题描述】:

在我的绘图中,辅助 x 轴用于显示某些数据的另一个变量的值。现在,原始轴是对数缩放的。不幸的是,孪生轴将刻度(和标签)放在原始轴的线性刻度上,而不是按照对数刻度的意图。如何克服?

这里的代码示例应该将孪生轴的刻度与原始轴的刻度放在相同(绝对轴)位置:

    def conv(x):
        """some conversion function"""
        # ...
        return x2

    ax = plt.subplot(1,1,1)
    ax.set_xscale('log')

    # get the location of the ticks of ax
    axlocs,axlabels = plt.xticks()

    # twin axis and set limits as in ax
    ax2 = ax.twiny()
    ax2.set_xlim(ax.get_xlim())

    #Set the ticks, should be set referring to the log scale of ax, but are set referring to the linear scale
    ax2.set_xticks(axlocs)

    # put the converted labels
    ax2.set_xticklabels(map(conv,axlocs))

另一种方法是(然后刻度不会设置在同一位置,但这没关系):

    from matplotlib.ticker import FuncFormatter

    ax = plt.subplot(1,1,1)
    ax.set_xscale('log')

    ax2 = ax.twiny()
    ax2.set_xlim(ax.get_xlim())
    ax2.xaxis.set_major_formatter(FuncFormatter(lambda x,pos:conv(x)))  

只要不使用对数刻度,这两种方法都可以很好地工作。

也许有一个简单的解决方法。我在文档中遗漏了什么吗?

作为一种解决方法,我尝试获取 ax 刻度的 ax.transAxes 坐标,并将刻度放在 ax2 中的相同位置。但是不存在类似的东西

    ax2.set_xticks(axlocs,transform=ax2.transAxes)
    TypeError: set_xticks() got an unexpected keyword argument 'transform'

【问题讨论】:

  • 我有点不清楚您的实际问题是什么,如果您可以添加一些随机数据甚至是显示问题的图表,这将是有帮助的。您是否考虑过仅对第二个变量进行对数缩放?
  • 感谢您的回复。这也是我的第一个想法。但是,设置 ax2.set_xscale('log') 不起作用。它根据标签对刻度重新排序。因此,与数据和 ax 的连接丢失。我会尽快用一些图来说明这个问题。
  • 不,我的意思是实际记录值本身——这样更容易理解发生了什么。
  • 那肯定行得通,因为线性刻度仍然存在。然而,这并不是我的目标。我更喜欢物理值(磁场梯度强度)的对数图,而不是对数值的线性图。因为在后一种情况下,观察者不能直接看到梯度强度,而是首先需要应用指数。

标签: python matplotlib


【解决方案1】:

这已经被问过一段时间了,但我偶然发现了同样的问题。

我最终设法通过引入对数缩放 (semilogx) 透明 (alpha=0) 虚拟图来解决问题。

例子:

import numpy as np
import matplotlib.pyplot as plt

def conversion_func(x):  # some arbitrary transformation function
    return 2 * x**0.5        # from x to z

x = np.logspace(0, 5, 100)
y = np.sin(np.log(x))

fig = plt.figure()

ax = plt.gca()
ax.semilogx(x, y, 'k')
ax.set_xlim(x[0], x[-1])  # this is important in order that limits of both axes match
ax.set_ylabel("$y$")
ax.set_xlabel("$x$", color='C0')
ax.tick_params(axis='x', which='both', colors='C0')
ax.axvline(100, c='C0', lw=3)

ticks_x = np.logspace(0, 5, 5 + 1)  # must span limits of first axis with clever spacing
ticks_z = conversion_func(ticks_x)
ax2 = ax.twiny()  # get the twin axis
ax2.semilogx(ticks_z, np.ones_like(ticks_z), alpha=0)  # transparent dummy plot
ax2.set_xlim(ticks_z[0], ticks_z[-1])
ax2.set_xlabel("$z \equiv f(x)$", color='C1')
ax2.xaxis.label.set_color('C1')
ax2.tick_params(axis='x', which='both', colors='C1')
ax2.axvline(20, ls='--', c='C1', lw=3)  # z=20 indeed matches x=100 as desired

fig.show()

在上面的例子中,垂直线表明第一个和第二个轴确实可以根据需要相互移动。 x = 100 转移到 z = 2*x**0.5 = 20。颜色只是为了说明哪条垂直线与哪个轴相配。

【讨论】:

    【解决方案2】:

    不需要覆盖它们,只需消除蜱虫!

    d= [7,9,14,17,35,70];
    j= [100,80,50,40,20,10];
    
    plt.figure()
    plt.xscale('log')
    plt.plot(freq, freq*spec)  #plot some spectrum
    
    ax1 = plt.gca()  #define my first axis 
    ax1.yaxis.set_ticks_position('both')
    ax1.tick_params(axis='y',which='both',direction='in');
    ax1.tick_params(axis='x',which='both',direction='in');
    
    ax2 = ax1.twiny()  #generates second axis (top) 
    ax2.set_xlim(ax1.get_xlim());  #same limits
    plt.xscale('log')  #make it log
    
    ax2.set_xticks(freq[d]); #my own 'major' ticks OVERLAPS!!! 
    ax2.set_xticklabels(j);  #change labels
    
    ax2.tick_params(axis='x',which='major',direction='in'); 
    ax2.tick_params(axis='x',which='minor',top=False); #REMOVE 'MINOR' TICKS
    ax2.grid()
    

    【讨论】:

      猜你喜欢
      • 2013-02-21
      • 1970-01-01
      • 1970-01-01
      • 2021-06-14
      • 2016-07-15
      • 2013-01-20
      • 1970-01-01
      • 2012-05-13
      • 1970-01-01
      相关资源
      最近更新 更多