1
votes

Following is a sample data frame

df <- data.frame(SampleID = c(1, 2, 3, 4, 5, 6, 7, 8),
                 Var1 = c(0.1 , 0.5,    0.7,    0,  0,  0,  0.5,    0.2), 
                 Var1PA = c("Present", "Present", "Present", "Absent", "Absent", "Absent",  "Present", "Present"), 
                 Var2 = c(0, 0, 0, 0, 0.1, 0.5, 0.7, 0.2), 
                 Var2PA = c("Absent", "Absent", "Absent", "Absent", "Present", "Present", "Present", "Present"))

My question started off as seemingly simple, but I could not find a way to edit the dataframe suitably to plot a barplot.

For Var1, I want to plot a stacked barplot of the percent of times var1 was present in the sample (i.e var1 value > 0) or absent (Similarly for var2 and so on).

I could determine this percentage by:

(1 - sum(df$Var1 == 0) / length(df$Var1)) * 100

But how do I convert this into a percentage while plotting? I looked at many melt options, but there is no unifying criteria for these variables that would make a common X axis

Finally, how does one answer the question above if I want to plot 5 variables from a dataframe of 1000 such column variables?

Edit: Thanks for the answers so far! I have a slight edit to the question I just added one more variable to my data frame

df <- data.frame(SampleID = c(1, 2, 3, 4, 5, 6, 7, 8),
             Var1 = c(0.1 , 0.5,    0.7,    0,  0,  0,  0.5,    0.2), 
             Var1PA = c("Present", "Present", "Present", "Absent", "Absent", "Absent",  "Present", "Present"), 
             Var2 = c(0, 0, 0, 0, 0.1, 0.5, 0.7, 0.2), 
             Var2PA = c("Absent", "Absent", "Absent", "Absent", "Present", "Present", "Present", "Present"),
             Disease = c("Case", "Control", "Case", "Control", "Case", "Control", "Case", "Control"))

I am trying to figure out how to plot the barplot for cases and controls with presence absence stacked within them for Var1PA, Var2PA and so on. If I have the right data frame input, the ggplot2 code would be : vars <- c('Var1PA', 'Var2PA', 'Var2PA') ##based on the first comment by @rawr tt <- data.frame(prop.table(as.table(sapply(df[, vars], table)), 2) * 100) ggplot(tt, aes(Disease, Freq)) +
geom_bar(aes(fill = Var1), position = "stack", stat="identity") + facet_grid(~vars)

How do I get percentages for cases (present and absent) and controls (present and absent) for each of the vars? Thanks!

1
what should be stackedrawr
Presence/absence as a percentage, Thanks!Manasi Shah
sorry cant test vars <- c('Var1PA', 'Var2PA', 'Var2PA'); tt <- data.frame(prop.table(as.table(sapply(df[, vars], table)), 2) * 100); ggplot(tt, aes(Var2, Freq, fill = Var1)) + geom_bar(stat = 'identity')rawr
A mildly hacky way: library(tidyverse) ; df %>% gather(var, pa, ends_with('PA')) %>% group_by(var) %>% do(pa = names(table(.$pa)), pct = prop.table(table(.$pa)) * 100) %>% unnest() %>% ggplot(aes(var, pct, fill = pa)) + geom_bar(stat = 'identity')alistaire
@rawr sorry for the late reply thanks for your answer it helped me a lot! If I add another variable Disease to my df, would it be easy with prop.table to get percentages separately for cases (present and absent) and controls (present and absent) within each var?Manasi Shah

1 Answers

2
votes

This should generalize nicely. You can, of course, be more selective about the variables you pick.

library(dplyr)
library(tidyr)
mdf = df %>% select(SampleID, ends_with("PA")) %>%
    gather(key = Var, value = PA, -SampleID) %>%
    mutate(PA = factor(PA, levels = c("Present", "Absent")))

ggplot(mdf, aes(x = Var, fill = PA)) +
    geom_bar(position = "fill") +
    scale_y_continuous(labels = scales::percent)

enter image description here

You can add the percentage columns to the long data frame:

mdf %>% group_by(Var) %>%
    mutate(p_present = mean(PA == "Present"),
           p_absent = mean(PA == "Absent"))
# Source: local data frame [16 x 5]
# Groups: Var [2]
# 
#    SampleID    Var      PA p_present p_absent
#       <dbl>  <chr>  <fctr>     <dbl>    <dbl>
# 1         1 Var1PA Present     0.625    0.375
# 2         2 Var1PA Present     0.625    0.375
# 3         3 Var1PA Present     0.625    0.375
# 4         4 Var1PA  Absent     0.625    0.375
# 5         5 Var1PA  Absent     0.625    0.375
# 6         6 Var1PA  Absent     0.625    0.375
# 7         7 Var1PA Present     0.625    0.375
# 8         8 Var1PA Present     0.625    0.375
# 9         1 Var2PA  Absent     0.500    0.500
# 10        2 Var2PA  Absent     0.500    0.500

Or if you'd rather see a 1-line-per-group summary, replace mutate with summarize:

mdf %>% group_by(Var) %>%
    summarize(p_present = mean(PA == "Present"),
           p_absent = mean(PA == "Absent"))
# # A tibble: 2 × 3
#      Var p_present p_absent
#    <chr>     <dbl>    <dbl>
# 1 Var1PA     0.625    0.375
# 2 Var2PA     0.500    0.500