Instead of hard coding the start and end position of the segments, you can capture this data from the plot object. Here's an alternative in which you specify the names of x elements and bar elements between which lines should be drawn.
Assign the graph to a variable:
p <- ggplot() + geom_bar(data = Example, aes(x = X_Axis, y = Percent, fill = Stack_Group), stat = 'identity', width = 0.5)
Take data from the plot object ( ggplot_build ). Convert to data.table ( setDT ):
d <- ggplot_build(p)$data[[1]] setDT(d)
In the data of the plot object, the variables 'x' and 'group' are not indicated explicitly by their name, but as numbers. Since categorical variables are ordered lexicographically in ggplot , we can match numbers with their names by their rank inside each x:
d[ , r := rank(group), by = x] Example[ , x := .GRP, by = X_Axis] Example[ , r := rank(Stack_Group), by = x]
Join to add the names "X_Axis" and "Stack_Group" from the source data to build the data:
d <- d[Example[ , .(X_Axis, Stack_Group, x, r)], on = .(x, r)]
Specify the names of the categories x and bar elements between which the lines should be drawn:
x_start_nm <- "Count" x_end_nm <- "Dollars" e_start <- "A & B" e_upper <- "A Mixed dollars" e_lower <- "B Mixed Dollars"
Select the appropriate parts of the plot object to create the start / end line data:
d2 <- data.table(x_start = rep(d[X_Axis == x_start_nm & Stack_Group == e_start, xmax], 2), y_start = d[X_Axis == x_start_nm & Stack_Group == e_start, c(ymax, ymin)], x_end = rep(d[X_Axis == x_end_nm & Stack_Group == e_upper, xmin], 2), y_end = c(d[X_Axis == x_end_nm & Stack_Group == e_upper, ymax], d[X_Axis == x_end_nm & Stack_Group == e_lower, ymin]))
Add line segments to the original chart:
p + geom_segment(data = d2, aes(x = x_start, xend = x_end, y = y_start, yend = y_end))
