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