HOWTO · Matplotlib
How to Rotate X-Axis Tick Label Text in Matplotlib
Learn five ways to rotate Matplotlib x-axis tick labels and align them when long labels overlap.
On this page
To rotate x-axis tick labels in Matplotlib, pass an angle such as rotation=45 to plt.xticks, fig.autofmt_xdate, ax.set_xticklabels, plt.setp, or ax.tick_params. A 45-degree angle is a useful starting point when long horizontal labels overlap; align the rotated labels with ha="right" to keep their ends near their ticks. The examples below show when each API is useful.
Without rotation, category names such as month names sit horizontally and fill the whole axis width, so longer names or a narrower figure make neighbouring labels run together:
Rotate x-axis tick labels with plt.xticks
plt.xticks is a concise option when working with pyplot. Its rotation keyword sets the angle in degrees; the default is horizontal. This example plots categories and rotates their labels by 45 degrees.
import matplotlib.pyplot as plt
months = ["January", "February", "March", "April"]
values = [12, 18, 15, 22]
fig, ax = plt.subplots()
ax.plot(months, values, marker="o")
plt.xticks(rotation=45, ha="right")
ax.grid(True)
fig.tight_layout()
Use plt.xticks for a quick change to the current axes. If your code already uses an Axes object, the corresponding methods below make the target axes explicit.
Rotate date-axis labels with fig.autofmt_xdate
For date-oriented plots, fig.autofmt_xdate formats the figure’s date labels and rotates them to improve readability. Its defaults also adjust alignment and the bottom margin; you can set rotation explicitly when you want a particular angle. Behavior depends on the figure’s axes and date format, so use it for date axes rather than as a general replacement for every tick-label setting.
import matplotlib.pyplot as plt
from datetime import date, timedelta
start = date(2024, 1, 1)
dates = [start + timedelta(days=7 * i) for i in range(6)]
values = [3, 5, 4, 7, 6, 9]
fig, ax = plt.subplots()
ax.plot(dates, values, marker="o")
fig.autofmt_xdate(rotation=45)
ax.grid(True)
This is convenient when the x-axis uses dates and their formatted labels need rotation and spacing. For ordinary categories, choose one of the tick-label methods in the other sections.
Set labels and rotation with ax.set_xticklabels
Use ax.set_xticklabels when you need to provide custom label text as well as its rotation. Set the tick positions explicitly first, and provide one label for each position so each string stays associated with the intended tick. Rotation alone does not require replacing the labels; use tick_params or plt.setp to keep the existing text.
import matplotlib.pyplot as plt
positions = [0, 1, 2, 3]
labels = ["North region", "South region", "East region", "West region"]
values = [8, 5, 9, 6]
fig, ax = plt.subplots()
ax.plot(positions, values, marker="o")
ax.set_xticks(positions)
ax.set_xticklabels(labels, rotation=45, ha="right")
ax.grid(True)
fig.tight_layout()
Keep the positions and labels in the same order. If the plot’s ticks change later, update the custom labels to match them.
Set label properties with plt.setp
plt.setp updates properties on existing Matplotlib artists, including the current x-axis tick-label objects returned by ax.get_xticklabels(). It is useful when the labels are already in place and you only want to change their appearance.
import matplotlib.pyplot as plt
categories = ["First quarter", "Second quarter", "Third quarter", "Fourth quarter"]
values = [14, 17, 13, 21]
fig, ax = plt.subplots()
ax.plot(categories, values, marker="o")
plt.setp(ax.get_xticklabels(), rotation=45, ha="right")
ax.grid(True)
fig.tight_layout()
Here, rotation changes the angle and ha sets horizontal alignment. This updates the current tick-label objects without replacing their text.
Set x-axis label rotation with ax.tick_params
ax.tick_params sets tick, tick-label, and grid-line properties for a chosen axis. Pass axis="x" and the lowercase labelrotation keyword to rotate x-axis labels while leaving their text and positions intact.
import matplotlib.pyplot as plt
categories = ["Planning", "Development", "Review", "Delivery"]
values = [2, 5, 3, 6]
fig, ax = plt.subplots()
ax.plot(categories, values, marker="o")
ax.tick_params(axis="x", labelrotation=45)
ax.grid(True)
fig.tight_layout()
Use this axis-level form when you already have an Axes reference. The keyword spelling is labelrotation, all lowercase.
Align rotated tick labels
Rotation changes the angle, while horizontal alignment controls which part of each label sits on its tick. With ha="right", the label’s right end meets the tick; with ha="left", its left end meets the tick; and with ha="center", its midpoint meets the tick. For 45-degree labels that extend to the left of their ticks, right alignment is a common choice. Try the options with your label lengths and chart layout.
import matplotlib.pyplot as plt
positions = [0, 1, 2, 3]
labels = ["January", "February", "March", "April"]
values = [4, 7, 5, 8]
alignments = ["right", "left", "center"]
fig, axes = plt.subplots(1, 3, figsize=(10, 3))
for ax, alignment in zip(axes, alignments):
ax.plot(positions, values, marker="o")
ax.set_xticks(positions)
ax.set_xticklabels(labels, rotation=45, ha=alignment)
ax.set_title(f'ha="{alignment}"')
ax.grid(True)
fig.tight_layout()
Select alignment based on where you want each label to anchor. If labels still feel crowded, adjust the figure width or label wording in addition to rotating them.
Handle clipped labels and label-count errors
Two failures remain after the rotation itself works. First, ax.set_xticklabels replaces the label text, so the number of labels must equal the number of tick positions. Passing three labels for four positions fails before anything is drawn:
import matplotlib.pyplot as plt
positions = [0, 1, 2, 3]
labels = ["North", "South", "East"]
values = [8, 5, 9, 6]
fig, ax = plt.subplots()
ax.plot(positions, values, marker="o")
ax.set_xticks(positions)
ax.set_xticklabels(labels, rotation=45, ha="right")
The call ends with this error:
ValueError: The number of FixedLocator locations (4), usually from a call to set_ticks, does not match the number of labels (3).
Add the missing label so the two sequences have the same length, in the same order. If you only need to rotate the existing text, prefer plt.setp or ax.tick_params instead: they keep the current labels, so this mismatch cannot occur.
Second, rotation changes the angle but does not create room below the axes. Render the set_xticklabels example above without its fig.tight_layout() call and the rotated labels run past the bottom edge of the figure — in a default-size render they extend about 31 pixels beyond the edge and are cut off mid-text:
fig.tight_layout() recalculates the figure box so every label fits; measured the same way, the labels then end exactly at the figure edge with nothing outside it. fig.autofmt_xdate makes the same kind of margin adjustment for date axes. If labels still collide after the layout adjustment, shorten the label text or widen the figure rather than increasing the angle.