I'm trying to overlay a barplot on top of an existing plot, by mapping the positions of the new barplot to the values of the original plot.
Example
Using the mpg dataset from the {ggplot2} package, I want to assess the relationship between the variables cty and manufacturer. To keep this simple, I'll focus on 3 manufacturers only.
Step 1 -- data for analysis
I'm going to add another column that categorizes the cty values into 3 categories "low", "medium", "high".
library(ggplot2)
library(dplyr)
my_manuf <- c("audi", "ford", "dodge")
my_df <-
mpg %>%
filter(manufacturer %in% my_manuf) %>%
select(manufacturer, cty) %>%
mutate(cty_range = case_when(between(cty, 9, 13) ~ "low",
between(cty, 13, 16) ~ "medium",
between(cty, 16, 21) ~ "high"))
my_df
#> # A tibble: 80 x 3
#> manufacturer cty cty_range
#> <chr> <int> <chr>
#> 1 audi 18 high
#> 2 audi 21 high
#> 3 audi 20 high
#> 4 audi 21 high
#> 5 audi 16 medium
#> 6 audi 18 high
#> 7 audi 18 high
#> 8 audi 18 high
#> 9 audi 16 medium
#> 10 audi 20 high
#> # ... with 70 more rows
Step 2 -- fit a (very) simple model
2.1) Going to fit the model lm(cty ~ manufacturer)
library(emmeans)
library(ggeffects)
model_results <-
my_df %>%
lm(cty ~ manufacturer, data = .) %>%
ggeffects::ggemmeans(terms = "manufacturer") %>%
as_tibble() %>%
rename(manufacturer = x)
model_results
#> # A tibble: 3 x 6
#> manufacturer predicted std.error conf.low conf.high group
#> <fct> <dbl> <dbl> <dbl> <dbl> <fct>
#> 1 audi 17.6 0.521 16.6 18.6 1
#> 2 dodge 13.1 0.364 12.4 13.9 1
#> 3 ford 14 0.442 13.1 14.9 1
2.2) Going to merge model_results with my_df to be able to add raw data points to the plot.
data_for_plot <- left_join(my_df, model_results)
Step 3 -- visualize
p <-
data_for_plot %>%
ggplot(aes(x = manufacturer, y = predicted)) +
geom_label(aes(label = round(predicted, 2))) +
geom_errorbar(aes(ymin = conf.low, ymax = conf.high), width = 0.2) +
geom_jitter(aes(x = manufacturer, y = predicted, color = cty_range)) +
expand_limits(y = c(12, 21)) +
theme_minimal()
p
Desired output
I want to add a barplot aligned to each manufacturer, to account for the proportion of the cty_range variable in each of its categories ("low"/"medium"/"high").
In my mind I imagine it as something like the following (not drawn to scale but values are real):
I know there are tools from packages such as patchwork and cowplot. However, here I want to map the barplots to the x-axis scale, such that the barplot relevant to audi will be positioned respectively, etc.
Second, I wish there's an easy way to achieve this by simply adding another "barplot prop" geom to the structure that constructs p. This is because p already originates from data_for_plot, which has all the info we need to compute the proportions for the barplots (i.e., via dplyr::count() or alike).



