Punchline: I have opened a pull request to give IPython an xkcdify()
function that can be used to render an IPython Notebook in the xkcd visual style. Read on to find out more.
At SciPy 2013, Michael Droettboom gave a talk about the state of Matplotlib. He focused on the new features in the upcoming 1.3 release. It was a fantastic talk that covered a lot of new features. Here is the talk in case you are interested:
from IPython.display import YouTubeVideo
YouTubeVideo('gj5i_19Bftk')
One of the features that Michael talked about is the new xkcd rendering mode. With a single call to the xkcd()
function, an entire Matplotlib figure can be transformed to use the visual style of the xkcd webcomic. As Jake Vanderplas describes in this blog post, this idea started out on a Mathematica Stack Exchange question. On the Python side, Damon McDougall, Fernando Perez and Jake sprung into action; this resulted in Jake's often cited notebook here.
After that, the Matplotlib team built this functionality into Matplotlib itself. The amazing thing about this work is the relatively low level at which this feature was built into Matplotlib. This fact was highlighted in Michael's talk when someone from the audience asked if he could enable the xkcd mode on a live animation of a double pendulum. A few seconds later the entire animation looked handdrawn! You can see the entire Matplotlib gallery rendered in this mode here.
Here are a few examples from the Matplotlib Gallery that shows the xkcd mode in action:
%pylab inline
Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.kernel.zmq.pylab.backend_inline]. For more information, type 'help(pylab)'.
Here is a plot that reproduces xkcd #373:
plt.xkcd()
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.bar([-0.125, 1.0-0.125], [0, 100], 0.25)
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.set_xticks([0, 1])
ax.set_xlim([-0.5, 1.5])
ax.set_ylim([0, 110])
ax.set_xticklabels(['CONFIRMED BY\nEXPERIMENT',
'REFUTED BY\nEXPERIMENT'])
plt.yticks([])
plt.title("CLAIMS OF SUPERNATURAL POWERS");
Here is a more quantitative example that shows how different plot elements (axes, tick marks, lines, shapes) are styled:
from matplotlib.ticker import NullFormatter
x = np.random.randn(1000)
y = np.random.randn(1000)
nullfmt = NullFormatter()
left, width = 0.1, 0.65
bottom, height = 0.1, 0.65
bottom_h = left_h = left+width+0.02
rect_scatter = [left, bottom, width, height]
rect_histx = [left, bottom_h, width, 0.2]
rect_histy = [left_h, bottom, 0.2, height]
plt.figure(1, figsize=(8,8))
axScatter = plt.axes(rect_scatter)
axHistx = plt.axes(rect_histx)
axHisty = plt.axes(rect_histy)
axHistx.xaxis.set_major_formatter(nullfmt)
axHisty.yaxis.set_major_formatter(nullfmt)
axScatter.scatter(x, y)
binwidth = 0.25
xymax = np.max( [np.max(np.fabs(x)), np.max(np.fabs(y))] )
lim = ( int(xymax/binwidth) + 1) * binwidth
axScatter.set_xlim( (-lim, lim) )
axScatter.set_ylim( (-lim, lim) )
bins = np.arange(-lim, lim + binwidth, binwidth)
axHistx.hist(x, bins=bins)
axHisty.hist(y, bins=bins, orientation='horizontal')
axHistx.set_xlim( axScatter.get_xlim() )
axHisty.set_ylim( axScatter.get_ylim() );
Part of what makes the xkcd visual style so attractive is the hand-drawn look. As a physicist, I have spent countless hours writing complex mathematical derivations by hand. This work often involves making hand-drawn plots as well. Even though I love computing, most of my graduate and post-graduate work was done in this manner. Furthermore, when we teach physics almost all of it is done by hand. In spite of the amazing growth of computing in science and engineering, the foundations of these fields are built with handwritten work. The hand-drawn look of xkcd reminds me of that foundation.
With this in mind, I thought it was appropriate for the IPython Notebook to have an xkcd mode as well. I also thought that Matplotlib's xkcd mode looked a bit out of place with the default styling of the Notebook. The xkcd mode in the IPython Notebook is made possible by the xkcd inspired Humor Sans Font. This mode is enabled in the notebook using the xkcdify()
function:
from IPython.display import xkcdify, display, HTML
xkcdify()
This function is not yet in IPython - I am hoping my pull request will be merged before the upcoming 1.0 release.
I will admit that using this style on code and output is a bit extreme. It is particularly difficult given that Humor Sans doesn't distinguish between upper and lower case (but Python does!). I have added keyword arguments to allow you to disable the styling of specific elements:
xkcdify(code=False, prompts=False, output=False)
To show how you can use this mode, I have tried to reproduce a few xkcd comics that are table based below. However, I have another goal with this work. I wanted to show to style the notebook with a little CSS. Another beautiful example of this is Cameron Davidson-Pilon's Probabilistic Programming and Bayesian Methods for Hackers. I am hoping that we can develop support in IPython to make this type of thing easier.
Here is a simple table in a Markdown cell that reproduces xkcd #1070, entitled "Words for Small Sets":
Just to clear things up:
a few | anywhere from 2 to 5 |
a handful | anywhere from 2 to 5 |
several | anywhere from 2 to 5 |
a couple | 2 (but sometimes up to 5) |
More importantly, we can use the full power of Python to build xkcd-style tables. Here we use a pandas DataFrame
object to read in a CSV file with the data for xkcd #1093:
import pandas
df = pandas.read_csv('1093.csv',)
Then we can use IPython's display system to show the table along with the title/subtitle of the comic. Question: does anyone know how to get pandas to hide the index column when displaying the DataFrame
?
display(HTML("""
<h2 style="text-align: center">When will we forget?</h2>
<hr style="height: 2px;"/>
<h3 style="text-align: center">Based on US Census
Bureau National population projections</h3>
<hr style="height: 2px;"/>
<p style="text-align: center">Assuming we don't remember
cultural events from before age 5 or 6</p>
"""))
display(df)
Assuming we don't remember cultural events from before age 5 or 6
By this year: | The majority of Americans will be too young to remember: | |
---|---|---|
0 | 2012 | The seventies |
1 | 2013 | The Carter Presidency |
2 | 2014 | The Reagan shooting |
3 | 2015 | The Falkland Islands war |
4 | 2016 | Return of the Jedi release |
5 | 2017 | The first Apple Macintosh |
6 | 2018 | New Coke |
7 | 2019 | Challenger |
8 | 2020 | Chernobyl |
9 | 2021 | Black Monday |
10 | 2022 | The Reagan presidency |
11 | 2023 | The Berlin wall |
12 | 2024 | Hammertime |
13 | 2025 | The Soviet Union |
14 | 2026 | The LA riots |
15 | 2027 | Lorena Bobbitt |
16 | 2028 | The Forrest Gump release |
17 | 2029 | The Rwandan Genocide |
18 | 2030 | OJ Simpson's trial |
19 | 2031 | Clinton's reelection |
20 | 2032 | Princess Diana |
21 | 2033 | Clinton's impeachment |
22 | 2034 | Columbine |
23 | 2035 | Forgot about DRE |
24 | 2036 | 9/11 |
25 | 2037 | VH1's I Love the 80s |
26 | 2038 | A time before Facebook |
27 | 2039 | VH1's I Love the 90s |
28 | 2040 | Hurricance Katrina |
29 | 2041 | The planet Pluto |
30 | 2042 | The first iPhone |
31 | 2043 | The Bush presidency |
32 | 2044 | Michael Jackson |
33 | 2045 | Trying to say "EYJAFJALLAJOKULL" |
34 | 2046 | The Arab spring |
35 | 2047 | Anything embarrassing you do today |
This cell contains some formatting...