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.
The pie chart:
The bar chart:
The ink location chart:
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:
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.
And then I fed the results of that into the panel generating functions.
I then used it on a completely blank strip as the initial guess.
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.
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.
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:
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.
Then I needed a new color analysis function and MakeImageGrid function.
If I could just get Mathematica to automate the humor of xkcd, then I would make a fortune!
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.
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).
Would it be possible to ask for a notebook on these code? Pretty cool stuff! Thanks!
Actually, it’s more fun to type it up, for instance, I didn’t know about “TEXT\nTEXT” , THANKS!
Splendid idea! :D
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.
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.
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…
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…
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.
A guy named Phil Hassey did this in January using Python + Pygame.
Hi, nice article. I did the same with Mathematica in january: http://forums.xkcd.com/viewtopic.php?f=7&t=55212&hilit=688&sid=0c05fa6227bedd71970247ca09b26d9e&start=120#p1968190
Is it possible to get this code as text or nb?