堆叠式条形图:如何控制每个堆叠中条形的顺序

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

我试图在 plotly 中订购堆叠条形图,但它不符合我在数据框中传递它的顺序。

最好使用一些模拟数据显示:

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

生成的图不符合顺序,我希望 mpg 最大的汽车堆叠在每个气缸组的底部。有什么想法吗?

解决此问题的一种方法是为所有车型赋予唯一名称并在 plotly 中使用该名称,但这会使图例更加混乱并影响颜色映射。这里有几个选项:

dat$carsID <- make.unique(as.character(dat$cars))
# dat$carsID <- apply(dat, 1, paste0, collapse = " ") # alternative

plot_ly(dat) %>% 
  add_trace(data = dat, type = "bar", x = carb, y = mpg, color = carsID) %>%  
  layout(barmode = "stack") 

plot_ly(dat) %>% 
  add_trace(data = dat, type = "bar", x = carb, y = mpg, color = carsID,
            colors = rainbow(length(unique(carsID)))) %>%  
  layout(barmode = "stack")

明天我会多看看是否可以改进图例和颜色映射。

正如已经指出的 ,问题是由用于颜色分组的列中的重复值引起的(在本例中,cars)。如前所述,可以通过按一列唯一名称对颜色进行分组来纠正条形的顺序。但是,这样做会产生一些不良副作用:

  1. 来自同一制造商的不同型号的汽车将以不同的颜色显示(不是您想要的 - 您想要按制造商着色)
  2. 图例中的条目比您想要的要多,即每个车型一个,而不是每个制造商一个。

我们可以通过 a) 从永远不会显示的虚拟轨迹创建图例(下面代码中的add_trace(type = "bar", x = 0, y = 0...),以及 b) 使用手动设置每个类别的颜色colors= 参数。我在下面使用彩虹调色板来展示原理。您可能想 select 自己尝试一些更吸引人的颜色。

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