Даны эти два набора данных, 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")
)
В некоторых местах метки значений баров и линий перекрываются. Есть ли способ избежать этого автоматически?
Один обходной путь, который я могу придумать, - это добавить данные линии к данным столбца, а затем изобразить их как невидимые столбцы или такой же розовый цвет, как на вашем графике. Таким образом, вам понадобится только одна линия geom_text()
и вы сможете контролировать перекрытие. Также взгляните на geom_bartext()
в erocoar.github.io/ggpol и geom_bar_text()
в wilkox.org/ggfittext
Вот подход, заменяющий три слоя 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()
)
) +
Вот два подхода.
Во-первых, быстрым и грязным обходным путем было бы выравнивание по левому краю одного набора меток и выравнивание по правому краю другого. Здесь я добавил hjust = 1.1
к geom_text()
вызовам для столбцов и fontface = "bold", hjust = -0.1
к 2 вызовам geom_text()
для линий (украл идею @JonSpring о выделении жирным шрифтом меток линий). Весь остальной код остается без изменений.
Маркировка по-прежнему не совсем интуитивно понятна. Если вы действительно хотите отображать проценты как для строк, так и для столбцов, рассмотрите возможность добавления интерактивности. Например, вы можете отображать статические метки для линий и метки для сегмента полосы во всплывающих подсказках. Использование гграфа:
library(ggplot2)
library(ggtext)
library(ggiraph)
p <- ggplot(df_bars, aes(x = col1, y = Values)) +
geom_bar_interactive(
mapping = aes(
fill = Status,
tooltip = ifelse(Values >= 0.01, paste0(sprintf("%1.1f%%", 100 * Values)), ""),
data_id = paste(col1, Status)
),
position = "stack",
stat = "identity"
) +
# remove following geom_text() call
geom_line(
# rest of plot code as in OP
# ...
girafe(
ggobj = p,
options = list(opts_hover("filter:brightness(120%);"))
)
Скриншот при наведении курсора на зеленую часть панели "FFF"
:
Хорошо, выравнивание кажется мне очень интуитивным способом различить их.
Пакет
ggrepel
— мой выбор для автоматического разделения перекрывающихся меток.