Multiple lines of x tick labels
Asked Answered
P

5

33

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.

Parian answered 12/12, 2013 at 0:14 Comment(3)
A good example of multiple axes is here: #7762278 Is this close enough?Intellect
This is similar to what I want, but I don't want there to be a physical second x-axis. I basically want to add a second line of text to the first axis which can be moved irrespective of the first. i.e. 'Background' is always in the same position, but '5 Year Summary' can be moved to the left or right depending on how many plots are added to the graph.Parian
It's easy enough to hide the second axis. Overall, it's not quite clear how you want things to vary.. what's locked to what? You can use text, annotate or axis and spines (even if you don't show the actual axis associated with these two). Which will be easiest for you is dependent not on the picture you show, but on what you want to different items to register to (for both when you scale the plot and when you change the inputs). Currently, that's all unclear (ie, when you move '5 year Summary' moved wrt what?).Intellect
U
29

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' )
Unwish answered 12/12, 2013 at 14:50 Comment(0)
P
14

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.

Phytohormone answered 19/2, 2016 at 7:42 Comment(0)
P
2

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"])
Pentobarbital answered 5/5, 2022 at 8:7 Comment(0)
T
1

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!

Tobacconist answered 3/4, 2020 at 16:53 Comment(0)
P
0

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

Parian answered 12/12, 2013 at 13:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.