# econographs

> Publication-quality economics diagrams in Python.  Install: `pip install econographs`

## Quick-start pattern

```python
# Always start scripts with:
import matplotlib
matplotlib.use("Agg")  # only needed in headless / server environments

from econographs import Linear, SupplyDemand, theme
theme.use("textbook")  # or "journal", "teaching"

# Option A — fluent builder (most flexible)
fig, ax = (
    SupplyDemand()
    .demand(Linear(10, -1), label="D")     # P = 10 - Q
    .supply(Linear(2, 0.5), label="S")     # P = 2 + 0.5Q
    .equilibrium()
    .surplus()
    .plot()
)
fig.savefig("market.png", bbox_inches="tight")

# Option B — one-liner
from econographs import supply_demand
fig, ax = supply_demand(Linear(10, -1), Linear(2, 0.5), surplus=True)

# Option C — constructor shorthand
fig, ax = SupplyDemand(demand=Linear(10, -1), supply=Linear(2, 0.5)).equilibrium().plot()
```

## Curves

Curves are inverse functions: vertical axis (P) as a function of horizontal axis (Q).

| Class | Signature | Meaning |
|-------|-----------|---------|
| `Linear(intercept, slope)` | `Linear(10, -1)` | P = 10 − Q |
| `Isoelastic(scale, exponent)` | `Isoelastic(12, -0.5)` | P = 12·Q^(−0.5) |
| `Quadratic(a, b, c)` | `Quadratic(0, 2, -0.1)` | P = 2Q − 0.1Q² |
| `Horizontal(y_value)` | `Horizontal(5)` | P = 5 |
| `Vertical(x_value)` | `Vertical(8)` | Q = 8 |
| `Custom(func)` | `Custom(lambda x: 10/x)` | any callable |

Curves also accept shorthand via `as_curve()`:
- Tuple: `(10, -1)` → `Linear(10, -1)`
- String: `"10 - Q"` → `Linear(10, -1)`

## SupplyDemand builder

```python
SupplyDemand(*, demand=None, supply=None, x_label="Q", y_label="P",
             title=None, theme=None, xlim=None, ylim=None)
```

Chainable methods (return self):
- `.demand(curve, label=None)` — add a demand curve
- `.supply(curve, label=None)` — add a supply curve
- `.equilibrium(show=True, drop_lines=True, marker=True, q_label="Q*", p_label="P*")`
- `.surplus(consumer=True, producer=True)` — shade CS and/or PS
- `.tax(amount, show_incidence=True, show_dwl=True, show_revenue=True)`
- `.subsidy(amount, show_dwl=True, show_outlay=True)`

Terminal methods:
- `.plot(ax=None, theme=None)` → `(Figure, Axes)`
- `.show()` → `(Figure, Axes)` — calls `plt.show()`
- `.save("path.png")` → `(Figure, Axes)` — calls `fig.savefig()`

## Shifts

Add a second demand or supply call; the library draws a shift arrow automatically.

```python
SupplyDemand()
    .demand(Linear(10, -1), label="D")
    .demand(Linear(13, -1), label="D′", linestyle="--")
    .supply(Linear(2, 0.5), label="S")
    .equilibrium()
    .plot()
```

## Tax example

```python
fig, ax = supply_demand(Linear(10, -1), Linear(2, 0.5), tax=2.0)
```

## All chart classes (zero-argument defaults work)

### Micro
- `supply_demand()` / `SupplyDemand` — market diagram
- `ppf()` / `PPF` — production possibility frontier
- `price_controls()` / `PriceControls(demand, supply, ceiling=..., floor=...)`
- `monopoly()` / `Monopoly` — monopoly with DWL
- `perfect_competition()` / `PerfectCompetition`
- `monopolistic_competition()` / `MonopolisticCompetition`
- `cournot()` / `Cournot` — reaction functions
- `externality()` / `Externality` — negative/positive externality with Pigou tax
- `public_goods()` / `PublicGoods`
- `labor_market()` / `LaborMarket`
- `budget_constraint()` / `BudgetConstraint`
- `optimal_choice()` / `OptimalChoice` — Cobb-Douglas tangency
- `indifference_map()` / `IndifferenceMap`
- `income_substitution()` / `IncomeSubstitution` — Hicksian decomposition
- `engel_curve()` / `EngelCurve`
- `production_function()` / `ProductionFunction`
- `cost_curves()` / `CostCurves`
- `long_run_atc()` / `LongRunATC`
- `isoquant_isocost()` / `IsoquantIsocost`
- `lorenz()` / `Lorenz` — Lorenz curve with Gini
- `edgeworth_box()` / `EdgeworthBox`
- `kinked_demand()` / `KinkedDemand`
- `price_discrimination()` / `PriceDiscrimination`
- `elasticity_comparison()` / `ElasticityComparison`
- `tariff_quota()` / `TariffQuota`
- `comparative_advantage()` / `ComparativeAdvantage`
- `circular_flow()` / `CircularFlow`

### Macro
- `adas()` / `ADAS` — aggregate demand / aggregate supply
- `keynesian_cross()` / `KeynesianCross`
- `consumption_function()` / `ConsumptionFunction`
- `is_lm()` / `ISLM`
- `mundell_fleming()` / `MundellFleming` — IS-LM-BP
- `phillips_curve()` / `PhillipsCurve`
- `money_market()` / `MoneyMarket`
- `loanable_funds()` / `LoanableFunds`
- `crowding_out()` / `CrowdingOut`
- `yield_curve()` / `YieldCurve`
- `laffer_curve()` / `LafferCurve`
- `solow()` / `Solow` — Solow growth model
- `aggregate_production()` / `AggregateProduction`
- `business_cycle()` / `BusinessCycle`
- `forex_market()` / `ForexMarket`

## Themes

Three built-in themes: `"textbook"` (default, serif, near-black), `"journal"` (compact, grayscale), `"teaching"` (colorful, sans-serif).

```python
from econographs import theme
theme.use("teaching")          # set process-wide default
# or per-chart:
SupplyDemand(theme="journal").demand(Linear(10, -1)).supply(Linear(2, 0.5)).plot()
```

## Geometry helpers

```python
from econographs import intersection, linear_surplus_areas, linear_tax_incidence

intersection(Linear(10, -1), Linear(2, 0.5))          # → (x, y) or None
linear_surplus_areas(10, -1, 2, 0.5)                   # → (CS, PS, Q*, P*, total)
linear_tax_incidence(10, -1, 2, 0.5, tax=2.0)          # → dict with prices, revenue, DWL
```

## Key rules

1. Every chart's `.plot()` returns `(matplotlib.figure.Figure, matplotlib.axes.Axes)`.
2. `.show()` and `.save("path.png")` are convenience wrappers around `.plot()`.
3. `Linear(intercept, slope)` — first arg is the y-intercept, second is slope.
4. All convenience functions (lowercase) call the class and return `.plot()`.
5. Pass `ax=` to `.plot()` to draw into an existing matplotlib Axes.
6. Requires: `numpy>=1.24`, `matplotlib>=3.7`, `scipy>=1.10`, Python ≥3.10.
