\documentclass[article]{jss} %% Alt-n s %%\VignetteIndexEntry{Using xkcd} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% declarations for jss.cls %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \usepackage[utf8]{inputenc} \usepackage{caption} \usepackage{subcaption} \newcommand*{\captionsource}[2]{% \caption[{#1}]{% #1% \footnotesize{}% \\\hspace{\linewidth}% Source: #2% }% } %% almost as usual \author{Emilio Torres-Manzanera\\University of Oviedo} \title{\pkg{xkcd}: An \proglang{R} Package for Plotting XKCD Graphs} %% for pretty printing and a nice hypersummary also set: \Plainauthor{Emilio Torres-Manzanera} %% comma-separated \Plaintitle{xkcd: Plotting XKCD graphs} %% without formatting \Shorttitle{\pkg{xkcd}: Plotting XKCD Graphs} %% a short title (if necessary) %% an abstract and keywords \Abstract{ \href{http://xkcd.com}{XKCD} is a popular stick figure web comic with themes in mathematics, science, language, and romance created by Randall Munroe. Folk have figured out how to make XKCD style graphs in \proglang{Mathematica}, in \proglang{python}, \LaTeX{} and in other programming languages. But so far there is no an elegant solution to make it in \proglang{R}. \pkg{xkcd} gives a satisfactory answer to the question \emph{How can we make XKCD style graphs in \proglang{R}?}. It provides a set of functions for plotting data in an XKCD style using \pkg{ggplot2}. } \Keywords{XKCD, stick figure, \pkg{ggplot2}, \pkg{xkcd}, \proglang{R}} \Plainkeywords{XKCD, , stick figure, ggplot2, xkcd, R} %% without formatting %% at least one keyword must be supplied %% publication information %% NOTE: Typically, this can be left commented and will be filled out by the technical editor %% \Volume{50} %% \Issue{9} %% \Month{June} %% \Year{2012} %% \Submitdate{2012-06-04} %% \Acceptdate{2012-06-04} %% The address of (at least) one author should be given %% in the following format: \Address{ Emilio Torres-Manzanera\\ Department of Statistics\\ Faculty of Comerce\\ University of Oviedo\\ C/ Luis Moya Blanco, 261, 33203 Gijón, Spain\\ E-mail: \email{torres@uniovi.es}\\ URL: \url{http://uce.uniovi.es/} } %% It is also possible to add a telephone and fax number %% before the e-mail in the following format: %% Telephone: +43/512/507-7103 %% Fax: +43/512/507-2851 %% for those who use Sweave please include the following line (with % symbols): %% need no \usepackage{Sweave.sty} \SweaveOpts{eval=FALSE} % FIXME %% end of declarations %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{document} %% include your article here, just as usual %% Note that you should use the \pkg{}, \proglang{} and \code{} commands. <>= install.packages(c("xkcd","splancs","reshape"), dependencies=TRUE) @ \section{Introduction and Main Motivation} The \href{http://xkcd.com}{XKCD} web site is a web comic created by \citet{xkcdcomicwepage}, who described it as a web comic of romance, sarcasm, math, and language. He use stick figures, very simple drawings composed of a few lines and curves, in his comics strips, that are available under the Creative Commons Attribution-NonCommercial 2.5 License (Fig.~\ref{fig:convincing}). Due to the popularity of Randall Munroe's work, several questions about how to draw XKCD style graphs using different programming languages were posted in Stack Overflow, a language-independent collaboratively edited question and answer site for programmers. Many authors tried to replicate such style using different programming languages. For instance, \citet{stackmathematica} and \citet{stackmatlab} created functions that apply a distortion using image processing to existing charts in \proglang{Mathematica} and in \proglang{Matlab}, respectively; there exists a \proglang{python} library focused on this style \citep{stackpython}; or \citet{stacklatex} proposed an example in \LaTeX{} (Fig.~\ref{fig:programminglanguages}). \begin{figure} \centering \includegraphics[width=\textwidth]{convincing} \caption{\href{http://xkcd.com/833/}{Convincing (And if you labeled your axes, I could tell you exactly how much better)} \citep{xkcdcomicconvinncing}.} \label{fig:convincing} \end{figure} \begin{figure} \centering % \begin{subfigure}[b]{0.3\textwidth} % \includegraphics[width=\textwidth]{grmathematica} % \caption{\proglang{Mathematica} } % \label{fig:grmathematica} % \end{subfigure}% % ~ %add desired spacing between images, e. g. ~, \quad, \qquad, \hfill etc. % % (or a blank line to force the subfigure onto a new line) \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{grpython} \caption{\proglang{Python}} \label{fig:grpython} \end{subfigure}% ~ %add desired spacing between images, e. g. ~, \quad, \qquad, \hfill etc. % (or a blank line to force the subfigure onto a new line) \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{grlatex} \caption{\LaTeX} \label{fig:gralatex} \end{subfigure} \captionsource{Examples of XKCD graphs in several programming languages.}{\citet{stackpython,stacklatex}}\label{fig:programminglanguages} \end{figure} The \proglang{R} language \citep{R:2104}, despite of being a software environment for statistical computing and graphics, lacked of a specific package devoted to plot graphs in an XKCD style. \pkg{RXKCD} \citep{rxkcd} allowed the visualisation of XKCD comic strip directly from \proglang{R}, and there was just a function to plot a tree with this style in \pkg{phytools} \citep{phytools}. To the best of our knowledge, there was not a satisfactory response to the question \href{http://stackoverflow.com/questions/12675147/how-can-we-make-xkcd-style-graphs-in-r}{\textit{How can we make xkcd style graphs in \proglang{R}?}} published in Stack Overflow by \citet{stackr}. There was not a specific package devoted to draw stick figures, where the head is represented by a circle an the arms, legs and torso are all represented by straight lines, nor to plot axis or lines as in a handmade drawing. Fortunately, \proglang{R} is rich with facilities for creating and developing interesting graphics \citep{crantaskviewsgraphics}. For instance, \pkg{lattice} \citep{lattice} and \pkg{ggplot2} \citep{ggplot2} allowed for building many types of plots with sophisticated layouts. In particular, the implementation of the semantic for graphics of \citet{Wilkinson:2005:GG:1088896} in \proglang{R} by \citet{ggplot2} allowed the design of XKCD style graphs. The package \pkg{xkcd} presented in this paper develops several functions to plot statistical graphs in a freehand sketch style following the guidelines of the \href{http://xkcd.com}{XKCD} web site. In this paper, an introduction to plot such graphs in \proglang{R} is detailed. The following section deals with installing xkcd fonts and saving graphs, a step that raised several questions among users. In the next section some basic examples are explained and the graph gallery section shows several complex plots. Finally, the article ends with a discussion concerning statistical information and creative drawing. \section{The XKCD fonts} The package \pkg{xkcd} uses the XKCD fonts, so you must install them in your computer. An easy way to check whether this fonts are installed in the computer or not is typing the following code and comparing the results (Fig.~\ref{fig:fonts}): <>= library(extrafont) library(ggplot2) if( 'xkcd' %in% fonts()) { p <- ggplot() + geom_point(aes(x=mpg, y=wt), data=mtcars) + theme(text = element_text(size = 16, family = "xkcd")) } else { warning("Not xkcd fonts installed!") p <- ggplot() + geom_point(aes(x=mpg, y=wt), data=mtcars) } p @ %% <>= p <- ggplot() + geom_point(aes(x=mpg, y=wt), data=mtcars) ggsave("grnofonts.png",p) p <- ggplot() + geom_point(aes(x=mpg, y=wt), data=mtcars) + theme(text = element_text(size = 16, family = "xkcd")) ggsave("grfonts.png",p) @ %% \begin{figure} \centering \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{grnofonts} \caption{No XKCD fonts} \label{fig:grnofonts} \end{subfigure}% ~ %add desired spacing between images, e. g. ~, \quad, \qquad, \hfill etc. % (or a blank line to force the subfigure onto a new line) \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{grfonts} \caption{XKCD fonts installed} \label{fig:grfonts} \end{subfigure} \caption{Are XKCD fonts installed on your computer?}\label{fig:fonts} \end{figure} Look at the labels and check the type of font that appears on them. In the case that you do not see the XKCD fonts, you should get and install them following the instructions of the next subsection. \subsection{Installing the xkcd fonts in the computer} If the XKCD fonts are not installed in the system, you should install them using the package \pkg{extrafont} developed by \citet{extrafont}. In particular, the function \code{font_import()} registers font files and assigns a family name, \code{fonts()} lists available type fonts, \code{fonttable()} lists available font families, and finally, \code{loadfonts()} registers the fonts in the Adobe font metric table with \proglang{R}'s PDF (portable document format) or PostScript output device. <>= library(extrafont) download.file("http://simonsoftware.se/other/xkcd.ttf", dest="xkcd.ttf", mode="wb") system("mkdir ~/.fonts") system("cp xkcd.ttf ~/.fonts") font_import(pattern = "[X/x]kcd", prompt=FALSE) fonts() fonttable() if(.Platform$OS.type != "unix") { ## Register fonts for Windows bitmap output loadfonts(device="win") } else { loadfonts() } @ In the previous code, a font file in format \code{ttf} (TrueType outline font) is downloaded from a external site and installed in the computer. If you want to modify these fonts, you may use the spline font database file format (\code{sfd}), \href{https://github.com/ipython/xkcd-font}{the official xkcd font} created by \citet{fontsdfxkcd} and distributed under a Creative Commons Attribution-NonCommercial 3.0 License, which can be opened with FontForge, an open-source font editor \citep{fontforge}. \subsection{Saving the graphs} \code{ggsave()} is the preferred function for saving a \pkg{ggplot2} plot. For instance, the following instruction saves the graph as a bitmap file: <>= ggsave("gr1.png", p) @ If you want to save this chart as PDF you should embed the fonts into the PDF file, using \code{embed_fonts()} \citep{extrafont}. First, if you are running Windows, you may need to tell it where the Ghostscript program is, for embedding fonts. <>= ggsave("gr1.pdf", plot=p, width=12, height=4) if(.Platform$OS.type != "unix") { ## Needed for Windows. Make sure you have the correct path Sys.setenv(R_GSCMD = "C:\\Program Files (x86)\\gs\\gs9.06\\bin\\gswin32c.exe") } embed_fonts("gr1.pdf") @ \bigskip See the development site of \pkg{extrafont} for additional instructions and examples of using fonts other than the standard PostScript fonts, like TrueType fonts, with PDF or PostScript output files, and with bitmap output files in Windows \citep{extrafont}. \section[Installing xkcd]{Installing \pkg{xkcd}} The home site of \pkg{xkcd} is located at \href{http://xkcd.r-forge.r-project.org}{R-forge}, a central platform for the development of \proglang{R} packages. From within R, you can install the stable version from CRAN (The Comprehensive R Archive Network) with the following instruction: <>= install.packages("xkcd",dependencies = TRUE) @ Then, you may want to see the vignette and check the code: <>= help(package="xkcd") vignette("xkcd-intro") # It opens the PDF browseVignettes(package = "xkcd") # To browse the PDF, R and Rnw @ Once the package has been installed, it can be loaded by typing: <>= library(xkcd) @ Automatically, it loads the packages \pkg{ggplot2} and \pkg{extrafont}. The most relevant functions are \code{xkcdaxis()}, that plots axis in a handwritten style, \code{xkcdman()}, that draws stick figures, and \code{xkcdrect()}, that creates fuzzy rectangles. These functions are compatible with the grammar of graphics proposed by \citet{ggplot2}. From a technical point of view, lines plotted with the \pkg{xkcd} package are jittered with white noise and then smoothed using curves of Bézier with the \code{bezier()} function from \pkg{Hmisc} \citep{hmisc}. \section{Axis, Stick Figures and Facets} \label{sec:Axis} In order to get a handmade drawing of the axis and an XKCD theme, a specific function based on the \pkg{ggplot2} framework was created, \code{xkcdaxis()} (Fig.~\ref{fig:grtheme}): <>= xrange <- range(mtcars$mpg) yrange <- range(mtcars$wt) set.seed(123) # for reproducibility p <- ggplot() + geom_point(aes(mpg, wt), data=mtcars) + xkcdaxis(xrange,yrange) p @ <>= ggsave("graxis.png",p) @ \begin{figure} \centering %add desired spacing between images, e. g. ~, \quad, \qquad, \hfill etc. % (or a blank line to force the subfigure onto a new line) \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{graxis} \caption{xkcd theme} \label{fig:grtheme} \end{subfigure}% ~% \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{grstickfigure} \caption{Stick figures} \label{fig:stickfigure} \end{subfigure}% \caption{Creating handmade axis and stickmen.} \label{fig:graxis} \end{figure} Due to the fact that white random noise is used in the picture, it is convenient to fix a seed for reproducing the same figure (\code{set.seed()}). May be the most flashy function is \code{xkcdman()}, that draws a stick figure with different positions, angles and lengths (Fig.~\ref{fig:stickfigure}). <>= ratioxy <- diff(xrange)/diff(yrange) mapping <- aes(x, y, scale, ratioxy, angleofspine, anglerighthumerus, anglelefthumerus, anglerightradius, angleleftradius, anglerightleg, angleleftleg, angleofneck, linetype=city) dataman <- data.frame(x= c(15,30), y=c(3, 4), scale = c(0.3,0.51) , ratioxy = ratioxy, angleofspine = -pi/2 , anglerighthumerus = c(pi/4, -pi/6), anglelefthumerus = c(pi/2 + pi/4, pi +pi/6), anglerightradius = c(pi/3, -pi/3), angleleftradius = c(pi/3, -pi/3), anglerightleg = 3*pi/2 - pi / 12, angleleftleg = 3*pi/2 + pi / 12 , angleofneck = runif(1, 3*pi/2-pi/10, 3*pi/2+pi/10), city=c("Liliput","Brobdingnag")) p <- ggplot() + geom_point(aes(mpg, wt, colour=as.character(vs)), data=mtcars) + xkcdaxis(xrange,yrange) + xkcdman(mapping, dataman) p @ <>= ggsave("grstickfigure.png",p) @ Additionally, you may use the facet option of \pkg{ggplot2} to do split up your data by one or more variables and plot the subsets of data together. <>= p + facet_grid(.~vs) @ \section{Some Basic Examples} In this section the code to plot a line graph and a bar chart is detailed (Fig.~\ref{fig:basicexamples}). Remember to set the seed if you want to replicate your own figures (see Section~\ref{sec:Axis}). \begin{figure} \centering \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{grcaritas} \caption{Line graph} \label{fig:grcaritas} \end{subfigure}% ~ %add desired spacing between images, e. g. ~, \quad, \qquad, \hfill etc. % (or a blank line to force the subfigure onto a new line) \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{grbar} \caption{Bar graph} \label{fig:grbar} \end{subfigure} \caption{Some basic examples} \label{fig:basicexamples} \end{figure} <>= volunteers <- data.frame(year=c(2007:2011), number=c(56470, 56998, 59686, 61783, 64251)) xrange <- range(volunteers$year) yrange <- range(volunteers$number) ratioxy <- diff(xrange) / diff(yrange) datalines <- data.frame(xbegin=c(2008.3,2010.5),ybegin=c(63000,59600), xend=c(2008.5,2010.3), yend=c(63400,59000)) mapping <- aes(x, y, scale, ratioxy, angleofspine, anglerighthumerus, anglelefthumerus, anglerightradius, angleleftradius, anglerightleg, angleleftleg, angleofneck) dataman <- data.frame( x= c(2008,2010), y=c(63000, 58850), scale = 1000 , ratioxy = ratioxy, angleofspine = -pi/2 , anglerighthumerus = c(-pi/6, -pi/6), anglelefthumerus = c(-pi/2 - pi/6, -pi/2 - pi/6), anglerightradius = c(pi/5, -pi/5), angleleftradius = c(pi/5, -pi/5), angleleftleg = 3*pi/2 + pi / 12 , anglerightleg = 3*pi/2 - pi / 12, angleofneck = runif(1, 3*pi/2-pi/10, 3*pi/2+pi/10)) p <- ggplot() + geom_smooth(mapping=aes(x=year, y =number), data =volunteers, method="loess") + xkcdaxis(xrange,yrange) + ylab("Volunteers at Caritas Spain") + xkcdman(mapping, dataman) + annotate("text", x=2008.7, y = 63700, label = "We Need\nVolunteers!", family="xkcd" ) + annotate("text", x=2010.5, y = 60000, label = "Sure\nI can!", family="xkcd" ) + xkcdline(aes(xbegin=xbegin,ybegin=ybegin,xend=xend,yend=yend), datalines, xjitteramount = 0.12) p # Figure 5.a @ <>= ggsave("grcaritas.png",p) @ One interesting property of this charts is that when xkcd lines intersect, there is a space in blank in the crossing, following XKCD style (Fig.~\ref{fig:grcaritas}). The following code plots the line char as a bar chart (Fig.~\ref{fig:grbar}): <>= data <- volunteers data$xmin <- data$year - 0.1 data$xmax <- data$year + 0.1 data$ymin <- 50000 data$ymax <- data$number xrange <- range(min(data$xmin)-0.1, max(data$xmax) + 0.1) yrange <- range(min(data$ymin)+500, max(data$ymax) + 1000) mapping <- aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax) p <- ggplot() + xkcdrect(mapping,data) + xkcdaxis(xrange,yrange) + xlab("Year") + ylab("Volunteers at Caritas Spain") p # Figure 5.b @ %% $ (For emacs colour sintax) <>= ggsave("grbar.png",p) @ You may specify the width, the height, and colours of the bars (see \code{example(xkcdrect)}). \section{Graph Gallery} This gallery provides a variety of complex charts designed to address your idea (Fig.~\ref{fig:examples}). The code is in the \code{.Rnw} file of this paper and in the \href{http://xkcd.r-forge.r-project.org/}{R-forge} site, where there are more elaborate examples. Figures~\ref{fig:grhelp} and~\ref{fig:grmotherday} fill the area under the data with letters, Figure~\ref{fig:grhomosapiens} represents line graphs, and Figure~\ref{fig:grsevan} shows a population pyramidal. \begin{figure} \centering \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{grhelp} \caption{Help!} \label{fig:grhelp} \end{subfigure}% ~ %add desired spacing between images, e. g. ~, \quad, \qquad, \hfill etc. % (or a blank line to force the subfigure onto a new line) \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{grhomosapiens} \caption{Homo Sapiens Sapiens} \label{fig:grhomosapiens} \end{subfigure} \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{grsevan} \caption{A population pyramid} \label{fig:grsevan} \end{subfigure}% ~ %add desired spacing between images, e. g. ~, \quad, \qquad, \hfill etc. % (or a blank line to force the subfigure onto a new line) \begin{subfigure}[b]{0.5\textwidth} \includegraphics[width=\textwidth]{grmotherday} \caption{Mother's day} \label{fig:grmotherday} \end{subfigure} \caption{Graph gallery} \label{fig:examples} \end{figure} %% ============================================================ %% ============================================================ <>= library(zoo) library(xkcd) require(splancs) #install.packages("splancs", dependencies = TRUE, repos="http://cran.es.r-project.org/") mydatar <- read.table(text=" 6.202 5.965 5.778 5.693 5.639 5.273 4.978 4.833 4.910 4.696 4.574 4.645 4.612 ") mydata1 <- mydatar[dim(mydatar)[1]:1,] z <- zooreg(mydata1, end = as.yearqtr("2013-1"), frequency = 4) z mydata <- data.frame(parados=z) mydata$year <- as.numeric(as.Date(as.yearqtr(rownames(mydata)))) mydata$label <- paste(substr(rownames(mydata),3,4),substr(rownames(mydata),6,7),sep="") data <- mydata data$xmin <- as.numeric(data$year) -1 data$xmax <- data$xmin + 90 data$ymin <- 4.5 data$ymax <- data$parados n <- 3200 poligono <- mydata[,c("year","parados")] names(poligono) <- c("x","y") poligono <- rbind(poligono, c(max(poligono$x),4.4)) poligono <- rbind(poligono, c(min(poligono$x),4.4)) points <- data.frame(x=runif(n,range(poligono$x)[1],range(poligono$x)[2] ), y=runif(n,range(poligono$y)[1],range(poligono$y)[2] )) kk <- inout(points, poligono) points <- points[kk, ] points <- rbind(points,poligono) x <- points$x y <- points$y nman <- length(x) sizer <-runif(nman, 4, 6) nman xrange <- c(min(x),max(x)) yrange <- c(min(y),max(y)) ratioxy <- diff(xrange)/diff(yrange) n <- 2 set.seed(123) twomen <- xkcdman(mapping= aes(x, y, scale, ratioxy, angleofspine , anglerighthumerus, anglelefthumerus, anglerightradius, angleleftradius, anglerightleg, angleleftleg, angleofneck), data.frame(x=c(15600, 14800) , y=c(5.3, 5.7), scale = 0.2, ratioxy = ratioxy, angleofspine = runif(n, - pi/2 - pi/10, -pi/2 + pi/10), anglerighthumerus = runif(n, -pi/6- pi/10, - pi/6 + pi/10), anglelefthumerus = runif(n, pi + pi/6 -pi/10, pi + pi/6 + pi/10), anglerightradius = runif(n, -pi/4, pi/4), angleleftradius = runif(n, pi -pi/4, pi + pi/4), anglerightleg = runif(n, 3* pi/2 + pi/12 , 3* pi/2 + pi/12 + pi/10), angleleftleg = runif(n, 3* pi/2 - pi/12 - pi/10, 3* pi/2 - pi/12 ), angleofneck = runif(n, -pi/2-pi/10, -pi/2 + pi/10))) p1 <- ggplot() + geom_text(aes(x,y,label="0"), data.frame(x=x,y=y),family="xkcd",alpha=0.4,size=sizer) + xkcdaxis(xrange,yrange) + ylab("Unemployed persons (millions)") + xlab("Date") + twomen + annotate("text", x= 15250, y=5.95,label="Help!", family="xkcd",size=7) + xkcdline(aes(xbegin=xbegin,ybegin=ybegin,xend=xend,yend=yend), data=data.frame( xbegin=15600, ybegin=5.42, xend=15250, yend=5.902 ) , xjitteramount = 200) + theme(legend.position="none") #p1 p2 <- p1 + scale_x_continuous(breaks=as.numeric(mydata$year),label=mydata$label) p2 ggsave("grhelp.png") @ %% ============================================================ %% ============================================================ <>= library(reshape) mydata <- read.table(header=TRUE,sep=",",text=" year,ministerio,banco,fmi,homo 2013,2,1.95,1.96,1.94 2014,2.1,1.97,1.93,1.88 2015,2.2,2.05,1.90,1.87 ") mydatalong <- melt(mydata, id="year", measure.vars= names(mydata)[-1]) xrange <- c(2013,2015) yrange <- c(1.86,2.21) set.seed(123) ##p <- ggplot() + geom_smooth(aes(x=year, y=value, group=variable,linetype=variable), data=mydatalong, position = position_jitter(h=0.0001),color="black") + theme(legend.position = "none") + xkcdaxis(xrange,yrange) p <- ggplot() + geom_smooth(aes(x=year, y=value, group=variable,linetype=variable), data=mydatalong,color="black") + theme(legend.position = "none") + xkcdaxis(xrange,yrange) p2 <- p + ylab("Change in real GDP (%)") + xlab("Economic Projections of several Institutes") + scale_x_continuous(breaks=c(mydata$year), labels=c(mydata$year)) datalabel <- data.frame(x=2014.95, y=t(mydata[mydata$year==2015,c(2,3,4,5)]), label=c("Ministry of Economy","National Bank","International Monetary Fund","Homo Sapiens Sapiens*")) names(datalabel) <- c("x","y","label") p3 <- p2 + geom_text(aes(x=x,y=y,label=label), data=datalabel, hjust=1, vjust=1,family="xkcd",size=7) + annotate("text", x=2013.4, y=1.852, label="*Homo Sapiens Sapiens = Doubly Wise Man",family="xkcd",size=3.5) ggsave("grhomosapiens.png",p3) @ <>= resumen <- structure(list(tonombre = structure(c(1L, 2L, 3L, 11L, 4L, 5L, 8L, 6L, 7L, 9L, 10L, 14L, 12L, 13L, 15L), .Label = c("Andalucía", "Aragón", "Asturias", "Canarias", "Cantabria", "C-LaMancha", "CyLeón", "Cataluña", "Extremadura", "Galicia", "Baleares", "Madrid", "Murcia", "La Rioja", "Valencia"), class = "factor"), persons = c(2743706L, 515772L, 364410L, 399963L, 699410L, 212737L, 2847377L, 717874L, 894946L, 371502L, 942277L, 119341L, 2561918L, 493833L, 1661613L), frompersons = c(14266L, 3910L, 3214L, 3283L, 4371L, 1593L, 10912L, 8931L, 9566L, 3231L, 5407L, 940L, 21289L, 3202L, 9939L), topersons = c(10341L, 3805L, 2523L, 4039L, 3911L, 1524L, 12826L, 10897L, 7108L, 2312L, 4522L, 1066L, 26464L, 3529L, 9187L), llegan = c(0.38, 0.74, 0.69, 1.01, 0.56, 0.72, 0.45, 1.52, 0.79, 0.62, 0.48, 0.89, 1.03, 0.71, 0.55), sevan = c(0.52, 0.76, 0.88, 0.82, 0.62, 0.75, 0.38, 1.24, 1.07, 0.87, 0.57, 0.79, 0.83, 0.65, 0.6)), .Names = c("tonombre", "persons", "frompersons", "topersons", "llegan", "sevan"), row.names = c(NA, -15L), class = "data.frame") resumenlargo <- melt(resumen[,c("tonombre","llegan","sevan")]) oo <- order(resumen$llegan) nombreordenados <- (resumen$tonombre)[oo] nombreordenados resumenlargo$tonombre <- factor( resumenlargo$tonombre, levels=nombreordenados, ordered=TRUE) set.seed(130613) kk <- ggplot() + geom_bar( aes(y= value, x=tonombre,fill=variable ), data=resumenlargo[resumenlargo$variable=="llegan", ], stat="identity") + geom_bar(aes(y= (-1)* value, x=tonombre,fill=variable ), data=resumenlargo[resumenlargo$variable=="sevan", ], stat="identity") + scale_y_continuous(breaks=seq(-1.2,1.5,0.3),labels=abs(seq(-1.2,1.5,0.3))) + ylab("Movilidad de los asalariados (% sobre asalariados residentes)") + coord_flip() + theme_xkcd() + xlab("") + theme(axis.ticks.y = element_blank(), axis.text.y = element_blank()) kk2 <- kk + geom_text(aes(x=(tonombre),y=0,label=tonombre), data=resumenlargo,family="xkcd") lleganespana <- sum(resumen$topersons)*100/ sum(resumen$persons) sevanespana <- sum(resumen$frompersons)*100/ sum(resumen$persons) lineaespana1 <- xkcdline(mapping=aes(xbegin=1-0.5,ybegin=lleganespana,xend=15+0.5, yend=lleganespana, yjitteramount=0.051), data= resumenlargo, linetype=2,mask=FALSE) lineaespana2 <- xkcdline(mapping=aes(xbegin=1-0.5,ybegin=-lleganespana,xend=15+0.5, yend=-lleganespana), yjitteramount=0.051, data= resumenlargo,linetype=2,mask=FALSE) kk3 <- kk2 + xkcdline(mapping=aes(xbegin=as.numeric(tonombre)-0.5,ybegin=-1.24,xend=as.numeric(tonombre)-0.5, yend=1.52, xjitteramount=0.151), data= resumenlargo, size=3,color="white") + lineaespana1 + lineaespana2 kk4 <- kk3 + annotate("text",x=1, y=c(lleganespana,-lleganespana),label="Media de España", hjust=c(-0.11,-0.11), vjust=c(-0.1,0.1),family="xkcd",angle=90) kk5 <- kk4 + scale_fill_discrete(name="", breaks=c("llegan", "sevan"), labels=c("Llegan", "Se van")) + theme(legend.justification=c(0,0), legend.position=c(0,0)) xrange <- c(1,15) yrange <- c(-1.3,1.6) ratioxy <- diff(xrange)/diff(yrange) x <- 7 y <- 1.5 scale <- 0.35 mapman <- aes(x, y, scale, ratioxy, angleofspine , anglerighthumerus, anglelefthumerus, anglerightradius, angleleftradius, anglerightleg, angleleftleg, angleofneck) n <- 1 set.seed(130613) datamanflip <- data.frame( x= x, y= y, scale = scale , ratioxy = ratioxy, angleofspine = runif(n, -pi/2 -pi/2 - pi/10,-pi/2 -pi/2 + pi/10), ##angleofspine = runif(n, -0 - pi/10,-0 + pi/10), anglerighthumerus = runif(n, -pi/2-pi/6-pi/10, -pi/2 -pi/6+pi/10), anglelefthumerus = runif(n, -pi/2-pi/2 - pi/10, -pi/2 -pi/2 + pi/10), anglerightradius = runif(n, -pi/2-pi/5 - pi/10, -pi/2-pi/5 + pi/10), angleleftradius = runif(n, -pi/2-pi/5 - pi/10, -pi/2-pi/5 + pi/10), angleleftleg = runif(n, -pi/2 + 3*pi/2 + pi / 12 -pi/20,-pi/2 +3*pi/2 + pi / 12 +pi/20) , anglerightleg = runif(n, -pi/2 + 3*pi/2 - pi / 12 -pi/20, -pi/2+ 3*pi/2 - pi / 12 +pi/20) , angleofneck = runif(n, -pi/2+3*pi/2-pi/10, -pi/2+3*pi/2+pi/10)) p1 <- xkcdman(mapman , datamanflip) kk6 <- kk5 + p1 kk7 <- kk6 + annotate("text", x=9.3, y = 1.3, label="Unos vienen, otros se van",family="xkcd" ) + xkcdline(aes(xbegin=xbegin,xend=xend,yend=yend,ybegin=ybegin), yjitteramount=0.135,data=data.frame(xbegin=9.0, xend=7.2, ybegin=1.2, yend=1.3)) ggsave(kk7,filename="grsevan.png") @ %% ============================================================ %% ============================================================ <>= mommy <- read.table(sep=" ",text =" 8 100 9 0 10 0 11 0 12 0 13 0 14 100 15 100 16 500 17 420 18 75 19 50 20 100 21 40 22 0 ") names(mommy) <- c("hour","number") data <- mommy data$xmin <- data$hour - 0.25 data$xmax <- data$xmin + 1 data$ymin <- 0 data$ymax <- data$number xrange <- range(8, 24) yrange <- range(min(data$ymin) + 10 , max(data$ymax) + 200) ratioxy <- diff(xrange)/diff(yrange) timelabel <- function(text,x,y) { te1 <- annotate("text", x=x, y = y + 65, label=text, size = 6,family ="xkcd") list(te1, xkcdline(aes(xbegin=xbegin, ybegin= ybegin, xend=xend,yend=yend), data.frame(xbegin=x,ybegin= y + 50, xend=x,yend=y), xjitteramount = 0.5)) } n <- 1800 set.seed(123) x <- runif(n, xrange[1],xrange[2] ) y <- runif(n, yrange[1],yrange[2] ) inside <- unlist(lapply(1:n, function(i) any(data$xmin <= x[i] & x[i] < data$xmax & data$ymin <= y[i] & y[i] < data$ymax))) x <- x[inside] y <- y[inside] nman <- length(x) sizer <- round(runif(nman, 1, 10),0) angler <- runif(nman, -10,10) p <- ggplot() + geom_text(aes(x,y,label="Mummy",angle=angler,hjust=0, vjust=0), family="xkcd",size=sizer,alpha=0.3) + xkcdaxis(xrange,yrange) + annotate("text", x=16, y = 650, label="Happy Mother's day", size = 16,family ="xkcd") + xlab("daily schedule") + ylab("Number of times mothers are called on by their children") + timelabel("Wake up", 9, 125) + timelabel("School", 12.5, 90) + timelabel("Lunch", 15, 130) + timelabel("Homework", 18, 525) + timelabel("Bath", 21, 110) + timelabel("zzz", 23.5, 60) p ggsave("grmotherday.png",p) @ %% ============================================================ %% ============================================================ \section{Discussion} As \cite{chen2007handbook} stated, visualising the data is an essential part of any data analysis, but the role graphics played to enlighten the audience means different things to different people. On the one hand, statisticians argue that graphic display need to be clear, concise and accurate; on the other hand, artists say that to be effective, it need to be eye-catching, engaging, and innovative \citep{holmes12}. As \citet{xkcdcomicblogofractal} points out, the book of \citet{Tufte:1983} is a reference in such field as the visual communication of information. \citet{Tufte:1983} coined the word \textit{chartjunk} to refer to useless, non-informative, or information-obscuring elements of quantitative information displays and argue against using excessive decoration. Overloading your chart with XKCD elements may lead to loss of accuracy and the data visualisation might become a chartjunk. In order to avoid this error, you must think about what the consumers of your graphs are looking for. Charts designed for business decisions and those designed for t-shirts should not be the same. If you are trying to provoke or entertain, the XKCD style graphs may be suitable for your purpose and meaningful to your audience. In summary, the package \pkg{xkcd} is a \pkg{ggplot2} wrapper that makes graphs look like they came from an XKCD comic and it gives a satisfactory answer to the question \emph{How can we make XKCD style graphs in \proglang{R}?} \bibliography{article-ref} \tableofcontents \end{document} <>= require(tools) texi2dvi("xkcd-intro.tex", pdf = TRUE) @