Getting Started

How xticks and xticklabels Really Work: a Walkthrough

Henry Alpert
Towards Data Science
5 min readAug 17, 2021

--

Photo by Markus Winkler on Unsplash

I was recently creating visualizations in Seaborn, which is based on Matplotlib, and when labeling the x-axis, I wasn’t getting the results I was expecting. I decided to take a step back and experiment to see what xticks and xticklabels actually do in a visualization.

Let’s break it down.

A Basic Plot

First, I created a dataframe with two columns of 100 rows. The first column assigns each row a random number 1 through 15, the second assigns each row a random number 16 through 30.

np.random.seed(0)
col1 = np.random.randint(1, 16, size=100).tolist()
col2 = np.random.randint(16, 31, size=100).tolist()
df = pd.DataFrame({'col1': col1, 'col2': col2})

Using Seaborn’s countplot method, I tested out the first column.

ax = sns.countplot(x = df['col1'])
Image by author

When I ran a cell with len(df.loc[df['col1'] == 4]), I got 12, which matches my visualization. In other words, 12 rows in this column of 100 rows are part of the category bin 4. So far, so good.

Let’s look at the column with the higher numbers.

ax = sns.countplot(x = df['col2'])
Image by author

The results look similar to the first one. The labels show the numbers 16 through 30 as expected.

Adding Some Ticks

Suppose instead 15 potential values along the x-axis, I had 100? Or 200? The axis labels would get way too crowded to be legible.

The point of the xticks property is show values only at certain spots along the x-axis. So, let’s try displaying just three, spaced-out values using xticks.

ax = sns.countplot(x = df['col1'])
ax.set(xticks=([0, 7, 14]))
Image by author

Notice how in ax.set(xticks=([0, 7, 14]), the numbers refer to indices. The number 1 is at the 0 index of xticks, then it goes to index 7 which is number 8 in the dataframe, and then it goes to index 14 which is number 15 in the dataframe. But see how the xticks count off 1, 2, 3 and not 1, 8, 15.

And what about with the higher-count column?

ax = sns.countplot(x = df['col2'])
ax.set(xticks=[0, 7, 14])
Image by author

Again, in ax.set(xticks=([0, 7, 14]), the numbers refer to indices. The number 16 is at the 0 index of xticks, then it goes to index 7 which is number 23 in the dataframe, and then it goes to index 14 which is number 30 in the dataframe. The visualizations’ values are still fine along the y-axis, but see how the xticks count off 16, 17, 18 and not 16, 23, 30.

To sum up, counting starts at the value of the first index, which makes sense. But then, along the x-axis, the label goes up by 1 each time, regardless of the value of that categorical bin.

And I should note, it’s only going up by 1 each time, because my bins are integers that increment by one. I made a new column, col3, with 100 random numbers between 1 and 30 made up of even numbers only.

The standard plot is what you’d expect:

ax = sns.countplot(x = df['col3'])
Image by author

When I choose the same indices as in the other examples, the xticks count off by 2.

ax = sns.countplot(x = df['col3'])
ax.set(xticks=[0, 7, 14])
Image by author

And the xticks count off 2, 4, 6 and not 2, 16, 30.

Out of curiosity, let’s see what happens if I put the xticks beyond the values of the dataframe. Using the column with lower numbers again:

ax = sns.countplot(x=df['col1'])
ax.set(xticks=([0, 7, 14, 21]))
Image by author

In this visualization, I added another index, 21, to the list of xticks, one that is higher than any index that would refer to a category bin value. As you can see, it extends the x-axis to show a blank area.

One more thing: Although the list passed to xticks() refers to indices, you can use floats to put ticks between the indices if desired.

Specify the Labels

To gain control over what the labels display, set the ax’s xticklabels property:

ax = sns.countplot(x=df['col1'])
ax.set(xticks=([0, 7, 14]))
ax.set(xticklabels = (['one', 'eight', 'fifteen']))
Image by author

Cool. I got the result I was looking for. Strings or numbers can be used. Note that if I hadn’t set the xticks for the ax at some point, the three labels would be placed in the first three indices, or [0, 1, 2].

Also, note in all the above examples that I used the general Axes.set() function and then passed keyword arguments.

For more control over the ticks and their labels, use Axes.set_xticks() and Axes.set_xticklabels(). With the latter, you can specify various font properties, the rotation of the label, and more.

ax = sns.countplot(x=df['col1'])
ax.set_xticks([0, 7, 14])
ax.set_xticklabels(labels = ['one', 'eight', 'fifteen'],
rotation=45,
fontstyle='italic',
color='green')
Image by author

Summary

  • If you don’t specify anything, all ticks will be placed automatically.
  • Use ax.set(xticks=[a, b, c]) or ax.set_xticks([a, b, c]) to choose specific places to add ticks at indices.
  • If you don’t specify labels, the first tick will take the value of the first index entered. Then, subsequent values will be used at the ticks even though they may not refer to the actual values at the rest of the indices.
  • Use ax.set(xticklabels=[a, b, c]) or ax.set_xticklabels([a, b, c]) to choose labels (strings or numbers) to add ticks at the set indices.
  • To control the labels’ appearance and text properties, use set_xticklabels() with keyword arguments.

--

--