Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
import numpy as np
from matplotlib import pyplot as plt
#### From XKCD plot generator
"""
XKCD plot generator
-------------------
Author: Jake Vanderplas
This is a script that will take any matplotlib line diagram, and convert it
to an XKCD-style plot. It will work for plots with line & text elements,
including axes labels and titles (but not axes tick labels).
The idea for this comes from work by Damon McDougall
http://www.mail-archive.com/matplotlib-users@lists.sourceforge.net/msg25499.html
"""
import numpy as np
import pylab as pl
from scipy import interpolate, signal
import matplotlib.font_manager as fm
# We need a special font for the code below. It can be downloaded this way:
import os
import urllib2
if not os.path.exists('Humor-Sans.ttf'):
fhandle = urllib2.urlopen('http://antiyawn.com/uploads/Humor-Sans.ttf')
open('Humor-Sans.ttf', 'w').write(fhandle.read())
def xkcd_line(x, y, xlim=None, ylim=None,
mag=1.0, f1=30, f2=0.05, f3=15):
"""
Mimic a hand-drawn line from (x, y) data
Parameters
----------
x, y : array_like
arrays to be modified
xlim, ylim : data range
the assumed plot range for the modification. If not specified,
they will be guessed from the data
mag : float
magnitude of distortions
f1, f2, f3 : int, float, int
filtering parameters. f1 gives the size of the window, f2 gives
the high-frequency cutoff, f3 gives the size of the filter
Returns
-------
x, y : ndarrays
The modified lines
"""
x = np.asarray(x)
y = np.asarray(y)
# get limits for rescaling
if xlim is None:
xlim = (x.min(), x.max())
if ylim is None:
ylim = (y.min(), y.max())
if xlim[1] == xlim[0]:
xlim = ylim
if ylim[1] == ylim[0]:
ylim = xlim
# scale the data
x_scaled = (x - xlim[0]) * 1. / (xlim[1] - xlim[0])
y_scaled = (y - ylim[0]) * 1. / (ylim[1] - ylim[0])
# compute the total distance along the path
dx = x_scaled[1:] - x_scaled[:-1]
dy = y_scaled[1:] - y_scaled[:-1]
dist_tot = np.sum(np.sqrt(dx * dx + dy * dy))
# number of interpolated points is proportional to the distance
Nu = int(200 * dist_tot)
u = np.arange(-1, Nu + 1) * 1. / (Nu - 1)
# interpolate curve at sampled points
k = min(3, len(x) - 1)
res = interpolate.splprep([x_scaled, y_scaled], s=0, k=k)
x_int, y_int = interpolate.splev(u, res[0])
# we'll perturb perpendicular to the drawn line
dx = x_int[2:] - x_int[:-2]
dy = y_int[2:] - y_int[:-2]
dist = np.sqrt(dx * dx + dy * dy)
# create a filtered perturbation
coeffs = mag * np.random.normal(0, 0.01, len(x_int) - 2)
b = signal.firwin(f1, f2 * dist_tot, window=('kaiser', f3))
response = signal.lfilter(b, 1, coeffs)
x_int[1:-1] += response * dy / dist
y_int[1:-1] += response * dx / dist
# un-scale data
x_int = x_int[1:-1] * (xlim[1] - xlim[0]) + xlim[0]
y_int = y_int[1:-1] * (ylim[1] - ylim[0]) + ylim[0]
return x_int, y_int
#### End copy & paste
in2011 = np.array([
539491,
537521,
579590,
688686,
790901,
814661,
761457,
770781,
728518,
686134,
642516,
571452,
550916,
538165,
453962,
701366,
], dtype=float)
brate = in2011[0]/in2011[4:8].sum()
drate = in2011[0]/in2011[-1:].sum()
population = [in2011.sum()]
rate = in2011[-3:].sum()/float(in2011[4:8].sum())
rates = [rate]
steps = 20
for i in xrange(steps):
old = in2011[-1]
in2011[1:] = in2011[:-1]
in2011[0] = brate * in2011[4:8].sum()
in2011[-1] += (1.-drate)*old
rate = in2011[-3:].sum()/float(in2011[4:8].sum())
rates.append(rate)
population.append(in2011.sum())
population = np.array(population)
rates = np.array(rates)
years = 2011.+np.arange(0,5*steps+1,5)
years_,population = xkcd_line(years, population/1000./1000.)
plt.plot(years_, population, 'r', lw=3)
plt.xlabel('Year')
plt.ylabel('Population (in millions)')
ax2 = plt.twinx()
years_,rates = xkcd_line(years, rates)
ax2.plot(years_, rates, 'b', lw=3)
ax2.set_ylabel('Dependency ratio')
plt.savefig('population.png')
brate = [
24.1, 24.4, 24.5, 23.5, 24.0, 23.4, 23.2, 22.8, 22.1, 21.7, 20.8, 21.0, 20.2,
20.0, 19.6, 19.8, 20.0, 19.1, 17.5, 16.6, 16.2, 15.4, 15.2, 14.5, 14.3, 13.0,
12.6, 12.3, 12.2, 11.8, 11.7, 11.7, 11.5, 11.4, 10.9, 10.7, 11.0, 11.2, 11.2,
11.4, 11.7, 11.0, 11.0, 10.8, 10.4, 10.4, 10.0, 9.7, 9.8, 9.4, 9.6, 9.2]
plt.clf()
plt.xlabel('year')
plt.ylabel('fertility rate')
years = np.arange(1960,1960+len(brate))
years_, brate = xkcd_line(years, brate)
plt.plot(years_, brate, 'r', lw=3)
plt.savefig('fertility.png')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.