Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stacked bar graphs in plotly: how to control the order of bars in each stack

Tags:

r

plotly

I'm trying to order a stacked bar chart in plotly, but it is not respecting the order I pass it in the data frame.

It is best shown using some mock data:

library(dplyr)
library(plotly)
cars <- sapply(strsplit(rownames(mtcars), split = " "), "[", i = 1)
dat <- mtcars
dat <- cbind(dat, cars, stringsAsFactors = FALSE)
dat <- dat %>% 
         mutate(carb = factor(carb)) %>%
         distinct(cars, carb) %>% 
         select(cars, carb, mpg) %>% 
         arrange(carb, desc(mpg))
plot_ly(dat) %>% 
  add_trace(data = dat, type = "bar", x = carb, y = mpg, color = cars) %>%  
  layout(barmode = "stack") 

The resulting plot doesn't respect the ordering, I want the cars with the largest mpg stacked at the bottom of each cylinder group. Any ideas?

enter image description here

like image 895
stu Avatar asked Jun 15 '16 02:06

stu


People also ask

How do I change the order of bars in a stacked bar chart?

Under Chart Tools, on the Design tab, in the Data group, click Select Data. In the Select Data Source dialog box, in the Legend Entries (Series) box, click the data series that you want to change the order of. Click the Move Up or Move Down arrows to move the data series to the position that you want.

How do you sort a bar graph in Plotly?

In Plotly. express, we can sort a bar plot using the update_layout() function and the xaxis and yaxis parameters. In our example, we wish to sort the data based on the salary starting with the smallest to the highest salary. Hence, we need to use the xaxis parameter.


1 Answers

As already pointed out here, the issue is caused by having duplicate values in the column used for color grouping (in this example, cars). As indicated already, the ordering of the bars can be remedied by grouping your colors by a column of unique names. However, doing so will have a couple of undesired side-effects:

  1. different model cars from the same manufacturer would be shown with different colors (not what you are after - you want to color by manufacturer)
  2. the legend will have more entries in it than you want i.e. one per model of car rather than one per manufacturer.

We can hack our way around this by a) creating the legend from a dummy trace that never gets displayed (add_trace(type = "bar", x = 0, y = 0... in the code below), and b) setting the colors for each category manually using the colors= argument. I use a rainbow pallette below to show the principle. You may like to select sme more attractive colours yourself.

dat$unique.car <- make.unique(as.character(dat$cars))
dat2 <- data.frame(cars=levels(as.factor(dat$cars)),color=rainbow(nlevels(as.factor(dat$cars))))
dat2[] <- lapply(dat2, as.character)
dat$color <- dat2$color[match(dat$cars,dat2$cars)]

plot_ly() %>% 
  add_trace(data=dat2, type = "bar", x = 0, y = 0, color = cars, colors=color, showlegend=T) %>%  
  add_trace(data=dat, type = "bar", x = carb, y = mpg, color = unique.car, colors=color, showlegend=F, marker=list(line=list(color="black", width=1))) %>%  
  layout(barmode = "stack", xaxis = list(range=c(0.4,8.5))) 

enter image description here

like image 174
dww Avatar answered Nov 04 '22 01:11

dww