Given are these two data sets, df_bars
and 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)
)
I create a stacked bar chart, which is OK so far. Here I also display the value labels.
In addition, there are two lines where the value labels are also displayed.
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")
)
In some places the value labels of the bars and the lines overlap. Is there a way to avoid this automatically?
Here are two approaches.
First, a quick and dirty workaround would be to left-align one set of labels and right-align the other. Here I added hjust = 1.1
to the geom_text()
call for the bars, and fontface = "bold", hjust = -0.1
to the 2 geom_text()
calls for the lines (stealing @JonSpring's idea of bolding the line labels). All other code is unchanged.
The labeling still isn't exactly intuitive. If you really want to show percentages for both the lines and bars, consider adding interactivity. For instance, you could show static labels for the lines, and labels for the bar segment in tooltips. Using ggiraph:
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%);"))
)
Screenshot of hovering over the green section of the "FFF"
bar: