pythonnumpymatplotlibtwiny

Secondary x-Axis with different Labels & Ticks


I want to plot something with two x-axes. However the xticks don't align. Somehow the margins are ignored?! In the final version, the xlabels are different that means simply showing the axis at the top is not an option.

import matplotlib.pyplot as plt
import numpy as np 

fig = plt.figure(figsize=(10.0, 4.0))
axs = fig.subplots(2, 2)

xticklabels = [str(x) for x in range(0, 40+1, 5)]
y = np.random.rand(41*8)
ax0 = axs[0,0].twiny()
axs[0,0].set_xticks(np.arange(0,41*8,5*8))
axs[0,0].set_xticklabels(xticklabels)
ax0.set_xlim(axs[0,0].get_xlim())
ax0.set_xticks(np.arange(0,41*8,5*8))
ax0.set_xticklabels(xticklabels)

axs[0,0].plot(y)

plt.show()

enter image description here

EDIT: Actually I want to have something like this:

import matplotlib.pyplot as plt
import numpy as np 

fig = plt.figure(figsize=(10.0, 4.0))
axs = fig.subplots(2, 2)

xticklabels = [str(x) for x in range(0, 40+1, 5)]
y = np.random.rand(41*8)
ax0 = axs[0,0].twiny()
axs[0,0].set_xticks(np.arange(0,41*8,5*8))
axs[0,0].set_xticklabels(xticklabels)
ax0.set_xlim(axs[0,0].get_xlim())
ax0.set_xticks(np.arange(10*8,31*8,5*8))
ax0.set_xticklabels(["0", "25", "50", "75", "100"])

axs[0,0].plot(y)

plt.show()

enter image description here

But as you can see the ticks don't align. I'm getting crazy!


Solution

  • If you just want to show a second x-axis (without plotting anything on it) it may be easier with a secondary axis. You'll have to change the functions as needed:

    import matplotlib.pyplot as plt
    import numpy as np 
    
    y = np.random.rand(41*8)
    
    fig,ax = plt.subplots()
    ax.set_xticks(np.arange(0,41*8,5*8))
    xticklabels = [str(x) for x in range(0, 41, 5)]
    ax.set_xticklabels(xticklabels)
    
    secx = ax.secondary_xaxis('top', functions=(lambda x: x/8, lambda x: x/8))
    
    ax.plot(y)
    plt.show()
    

    enter image description here


    I assume that the problem with twiny is due to the absence of data on the new Axes, but I didn't manage to get it working, even after manually setting the data interval.


    Update as per comment and edited question:

    secx = ax.secondary_xaxis('top', functions=(lambda x: 5*x/8-50, lambda x: 5*x/8-50))
    secx.set_xticks([0,25,50,75,100])
    secx.set_xticklabels([f'{x}' for x in secx.get_xticks()])
    

    enter image description here