Wolfram Blog
Jon McLoone


September 7, 2010 — Jon McLoone, Director, Technical Communication & Strategy

I am a big fan of Randall Munroe’s web comic strip xkcd. (Apparently I am not alone.)

A while ago, Randall posted a strip with a self-referential chart of the amount of black ink in the image.


If you have read my past blog items, you know I like recursive pictures. So I thought I would create a Mathematica version of this strip.

First, I generated each of the charts, which are all pretty straightforward chart types in Mathematica. The work was in making them roughly follow Randall’s style choices.

Chart type

The pie chart:

Pie chart type

The bar chart:

Bar chart type

The ink location chart:

Ink location type

Next, I solved the equation f[x]=x, where f is the function that generates an analysis report on the ink in an image and x is the image of the report.

If the equation is substituted into itself, it also solves f[f[x]]=x, and for that matter f[f[f[f[f[f[f[x]]]]]]]=x.

If f meets certain convergence criteria, then this problem can be solved iteratively just by working out f[f[f[...f[x]…]]] for some random initial guess at x.

This is exactly the numerical analysis task that every bored schoolchild has done at some point by pressing the Cos button on a calculator repeatedly. It eventually converges on 0.739085, which is the solution to the equation Cos[x]=x. In Mathematica this is easily done with:

Solution to equation Cos[x]=x
Solution to equation Cos[x]=x

So all I needed was a function that generates a cartoon strip based on the analysis of a cartoon strip. I started by creating a measure of black ink in an image. Since Mathematica mostly prefers vector graphics, I first needed to convert to a raster image before I could count pixels.

Converting to raster image

And then I fed the results of that into the panel generating functions.

Panel generating functions

I then used it on a completely blank strip as the initial guess.

Initial guess

Blank strip
Blank strip

Since I started with a blank strip, it registered no black ink. But the second iteration picked up the black from the edge of the pie chart, the frame, the axes, and the text in the first iteration.

Second iteration
Second iteration

Then I did the same as we all did with Cos and found the fixed point, the point at which applying the function again makes no difference.

Fixed point
Fixed point

I didn’t deal with convergence criteria here, and for some design choices, that is a problem. But in practice, for this task, convergence problems are cycles of dithering of individual anti-aliased pixels, rather than a fundamental divergence. The differences become imperceptible to the human eye after 10 or 20 iterations. So the following is more practical than FixedPoint:

Improvement over FixedPoint

One can quickly extend the idea to a color version. Here is one in CMYK (cyan, magenta, yellow, black—the standard ink colors), but one could equally do RGB, HSB, or CMYK+White.

First, I had to update the styles to make the strip colorful.

Updating styles

Updating styles

Then I needed a new color analysis function and MakeImageGrid function.

New color analysis function

New MakeImageGrid function

Colorful strip
Colorful strip

If I could just get Mathematica to automate the humor of xkcd, then I would make a fortune!

Leave a Comment


Steven H Noble

Oh dear, now I’m curious of the characteristics of the solution set. I suspect the solution for the black and white case is unique (although I think you can reduce the problem to solving for a quadratic; Mmm maybe a higher degree polynomial). I have no idea about the colour case though.

Posted by Steven H Noble    September 7, 2010 at 5:47 pm
Randall Munroe

A friend just linked me here. Wow, that’s really cool! I never thought it could be automated so easily.

I did the convergences by hand for my version, using Photoshop’s pixel-counting tool—I did one version on paper, scanned it, and then started redrawing over it in Photoshop to get the counts to converge. I went back and forth between panels 1 and 2, propagating the results a few levels down panel 3 each time (so they built down each time, with deeper versions slightly less up-to-date), and had a version that was relatively stable at web resolution after not too many iterations. Since I was doing a high-res version for prints, I then replicated the final stable version down all the way down (6 or 8 levels at the resolution I was working at) and found that it didn’t change the bar location by more than the precision of my ink, so I was done.

If you ever figure out how to automate the general problem of webcomic generation, you should totally get a whole distributed computing project behind it and create the first webcomic that updates more than once a minute. If we thought webcomics hurt office productivity before … (Of course, you’ve got quite a hill to climb, given the current state of the art).

Posted by Randall Munroe    September 7, 2010 at 7:57 pm
Samuel Chen

Would it be possible to ask for a notebook on these code? Pretty cool stuff! Thanks!

Posted by Samuel Chen    September 7, 2010 at 11:00 pm
Samuel Chen

Actually, it’s more fun to type it up, for instance, I didn’t know about “TEXT\nTEXT” , THANKS!

Posted by Samuel Chen    September 7, 2010 at 11:54 pm

Splendid idea! :D

Posted by Schmiddi    September 8, 2010 at 1:35 am

Very cool. You have to wonder whether the guy in charge of “International Business & Strategic Development” is really the one who thought up this great idea, or if he’s really taking credit for some anonymous engineer’s work. The optimistic side of me hopes this guy really did write this blog post, but the realistic part doesn’t think it’s likely.

Posted by Alex    September 8, 2010 at 3:40 am

Given the guy’s posting history, the variety of posters on the blog and the general vibe I get from Wolfram, I wouldn’t doubt that he wrote it himself.

I’d actually guess that “strategic development” means part of his job is to come up with unusual (or at least fun/simple) new ways to demonstrate Mathematica.

Posted by Moby    September 8, 2010 at 3:41 am

Actually, the first 2 images aren’t accurate. There’s black in the circle border and on the chart axes, so the solution is false :-)

Yeah, i know…

Posted by valentin    September 8, 2010 at 4:10 am
Sander Huisman

I’m suprised it actually converges, somehow I would expect it too blow up:

if black>white, then black grows, which makes black>>white, which makes black>>>white… Somehow it goes to a limit…interesting…

Posted by Sander Huisman    September 8, 2010 at 6:05 am
Chris Lomont

It converges since there is always some amount of white in the image, and the white/black ratio is bounded away from 0 and 1. So in each iteration, since you’re increasing the black and the result is bounded away from an entirely black image, it converges to a value.

It would be interesting to see if this solution is unique, or if there are more fixed points.

Posted by Chris Lomont    September 9, 2010 at 9:37 am
Shad Sharma

A guy named Phil Hassey did this in January using Python + Pygame.


Posted by Shad Sharma    September 9, 2010 at 11:36 am
Peter Frentrup
Posted by Peter Frentrup    September 9, 2010 at 2:57 pm
Yaroslav Bulatov

Is it possible to get this code as text or nb?

Posted by Yaroslav Bulatov    October 3, 2010 at 1:41 pm

Leave a comment