Please Stop using Pylab

[Edit] thanks to Randy Olson for sending me a PR with grammar and spelling corrections.

TL;DR, Please stop advising people to use the pylab flag when using IPython. It is harmful. If you want to help IPython, try to avoid retweeting, and promoting things that use the pylab flag and make the authors aware of the issues.

Use explicit import, and %matplotlib inline magic. It is better (and supports switching between inline/not inline.)

This was mainly prompted by a day where I came across consecutive issues due to the pylab flag, and people happy to discover it.

Pylab, my worst friend

When IPython 1.0 was released almost 6 months ago, we had quite a few decisions to make in less than a week and loads of discussions at the last moment. One of those decisions comes and goes often: we want to get rid of this stupid pylab flag. If you look at our stable (1.0) dev doc and examples there shouldn't be a mention of the pylab flag anywhere. If there is, we will quickly remove it. Why? Because it is harmful, first to us, then to new users, to the Python community, and finally to research in general.

Do you know about pylab? If you don't, please be extra careful and try to avoid it as much as possible. It is like smoking: it looks cool at first, then after a few years you realise you can live without it, but it makes you sick.

You think you know what pylab does? Really? Take few seconds to think what the pylab flag is doing, then read the rest.

What is it supposed to do?

The pylab package main purpose was to build a transition tool from other languages to Python. As it was more and more common and painful to do the same import in IPython every time when only the IPython shell was around, the --pylab flag was added. Basically, it did the following:

import numpy
import matplotlib
from matplotlib import pylab, mlab, pyplot
np = numpy
plt = pyplot

from IPython.core.pylabtools import figsize, getfigs

from pylab import *
from numpy import *

Did you get it right the first time without cheating ? Are you able to say what has been imported in from pylab import * ? in from numpy import * ?

Of course, that is not the only thing it does. But was it your intention to do that the last time you used pylab?

It is irreversible

Once you activate pylab mode, there is no going back. You cannot unimport things. Of course, with the %pylab magic you can always restart your kernel, but with the flag, all your kernels will start in pylab mode. Are you sure you will not need a non-pylab kernel?

Unclear

When using the pylab flag, your audience usually has no way of knowing that you used the flag. If I use plot(range(10)), what will happen? Will it pop up a figure ? Inline it? Or throw an error?

In [ ]:
plot(range(10))

Because I'm mean, I won't execute the cell, so that you don't know whether or not I'm running in pylab mode or not. You might think it's not a big deal, but in teaching and research it is important to communicate exactly what you are doing.

It pollutes the namespace

In [1]:
len(get_ipython().user_ns.keys())
Out[1]:
20
In [2]:
%pylab
Using matplotlib backend: Agg
Populating the interactive namespace from numpy and matplotlib

IPython 2.0-dev gives some warning, and will tell you wether it clobbers already non-built-in variables in the user namespace.

In [3]:
len(get_ipython().user_ns.keys())
Out[3]:
968

Can you really tell me the 948 additional things you now have in your namespace? Not a big deal? Really?

It replaces built-ins

In [6]:
sum,all
Out[6]:
(<function numpy.core.fromnumeric.sum>, <function numpy.core.fromnumeric.all>)

Both used to be <function sum>,<function all> before using pylab, and this changes the behavior of your programs!

For example, it leads to non-pickable object in some cases:

@treycausey on Twitter

@ogrisel @myusuf3 Ah, very curious. It loads fine in IPython but not in an IPython notebook. I must have a namespace collision or something.

Me:

Let me guess: $ipython notebook --pylab? But $ipython alone?

Other unrelated actions

IPython developed and added the rich display protocol, so we added from IPython.display import display to what import pylab does.

Because matplotlib can work with different event loops, pylab added options to activate qt/gtk/osx/etc. event loops, and with the QtConsole and Notebook creation, the ability to select the inline backend, which registers display hooks.

The main things users remember, and often the main message that you can read here and there is that:

You need to use Pylab to get inline figures.

Which is false. Inline pylab mode is a convenient method to activate inline, and set up a display hook with matplotlib. You do not need pylab to have inline images, nor do you need matplotlib. With 1.0 and above the recommended way to set up inline figures would be to use %matplotlib.

Side Effects

The worst part is it has the side effect of making people use pylab without even knowing it. Later on, they start asking question about how to reuse a graph in matplotlib because no one ever encounters the following code any more:

fig,ax = subplots(1,1)
ax.plot(...)

or why their script suddenly does not work in plain Python but works in IPython.

It kills kittens, with a spoon...

Maybe not kittens, but it will force developers to explain the same things, again, and again, and again...

In [8]:
from IPython.display import YouTubeVideo
YouTubeVideo('9VDvgL58h_Y',start=4*60+27)
Out[8]:

Make --pylab disappear.

Of course, we will not remove the --pylab flag for compatibility reasons, but please, for 2014, make the following resolutions:

  • Use %matplotlib [inline|qt|osx|gtx] to select the right backend/event hook.
  • Use explicit imports
  • Make people aware of the issues
  • Help by making no new articles/tutorials that mention --pylab

If really you only have 10 seconds left, the %pylab magic is fine.

As usual, this has been written in an IPython Notebook. You can send me pull request if I made mistakes, or if you have any additional remarks on why you shouldn't use --pylab.