matplotlib colorbar alternating top bottom labels

前端 未结 2 902
情歌与酒
情歌与酒 2021-01-27 09:55

First of all, this was intended as a self-answer question, because I believe it would be helpful in certain situations, e.g. in this post the author tried to hide

2条回答
  •  旧巷少年郎
    2021-01-27 10:12

    Jump to a simple working example:

    import numpy
    import matplotlib.pyplot as plt
    
    #------------------Get some data------------------
    X = numpy.arange(100)
    Y = numpy.arange(100)
    Z = numpy.arange(100**2).reshape((100,100))
    
    levels=numpy.arange(0,100**2,1000)
    ltop=levels[::2]           # labels appear on top
    lbot=levels[1:][::2]       # labels appear at bottom
    
    #-----------------------Plot-----------------------
    f = plt.figure()
    ax = f.gca()
    
    cf = ax.contourf(X,Y,Z,100)
    cbar=plt.colorbar(cf,orientation='horizontal',ticks=lbot,drawedges=True)
    
    vmin=cbar.norm.vmin
    vmax=cbar.norm.vmax
    
    #-------------Print bottom tick labels-------------
    cbar.ax.set_xticklabels(lbot)
    
    #--------------Print top tick labels--------------
    for ii in ltop:
        cbar.ax.text((ii-vmin)/(vmax-vmin), 1.5, str(ii), transform=cbar.ax.transAxes, va='bottom', ha='center')
    
    plt.show(block=False)
    

    Basically the bottom labels are plotted using the default method cbar.ax.set_xticklabels(lbot). For the top labels, I added them manually using cbar.ax.text().

    The plot looks like this:

    EDIT: IMPORTANT UPDATE TO MY ANSWER:

    When the colorbar has extend/overflow, a triangle is used on the relevant end to indicate value overflow. In such cases the top line tick labels need some adjustment to properly align with colorbar sections.

    By default the triangle size is 5% of the colorbar axis, this is used to get the proper offset and scaling to align the labels.

    See an example below which has extends on both ends. Using my previous method, the result looks like this:

    The 2 end numbers at top line are aligned with the tip of the triangles. If only one end has extend and the number of contour levels are big (>=10 or so), the misalignment will get worse.

    The plot after correction:

    And this is the code to generate the correct plot:

    import numpy
    import matplotlib.pyplot as plt
    
    #------------------Get some data------------------
    X = numpy.linspace(-1,1,100)
    Y = numpy.linspace(-1,1,100)
    X,Y=numpy.meshgrid(X,Y)
    Z=numpy.sin(X**2)
    
    levels=numpy.linspace(-0.8,0.8,9)
    
    ltop=levels[::2]           # labels appear on top
    lbot=levels[1:][::2]       # labels appear at bottom
    
    #-----------------------Plot-----------------------
    f = plt.figure()
    ax = f.gca()
    
    cf = ax.contourf(X,Y,Z,levels,extend='both')
    cbar=plt.colorbar(cf,orientation='horizontal',ticks=lbot,drawedges=True)
    
    #------------Compute top tick label locations------------
    vmin=cbar.norm.vmin
    vmax=cbar.norm.vmax
    
    if cbar.extend=='min':
        shift_l=0.05
        scaling=0.95
    elif cbar.extend=='max':
        shift_l=0.
        scaling=0.95
    elif cbar.extend=='both':
        shift_l=0.05
        scaling=0.9
    else:
        shift_l=0.
        scaling=1.0
    
    #-------------Print bottom tick labels-------------
    cbar.ax.set_xticklabels(lbot)
    
    #--------------Print top tick labels--------------
    for ii in ltop:
        cbar.ax.text(shift_l + scaling*(ii-vmin)/(vmax-vmin),
            1.5, str(ii), transform=cbar.ax.transAxes,
            va='bottom', ha='center')
    
    plt.show(block=False)
    

提交回复
热议问题