563

I want to plot a graph with one logarithmic axis using matplotlib.

I've been reading the docs, but can't figure out the syntax. I know that it's probably something simple like 'scale=linear' in the plot arguments, but I can't seem to get it right

Sample program:

import pylab
import matplotlib.pyplot as plt
a = [pow(10, i) for i in range(10)]
fig = plt.figure()
ax = fig.add_subplot(2, 1, 1)

line, = ax.plot(a, color='blue', lw=2)
pylab.show()
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158

6 Answers6

642

You can use the Axes.set_yscale method. That allows you to change the scale after the Axes object is created. That would also allow you to build a control to let the user pick the scale if you needed to.

The relevant line to add is:

ax.set_yscale('log')

You can use 'linear' to switch back to a linear scale. Here's what your code would look like:

import pylab
import matplotlib.pyplot as plt
a = [pow(10, i) for i in range(10)]
fig = plt.figure()
ax = fig.add_subplot(2, 1, 1)

line, = ax.plot(a, color='blue', lw=2)

ax.set_yscale('log')

pylab.show()

result chart

Max Ghenis
  • 14,783
  • 16
  • 84
  • 132
Mathieu
  • 7,001
  • 2
  • 19
  • 16
  • 7
    This method is nice since it works with all sorts of plots (e.g. histograms), not just with "plot" (which is what semilogx/semilogy does) – Tim Whitcomb Jul 26 '09 at 00:18
  • 19
    I came here looking for how to use an axis for powers of two: pylab.gca().set_xscale('log',basex=2) – zje Apr 12 '12 at 20:16
  • 75
    Matplotlib has `semilogy()`. Furthermore, it is easier to directly use `pyplot.yscale()` than to use `ax.set_yscale('log')`, as there is no need to get the `ax` object (which is not always immediately available). – Eric O. Lebigot Feb 28 '13 at 05:43
  • 7
    If you want log scales on both axes, try `loglog()` or on x-axis only try `semilogx()` – drevicko Jun 28 '13 at 07:00
  • 16
    @EOL I would advise the opposite. It is better to use an explicit `ax` object that to use `pyplot` which only _might_ apply to the Axes you want it to. – tacaswell May 03 '16 at 04:08
  • 1
    @tcaswell While I do appreciate the fact that the object-oriented approach to plotting is more explicit, I must say that in many many years of usage of Matplotlib I have _never_ been bitten by the state machine approach that I was recommending for its ease of use… I sometimes do use the object-oriented approach, but only in some rare, more complicated plotting tasks. – Eric O. Lebigot May 03 '16 at 12:06
  • 1
    Does set_yscale('log') uses base 10 as the default? I am not able to find any official documentation on the same. – outlier229 Dec 07 '17 at 00:26
  • 1
    @EricOLebigot For me it's the opposite, I use the object-oriented approach every day because my Qt-based programs have embedded Matplotlib graphs, and the `plt.do_something()` examples found everywhere on StackOverflow or in the documentation never work for me. – Guimoute Dec 03 '19 at 14:18
  • @outlier229 yes, the default is base 10. source: https://matplotlib.org/stable/api/scale_api.html#matplotlib.scale.LogScale – inavda Apr 09 '22 at 21:50
391

First of all, it's not very tidy to mix pylab and pyplot code. What's more, pyplot style is preferred over using pylab.

Here is a slightly cleaned up code, using only pyplot functions:

from matplotlib import pyplot

a = [ pow(10,i) for i in range(10) ]

pyplot.subplot(2,1,1)
pyplot.plot(a, color='blue', lw=2)
pyplot.yscale('log')
pyplot.show()

The relevant function is pyplot.yscale(). If you use the object-oriented version, replace it by the method Axes.set_yscale(). Remember that you can also change the scale of X axis, using pyplot.xscale() (or Axes.set_xscale()).

Check my question What is the difference between ‘log’ and ‘symlog’? to see a few examples of the graph scales that matplotlib offers.

Community
  • 1
  • 1
Denilson Sá Maia
  • 47,466
  • 33
  • 109
  • 111
104

if you want to change the base of logarithm, just add:

plt.yscale('log',base=2) 

Before Matplotlib 3.3, you would have to use basex/basey as the bases of log

mrks
  • 8,033
  • 1
  • 33
  • 62
Dawid
  • 1,385
  • 1
  • 15
  • 23
78

You simply need to use semilogy instead of plot:

from pylab import *
import matplotlib.pyplot  as pyplot
a = [ pow(10,i) for i in range(10) ]
fig = pyplot.figure()
ax = fig.add_subplot(2,1,1)

line, = ax.semilogy(a, color='blue', lw=2)
show()
Scott McCammon
  • 1,865
  • 16
  • 10
  • 11
    There is also [semilogx](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.semilogx). If you need log on both axes, use [loglog](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.loglog) – drevicko Jan 19 '15 at 00:24
12

I know this is slightly off-topic, since some comments mentioned the ax.set_yscale('log') to be "nicest" solution I thought a rebuttal could be due. I would not recommend using ax.set_yscale('log') for histograms and bar plots. In my version (0.99.1.1) i run into some rendering problems - not sure how general this issue is. However both bar and hist has optional arguments to set the y-scale to log, which work fine.

references: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.bar

http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.hist

user3465408
  • 199
  • 2
  • 3
10

So if you are simply using the unsophisticated API, like I often am (I use it in ipython a lot), then this is simply

yscale('log')
plot(...)

Hope this helps someone looking for a simple answer! :).

crazy2be
  • 2,134
  • 1
  • 21
  • 17