Tick Locators & Formatters

Reviewed & published by Brayan K

Tick locators decide where the marks on an axis go, while tick formatters decide how each mark's value is written — together they give you complete control over axis labels.

Part of the free Matplotlib course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

In this lesson you'll set ticks by hand, place them with MaxNLocator and MultipleLocator, reformat numbers with FuncFormatter and PercentFormatter, rotate crowded labels, and add minor ticks.

What You'll Learn in This Lesson

1 Setting Ticks by Hand

The most direct approach: call ax.set_xticks() with the positions where ticks should sit, then ax.set_xticklabels() with the text for each. This is ideal when you plot against numeric positions but want friendly labels like month names underneath.

import matplotlib.pyplot as plt

months = ["Jan", "Feb", "Mar", "Apr", "May"]
sales = [120, 145, 130, 160, 175]

fig, ax = plt.subplots(figsize=(7, 4), constrained_layout=True)
ax.plot(range(5), sales, marker="o")

# Place ticks at positions 0..4, then label them with month names
ax.set_xticks(range(5))
ax.set_xticklabels(months)

ax.set_title("Monthly Sales")
ax.set_ylabel("Units")
plt.show()
The chart this code draws: Place ticks at numeric positions and label them with text
What this code draws, rendered with Matplotlib.

What you'll see: a five-point line of monthly sales rising overall, with the x-axis marked Jan through May instead of the raw numbers 0 to 4.

2 Locators: MultipleLocator & MaxNLocator

When the data range varies, hard-coding ticks is fragile. Locators place them by a rule instead. MultipleLocator(2) puts a tick at every multiple of 2, while MaxNLocator(5) picks at most five nicely rounded values. Both live in matplotlib.ticker and attach via ax.xaxis.set_major_locator().

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MultipleLocator, MaxNLocator

x = np.linspace(0, 20, 200)
y = np.sin(x)

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6), constrained_layout=True)

# Top: a tick every 2 units on x, every 0.5 on y
ax1.plot(x, y)
ax1.xaxis.set_major_locator(MultipleLocator(2))
ax1.yaxis.set_major_locator(MultipleLocator(0.5))
ax1.set_title("MultipleLocator: ticks at fixed steps")

# Bottom: at most 5 nicely-rounded ticks
ax2.plot(x, y, color="darkorange")
ax2.xaxis.set_major_locator(MaxNLocator(5))
ax2.set_title("MaxNLocator: at most 5 tidy ticks")

plt.show()
The chart this code draws: Place ticks by a rule with MultipleLocator and MaxNLocator
What this code draws, rendered with Matplotlib.

What you'll see: two sine waves. The top one has evenly stepped gridlike ticks every 2 units on x and 0.5 on y; the bottom one shows just a handful of clean, rounded x-ticks chosen automatically.

3 Formatters: Currency, Percent & More

A formatter rewrites each tick's number. PercentFormatter(xmax=1.0) turns 0.25 into 25%. FuncFormatter runs your own function on every value — perfect for currency. StrMethodFormatter("{x:,.0f}") applies a format string with thousands separators. Attach any of them with ax.yaxis.set_major_formatter().

What you'll see: two panels. The left bars have y-axis labels like $1,200 and $2,400; the right line has y-axis labels like 10% and 30% — the same numbers dressed up for their audience.

🎯 Your Turn: Fill in the Blanks

Replace each ___ to rotate the long day labels so they stop overlapping.

import matplotlib.pyplot as plt

days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
visits = [340, 280, 410, 390, 460]

fig, ax = plt.subplots(figsize=(7, 4), constrained_layout=True)
ax.bar(days, visits, color="steelblue")

# Put ticks under each bar, then rotate the labels 45 degrees
ax.set_xticks(range(5))
ax.set_xticklabels(days, rotation=___, ha="right")

ax.set_title("Daily Visits")
plt.show()

Hint: 45 degrees with ha="right" is the classic fix for crowded labels.

📋 Common Errors & Quick Reference

❌ Labels are shifted off their ticks

You set labels without matching positions. Call set_xticks(positions) first, then set_xticklabels(labels) with the same count.

❌ TypeError: FuncFormatter takes 2 arguments

Your formatter function must accept both value and position: lambda v, pos: ..., even if you ignore pos.

❌ ImportError on the locator/formatter

Import from the right module: from matplotlib.ticker import MultipleLocator, FuncFormatter, PercentFormatter.

ToolWhat It Does
MultipleLocator(n)Tick at every multiple of n
MaxNLocator(k)At most k tidy ticks
PercentFormatter()Show values as percentages
FuncFormatter(fn)Custom text from your function

🏆 Mini Challenge: Major & Minor Ticks

Plot exponential growth with major ticks every 2 and minor ticks every 0.5, format the y-axis with thousands separators, and add a two-level grid.

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MultipleLocator, StrMethodFormatter

x = np.linspace(0, 10, 300)
y = np.exp(0.3 * x)

fig, ax = plt.subplots(figsize=(8, 5), constrained_layout=True)
ax.plot(x, y, color="crimson")

# Major ticks every 2, minor ticks every 0.5
ax.xaxis.set_major_locator(MultipleLocator(2))
ax.xaxis.set_minor_locator(MultipleLocator(0.5))

# Format y-axis numbers with thousands separators
ax.yaxis.set_major_formatter(StrMethodFormatter("{x:,.0f}"))

# Show a grid that uses both major and minor ticks
ax.grid(which="major", linestyle="-", alpha=0.5)
ax.grid(which="minor", linestyle=":", alpha=0.3)

ax.set_title("Growth with Major & Minor Ticks")
plt.show()
The chart this code draws: Combine locators, a formatter, and a two-level grid
What this code draws, rendered with Matplotlib.
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter

fig, ax = plt.subplots()
ax.plot([0, 1, 2, 3, 4], [0, 2500, 5000, 7500, 10000])

ax.yaxis.set_major_formatter(FuncFormatter(lambda v, pos: f"£{v:,.0f}"))
ax.set_xticks([0, 1, 2, 3, 4], labels=["Mon", "Tue", "Wed", "Thu", "Fri"])

fig.canvas.draw()

print("X tick labels:", [t.get_text() for t in ax.get_xticklabels()])
print("Y tick labels:", [t.get_text() for t in ax.get_yticklabels()])
print("Formatter used:", type(ax.yaxis.get_major_formatter()).__name__)
print("Locator after set_xticks:", type(ax.xaxis.get_major_locator()).__name__)
print("Number of x ticks:", len(ax.get_xticks()))

# ✅ Expected output:
# X tick labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
# Y tick labels: ['£-2,000', '£0', '£2,000', '£4,000', '£6,000', '£8,000', '£10,000', '£12,000']
# Formatter used: FuncFormatter
# Locator after set_xticks: FixedLocator
# Number of x ticks: 5
The chart this code draws: The labels a formatter produced, and what set_xticks quietly did to the locator
What this code draws, rendered with Matplotlib.

❓ Frequently Asked Questions

Lesson complete — your axes now say exactly what you mean!

You set ticks by hand, placed them with MultipleLocator and MaxNLocator, reformatted numbers with FuncFormatter and PercentFormatter, rotated long labels, and added minor ticks.

Practice quiz

What does a tick LOCATOR control?

  • The chart's colormap
  • The figure size
  • How each tick number is written
  • WHERE the ticks are placed on an axis

Answer: WHERE the ticks are placed on an axis. A locator decides where ticks go; a formatter decides how each is written.

Which pair sets tick positions and their text labels by hand?

  • ax.ticks() and ax.labels()
  • ax.set_locator() and ax.set_text()
  • ax.set_xticks() and ax.set_xticklabels()
  • ax.xticks() and ax.xlabels()

Answer: ax.set_xticks() and ax.set_xticklabels(). set_xticks(positions) then set_xticklabels(labels) places labels manually.

Which locator puts a tick at every multiple of a value?

  • MaxNLocator(n)
  • MultipleLocator(n)
  • AutoLocator(n)
  • FixedLocator(n)

Answer: MultipleLocator(n). MultipleLocator(2) places a tick at every multiple of 2.

What does MaxNLocator(5) do?

  • Picks at most 5 nicely-rounded tick values
  • Places exactly 5 random ticks
  • Removes all but 5 data points
  • Limits the axis to 5 units

Answer: Picks at most 5 nicely-rounded tick values. MaxNLocator(5) chooses at most five tidy, rounded tick values.

Which formatter turns 0.25 into 25%?

  • FuncFormatter(xmax=1.0)
  • StrMethodFormatter('%')
  • ScalarFormatter()
  • PercentFormatter(xmax=1.0)

Answer: PercentFormatter(xmax=1.0). PercentFormatter(xmax=1.0) renders fractions as percentages.

How many arguments must a FuncFormatter function accept?

  • Zero
  • Exactly one
  • Two — the value and its position
  • Three

Answer: Two — the value and its position. A FuncFormatter receives the value and its position; both must be in the signature.

Which module holds MultipleLocator and FuncFormatter?

  • matplotlib.pyplot
  • matplotlib.ticker
  • matplotlib.axes
  • matplotlib.scale

Answer: matplotlib.ticker. Locators and formatters live in matplotlib.ticker.

Which call attaches a locator to the x-axis?

  • ax.xaxis.set_major_locator(loc)
  • ax.set_locator(loc)
  • ax.xticks(loc)
  • ax.locator_x(loc)

Answer: ax.xaxis.set_major_locator(loc). ax.xaxis.set_major_locator() attaches the locator to the x-axis.

How do you stop long category labels from overlapping?

  • Hide the x-axis entirely
  • Make the figure smaller
  • Use a logarithmic scale
  • Rotate them, e.g. rotation=45, ha='right'

Answer: Rotate them, e.g. rotation=45, ha='right'. set_xticklabels(labels, rotation=45, ha='right') keeps crowded labels readable.

What does StrMethodFormatter('{x:,.0f}') add to numbers?

  • Percent signs
  • Thousands separators
  • Scientific notation
  • Currency symbols

Answer: Thousands separators. The format string {x:,.0f} adds thousands separators to each tick value.

Continue this course

Frequently asked questions

What is the difference between a locator and a formatter?

A locator decides WHERE ticks are placed on an axis — for example one every 2 units, or at most 5 tidy values. A formatter decides HOW each tick's number is written — as currency, a percentage, or with thousands separators. You usually set them with ax.xaxis.set_major_locator() and ax.xaxis.set_major_formatter().

When should I use set_xticks vs a locator?

set_xticks(positions) plus set_xticklabels(labels) is perfect when you have a small fixed set of labels, like month names. A locator such as MaxNLocator or MultipleLocator is better when the data range changes and you want ticks to follow a rule automatically rather than listing them by hand.

How do I format axis numbers as percentages or currency?

Use the ticker module. PercentFormatter(xmax=1.0) turns 0.25 into 25%. For currency or custom text, FuncFormatter(lambda v, pos: f'${v:,.0f}') runs your own function on every tick value. StrMethodFormatter('{x:,.0f}') adds thousands separators with a format string.

How do I rotate tick labels so they stop overlapping?

Long category names crowd the x-axis. Pass rotation to set_xticklabels, for example set_xticklabels(labels, rotation=45, ha='right'). The ha='right' alignment keeps each rotated label anchored neatly under its tick. plt.setp() and fig.autofmt_xdate() are alternatives for dates.