From 5a5651057fd20de617275b05993d88d0b2dfd5dd Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Fri, 9 Oct 2026 12:16:39 +1100 Subject: [PATCH] [ak2, ak_aiyagari, two_computation] Add figure captions and lw=2 Give every code-generated figure in the main text a mystnb caption and name, and set lw=2 on line charts, per the figures page of the style guide. Figures inside exercises and solutions are left uncaptioned so the PDF build is unaffected. See #1080 Co-Authored-By: Claude Fable 5.1 --- lectures/ak2.md | 102 ++++++++++++++++++++++++++---------- lectures/ak_aiyagari.md | 76 +++++++++++++++++++++------ lectures/two_computation.md | 62 ++++++++++++++++++++-- 3 files changed, 192 insertions(+), 48 deletions(-) diff --git a/lectures/ak2.md b/lectures/ak2.md index fecdbde79..086055e74 100644 --- a/lectures/ak2.md +++ b/lectures/ak2.md @@ -681,7 +681,7 @@ class ClosedFormTrans: # quantities for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): ax = axs[i//3, i%3] - ax.plot(range(T+1), quant_seq[:T+1, i], label=name) + ax.plot(range(T+1), quant_seq[:T+1, i], label=name, lw=2) ax.hlines(init_ss[i], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -689,7 +689,7 @@ class ClosedFormTrans: # prices for i, name in enumerate(['W', 'r']): ax = axs[(i+4)//3, (i+4)%3] - ax.plot(range(T+1), price_seq[:T+1, i], label=name) + ax.plot(range(T+1), price_seq[:T+1, i], label=name, lw=2) ax.hlines(init_ss[i+4], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -697,7 +697,7 @@ class ClosedFormTrans: # policies for i, name in enumerate(['τ', 'D', 'G']): ax = axs[(i+6)//3, (i+6)%3] - ax.plot(range(T+1), policy_seq[:T+1, i], label=name) + ax.plot(range(T+1), policy_seq[:T+1, i], label=name, lw=2) ax.hlines(init_ss[i+6], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -756,6 +756,12 @@ Let's use the `simulate` method of `closed` to compute dynamic transitions. Note that we leave `τ_pol` as `None`, since the tax rates need to be determined to satisfy the government budget constraint. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Transition after a tax cut + name: ak2_exp1_tax_cut +--- quant_seq1, price_seq1, policy_seq1 = closed.simulate(T, init_ss, D_pol=D_seq, G_pol=G_seq) @@ -779,13 +785,19 @@ quant_seq2, price_seq2, policy_seq2 = closed.simulate(T, init_ss, ``` ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Tax cut transitions for two tax rates + name: ak2_exp1_two_rates +--- fig, axs = plt.subplots(3, 3, figsize=(14, 10)) # quantities for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): ax = axs[i//3, i%3] - ax.plot(range(T+1), quant_seq1[:T+1, i], label=f'{name}, 1/3') - ax.plot(range(T+1), quant_seq2[:T+1, i], label=f'{name}, 0.2') + ax.plot(range(T+1), quant_seq1[:T+1, i], label=f'{name}, 1/3', lw=2) + ax.plot(range(T+1), quant_seq2[:T+1, i], label=f'{name}, 0.2', lw=2) ax.hlines(init_ss[i], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -793,8 +805,8 @@ for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): # prices for i, name in enumerate(['W', 'r']): ax = axs[(i+4)//3, (i+4)%3] - ax.plot(range(T+1), price_seq1[:T+1, i], label=f'{name}, 1/3') - ax.plot(range(T+1), price_seq2[:T+1, i], label=f'{name}, 0.2') + ax.plot(range(T+1), price_seq1[:T+1, i], label=f'{name}, 1/3', lw=2) + ax.plot(range(T+1), price_seq2[:T+1, i], label=f'{name}, 0.2', lw=2) ax.hlines(init_ss[i+4], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -802,8 +814,8 @@ for i, name in enumerate(['W', 'r']): # policies for i, name in enumerate(['τ', 'D', 'G']): ax = axs[(i+6)//3, (i+6)%3] - ax.plot(range(T+1), policy_seq1[:T+1, i], label=f'{name}, 1/3') - ax.plot(range(T+1), policy_seq2[:T+1, i], label=f'{name}, 0.2') + ax.plot(range(T+1), policy_seq1[:T+1, i], label=f'{name}, 1/3', lw=2) + ax.plot(range(T+1), policy_seq2[:T+1, i], label=f'{name}, 0.2', lw=2) ax.hlines(init_ss[i+6], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -823,6 +835,12 @@ The government targets the same tax rate $\tau_t=\hat{\tau}$ and to accumulate To conduct this experiment, we pass `τ_seq` and `G_seq` as inputs and let `D_pol` be determined along the path by satisfying the government budget constraint. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Transition after a permanent expenditure cut + name: ak2_exp2_expenditure_cut +--- # government expenditure cut by a half G_seq = τ_hat * 0.5 * Y_hat * np.ones(T+1) @@ -844,7 +862,7 @@ mystnb: caption: Ratio of government assets to capital name: ak2_asset_capital_ratio --- -plt.plot(range(T+1), -closed.policy_seq[:-1, 1] / closed.quant_seq[:, 0]) +plt.plot(range(T+1), -closed.policy_seq[:-1, 1] / closed.quant_seq[:, 0], lw=2) plt.xlabel('t') plt.ylabel('-D/K') plt.show() @@ -878,6 +896,12 @@ But now the cut lasts for one period only: the government sets $G_0 = 0$ and ret From $t \geq 1$, government expenditures return to $\hat{G}$ and $\tau_t$ adjusts to maintain the asset level $-D_t = -D_1$. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Transition after a temporary expenditure cut + name: ak2_exp3_temporary_cut +--- # sequence of government purchase G_seq = τ_hat * Y_hat * np.ones(T+1) G_seq[0] = 0 @@ -1059,11 +1083,11 @@ class AK2(): if verbose: # plot current prices at ith iteration for i, name in enumerate(['W', 'r']): - axs[i].plot(range(T+1), price_seq[:T+1, i]) + axs[i].plot(range(T+1), price_seq[:T+1, i], lw=2) axs[i].set_title(name) axs[i].set_xlabel('t') axs[2].plot(range(T+1), policy_seq[:T+1, 0], - label=f'{i_iter}th iteration') + label=f'{i_iter}th iteration', lw=2) axs[2].legend(bbox_to_anchor=(1.05, 1), loc='upper left') axs[2].set_title('τ') axs[2].set_xlabel('t') @@ -1141,7 +1165,7 @@ class AK2(): # quantities for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): ax = axs[i//3, i%3] - ax.plot(range(T+1), quant_seq[:T+1, i], label=name) + ax.plot(range(T+1), quant_seq[:T+1, i], label=name, lw=2) ax.hlines(init_ss[i], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -1149,7 +1173,7 @@ class AK2(): # prices for i, name in enumerate(['W', 'r']): ax = axs[(i+4)//3, (i+4)%3] - ax.plot(range(T+1), price_seq[:T+1, i], label=name) + ax.plot(range(T+1), price_seq[:T+1, i], label=name, lw=2) ax.hlines(init_ss[i+4], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -1157,7 +1181,7 @@ class AK2(): # policies for i, name in enumerate(['τ', 'D', 'G']): ax = axs[(i+6)//3, (i+6)%3] - ax.plot(range(T+1), policy_seq[:T+1, i], label=name) + ax.plot(range(T+1), policy_seq[:T+1, i], label=name, lw=2) ax.hlines(init_ss[i+6], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -1186,6 +1210,12 @@ D_pol[1:] = D1 ``` ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Price iterations of the fixed point algorithm + name: ak2_fixed_point_iterations +--- quant_seq3, price_seq3, policy_seq3 = ak2.simulate(T, init_ss, δy_seq, δo_seq, D_pol=D_pol, G_pol=G_pol, @@ -1193,6 +1223,12 @@ quant_seq3, price_seq3, policy_seq3 = ak2.simulate(T, init_ss, ``` ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Tax cut transition computed with AK2 + name: ak2_exp1_ak2 +--- ak2.plot() ``` @@ -1215,13 +1251,19 @@ quant_seq4, price_seq4, policy_seq4 = ak2.simulate(T, init_ss, Note how "crowding out" has been mitigated. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Transitions with and without lump sum taxes + name: ak2_exp1_lump_sum +--- fig, axs = plt.subplots(3, 3, figsize=(14, 10)) # quantities for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): ax = axs[i//3, i%3] - ax.plot(range(T+1), quant_seq3[:T+1, i], label=rf'{name}, $\delta$s=0') - ax.plot(range(T+1), quant_seq4[:T+1, i], label=rf'{name}, $\delta$s=0.005') + ax.plot(range(T+1), quant_seq3[:T+1, i], label=rf'{name}, $\delta$s=0', lw=2) + ax.plot(range(T+1), quant_seq4[:T+1, i], label=rf'{name}, $\delta$s=0.005', lw=2) ax.hlines(init_ss[i], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -1229,8 +1271,8 @@ for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): # prices for i, name in enumerate(['W', 'r']): ax = axs[(i+4)//3, (i+4)%3] - ax.plot(range(T+1), price_seq3[:T+1, i], label=rf'{name}, $\delta$s=0') - ax.plot(range(T+1), price_seq4[:T+1, i], label=rf'{name}, $\delta$s=0.005') + ax.plot(range(T+1), price_seq3[:T+1, i], label=rf'{name}, $\delta$s=0', lw=2) + ax.plot(range(T+1), price_seq4[:T+1, i], label=rf'{name}, $\delta$s=0.005', lw=2) ax.hlines(init_ss[i+4], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -1238,8 +1280,8 @@ for i, name in enumerate(['W', 'r']): # policies for i, name in enumerate(['τ', 'D', 'G']): ax = axs[(i+6)//3, (i+6)%3] - ax.plot(range(T+1), policy_seq3[:T+1, i], label=rf'{name}, $\delta$s=0') - ax.plot(range(T+1), policy_seq4[:T+1, i], label=rf'{name}, $\delta$s=0.005') + ax.plot(range(T+1), policy_seq3[:T+1, i], label=rf'{name}, $\delta$s=0', lw=2) + ax.plot(range(T+1), policy_seq4[:T+1, i], label=rf'{name}, $\delta$s=0.005', lw=2) ax.hlines(init_ss[i+6], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -1281,13 +1323,19 @@ quant_seq5, price_seq5, policy_seq5 = ak2.simulate(T, init_ss, ``` ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Tax cut versus social security transfer + name: ak2_exp4_social_security +--- fig, axs = plt.subplots(3, 3, figsize=(14, 10)) # quantities for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): ax = axs[i//3, i%3] - ax.plot(range(T+1), quant_seq3[:T+1, i], label=f'{name}, tax cut') - ax.plot(range(T+1), quant_seq5[:T+1, i], label=f'{name}, transfer') + ax.plot(range(T+1), quant_seq3[:T+1, i], label=f'{name}, tax cut', lw=2) + ax.plot(range(T+1), quant_seq5[:T+1, i], label=f'{name}, transfer', lw=2) ax.hlines(init_ss[i], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -1295,8 +1343,8 @@ for i, name in enumerate(['K', 'Y', 'Cy', 'Co']): # prices for i, name in enumerate(['W', 'r']): ax = axs[(i+4)//3, (i+4)%3] - ax.plot(range(T+1), price_seq3[:T+1, i], label=f'{name}, tax cut') - ax.plot(range(T+1), price_seq5[:T+1, i], label=f'{name}, transfer') + ax.plot(range(T+1), price_seq3[:T+1, i], label=f'{name}, tax cut', lw=2) + ax.plot(range(T+1), price_seq5[:T+1, i], label=f'{name}, transfer', lw=2) ax.hlines(init_ss[i+4], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') @@ -1304,8 +1352,8 @@ for i, name in enumerate(['W', 'r']): # policies for i, name in enumerate(['τ', 'D', 'G']): ax = axs[(i+6)//3, (i+6)%3] - ax.plot(range(T+1), policy_seq3[:T+1, i], label=f'{name}, tax cut') - ax.plot(range(T+1), policy_seq5[:T+1, i], label=f'{name}, transfer') + ax.plot(range(T+1), policy_seq3[:T+1, i], label=f'{name}, tax cut', lw=2) + ax.plot(range(T+1), policy_seq5[:T+1, i], label=f'{name}, transfer', lw=2) ax.hlines(init_ss[i+6], 0, T+1, color='r', linestyle='--') ax.legend() ax.set_xlabel('t') diff --git a/lectures/ak_aiyagari.md b/lectures/ak_aiyagari.md index 8a120179c..eb62faff6 100644 --- a/lectures/ak_aiyagari.md +++ b/lectures/ak_aiyagari.md @@ -585,7 +585,7 @@ mystnb: name: ak_aiy_asset_dist --- for j in [0, 5, 20, 45, 49]: - plt.plot(hh.a_grid, jnp.sum(μ[j].reshape((hh.a_grid.size, hh.γ_grid.size)), axis=1), label=f'j={j}') + plt.plot(hh.a_grid, jnp.sum(μ[j].reshape((hh.a_grid.size, hh.γ_grid.size)), axis=1), label=f'j={j}', lw=2) plt.legend() plt.xlabel('a') @@ -629,19 +629,25 @@ distributions of assets at different ages. We'll plot some saving functions with the following Python code. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Optimal saving policies by age + name: ak_aiy_policy +--- σ_reshaped = σ.reshape(hh.j_grid.size, hh.a_grid.size, hh.γ_grid.size) j_labels = [f'j={j}' for j in [0, 5, 20, 45, 49]] fig, axs = plt.subplots(1, 2, figsize=(14, 5)) -axs[0].plot(hh.a_grid, hh.a_grid[σ_reshaped[[0, 5, 20, 45, 49], :, 0].T]) +axs[0].plot(hh.a_grid, hh.a_grid[σ_reshaped[[0, 5, 20, 45, 49], :, 0].T], lw=2) axs[0].plot(hh.a_grid, hh.a_grid, '--') axs[0].set_xlabel("$a_{j}$") axs[0].set_ylabel("$a^*_{j+1}$") axs[0].legend(j_labels+['45 degree line']) axs[0].set_title(r"Optimal saving policy, low $\gamma$") -axs[1].plot(hh.a_grid, hh.a_grid[σ_reshaped[[0, 5, 20, 45, 49], :, 1].T]) +axs[1].plot(hh.a_grid, hh.a_grid[σ_reshaped[[0, 5, 20, 45, 49], :, 1].T], lw=2) axs[1].plot(hh.a_grid, hh.a_grid, '--') axs[1].set_xlabel("$a_{j}$") axs[1].set_ylabel("$a^*_{j+1}$") @@ -1022,9 +1028,9 @@ def path_iteration(ss1, ss2, pol_target, household, firm, Q, tol=1e-4, if verbose: fig, axs = plt.subplots(1, 3, figsize=(14, 3)) - axs[0].plot(jnp.arange(T), r_seq) - axs[1].plot(jnp.arange(T), w_seq) - axs[2].plot(jnp.arange(T), τ_seq, label=f'iter {num_iter}') + axs[0].plot(jnp.arange(T), r_seq, lw=2) + axs[1].plot(jnp.arange(T), w_seq, lw=2) + axs[2].plot(jnp.arange(T), τ_seq, label=f'iter {num_iter}', lw=2) while (error > tol) and (num_iter < max_iter): # Repeat until finding the fixed point, or until max_iter @@ -1059,9 +1065,9 @@ def path_iteration(ss1, ss2, pol_target, household, firm, Q, tol=1e-4, num_iter += 1 if verbose: print(f"Iteration {num_iter:3d}: error = {error:.6e}") - axs[0].plot(jnp.arange(T), r_seq) - axs[1].plot(jnp.arange(T), w_seq) - axs[2].plot(jnp.arange(T), τ_seq, label=f'iter {num_iter}') + axs[0].plot(jnp.arange(T), r_seq, lw=2) + axs[1].plot(jnp.arange(T), w_seq, lw=2) + axs[2].plot(jnp.arange(T), τ_seq, label=f'iter {num_iter}', lw=2) r_seq = (r_seq + r_old) / 2 w_seq = (w_seq + w_old) / 2 @@ -1130,6 +1136,12 @@ We can use `path_iteration` to find equilibrium transition dynamics. Setting the key argument `verbose=True` tells the function `path_iteration` to display convergence information. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Price path iterations for an immediate tax cut + name: ak_aiy_exp1_iterations +--- paths = path_iteration(ss1, ss2, [D_seq, G_seq, δ_seq], hh, firm, Q, verbose=True) ``` @@ -1191,7 +1203,7 @@ for t in [1, 10, 20, 50, 149]: c_mean = (c * μ_seq[t]).sum(axis=1) - plt.plot(range(hh.j_grid.size), c_mean-c_mean0, label=f't={t}') + plt.plot(range(hh.j_grid.size), c_mean-c_mean0, label=f't={t}', lw=2) plt.legend() plt.xlabel(r'j') @@ -1244,15 +1256,21 @@ for t in range(T): ``` ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Transition after an immediate tax cut + name: ak_aiy_exp1_transition +--- fig, axs = plt.subplots(3, 3, figsize=(14, 10)) # Cy (j=0-24) -axs[0, 0].plot(Cy_seq) +axs[0, 0].plot(Cy_seq, lw=2) axs[0, 0].hlines(Cy_ss1, 0, T, color='r', linestyle='--') axs[0, 0].set_title('Cy (j < 25)') # Cy (j=25-49) -axs[0, 1].plot(Co_seq) +axs[0, 1].plot(Co_seq, lw=2) axs[0, 1].hlines(Co_ss1, 0, T, color='r', linestyle='--') axs[0, 1].set_title(r'Co (j $\geq$ 25)') @@ -1264,7 +1282,7 @@ for i in range(len(names)): row_i = i_axes // 3 col_i = i_axes % 3 - axs[row_i, col_i].plot(paths[i_var]) + axs[row_i, col_i].plot(paths[i_var], lw=2) axs[row_i, col_i].hlines(ss1[i_var], 0, T, color='r', linestyle='--') axs[row_i, col_i].set_title(names[i]) @@ -1295,6 +1313,12 @@ for t in range(T): ``` ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Consumption mean and variance over age and time + name: ak_aiy_exp1_surfaces +--- J_seq, T_range = np.meshgrid(np.arange(J), np.arange(T)) fig = plt.figure(figsize=[20, 20]) @@ -1346,6 +1370,12 @@ ss2 = find_ss(hh, firm, [D_seq[-1], G_seq[-1], δ_seq[-1]], Q) ``` ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Price path iterations for a preannounced tax cut + name: ak_aiy_exp2_iterations +--- paths = path_iteration(ss1, ss2, [D_seq, G_seq, δ_seq], hh, firm, Q, verbose=True) ``` @@ -1382,15 +1412,21 @@ Below we plot the transition paths of the economy. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Transition after a preannounced tax cut + name: ak_aiy_exp2_transition +--- fig, axs = plt.subplots(3, 3, figsize=(14, 10)) # Cy (j=0-24) -axs[0, 0].plot(Cy_seq) +axs[0, 0].plot(Cy_seq, lw=2) axs[0, 0].hlines(Cy_ss1, 0, T, color='r', linestyle='--') axs[0, 0].set_title('Cy (j < 25)') # Cy (j=25-49) -axs[0, 1].plot(Co_seq) +axs[0, 1].plot(Co_seq, lw=2) axs[0, 1].hlines(Co_ss1, 0, T, color='r', linestyle='--') axs[0, 1].set_title(r'Co (j $\geq$ 25)') @@ -1402,7 +1438,7 @@ for i in range(len(names)): row_i = i_axes // 3 col_i = i_axes % 3 - axs[row_i, col_i].plot(paths[i_var]) + axs[row_i, col_i].plot(paths[i_var], lw=2) axs[row_i, col_i].hlines(ss1[i_var], 0, T, color='r', linestyle='--') axs[row_i, col_i].set_title(names[i]) @@ -1434,7 +1470,7 @@ K_lo = min(float(K_path.min()), float(ss1[i_var])) K_hi = max(float(K_path.max()), float(ss1[i_var])) pad = 0.1 * (K_hi - K_lo) -plt.plot(K_path) +plt.plot(K_path, lw=2) plt.hlines(ss1[i_var], 0, 25, color='r', linestyle='--') plt.axvline(20, color='k', linestyle='--', linewidth=0.5) plt.text(17, K_lo - 0.5 * pad, r'tax cut') @@ -1477,6 +1513,12 @@ for t in range(T): ``` ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Consumption surfaces for the preannounced tax cut + name: ak_aiy_exp2_surfaces +--- J_seq, T_range = np.meshgrid(np.arange(J), np.arange(T)) fig = plt.figure(figsize=[20, 20]) diff --git a/lectures/two_computation.md b/lectures/two_computation.md index d9701bdc1..14e6347a1 100644 --- a/lectures/two_computation.md +++ b/lectures/two_computation.md @@ -642,11 +642,11 @@ mystnb: fig, axs = plt.subplots(1, 2, figsize=(10, 6)) -axs[0].plot(ε_arr) +axs[0].plot(ε_arr, lw=2) axs[0].set_title("Working efficiency") axs[0].set_xlabel("age") -axs[1].plot(α_arr) +axs[1].plot(α_arr, lw=2) axs[1].set_title("Survival probability") axs[1].set_xlabel("age") @@ -749,7 +749,7 @@ mystnb: name: two_comp_pop_dist --- fig, ax = plt.subplots() -ax.plot(hh.frac) +ax.plot(hh.frac, lw=2) ax.set_xlabel("age") ax.set_ylabel("population fraction") plt.show() @@ -1227,7 +1227,7 @@ for i, Gb in enumerate(Gb_arr): debt2gdp_arr[i] = ss.debt2gdp fig, ax = plt.subplots() -ax.plot(τl_arr, debt2gdp_arr) +ax.plot(τl_arr, debt2gdp_arr, lw=2) ax.hlines(ss0.debt2gdp, τl_arr.min(), np.maximum(τl_arr.max(), ss0.τ_l), linestyle='--', color='r') ax.scatter(ss0.τ_l, ss0.debt2gdp) @@ -2078,6 +2078,12 @@ exp1_exo = { The following figure shows how the buy-out reshapes initial asset holdings across cohorts. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Assets and compensation by age at the reform + name: two_comp_exp1_compensation +--- # Extract results _, μx_seq_bo, μc_seq_bo, k_seq_bo, Gb_seq_bo, _, _ = exp1_exo['results_buyout'] results_nb = exp1_exo['results_no_buyout'] @@ -2134,6 +2140,12 @@ The declining profile among retirees reflects the actuarial calculation: older r We now plot the aggregate transition paths for the labor tax, government debt, capital, and consumption under both schemes. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Experiment 1 paths with and without the buy-out + name: two_comp_exp1_paths +--- # hh, tech, ss0, ss1 already in scope -- just alias from dict for readability ss0_exp1 = exp1_exo['ss0'] ss1_exp1 = exp1_exo['ss1'] @@ -2205,6 +2217,12 @@ Both schemes converge to the same terminal steady state. We now examine consumption paths for cohorts at different ages when the reform occurs. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Cohort consumption paths in Experiment 1 + name: two_comp_exp1_cohorts +--- fig, axes = plt.subplots(2, 2, figsize=(14, 10)) selected_ages = [0, 20, 40, 60] # Cohorts at different ages at s=0 @@ -2542,6 +2560,12 @@ exp1_endo = { The following figure compares the transition paths under fixed and endogenous factor prices, showing how general equilibrium effects alter the tax, debt, interest rate, and wage paths. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Experiment 1 under fixed and endogenous prices + name: two_comp_exp1_prices +--- # Get endogenous price sequences price_seq_endo = exp1_endo['price_seq'] S_endo = price_seq_endo.shape[0] - 2 @@ -2785,6 +2809,12 @@ exp2_endo = { We now compare all four reform scenarios: the buy-out scheme and the government funding scheme, each under fixed and endogenous factor prices. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Comparison of the four reform scenarios + name: two_comp_four_scenarios +--- # Get debt sequences for all cases Gb_buyout_fixed = Gb_seq_bo Gb_buyout_endo = exp1_endo['Gb_seq'] @@ -3064,6 +3094,12 @@ Each surface shows the joint distribution across age ($t$) and calendar time ($s The mean asset surfaces display the hump-shaped life-cycle profile of asset holdings, with peak assets shifting as working generations increase their saving in response to the reform. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Mean assets by age and time + name: two_comp_surf_assets +--- plot_surface_grid( [μa_bf, μa_be, μa_af, μa_ae], case_names, 'Mean assets', @@ -3074,6 +3110,12 @@ plot_surface_grid( The asset variance surfaces show how cumulative income shocks cause dispersion to increase with age, with the transition potentially altering the rate of dispersion growth. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Asset dispersion by age and time + name: two_comp_surf_asset_sd +--- plot_surface_grid( [Va_bf, Va_be, Va_af, Va_ae], case_names, 'Std. dev. of assets', @@ -3085,6 +3127,12 @@ plot_surface_grid( The mean consumption surfaces reflect the optimal consumption path, which should be smooth across ages due to the permanent income hypothesis underlying the model. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Mean consumption by age and time + name: two_comp_surf_cons +--- plot_surface_grid( [μc_bf, μc_be, μc_af, μc_ae], case_names, 'Mean consumption', @@ -3098,6 +3146,12 @@ The consumption variance surfaces show how within-cohort consumption dispersion Note that consumption dispersion is not a by-product of certainty equivalence: with $\sigma = -0.05$ the decision rules themselves depend on the volatility of income, as {ref}`two_comp_ex2` confirms. ```{code-cell} ipython3 +--- +mystnb: + figure: + caption: Consumption dispersion by age and time + name: two_comp_surf_cons_sd +--- plot_surface_grid( [Vc_bf, Vc_be, Vc_af, Vc_ae], case_names, 'Std. dev. of consumption',