R: How to Layout and Design an Infographic
[This article was first published on Analysis with Programming, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
As promised from my recent article, here’s my tutorial on how to layout and design an infographic in R. This article will serve as a template for more infographic design that I plan to share on future posts. Hence, we will go through the following sections:
To start with, we need to setup our data first. And for illustration purposes, we will use a simulated data:
So that’s the default theme of ggplot2, and we want to customize this using the
What happens above is that all fonts installed in your machine will be imported. It’s better to import all of it so that we’ll have several choices to play on. For the above infographic, the font used is called Impact, which is available on windows and I think on mac as well. If you don’t have that, then download and install it first before running the above codes. To arrive on the design of the bar plot in the infographic we use the following theme,
I named it
Obtain by running
And you’ll have
So that’s our first plot, next is to plot
Obtain by running the following code:
Applying
Above plot is generated by running
So that we have the following result:
Now that’s better, one more issue is the title label for the legend. To change the label, run the following code:
And that will give us
Finally,
by default we have,
Applying

- Layout – mainly handles by grid package.
- Design – style of the elements in the layout.
- Texts – use extrafont package for custom fonts;
- Shapes (lines and point characters) – use grid, although this package has been removed from CRAN (as of February 26, 2015), the compressed file of the source code of the package is still available. But if I am not mistaken, by default this package is included in R. You might check it first before installing.
- Plots – several choices for plotting data in R: base plot, lattice, or ggplot2 package.
The Infographic
We aim to obtain the following layout and design in the final output of our code:To start with, we need to setup our data first. And for illustration purposes, we will use a simulated data:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
y1 <- round(rnorm(n = 36, mean = 7, sd = 2)) # Simulate data from normal distribution | |
y2 <- round(rnorm(n = 36, mean = 21, sd = 6)) | |
y3 <- round(rnorm(n = 36, mean = 50, sd = 8)) | |
x <- rep(LETTERS[1:12], 3) | |
grp <- rep(c("Grp 1", "Grp 2", "Grp 3"), each = 12) | |
dat <- data.frame(grp, x, y1, y2, y3) |
Colour
The aesthetic of an infographic not only depends on the shapes and plots, but also on the colours. So if you are not an artist, I suggest to look first for a list of sample infographics to get some inspiration. Once you have found the theme for your charts, grab the colour of it. To grab the colour, use eyedropper tool from software such as photoshop, affinity designer, etc. There is also free add ons for Mozilla Firefox called ColorZilla, I haven’t tried it but maybe you could explore that. For the above theme, there are five colours with the following hexadecimal colour code:Colour Name | Hexadecimal |
---|---|
Table 1: Colours Used for in the Infographic. | |
Dark Violet | #552683 |
Dark Yellow | #E7A922 |
White | #FFFFFF |
Gray (Infographic Text) | #A9A8A7 |
Dark Yellow (Crime Text) | #CA8B01 |
Data Visualization
At this point, we’ll prepare the elements in the layout, and we begin with the plots. Below is the bar plot ofy1
in the data frame, dat
, in three groupings, grp
. Note that the plot you’ll obtain will not be the same with the one below since the data changes every time we run the simulation above. 
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
library(ggplot2) | |
# Using default theme | |
p1 <- ggplot(data = dat, aes(x = x, y = y1)) + geom_bar(stat = "identity", fill = "#552683") + | |
coord_flip() + ylab("Y LABEL") + xlab("X LABEL") + facet_grid(. ~ grp) + | |
ggtitle("TITLE OF THE FIGURE") | |
p1 |
theme
function. One of the elements in the plot that will be tweaked is the font. To deal with this we need to import the fonts using the extrafont package. That is,
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
library(extrafont) | |
font_import() # Import all fonts | |
fonts() # Print list of all fonts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Configure Theme | |
kobe_theme <- function() { | |
theme( | |
plot.background = element_rect(fill = "#E2E2E3", colour = "#E2E2E3"), | |
panel.background = element_rect(fill = "#E2E2E3"), | |
panel.background = element_rect(fill = "white"), | |
axis.text = element_text(colour = "#E7A922", family = "Impact"), | |
plot.title = element_text(colour = "#552683", face = "bold", size = 18, vjust = 1, family = "Impact"), | |
axis.title = element_text(colour = "#552683", face = "bold", size = 13, family = "Impact"), | |
panel.grid.major.x = element_line(colour = "#E7A922"), | |
panel.grid.minor.x = element_blank(), | |
panel.grid.major.y = element_blank(), | |
panel.grid.minor.y = element_blank(), | |
strip.text = element_text(family = "Impact", colour = "white"), | |
strip.background = element_rect(fill = "#E7A922"), | |
axis.ticks = element_line(colour = "#E7A922") | |
) | |
} |
kobe_theme
since if you recall from my previous article, the above chart is inspired by Kobe Bryant Infographic. So applying this to the plot we’ll have the following, 
p1 + kobe_theme()
. If in case you want to reorder the ticks in the x-axis, by starting with A from the top and ending with L in the bottom, simply run the following,
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
x_id <- rep(12:1, 3) # use this index for reordering the x ticks | |
p1 <- ggplot(data = dat, aes(x = reorder(x, x_id), y = y1)) + geom_bar(stat = "identity", fill = "#552683") + | |
coord_flip() + ylab("Y LABEL") + xlab("X LABEL") + facet_grid(. ~ grp) + | |
ggtitle("TITLE OF THE FIGURE") | |
p1 + kobe_theme() |

y2
from dat
data frame, this time using the line plot. 
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
p2 <- ggplot(data = dat, aes(x = x, y = y2, group = factor(grp))) + | |
geom_line(stat = "identity", aes(linetype = factor(grp)), size = 0.7, colour = "#552683") + | |
ylab("Y LABEL") + xlab("X LABEL") + ggtitle("TITLE OF THE FIGURE") | |
p2 |
kobe_theme
, will give us 
p2 + kobe_theme()
. We should expect this since the kobe_theme
that was applied in the bar plot with coord_flip
option enabled, affects the orientation of the grids. So instead, we do a little tweak on the current theme, and see for yourself the difference:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
kobe_theme2 <- function() { | |
theme( | |
legend.position = "bottom", legend.title = element_text(family = "Impact", colour = "#552683", size = 10), | |
legend.background = element_rect(fill = "#E2E2E3"), | |
legend.key = element_rect(fill = "#E2E2E3", colour = "#E2E2E3"), | |
legend.text = element_text(family = "Impact", colour = "#E7A922", size = 10), | |
plot.background = element_rect(fill = "#E2E2E3", colour = "#E2E2E3"), | |
panel.background = element_rect(fill = "#E2E2E3"), | |
panel.background = element_rect(fill = "white"), | |
axis.text = element_text(colour = "#E7A922", family = "Impact"), | |
plot.title = element_text(colour = "#552683", face = "bold", size = 18, vjust = 1, family = "Impact"), | |
axis.title = element_text(colour = "#552683", face = "bold", size = 13, family = "Impact"), | |
panel.grid.major.y = element_line(colour = "#E7A922"), | |
panel.grid.minor.y = element_blank(), | |
panel.grid.major.x = element_blank(), | |
panel.grid.minor.x = element_blank(), | |
strip.text = element_text(family = "Impact", colour = "white"), | |
strip.background = element_rect(fill = "#E7A922"), | |
axis.ticks = element_line(colour = "#E7A922") | |
) | |
} |

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
p2 + kobe_theme2() + scale_linetype_discrete("GROUP") |

y3
variable is plotted using the following codes:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
p3 <- ggplot(data = dat, aes(x = reorder(x, rep(1:12, 3)), y = y3, group = factor(grp))) + | |
geom_bar(stat = "identity", fill = "#552683") + coord_polar() + facet_grid(. ~ grp) + | |
ylab("Y LABEL") + xlab("X LABEL") + ggtitle("TITLE OF THE FIGURE") | |
p3 |

kobe_theme2()
, 
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
p3 + kobe_theme2() |
Layout
All plots are now set, next is to place it in the layout. The following steps explain the procedure:- Start by creating new grid plot,
grid.newpage()
; - Next define the layout of the grid. Think of this as a matrix of plots, where a 2 by 2 matrix plot will give us 4 windows (two rows and two columns). This windows will serve as a placeholder of the plots. So to achieve a matrix plot with 4 rows and 3 columns, we runThis file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
pushViewport(viewport(layout = grid.layout(4, 3))) - Next is the background colour, this will be the background colour of the infographic. For the given chart, we run the following:This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
grid.rect(gp = gpar(fill = "#E2E2E3", col = "#E2E2E3")) - Next is to insert texts in the layout, use the
grid.text
function. The position of objects/elements such as texts in the grid is defined by the (x, y) coordinates. The bound of the grid by default is a unit square, of course the aspect ratio of the square can be modified. So the support of x and y is $[0,1]^2$; - To insert the plot into a specific window in the matrix plot use the
vplayout
function for the coordinates of the placeholder, andprint
for pasting. Say we want to insert the first plot in first row, second column, we code it this wayThis file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersprint(p1, vp = vplayout(1, 2)) This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersprint(p1, vp = vplayout(1, 1:3))
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Generate Infographic in PDF format | |
library(grid) | |
pdf("~/Documents/Infographics1.pdf", width = 10, height = 20) | |
grid.newpage() | |
pushViewport(viewport(layout = grid.layout(4, 3))) | |
grid.rect(gp = gpar(fill = "#E2E2E3", col = "#E2E2E3")) | |
grid.text("INFOGRAPHIC", y = unit(1, "npc"), x = unit(0.5, "npc"), vjust = 1, hjust = .5, gp = gpar(fontfamily = "Impact", col = "#A9A8A7", cex = 12, alpha = 0.3)) | |
grid.text("RProgramming", y = unit(0.94, "npc"), gp = gpar(fontfamily = "Impact", col = "#E7A922", cex = 6.4)) | |
grid.text("BY AL-AHMADGAID B. ASAAD", vjust = 0, y = unit(0.92, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 0.8)) | |
grid.text("ANALYSIS WITH PROGRAMMING", vjust = 0, y = unit(0.913, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 0.8)) | |
grid.text("alstatr.blogspot.com", vjust = 0, y = unit(0.906, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 0.8)) | |
print(p3, vp = vplayout(4, 1:3)) | |
print(p1, vp = vplayout(3, 1:3)) | |
print(p2, vp = vplayout(2, 1:3)) | |
grid.rect(gp = gpar(fill = "#E7A922", col = "#E7A922"), x = unit(0.5, "npc"), y = unit(0.82, "npc"), width = unit(1, "npc"), height = unit(0.11, "npc")) | |
grid.text("CATEGORY", y = unit(0.82, "npc"), x = unit(0.5, "npc"), vjust = .5, hjust = .5, gp = gpar(fontfamily = "Impact", col = "#CA8B01", cex = 13, alpha = 0.3)) | |
grid.text("A VERY VERY VERY VERY LONG TITLE", vjust = 0, hjust = 0, x = unit(0.01, "npc"), y = unit(0.88, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 1.2)) | |
grid.text("DATA INFO", vjust = 0, hjust = 0, x = unit(0.01, "npc"), y = unit(0.86, "npc"), gp = gpar(fontfamily = "Impact", col = "white", cex = 1.2)) | |
grid.text(paste( | |
"Syndicated to", | |
"Source", | |
"Author", | |
"Maintainer", | |
"Frequency of Update", | |
"Granularity", | |
"Temporal Date", sep = "\n"), vjust = 0, hjust = 0, x = unit(0.01, "npc"), y = unit(0.79, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 0.8)) | |
grid.text(paste( | |
"http://alstatr.blogspot.com", | |
"http://alstatr.blogspot.com", | |
"Analysis with Programming", | |
"Al-Ahmadgaid B. Asaad", | |
"Annually", | |
"National", | |
"2011-2013", sep = "\n"), vjust = 0, hjust = 0, x = unit(0.15, "npc"), y = unit(0.79, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 0.8)) | |
dev.off() | |
# Generate Infographic in PNG Format | |
png("~/Documents/Infographics1.png", width = 10, height = 20, units = "in", res = 500) | |
grid.newpage() | |
pushViewport(viewport(layout = grid.layout(4, 3))) | |
grid.rect(gp = gpar(fill = "#E2E2E3", col = "#E2E2E3")) | |
grid.text("INFOGRAPHIC", y = unit(1, "npc"), x = unit(0.5, "npc"), vjust = 1, hjust = .5, gp = gpar(fontfamily = "Impact", col = "#A9A8A7", cex = 12, alpha = 0.3)) | |
grid.text("RProgramming", y = unit(0.94, "npc"), gp = gpar(fontfamily = "Impact", col = "#E7A922", cex = 6.4)) | |
grid.text("BY AL-AHMADGAID B. ASAAD", vjust = 0, y = unit(0.92, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 0.8)) | |
grid.text("ANALYSIS WITH PROGRAMMING", vjust = 0, y = unit(0.913, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 0.8)) | |
grid.text("alstatr.blogspot.com", vjust = 0, y = unit(0.906, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 0.8)) | |
print(p3, vp = vplayout(4, 1:3)) | |
print(p1, vp = vplayout(3, 1:3)) | |
print(p2, vp = vplayout(2, 1:3)) | |
grid.rect(gp = gpar(fill = "#E7A922", col = "#E7A922"), x = unit(0.5, "npc"), y = unit(0.82, "npc"), width = unit(1, "npc"), height = unit(0.11, "npc")) | |
grid.text("CATEGORY", y = unit(0.82, "npc"), x = unit(0.5, "npc"), vjust = .5, hjust = .5, gp = gpar(fontfamily = "Impact", col = "#CA8B01", cex = 13, alpha = 0.3)) | |
grid.text("A VERY VERY VERY VERY LONG TITLE", vjust = 0, hjust = 0, x = unit(0.01, "npc"), y = unit(0.88, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 1.2)) | |
grid.text("DATA INFO", vjust = 0, hjust = 0, x = unit(0.01, "npc"), y = unit(0.86, "npc"), gp = gpar(fontfamily = "Impact", col = "white", cex = 1.2)) | |
grid.text(paste( | |
"Syndicated to", | |
"Source", | |
"Author", | |
"Maintainer", | |
"Frequency of Update", | |
"Granularity", | |
"Temporal Date", sep = "\n"), vjust = 0, hjust = 0, x = unit(0.01, "npc"), y = unit(0.79, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 0.8)) | |
grid.text(paste( | |
"http://alstatr.blogspot.com", | |
"http://alstatr.blogspot.com", | |
"Analysis with Programming", | |
"Al-Ahmadgaid B. Asaad", | |
"Annually", | |
"National", | |
"2011-2013", sep = "\n"), vjust = 0, hjust = 0, x = unit(0.15, "npc"), y = unit(0.79, "npc"), gp = gpar(fontfamily = "Impact", col = "#552683", cex = 0.8)) | |
dev.off() |
PNG Output

PDF Output
To leave a comment for the author, please follow the link and comment on their blog: Analysis with Programming.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.