英文:
Arrange items in a legend in a defined way
问题
我可以为您提供代码的翻译部分,以下是代码的翻译:
# 导入ggplot2库
library(ggplot2)
# 创建数据框DF
DF = data.frame(val = c(10,20,30,40,50,60,70,80,90,100),
param = rep(letters[1:5],2),
x = rep(c('X', 'Y'), 5))
# 使用ggplot创建图表
ggplot(data = DF) +
geom_bar(aes(y = val, fill = param, x = x),
stat = 'identity',
position = position_dodge2(preserve = 'single')) +
guides(fill = guide_legend(nrom = 2, byrow = TRUE))
另外,关于您在图例中看到的白色块问题,似乎与geom_col
中的alpha = 0.6
有关。您可以尝试将alpha
值设置为1,或者在scale_fill_manual
中设置颜色时考虑透明度。不过,具体如何解决问题可能需要进一步的调试和实验,因为涉及到颜色和透明度的调整。
请注意,我只提供了代码的翻译部分,不包括问题的回答。如果您需要更多帮助,请随时提出。
英文:
I have below ggplot
library(ggplot2)
DF = data.frame(val = c(10,20,30,40,50,60,70,80,90,100), param = rep(letters[1:5],2), x = rep(c('X', 'Y'), 5))
ggplot(data = DF) + geom_bar(aes(y = val, fill = param, x = x), stat = 'identity', position = position_dodge2(preserve = 'single')) + guides(fill = guide_legend(nrom = 2, byrow = TRUE))
While I can generate the plot, however, I want to arrange the items in the legend in a specific way as below.
- First 2 items i.e.
a & b
should be in the first row - Remaining items should be arranged in an array fashion with 3 columns and applicable number of rows based on the number of items except first 2 i.e.
a & b
, starting from the second row (first row will only containa & b
) - I also want to bold-face the items
a & b
only, in the legend
Is there any way to achieve such custom arrangement?
Based on the kind answer from @stefan, I modified my code as below
library(ggplot2)
library(scales)
library(dplyr)
DF = data.frame(val = c(10,20,30,40,50,60,70,80,90,100), param = rep(letters[1:5],2), x = rep(c('X', 'Y'), 5))
DF$param <- factor(DF$param, c("a", "b", "spacer", "c", "d", "e"))
pal_fill <- scales::hue_pal()(5)
names(pal_fill) <- letters[1:5]
pal_fill <- c(pal_fill, spacer = "transparent")
ggplot(data = DF) +
geom_col(aes(y = val, fill = param, x = x), alpha = 0.6,
position = position_dodge2(preserve = "single")
) +
scale_fill_manual(
values = pal_fill,
drop = FALSE,
labels = ~ dplyr::case_match(
.x, "spacer" ~ "", c("a", "b") ~ paste0("**", .x, "**"),
.default = .x)
) +
guides(fill = guide_legend(
nrow = 2, byrow = TRUE
)) +
theme(
legend.position=c(.9,.75),
legend.background = element_rect(fill = alpha('#e5e5e5', 0.60)),
#legend.text = ggtext::element_markdown(),
legend.key = element_rect(fill = "transparent")
)
As you see, I see a white
patch in the legend. This actually goes off if I remove alpha = 0.6
in geom_col
. This is strange to me as I failed to understand the connection between alpha
in geom_col
and legend items.
Is there any way to correct this i.e. remove the white
patch?
Any pointer will be very helpful.
答案1
得分: 2
如果我理解您的意思正确,那么实现您期望的结果的一种方法是为一些虚假的图例项添加一些虚假的图例键,通过删除标签并将填充颜色设置为例如 "transparent"
来使图例键“不可见”。
首先,这需要将 param
转换为因子,并在正确的位置添加虚假元素。此外,我们还必须为填充比例设置 drop=FALSE
,以便未使用的虚假元素实际上在图例中显示出来。最后,仅加粗一些图例元素是最简单的任务,可以通过 ggtext::element_markdown
来实现。
注意:根据 theme
设置,将填充颜色设置为 "transparent"
不足以使虚假元素不可见,例如,默认的 theme_grey
在键上有灰色背景填充。因此,我添加了 legend.key = element_rect(fill = "transparent")
以使背景填充也透明。
library(ggplot2)
library(scales)
library(dplyr)
DF$param <- factor(DF$param, c("a", "b", "spacer", "c", "d", "e"))
pal_fill <- scales::hue_pal()(5)
names(pal_fill) <- letters[1:5]
pal_fill <- c(pal_fill, spacer = "transparent")
ggplot(data = DF) +
geom_col(aes(y = val, fill = param, x = x),
position = position_dodge2(preserve = "single")
) +
scale_fill_manual(
values = pal_fill,
drop = FALSE,
labels = ~ dplyr::case_match(
.x, "spacer" ~ "", c("a", "b") ~ paste0("**", .x, "**"),
.default = .x)
) +
guides(fill = guide_legend(
nrow = 2, byrow = TRUE
)) +
theme(
legend.text = ggtext::element_markdown(),
legend.key = element_rect(fill = "transparent")
)
编辑 不得不承认我不太清楚问题在哪里,但解决方法是为“spacer”设置 alpha
为零,我在 geom_col
中使用 after_scale
和 if_else
:
ggplot(data = DF) +
geom_col(
aes(
y = val, fill = param, x = x,
alpha = after_scale(if_else(fill != "transparent", 0.6, 0))
),
position = position_dodge2(preserve = "single")
) +
scale_fill_manual(
values = pal_fill,
drop = FALSE,
labels = ~ dplyr::case_match(
.x, "spacer" ~ "", c("a", "b") ~ paste0("**", .x, "**"),
.default = .x
)
) +
guides(fill = guide_legend(
nrow = 2, byrow = TRUE
)) +
theme(
legend.position = c(.9, .75),
legend.background = element_rect(fill = alpha("#e5e5e5", 0.60)),
#legend.text = ggtext::element_markdown(),
legend.key = element_rect(fill = "transparent")
)
<details>
<summary>英文:</summary>
If I understand you correctly then one approach to achieve your desired result would be to add some fake legend entries for which we make the legend keys "invisible" by removing the labels and setting the fill color to e.g. `"transparent"`.
As a first step this requires to convert `param` to a factor and adding the fake elements at the correct position. Additionally we have to set `drop=FALSE` for the fill scale so that the unused fake elements are actually displayed in the legend. Finally, bolding only some of the legend elements is the easiest task and could be achieved via `ggtext::element_markdown`.
Note: Depending on the `theme` setting the fill color to `"transparent"` is not sufficient to make the fake elements invisible, e.g. in case of the default `theme_grey` the keys have a grey background fill. Hence, I added `legend.key = element_rect(fill = "transparent")` to make the background fill transparent as well.
library(ggplot2)
library(scales)
library(dplyr)
DF$param <- factor(DF$param, c("a", "b", "spacer", "c", "d", "e"))
pal_fill <- scales::hue_pal()(5)
names(pal_fill) <- letters[1:5]
pal_fill <- c(pal_fill, spacer = "transparent")
ggplot(data = DF) +
geom_col(aes(y = val, fill = param, x = x),
position = position_dodge2(preserve = "single")
) +
scale_fill_manual(
values = pal_fill,
drop = FALSE,
labels = ~ dplyr::case_match(
.x, "spacer" ~ "", c("a", "b") ~ paste0("", .x, ""),
.default = .x)
) +
guides(fill = guide_legend(
nrow = 2, byrow = TRUE
)) +
theme(
legend.text = ggtext::element_markdown(),
legend.key = element_rect(fill = "transparent")
)
[![enter image description here][1]][1]
**EDIT** Have to admit that I don't know exactly what's the issue but a fix would be to set `alpha` for the "spacer" to zero for which I use `after_scale` and an `if_else` in `geom_col`:
ggplot(data = DF) +
geom_col(
aes(
y = val, fill = param, x = x,
alpha = after_scale(if_else(fill != "transparent", .6, 0))
),
position = position_dodge2(preserve = "single")
) +
scale_fill_manual(
values = pal_fill,
drop = FALSE,
labels = ~ dplyr::case_match(
.x, "spacer" ~ "", c("a", "b") ~ paste0("", .x, ""),
.default = .x
)
) +
guides(fill = guide_legend(
nrow = 2, byrow = TRUE
)) +
theme(
legend.position = c(.9, .75),
legend.background = element_rect(fill = alpha("#e5e5e5", 0.60)),
#legend.text = ggtext::element_markdown(),
legend.key = element_rect(fill = "transparent")
)
[![enter image description here][2]][2]
[1]: https://i.stack.imgur.com/pO7cO.png
[2]: https://i.stack.imgur.com/F4lms.png
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论