I want to make a picture with R. I have data like this: 3 Samples and 4 categories, with value A, B and C
Sam1 Sam2 Sam3
Cat1 A B;C C
Cat2 B A A;B
Cat3 A;C C A;B;C
Cat4 B A C
I want to make a plot, with stack colour for the multiple value. The output that I want is in the picture.
Can anyone help? Thank you.
(This solved by Robert Hacken, Thanks).. Another add-on that I want is add notes on the side For G1 has note D1 on the side, and so on... Is it possible?
Thank you.
With visualizations like this, I usually find it easiest to just draw them:
dat <- read.table(text='Sam1 Sam2 Sam3
Cat1 A B;C C
Cat2 B A A;B
Cat3 A;C C A;B;C
Cat4 B A C')
let.col <- c(A='red', B='#5b9bd5', C='#70ad47')
# width of the space between squares; square side + sep = 1, so sep=.2 means
# that the square's side will be four times the empty space
sep <- .2
par(mar = rep(0, 4))
frame()
plot.window(c(0, ncol(dat) + 2), c(nrow(dat) + 1, 0), asp=1)
for (i in 0:nrow(dat)) {
for (j in 0:ncol(dat)) {
# first row -- Sx labels
if (i == 0) {
if (j > 0) text(j + .5, .5, paste0('S', j))
# first column -- Gx labels
} else if (j == 0) {
if (i > 0) text(.5, i + .5, paste0('G', i))
# stacked colours
} else {
# colors for the current stack
cols.ij <- let.col[unlist(strsplit(dat[i, j], ';'))]
for (k in seq_along(cols.ij)) {
rect(j + sep/2,
# rectangle's top goes down for subsequent colors in the stack
i + (1-sep) * (k-1) / length(cols.ij) + sep/2,
j + 1 - sep/2,
i + 1 - sep/2,
col=cols.ij[k])
}
}
}
}
We could use legend()
for legend but its customizability is limited and doing it by hand is not so much work:
# legend top left coordinates
leg.x <- ncol(dat) + 1.4
leg.y <- 1 + mar/2
# size of the square in legend
leg.sq <- .4
# space between squares in legend
leg.sep <- mar
for (i in seq_along(let.col)) {
rect(leg.x, leg.y, leg.x + leg.sq, leg.y + leg.sq, col=let.col[i])
text(leg.x + leg.sq*1.4, leg.y + leg.sq/2, names(let.col)[i])
leg.y <- leg.y + leg.sq + leg.sep
}
To add a column with notes you can modify the code like this:
par(mar = rep(0, 4))
frame()
plot.window(c(0, ncol(dat) + 3), c(nrow(dat) + 1, 0), asp=1)
col.labels <- c(paste0('S', seq_len(ncol(dat))), 'Note')
notes <- c('D1', 'note2%', 'D3', 'D4')
for (i in 0:nrow(dat)) {
for (j in 0:(ncol(dat)+1)) {
# first row -- Sx labels
if (i == 0) {
if (j > 0) text(j + .5, .5, col.labels[j])
# first column -- Gx labels
} else if (j == 0) {
if (i > 0) text(.5, i + .5, paste0('G', i))
# stacked colours
} else {
# colors for the current stack
if (j <= ncol(dat)) {
cols.ij <- let.col[unlist(strsplit(dat[i, j], ';'))]
for (k in seq_along(cols.ij)) {
rect(j + sep/2,
# rectangle's top goes down for subsequent colors in the stack
i + (1-sep) * (k-1) / length(cols.ij) + sep/2,
j + 1 - sep/2,
i + 1 - sep/2,
col=cols.ij[k])
}
# notes
} else {
text(j + .3, i + .5, notes[i], adj=0)
}
}
}
}
This is without the legend but it can be added the same way as before, just increase leg.x
to make space for the notes.