How can we make xkcd style graphs?
You might want to consider the following package:
Package xkcd: Plotting ggplot2 graphics in a XKCD style.
library(xkcd)
vignette("xkcd-intro")
Some examples (Scatterplots, Bar Charts):
- Scatterplot:
- Bar Chart:
xkcd style graphs in MATLAB
I see two ways to solve this: The first way is to add some jitter to the x/y coordinates of the plot features. This has the advantage that you can easily modify a plot, but you have to draw the axes yourself if you want to have them xkcdyfied (see @Rody Oldenhuis' solution). The second way is to create a non-jittery plot, and use imtransform
to apply a random distortion to the image. This has the advantage that you can use it with any plot, but you will end up with an image, not an editable plot.
I'll show #2 first, and my attempt at #1 below (if you like #1 better, look at Rody's solution!).
This solution relies on two key functions: EXPORT_FIG from the file exchange to get an anti-aliased screenshot, and IMTRANSFORM to get a transformation.
%# define plot data
x = 1:0.1:10;
y1 = sin(x).*exp(-x/3) + 3;
y2 = 3*exp(-(x-7).^2/2) + 1;
%# plot
fh = figure('color','w');
hold on
plot(x,y1,'b','lineWidth',3);
plot(x,y2,'w','lineWidth',7);
plot(x,y2,'r','lineWidth',3);
xlim([0.95 10])
ylim([0 5])
set(gca,'fontName','Comic Sans MS','fontSize',18,'lineWidth',3,'box','off')
%# add an annotation
annotation(fh,'textarrow',[0.4 0.55],[0.8 0.65],...
'string',sprintf('text%shere',char(10)),'headStyle','none','lineWidth',1.5,...
'fontName','Comic Sans MS','fontSize',14,'verticalAlignment','middle','horizontalAlignment','left')
%# capture with export_fig
im = export_fig('-nocrop',fh);
%# add a bit of border to avoid black edges
im = padarray(im,[15 15 0],255);
%# make distortion grid
sfc = size(im);
[yy,xx]=ndgrid(1:7:sfc(1),1:7:sfc(2));
pts = [xx(:),yy(:)];
tf = cp2tform(pts+randn(size(pts)),pts,'lwm',12);
w = warning;
warning off images:inv_lwm:cannotEvaluateTransfAtSomeOutputLocations
imt = imtransform(im,tf);
warning(w)
%# remove padding
imt = imt(16:end-15,16:end-15,:);
figure('color','w')
imshow(imt)
Here's my initial attempt at jittering
%# define plot data
x = 1:0.1:10;
y1 = sin(x).*exp(-x/3) + 3;
y2 = 3*exp(-(x-7).^2/2) + 1;
%# jitter
x = x+randn(size(x))*0.01;
y1 = y1+randn(size(x))*0.01;
y2 = y2+randn(size(x))*0.01;
%# plot
figure('color','w')
hold on
plot(x,y1,'b','lineWidth',3);
plot(x,y2,'w','lineWidth',7);
plot(x,y2,'r','lineWidth',3);
xlim([0.95 10])
ylim([0 5])
set(gca,'fontName','Comic Sans MS','fontSize',18,'lineWidth',3,'box','off')
xkcd style graph - error with registered fonts
I think I had the same problem some time ago. Here is what I did:
Put Humor-Sans font file into your project folder and make sure your working directory is set to the same.
Import the fonts (this might take a while) by calling
font_import()
Look through the list of fonts and see if you can find Humor-Sans by
fonts()
Load the fonts
loadfonts(device = "win")
Let me know if it works!
Getting xkcd plots using matplotlib
To get it working, you need
- matplotlib 1.3.1 (it won't work with matplotlib 1.3.0 or earlier)
sudo pip install matplotlib --upgrade
- font Humor Sans
- download from here or here, install (on OS X you open it and click Install)
- remove the matplotlib font cache (as suggested by DanHickstein in matplotlib/issues/2269)
rm ~/.matplotlib/fontList.cache
Now, execute the code and it should work.
You do not need to change backend to TkAgg
, as some people suggest. For me it works perfectly fine on 'module://IPython.kernel.zmq.pylab.backend_inline'
(you can check it by plt.get_backend()
).
(I had the same problem and I've solved it, at least on OS X 10.8.5, with matplotlib 1.3.1 and IPython 2.0.0; removing font cache was necessary to get the font running.)
Matplotlib text won't display in xkcd font
As the examples show, you'll need to put plt.xkcd()
at the start of the code, before all the plotting commands. Thus:
from matplotlib import pyplot as plt
import numpy as np
x = np.arange(10)
y = np.sin(x)
plt.xkcd()
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax1 = fig.add_subplot(1,1,1)
ax1.plot(x,y)
ax1.xaxis.set_visible(False)
ax1.yaxis.set_visible(False)
plt.axvline(x=2.3, color='k', ls='dashed')
plt.axvline(x=6, color='k', ls='dashed')
ax.text(4,4,'Culture Shock', size=16)
plt.title('Test title')
plt.show()
which results in this figure for me:
As you see, the wobbly lines are there, but the font is wrong, simply because it's not available on my Linux machine (I also get a warning about this on the command line).
Putting plt.xkcd()
at the end of the code results in the straightforward matplotlib figure, without the wobbly lines.
Here is a summary of what pyplot.xkcd()
does under the hood; it just sets a lot of resource parameters:
rcParams['font.family'] = ['Humor Sans', 'Comic Sans MS']
rcParams['font.size'] = 14.0
rcParams['path.sketch'] = (scale, length, randomness)
rcParams['path.effects'] = [
patheffects.withStroke(linewidth=4, foreground="w")]
rcParams['axes.linewidth'] = 1.5
rcParams['lines.linewidth'] = 2.0
rcParams['figure.facecolor'] = 'white'
rcParams['grid.linewidth'] = 0.0
rcParams['axes.unicode_minus'] = False
rcParams['axes.color_cycle'] = ['b', 'r', 'c', 'm']
rcParams['xtick.major.size'] = 8
rcParams['xtick.major.width'] = 3
rcParams['ytick.major.size'] = 8
rcParams['ytick.major.width'] = 3
Related Topics
Floating Point Less-Than-Equal Comparisons After Addition and Substraction
How to Access the Last Value in a Vector
Pass a Vector of Variable Names to Arrange() in Dplyr
Add "Filename" Column to Table as Multiple Files Are Read and Bound
R - Group by Variable and Then Assign a Unique Id
Reading Multiple Files and Calculating Mean Based on User Input
How to One Hot Encode Several Categorical Variables in R
Use Merge() to Update a Data Frame with Values from a Second Data Frame
Alternative to Expand.Grid for Data.Frames
Sum Cells of Certain Columns for Each Row
Create Categories by Comparing a Numeric Column with a Fixed Value
Mean of Each Element of a List of Matrices
Ggplot2 Multiple Sub Groups of a Bar Chart
What Are the R Sorting Rules of Character Vectors
Collapsing Data Frame by Selecting One Row Per Group
How to Initialize Empty Data Frame (Lot of Columns at the Same Time) in R