Spaces:
Sleeping
Sleeping
File size: 9,206 Bytes
b0c7d17 0fb1235 b0c7d17 0fb1235 b0c7d17 0fb1235 b0c7d17 0fb1235 b0c7d17 0fb1235 b0c7d17 0fb1235 b0c7d17 0fb1235 b0c7d17 97aadea b0c7d17 0fb1235 b0c7d17 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
def calculate_metrics(a, b, c, d, price_control=None):
"""
Calculates equilibrium, consumer surplus, producer surplus, and deadweight loss.
Args:
a (float): Y-intercept of the supply curve (P = a + bQ).
b (float): Slope of the supply curve.
c (float): Y-intercept of the demand curve (P = c - dQ).
d (float): Slope of the demand curve.
price_control (float, optional): An enforced price (floor or ceiling). Defaults to None.
Returns:
tuple: (Q_eq, P_eq, CS, PS, TS, DWL, Q_traded, price_control)
Returns (0, 0, 0, 0, 0, 0, 0, price_control) if parameters are invalid.
"""
# Ensure positive slopes for realistic curves
b = max(0.01, b) # Supply slope
d = max(0.01, d) # Demand slope
# Check for valid parameters that lead to an intersection with positive quantity
if (c - a) <= 0: # Demand intercept must be above supply intercept for Q_eq > 0
return 0, 0, 0, 0, 0, 0, 0, price_control
# 1. Equilibrium Calculation
Q_eq = (c - a) / (d + b)
P_eq = a + b * Q_eq
# Ensure valid equilibrium (positive quantity and price)
if Q_eq < 0.01 or P_eq < 0.01: # Check for near zero or negative values
return 0, 0, 0, 0, 0, 0, 0, price_control
# 2. Consumer Surplus (CS)
# Area of the triangle above equilibrium price and below demand curve
CS = 0.5 * Q_eq * (c - P_eq)
CS = max(0, CS) # Ensure non-negative
# 3. Producer Surplus (PS)
# Area of the triangle below equilibrium price and above supply curve
PS = 0.5 * Q_eq * (P_eq - a)
PS = max(0, PS) # Ensure non-negative
# 4. Total Surplus
TS = CS + PS
# 5. Deadweight Loss (DWL) and Quantity Traded under Price Control
DWL = 0
Q_traded = Q_eq # Initialize quantity traded to equilibrium quantity
if price_control is not None and price_control > 0: # If a price control is set
# Calculate quantity demanded and supplied at the controlled price
Q_demanded_at_pc = (c - price_control) / d
Q_supplied_at_pc = (price_control - a) / b
# The actual quantity traded is the minimum of Qd and Qs at the controlled price,
# ensuring it's non-negative (cannot trade negative quantity).
Q_traded = min(max(0, Q_demanded_at_pc), max(0, Q_supplied_at_pc))
# Calculate DWL if trade is restricted from equilibrium
if Q_traded < Q_eq:
# Price on the demand curve at the restricted quantity traded
P_demand_at_Q_traded = c - d * Q_traded
# Price on the supply curve at the restricted quantity traded
P_supply_at_Q_traded = a + b * Q_traded
# DWL is the area of the triangle between demand and supply curves
# from Q_traded to Q_eq. Height is the vertical distance between D & S at Q_traded.
DWL = 0.5 * (Q_eq - Q_traded) * (P_demand_at_Q_traded - P_supply_at_Q_traded)
DWL = max(0, DWL) # Ensure DWL is non-negative
return Q_eq, P_eq, CS, PS, TS, DWL, Q_traded, price_control
st.set_page_config(layout="wide", page_title="Supply & Demand Model")
st.title("๐ Econ 101: Supply and Demand Model")
st.sidebar.header("โ๏ธ Adjust Model Parameters")
# Sliders for demand curve: P = c - dQ
st.sidebar.subheader("Demand Curve: P = `c` - `d`Q")
c = st.sidebar.slider("c (Demand Intercept)", 10.0, 200.0, 100.0, 1.0, help="Maximum price consumers are willing to pay for 0 quantity.")
d = st.sidebar.slider("d (Demand Slope)", 0.1, 10.0, 2.0, 0.1, help="How much price decreases for each unit demanded.")
# Sliders for supply curve: P = a + bQ
st.sidebar.subheader("Supply Curve: P = `a` + `b`Q")
a = st.sidebar.slider("a (Supply Intercept)", 0.0, 100.0, 10.0, 1.0, help="Minimum price producers are willing to accept for 0 quantity.")
b = st.sidebar.slider("b (Supply Slope)", 0.1, 10.0, 1.0, 0.1, help="How much price increases for each unit supplied.")
# Price control slider
st.sidebar.subheader("Enforced Price (e.g., Price Floor/Ceiling)")
price_control = st.sidebar.slider("Set Enforced Price (0 for none)", 0.0, 200.0, 0.0, 0.5,
help="Set a price floor or ceiling. If 0, no price control is active.")
# Perform calculations
Q_eq, P_eq, CS, PS, TS, DWL, Q_traded, pc_used = calculate_metrics(a, b, c, d, price_control)
# Display results and plot
col1, col2 = st.columns([1, 2])
with col1:
st.header("๐ Economic Metrics")
if Q_eq == 0 and P_eq == 0 and CS == 0: # Indicates invalid parameters from calculate_metrics
st.error("Invalid parameters: Please adjust 'c' to be greater than 'a' to ensure a valid equilibrium.")
else:
st.metric("Equilibrium Quantity (Qe)", f"{Q_eq:.2f}")
st.metric("Equilibrium Price (Pe)", f"${P_eq:.2f}")
st.metric("Consumer Surplus (CS)", f"${CS:.2f}")
st.metric("Producer Surplus (PS)", f"${PS:.2f}")
st.metric("Total Surplus (TS)", f"${TS:.2f}")
if price_control > 0: # Only show these metrics if a price control is active
st.subheader("Metrics with Price Control")
st.metric("Enforced Price", f"${pc_used:.2f}")
st.metric("Quantity Traded (Q_traded)", f"{Q_traded:.2f}")
st.metric("Deadweight Loss (DWL)", f"${DWL:.2f}")
if DWL > 0:
st.warning("Deadweight Loss indicates market inefficiency due to the enforced price.")
else:
st.info("No Deadweight Loss with current enforced price (or price is ineffective).")
else:
st.info("Set 'Enforced Price' to calculate Deadweight Loss.")
with col2:
st.header("๐ Supply and Demand Graph")
fig, ax = plt.subplots(figsize=(12, 8))
# Determine appropriate x and y axis limits for plotting
max_Q_plot = max(Q_eq * 1.5, (c / d) * 1.1, 20) # Extends beyond equilibrium and demand intercept
max_P_plot = max(P_eq * 1.5, c * 1.1, 150) # Extends beyond equilibrium and demand intercept
Q_values = np.linspace(0, max_Q_plot, 400)
# Demand Curve: P = c - dQ
P_demand = c - d * Q_values
# Supply Curve: P = a + bQ
P_supply = a + b * Q_values
# Filter out negative prices/quantities for plotting realism
P_demand[P_demand < 0] = np.nan # Don't plot negative prices
P_supply[P_supply < 0] = np.nan # Don't plot negative prices
Q_values[Q_values < 0] = np.nan # Don't plot negative quantities
ax.plot(Q_values, P_demand, label=f'Demand: P = {c:.1f} - {d:.1f}Q', color='blue', linewidth=2)
ax.plot(Q_values, P_supply, label=f'Supply: P = {a:.1f} + {b:.1f}Q', color='red', linewidth=2)
# Plot Equilibrium Point and lines
if Q_eq > 0 and P_eq > 0:
ax.plot(Q_eq, P_eq, 'go', markersize=8, label=f'Equilibrium (Q={Q_eq:.2f}, P=${P_eq:.2f})')
ax.vlines(Q_eq, 0, P_eq, linestyle=':', color='gray', linewidth=1)
ax.hlines(P_eq, 0, Q_eq, linestyle=':', color='gray', linewidth=1)
# Consumer Surplus Area
Q_cs_plot = np.linspace(0, Q_eq, 100)
P_cs_plot = c - d * Q_cs_plot
ax.fill_between(Q_cs_plot, P_eq, P_cs_plot, where=P_cs_plot > P_eq, color='skyblue', alpha=0.3, label='Consumer Surplus')
# Producer Surplus Area
Q_ps_plot = np.linspace(0, Q_eq, 100)
P_ps_plot = a + b * Q_ps_plot
ax.fill_between(Q_ps_plot, P_ps_plot, P_eq, where=P_eq > P_ps_plot, color='lightcoral', alpha=0.3, label='Producer Surplus')
# Plot Price Control and Deadweight Loss
if price_control > 0 and Q_traded < Q_eq:
ax.hlines(pc_used, 0, Q_traded, linestyle='--', color='purple', label=f'Enforced Price (${pc_used:.2f})', linewidth=1.5)
ax.vlines(Q_traded, 0, pc_used, linestyle='--', color='purple', linewidth=1.5)
# Identify the points for the DWL triangle
# Price on demand curve at Q_traded
P_demand_at_Q_traded_plot = c - d * Q_traded
# Price on supply curve at Q_traded
P_supply_at_Q_traded_plot = a + b * Q_traded
# Shade DWL triangle
# The points for the DWL triangle are (Q_traded, P_supply_at_Q_traded), (Q_traded, P_demand_at_Q_traded), and (Q_eq, P_eq)
# Plotting the triangle as a fill_between area between Q_traded and Q_eq
Q_dwl_fill = np.linspace(Q_traded, Q_eq, 100)
P_demand_dwl_fill = c - d * Q_dwl_fill
P_supply_dwl_fill = a + b * Q_dwl_fill
ax.fill_between(Q_dwl_fill, P_supply_dwl_fill, P_demand_dwl_fill, color='red', alpha=0.5, label='Deadweight Loss')
# Mark points relevant to price control
# ax.plot(Q_traded, c - d * Q_traded, 'kx', markersize=8, label=f'Demand at PC ({Q_traded:.2f})')
# ax.plot(Q_traded, a + b * Q_traded, 'bx', markersize=8, label=f'Supply at PC ({Q_traded:.2f})')
ax.set_xlabel("Quantity (Q)", fontsize=12)
ax.set_ylabel("Price (P)", fontsize=12)
ax.set_title("Supply and Demand Equilibrium", fontsize=14)
ax.set_ylim(bottom=0, top=max_P_plot)
ax.set_xlim(left=0, right=max_Q_plot)
ax.legend(loc='upper right')
ax.grid(True, linestyle='--', alpha=0.7)
st.pyplot(fig)
|