matplotlib 颜色条交替顶部底部标签

2022-01-25 00:00:00 python matplotlib colorbar labels

问题描述

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 every other label to avoid texts overlapping, one alternative might be to alternate the label position so that one retains all labels and avoids overlapping (if there isn't a crazy number of labels) as well, which is what this post aims to solve:

How to make matplotlib colorbar with alternating top and bottom labels?

解决方案

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)

相关文章