I guess my question is very simple for someone who knows ggplot very well but I spent a lot of time trying different ways. I want to draw a horizontal line that pass-through y axis to separate each band of the bars produced using geom_col. For example, I want to draw a horizontal line that separate bars of meat from maize. Here is my code, example data and the design of the figure I want to produce.
library(tidyverse)
library(ggplot2)
# sample data
Food = c("meat", "meat", "meat", "meat", "wheat","wheat","wheat", "wheat", "maize","maize","maize","maize")
Subgroup = c("Male", "Female", "Urban", "Rural", "Male", "Female", "Urban", "Rural", "Male", "Female","Urban", "Rural")
mean = c(8.66, 10.45, 9.88, 7.32, 21.04, 19.65, 20.26, 20.87, 51.06 , 44.51, 47.60, 48.40)
df <- data.frame(Food, Subgroup, mean)
#Color code
colorPanel = c('#083c5d','#2d004b','#106d8e','#7d103d')
# Plot
Plot_FBGDS <- ggplot(df, aes(x = Food, y = mean, fill = Subgroup))
geom_col(stat = "identity", position = position_dodge(-0.9), width = 0.82)
scale_y_continuous(breaks = c(0,20, 40, 60,80), expand = c(0,0),
limits = c(0,100),
labels = function(x) paste0(x, "%"))
coord_flip()
scale_fill_manual(values = colorPanel)
labs( x= " ",
y = " ")
CodePudding user response:
Try this, using geom_vline with manually specified xintercept.
# Plot
ggplot(df, aes(x = Food, y = mean, fill = Subgroup))
geom_col(stat = "identity", position = position_dodge(-0.9), width = 0.82)
scale_y_continuous(breaks = c(0,20, 40, 60,80), expand = c(0,0),
limits = c(0,100),
labels = function(x) paste0(x, "%"))
geom_vline(xintercept = c(0.5, 1.5, 2.5, 3.5))
coord_flip()
scale_fill_manual(values = colorPanel)
labs( x= " ",
y = " ")
Note that geom_vline typically produces a vertical line, but since you have coord_flip it becomes horizontal. Without the coord_flip, you would use geom_hline and set the yintercept parameter instead.
Also, if I may suggest an alternative way to visualize this using facet_wrap instead, I would say the option below looks a lot better and you can style the facets using the strip_ properties in plot_theme
# Plot
ggplot(df, aes(x = Subgroup, y = mean, fill = Subgroup))
geom_col(stat = "identity", position = position_dodge(-0.9), width = 0.82)
scale_y_continuous(breaks = c(0,20, 40, 60,80), expand = c(0,0),
limits = c(0,100),
labels = function(x) paste0(x, "%"))
coord_flip()
scale_fill_manual(values = colorPanel)
facet_wrap(~Food, ncol=1)
labs( x= " ",
y = " ")
theme(
legend.position = "none"
)
CodePudding user response:
Note that I had to include Subgroup as a column in the linesdata data frame. The way to avoid having to do this would be to specify the fill= aesthetic inside geom_col instead of globally... but it works this way too.
The reason why geom_hline and vline always clip
Interestingly, you'll note that even though yend=Inf, the line does not extend beyond the panel area in the positive direction! I had no idea this works this way, but It seems Inf is specially designed to clip to the panel area no matter what. I'm pretty sure that geom_vline() and geom_hline() are using values of Inf and -Inf under the hood. If I change the value to y=-Inf inside geom_segment() you can see it doesn't extend the same way as specifying a number:
ggplot(df, aes(x = Food, y = mean, fill = Subgroup))
geom_col(position = position_dodge(-0.9), width = 0.82)
scale_y_continuous(breaks = c(0,20, 40, 60,80), expand = c(0,0),
limits = c(0,100),
labels = function(x) paste0(x, "%"))
coord_flip(clip="off")
geom_segment(
data=linesdata, y=-Inf, yend=Inf,
aes(x=xvals, xend=xvals)
)
scale_fill_manual(values = colorPanel)
labs( x= " ",
y = " ")
The only problem here is that you have to play around a bit to find the right value for the starting y value via trial and error. I found -5 did the trick pretty well.


