简体   繁体   中英

ggplot2: geom_bar(); how to alternate order of fill so bars are not lost inside a bar with a higher value?

I am trying to position two bars at the same position on the x-axis and seperated out by colour (almost as if stacking).

However, instead of stacking I want the bar simply inside the other bar - with the smallest Y-value being visable inside the bar with the highest Y-value.

I can get this to work to some extent - but the issue is that one Y-value is not consistently higher across one of the two factors. This leads to bars being 'lost' within a bar with a higher Y-value.

Here is a subset of my dataset and the current ggplot code:

    condition hours expression freq_genes
 1      tofde     9         up         27
 2      tofde    12         up         92
 3      tofde    15         up        628
 17     tofde     9       down          0
 18     tofde    12       down          1
 19     tofde    15       down          0
 33      tofp     9         up       2462
 34      tofp    12         up        786
 35      tofp    15         up        298
 49      tofp     9       down        651
 50      tofp    12       down        982
 51      tofp    15       down       1034
 65       tos     0         up         27
 66       tos     3         up        123
 67       tos     6         up        752
 81       tos     0       down          1
 82       tos     3       down         98
 83       tos     6       down        594 


sf_plot <- ggplot(data = gene_freq, 
              aes(x = hours, 
                  y = freq_genes, 
                  group = condition,
                  fill = factor(expression,
                                labels=c("Down", 
                                         "Up"))))

sf_plot <- sf_plot + labs(fill="Expression")

sf_plot <- sf_plot + geom_bar(stat = "identity", 
                          width = 2.5, 
                          position = "dodge")

sf_plot <- sf_plot + scale_fill_manual(values=c("#9ecae1", 
                                            "#3182bd"))

sf_plot <- sf_plot + xlab("Time (Hours)")

sf_plot <- sf_plot + scale_x_continuous(breaks = 
seq(min(gene_freq$freq_genes), 
max(gene_freq$freq_genes),
by = 3))                                                         

sf_plot <- sf_plot + ylab("Gene Frequency")

sf_plot <- sf_plot + facet_grid(. ~ condition, scales = "free")

sf_plot <- sf_plot + theme_bw()

sf_plot <- sf_plot + theme(panel.grid.major = element_blank(), 
                       panel.grid.minor = element_blank())

sf_plot <- sf_plot + theme(axis.text.x = element_text(angle = 90))


# Print plot
sf_plot

在此处输入图片说明

You can add alpha = 0.5 to your geom_bar() statement to make the bars transparent. This will allow both bars to be seen. Adding that alpha statement and nothing else will produce what you're looking for, to make both overlaid bars visible. The colors, however, make seeing the two different bars challenging.

在此处输入图片说明

Another (and maybe better) option is to change the order in which the plot is created. If I recall correctly, ggplot will plot the bars in alphabetical or numeric or factor-level order. Here, your expression values are c("Down", "Up") and "Down" is being plotted first. If you force "Up" to be plotted first, you could resolve this, too.

library(dplyr)
library(ggplot2)

dat <- 
  read.table(text = "condition hours expression freq_genes
1      tofde     9         up         27
2      tofde    12         up         92
3      tofde    15         up        628
17     tofde     9       down          0
18     tofde    12       down          1
19     tofde    15       down          0
33      tofp     9         up       2462
34      tofp    12         up        786
35      tofp    15         up        298
49      tofp     9       down        651
50      tofp    12       down        982
51      tofp    15       down       1034
65       tos     0         up         27
66       tos     3         up        123
67       tos     6         up        752
81       tos     0       down          1
82       tos     3       down         98
83       tos     6       down        594") %>%
  mutate(expression2 = ifelse(expression == "up", 1, 2))

dat %>%
ggplot(aes(x = hours, y = freq_genes, group = condition, 
           fill = factor(expression2, labels=c("Up", "Down")))) +
  labs(fill="Expression") + 
  geom_bar(stat = "identity", position = "dodge", width = 2.5, alpha = 0.5) + 
  scale_fill_manual(values=c("#9ecae1", "#3182bd")) + 
  xlab("Time (Hours)") + 
  scale_x_continuous(breaks = seq(min(dat$freq_genes), 
                                  max(dat$freq_genes),
                                  by = 3)) + 
  ylab("Gene Frequency") + 
  facet_grid(. ~ condition, scales = "free") + 
  theme_bw() + 
  theme(panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), 
        legend.position = "bottom", 
        axis.text.x = element_text(angle = 90))

Here, I've created a new column called expression2 that is just a numeric version of expression . I changed the fill variable in aes() to match with those new labels. I left the colors in scale_fill_manual() the same as in your original statement and kept the alpha value. "Down" is being plotted on top of "Up" but in keeping the same colors with the alpha value, both bars are easier to see. You can play with the legend to display "Down" before "Up" if that's necessary.

在此处输入图片说明

Note that providing machine readable data goes a long way in allowing others to help you out. Consider using dput() to output your data next time rather than pasting it in. Also note that you can "chain" together ggplot() statements with a + . This makes code much more compact and easier to read.

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