简体   繁体   中英

Stacked Diverging Bar Chart Plot by groups in ggplot

I am trying to do a chart like this one:

在此处输入图像描述

The idea is to plot 3 amounts, in this mixed stacked bar chart we have a dataframe which has one row for a negative value and two rows for the positive value, however i need to stack the negative with the first positive bar, i also need 3 colors. The code I have so far is as follows: (the dataframe already has the desired shape):

df3 <- read.table(
text = 
"region group metric somevalue
blue T1 epsilon 63
blue T2 epsilon -40
red T1 epsilon 100
blue T1 kappa 19
blue T2 kappa -30
red T1 kappa 75
blue T1 zulu  50
blue T2 zulu -18
red T1 zulu 68", header=TRUE)

p2 <- ggplot(df3, aes(x = metric, y = somevalue, fill=region))+
  geom_col(aes(fill = group), width = 0.7) + geom_bar(position = 'dodge', stat='identity')
p2

please help me out, if you think the dataframe has to be modified please let me know. thanks

Stacking and dodging is always a bit tricky. In your case this could be achieved like so:

  1. Convert region to a factor . (This makes sure that step 3 works)
  2. Split your dataset in two for negative and positive values.
  3. Fill up the datasets using tidy::complete so that each dataset contains "all" combinations of metric, region and group. (This makes sure that the dodging works
  4. Use two geom_col layers to plot the positive and negative values using position="dodge" . I added na.rm = TRUE to remove the missing values we added via complete .

library(ggplot2)
library(dplyr)
library(tidyr)

df3$region <- factor(df3$region)

df3_neg <- filter(df3, somevalue < 0) %>% 
  tidyr::complete(region, group, metric)

df3_pos<- filter(df3, somevalue > 0) %>% 
  tidyr::complete(region, group, metric)

p2 <- ggplot(df3, aes(somevalue, metric)) +
  geom_col(aes(alpha = group, fill=region), data = df3_pos, position = "dodge", na.rm = TRUE) +
  geom_col(aes(alpha = group, fill=region), data = df3_neg, position = "dodge", na.rm = TRUE) +
  scale_fill_identity() +
  scale_alpha_manual(values = c(T2 = .6, T1 = 1)) +
  guides(alpha = FALSE)
p2

EDIT Adding annotations could be achieved the same way, eg my code below uses two geom_text to add the values next to the bar where I make use of position_dodge2(.9) so that the labels align nicely with the bars:


p2 <- ggplot(df3, aes(somevalue, metric)) +
  geom_col(aes(alpha = group, fill=region), data = df3_pos, position = "dodge", na.rm = TRUE) +
  geom_col(aes(alpha = group, fill=region), data = df3_neg, position = "dodge", na.rm = TRUE) +
  geom_text(aes(x = somevalue + 1, label = somevalue), data = df3_pos, position = position_dodge2(width  = .9), hjust = 0, na.rm = TRUE) +
  geom_text(aes(x = somevalue - 1, label = somevalue), data = df3_neg, , position = position_dodge2(width  = .9), hjust = 1, na.rm = TRUE) +
  scale_fill_identity() +
  scale_alpha_manual(values = c(T2 = .6, T1 = 1)) +
  guides(alpha = FALSE)
p2

EDIT2 Adding a table is indeed a different thing. In that case I would go for patchwork which means making plots to mimic the table layout. To make the dodging work or to make sure that the table rows align with the bars you have make a plot for each table column. The basic approach may look like so:

library(patchwork)

# 1. Make a dataframe with all combinations of region and metric using expand_grid
d_table <- expand_grid(region = unique(df3$region), metric = unique(df3$metric))

# 2. Add columns with the table content
d_table$column1 <- LETTERS[1:6]
d_table$column2 <- letters[1:6]

# 3. Make a plot for each column of the table
p_column1 <- ggplot(d_table, aes(y = metric, x = 1, label = column1)) +
  geom_text(aes(group = region), position = position_dodge2(width = .9), na.rm = TRUE) +
  scale_x_continuous(position = "top", breaks = 1, labels = "column1") +
  labs(y = NULL, x = "") +
  theme(axis.text.y = element_blank(), 
        axis.text.x.bottom = element_blank(),
        axis.ticks = element_blank(), 
        plot.margin = unit(rep(0, 4), "pt"), 
        panel.background = element_rect(fill = NA))
p_column2 <- ggplot(d_table, aes(y = metric, x = 1, label = column2)) +
  geom_text(aes(group = region), position = position_dodge2(width = .9), na.rm = TRUE) +
  scale_x_continuous(position = "top", breaks = 1, labels = "column2") +
  labs(y = NULL, x = "") +
  theme(axis.text.y = element_blank(), 
        axis.text.x.bottom = element_blank(),
        axis.ticks = element_blank(), 
        plot.margin = unit(rep(0, 4), "pt"), 
        panel.background = element_rect(fill = NA))
# 4. Add the table columns via patchwork
p2 + p_column1 + p_column2 + plot_layout(widths = c(1, .1, .1))

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM