Subsetting multiple dataframes and aggregating them for plotting in an efficient manner

Viewed 41

I would like to subset two dataframes by their columns, whilst retaining the 1st column (containing names), then I want to generate a plot for each subset of the original dataframes. The trick is that they each have one column per month, and I then aggregate those columns to obtain a barplot.

I've generated an example with random data to illustrate my problem:

df1 <- data.frame(name = c("name1","name2","name3","name4"),
                 month1 = c(5,6,7,8),
                 month2 = c(10,11,12,13),
                 month3 = c(15,16,17,18))

df2 <- data.frame(name = c("name1","name2","name3","name4"),
                 month1 = c(22,23,24,25),
                 month2 = c(31,34,35,39),
                 month3 = c(42,43,45,46))
A data.frame: 4 × 4
name    month1  month2  month3
<chr>   <dbl>   <dbl>   <dbl>
name1   5   10  15
name2   6   11  16
name3   7   12  17
name4   8   13  18


A data.frame: 4 × 4
name    month1  month2  month3
<chr>   <dbl>   <dbl>   <dbl>
name1   22  31  42
name2   23  34  43
name3   24  35  45
name4   25  39  46

So essentially, here I would like to have three subset frames, one for each month column, whilst retaining the name column. This is how I manually achieve this:

month1description1 <- df1 %>%
  select("name","month1") %>%
  rename("description 1" = "month1")

month1description2 <- df2 %>%
  select("name","month1") %>%
  rename("description 2" = "month1")


month1plot <- left_join(month1description1, month1description2, by = c("name"))
rm(month1description1,month1description2)

month1plot <- melt(month1plot, id = "name") 



name    variable    value
<chr>   <fct>   <dbl>
name1   description 1   5
name2   description 1   6
name3   description 1   7
name4   description 1   8
name1   description 2   22
name2   description 2   23
name3   description 2   24
name4   description 2   25

##Plot
month1 <- month1plot %>%
  ggplot(aes(x = name, y = value, fill = variable)) +
  geom_bar(stat = "identity", position = position_stack()) +
  labs(title = "Plot Title",
       subtitle = "month 1",
       x="",
       y="Count") +
  scale_fill_viridis_d(name = "", option = "inferno", begin = 0.3, end = 0.7, direction = -1) +
  scale_shape_tableau() +
  theme_economist() +
  theme(plot.background = element_rect(fill = "white"), 
        plot.title = element_text(hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5),
        axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1),
        plot.margin = unit(c(1,1,1,1), "cm"))
month1

I then plot this dataframe, and the color/fill element in ggplot is the variable added by characterizing the content of each original frame (description 1 and description 2).

enter image description here

Generally speaking, this does not represent an inordinate amount of code, and I would be happy keeping it as it is, but when faced with 12+ months in the form of columns, and needing 12+ individual plots, the code seems a little clunky.

Is there a way to at least generate each of the subset dataframes in a more efficient manner than splitting, aggregating and melting each one?

1 Answers

There is no need for melt. Put your dfs in a list, use dplyr::bind_rows, rename/select your variables:

library(dplyr)
library(ggplot2)
library(ggthemes)

month1plot <-list("description 1" = df1, "description 2" = df2) %>% 
  dplyr::bind_rows(.id = "variable") %>% 
  dplyr::select(name, variable, value = month1)

month1plot %>%
  ggplot(aes(x = name, y = value, fill = variable)) +
  geom_bar(stat = "identity", position = position_stack()) +
  labs(title = "Plot Title",
       subtitle = "month 1",
       x="",
       y="Count") +
  scale_fill_viridis_d(name = "", option = "inferno", begin = 0.3, end = 0.7, direction = -1) +
  scale_shape_tableau() +
  theme_economist() +
  theme(plot.background = element_rect(fill = "white"), 
        plot.title = element_text(hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5),
        axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1),
        plot.margin = unit(c(1,1,1,1), "cm"))

Related