Search code examples
pythonmatplotlibplotaxesmultiple-axes

matplotlib axes.Axes.secondary_xaxis in a loop: only the last figure in the loop is correct


The code below seems to work fine. However, if I change the stop value of range (the max value of m), I realized only the last figure has the secondary axis plotted correctly. The secondary axis of all figures before the last ones seems to follow the scale of the secondary axis on the last figure.

import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator,
                               AutoMinorLocator,
                               FixedLocator)

dataX = [0, 1 , 2 , 3, 4]  #trivial
dataY = dataX

for m in range(1, 3): #try to change the number "3" and compare the results.
    print(m)
    fig, ax = plt.subplots(dpi=300)
    secax = ax.secondary_xaxis('top',
                               functions=(lambda x: x*m*10,
                                          lambda x: x/m/10))
    ax.plot(dataX, dataY, 'k', ls='dashed', marker='o')
    ax.set_title(f'figure {m}')

    ### below is only to compare between figures, i set the same tick location ###
    Xtick_loc = [0, 1, 2, 3, 4]
    sec_Xtick_loc = []
    for xp in Xtick_loc:
        sec_Xtick_loc.append(xp*m*10)
    print(Xtick_loc, sec_Xtick_loc)

    ax.xaxis.set_major_locator(FixedLocator(Xtick_loc))
    secax.xaxis.set_major_locator(FixedLocator(sec_Xtick_loc))

It will be clear when you compare the same "Figure 1" but for different stop value of the loop.

Did I make a mistake? Is there any solution for this problem? Thanks before!


Solution

  • If I use secax = ax.twiny() it works for me. Essentially, you modify your original axes, then create a twin top secondary axis and change the tick labels. See the following code and plots (which I didn't post):

    import matplotlib.pyplot as plt
    from matplotlib.ticker import (MultipleLocator,
                                   AutoMinorLocator,
                                   FixedLocator)
    
    dataX = [0, 1 , 2 , 3, 4]  #trivial
    dataY = dataX
    
    for m in range(1, 4): #try to change the number "3" and compare the results.
        print(m)
        fig, ax = plt.subplots(dpi=300)
    
        ax.plot(dataX, dataY, 'k', ls='dashed', marker='o')
        ax.set_title(f'figure {m}')
    
        ### below is only to compare between figures, i set the same tick location ###
        Xtick_loc = [0, 1, 2, 3, 4]
        sec_Xtick_loc = []
        for xp in Xtick_loc:
            sec_Xtick_loc.append(xp*m*10)
        print(Xtick_loc, sec_Xtick_loc)
    
        ax.xaxis.set_major_locator(FixedLocator(Xtick_loc))
    
        # Added code below:
        secax = ax.twiny()
        secax.set_xlim(ax.get_xlim())
        secax.xaxis.set_major_locator(FixedLocator(Xtick_loc))
        secax.xaxis.set_ticklabels(sec_Xtick_loc)