0

I'm trying to do a simple thing that's very easy in base R plot, but for versatility reasons, I want to use ggplot instead and I can't find the best way to do so.

I have a named number vector of PCA eigenavalues:

nums <- c(2.491301e-01, 6.591505e-02, 4.615435e-02, 3.723229e-02, 2.124809e-02,
          1.662227e-02, 1.476976e-02, 1.297296e-02, 1.053972e-02, 6.665518e-03,
           5.040257e-03, 4.258138e-03, 2.766567e-03, 2.612342e-03, 1.504883e-03,
           1.387214e-03, 1.037458e-03, 7.814771e-04, 4.749074e-04, 4.263183e-04,
           2.812258e-04, 2.188441e-04, 1.382420e-04, 8.760467e-05, 5.336446e-05,
           1.475674e-05, 9.216328e-06)


names(nums) <- c(  "PC1"  ,"PC2" , "PC3" , "PC4" , "PC5" , "PC6" , "PC7" , "PC8" , "PC9" , "PC10",
                   "PC11", "PC12", "PC13", "PC14", "PC15", "PC16", "PC17", "PC18", "PC19", "PC20",
                   "PC21", "PC22", "PC23", "PC24", "PC25", "PC26", "PC27")

In base R, I can easily make a labeled barplot of these values:

barplot(nums, main = "Eigenvalues", col = "grey", las = 2)
abline(h = mean(nums), col = "red3", lwd = 2)
legend("topright", "Average eigenvalue",
       lwd = 2, col = "red3" )

But I'm having trouble doing this as easily in ggplot. Best I've come up with so far is:

nums %>% 
  data.frame() %>%
  ggplot(aes(names(nums),nums)) + 
  geom_bar(stat="identity",fill="grey",color="black") +
  geom_hline(yintercept = mean(nums))+
  theme_classic() +
  theme(axis.text.x = element_text(angle=90),
        axis.title = element_blank(),
        plot.title = element_text(hjust=.5))+
  labs(title="Eigenvalues")

But this makes them annoyingly out of order. Is there a not annoying way to do this for a quick exploratory plot? Is this one of the rare times that base R plotting is superior?

Jake L
  • 987
  • 9
  • 21
  • 2
    Does this answer your question? [Order Bars in ggplot2 bar graph](https://stackoverflow.com/questions/5208679/order-bars-in-ggplot2-bar-graph) – tjebo Jul 01 '20 at 17:00

2 Answers2

2

The names are being converted to a factor behind the scenes, which means that by default your names will be sorted alphabetically in the factor conversion. You simply need to make the desired ordering explicit by making the names a factor and declaring the order of the levels.

Two other points to note are that geom_bar with stat = "identity" can be replaced with geom_col, and that it is generally easier to create a data frame from your variables before plotting in ggplot.

library(ggplot2)
library(dplyr)

data.frame(names = factor(names(nums), levels = names(nums)), nums) %>%
  ggplot(aes(names, nums)) + 
  geom_col() +
  geom_hline(yintercept = mean(nums)) +
  theme_classic() +
  theme(axis.text.x = element_text(angle = 90),
        axis.title  = element_blank(),
        plot.title  = element_text(hjust = 0.5)) +
  labs(title="Eigenvalues")

Created on 2020-07-01 by the reprex package (v0.3.0)

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
0

How about this?

nums <- c(2.491301e-01, 6.591505e-02, 4.615435e-02, 3.723229e-02, 2.124809e-02,
          1.662227e-02, 1.476976e-02, 1.297296e-02, 1.053972e-02, 6.665518e-03,
          5.040257e-03, 4.258138e-03, 2.766567e-03, 2.612342e-03, 1.504883e-03,
          1.387214e-03, 1.037458e-03, 7.814771e-04, 4.749074e-04, 4.263183e-04,
          2.812258e-04, 2.188441e-04, 1.382420e-04, 8.760467e-05, 5.336446e-05,
          1.475674e-05, 9.216328e-06)

PC <- c(  "PC1"  ,"PC2" , "PC3" , "PC4" , "PC5" , "PC6" , "PC7" , "PC8" , "PC9" , "PC10",
          "PC11", "PC12", "PC13", "PC14", "PC15", "PC16", "PC17", "PC18", "PC19", "PC20",
          "PC21", "PC22", "PC23", "PC24", "PC25", "PC26", "PC27")
names(nums) <- PC

barplot(nums, main = "Eigenvalues", col = "grey", las = 2)
abline(h = mean(nums), col = "red3", lwd = 2)
legend("topright", "Average eigenvalue",
       lwd = 2, col = "red3" )


nums %>% 
  data.frame() %>%
  ggplot(aes(factor(names(nums),levels = PC),nums)) + 
  geom_bar(stat="identity",fill="grey",color="black") +
  geom_hline(yintercept = mean(nums))+
  theme_classic() +
  theme(axis.text.x = element_text(angle=90),
        axis.title = element_blank(),
        plot.title = element_text(hjust=.5))+
  labs(title="Eigenvalues")
LocoGris
  • 4,432
  • 3
  • 15
  • 30