如何将geom_label_repel标签居中,使其位于每个条形图的中间?

huangapple go评论65阅读模式
英文:

How can I center geom_label_repel labels so that they are in the middle of each bar?

问题

我使用geom_label_repel来在分面水平条形图中放置百分比,大部分情况下效果很好,但我似乎找不到一种将标签移动到每个条形的中间(或尽可能接近中间)的方法。相反,它们被右对齐,这在视觉上有点令人困惑,因为一些条形彼此靠近。

我已经尝试使用h_justv_just,但这些只会将文本居中在其框内,而不是将框放在图中的中间。如果我放弃position_identity() 而选择 nudge_x,则所有条形都消失,所以这不适用。我假设有一种简单的方法来实现这一点,但我没有看到它!

这是我制作绘图的函数:

plot_single_result_with_facets <- function(x) {
  x %>%
    pivot_longer(!response, names_to = "bin_name", values_to = "b") %>%
    count(response, bin_name, b) %>%
    filter(!is.na(response)) %>%
    group_by(bin_name, b) %>%
    mutate(perc = paste0(round(n * 100 / sum(n), 0), "%")) %>%
    ggplot(aes(x = n, y = "", fill = response, label = perc)) +
    geom_col(position = position_fill(), aes(fill = forcats::fct_rev(response))) +
    coord_cartesian(clip = "off") +
    geom_vline(xintercept = x_limits, linetype = 3) +
    geom_label_repel(
      aes(group = forcats::fct_rev(response), label = perc),
      hjust = 0.5,
      vjust = 0.5,
      direction = "y",
      force = 1.5,
      fill = "white",
      size = 1.5,
      max.overlaps = Inf,
      position = position_fill(),
      segment.size = 0.2,
      point.size = NA,
      box.padding = 0.001
    ) +
    scale_fill_brewer(palette = "YlOrBr", direction = -1) +
    scale_x_continuous(labels = scales::percent_format(), expand = c(0.05, 0.05)) +
    facet_grid(vars(b), vars(bin_name), labeller = as_labeller(facet_names)) +
    labs(title = title, caption = caption, x = "", y = "") +
    guides(fill = guide_legend(title = NULL)) +
    theme_classic()
}

使用它的代码:

caption <- NULL
df <- select(data, Q51_bin, Q52_bin, Q57_bin, Q53_bin, Q4)
df <- as_factor(df)
names(df) <- c("Q51_bin", "Q52_bin", "Q57_bin", "Q53_bin", "response")
facet_names <- c(`Q51_bin` = "Nature Relatedness", `Q52_bin` = "Spirituality", `Q57_bin` = "Religiosity", `Q53_bin` = "Politics L/R", `low` = "low", `medium` = "medium", `high` = "high")
facet_labeller <- function(variable, value) {
  return(facet_names[value])
}
x_limits <- c(0.50, NA)
facet_grid(~fct_relevel(df, 'Nature Relatedness', 'Spirituality', 'Religiosity', 'Politics L/R'))
plot_single_result_with_facets(df)
ggsave("figures/q5_faceted.png", width = 20, height = 10, units = "cm")

这是当前的图:

如何将geom_label_repel标签居中,使其位于每个条形图的中间?

为了使其可再现,这是一些数据:

df <- structure(list(Q51_bin = structure(c(2L, 2L, 2L, 2L), levels = c("low", "medium", "high"), class = "factor"), Q52_bin = structure(c(3L, 2L, 2L, 2L), levels = c("low", "medium", "high"), class = "factor"), Q57_bin = structure(c(2L, 2L, 2L, 2L), levels = c("low", "medium", "high"), class = "factor"), Q53_bin = structure(c(2L, 3L, 2L, 2L), levels = c("low", "medium", "high"), class = "factor"), Q4 = structure(c(2, 3, 3, 5), label = "How much have you thought about climate change before today?", format.spss = "F40.0", display_width = 5L, labels = c(`Not at all` = 1, `A little` = 2, Some = 3, `A lot` = 4, `A great deal` = 5, `Don't know` = 99), class = c("haven_labelled", "vctrs_vctr", "double"))), class = c("rowwise_df", "tbl_df", "tbl", "data.frame"), row.names = c(NA, -4L), groups = structure(list(.rows = structure(list(1L, 2L, 3L, 4L), ptype = integer(0), class = c("vctrs_list_of", "vctrs_vctr", "list"))), row names = c(NA, -4L), class = c("tbl_df", "tbl", "data.frame")))
英文:

I'm using geom_label_repel to place percentages in a faceted horizontal bar chart, which mostly works great, except that I can't seem to find a way to shift the labels to the middle (or as close as possible) of each bar. Instead, they are justified right, which visually is a bit confusing as some bars are close to one another.

I've tried using h_just and v_just, but these just center the text within its box rather than the box within the plot. If I drop position_identity() in favour of nudge_x the bars all drop out, so that doesn't get me there. Assuming there is some simple way to do this, but I'm not seeing it!

Here's the function I've made to do the plot:

plot_single_result_with_facets &lt;- function(x) {
  x %&gt;% 
    # we need to get the data including facet info in long format, so we use pivot_longer()
    pivot_longer(!response, names_to = &quot;bin_name&quot;, values_to = &quot;b&quot;) %&gt;% 
    # add counts for plot below
    count(response, bin_name, b) %&gt;%
    # remove nas
    filter(!is.na(response)) %&gt;%
    # add grouping by bins
    group_by(bin_name,b) %&gt;%
    # calculate percentages
    mutate(perc=paste0(round(n*100/sum(n),0),&quot;%&quot;)) %&gt;% 
    # run ggplot
    ggplot(aes(x = n, y = &quot;&quot;, fill = response, label = perc)) +
    # reversing order here using forcats::fct_rev() note - needs to be changed under geom_label_repel as well
    geom_col(position=position_fill(), aes(fill=forcats::fct_rev(response))) +
    coord_cartesian(clip = &quot;off&quot;) +
    geom_vline(xintercept = x_limits, linetype = 3) +
    geom_label_repel(
      # important to make sure grouping of data matches grouping of labels so they aren&#39;t backwards
      # reversing order here using forcats::fct_rev() note - needs to be changed above as well
      aes(group = forcats::fct_rev(response), label = perc),
      # justify text using center = 0.5, left = 0 and right = 1
      hjust = 0.5,
      vjust = 0.5,
      direction = &quot;y&quot;,
      force = 1.5,
      fill = &quot;white&quot;, 
      # font size in the text labels
      size = 1.5,
      # allow labels to overlap
      max.overlaps = Inf,
      # make sure that bars are included
      position = position_fill(),
      # hide points
      segment.size = 0.2,
      point.size = NA,
      # reduce padding around each text label
      box.padding = 0.001
    ) +
    scale_fill_brewer(palette=&quot;YlOrBr&quot;, direction = -1) +
    scale_x_continuous(labels = scales::percent_format(), expand = c(0.05, 0.05)) +
    facet_grid(vars(b), vars(bin_name), labeller=as_labeller(facet_names)) + 
    labs(title = title, caption = caption, x = &quot;&quot;, y = &quot;&quot;) + 
    guides(fill = guide_legend(title = NULL)) +
    theme_classic()
}

And the code that uses it:

caption &lt;- NULL
df &lt;- select(data, Q51_bin, Q52_bin, Q57_bin, Q53_bin, Q4)
df &lt;- as_factor(df)
names(df) &lt;- c(&quot;Q51_bin&quot;, &quot;Q52_bin&quot;, &quot;Q57_bin&quot;, &quot;Q53_bin&quot;, &quot;response&quot;)
facet_names &lt;- c(`Q51_bin` = &quot;Nature Relatedness&quot;, `Q52_bin` = &quot;Spirituality&quot;, `Q57_bin` = &quot;Religiosity&quot;, `Q53_bin` = &quot;Politics L/R&quot;, `low`=&quot;low&quot;, `medium`=&quot;medium&quot;, `high`=&quot;high&quot;)
facet_labeller &lt;- function(variable,value){return(facet_names[value])}
x_limits &lt;- c(.50, NA)
facet_grid(~fct_relevel(df,&#39;Nature Relatedness&#39;,&#39;Spirituality&#39;,&#39;Religiosity&#39;,&#39;Politics L/R&#39;))
plot_single_result_with_facets(df)
ggsave(&quot;figures/q5_faceted.png&quot;, width = 20, height = 10, units = &quot;cm&quot;)

Here's the plot as it currently stands:

如何将geom_label_repel标签居中,使其位于每个条形图的中间?

And a bit of data to make it reproducible:

df &lt;- structure(list(Q51_bin = structure(c(2L, 2L, 2L, 2L), levels = c(&quot;low&quot;, &quot;medium&quot;, &quot;high&quot;), class = &quot;factor&quot;), Q52_bin = structure(c(3L, 2L, 2L, 2L), levels = c(&quot;low&quot;, &quot;medium&quot;, &quot;high&quot;), class = &quot;factor&quot;), Q57_bin = structure(c(2L, 2L, 2L, 2L), levels = c(&quot;low&quot;, &quot;medium&quot;, &quot;high&quot;), class = &quot;factor&quot;), Q53_bin = structure(c(2L, 3L, 2L, 2L), levels = c(&quot;low&quot;, &quot;medium&quot;, &quot;high&quot;), class = &quot;factor&quot;), Q4 = structure(c(2, 3, 3, 5), label = &quot;How much have you thought about climate change before today?&quot;, format.spss = &quot;F40.0&quot;, display_width = 5L, labels = c(`Not at all` = 1, `A little` = 2, Some = 3, `A lot` = 4, `A great deal` = 5, `Don&#39;t know` = 99), class = c(&quot;haven_labelled&quot;, &quot;vctrs_vctr&quot;, &quot;double&quot;))), class = c(&quot;rowwise_df&quot;, &quot;tbl_df&quot;, &quot;tbl&quot;, &quot;data.frame&quot;), row.names = c(NA, -4L), groups = structure(list(.rows = structure(list(1L, 2L, 3L, 4L), ptype = integer(0), class = c(&quot;vctrs_list_of&quot;, &quot;vctrs_vctr&quot;, &quot;list&quot;))), row.names = c(NA, -4L), class = c(&quot;tbl_df&quot;, &quot;tbl&quot;, &quot;data.frame&quot;)))

答案1

得分: 2

你需要将 vjust = 0.5 放在 position_fill 内:

x %&gt;% 
  pivot_longer(!response, names_to = &quot;bin_name&quot;, values_to = &quot;b&quot;) %&gt;% 
  count(response, bin_name, b) %&gt;
  filter(!is.na(response)) %&gt;
  group_by(bin_name,b) %&gt;
  mutate(perc=paste0(round(n*100/sum(n),0),&quot;%&quot;)) %&gt;%
  ggplot(aes(x = n, y = &quot;&quot;, fill = response, label = perc)) +
  
  geom_col(position=position_fill(vjust = 0.5), aes(fill=forcats::fct_rev(response))) +
  coord_cartesian(clip = &quot;off&quot;) +
  geom_vline(xintercept = x_limits, linetype = 3) +
  geom_label_repel(
    aes(group = forcats::fct_rev(response), label = perc),
    hjust = 0.5,
    vjust = 0.5,
    direction = &quot;y&quot;,
    force = 1.5,
    fill = &quot;white&quot;, 
    size = 1.5,
    max.overlaps = Inf,
    position = position_fill(vjust = 0.5),
    segment.size = 0.2,
    point.size = NA,
    box.padding = 0.001
  ) +
  scale_fill_brewer(palette=&quot;YlOrBr&quot;, direction = -1) +
  scale_x_continuous(labels = scales::percent_format(), expand = c(0.05, 0.05)) +
  facet_grid(vars(b), vars(bin_name), labeller=as_labeller(facet_names)) + 
  labs(title = &#39;title&#39;, caption = caption, x = &quot;&quot;, y = &quot;&quot;) + 
  guides(fill = guide_legend(title = NULL)) +
  theme_classic()

如何将geom_label_repel标签居中,使其位于每个条形图的中间?

英文:

You need to put vjust = 0.5 inside position_fill:

x %&gt;% 
  pivot_longer(!response, names_to = &quot;bin_name&quot;, values_to = &quot;b&quot;) %&gt;% 
  count(response, bin_name, b) %&gt;%
  filter(!is.na(response)) %&gt;%
  group_by(bin_name,b) %&gt;%
  mutate(perc=paste0(round(n*100/sum(n),0),&quot;%&quot;)) %&gt;% 
  ggplot(aes(x = n, y = &quot;&quot;, fill = response, label = perc)) +
  
  geom_col(position=position_fill(), aes(fill=forcats::fct_rev(response))) +
  coord_cartesian(clip = &quot;off&quot;) +
  geom_vline(xintercept = x_limits, linetype = 3) +
  geom_label_repel(
    aes(group = forcats::fct_rev(response), label = perc),
    hjust = 0.5,
    vjust = 0.5,
    direction = &quot;y&quot;,
    force = 1.5,
    fill = &quot;white&quot;, 
    size = 1.5,
    max.overlaps = Inf,
    position = position_fill(vjust = 0.5),
    segment.size = 0.2,
    point.size = NA,
    box.padding = 0.001
  ) +
  scale_fill_brewer(palette=&quot;YlOrBr&quot;, direction = -1) +
  scale_x_continuous(labels = scales::percent_format(), expand = c(0.05, 0.05)) +
  facet_grid(vars(b), vars(bin_name), labeller=as_labeller(facet_names)) + 
  labs(title = &#39;title&#39;, caption = caption, x = &quot;&quot;, y = &quot;&quot;) + 
  guides(fill = guide_legend(title = NULL)) +
  theme_classic()

如何将geom_label_repel标签居中,使其位于每个条形图的中间?

huangapple
  • 本文由 发表于 2023年2月17日 23:34:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75486287.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定