# ── Negative Externality: MSC vs MPC diagram ──────────────────────────────────
# Illustrative linear supply/demand model
# Demand: P = 100 - 2Q
# MPC (private supply): P = 10 + 2Q
# MSC (social supply): P = 10 + 2Q + 20 = 30 + 2Q (constant MEC = $20/unit)
Q_vals <- seq(0, 50, by = 0.5)
demand <- 100 - 2 * Q_vals
mpc <- 10 + 2 * Q_vals
msc <- 30 + 2 * Q_vals # MEC = $20 per unit
# Market equilibrium (Demand = MPC): 100 - 2Q = 10 + 2Q → Q* = 22.5, P* = 55
Q_mkt <- 22.5; P_mkt <- 55
# Social optimum (Demand = MSC): 100 - 2Q = 30 + 2Q → Q** = 17.5, P** = 65
Q_soc <- 17.5; P_soc <- 65
df <- tibble(Q = Q_vals, Demand = demand, MPC = mpc, MSC = msc) %>%
filter(Demand >= 0, MPC >= 0)
# Deadweight loss polygon
dwl_poly <- tibble(
Q = c(Q_soc, Q_mkt, Q_mkt, Q_soc),
P = c(P_soc, P_mkt, 30 + 2 * Q_mkt, P_soc)
)
ggplot(df, aes(x = Q)) +
# Deadweight loss shading
geom_polygon(data = dwl_poly, aes(x = Q, y = P),
fill = pal$coral, alpha = 0.25) +
# Curves
geom_line(aes(y = Demand), color = pal$navy, linewidth = 1.5) +
geom_line(aes(y = MPC), color = pal$teal, linewidth = 1.5, linetype = "solid") +
geom_line(aes(y = MSC), color = pal$red, linewidth = 1.5, linetype = "dashed") +
# Market equilibrium point
geom_point(aes(x = Q_mkt, y = P_mkt), color = pal$teal, size = 4) +
annotate("text", x = Q_mkt + 1.5, y = P_mkt + 2,
label = sprintf("Market Eq.\nQ* = %.1f, P* = $%.0f", Q_mkt, P_mkt),
color = pal$teal, size = 3.5, hjust = 0) +
# Social optimum point
geom_point(aes(x = Q_soc, y = P_soc), color = pal$red, size = 4) +
annotate("text", x = Q_soc - 2, y = P_soc + 3,
label = sprintf("Social Optimum\nQ** = %.1f, P** = $%.0f", Q_soc, P_soc),
color = pal$red, size = 3.5, hjust = 1) +
# DWL label
annotate("text", x = 21, y = 53,
label = "DWL\n(overproduction)", color = pal$coral,
size = 3.5, fontface = "bold", hjust = 0.5) +
# MEC arrow
annotate("segment", x = 5, xend = 5, y = 10 + 2 * 5, yend = 30 + 2 * 5,
arrow = arrow(length = unit(0.2, "cm"), ends = "both"),
color = pal$orange, linewidth = 1) +
annotate("text", x = 7, y = 32,
label = "MEC = $20\n(external cost\nper unit)",
color = pal$orange, size = 3.2, hjust = 0) +
# Pigouvian tax arrow
annotate("segment", x = Q_soc, xend = Q_soc, y = 0, yend = P_soc,
linetype = "dotted", color = pal$purple, linewidth = 0.8) +
geom_segment(aes(x = 0, xend = Q_soc, y = P_soc, yend = P_soc),
linetype = "dotted", color = pal$purple, linewidth = 0.8) +
# Labels
annotate("text", x = 2, y = 97, label = "Demand (MSB)",
color = pal$navy, size = 4, fontface = "bold", hjust = 0) +
annotate("text", x = 30, y = mpc[Q_vals == 30] + 3,
label = "MPC (Private Supply)",
color = pal$teal, size = 3.8, fontface = "bold", hjust = 0) +
annotate("text", x = 25, y = msc[Q_vals == 25] + 3,
label = "MSC (Social Supply)",
color = pal$red, size = 3.8, fontface = "bold", hjust = 0) +
scale_y_continuous(labels = dollar_format(prefix = "$"), limits = c(0, 105)) +
scale_x_continuous(limits = c(0, 50)) +
labs(
title = "Negative Externality: Market Overproduction",
subtitle = "When private cost < social cost, markets produce too much — creating deadweight loss",
x = "Quantity (Q)",
y = "Price / Cost ($)",
caption = paste0(
"Illustrative model: Demand = 100 - 2Q | MPC = 10 + 2Q | MSC = 30 + 2Q (MEC = $20/unit)\n",
"Cowen & Tabarrok, Modern Principles: Microeconomics, 5th ed., Ch. 10 | ECON2120G-M02"
)
) +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(face = "bold", color = pal$navy),
plot.subtitle = element_text(color = pal$slate),
panel.grid.minor = element_blank()
)