R – Creating Horizontally ‘Stacked’ Bar Chart with given data in R

bar-chartggplot2r

I'm trying to create a horizontally 'stacked' bar chart in R. I'm racking my brain as most of the examples I have read do not quite give me what I am looking for. Here is some example data:

pat3 <- pat2[c("id", "visitday","dose")] #given data.
pat3

    id    visitday dose
7   11558     1.87 3850
8   11558    41.14 3850
9   11558    95.37 3800
10  11558   132.77 3800
28  11559     1.87 3850
29  11559    56.10 3800
30  11559    95.37 3800
31  11559   132.77 3800
32  11559   173.91 3800
46  11560     1.87 3850
47  11560    69.19 3794
48  11560   108.46 3794
49  11560   147.73 3794
50  11560   187.00 3794
51  11560   226.27 3794
  1. On the y-axis I would need unique 'id' in ascending order.
  2. The x-axis would be a continuous scale, where the horizontal bars would 'stack' onto each other up to each 'visitday' in ascending order.
  3. The 'dose' is a measurement of liquid consumed starting from time 0 until next 'visitday'. The doses would be 'stacked' horizontally, where a given dose would be a specific color on the bar for every ID up until the corresponding 'visitday'.

For example, for ID=115588, from visitday 0 to 1.87 they have consumed a dose of 3850, so their bar would be blue from 0 – 1.87 on the bar chart. By visitday 41.14, they still have consumed another dose of 3850, so from 1.88 to 41.14, their bar would still be blue. But from 41.15 – 95.37, they'll have taken a new dose of 3800, where their bar would now be a different color, say red. And the same for visitday 95.38 – 132.77, since still the same dose of 3800.

So for this ID=115588, we should see a bar that is BLUE, for dose=3850, from visitday 0 – 41.14, and 'stacked' on that would be RED, for dose=3800, from visitday 41.15 – 132.77.

This is where I am now:

pat3 <- pat2[c("id", "visitday","dose")] #get data.

diff2 <- function(x) diff(c(0, x))
pat3$diffday <- c(unlist(t(aggregate(visitday~id, pat3, diff2)[, -1])))

pat3 #check diffday

w <- reshape(pat3, 
         timevar = "id",
         idvar = c("dose","visitday"),
         direction = "wide")

drops <- c("visitday")
w2 <- w[,!(names(w) %in% drops)]

w2[is.na(w2)] <- 0
w3 <- data.matrix(w2)

barplot(w3, horiz=T)

As you can see, I'm stuck on how to categorize the colors for each of the doses, where, again, the doses can be any color as long as they're consistent for all patients taking those doses. So if any person took dose=3850, that part of their bar should be blue, if anyone took dose=3800, that part of their bar should be red, if any person took dose=3794, that part of the bar should be green.

I also need to remove the 'dose' bar from the chart as I only kept it to help categorize the colors for each of the dose groups, but didn't even get that far…

Any help is appreciated. Thanks!

Best Answer

I am having a bit hard time to see what you want. But, here is my suggestion. You wanted two things. One is that you wanted specific colours for specific numbers of dose. The other is that you wanted have IDs in a specific order. I have done the following.

mydf$id <- factor(mydf$id)
mydf$id <- factor(mydf$id, levels = c("11560", "11559", "11558"))

p <- ggplot(data = mydf, aes(x = id, y = dose, fill = factor(dose)))+
     geom_bar(stat="identity") +
     scale_fill_manual(values = c("green", "red", "blue"))

As, Paulo suggested, you can have visit day on the y axis, but I chose Dose on the axis. Since you have different visit day for each period, I thought it would be nice to show visit days on the bars. foo$day is a column including visit day from your data set.

#After reordering the factor level, I need to change the order of visit day
ana <- as.matrix(mydf$visitday)
ana <- ana[c(10:15,5:9,1:4)]

# foo will be used to add texts (visit day) in ggplot.
foo = ggplot_build(p)$data[[1]]
foo$day <- ana

p + 
annotate(x = foo$x, y = foo$ymax, label = foo$day, geom="text", size=3) +
xlab("ID") +
ylab("Dose") +
guides(fill=guide_legend(title="Dose")) +
coord_flip()

enter image description here

Related Topic