HOWTO · Matplotlib
How to Plot Logarithmic Axes in Matplotlib
Plot logarithmic axes in Matplotlib with set_yscale(), semilogy(), or loglog().
On this page
Use set_xscale() or set_yscale() to choose the scale of either axis independently. For a logarithmic scale on both axes, use loglog(). The semilogx() and semilogy() helpers apply a logarithmic scale to the x-axis or y-axis, respectively. A logarithmic axis spaces its ticks by powers of ten, so data that spans several orders of magnitude stays readable instead of crowding into the lowest decade of a linear axis.
Every code example below was executed successfully.
set_xscale() or set_yscale() Functions
Call set_xscale("log") to scale the x-axis, set_yscale("log") to scale the y-axis, or both to scale both axes. Because the two calls are independent, you can convert exactly one axis and leave the other linear.
To make only the x-axis logarithmic, plot the data as usual and then call set_xscale("log") on the axes:
import matplotlib.pyplot as plt
x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]
fig, ax = plt.subplots()
ax.plot(x, y, marker="o")
ax.set_xscale("log")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)
The printed result confirms that only the x-axis changed: x-axis: log, y-axis: linear. The decade ticks at 1, 10, 100 and 1000 are spaced evenly even though the values themselves grow by a factor of ten.
To make only the y-axis logarithmic, call set_yscale("log") instead and leave the x-axis untouched:
import matplotlib.pyplot as plt
x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]
fig, ax = plt.subplots()
ax.plot(x, y, marker="o")
ax.set_yscale("log")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)
This time the printout reads x-axis: linear, y-axis: log, and the y-axis carries the evenly spaced decade ticks.
The pyplot state-machine interface offers the same change as the top-level functions plt.xscale() and plt.yscale(), which act on the current axes. The yscale() variant of the same plot looks like this:
import matplotlib.pyplot as plt
x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]
plt.plot(x, y, marker="o")
plt.yscale("log")
plt.xlabel("x")
plt.ylabel("y")
ax = plt.gca()
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close()
The result is the same logarithmic y-axis; the axes-object methods are usually clearer in programs that keep an explicit ax reference, because the target axes is named in the call instead of implied by the current figure.
Calling both methods on the same axes scales both axes, which is the combination this article’s earlier version used as its only set_xscale()/set_yscale() example:
import matplotlib.pyplot as plt
x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]
fig, ax = plt.subplots()
ax.plot(x, y, marker="o")
ax.set_xscale("log")
ax.set_yscale("log")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)
The printout now reports x-axis: log, y-axis: log, and equal ratios occupy equal distances along both axes.
A standard log scale represents positive values. If your data includes signed values, use symlog for the relevant axis, for example ax.set_yscale("symlog"); it can display values on both sides of zero. The last section returns to this case with a verified example.
semilogx() or semilogy() Functions
Use semilogx() when the x-axis should be logarithmic and the y-axis should remain linear. Use semilogy() for a logarithmic y-axis and linear x-axis. Both helpers accept the x and y data as arguments, so the selected scale is explicit in the plotting call. If both axes should be logarithmic, use loglog() or combine semilogx() with semilogy() on the same axes.
The semilogx() call below plots the data and sets the logarithmic x-axis in one step:
import matplotlib.pyplot as plt
x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]
fig, ax = plt.subplots()
ax.semilogx(x, y, marker="o", label="logarithmic x")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend()
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)
The helper returns the plotted line, and the axes reports x-axis: log, y-axis: linear afterwards, exactly as with the explicit set_xscale("log") call in the first section.
Combining the two helpers on one axes produces a logarithmic scale on both axes. Keep in mind that a scale belongs to the axes, not to a single plotted line: once semilogy() sets the y-axis, that scale applies to every series the axes holds, including the one drawn earlier by semilogx().
import matplotlib.pyplot as plt
x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]
y2 = [3, 8, 30, 120]
fig, ax = plt.subplots()
ax.semilogx(x, y, marker="o", label="first series")
ax.semilogy(x, y2, marker="s", label="second series")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend()
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)
Both series end up on logarithmic x and y axes, and the printout confirms the final state: x-axis: log, y-axis: log.
loglog() Function
Use loglog() when both axes need logarithmic scales. It plots the supplied x and y data and sets both axes to the standard logarithmic scale. Here is a complete example with positive numeric values:
import matplotlib.pyplot as plt
x = [1, 10, 100, 1000]
y = [2, 5, 20, 80]
fig, ax = plt.subplots()
ax.loglog(x, y, marker="o")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)
The rendered result matches the set_xscale("log") plus set_yscale("log") combination from the first section; loglog() simply folds the scale choice into the plotting call itself.
Non-Positive Values and Invalid Scale Names
Two things regularly surprise users of logarithmic axes, and both are worth knowing before you debug a plot that looks wrong. First, the scale name is validated immediately: a misspelling such as ax.set_yscale("logg") raises ValueError: 'logg' is not a valid value for scale. Did you mean one of: 'log', 'logit', 'symlog'? (message captured verbatim on Matplotlib 3.11). The error names the accepted values, so a typo fails fast instead of silently producing a linear axis.
Second, a logarithmic scale cannot represent zero or negative values, and this case does not raise an error. Matplotlib silently drops the non-positive points: they are masked out of the drawing, line segments that would pass through them disappear, and the axis limits cover the positive values only. The example below plots y = [2, 0, -5, 80] on a logarithmic y-axis:
import matplotlib.pyplot as plt
x = [1, 10, 100, 1000]
y = [2, 0, -5, 80]
fig, ax = plt.subplots()
ax.plot(x, y, marker="o")
ax.set_yscale("log")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)
The call completes normally and reports y-axis: log, but only the points at y = 2 and y = 80 can appear; in the verified run the resulting y-axis limits were approximately 1.66 to 96.2, spanning the positive data only. If a series seems to lose points after you switch an axis to log, check the data for zeros and negative values before suspecting the plotting code.
When the data genuinely contains signed values, the symlog (symmetric log) scale is the appropriate alternative: it applies a logarithmic scale away from zero and a linear scale in a small region around zero, so every point stays visible.
import matplotlib.pyplot as plt
x = [1, 10, 100, 1000]
y = [2, 0, -5, 80]
fig, ax = plt.subplots()
ax.plot(x, y, marker="o")
ax.set_yscale("symlog")
ax.set_xlabel("x")
ax.set_ylabel("y")
print(f"x-axis: {ax.get_xscale()}, y-axis: {ax.get_yscale()}")
plt.close(fig)
All four points, including 0 and -5, are plotted on the symlog y-axis. Use it whenever the sign of the values carries information; keep the plain log scale for data that is positive by nature, such as counts, sizes and physical measurements.