Search code examples
pythonmatplotlibgridlines

Find all shared x-axes in matplotlib and turn off the grid on siblings


I'd like to find all shared x-axes siblings (ax_2 = ax_1.twinx()) in a pyQt / matplotlib application and turn off their grid.

I tried fiddling around with ax.get_shared_x_axes().get_siblings(ax) but this seems overly complicated. I'm looking for a solution similar to the following pseudo-code

for ax in all_axes:
    if hasattr(ax,"is_sibling"):
        ax.grid(False)

Edit:

My fiddling around so far is (drawing heavily from http://matplotlib.1069221.n5.nabble.com/get-parent-or-child-from-twinx-or-twiny-td2038.html):

for ax in self.fig.axes:
    shared_x = [ax2 for ax2 in ax.get_shared_x_axes().get_siblings(ax) if ax2 is not ax]
    for ax2 in shared_x:
        ax2.grid(False)

The list comprehension is supposed to find all sibling axes of ax but not ax itself. This nearly works, however, the grid of left axis (the "original" axis) is turned off but not the grid of the right axis. I find the documentation of get_shared_x_axes() very unhelpful, I don't even understand what is returned.

Edit 2:

Another, maybe simpler approach, could be to find all axes with y-labels on the right hand side but I have no idea how to do that.


Solution

  • There is no way of knowing with certainty which axes of a group of shared axes is the one which has been created via twinx. But there are ways to get close to it.

    Use custom attribute

    First let me mention that you may of course create the attribute to query yourself.

    import matplotlib.pyplot as plt
    plt.rcParams["axes.grid"] = True
    
    fig, axes = plt.subplots(2,2)
    ax5 = axes[0,1].twinx()
    ax5.is_sibling = True
    ax5.plot([2,4,3])
    ax6 = axes[1,0].twinx()
    ax6.plot([.1,.5,.6])
    ax6.is_sibling = True
    
    
    # later query the is_sibling attribute
    for ax in fig.axes:
        if hasattr(ax,"is_sibling"):
            ax.grid(False)
    
    plt.tight_layout()
    plt.show()
    

    This is by far the cleanest solution.

    Find twinx axes by order

    It seems that in the list of axes obtained via ax.get_shared_x_axes().get_siblings(ax), the original axes is always in the second position.

     [twin axes, original axes, possible further shared axes]
    

    Hence you may use

    for ax in fig.axes:
        shared_x = ax.get_shared_x_axes().get_siblings(ax)
        if len(shared_x) > 1:
            for a in [a for i,a in enumerate(shared_x) if i is not 1]:
                a.grid(False)
    

    However, I did not find any reason for this always be the case, it is hence just an assumption, which may prove wrong in certain cases.

    Find twinx by properties

    In case the axes you are looking for are shared axes with their ticks on the right side and having the same position as the original axes, one may query those properties. Note however that you might also create twin axes with their labels on the left side, so this also depends on how the axes were created.

    def is_twinx(ax):
        s = ax.get_shared_x_axes().get_siblings(ax)
        if len(s) > 1:
            for ax1 in [ax1 for ax1 in s if ax1 is not ax]:
                if ax1.bbox.bounds == ax.bbox.bounds:
                    if ax.yaxis.get_ticks_position() == "right":
                        return True
        return False
    
    for ax in fig.axes:
        if is_twinx(ax):
            ax.grid(False)