Multiple lines of x tick labels

46.3k views Asked by At

I'm trying to make a plot similar to this excel example:

example

I would like to know if there is anyways to have a second layer on the x tick labels (e.g. "5 Year Statistical Summary"). I know I can make multi-line tick labels using \n but I want to be able to shift the two levels independently.

5

There are 5 answers

0
HHains On

The best solution I've found is to use the plt.annotate function. It's described well here: in the last comment

0
behzad.nouri On

this gets close:

xtick

fig = plt.figure( figsize=(8, 4 ) )
ax = fig.add_axes( [.05, .1, .9, .85 ] )
ax.set_yticks( np.linspace(0, 200, 11 ) )

xticks = [ 2, 3, 4, 6, 8, 10 ]
xticks_minor = [ 1, 5, 7, 9, 11 ]
xlbls = [ 'background', '5 year statistical summary', 'future build',
          'maximum day', '90th percentile day', 'average day' ]

ax.set_xticks( xticks )
ax.set_xticks( xticks_minor, minor=True )
ax.set_xticklabels( xlbls )
ax.set_xlim( 1, 11 )

ax.grid( 'off', axis='x' )
ax.grid( 'off', axis='x', which='minor' )

# vertical alignment of xtick labels
va = [ 0, -.05, 0, -.05, -.05, -.05 ]
for t, y in zip( ax.get_xticklabels( ), va ):
    t.set_y( y )

ax.tick_params( axis='x', which='minor', direction='out', length=30 )
ax.tick_params( axis='x', which='major', bottom='off', top='off' )
0
asccondor On

Here is a Matplotlib reference/example for multiple x-tick lines: Multiline

it uses the same approach as omegamanda

ax1.set_xticks([0.2, 0.4, 0.6, 0.8, 1.],
               labels=["Jan\n2009", "Feb\n2009", "Mar\n2009", "Apr\n2009",
                       "May\n2009"])
0
omegamanda On

I'm unable to comment on behzad's answer due to lack of reputation. I found his solution to be immensely helpful, but I thought I'd share that instead of controlling the vertical alignment by using set_y(), I just added a newline character to vertically offset the labels. So, for the above example:

xlbls = [ 'background', '\n5 year statistical summary', 'future build',
      '\nmaximum day', '\n90th percentile day', '\naverage day' ]

For me, this was a better solution for keeping multi-lined labels and multi-layered labels vertically aligned.

0
aputman On

I am also unable to comment due to reputation but have a minor fix for behzad's answer.

The tick_params() 'bottom' and 'top' keywords take booleans, not strings (at least for py3.6). For example, using bottom = 'off' for me still produces ticks whereas using bottom = False removes ticks.

so replace

ax.tick_params( axis='x', which='major', bottom='off', top='off' )

with

ax.tick_params( axis='x', which='major', bottom=False, top=False )

and it works!