Logarithmic & Symlog Scales

Reviewed & published by Brayan K

A logarithmic scale spaces an axis by powers rather than by equal steps, so data spanning many orders of magnitude fits in one chart and exponential growth straightens into a readable line.

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 switch axes to log with set_yscale('log'), use the loglog/semilogx/semilogy shortcuts, handle zeros and negatives with symlog, and tidy log ticks.

What You'll Learn in This Lesson

1 From Linear to Log

When values explode across magnitudes, a linear axis crushes the small numbers into a flat line near zero. Flip the axis with ax.set_yscale('log') and each gridline becomes a power of ten, so 1, 10, 100, and 1000 are evenly spaced and all visible at once.

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(0, 10)
y = 2 ** x   # 1, 2, 4, ... up to 512

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

# Left: linear — small values look flat
ax1.plot(x, y, marker="o", color="crimson")
ax1.set_title("Linear y-axis")

# Right: log — the same data is a straight line
ax2.plot(x, y, marker="o", color="teal")
ax2.set_yscale("log")
ax2.set_title("Log y-axis")

fig.tight_layout()
plt.show()
The chart this code draws: Compare the same exponential data on both scales
What this code draws, rendered with Matplotlib.

What you'll see: two panels of the same doubling data — on the left the early values hug the bottom while the last point shoots up, but on the right the log axis turns the whole series into a clean straight line.

2 loglog, semilogx & semilogy

Matplotlib offers one-call shortcuts that plot and set the scale together. ax.semilogy() logs the y-axis, ax.semilogx() logs the x-axis, and ax.loglog() logs both. A power law like y = x² becomes a straight line on a loglog plot, with the slope revealing the exponent.

import matplotlib.pyplot as plt
import numpy as np

x = np.logspace(0, 3, 50)   # 1 to 1000, log-spaced
y = x ** 2                  # a power law

fig, ax = plt.subplots()

# One call plots AND logs both axes
ax.loglog(x, y, marker=".", color="purple")

ax.set_title("Power Law on a loglog Plot")
ax.set_xlabel("x")
ax.set_ylabel("y = x squared")
ax.grid(True, which="both", linestyle="--", alpha=0.4)

plt.show()
The chart this code draws: See y = x squared as a straight line on log-log axes
What this code draws, rendered with Matplotlib.

3 Zeros & Negatives With symlog

A plain log scale cannot show zero or negative values. symlog (symmetric log) fixes this: it is linear in a small band around zero — set by linthresh — and logarithmic beyond it on both sides. That makes it perfect for data that crosses zero yet still spans large magnitudes.

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-100, 100, 400)
y = x ** 3   # ranges from -10^6 to +10^6 and passes through 0

fig, ax = plt.subplots()
ax.plot(x, y, color="darkgreen")

# Symlog: linear within +/-100, log outside it
ax.set_yscale("symlog", linthresh=100)

ax.set_title("Cubic on a symlog Axis")
ax.set_xlabel("x")
ax.set_ylabel("x cubed")
ax.grid(True, linestyle="--", alpha=0.4)

plt.show()
The chart this code draws: Plot data that crosses zero across huge magnitudes
What this code draws, rendered with Matplotlib.

What you'll see: the cubic curve sweeping from large negative to large positive values through zero — the symlog axis keeps the small middle readable while compressing the enormous tails on both ends.

🎯 Your Turn: Fill in the Blanks

Replace each ___ to plot growth data on a log y-axis.

import matplotlib.pyplot as plt
import numpy as np

days = np.arange(0, 15)
cases = 3 ** days   # tripling every day

fig, ax = plt.subplots()
ax.plot(days, cases, marker="o", color="darkred")

# Make the y-axis logarithmic
ax.set_yscale("___")

ax.set_title("Exponential Growth")
ax.set_xlabel("Day")
ax.set_ylabel("Cases")

# Display the figure
plt.___()

📋 Common Errors & Quick Reference

❌ My log plot is blank or warns about non-positive data

Log cannot handle 0 or negatives. ✅ Filter them out, or use set_yscale('symlog') which spans zero.

❌ symlog ignores my zero-crossing

The linear band is the wrong size. ✅ Tune linthresh= to roughly the smallest magnitude you care about.

❌ logit raised a ValueError

logit needs values strictly between 0 and 1. ✅ Keep your data inside the open interval (0, 1) — no exact 0 or 1.

CallWhat It Does
ax.set_yscale('log')Log y-axis
ax.semilogy(x, y)Plot + log y in one call
ax.loglog(x, y)Plot + log both axes
set_yscale('symlog', linthresh=1)Log that spans zero
set_yscale('logit')Stretch probabilities near 0 and 1

🎯 Mini-Challenge: Compare Three Growth Rates

Plot linear, quadratic, and exponential growth on a semilog y-axis so their very different scales all fit.

import matplotlib.pyplot as plt
import numpy as np

t = np.arange(1, 15)

fig, ax = plt.subplots()
ax.semilogy(t, t, marker="o", label="linear: t")
ax.semilogy(t, t ** 2, marker="s", label="quadratic: t^2")
ax.semilogy(t, 2.0 ** t, marker="^", label="exponential: 2^t")

ax.set_title("Three Growth Rates on a Log Axis")
ax.set_xlabel("t")
ax.set_ylabel("value (log)")
ax.legend()
ax.grid(True, which="both", linestyle="--", alpha=0.4)

plt.show()
The chart this code draws: Linear, quadratic, and exponential on one semilog axis
What this code draws, rendered with Matplotlib.
import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [10, 100, 1000, 10000, 100000]

fig, ax = plt.subplots()
ax.plot(x, y, marker="o")
ax.set_yscale("log")

fig.canvas.draw()

print("Y scale:", ax.get_yscale())
print("X scale:", ax.get_xscale())
print("Y tick positions:", [int(v) for v in ax.get_yticks() if v >= 1][:6])
print("Each step is 10x:", all(y[i + 1] / y[i] == 10 for i in range(len(y) - 1)))
print("Straight line on a log axis:", len(set(round(y[i+1]/y[i], 6) for i in range(len(y)-1))) == 1)

# ✅ Expected output:
# Y scale: log
# X scale: linear
# Y tick positions: [1, 10, 100, 1000, 10000, 100000]
# Each step is 10x: True
# Straight line on a log axis: True
The chart this code draws: The scale each axis is on, the tick positions a log axis picks, and the constant ratio that makes the line straight
What this code draws, rendered with Matplotlib.

❓ Frequently Asked Questions

Lesson complete — magnitudes hold no fear!

You switched axes to log, used the semilog and loglog shortcuts, recognized exponential growth as a straight line, and handled zeros and negatives with symlog.

Practice quiz

Which call switches an existing y-axis to a logarithmic scale?

  • ax.logy()
  • ax.set_ylog()
  • ax.set_yscale('log')
  • ax.yscale(log=True)

Answer: ax.set_yscale('log'). ax.set_yscale('log') flips the y-axis to a log scale.

On a log axis, what does a straight line indicate?

  • Exponential growth
  • Linear growth
  • Constant data
  • Random noise

Answer: Exponential growth. Equal distances on a log axis are equal ratios, so exponential growth becomes a straight line.

Which shortcut plots and logs BOTH axes in one call?

  • ax.semilogx()
  • ax.semilogy()
  • ax.plot(log=True)
  • ax.loglog()

Answer: ax.loglog(). ax.loglog(x, y) plots and sets both axes to log.

What does ax.semilogy(x, y) do?

  • Logs both axes
  • Plots and logs only the y-axis
  • Logs only the x-axis
  • Plots with no log scale

Answer: Plots and logs only the y-axis. semilogy logs the y-axis only while plotting in one call.

Why does a plain log scale fail on zero or negative data?

  • It needs integers
  • It requires sorted data
  • The log of zero is undefined and of a negative is complex
  • It only works on the x-axis

Answer: The log of zero is undefined and of a negative is complex. log(0) is undefined and log of a negative is complex, so those points drop or error.

Which scale handles data that crosses zero across large magnitudes?

  • log
  • logit
  • linear
  • symlog

Answer: symlog. symlog is linear near zero and logarithmic beyond it, so it spans zero and negatives.

What does the linthresh parameter control on a symlog scale?

  • The width of the linear band around zero
  • The color of the axis
  • The number of ticks
  • The line width

Answer: The width of the linear band around zero. linthresh sets how wide the linear region around zero is before the log behavior begins.

Which scale stretches values near 0 and near 1 for probabilities?

  • symlog
  • logit
  • log
  • linear

Answer: logit. The logit scale stretches regions near 0 and 1, ideal for proportions in (0, 1).

What does which='both' do in ax.grid() on a log axis?

  • Logs both axes
  • Removes the grid
  • Doubles the figure
  • Shows major and minor gridlines

Answer: Shows major and minor gridlines. which='both' draws major and minor gridlines, including the faint minor lines within each decade.

What input does the logit scale require?

  • Any real numbers
  • Only integers
  • Values strictly between 0 and 1
  • Only negative values

Answer: Values strictly between 0 and 1. logit needs values strictly in the open interval (0, 1) — no exact 0 or 1.

Continue this course

Frequently asked questions

When should I use a logarithmic scale?

Reach for a log scale when your data spans several orders of magnitude — say values from 1 to 1,000,000 — or when you care about multiplicative change like growth rates. On a log axis equal distances represent equal ratios, so exponential growth becomes a straight line and small and large values are both readable in one chart.

What is the difference between set_yscale('log') and semilogy()?

They do the same thing in two styles. ax.set_yscale('log') flips an existing axes to a log y-axis, while ax.semilogy(x, y) is a shortcut that plots and sets the log y-scale in one call. Similarly semilogx logs the x-axis and loglog logs both. Use whichever reads more cleanly in your code.

Why does my log plot fail or show gaps with zero or negative data?

The logarithm of zero is undefined and of a negative number is complex, so a plain log scale drops or errors on those points. Use 'symlog' instead: it is linear in a small band around zero and logarithmic beyond it, so it handles zeros and negatives gracefully while still compressing large magnitudes.

What is the logit scale for?

The logit scale is designed for probabilities and proportions strictly between 0 and 1. It stretches the regions near 0 and near 1 so differences like 0.99 versus 0.999 become visible, which a linear axis would squash together. Set it with ax.set_yscale('logit') when plotting things like accuracy or survival fractions.