# How to adjust the x axis tick labels so they fit in the screen
In order to make the labels fit, we're going to rotate the labels.
That way, they'll take up less space horizontally and more space vertically. In addition, since all the labels will be rotated by the same amount, they won't intersect each other.
We can do this with plt.xticks()
, which allows us to configure the x ticks of a plot:
import matplotlib.pyplot as plt
def create_bar_chart(polls):
figure = plt.figure(figsize=(8, 8))
figure.subplots_adjust(bottom=0.35)
axes = figure.add_subplot(1, 1, 1)
axes.set_title("Polls to their vote counts")
axes.set_ylabel("Vote count")
axes.bar(
range(len(polls)),
[poll[1] for poll in polls],
tick_label=[poll[0] for poll in polls]
)
plt.xticks(rotation=30)
return figure
Note that I'm calling the plt
library directly, and not using the object-oriented approach.
# Using the object-oriented approach
WARNING
The object-oriented approach is perfectly valid, but it is more advanced. It changes some properties of the figure that we haven't learned about, and as such it can produce some unwanted effects.
I'll show you how to use the object-oriented approach, but do remember this warning for your future projects!
To use the object-oriented approach we use axes.set_xticklabels()
:
import matplotlib.pyplot as plt
def create_bar_chart(polls):
figure = plt.figure(figsize=(8, 8))
figure.subplots_adjust(bottom=0.35)
axes = figure.add_subplot(1, 1, 1)
axes.set_title("Polls to their vote counts")
axes.set_ylabel("Vote count")
axes.bar(
range(len(polls)),
[poll[1] for poll in polls],
tick_label=[poll[0] for poll in polls]
)
axes.set_xticklabels([poll[0] for poll in polls], rotation=30)
return figure
The object-oriented approach replaces the x tick labels by new ones, so we need to pass in the labels again.
Since we must do this, we might be tempted to remove them from the axes.bar()
call, like so:
import matplotlib.pyplot as plt
def create_bar_chart(polls):
figure = plt.figure(figsize=(8, 8))
figure.subplots_adjust(bottom=0.35)
axes = figure.add_subplot(1, 1, 1)
axes.set_title("Polls to their vote counts")
axes.set_ylabel("Vote count")
axes.bar(
range(len(polls)),
[poll[1] for poll in polls]
)
axes.set_xticklabels([poll[0] for poll in polls], rotation=30)
return figure
But if we do this, we're no longer telling the axes how many ticks there are, and so it reverts back to generating its own ticks.
We have 6 bars in our chart, starting at position 0
, and ending at position 5
(given by our range(len(polls))
). Therefore we must give a name to the tick at each index.
And by default, matplotlib creates one tick too many at each end of our provided values. That means that if you have 6 polls, you end up with ticks [-1, 0, 1, 2, 3, 4, 5, 6]
rather than [0, 1, 2, 3, 4, 5]
.
When we do set_xticklabels()
though, we're giving names to the ticks that exist in order, which means ticks [-1, 0, 1, 2, 3, 4]
end up with labels, and ticks [5, 6]
end up without labels.
Hence just using set_xticklabels()
will often not to exactly what you want.
It's necessary when using set_xticklabels()
to also use set_xticks()
to define what the x ticks are:
import matplotlib.pyplot as plt
def create_bar_chart(polls):
figure = plt.figure(figsize=(8, 8))
figure.subplots_adjust(bottom=0.35)
axes = figure.add_subplot(1, 1, 1)
axes.set_title("Polls to their vote counts")
axes.set_ylabel("Vote count")
axes.bar(
range(len(polls)),
[poll[1] for poll in polls]
)
axes.set_xticks(range(len(polls)))
axes.set_xticklabels([poll[0] for poll in polls], rotation=30)
return figure
But now we're back to the original state of duplication!
Using set_xticks()
and set_xticklabels()
affords us greater flexibility, rather than just letting plt.xticks()
use its default behaviour. However, it's a bit more work and there's more going on behind the scenes.
That means they are a bit more complicated for our use case.
That's why, for now, I recommend using plt.xticks()
for this rather than the object-oriented approach.
I generally discourage mixing the functional and object-oriented approaches, but in this case I think it's worth it.
# Aligning text in our labels
Let's go back to the functional approach:
import matplotlib.pyplot as plt
def create_bar_chart(polls):
figure = plt.figure(figsize=(8, 8))
figure.subplots_adjust(bottom=0.35)
axes = figure.add_subplot(1, 1, 1)
axes.set_title("Polls to their vote counts")
axes.set_ylabel("Vote count")
axes.bar(
range(len(polls)),
[poll[1] for poll in polls],
tick_label=[poll[0] for poll in polls]
)
plt.xticks(rotation=30)
return figure
If we run this with our data, we'll see that the text isn't quite aligned right. We've rotated it, but the anchor point is in its centre. That means the text now appears to have moved to the right.
We can right-align the text so its rotation anchor point will be at the right:
import matplotlib.pyplot as plt
def create_bar_chart(polls):
figure = plt.figure(figsize=(8, 8))
figure.subplots_adjust(bottom=0.35)
axes = figure.add_subplot(1, 1, 1)
axes.set_title("Polls to their vote counts")
axes.set_ylabel("Vote count")
axes.bar(
range(len(polls)),
[poll[1] for poll in polls],
tick_label=[poll[0] for poll in polls]
)
plt.xticks(rotation=30, ha="right")
return figure
The ha
parameter stands for "horizontal alignment".
And with that, we're done! Our chart now looks excellent and the labels are visible!