1

I want to know if there is a way for defining the order of appearance per group for the side by side barplot in ggplot. My dataset is

> df
        V1         V2   V3
1     True      Joint 0.18
2     True Individual 0.82
3 Estimate      Joint 0.37
4 Estimate Individual 0.63

The following line of code

library(ggplot2)

ggplot(df, aes(x = V2, y = V3, fill = V1)) +
  geom_col(position = position_dodge2()) +
  scale_fill_manual(values=c("steelblue","coral2")) +
  guides(fill = guide_legend(reverse = T)) +
  scale_x_discrete(limits = unique(df$V2)) +
  theme(legend.title = element_blank()) +
  xlab("Structure") + ylab("Variance") +
  ggtitle("Variance Explained by Joint and Individual structure")

gives me this graph side-by-side-barplot.

I want the coral-colored bar to be on the left and the blue bar on the right for each group. I have tried reordering the dataset with lines of code such as

df = arrange(df, df$V1)
df = df[order(df$V1, decreasing = F),]
df = df[c(1,3,2,4),]
df = df[c(1,4,3,2),]

but they did not work.

2 Answers2

3

You could achieve your desired result by converting to a factor and setting the levels in your desired order:

Additionally I made use of a named vector to assign the colors to the categories. But that is just a matter of personal preference.

library(ggplot2)

ggplot(df, aes(x = V2, y = V3, fill = factor(V1, levels = c("True", "Estimate")))) +
  geom_col(position = position_dodge2()) +
  scale_fill_manual(values = c(Estimate = "steelblue", True = "coral2")) +
  guides(fill = guide_legend(reverse = T)) +
  scale_x_discrete(limits = unique(df$V2)) +
  theme(legend.title = element_blank()) +
  xlab("Structure") +
  ylab("Variance") +
  ggtitle("Variance Explained by Joint and Individual structure")

DATA

df <- structure(list(
  V1 = c("True", "True", "Estimate", "Estimate"),
  V2 = c("Joint", "Individual", "Joint", "Individual"), V3 = c(
    0.18,
    0.82, 0.37, 0.63
  )
), class = "data.frame", row.names = c(
  "1",
  "2", "3", "4"
))
stefan
  • 90,330
  • 6
  • 25
  • 51
  • I don't understand why, but your way works. If I produce the same line of code for the plot in my program it does not work. There is something different with the way you created your dataset. I used the following line of code `df = as.data.frame(cbind(c(rep("True", 2), rep("Estimate", 2)), rep(c("Joint", "Individual"), 2), c(0.18,0.82,0.37,0.63)), row.names = 1:4)` – Ilias Moysidis Dec 22 '21 at 00:27
  • (: Actually I wondered myself why you got the bars in different orders. Concerning the dataframe, there is nothing special. The way I added the data was via the `dput()` function (Try it out on your data: `dput(df)`) which is the preferred way of sharing data on SO. Makes it easy to copy the data in a reproducible format which preserves the datatypes. Also fine would have been to add the data via the code you used to create it. For more see [how to make a minimal reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example). – stefan Dec 22 '21 at 08:20
1

You could simply add the reverse = TRUE argument to position_dodge2:

ggplot(df, aes(x = V2, y = V3, fill = V1)) +
  geom_col(position = position_dodge2(reverse = TRUE)) +
  scale_fill_manual(values=c("steelblue","coral2")) +
  guides(fill = guide_legend(reverse = T)) +
  scale_x_discrete(limits = unique(df$V2)) +
  theme(legend.title = element_blank()) +
  xlab("Structure") + ylab("Variance") +
  ggtitle("Variance Explained by Joint and Individual structure")

enter image description here

TarJae
  • 72,363
  • 6
  • 19
  • 66