neversaint
neversaint

Reputation: 64074

Avoid ggplot sorting the x-axis while plotting geom_bar()

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

Upvotes: 97

Views: 111717

Answers (6)

Zelbinian
Zelbinian

Reputation: 3417

As other answers have pointed out, ggplot wants you to specify a variable as a factor if you don't want it to presume the order to display things in. Using the readr library is the easiest way to do this if you're working with data that has already been ordered.

Instead of the read.table function, use read_table and as part of the col_types argument, specify the column with the labels (V1 in this case) as a factor. For small datasets like this a simple format string is often the easiest way

dat <- read_table("http://dpaste.com/1469904/plain/", col_types = "fd")

The string "fd" tells read_table that the first column is a factor and the second column is a double. The help file for the function includes a character mapping for other types of data.

Upvotes: 0

AndrewGB
AndrewGB

Reputation: 16876

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))

Upvotes: 14

Alex Thomas
Alex Thomas

Reputation: 1242

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

Upvotes: 53

Thomas Luechtefeld
Thomas Luechtefeld

Reputation: 1466

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()

Upvotes: 10

Romeo Kienzler
Romeo Kienzler

Reputation: 3547

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

x$name <- factor(x$name, levels = x$name[order(x$val)])

Upvotes: 7

Ben
Ben

Reputation: 42343

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

Upvotes: 100

Related Questions