简体   繁体   中英

Matplotlib: how to set ticks of twinned axis in log plot

In my plot, a secondary x axis is used to display the value of another variable for some data. Now, the original axis is log scaled. Unfortunaltely, the twinned axis puts the ticks (and the labels) referring to the linear scale of the original axis and not as intended to the log scale. How can this be overcome?

Here the code example that should put the ticks of the twinned axis in the same (absolute axes) position as the ones for the original axis:

    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))

An alternative way would be (the ticks are then not set in the same position, but that doesn't matter):

    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)))  

Both approaches work well as long as no log scale is used.

Perhaps there exists an easy fix. Is there something I missed in the documentation?

As a workaround, I tried to obtain the ax.transAxes coordinates of the ticks of ax and put the ticks at the very same position in ax2. But there does not exist something like

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

This has been asked a while ago, but I stumbled over it with the same question.

I eventually managed to solve the problem by introducing a logscaled ( semilogx ) transparent ( alpha=0 ) dummy plot.

Example:

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()

具有不同对数刻度的第二(双)轴的 matplotlib 图。

In the above example the vertical lines demonstrate that first and second axis are indeed shifted to one another as wanted. x = 100 gets shifted to z = 2*x**0.5 = 20 . The colours are just to clarify which vertical line goes with which axis.

Don't need to cover them, just Eliminate the ticks!

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM