英文:
How can I center geom_label_repel labels so that they are in the middle of each bar?
问题
我使用geom_label_repel
来在分面水平条形图中放置百分比,大部分情况下效果很好,但我似乎找不到一种将标签移动到每个条形的中间(或尽可能接近中间)的方法。相反,它们被右对齐,这在视觉上有点令人困惑,因为一些条形彼此靠近。
我已经尝试使用h_just
和v_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")
这是当前的图:
为了使其可再现,这是一些数据:
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 <- function(x) {
x %>%
# we need to get the data including facet info in long format, so we use pivot_longer()
pivot_longer(!response, names_to = "bin_name", values_to = "b") %>%
# add counts for plot below
count(response, bin_name, b) %>%
# remove nas
filter(!is.na(response)) %>%
# add grouping by bins
group_by(bin_name,b) %>%
# calculate percentages
mutate(perc=paste0(round(n*100/sum(n),0),"%")) %>%
# run ggplot
ggplot(aes(x = n, y = "", 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 = "off") +
geom_vline(xintercept = x_limits, linetype = 3) +
geom_label_repel(
# important to make sure grouping of data matches grouping of labels so they aren'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 = "y",
force = 1.5,
fill = "white",
# 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="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()
}
And the code that uses it:
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(.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")
Here's the plot as it currently stands:
And a bit of data to make it reproducible:
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")))
答案1
得分: 2
你需要将 vjust = 0.5
放在 position_fill
内:
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(vjust = 0.5), 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(vjust = 0.5),
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()
英文:
You need to put vjust = 0.5
inside position_fill
:
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(vjust = 0.5),
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()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论