Python visualization demystified

Rotating Axis Labels in Matplotlib

A look at all the ways you can rotate axis labels in Matplotlib

An entire post on how to rotate axis labels?? Yes indeed. After playing around with Matplotlib for some time, I could never remember how to rotate axis labels. Part of the reason it's hard to remember is that there are a plethora of ways to do it. In this post, we'll go through all the ways I've uncovered, with a few recommendations of which to use and when.

Just want the answers? Scroll to the very bottom.

Get our data

Let's get some simple data to use for this example. We'll use the EPA's gas efficiency dataset.

import matplotlib.pyplot as plt
import pandas as pd

fuel_economy = pd.read_csv('https://raw.githubusercontent.com/getup8/datasets/master/2019_Car_Fuel_Economy.csv')
fields = ['Manufacturer', 'Comb FE (Guide) - Conventional Fuel']
df = fuel_economy[fields].copy()
df.rename(columns={'Comb FE (Guide) - Conventional Fuel': 'Combined MPG'},
          inplace=True)
# Get the top 10 manufacturers by their average MPG.
dfg = df.groupby('Manufacturer').mean().sort_values(
    'Combined MPG', ascending=False)
df = dfg[:10].reset_index()
# Get the rest, we'll use these later for an example.
df2 = dfg[10:].reset_index()

df
Manufacturer Combined MPG
0 Honda 28.375000
1 Mitsubishi Motors Co 28.375000
2 MAZDA 28.285714
3 Kia 28.000000
4 Hyundai 26.672727
5 Toyota 26.663366
6 Subaru 25.954545
7 Volvo 25.050000
8 BMW 23.950820
9 Volkswagen Group of 23.746032

Plot our data

Let's just create a simple bar chart to see what we're working with.

fig, ax = plt.subplots()

ax.bar(df['Manufacturer'], df['Combined MPG'])

matplotlib simple bar chart

It's a mess! We need to rotate the axis labels...

Let's go through all the ways in which we can do this one by one.

Option 1: plt.xticks()

plt.xticks() is probably the easiest way to rotate your labels. The only "issue" is that it's using the "stateful" API (not the Object-Oriented API); that sometimes doesn't matter but in general, it's recommended to use OO methods where you can. We'll show an example of why it might matter a bit later.

fig, ax = plt.subplots()
ax.bar(df['Manufacturer'], df['Combined MPG'])

plt.xticks(rotation=30)

matplotlib bar chart label rotation

Looks better-ish but the alignment is funky. That's because, by default, Matplotlib aligns the center of the text to the tick. When you rotate the text, this no longer works so we need to change the alignment to right-aligned, like this:

# `ha` is just shorthand for horizontalalignment, which can also be used.
plt.xticks(rotation=30, ha='right')

matplotlib bar chart label alignment

Bueno.

Note: Throughout this post we'll just focus on the x-axis but know you can do the exact same thing for the y-axis as well - just substitute x for y (e.g. plt.xticks() -> plt.yticks())

Where plt.xticks() doesn't really work

Let's say you now want to plot two bar charts in the same figure.

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5))

ax1.bar(df['Manufacturer'], df['Combined MPG'])
ax1.set_ylim(0, 30)

ax2.bar(df2['Manufacturer'], df2['Combined MPG'])
ax2.set_ylim(0, 30)

# This only works for the last chart, even if we call it
# right after we create ax1!
plt.xticks(rotation=30, ha='right')

matplotlib two bar charts plt alignment fail

As you can see, only the last chart gets adjusted correctly. This is because the plt method finds the current Axes object (each bar chart here is a separate Axes object) and just modifies that one.

If you're just plotting one chart and doing EDA, this method is great. Otherwise, it's probably best to get used to using an OO method below.

Option 2: ax.set_ticklabels()

Let's first try using the Axes method set_ticklabels(). This method takes the labels themselves as a required first parameter.

ax.set_xticklabels(df['Manufacturer'], rotation=30, ha='right')

matplotlib bar chart label alignment

But what if you want don't want to manually give the labels? Why can't we just tell Matplotlib to re-use what it already has? You can - using ax.get_xticklabels() - but with some nuance.

ax.set_xticklabels(ax.get_xticklabels(), rotation=30, ha='right')

matplotlib bar chart no label

What happened? Long story short, Matplotlib doesn't attach the labels to the chart until the very end, when the chart is drawn. So if you try to call get_xticklabels() before that, you get empty strings. A relatively hacky fix is just to draw the chart before calling the method.

# Draw the chart so labels are actually attached to the Axes object.
plt.draw()

ax.set_xticklabels(ax.get_xticklabels(), rotation=30, ha='right')

matplotlib bar chart label alignment

Let's try adjusting both charts using this method.

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5))

ax1.bar(df['Manufacturer'], df['Combined MPG'])
ax1.set_ylim(0, 30)

ax2.bar(df2['Manufacturer'], df2['Combined MPG'])
ax2.set_ylim(0, 30)

plt.draw()

ax1.set_xticklabels(ax1.get_xticklabels(), rotation=30, ha='right')
ax2.set_xticklabels(ax2.get_xticklabels(), rotation=30, ha='right')

matplotlib two bar charts aligned

Nice. This is a great method to know how to use but it's relatively verbose and comes with the caveat about needing to make sure the figure has been drawn before calling the get method.

Option 3: ax.get_xticklabels()

In this method, you get a list of the labels, loop through each one, and set rotation and alignment for each. A few nice things about this method:

  • It uses the OO API
  • It's pretty intuitive. Get the labels. For each, set rotation and alignment.
  • It doesn't actually touch the value of the labels themselves (like the previous method), it just adjusts the formatting. This means no weird caveats.
for label in ax.get_xticklabels():
  label.set_rotation(30)
  label.set_ha('right')

Have multiple charts? Just concat the lists together and do it all in one loop.

for label in ax1.get_xticklabels() + ax2.get_xticklabels():
  label.set_rotation(30)
  label.set_ha('right')

Option 4: ax.tick_params()

This option is relatively simple but comes with a big drawback at the moment - you can't currently set alignment. However, there's an open feature request to allow it, so stay tuned!

# No horizontal alignment option!
ax.tick_params(axis='x', labelrotation=30)

# Need this as well :/
plt.xticks(ha='right')

Option 5: plt.setp()

plt.setp is a powerful method that allows you to set the properties of many (all?) Matplotlib objects. Here we use it by handing it the set of tick labels and setting the rotation and alignment properties for them.

plt.setp(ax.get_xticklabels(), rotation=30, ha='right')

While this looks like it's not OO, it actually is since you're using ax.get_xticklabels().

This works equally well when you have multiple charts:

plt.setp(ax1.get_xticklabels() + ax2.get_xticklabels(), rotation=30, ha='right')

matplotlib two bar charts aligned

A Summary

As you can see, there are almost too many options when deciding how to do this. I think it's good to know all the methods honestly, but in the future, when label alignment is available, it will probably be "best" to use ax.tick_params(). But really, to each their own.

# Option 1
plt.xticks(rotation=30, ha='right')

# Option 2
plt.draw()
ax.set_xticklabels(ax.get_xticklabels(), rotation=30, ha='right')

# Option 3
for label in ax.get_xticklabels():
  label.set_rotation(30)
  label.set_ha('right')

# Option 4
ax.tick_params(axis='x', labelrotation=30)
# Eventually, this shouldn't be needed and an `ha` argument should
# be available for the above.
plt.xticks(ha='right')

# Option 5
plt.setp(ax.get_xticklabels(), rotation=30, ha='right')

Have yet MORE ways to do this or have a strong recommendation of which to use? Let me know :)