{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Please Stop using Pylab" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[Edit] thanks to [Randy Olson](https://github.com/Carreau/posts/pull/3) for sending me a PR with grammar and spelling corrections." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "TL;DR, Please stop advising people to use the `pylab` flag when using IPython.\n", "It is harmful. If you want to help IPython, try to avoid retweeting, and\n", "promoting things that use the `pylab` flag and make the authors aware of the issues.\n", "\n", "Use explicit import, and `%matplotlib inline` magic. It is better (and supports switching between inline/not inline.)\n", "\n", "\n", "This was mainly prompted by a day where I came across consecutive issues due to\n", "the pylab flag, and people happy to discover it.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Pylab, my worst friend" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When IPython 1.0 was released almost 6 months ago, we had quite a few decisions to\n", "make in less than a week and loads of discussions at the last moment. One of\n", "those decisions comes and goes often: we want to get rid of this stupid `pylab` flag. If\n", "you look at our stable (1.0) dev doc and examples there shouldn't be\n", "a mention of the `pylab` flag anywhere. If there is, we will quickly remove it.\n", "Why? Because it is harmful, first to us, then to new users, to the Python\n", "community, and finally to research in general. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Do you know about pylab? If you don't, please be extra careful and try to avoid it as much as possible.\n", "It is like smoking: it looks cool at first, then after a few years you realise you can live without it, \n", "but it makes you sick. \n", "\n", "You think you know what `pylab` does? Really? Take few seconds to think what the `pylab` flag is doing, then read the rest." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## What is it supposed to do?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `pylab` **package** main purpose was to build a [transition tool](https://wiki.scipy.org/PyLab) \n", "from other languages to Python. As it was more and more common and painful to do the same import \n", "in IPython every time when only the IPython shell was around, the `--pylab` flag was added. Basically, it did the following:\n", "\n", "```python\n", "import numpy\n", "import matplotlib\n", "from matplotlib import pylab, mlab, pyplot\n", "np = numpy\n", "plt = pyplot\n", "\n", "from IPython.core.pylabtools import figsize, getfigs\n", "\n", "from pylab import *\n", "from numpy import *\n", "```\n", "\n", "Did you get it right the first time without cheating ? Are you able to say what has been imported\n", "in `from pylab import *` ? in `from numpy import *` ?\n", "\n", "\n", "Of course, that is not the only thing it does. But was it your intention to do that the last time you used pylab?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### It is irreversible" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once you activate pylab mode, there is no going back. You cannot unimport\n", "things. Of course, with the `%pylab` magic you can always restart your kernel,\n", "but with the flag, all your kernels will start in pylab mode. Are you **sure**\n", "you will not need a non-pylab kernel?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Unclear" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When using the `pylab` flag, your audience usually has no way of knowing that you\n", "used the flag. If I use `plot(range(10))`, what will happen? Will it pop up a\n", "figure ? Inline it? Or throw an error?\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "plot(range(10))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because I'm mean, I won't execute the cell, so that you don't know whether or\n", "not I'm running in pylab mode or not. You might think it's not a big deal, but\n", "in teaching and research it is important to communicate exactly what you are doing." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### It pollutes the namespace" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "20" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(get_ipython().user_ns.keys())" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Using matplotlib backend: Agg\n", "Populating the interactive namespace from numpy and matplotlib\n" ] } ], "source": [ "%pylab" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "IPython 2.0-dev gives some warning, and will tell you wether it clobbers already non-built-in variables in the user namespace." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "968" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(get_ipython().user_ns.keys())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Can you really tell me the 948 additional things you now have in your namespace? Not a big deal? Really?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### It replaces built-ins" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(, )" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sum,all" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Both used to be `,` before using pylab, and this **changes the behavior of your programs!**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For example, it leads to non-pickable object in some cases:\n", "\n", "\n", "@treycausey on Twitter\n", "\n", "> @ogrisel @myusuf3 Ah, very curious. It loads fine in IPython but not in an IPython notebook. I must have a namespace collision or something.\n", "\n", "Me:\n", "> Let me guess: `$ipython notebook --pylab`? But `$ipython` alone?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Other unrelated actions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "IPython developed and added the rich display protocol, so we added `from IPython.display import display` to what `import pylab` does.\n", "\n", "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The main things users remember, and often the main message that you can read here and there is that:\n", "\n", "> You need to use Pylab to get inline figures.\n", "\n", "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. \n", "With 1.0 and above the recommended way to set up inline figures would be to use `%matplotlib`.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Side Effects" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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:\n", "\n", "```\n", "fig,ax = subplots(1,1)\n", "ax.plot(...)\n", "```\n", "\n", "or why their script suddenly does not work in plain Python but works in IPython.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### It kills kittens, with a spoon..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Maybe not kittens, but it will force developers to explain the same things, again, and again, and again..." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "

There was a problem loading this remote IFrame, have a look as Javascript console

\n", " " ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import YouTubeVideo\n", "YouTubeVideo('9VDvgL58h_Y',start=4*60+27)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Make `--pylab` disappear." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course, we will not remove the `--pylab` flag for compatibility reasons, but please, for 2014, make the following resolutions:\n", "\n", " - Use `%matplotlib [inline|qt|osx|gtx]` to select the right backend/event hook.\n", " - Use explicit imports\n", " - Make people aware of the issues\n", " - Help by making no new articles/tutorials that mention `--pylab`\n", " \n", "If really you only [have 10 seconds left](https://xkcd.com/1168/), the `%pylab` magic is fine." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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`." ] } ], "metadata": { "kernelspec": { "display_name": "IPython (Python 3)", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3" } }, "nbformat": 4, "nbformat_minor": 0 }