The current labeling is because the alphabetic ordering of 9:12
is c("10", "11", "12", "9")
. You can change it manually, or you can use something like mixedsort
from gtools
to do it, here using dplyr
and magrittr
instead of data.table
:
dt %<>%
mutate(Label = paste0(dt$ID, " (", dt$Region, ")") %>%
factor(levels = mixedsort(unique(.))))
Changing the labels in the legend is a bit harder, primarily because they have two characters (instead of just one). If your labels were all a single character, you could just do something like this:
ggplot(data=dt,aes(x=Year,y=Value,group=ID,colour=Label)) +
geom_line(show.legend = FALSE) +
geom_point() +
geom_label(aes(label=ID), show.legend = FALSE) +
guides(color = guide_legend(override.aes = list(shape = c("A","B","C","D")
, size = 3)))

However, you cannot (to my knowledge) use multiple characters in a shape. So, I resort to my common fall back: generating the complicated legend that I want as a separate plot and stitching them together with cowplot
.
First, store the plot you want to make without a legend
plotPart <-
ggplot(data=dt,aes(x=Year,y=Value,group=ID,colour=Label)) +
geom_line() +
geom_label(aes(label=ID)) +
theme(legend.position = "none")
Then, modify the original data to limit down to just one entry per region with the regions as factors in the same order as the labels are (here, using dplyr
but you could modify to use data.table
instead). Pass that in to ggplot
and generate the layout you want. I have the regions on the left still, but you could move them to the right with scale_y_discrete(position = "right")
.
legendPart <-
dt %>%
select(ID, Region, Label) %>%
filter(!duplicated(.)) %>%
arrange(desc(ID)) %>%
mutate(Region = factor(Region, levels = Region)) %>%
ggplot(
aes(x = 1
, y = Region
, color = Label
, label = ID)) +
geom_label() +
theme(legend.position = "none"
, axis.title = element_blank()
, axis.text.x = element_blank()
, axis.ticks.x = element_blank()
, panel.grid = element_blank()
)
Then, load cowplot
. Note that it resets the default theme
so you need to manually over ride it (unless you like the cowplot
theme) with theme_set
:
library(cowplot)
theme_set(theme_minimal())
Then, use plot_grid
to stitch everything together. The simplest version has no arguments, but doesn't look great:
plot_grid(plotPart, legendPart)
gives

But, we can control the spacing with rel_widths
(you will need to play with it to fit your actual data and aspect ratio):
plot_grid(plotPart
, legendPart
, rel_widths = c(0.9, 0.2)
)
gives

I personally like to "squish" the legend a bit, so I usually nest the legend within another plot_grid
call, here including a title for good measure:
plot_grid(
plotPart
, plot_grid(
ggdraw()
, ggdraw() + draw_label("Legend")
, legendPart
, ggdraw()
, rel_heights = c(1,1,3,2)
, ncol = 1
)
, rel_widths = c(0.9, 0.2)
)
gives

Which I believe meets the requirements from your question, though you will still likely want to tweak it to match your prefered style, etc.