1

I have attempted adapting from some other solutions for slightly different situations. I am not being able to sort this out.

I would like to build a mirrored barplot comparing chemicals with controls, but with results grouped by chemical concentrations, and (if possible) both positive axes.

I provide data below, and an example of I would like it to generally look like.

volatiles<-c("hexenal3", "trans2hexenal", "trans2hexenol", "ethyl2hexanol", "phenethylalcohol", "methylsalicylate", "geraniol", "eugenol")


require(reshape2)
dat<-list(
conc1=data.frame("volatile"=volatiles, "focal"=c(26,27,28,28,31,31,30,28), "control"=c(24,31,30,29,24,23,21,25)),
conc2=data.frame("volatile"=volatiles, "focal"=c(29,18,34,17,30,32,35,27), "control"=c(21,42,20,40,25,16,17,29)),
conc3=data.frame("volatile"=volatiles, "focal"=c(33, 5,38, 7,37,35,40,26), "control"=c(18,51,14, 50,15,12,13,31))
)
long.dat<-melt(dat)

Attempting the following isn't working. Perhaps I should input a different data structure?

ggplot(long.dat, aes(x=L1, group=volatile, y=value, fill=variable)) + 
geom_bar(stat="identity", position= "identity")

I would like it to look similar to this, but with the bars grouped in the triads of different concentrations (and, if possible, with all positive values).

data plot from another software Thanks in advance!

Scientist
  • 1,061
  • 2
  • 13
  • 30
  • 1
    You can control the `labels=` on the axis, I'd imagine that you could use `abs(.)` in the labelling function to show the negative numbers as positives (even though the values themselves would need to be negative to be on the left side of the axis). – r2evans Apr 16 '22 at 02:01
  • 1
    fyi, `object 'volatiles' not found`. – r2evans Apr 16 '22 at 02:01
  • I have edited the code to include an object I'd forgotten, thanks. – Scientist Apr 16 '22 at 12:24

2 Answers2

2

Try this:

long.dat$value[long.dat$variable == "focal"] <-  -long.dat$value[long.dat$variable == "focal"]

library(ggplot2)
gg <- ggplot(long.dat, aes(interaction(volatile, L1), value)) +
  geom_bar(aes(fill = variable), color = "black", stat = "identity") +
  scale_y_continuous(labels = abs) +
  scale_fill_manual(values = c(control = "#00000000", focal = "blue")) +
  coord_flip()
gg

ggplot2 bar plot, grouped and filled by 'variable', and 'focal' data to the left and 'control' data to the right of center

I suspect that the order on the left axis (originally x, but flipped to the left with coord_flip) will be relevant to you. If the current isn't what you need and using interaction(L1, volatile) instead does not give you the correct order, then you will need to combine them intelligently before ggplot(..), convert to a factor, and control the levels= so that they are in the order (and string-formatting) you need.

Most other aspects can be controlled via + theme(...), such as legend.position="top". I don't know what the asterisks in your demo image might be, but they can likely be added with geom_point (making sure to negate those that should be on the left).

For instance, if you have a $star variable that indicates there should be a star on each particular row,

set.seed(42)
long.dat$star <- sample(c(TRUE,FALSE), prob=c(0.2,0.8), size=nrow(long.dat), replace=TRUE)
head(long.dat)
#           volatile variable value    L1  star
# 1         hexenal3    focal   -26 conc1  TRUE
# 2    trans2hexenal    focal   -27 conc1  TRUE
# 3    trans2hexenol    focal   -28 conc1 FALSE
# 4    ethyl2hexanol    focal   -28 conc1  TRUE
# 5 phenethylalcohol    focal   -31 conc1 FALSE
# 6 methylsalicylate    focal   -31 conc1 FALSE

then you can add it with a single geom_point call (and adding the legend move):

gg +
  geom_point(aes(y=value + 2*sign(value)), data = ~ subset(., star), pch = 8) +
  theme(legend.position = "top")

same ggplot with stars and relocated legend

r2evans
  • 141,215
  • 6
  • 77
  • 149
  • Thanks so much! I do not think there's a mirrored plot in this configuration here in SO. Actually I am not sure what are the asterisks either, have asked a colleague. I will try grouping concentrations 1-3 for each compound by changing factor order and perhaps plotting an empty bar in between. – Scientist Apr 16 '22 at 22:38
1

Like r2evans stated, the only way to do this is to use negative values in your data, and then manually use abs() when labelling. More specifically, it would look something like this:

ggplot(long.dat, aes(x=L1, group=volatile, y=value, fill=variable)) + 
geom_bar(stat="identity", position= "identity") +
scale_y_continuous(breaks= c(-25,-15,-5,5,15,25),labels=abs(c(-25,-15,-5,5,15,25)))

Of course, use whatever labels make the most sense for your data, or you can set a sequence of numbers using the seq() function.

P.S. I also had trouble with your code, so next time please make sure your example is reproducible- you'll get answers quicker!

Kian
  • 96
  • 5