As alluded to by Greg Snow, it is better to format your data to work for ggplot2 rather than trying to make ggplot2 work for your data. If you combine your V* data into a single column, then you only have to call each geom_*() once.
To do this, you can pivot your data to long form using tidyr::pivot_longer(). I have also created a named list for assigning colour values. Your example plot only has labels at the first and last value so I modified the filter() for geom_text_repel(), edit to suit.
If you are only intending to plot just the first and last value for each V*, it can be easier to use two geom_text_repel() calls to control each side independently. It also makes sense to convert your fy values to numeric. Currently 2021 is not showing which makes the plot 'lie' as years are actually continuous variables.
You will need to play around with the label placement parameters to get them to match your example plot.
library(tidyr)
library(dplyr)
library(ggplot2)
library(ggrepel)
# Map list of colours to columns
col_map <- c(
v1 = "blue",
v2 = "purple",
v3 = "darkgreen"
)
# Pivot to long form
toy_data <- toy_data %>%
pivot_longer(-c(fy, id))
head(toy_data)
# # A tibble: 6 ×ばつ 4
# fy id name value
# <chr> <dbl> <chr> <dbl>
# 1 2019 1 v1 0.0439
# 2 2019 1 v2 0.0411
# 3 2019 1 v3 0.424
# 4 2020 1 v1 0.0526
# 5 2020 1 v2 0.0741
# 6 2020 1 v3 0.402
# Convert fy to numeric
toy_data$fy <- as.numeric(toy_data$fy)
toy_data %>%
filter(id == 1) %>%
ggplot() +
geom_line(aes(fy, value, group = name, colour = name),
linewidth = 2) +
geom_point(aes(fy, value, group = name, colour = name),
size = 2,
shape = 21,
fill = "white") +
geom_text_repel(data = toy_data %>%
filter(row_number() == 1, .by = name),
aes(fy, value, group = name, colour = name,
label = paste0(as.character(round(value * 100, 2)), "%")),
nudge_x = -0.25,
direction = "both",
min.segment.length = Inf,
fontface = 'bold') +
geom_text_repel(data = toy_data %>%
filter(row_number() == n(), .by = name),
aes(fy, value, group = name, colour = name,
label = paste0(as.character(round(value * 100, 2)), "%")),
nudge_x = 0.25,
direction = "both",
min.segment.length = Inf,
fontface = 'bold') +
scale_colour_manual(name = "Values",
values = col_map) +
scale_x_continuous(expand = expansion(add = c(0.75, 0.75)),
breaks = 2019:2024) +
guides(colour = guide_legend(override.aes = list(label = "")))
- 8.4k
- 23
- 34
- 47