如何重新排序 ggplot 和 plotly 中的图例?

How to reorder the legend in ggplot and pltly?

我有一个很简单的问题,但我不确定如何解决它:我正在绘制李克特比例条形图。

likert_results2 <-  structure(list(Survey = c("Post survey \nN= 274", "Post survey \nN= 274", 
                                              "Post survey \nN= 274", "Post survey \nN= 274", "Post survey \nN= 274", 
                                              "Post survey \nN= 274", "Pre survey \nN= 429", "Pre survey \nN= 429", 
                                              "Pre survey \nN= 429", "Pre survey \nN= 429", "Pre survey \nN= 429", 
                                              "Pre survey \nN= 429", "Post survey \nN= 276", "Post survey \nN= 276", 
                                              "Post survey \nN= 276", "Post survey \nN= 276", "Post survey \nN= 276", 
                                              "Post survey \nN= 276", "Pre survey \nN= 428", "Pre survey \nN= 428", 
                                              "Pre survey \nN= 428", "Pre survey \nN= 428", "Pre survey \nN= 428", 
                                              "Pre survey \nN= 428"), Response = c("agree", "disagree", "neither agree nor disagree", 
                                                                                   "somewhat agree", "somewhat disagree", "strongly agree", "agree", 
                                                                                   "disagree", "neither agree nor disagree", "somewhat agree", "somewhat disagree", 
                                                                                   "strongly agree", "agree", "disagree", "neither agree nor disagree", 
                                                                                   "somewhat agree", "somewhat disagree", "strongly agree", "agree", 
                                                                                   "disagree", "neither agree nor disagree", "somewhat agree", "somewhat disagree", 
                                                                                   "strongly agree"), Question = c("q1", 
                                                                                                                   "q1", 
                                                                                                                   "q1", 
                                                                                                                   "q1", 
                                                                                                                   "q1", 
                                                                                                                   "q1", 
                                                                                                                   "q1", 
                                                                                                                   "q1", 
                                                                                                                   "q1", 
                                                                                                                   "q1", 
                                                                                                                   "q1", 
                                                                                                                   "q1", 
                                                                                                                   "q2", 
                                                                                                                   "q2", 
                                                                                                                   "q2", 
                                                                                                                   "q2", 
                                                                                                                   "q2", 
                                                                                                                   "q2", 
                                                                                                                   "q2", 
                                                                                                                   "q2", 
                                                                                                                   "q2", 
                                                                                                                   "q2", 
                                                                                                                   "q2", 
                                                                                                                   "q2"
                                                                                   ), prop = c(0.17, 0.21, 0.08, 0.29, 0.16, 0.09, 0.14, 0.16, 0.16, 
                                                                                               0.3, 0.18, 0.07, 0.13, 0.21, 0.11, 0.29, 0.19, 0.07, 0.11, 0.18, 
                                                                                               0.18, 0.28, 0.21, 0.06)), class = c("tbl_df", "tbl", "data.frame"
                                                                                               ), row.names = c(NA, -24L))

# Create data frame with labels
prop_labels <- likert_results2 %>%
  mutate(
    position = case_when(
      Response == "somewhat disagree" | Response == "disagree" | Response == "strongly disagree" ~ "left",
      Response == "neither agree nor disagree" ~ "center",
      Response == "somewhat agree" | Response == "agree"  | Response == "strongly agree" ~ "right"
    )
  ) %>%
  group_by(Question, Survey, position) %>%
  dplyr::summarize(.,label = sum(prop * 100)) %>%
  pivot_wider(names_from = position,
              values_from = label)

# Data frame with left side values
high_columns <- likert_results2 %>%
  filter( Response == "strongly disagree" |  Response == "disagree"| Response == "somewhat disagree" | Response == "neither agree nor disagree") %>%
  mutate(prop = case_when(Response == "strongly disagree" ~ prop * 100,
                          Response == "disagree" ~ prop * 100,
                          Response == "somewhat disagree" ~ prop * 100,
                          Response == "neither agree nor disagree" ~ prop / 2 * 100
  ))
# Data frame with right side values
low_columns <- likert_results2 %>%
  filter(Response == "neither agree nor disagree" | Response == "somewhat agree" | Response == "agree" | Response == "strongly agree") %>%
  mutate(prop = case_when(Response == "neither agree nor disagree" ~ prop / 2 * 100,
                          Response == "somewhat agree" ~ prop * 100,
                          Response == "agree" ~ prop * 100,
                          Response == "strongly agree" ~ prop * 100,
  )) 
# Define empty ggplot object
p <- ggplot() +
  # Add central black line
  geom_hline(yintercept = 0,
             linetype="dashed",
             colour ="darkgrey") +
  # Add right side columns
  geom_bar(
    data = high_columns,
    mapping = aes(x = Survey,
                  y = prop,
                  fill = Response),
    position = position_stack(reverse = F),
    stat = "identity"
  ) +
  # Add left side columns
  geom_bar(
    data = low_columns,
    mapping = aes(x = Survey,
                  y = -prop,
                  fill = Response),
    position = position_stack(reverse = T),
    stat = "identity"
  ) +
  #Right side labels
  geom_text(
    data = prop_labels,
    mapping = aes(
      x = Survey,
      y = -100,
      label = paste(ifelse(is.na(right),0,round(right)) , "%", sep = "")),
    hjust = 1,
    color = "black",
    size = 3
  ) +
  # Central labels
  geom_text(
    data = prop_labels,
    mapping = aes(
      x = Survey,
      y = 0,
      label = paste(ifelse(is.na(center),0,round(center)) , "%", sep = "")),
    hjust = 0.5,
    color = "black",
    size = 3
  ) +
  # Left side labels
  geom_text(
    data = prop_labels,
    mapping = aes(
      x = Survey,
      y = 100,
      label = paste(ifelse(is.na(left),0,round(left)) , "%", sep = "")),
    hjust = -0.2,
    color = "black",
    size = 3
  )  +
  # Scale formatting
  scale_y_continuous(
    breaks = seq(-100, 100, 50),
    limits = c(-105, 105),
    labels = abs
  )  +
  # More formatting
  theme(legend.title = element_blank(),
        legend.position = "right",
        axis.ticks = element_blank(),
        strip.background = element_rect(fill = "#F0F0F0",
                                        color = "#F0F0F0"),
        panel.background = element_blank(),
        panel.border = element_rect(
          colour = "#F0F0F0",
          fill = NA,
          size = 1.5)
  ) +
  facet_wrap(~ Question, scales="free_y",ncol = 1) +
  coord_flip() +
  ylab("Percent of students") +
  xlab("") +
  # Change Likert labels
  scale_fill_manual(name = "Response", values = c("#1E4384","#6495CF","#7278A8","#AFA690", "#E9739B","#B54461","#B1235E") ,labels=c("strongly agree","agree","somewhat agree","neither agree nor disagree","somewhat disagree","disagree","strongly disagree"))
# Print the plot
p 

#plotly graph
ggplotly(p, width = 1200, height = 800) 

我遇到的问题是如何以正确的方式对图例中的项目进行排序。如果我 运行 没有 scale_fill_manual 的代码,情节看起来像这样:

[![在此处输入图片描述][1]][1]

除了我添加 scale_fill_manual

时的图例顺序外,其他都是正确的

当我用 scale_fill_manual 指定顺序时,我得到了这个:这确实改变了图例中的顺序以更正,但不是带有颜色的方块:

[![在此处输入图片描述][2]][2]

当我 运行 ggplotly- 该命令也会删除我指定的所有订单。 [1]: https://i.stack.imgur.com/Z53nF.png [2]: https://i.stack.imgur.com/QeRnw.png

您的代码似乎缺少一些变量,因此我无法向您展示相同的图,但您的问题似乎最好使用说明性示例数据框来回答。 TL;DR - 使用 breaks= 分配图例中键的顺序。

您的问题的答案在于了解如何使用 scale_*_manual():

更改图例的各个方面
  • labels= 使用它来更改每个图例键的外观(单词)。

  • values= 当您开始设置任何其他参数时必需。如果您提供一个命名向量或列表,您可以明确地为与数据关联的基础因素的每个水平分配一种颜色。如果您提供颜色列表,它们将根据图例中标签的顺序分配。请注意,它不是根据 因素水平分配的。

  • breaks= 使用此参数指示图例键出现的顺序

示例如下:

library(dplyr)
library(tidyr)
library(ggplot2)
df <- data.frame(x=1:100, Low=rnorm(100,5,1.2),Med=rnorm(100,10,2),High=rnorm(100,15,0.8))
df <- df %>% gather('Status','Values',-x)

p <- ggplot(df, aes(Status,Values)) + geom_boxplot(aes(fill=Status), alpha=0.5)
p + scale_fill_manual(values=c('red','blue','green'))

df$Status在x轴上的排列顺序由factor(df$Status)levels=的排列顺序决定。这不是您在问题中提出的问题,但最好记住。默认情况下,这似乎是按字母顺序决定的。

图例条目类似地按字母顺序排列,但这是因为对于离散值,顺序将默认为 factor(df$Status) 中级别的顺序。因此,values= 的未命名颜色向量是根据图例中项目的顺序分配的。

请注意如果您使用 labels= 尝试将其恢复为“低、中、高”会发生什么:

p + scale_fill_manual(labels=c('Low','Med','High'), values=c('red','blue','green'))

现在您应该看到用简单向量分配 labels= 的危险。 labels= 参数只是 重命名 各个级别的每个标签...但顺序不会改变。如果我们想重命名关卡,更好的方法是发送 labels= 命名向量:

p + scale_fill_manual(
  labels=c('Low'='Lowest','Med'='Medium','High'='Highest'),
  values=c('red','blue','green'))

如果您想更改图例 中项目的顺序,您可以使用breaks= 参数来实现。在这里,我将向您展示所有参数的组合:

p + scale_fill_manual(
  labels=c('Low'='Lowest','Med'='Medium','High'='Highest'),
  values=c('red','blue','green'),
  breaks=c('Low','Med','High'))