1

Suppose I want to show in a barplot the gene expression results (logFC) based on RNA-seq and q-PCR analysis. My dataset looks like that:

set.seed(42)

f1 <- expand.grid(
  comp = LETTERS[1:3],
  exp = c("qPCR", "RNA-seq"),
  geneID = paste("Gene", 1:4)
)
f1$logfc <- rnorm(nrow(f1))
f1$SE <- runif(nrow(f1), min=0, max=1.5)

My R command line


p=ggplot(f1, aes(x=geneID, y=logfc, fill= comp,color=exp))+
  geom_bar(stat="identity", position =position_dodge2(preserve="single"))+
  theme(axis.text.x = element_text(angle = 45, vjust = 0.5, hjust=1))```

I have this output:

enter image description here

I want to get any mark patterns or hatches on the bars corresponding to one of the variables (exp or comp) and adding the upper error bars as shown in this plot bellow:

enter image description here

Any help please?

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • 5
    Does this answer your question? [How can I add hatches, stripes or another pattern or texture to a barplot in ggplot?](https://stackoverflow.com/questions/62393159/how-can-i-add-hatches-stripes-or-another-pattern-or-texture-to-a-barplot-in-ggp) – teunbrand Apr 19 '21 at 15:24
  • Unfortunately no! I read this thread before posting here. But the data input is different to mine. They have Categorical variable and I have numerical variables. I have to plot the 'values (logfc)' in y axis , geneID in x-axis , fill or coloring bars based on 'comp' and adding pattern based on 'exp' (q-PCR or RNA-seq). – Dieunel Derilus Apr 19 '21 at 17:31
  • Alright then, can you post some (dummy) data that would work with your code as the `f1` object, so people here can try and get this pattern working? – teunbrand Apr 19 '21 at 17:37
  • 1
    I have edited my post and added an example input table as hyperlink – Dieunel Derilus Apr 19 '21 at 17:47
  • Just out of curiosity, which part of my answer to the linked question was tripping you up? I could consider improving it. – Ian Campbell Apr 20 '21 at 03:59

1 Answers1

4

Following the linked answer, it seems quite natural how to extend it to your case. In the example below, I'm using some dummy data structured like the head() data you gave, since the csv link gave me a 404.

library(ggplot2)
library(ggpattern)
#> 
#> Attaching package: 'ggpattern'
#> The following objects are masked from 'package:ggplot2':
#> 
#>     flip_data, flipped_names, gg_dep, has_flipped_aes, remove_missing,
#>     should_stop, waiver

# Setting up some dummy data
set.seed(42)
f1 <- expand.grid(
  comp = LETTERS[1:3],
  exp = c("qPCR", "RNA-seq"),
  geneID = paste("Gene", 1:4)
)
f1$logfc <- rnorm(nrow(f1))

ggplot(f1, aes(x = geneID, y = logfc, fill = comp)) +
  geom_col_pattern(
    aes(pattern = exp),
    colour = "black",
    pattern_fill = "black",
    pattern_angle = 45,
    pattern_density = 0.1,
    pattern_spacing = 0.01,
    position = position_dodge2(preserve = 'single'),
  ) +
  scale_pattern_manual(
    values = c("none", "stripe"),
    guide = guide_legend(override.aes = list(fill = "grey70")) # <- make lighter
  ) +
  scale_fill_discrete(
    guide = guide_legend(override.aes = list(pattern = "none")) # <- hide pattern
  )

Created on 2021-04-19 by the reprex package (v1.0.0)

EDIT: if you want to repeat the hatching in the fill legend, you can make an interaction() and then customise a manual fill scale.

ggplot(f1, aes(x = geneID, y = logfc)) +
  geom_col_pattern(
    aes(pattern = exp,
        fill = interaction(exp, comp)), # <- make this an interaction
    colour = "black",
    pattern_fill = "black",
    pattern_angle = 45,
    pattern_density = 0.1,
    pattern_spacing = 0.01,
    position = position_dodge2(preserve = 'single'),
  ) +
  scale_pattern_manual(
    values = c("none", "stripe"),
    guide = guide_legend(override.aes = list(fill = "grey70")) # <- make lighter
  ) +
  scale_fill_manual(
    # Have 3 colours and repeat each twice
    values = rep(scales::hue_pal()(3), each = 2),
    # Extract the second name after the '.' from the `interaction()` call
    labels = function(x) {
      vapply(strsplit(x, "\\."), `[`, character(1), 2)
    },
    # Repeat the pattern over the guide
    guide = guide_legend(
      override.aes = list(pattern = rep(c("none", "stripe"), 3))
    )
  )

Created on 2021-04-19 by the reprex package (v1.0.0)

EDIT2: Now with errorbars:

library(ggplot2)
library(ggpattern)
set.seed(42)

f1 <- expand.grid(
  comp = LETTERS[1:3],
  exp = c("qPCR", "RNA-seq"),
  geneID = paste("Gene", 1:4)
)
f1$logfc <- rnorm(nrow(f1))
f1$SE <- runif(nrow(f1), min=0, max=1.5)

ggplot(f1, aes(x = geneID, y = logfc)) +
  geom_col_pattern(
    aes(pattern = exp,
        fill = interaction(exp, comp)), # <- make this an interaction
    colour = "black",
    pattern_fill = "black",
    pattern_angle = 45,
    pattern_density = 0.1,
    pattern_spacing = 0.01,
    position = position_dodge2(preserve = 'single'),
  ) +
  geom_errorbar(
    aes(
      ymin = logfc,
      ymax = logfc + sign(logfc) * SE,
      group = interaction(geneID, comp, exp)
    ),
    position = "dodge"
  ) +
  scale_pattern_manual(
    values = c("none", "stripe"),
    guide = guide_legend(override.aes = list(fill = "grey70")) # <- make lighter
  ) +
  scale_fill_manual(
    # Have 3 colours and repeat each twice
    values = rep(scales::hue_pal()(3), each = 2),
    # Extract the second name after the '.' from the `interaction()` call
    labels = function(x) {
      vapply(strsplit(x, "\\."), `[`, character(1), 2)
    },
    # Repeat the pattern over the guide
    guide = guide_legend(
      override.aes = list(pattern = rep(c("none", "stripe"), 3))
    )
  )

Created on 2021-04-22 by the reprex package (v1.0.0)

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • Woww, this looks so great! I am almost there. What about if I want to customize legend of 'comp' with the pattern also, as shown in the second figure shown here in my post. In this context it looks like the 'comp' elements as A, B , C here here in your example would be one with pattern and one without pattern in the legend (as in the second figure). Thank you! – Dieunel Derilus Apr 19 '21 at 18:33
  • Yeah that makes it a little bit more complicated, but I've added an example in the edit. – teunbrand Apr 19 '21 at 18:41
  • Thank you @theunbrand. I am getting back to this. I have a second column 'SE' with the standard deviation of each value in 'logfc'. What is the best way to add the error bars. I have intended to add ist ass follow `limits <- aes(ymax = logfc + SE, ymin = logfc) dodge <- position_dodge(width = 0.9) `and and `p+geom_errorbar(limits, position = dodge, colour = "black")`, but i received a message error :**Error: Insufficient values in manual scale. 6 needed but only 4 provided.Run `rlang::last_error()` to see where the error occurred.** – Dieunel Derilus Apr 21 '21 at 20:59
  • Probably something like the following? `geom_errorbar(aes(ymin = logfc - SE, ymax = logfc + SE, group = interaction(geneID, comp, exp)), position = 'dodge')` – teunbrand Apr 21 '21 at 21:03
  • 1
    Yeah sorry I don't know what exactly it is you're doing differently than I am doing. I can't debug code and data I can't see and experiment with. – teunbrand Apr 21 '21 at 21:11
  • I understand your point @ teunbrand, Am I allowed to share with you my data and complete script via email? – Dieunel Derilus Apr 21 '21 at 21:28
  • 1
    I'd rather not; because (1) it deprives others the opportunity to answer your question and (2) it implies some kind of duty from my side to solve your problems, which I rather avoid. I'd be happy to help if I can, but I don't know yet if I can. I also only selectively answer SO questions that I think I understand well enough. I think the best thing to do is to generate a dummy dataset that you can share with whomever (just like I did above) and replicates the problem, and then post a different question to solve this different problem. – teunbrand Apr 21 '21 at 21:42
  • Ok I will post other question with a dummy dataset. Thank you! – Dieunel Derilus Apr 21 '21 at 22:30
  • Unfortunately my account is not allowed to ask new question. Here is an dummy dataset with the standard deviation value: `set.seed(42) f1 <- expand.grid(comp = LETTERS[1:3],exp = c("qPCR", "RNA-seq"),geneID = paste("Gene", 1:4)) f1$logfc <- rnorm(nrow(f1),.9,2) f1$SE <- rnorm(nrow(f1),.9,2) ` . I want to plot add the upper error bars as shown on the figure in my original post – Dieunel Derilus Apr 21 '21 at 22:43
  • Can you *edit* your original question to include this information? – Ben Bolker Apr 21 '21 at 23:25
  • I have edited my original question by adding a dummy dataset with the standard deviation column to add the error bars. I have also remarked that the plot generated by your script does not display the bars as expected. I would expect to have the 2 bars with the same color (with and without pattern) be side by side here Adding hatches or patterns to ggplot bars. Sorry if it looks trivial question, I am a beginner in R. – Dieunel Derilus Apr 22 '21 at 04:28
  • I've added an edit to my anwer, I hope it helps! – teunbrand Apr 22 '21 at 07:19
  • Thank you for adding the error bar. What about having the RNAseq and qPCR (same color ) for each gene side by side instead of getting them separated. I want to compare the qPCR and RNA-seq results for each gene. This is why I would be happy to have them glued side by side for each gene! – Dieunel Derilus Apr 22 '21 at 12:50
  • You'd have to set in the aes `group = interaction(exp, comp)` in the column and errorbar layers. – teunbrand Apr 22 '21 at 13:16
  • It works thank you! – Dieunel Derilus Apr 23 '21 at 18:10