Stacked barchart, independent fill order for each stack

前端 未结 3 668
南方客
南方客 2020-11-28 15:58

I\'m facing a behaviour of ggplot2, ordering and stacked barplot that I cannot understand.
I\'ve read some question about it (here,here and so on), but unlu

相关标签:
3条回答
  • 2020-11-28 16:31

    If you use separate geom_bars, you can make the orders different.

    dats %>% 
      ggplot(aes(x = id, y = value, fill = reorder(filling,-ordering))) + 
        geom_bar(stat = "identity", position = "stack", data = dats %>% filter(id == 1)) +
        geom_bar(stat = "identity", position = "stack", data = dats %>% filter(id == 2)) +
        geom_bar(stat = "identity", position = "stack", data = dats %>% filter(id == 3)) +
        guides(fill=guide_legend("ordering")) 
    

    More generally:

    bars <- map(unique(dats$id)
                , ~geom_bar(stat = "identity", position = "stack"
                           , data = dats %>% filter(id == .x)))
    
    dats %>% 
      ggplot(aes(x = id, y = value, fill = reorder(filling,-ordering))) + 
        bars +
        guides(fill=guide_legend("ordering"))
    
    0 讨论(0)
  • 2020-11-28 16:39

    The problem is that, in your case, different bars should use the same values (levels) of filling in a different order. This conflicts with the way ggplot works: taking the factor levels (which already have a certain order) and applying them in the same way for each bar.

    A workaround then is... To create many factor levels.

    ggplot(dats, aes(x = id, y = value, fill = interaction(-ordering, id))) + 
      geom_bar(stat = "identity", position = "stack")
    

    This one now is too "generous" by being too detailed. However, what we can do now is to deal with the legend and the different colors:

    dats <- arrange(dats, id, -ordering)
    aux <- with(dats, match(sort(unique(filling)), filling))
    ggplot(dats, aes(x = id, y = value, fill = interaction(-ordering, id))) + 
      geom_bar(stat = "identity", position = "stack") +
      scale_fill_manual("Ordering", values = scales::hue_pal()(4)[dats$filling],
                        labels = with(dats, filling[aux]), 
                        breaks = with(dats, interaction(-ordering, id)[aux]))
    

    Here I first rearrange the rows of dats as to avoid doing that later. Then aux is an auxiliary vector

    aux
    # [1] 3 2 1 8
    

    giving arbitrary positions (one for each) where levels a, b, c, and d (in this order) appear in dats, which again is useful later. Then I simply set corresponding scale values, labels, and breaks... Lastly, I use scales::hue_pal to recover the original color palette.

    0 讨论(0)
  • 2020-11-28 16:47

    The problem here is that the element filling = d only appears in the third group with a low value. One solution, could be to fill non-present values with 0:

    library(dplyr)
    #> 
    #> Attachement du package : 'dplyr'
    #> The following objects are masked from 'package:stats':
    #> 
    #>     filter, lag
    #> The following objects are masked from 'package:base':
    #> 
    #>     intersect, setdiff, setequal, union
    library(ggplot2)
    dats <- data.frame(id = c(1,1,1,1,2,2,2,2,3,3,3,3),
                       value = c(9,6,4,0,5,6,0,0,4,3,4,5),
                       ordering = c(1,2,3,5,2,3,5,5,1,3,2,4),
                       filling = c('a','b','c','d','b','a','c','d','a','c','d','b')) %>% arrange(id,ordering)
    
    
    ggplot(dats,aes(x = id,
                    y = value,
                    fill = reorder(filling,-ordering))) + 
      geom_bar(stat = "identity",position = "stack") +
      guides(fill=guide_legend("ordering")) 
    

    Created on 2018-12-03 by the reprex package (v0.2.1)

    0 讨论(0)
提交回复
热议问题