7

I am looking for a way to do a (actually quite common) visualization, whereby the split of a population of, say, N units into several categories is shown via a set of N pictograms - I'd prefer filled squares; in a newspaper, etc., one might see little humanoid shapes - with each pictogram colored according to the category of n'th unit. N fixed to 1 or 100, and the chart displaying fractions or percentages rather than counts, would be OK. The colored "stripes" would have to wrap to multiple lines. Is anyone aware of this chart available in an R package?

To take a specific example,

x = sample(c("A","B"),100,replace = T)

I would like to see a 10x10 (or 5x20, or whatever) grid of colored squares, some - corresponding to "A" - colored green, others red. The green (and likewise red) squares could be "bunched", or left in the original order.

Thank you.

Marcus Campbell
  • 2,746
  • 4
  • 22
  • 36
Dimitri Shvorob
  • 495
  • 1
  • 6
  • 24

4 Answers4

8

Below we show 3 versions. The first uses squares, the next uses circles, the next uses an icon of a man and finally we use smiley faces.

Squares

# input data
set.seed(123)
x <- sample(c("A","B"),100,replace = T)

# input parameters - nr * nc should equal length(x)
cols <- c("green", "red")
nr <- 10
nc <- 10

# create data.frame of positions and colors
m <- matrix(cols[factor(x)], nr, nc)
DF <- data.frame(row = c(row(m)), col = c(col(m)[, nc:1]), value = c(m), 
      stringsAsFactors = FALSE)

# plot squares - modify cex to get different sized squares
plot(col ~ row, DF, col = DF$value, pch = 15, cex = 4, asp = 1,
     xlim = c(0, nr), ylim = c(0, nc),
     axes = FALSE, xlab = "", ylab = "")

enter image description here

Circles

# plot circles
plot(col ~ row, DF, col = DF$value, pch = 20, cex = 6, asp = 1,
     xlim = c(0, nr), ylim = c(0, nc),
     axes = FALSE, xlab = "", ylab = "")

enter image description here

png Icons This solution uses a black/white icon of a man which we have assumed has been saved in the current directory as man.png. We color it red and green and use those two versions in place of the squares or circles:

# blank graph to insert man icons into
plot(col ~ row, DF, col = DF$value, asp = 1,
     xlim = c(0, nr), ylim = c(0, nc),
     axes = FALSE, xlab = "", ylab = "", type = "n")

library(png)
man <- readPNG("man.png")

red.man <- man
red.man[,,1] <- man[,,4] # fill in red dimension
R <- subset(DF, value == "red")
with(R, rasterImage(red.man, 
     row-.5, col-.5, row+.5, col+.5, 
     xlim = c(0, nr), ylim = c(0, nc),
     xlab = "", ylab = ""))

green.man <- man
green.man[,,2] <- man[,,4] # fill in green dimension
G <- subset(DF, value == "green")
with(G, rasterImage(green.man, 
     row-.5, col-.5, row+.5, col+.5, 
     xlim = c(0, nr), ylim = c(0, nc),
     xlab = "", ylab = ""))

enter image description here

Smiley Face Icons This solution uses a green smiley face icon and a red frowning face icon which we have assumed have been saved in the current directory as smiley_green.jpg and smiley_red.jpg.

# blank graph to insert man icons into
xp <- 1.25
plot(col ~ row, DF, col = DF$value, asp = 1,
     xlim = c(0, xp * nr), ylim = c(0, xp * nc),
     axes = FALSE, xlab = "", ylab = "", type = "n")

library(jpeg)
smiley_green <- readJPEG("smiley_green.jpg")
smiley_red <- readJPEG("smiley_red.jpg")    

R <- subset(transform(DF, row = xp * row, col = xp * col), value == "red")
with(R, rasterImage(smiley_red,
     row - .5, col - .5, row + .5, col + .5, 
     xlim = c(0, xp * nr), ylim = c(0, xp * nc),
     xlab = "", ylab = ""))

G <- subset(transform(DF, row = xp * row, col = xp * col), value == "green")
with(G, rasterImage(smiley_green,
     row - .5, col - .5, row + .5, col + .5, 
     xlim = c(0, xp * nr), ylim = c(0, xp * nc),
     xlab = "", ylab = ""))

enter image description here

Revised To 10x10 green/red and added version using man icon.

G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
5

BINGO. My prayers have been answered with

http://rud.is/b/2015/03/18/making-waffle-charts-in-r-with-the-new-waffle-package/

(But many thanks for the solutions suggested earlier).

# devtools::install_github("hrbrmstr/waffle")
library(waffle)
x <- sample(c("A","B"),100,replace = T)
x <- c(A=sum(x=="A"), B=sum(x=="B"))
waffle(x, rows=10, colors=c("red", "green"))

enter image description here

jalapic
  • 13,792
  • 8
  • 57
  • 87
Dimitri Shvorob
  • 495
  • 1
  • 6
  • 24
3

I also made a package for this (nigh-simultaneously with that other guy :-). It has three approaches, using geom_tile, geom_text (use e.g. FontAwesome for icons) and geom_point. The latter two can do drop shadows, but you have to tinker with the settings sometimes. There's some more examples here.

devtools::install_github("rubenarslan/formr")
library(formr)
qplot_waffle(rep(1:3,each=40,length.out=90))
library(ggplot2)
qplot_waffle_text(rep(1, each = 30), symbol = "", rows = 3) + ggtitle("Number of travellers in 2008")

simple counts

counts of travellers

Ruben
  • 3,452
  • 31
  • 47
2

The OP requested a ggplot2 solution on the ggplot2 Google group, so I'm posting it here as well:

ggplot(DF, aes(row, col, fill=value)) + 
  geom_tile(colour="white", lwd=2) + 
  scale_fill_manual(values=c("green","red")) +
  theme(panel.background=element_blank(),
        axis.text=element_blank(),
        axis.ticks=element_blank(),
        axis.title=element_blank()) +
  guides(fill=FALSE)

enter image description here

eipi10
  • 91,525
  • 24
  • 209
  • 285