Skip to content

Instantly share code, notes, and snippets.

@AustinRochford
Last active May 12, 2021 16:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AustinRochford/6c48e60953fad4069ff027c3fcdccc9a to your computer and use it in GitHub Desktop.
Save AustinRochford/6c48e60953fad4069ff027c3fcdccc9a to your computer and use it in GitHub Desktop.
How to Write a Jupyter Magic in Python
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "b5d65850",
"metadata": {},
"source": [
"---\n",
"title: How to Write a Jupyter Magic in Python\n",
"tags: Python, Jupyter\n",
"---"
]
},
{
"cell_type": "markdown",
"id": "2b0d3e01",
"metadata": {},
"source": [
"[Jupyter magics](https://ipython.readthedocs.io/en/stable/interactive/magics.html) allow us to run convenient utility functions within Jupyter notebooks. Anyone who has done much data analysis in a Jupyter notebook is likely familiar with"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "c883e6ac",
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"id": "2539678c",
"metadata": {},
"source": [
"which causes our `matplotlib` figures to be rendered in the notebook. This short post will explain the mechanics of creating Jupyter notebooks and exists mostly as a reference for my future self. For a slightly more involved example, my package [`giphy-ipython-magic`](https://github.com/AustinRochford/giphy-ipython-magic) serves well."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "9c550ff2",
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"!pip install -q giphy-ipython-magic"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "48692560",
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"text/html": [
"<img src=\"https://media3.giphy.com/media/YV4MD2hR4SJttvxPiE/giphy.gif\"/>"
],
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"%load_ext giphy_magic\n",
"%giphy magic"
]
},
{
"cell_type": "markdown",
"id": "3ef7d012",
"metadata": {},
"source": [
"## A simple magic\n",
"\n",
"To start, we'll implement a Jupyter magic that prints the result of [`cowsay`](https://en.wikipedia.org/wiki/Cowsay) (one of my favorite Unix utilities) given a phrase."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "558586eb",
"metadata": {},
"outputs": [],
"source": [
"!pip install -q cowsay"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "9002935d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting ./cowsay_magic.py\n"
]
}
],
"source": [
"%%writefile ./cowsay_magic.py\n",
"import cowsay as cs\n",
"\n",
"def cowsay(msg):\n",
" cs.cow(msg)"
]
},
{
"cell_type": "markdown",
"id": "3c7840fc",
"metadata": {},
"source": [
"Here the [`%%writefile` magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html#cellmagic-writefile) writes the contents of the rest of the cell to the `cowsay_magic.py` file in the current directory. The script written to this file calls a [Python library](https://github.com/VaasuDevanS/cowsay-python) that reimplements `cowsay` and prints the result. In order for Jupyter to know that this file and function define a magic command, we must register the magic in a function named `load_ipython_extension`. (Note that we could also use the [`@register_line_magic` decorator](http://localhost:8888/notebooks/jupyter_magic/Jupyter%20Magic.ipynb), but `load_ipython_extension` is necessary to redefine this magic momentarily. If anyone knows how to do this with the decorator, I'm all ears.)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "4e945fcd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Appending to ./cowsay_magic.py\n"
]
}
],
"source": [
"%%writefile -a ./cowsay_magic.py\n",
"def load_ipython_extension(ipython):\n",
" ipython.register_magic_function(cowsay, 'line')"
]
},
{
"cell_type": "markdown",
"id": "d00c48f3",
"metadata": {},
"source": [
"Here the `-a` argument causes `%%writefile` to append to the existing file instead of overwriting it, which is the default behavior.\n",
"\n",
"We make sure `cowsay_magic.py` is on the `PYTHONPATH` and load the magic into the Jupyter environment."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "2508abe3",
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"\n",
"sys.path.append('.')"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "c7b57614",
"metadata": {},
"outputs": [],
"source": [
"%load_ext cowsay_magic"
]
},
{
"cell_type": "markdown",
"id": "1e68bf59",
"metadata": {},
"source": [
"We can now use `%cowsay` to summon our bovine friend."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "283cd77f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" ______________\n",
"| Hello Jupyter! |\n",
" ==============\n",
" \\\n",
" \\\n",
" ^__^\n",
" (oo)\\_______\n",
" (__)\\ )\\/\\\n",
" ||----w |\n",
" || ||\n"
]
}
],
"source": [
"%cowsay Hello Jupyter!"
]
},
{
"cell_type": "markdown",
"id": "861e01ed",
"metadata": {},
"source": [
"### Adding arguments\n",
"\n",
"Jupyter passes the string after the magic as `msg`, and many magics implement shell-style arguments. We will add argument parsing to `%cowsay` in order to change the type of figure in the ASCII art."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "5159b147",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting ./cowsay_magic.py\n"
]
}
],
"source": [
"%%writefile ./cowsay_magic.py\n",
"from argparse import ArgumentParser\n",
"import cowsay as cs\n",
"\n",
"def parse_args(msg):\n",
" parser = ArgumentParser(prog='cowsay magic')\n",
" parser.add_argument('-f', dest='char_name', action='store', default='cow')\n",
" parser.add_argument('message', nargs='*')\n",
" \n",
" return parser.parse_args(msg.split())\n",
"\n",
"def cowsay(msg):\n",
" args = parse_args(msg)\n",
" \n",
" print(cs.get_output_string(args.char_name, ' '.join(args.message)))\n",
" \n",
"def load_ipython_extension(ipython):\n",
" ipython.register_magic_function(cowsay, 'line')"
]
},
{
"cell_type": "markdown",
"id": "d996f512",
"metadata": {},
"source": [
"Here we have used the [`argparse`](https://docs.python.org/3/library/argparse.html) module to parse `msg`. We reload the `cowsay_magic` extension."
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "dc3fb99e",
"metadata": {},
"outputs": [],
"source": [
"%reload_ext cowsay_magic"
]
},
{
"cell_type": "markdown",
"id": "fe8eca4d",
"metadata": {},
"source": [
"Passing no arguments to `%cowsay` still prints a cow."
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "f45be9d3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" ______________\n",
"| Hello Jupyter! |\n",
" ==============\n",
" \\\n",
" \\\n",
" ^__^\n",
" (oo)\\_______\n",
" (__)\\ )\\/\\\n",
" ||----w |\n",
" || ||\n"
]
}
],
"source": [
"%cowsay Hello Jupyter!"
]
},
{
"cell_type": "markdown",
"id": "8af92ffe",
"metadata": {},
"source": [
"Passing the `-f` argument to `%cowsay` changes the speaker."
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "e6f4d2f3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" ______________\n",
"| Hello Jupyter! |\n",
" ==============\n",
" \\\n",
" \\\n",
" \\\n",
" \\\n",
" .-=-==--==--.\n",
" ..-==\" ,'o`) `.\n",
" ,' `\"' \\\n",
" : ( `.__...._\n",
" | ) / `-=-.\n",
" : ,vv.-._ / / `---==-._\n",
" \\/\\/\\/VV ^ d88`;' / `.\n",
" `` ^/d88P!' / , `._\n",
" ^/ !' ,. , / \"-,,__,,--'\"\"\"\"-.\n",
" ^/ !' ,' \\ . .( ( _ ) ) ) ) ))_,-.\\\n",
" ^(__ ,!',\"' ;:+.:%:a. \\:.. . ,' ) ) ) ) ,\"' '\n",
" ',,,'',' /o:::\":%:%a. \\:.:.: . ) ) _,'\n",
" \"\"\"' ;':::'' `+%%%a._ \\%:%| ;.). _,-\"\"\n",
" ,-='_.-' ``:%::) )%:| /:._,\"\n",
" (/(/\" ,\" ,'_,'%%%: (_,'\n",
" ( (//(`.___; \\\n",
" \\ \\ ` `\n",
" `. `. `. :\n",
" \\. . .\\ : . . . :\n",
" \\. . .: `.. . .:\n",
" `..:.:\\ \\:...\\\n",
" ;:.:.; ::...:\n",
" ):%:: :::::;\n",
" __,::%:( :::::\n",
" ,;:%%%%%%%: ;:%::\n",
" ;,--\"\"-.`\\ ,=--':%:%:\\\n",
" /\" \"| /-\".:%%%%%%%\\\n",
" ;,-\"'`)%%)\n",
" /\" \"|\n"
]
}
],
"source": [
"%cowsay -f trex Hello Jupyter!"
]
},
{
"cell_type": "markdown",
"id": "ae91ee0b",
"metadata": {},
"source": [
"## Working with Python objects\n",
"\n",
"Our `%cowsay` magic works only with strings, but we can also manipulate Python objects in a magic function using [`eval`](https://docs.python.org/3/library/functions.html#eval). To demonstrate, we will define a magic to invert the y-axis of a `matplotlib` plot."
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "4a9b07f1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Overwriting flip_magic.py\n"
]
}
],
"source": [
"%%writefile flip_magic.py\n",
"from IPython.core.magic import needs_local_scope\n",
"\n",
"@needs_local_scope\n",
"def flip(fig_str, local_ns=None):\n",
" fig = eval(fig_str, None, local_ns)\n",
" fig.gca().invert_yaxis()\n",
" \n",
" return fig\n",
"\n",
"def load_ipython_extension(ipython):\n",
" ipython.register_magic_function(flip, 'line')"
]
},
{
"cell_type": "markdown",
"id": "84038778",
"metadata": {},
"source": [
"Note the `@needs_local_scope` decorater that tells Jupyter to pass the local scope to our magic function. We load `flip_magic` and see that it does indeed invert the y-axis of a simple plot."
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "cac061a4",
"metadata": {},
"outputs": [],
"source": [
"from matplotlib import pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "fddd8746",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 576x432 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots(figsize=(8, 6))\n",
"\n",
"ax.plot([0, 1], [0, 1]);"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "183b85f2",
"metadata": {},
"outputs": [],
"source": [
"%load_ext flip_magic"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "5a0bd6f8",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 576x432 with 1 Axes>"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"%flip fig"
]
},
{
"cell_type": "markdown",
"id": "de374e4c",
"metadata": {},
"source": [
"I hope that this simple tutorial has been helpful. For more detail about the custom magic API, consult the excellent [Jupyter documentation](https://ipython.readthedocs.io/en/stable/config/custommagics.html).\n",
"\n",
"The notebook this post was generated from is available as a Jupyter notebook [here](https://nbviewer.jupyter.org/gist/AustinRochford/6c48e60953fad4069ff027c3fcdccc9a)."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"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",
"version": "3.8.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment