84

I have the following data which I want to plot with ggplot:

SC_LTSL_BM    16.8275
SC_STSL_BM    17.3914
proB_FrBC_FL   122.1580
preB_FrD_FL    18.5051
B_Fo_Sp    14.4693
B_GC_Sp    15.4986

What I want to do is to make a bar plot and maintain the order of the bar, (i.e. starting with SC_LTSL_BM ...B_GC_Sp). But the default behavior of ggplot geom_bar is to sort them. How can I avoid that?

  library(ggplot2)
  dat <- read.table("http://dpaste.com/1469904/plain/")
  pdf("~/Desktop/test.pdf")
  ggplot(dat,aes(x=V1,y=V2))+geom_bar()
  dev.off()

The current figure looks like this: enter image description here

zx8754
  • 46,390
  • 10
  • 104
  • 180
neversaint
  • 55,647
  • 127
  • 291
  • 457

5 Answers5

91

You need to tell ggplot that you've got an ordered factor already, so it doesn't automatically order it for you.

dat <- read.table(text=
"SC_LTSL_BM    16.8275
SC_STSL_BM    17.3914
proB_FrBC_FL   122.1580
preB_FrD_FL    18.5051
B_Fo_Sp    14.4693
B_GC_Sp    15.4986", header = FALSE, stringsAsFactors = FALSE)

# make V1 an ordered factor
dat$V1 <- factor(dat$V1, levels = dat$V1)

# plot
library(ggplot2)
ggplot(dat,aes(x=V1,y=V2))+geom_bar(stat="identity")

enter image description here

Ben
  • 40,397
  • 18
  • 126
  • 218
  • 4
    And, to be technically nitpicky, it *does* order it for you. The default is alphabetical ordering---it's hardly ever what you want but it's hard to imagine a more sensible default. – Gregor Thomas May 14 '15 at 00:38
  • 1
    @Gregor I could have not known it was arranged by alphabetical order until you mentioned it. Thanks – Abel Callejo May 10 '19 at 01:35
47

Here is an approach that does not modify the original data, but uses scale_x_discrete. From ?scale_x_discrete, "Use limits to adjust the which levels (and in what order) are displayed". For example:

dat <- read.table(text=
                "SC_LTSL_BM    16.8275
              SC_STSL_BM    17.3914
              proB_FrBC_FL   122.1580
              preB_FrD_FL    18.5051
              B_Fo_Sp    14.4693
              B_GC_Sp    15.4986", header = FALSE, stringsAsFactors = FALSE)
# plot
library(ggplot2)
ggplot(dat,aes(x=V1,y=V2))+
  geom_bar(stat="identity")+
  scale_x_discrete(limits=dat$V1)

enter image description here

AndrewGB
  • 12,571
  • 4
  • 13
  • 38
Alex Thomas
  • 974
  • 10
  • 13
  • 8
    I would argue that this is the superior answer because it is compatible with stacked bar plots, which will have the same ID repeated in a column, and thus will not be compatible with transforming into a sortable factor. – Phil_T Mar 12 '18 at 04:11
8

dplyr lets you easily create a row column that you can reorder by in ggplot.

library(dplyr)
dat <- read.table("...") %>% mutate(row = row_number())
ggplot(df,aes(x=reorder(V1,row),y=V2))+geom_bar()
Thomas Luechtefeld
  • 1,082
  • 12
  • 20
7

You can also just re-order the corresponding factor as described here

x$name <- factor(x$name, levels = x$name[order(x$val)])
Romeo Kienzler
  • 3,135
  • 3
  • 31
  • 56
5

If you want to avoid changing the original data, then you can use fct_inorder from forcats (part of tidyverse) to keep the original order of the data along the x-axis (rather than it being changed to alphabetical).

library(tidyverse)

ggplot(dat, aes(x = fct_inorder(V1), y = V2)) +
  geom_bar(stat = "identity")

Output

enter image description here

Another option with forcats is to manually specify the order with fct_relevel.

ggplot(dat, aes(
  x = fct_relevel(
    V1,
    "SC_LTSL_BM",
    "SC_STSL_BM",
    "proB_FrBC_FL",
    "preB_FrD_FL",
    "B_Fo_Sp",
    "B_GC_Sp"
  ),
  y = V2
)) +
  geom_bar(stat = "identity") +
  xlab("Category")

Data

dat <- structure(list(
  V1 = c(
    "SC_LTSL_BM",
    "SC_STSL_BM",
    "proB_FrBC_FL",
    "preB_FrD_FL",
    "B_Fo_Sp",
    "B_GC_Sp"
  ),
  V2 = c(16.8275, 17.3914,
         122.158, 18.5051, 14.4693, 15.4986)
),
class = "data.frame",
row.names = c(NA, -6L))
AndrewGB
  • 12,571
  • 4
  • 13
  • 38