1

I have been trying to create a stacked bar plot, where the colors of the plot relate to those in a map. Basically, I have proportion of an area covered by a given polygon. I have sorted my df in advance so the stacks Proportion are in decreasing order per each Class. It works ok if a set the values of the fill as a continuos variable i.e. Cluster (but then I can't change particular colors of the stack), and if I convert them into factors Clu then the order of the stacks is lost or I can manage to sort them but for the whole graph not for each class... The same Cluster can occur in different classes i.e. cluster Two

          Num    Class Cluster Proportion   Clu Order consec
1    9  Class_9       2      0.859   Two     1      1
2    9  Class_9       5      0.141  Five     2      2
3   10 Class_10       2      0.622   Two     1      3
4   10 Class_10       1      0.179   One     2      4
5   10 Class_10       7      0.165 Seven     3      5
6   10 Class_10       6      0.034   Six     4      6
7   11 Class_11       7      1.000 Seven     1      7
8   12 Class_12       2      0.571   Two     1      8
9   12 Class_12       8      0.289 Eight     2      9
10  12 Class_12       1      0.140   One     3     10
11  13 Class_13       8      0.581 Eight     1     11
12  13 Class_13       4      0.210  Four     2     12
13  13 Class_13       2      0.112   Two     3     13
14  13 Class_13       3      0.079 Three     4     14
15  13 Class_13       5      0.018  Five     5     15

I have managed to go this far with the code.

cols<-c(One='Blue',Two='Red',Three='Yellow',Four='lightblue',Five='darkgrey',Six='Black', Seven='cyan',Eight='Green')
  

ggplot(Tx, aes(x=Class, y=Proportion, fill= Clu)) + 
  geom_col(width = .7, colour="black", lwd=0.1) +
  geom_text(aes(label=ifelse(Proportion >= 0.05, sprintf("%.2f",Proportion),"")),
            position=position_stack(vjust=0.5), colour="white") +
  coord_flip() +
  scale_y_continuous(labels = function(y) paste0(y))+
  scale_fill_manual(values = cols)+ 
  labs(y="", x="")

To summarize, I would like to have a graph with the proportions in increasing order for each class, but with the colors I specify for each clusters

enter image description here

nniloc
  • 4,128
  • 2
  • 11
  • 22
Ana
  • 13
  • 3
  • Hi Ana, welcome to SO! The data you provided does not have a variable `Ecoregion` but the plot does. It would be helpful if you could edit your question to provide a [minimal reproducible example](https://stackoverflow.com/a/5963610/12400385) – nniloc Sep 11 '20 at 19:11
  • Sorry, correction done. Thanks! – Ana Sep 11 '20 at 22:28

1 Answers1

0

One option (a little different than what you were thinking) is to use position.dodge and tidytext::reorder_within.

library(tidyverse)
library(tidytext)

cols<-c('Blue','Red','Yellow','lightblue','darkgrey','Black', 'cyan', 'Green')

Tx %>%
  mutate(Cluster2 = reorder_within(Cluster, Proportion, Class)) %>%
  ggplot(aes(Cluster2, Proportion, fill = as.factor(Cluster))) +
  geom_col(position = position_dodge2(preserve = "single")) +
  scale_x_reordered() +
  scale_fill_manual(values = cols) +
  coord_flip() +
  facet_grid(Class~., scales = 'free_y', space = 'free')

enter image description here


If you really need the stacked bars with the different orders, another option is to generate the plot for each class separately (which allows for the correct order) and then stack them all back together. This can be done using cowplot::plot_grid and cowplot::get_legend.

Generate list of plots with correct order and stack them into one plot.

library(tidyverse)
library(cowplot)

Tx2 <- Tx %>%
  mutate(Cluster = factor(Cluster))

cols<-c(One='Blue',Two='Red',Three='Yellow',Four='lightblue',Five='darkgrey',Six='Black', Seven='cyan',Eight='Green')


p_list <- lapply(unique(Tx2$Class), function(x){
  p <-  Tx2 %>%
    filter(Class == x) %>%
    ggplot(aes(Class, Proportion, fill = reorder(Clu, -Proportion))) +
    geom_col(color = 'black') +
    geom_text(aes(label=ifelse(Proportion >= 0.05, sprintf("%.2f",Proportion),"")),
              position=position_stack(vjust=0.5), 
              color = 'white') +
    coord_flip() +
    scale_fill_manual(values = cols) +
    labs(x = NULL, y = NULL) +
    theme_minimal() +
    theme(legend.position = 'none') 
  
 if (x != 'Class_13') p <- p + theme(axis.text.x = element_blank()) 
  
 p
})



p_col <- plot_grid(plotlist = p_list,
                   ncol = 1, 
                   align = 'v',
                   rel_heights = c(rep(1,4), 1.2))

Generate the legend to be used.

p <- ggplot(Tx2, aes(Class, Proportion, fill = reorder(Clu, as.numeric(Cluster)))) +  
  geom_col(color = 'black') +
  scale_fill_manual(values = cols, labels= 1:8, name = 'Cluster')
l <- cowplot::get_legend(p)

Put the stacked plots and the legend together.

plot_grid(p_col, l, rel_widths = c(3, .4))

!enter image description here


Data

Tx <- read.table(text = 
'  Num    Class Cluster Proportion   Clu Order consec
1    9  Class_9       2      0.859   Two     1      1
2    9  Class_9       5      0.141  Five     2      2
3   10 Class_10       2      0.622   Two     1      3
4   10 Class_10       1      0.179   One     2      4
5   10 Class_10       7      0.165 Seven     3      5
6   10 Class_10       6      0.034   Six     4      6
7   11 Class_11       7      1.000 Seven     1      7
8   12 Class_12       2      0.571   Two     1      8
9   12 Class_12       8      0.289 Eight     2      9
10  12 Class_12       1      0.140   One     3     10
11  13 Class_13       8      0.581 Eight     1     11
12  13 Class_13       4      0.210  Four     2     12
13  13 Class_13       2      0.112   Two     3     13
14  13 Class_13       3      0.079 Three     4     14
15  13 Class_13       5      0.018  Five     5     15')
nniloc
  • 4,128
  • 2
  • 11
  • 22
  • Thanks @nniloc! In my real data, clusters with higher proportions don't always correspond to an increasing cluster number (Cluster number in reality is only nominal, hence the Clu variable), I've changed the data set to reflect this. With the larger dataset, when I use your code, not all clusters are sorted by increasing proportion per class. – Ana Sep 12 '20 at 02:40
  • Sounds like you are asking to reorder the stack positions within each bar? I'm not sure if that is possible without generating each plot separately and merging them back together. Thinking outside the box, maybe a plot like this would suit your needs? https://stackoverflow.com/a/43176996/12400385 – nniloc Sep 12 '20 at 20:03
  • 1
    Thanks for the suggestion @nniloc I will try that. Yes I want like to sort the stacks within each bar... I don't understand why if I use the fill as a continuos variable and not as a factor, it can order the stacks per bar, but not when is a factor. I don't have enough points to post that chart, but it does it right. But i'll follow your suggestion, of generating each plot on its own. Need to do 6 sets of them though, so that's 42 lil' plots : (... It also seems that I don't have enough points to vote your answer. But really appreciated! – Ana Sep 14 '20 at 19:03
  • I think the real trick here is you can convert `Cluster` to a factor and reorder, but you can't do that for each `Class` without breaking the data into independent chunks. – nniloc Sep 14 '20 at 19:19
  • If this answers your question you should be able to accept this as the answer. If not, I suggest adding the `ggplot2` tag to the question and you might get some more people chiming in. – nniloc Sep 14 '20 at 19:20
  • Thanks again!! I'll go for option two, generate them separately and then stack togheter.. option one is not good for me as I need 5 more graphs like this, it will use up too much space! Very helpful, for a) solving my issue and b) do it by thinking outside the box. – Ana Sep 15 '20 at 22:09