如何防止标签在 ggplot 堆叠条形图中重叠?

问题描述 投票:0回答:2

给定的是这两个数据集,

df_bars
df_lines

library (ggplot2)
library (ggtext)

df_bars <-
  structure(
    list(
      col1 = structure(
        c(
          1L,
          2L,
          3L,
          4L,
          5L,
          6L,
          7L,
          8L,
          9L,
          10L,
          11L,
          12L,
          1L,
          2L,
          3L,
          4L,
          5L,
          6L,
          7L,
          8L,
          9L,
          10L,
          11L,
          12L,
          1L,
          2L,
          3L,
          4L,
          5L,
          6L,
          7L,
          8L,
          9L,
          10L,
          11L,
          12L,
          1L,
          2L,
          3L,
          4L,
          5L,
          6L,
          7L,
          8L,
          9L,
          10L,
          11L,
          12L,
          1L,
          2L,
          3L,
          4L,
          5L,
          6L,
          7L,
          8L,
          9L,
          10L,
          11L,
          12L
        ),
        levels = c(
          "AAA\nN =  172",
          "BBB",
          "CCC",
          "DDD",
          "EEE",
          "FFF",
          "GGG",
          "HHH",
          "III",
          "JJJ",
          "KKK",
          "LLL"
        ),
        class = c("ordered",
                  "factor")
      ),
      Status = structure(
        c(
          1L,
          1L,
          1L,
          1L,
          1L,
          1L,
          1L,
          1L,
          1L,
          1L,
          1L,
          1L,
          2L,
          2L,
          2L,
          2L,
          2L,
          2L,
          2L,
          2L,
          2L,
          2L,
          2L,
          2L,
          3L,
          3L,
          3L,
          3L,
          3L,
          3L,
          3L,
          3L,
          3L,
          3L,
          3L,
          3L,
          4L,
          4L,
          4L,
          4L,
          4L,
          4L,
          4L,
          4L,
          4L,
          4L,
          4L,
          4L,
          5L,
          5L,
          5L,
          5L,
          5L,
          5L,
          5L,
          5L,
          5L,
          5L,
          5L,
          5L
        ),
        levels = c("x", "aaa.kp", "bbb.kp",
                   "ccc.kp", "ddd.kp"),
        class = "factor"
      ),
      Values = c(
        1,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        NA,
        0,
        0,
        0,
        0,
        0,
        0.0813953488372093,
        0.226744186046512,
        0.36046511627907,
        0.447674418604651,
        0.476744186046512,
        0.476744186046512,
        NA,
        0.941860465116279,
        0.831395348837209,
        0.738372093023256,
        0.703488372093023,
        0.680232558139535,
        0.581395348837209,
        0.418604651162791,
        0.273255813953488,
        0.186046511627907,
        0.151162790697674,
        0.0523255813953488,
        NA,
        0,
        0,
        0.0406976744186047,
        0.0406976744186047,
        0.0523255813953488,
        0.0523255813953488,
        0.0581395348837209,
        0.0581395348837209,
        0.0581395348837209,
        0.0581395348837209,
        0.0581395348837209,
        NA,
        0.0581395348837209,
        0.168604651162791,
        0.22093023255814,
        0.255813953488372,
        0.267441860465116,
        0.284883720930233,
        0.296511627906977,
        0.308139534883721,
        0.308139534883721,
        0.313953488372093,
        0.412790697674419
      )
    ),
    row.names = c(NA, -60L),
    class = "data.frame"
  )


df_lines <-
  structure(
    list(
      col1 = structure(
        1:12,
        levels = c(
          "AAA\nN =  172",
          "BBB",
          "CCC",
          "DDD",
          "EEE",
          "FFF",
          "GGG",
          "HHH",
          "III",
          "JJJ",
          "KKK",
          "LLL"
        ),
        class = c("ordered",
                  "factor")
      ),
      aaa.l.rev = c(
        NA,
        1,
        1,
        1,
        1,
        1,
        0.968604651162791,
        0.854651162790698,
        0.866279069767442,
        0.912790697674419,
        0.97093023255814,
        1
      ),
      eee.l = c(
        NA,
        0.0381395348837209,
        0.09046511627907,
        0.0930232558139535,
        0.0348837209302326,
        0.0232558139534884,
        0.0174418604651163,
        0.0174418604651163,
        0.0116279069767442,
        0,
        0.00581395348837209,
        0.0988372093023256
      )
    ),
    class = "data.frame",
    row.names = c(NA, -12L)
  )

我创建了一个堆叠条形图,到目前为止还可以。在这里我也显示值标签。

此外,还有两行也显示了值标签。

    ggplot(df_bars, aes(x = col1, y = Values)) +
  geom_bar(
    data = df_bars,
    mapping = aes(x = col1, y = Values, fill = Status),
    position = "stack",
    stat = "identity"
  ) +
  geom_text(
    data = df_bars,
    aes(
      x = col1,
      y = Values,
      geom = Status,
      label = ifelse(Values >= 0.01, paste0 (sprintf(
        "%1.1f%%", 100 * Values
      )), "")
    ),
    size = 2.5,
    position = position_stack(vjust = 0.5),
    color = (farbe <- c("white", rep(c(
      "black"
    ), times = 55)))
  ) +
  geom_line(data = df_lines,
            mapping = aes(
              x = col1,
              y = eee.l,
              group = 1,
              colour = "Lorem"
            )) +
  geom_line(data = df_lines,
            mapping = aes(
              x = col1,
              y = aaa.l.rev,
              group = 1,
              colour = "Ipsum"
            )) +
  geom_text(
    data = df_lines,
    mapping = aes(
      x = col1,
      y = aaa.l.rev,
      label = ifelse(aaa.l.rev >= 0.1, paste0 (sprintf(
        "%1.1f%%", -100 * aaa.l.rev + 100
      )), "")
    ),
    size = 2.5,
    position = position_stack(vjust = .98)
  ) +
  geom_text(
    data = df_lines,
    mapping = aes(
      x = col1,
      y = eee.l,
      label = paste0 (sprintf("%1.1f%%", 100 * eee.l))
    ),
    size = 2.5,
    position = position_stack(vjust = .9)
  ) +
  scale_y_continuous(expand = c(NA, 100),
                     labels = NULL) +
  labs(title = "Title\n\n", colour = "") +
  labs(caption = paste(
    sprintf("**Bla/Blubb**: %s", "Blubb"),
    sprintf("\n\n**As of**: %s", format(Sys.time(), "%b %Y"))
  )) +
  ylab ("") + xlab ("") +
  scale_x_discrete(labels = df_bars$col1, position = "top") +
  coord_cartesian(clip = "off") +
  guides(fill = guide_legend(title = "")) +
  theme(
    legend.position = "top",
    legend.direction = "horizontal",
    legend.box = "vertical",
    legend.box.just = "left",
    legend.spacing.x = unit(0.2, 'cm'),
    legend.box.spacing = unit(0, "pt"),
    legend.margin = margin(0, 0, 0, 0),
    legend.text = element_text(size = 7, color = "black"),
    legend.background = element_rect(fill = "white", colour = "white"),
    axis.ticks.x = element_blank(),
    axis.ticks.y = element_blank(),
    panel.grid.major.x = element_line(color = "#EAEAEA"),
    panel.grid.major.y = element_line(color = "#EAEAEA"),
    plot.background = element_rect(fill = "white",
                                   color = "#EAEAEA"),
    panel.background = element_rect(fill = "white", colour = NA),
    plot.title = element_textbox(
      size = 11,
      lineheight = 1,
      face = "bold",
      width = unit(0.9, "npc"),
    ),
    plot.margin = margin(0.3, 0.5, 0.3, 0.5, "cm"),
    plot.caption.position = "plot",
    plot.caption = element_textbox(
      size = 7,
      lineheight = 1.2,
      hjust = 0.3,
      vjust = 0.5,
      width = unit(1.02, "npc"),
      margin = margin(12, 0, 0, 2)
    ),
    axis.text = element_text(size = 7, color = "black")
  )

在某些地方,条形和线条的值标签重叠。有没有办法自动避免这种情况?

r ggplot2 geom-bar geom-text
2个回答
1
投票

这里有一个替换三个geom_text层的方法,将它们组合起来使它们可以相互避开,并使用dplyr复制定位。我在这里尝试通过对线条标签使用粗体来使标签彼此更加区分,但肯定还有其他方法可以区分它们(例如颜色、标签轮廓、大小、字体等)

# after loading library(dplyr) as well
...


 ggrepel::geom_text_repel(
    aes(col1, Values_pos, label = label, fontface = fontface),
    direction = "y",
    box.padding = 0.1, label.padding = 0.1, 
    size = 2.5,
    data = bind_rows(
      df_bars %>% 
        arrange(Status) %>%
        group_by(col1) %>%
        arrange(desc(Status)) %>%
        mutate(Values_cuml = cumsum(Values),
               Values_pos = Values_cuml - Values/2,
               fontface = "plain",
               label = ifelse(Values >= 0.01, paste0 (sprintf(
                 "%1.1f%%", 100 * Values
               )), "")) %>%
        ungroup(),
      
      df_lines %>%
        group_by(col1) %>%
        mutate(Values_cuml = cumsum(aaa.l.rev),
               Values_pos = Values_cuml - 0.02*aaa.l.rev,
               fontface = "bold",
               label = ifelse(aaa.l.rev >= 0.1, paste0 (sprintf(
                 "%1.1f%%", -100 * aaa.l.rev + 100
               )), "")) %>%
        ungroup(),
      
      df_lines %>%
        group_by(col1) %>%
        mutate(Values_cuml = cumsum(eee.l),
               Values_pos = Values_cuml - 0.1*eee.l,
               fontface = "bold",
               label = paste0 (sprintf("%1.1f%%", 100 * eee.l))) %>%
        ungroup()
    )
  ) +

0
投票

一种快速而肮脏的解决方法是左对齐一组标签,右对齐另一组标签。在这里,我将

hjust = 1.1
添加到
geom_text()
调用中,并将
fontface = "bold", hjust = -0.1
添加到 2
geom_text()
调用中(窃取@JonSpring 加粗线条标签的想法)。所有其他代码不变。

标签仍然不是很直观。如果您真的想同时显示线条和条形的百分比,请考虑添加交互性,例如与 ggiraph 或密谋。例如,您可以在工具提示中显示线条的静态标签和条形段的标签。

© www.soinside.com 2019 - 2024. All rights reserved.