# Build data for elastic, inelastic, and perfectly inelastic
elast_data <- tibble(Q = seq(0, 100, 0.5)) %>%
mutate(
P_elastic = pmax(10 - 0.05 * Q, 0), # Flat: elastic
P_inelastic = pmax(10 - 0.5 * Q, 0), # Steep: inelastic
P_supply = 2 + 0.04 * Q
)
# Elastic panel
p_elastic <- ggplot(elast_data) +
geom_line(aes(x = Q, y = P_elastic), color = pal$teal, linewidth = 2) +
geom_line(aes(x = Q, y = P_supply), color = pal$green, linewidth = 1.2, alpha = 0.5) +
annotate("segment", x = 50, xend = 50, y = 0, yend = 7.5,
linetype = "dashed", color = pal$slate, alpha = 0.5) +
annotate("segment", x = 80, xend = 80, y = 0, yend = 6,
linetype = "dashed", color = pal$slate, alpha = 0.5) +
annotate("text", x = 65, y = 8.5, label = "Small ΔP",
fontface = "bold", size = 4, color = pal$coral) +
annotate("segment", x = 50, y = 7.5, xend = 80, yend = 6,
arrow = arrow(length = unit(0.3, "cm")),
color = pal$coral, linewidth = 1) +
annotate("text", x = 65, y = 1.5, label = "BIG ΔQ",
fontface = "bold", size = 4, color = pal$coral) +
annotate("text", x = 85, y = 3, label = "Demand\n(elastic)", fontface = "bold.italic",
size = 4, color = pal$teal) +
scale_x_continuous(limits = c(0, 100)) +
scale_y_continuous(limits = c(0, 11)) +
labs(title = "ELASTIC (Ed > 1)", subtitle = "Flat curve: small ΔP → big ΔQ",
x = "Q", y = "P ($)",
caption = "Examples: corn, tortilla chips, beef → chicken") +
theme_minimal(base_size = 13) +
theme(plot.title = element_text(face = "bold", color = pal$teal),
panel.grid.minor = element_blank())
# Inelastic panel
p_inelastic <- ggplot(elast_data %>% filter(Q <= 20)) +
geom_line(aes(x = Q, y = P_inelastic), color = pal$red, linewidth = 2) +
annotate("segment", x = 5, xend = 5, y = 0, yend = 7.5,
linetype = "dashed", color = pal$slate, alpha = 0.5) +
annotate("segment", x = 8, xend = 8, y = 0, yend = 6,
linetype = "dashed", color = pal$slate, alpha = 0.5) +
annotate("text", x = 3, y = 5, label = "BIG ΔP",
fontface = "bold", size = 4, color = pal$coral) +
annotate("segment", x = 5, y = 7.5, xend = 8, yend = 6,
arrow = arrow(length = unit(0.3, "cm")),
color = pal$coral, linewidth = 1) +
annotate("text", x = 6.5, y = 1.5, label = "small ΔQ",
fontface = "bold", size = 4, color = pal$coral) +
annotate("text", x = 15, y = 3, label = "Demand\n(inelastic)", fontface = "bold.italic",
size = 4, color = pal$red) +
scale_x_continuous(limits = c(0, 20)) +
scale_y_continuous(limits = c(0, 11)) +
labs(title = "INELASTIC (Ed < 1)", subtitle = "Steep curve: big ΔP → small ΔQ",
x = "Q", y = "P ($)",
caption = "Examples: coffee, heroin, tiger eyeballs") +
theme_minimal(base_size = 13) +
theme(plot.title = element_text(face = "bold", color = pal$red),
panel.grid.minor = element_blank())
# Perfectly inelastic panel
p_perfect <- ggplot() +
geom_vline(xintercept = 10, color = pal$purple, linewidth = 2.5) +
annotate("text", x = 10, y = 9.5, label = "Demand\n(perfectly\ninelastic)",
fontface = "bold.italic", size = 4, color = pal$purple) +
annotate("segment", x = 10, xend = 10, y = 3, yend = 7,
arrow = arrow(length = unit(0.3, "cm"), ends = "both"),
color = pal$coral, linewidth = 1) +
annotate("text", x = 7, y = 5, label = "ANY ΔP →\nZERO ΔQ",
fontface = "bold", size = 4, color = pal$coral) +
scale_x_continuous(limits = c(0, 20)) +
scale_y_continuous(limits = c(0, 11)) +
labs(title = "PERFECTLY INELASTIC (Ed = 0)", subtitle = "Vertical: price doesn't matter",
x = "Q", y = "P ($)",
caption = "Example: insulin (you'll die without it)") +
theme_minimal(base_size = 13) +
theme(plot.title = element_text(face = "bold", color = pal$purple),
panel.grid.minor = element_blank())
# Combine panels
library(patchwork)
p_elastic + p_inelastic + p_perfect +
plot_annotation(
title = "Elastic vs. Inelastic vs. Perfectly Inelastic Demand",
subtitle = "The shape of the demand curve tells you everything about how responsive consumers are to price changes",
caption = "Cowen & Tabarrok, Ch. 5 | Illustrative curves",
theme = theme(
plot.title = element_text(face = "bold", size = 16),
plot.subtitle = element_text(size = 12)
)
)