import numpy as np
import os
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
from mpl_toolkits.mplot3d import Axes3D
import matplotlib
from ogcore.constants import (
VAR_LABELS,
ToGDP_LABELS,
DEFAULT_START_YEAR,
)
import ogcore.utils as utils
from ogcore.utils import Inequality
[docs]
def plot_aggregates(
base_tpi,
base_params,
reform_tpi=None,
reform_params=None,
var_list=["Y", "C", "K", "L"],
plot_type="pct_diff",
stationarized=True,
num_years_to_plot=50,
start_year=DEFAULT_START_YEAR,
forecast_data=None,
forecast_units=None,
vertical_line_years=None,
plot_title=None,
path=None,
):
"""
Create a plot of macro aggregates.
Args:
base_tpi (dictionary): TPI output from baseline run
base_params (OG-Core Specifications class): baseline parameters
object
reform_tpi (dictionary): TPI output from reform run
reform_params (OG-Core Specifications class): reform parameters
object
var_list (list): names of variable to plot
plot_type (string): type of plot, can be:
'pct_diff': plots percentage difference between baseline
and reform ((reform-base)/base)
'diff': plots difference between baseline and reform
(reform-base)
'levels': plot variables in model units
'forecast': plots variables in levels relative to baseline
economic forecast
stationarized (bool): whether used stationarized variables (False
only affects pct_diff right now)
num_years_to_plot (integer): number of years to include in plot
start_year (integer): year to start plot
forecast_data (array_like): baseline economic forecast series,
must have length = num_year_to_plot
forecast_units (str): units that baseline economic forecast is in
vertical_line_years (list): list of integers for years want
vertical lines at
plot_title (string): title for plot
path (string): path to save figure to
Returns:
fig (Matplotlib plot object): plot of macro aggregates
"""
assert isinstance(start_year, (int, np.integer))
assert isinstance(num_years_to_plot, int)
assert num_years_to_plot <= base_params.T
# Make sure both runs cover same time period
if reform_tpi:
assert base_params.start_year == reform_params.start_year
year_vec = np.arange(start_year, start_year + num_years_to_plot)
start_index = start_year - base_params.start_year
# Check that reform included if doing pct_diff or diff plot
if plot_type == "pct_diff" or plot_type == "diff":
assert reform_tpi is not None
fig1, ax1 = plt.subplots()
for i, v in enumerate(var_list):
assert (
v in VAR_LABELS.keys()
), "{} is not in the list of variable labels".format(v)
if plot_type == "pct_diff":
if v in ["r_gov", "r", "r_p"]:
# Compute just percentage point changes for rates
plot_var = reform_tpi[v] - base_tpi[v]
else:
if stationarized:
plot_var = (reform_tpi[v] - base_tpi[v]) / base_tpi[v]
else:
pct_changes = utils.pct_change_unstationarized(
base_tpi,
base_params,
reform_tpi,
reform_params,
output_vars=[v],
)
plot_var = pct_changes[v]
ylabel = r"Pct. change"
plt.plot(
year_vec,
plot_var[start_index : start_index + num_years_to_plot],
label=VAR_LABELS[v],
)
elif plot_type == "diff":
plot_var = reform_tpi[v] - base_tpi[v]
ylabel = r"Difference (Model Units)"
plt.plot(
year_vec,
plot_var[start_index : start_index + num_years_to_plot],
label=VAR_LABELS[v],
)
elif plot_type == "levels":
plt.plot(
year_vec,
base_tpi[v][start_index : start_index + num_years_to_plot],
label="Baseline " + VAR_LABELS[v],
)
if reform_tpi:
plt.plot(
year_vec,
reform_tpi[v][
start_index : start_index + num_years_to_plot
],
label="Reform " + VAR_LABELS[v],
)
ylabel = r"Model Units"
elif plot_type == "forecast":
# Need reform and baseline to ensure plot makes sense
assert reform_tpi is not None
# Plot forecast of baseline
plot_var_base = forecast_data
plt.plot(
year_vec, plot_var_base, label="Baseline " + VAR_LABELS[v]
)
# Plot change from baseline forecast
pct_change = ((reform_tpi[v] - base_tpi[v]) / base_tpi[v])[
start_index : start_index + num_years_to_plot
]
plot_var_reform = (1 + pct_change) * forecast_data
plt.plot(
year_vec, plot_var_reform, label="Reform " + VAR_LABELS[v]
)
# making units labels will not work if multiple variables
# and they are in different units
ylabel = forecast_units
else:
print("Please enter a valid plot type")
assert False
# vertical markers at certain years
if vertical_line_years:
for yr in vertical_line_years:
plt.axvline(x=yr, linewidth=0.5, linestyle="--", color="k")
plt.xlabel(r"Year $t$")
plt.ylabel(ylabel)
if plot_title:
plt.title(plot_title, fontsize=15)
ax1.set_yticks(ax1.get_yticks().tolist())
vals = ax1.get_yticks()
if plot_type == "pct_diff":
ax1.set_yticklabels(["{:,.2%}".format(x) for x in vals])
plt.xlim(
(
base_params.start_year - 1,
base_params.start_year + num_years_to_plot,
)
)
plt.legend(loc=9, bbox_to_anchor=(0.5, -0.15), ncol=2)
if path:
fig_path1 = os.path.join(path)
plt.savefig(fig_path1, bbox_inches="tight", dpi=300)
else:
return fig1
plt.close()
def plot_industry_aggregates(
base_tpi,
base_params,
reform_tpi=None,
reform_params=None,
var_list=["Y_vec"],
ind_names_list=None,
plot_type="pct_diff",
num_years_to_plot=50,
start_year=DEFAULT_START_YEAR,
forecast_data=None,
forecast_units=None,
vertical_line_years=None,
plot_title=None,
path=None,
):
"""
Create a plot of macro aggregates by industry.
Args:
base_tpi (dictionary): TPI output from baseline run
base_params (OG-Core Specifications class): baseline parameters
object
reform_tpi (dictionary): TPI output from reform run
reform_params (OG-Core Specifications class): reform parameters
object
var_list (list): names of variable to plot
plot_type (string): type of plot, can be:
'pct_diff': plots percentage difference between baseline
and reform ((reform-base)/base)
'diff': plots difference between baseline and reform
(reform-base)
'levels': plot variables in model units
'forecast': plots variables in levels relative to baseline
economic forecast
num_years_to_plot (integer): number of years to include in plot
start_year (integer): year to start plot
forecast_data (array_like): baseline economic forecast series,
must have length = num_year_to_plot
forecast_units (str): units that baseline economic forecast is in
vertical_line_years (list): list of integers for years want
vertical lines at
plot_title (string): title for plot
path (string): path to save figure to
Returns:
fig (Matplotlib plot object): plot of macro aggregates
"""
assert isinstance(start_year, (int, np.integer))
assert isinstance(num_years_to_plot, int)
assert num_years_to_plot <= base_params.T
dims = base_tpi[var_list[0]].shape[1]
if ind_names_list:
assert len(ind_names_list) == dims
else:
ind_names_list = [str(i) for i in range(dims)]
# Make sure both runs cover same time period
if reform_tpi:
assert base_params.start_year == reform_params.start_year
year_vec = np.arange(start_year, start_year + num_years_to_plot)
start_index = start_year - base_params.start_year
# Check that reform included if doing pct_diff or diff plot
if plot_type == "pct_diff" or plot_type == "diff":
assert reform_tpi is not None
fig1, ax1 = plt.subplots()
for i, v in enumerate(var_list):
assert (
v in VAR_LABELS.keys()
), "{} is not in the list of variable labels".format(v)
if len(var_list) == 1:
var_label = ""
else:
var_label = VAR_LABELS[v]
for m in range(dims):
if plot_type == "pct_diff":
plot_var = (
reform_tpi[v][:, m] - base_tpi[v][:, m]
) / base_tpi[v][:, m]
ylabel = r"Pct. change"
plt.plot(
year_vec,
plot_var[start_index : start_index + num_years_to_plot],
label=var_label + " " + ind_names_list[m],
)
elif plot_type == "diff":
plot_var = reform_tpi[v][:, m] - base_tpi[v][:, m]
ylabel = r"Difference (Model Units)"
plt.plot(
year_vec,
plot_var[start_index : start_index + num_years_to_plot],
label=var_label + " " + ind_names_list[m],
)
elif plot_type == "levels":
plt.plot(
year_vec,
base_tpi[v][
start_index : start_index + num_years_to_plot, m
],
label="Baseline " + var_label + " " + ind_names_list[m],
)
if reform_tpi:
plt.plot(
year_vec,
reform_tpi[v][
start_index : start_index + num_years_to_plot, m
],
label="Reform " + var_label + " " + ind_names_list[m],
)
ylabel = r"Model Units"
elif plot_type == "forecast":
# Need reform and baseline to ensure plot makes sense
assert reform_tpi is not None
# Plot forecast of baseline
plot_var_base = forecast_data
plt.plot(
year_vec,
plot_var_base,
label="Baseline " + var_label + " " + ind_names_list[m],
)
# Plot change from baseline forecast
pct_change = (
reform_tpi[v][
start_index : start_index + num_years_to_plot, m
]
- base_tpi[v][
start_index : start_index + num_years_to_plot, m
]
) / base_tpi[v][
start_index : start_index + num_years_to_plot, m
]
plot_var_reform = (1 + pct_change) * forecast_data
plt.plot(
year_vec,
plot_var_reform,
label="Reform " + var_label + " " + ind_names_list[m],
)
# making units labels will not work if multiple variables
# and they are in different units
ylabel = forecast_units
else:
print("Please enter a valid plot type")
assert False
# vertical markers at certain years
if vertical_line_years:
for yr in vertical_line_years:
plt.axvline(x=yr, linewidth=0.5, linestyle="--", color="k")
plt.xlabel(r"Year $t$")
plt.ylabel(ylabel)
if plot_title:
plt.title(plot_title, fontsize=15)
ax1.set_yticks(ax1.get_yticks().tolist())
vals = ax1.get_yticks()
if plot_type == "pct_diff":
ax1.set_yticklabels(["{:,.2%}".format(x) for x in vals])
plt.xlim(
(
base_params.start_year - 1,
base_params.start_year + num_years_to_plot,
)
)
plt.legend(loc=9, bbox_to_anchor=(0.5, -0.15), ncol=2)
if path:
fig_path1 = os.path.join(path)
plt.savefig(fig_path1, bbox_inches="tight", dpi=300)
else:
return fig1
plt.close()
def ss_3Dplot(
base_params,
base_ss,
reform_params=None,
reform_ss=None,
var="bssmat_splus1",
plot_type="levels",
plot_title=None,
path=None,
):
"""
Create a 3d plot of household decisions.
Args:
base_params (OG-Core Specifications class): baseline parameters object
base_ss (dictionary): SS output from baseline run
reform_params (OG-Core Specifications class): reform parameters object
reform_ss (dictionary): SS output from reform run
var (string): name of variable to plot
plot_type (string): type of plot, can be:
'pct_diff': plots percentage difference between baseline
and reform ((reform-base)/base)
'diff': plots difference between baseline and reform (reform-base)
'levels': plot variables in model units
plot_title (string): title for plot
path (string): path to save figure to
Returns:
fig (Matplotlib plot object): plot of household decisions
"""
if reform_params:
assert base_params.J == reform_params.J
assert base_params.starting_age == reform_params.starting_age
assert base_params.ending_age == reform_params.ending_age
assert base_params.S == reform_params.S
domain = np.linspace(
base_params.starting_age, base_params.ending_age, base_params.S
)
Jgrid = np.zeros(base_params.J)
for j in range(base_params.J):
Jgrid[j:] += base_params.lambdas[j]
if plot_type == "levels":
data = base_ss[var].T
elif plot_type == "diff":
data = (reform_ss[var] - base_ss[var]).T
elif plot_type == "pct_diff":
data = ((reform_ss[var] - base_ss[var]) / base_ss[var]).T
cmap1 = matplotlib.colormaps.get_cmap("jet")
X, Y = np.meshgrid(domain, Jgrid)
fig5, ax5 = plt.subplots(subplot_kw={"projection": "3d"})
ax5.set_xlabel(r"age-$s$")
ax5.set_ylabel(r"ability type-$j$")
ax5.set_zlabel(r"individual savings $\bar{b}_{j,s}$")
ax5.plot_surface(X, Y, data, rstride=1, cstride=1, cmap=cmap1)
if plot_title:
plt.title(plot_title)
if path:
plt.savefig(path, dpi=300)
else:
return plt
[docs]
def plot_gdp_ratio(
base_tpi,
base_params,
reform_tpi=None,
reform_params=None,
var_list=["D"],
plot_type="levels",
num_years_to_plot=50,
start_year=DEFAULT_START_YEAR,
vertical_line_years=None,
plot_title=None,
path=None,
):
"""
Create a plot of some variable to GDP.
Args:
base_tpi (dictionary): TPI output from baseline run
base_params (OG-Core Specifications class): baseline parameters object
reform_tpi (dictionary): TPI output from reform run
reform_params (OG-Core Specifications class): reform parameters object
p (OG-Core Specifications class): parameters object
var_list (list): names of variable to plot
plot_type (string): type of plot, can be:
'diff': plots difference between baseline and reform
(reform-base)
'levels': plot variables in model units
num_years_to_plot (integer): number of years to include in plot
start_year (integer): year to start plot
vertical_line_years (list): list of integers for years want
vertical lines at
plot_title (string): title for plot
path (string): path to save figure to
Returns:
fig (Matplotlib plot object): plot of ratio of a variable to GDP
"""
assert isinstance(start_year, (int, np.integer))
assert isinstance(num_years_to_plot, int)
assert num_years_to_plot <= base_params.T
if plot_type == "diff":
assert reform_tpi is not None
# Make sure both runs cover same time period
if reform_tpi:
assert base_params.start_year == reform_params.start_year
year_vec = np.arange(start_year, start_year + num_years_to_plot)
start_index = start_year - base_params.start_year
fig1, ax1 = plt.subplots()
for i, v in enumerate(var_list):
assert (
v in ToGDP_LABELS.keys()
), "{} is not in the list of variable labels".format(v)
if plot_type == "levels":
plot_var_base = (
base_tpi[v][: base_params.T] / base_tpi["Y"][: base_params.T]
)
if reform_tpi:
plot_var_reform = (
reform_tpi[v][: base_params.T]
/ reform_tpi["Y"][: base_params.T]
)
plt.plot(
year_vec,
plot_var_base[
start_index : start_index + num_years_to_plot
],
label="Baseline " + ToGDP_LABELS[v],
)
plt.plot(
year_vec,
plot_var_reform[
start_index : start_index + num_years_to_plot
],
label="Reform " + ToGDP_LABELS[v],
)
else:
plt.plot(
year_vec,
plot_var_base[
start_index : start_index + num_years_to_plot
],
label=ToGDP_LABELS[v],
)
else: # if plotting differences in ratios
var_base = (
base_tpi[v][: base_params.T] / base_tpi["Y"][: base_params.T]
)
var_reform = (
reform_tpi[v][: base_params.T]
/ reform_tpi["Y"][: base_params.T]
)
plot_var = var_reform - var_base
plt.plot(
year_vec,
plot_var[start_index : start_index + num_years_to_plot],
label=ToGDP_LABELS[v],
)
ylabel = r"Percent of GDP"
# vertical markers at certain years
if vertical_line_years:
for yr in vertical_line_years:
plt.axvline(x=yr, linewidth=0.5, linestyle="--", color="k")
plt.xlabel(r"Year $t$")
plt.ylabel(ylabel)
if plot_title:
plt.title(plot_title, fontsize=15)
ax1.set_yticks(ax1.get_yticks().tolist())
vals = ax1.get_yticks()
if plot_type == "levels":
ax1.set_yticklabels(["{:,.0%}".format(x) for x in vals])
else:
ax1.set_yticklabels(["{:,.2%}".format(x) for x in vals])
plt.xlim(
(
base_params.start_year - 1,
base_params.start_year + num_years_to_plot,
)
)
plt.legend(loc=9, bbox_to_anchor=(0.5, -0.15), ncol=2)
if path:
fig_path1 = os.path.join(path)
plt.savefig(fig_path1, bbox_inches="tight", dpi=300)
else:
return fig1
plt.close()
[docs]
def ability_bar(
base_tpi,
base_params,
reform_tpi,
reform_params,
var="n_mat",
num_years=5,
start_year=DEFAULT_START_YEAR,
plot_title=None,
path=None,
):
"""
Plots percentage changes from baseline by ability group for a
given variable.
Args:
base_tpi (dictionary): TPI output from baseline run
base_params (OG-Core Specifications class): baseline parameters
object
reform_tpi (dictionary): TPI output from reform run
reform_params (OG-Core Specifications class): reform parameters
object
var (string): name of variable to plot
num_year (integer): number of years to compute changes over
start_year (integer): year to start plot
plot_title (string): title for plot
path (string): path to save figure to
Returns:
fig (Matplotlib plot object): plot of results by ability type
"""
assert isinstance(start_year, (int, np.integer))
assert isinstance(num_years, (int, np.integer))
# Make sure both runs cover same time period
if reform_tpi:
assert base_params.start_year == reform_params.start_year
N = base_params.J
fig, ax = plt.subplots()
ind = np.arange(N) # the x locations for the groups
width = 0.2 # the width of the bars
start_index = start_year - base_params.start_year
omega_to_use = base_params.omega[: base_params.T, :].reshape(
base_params.T, base_params.S, 1
)
base_val = (
(base_tpi[var] * omega_to_use)[
start_index : start_index + num_years, :, :
]
.sum(1)
.sum(0)
)
reform_val = (
(reform_tpi[var] * omega_to_use)[
start_index : start_index + num_years, :, :
]
.sum(1)
.sum(0)
)
var_to_plot = (reform_val - base_val) / base_val
ax.bar(ind, var_to_plot * 100, width, bottom=0)
ax.set_xticks(ind + width / 4)
ax.set_xticklabels(list(lambda_labels(base_params.lambdas).values()))
plt.xticks(rotation=45)
plt.ylabel(r"Percentage Change in " + VAR_LABELS[var])
if plot_title:
plt.title(plot_title, fontsize=15)
if path:
fig_path1 = os.path.join(path)
plt.savefig(fig_path1, bbox_inches="tight", dpi=300)
else:
return fig
plt.close()
[docs]
def ability_bar_ss(
base_ss,
base_params,
reform_ss,
reform_params,
var="nssmat",
plot_title=None,
path=None,
):
"""
Plots percentage changes from baseline by ability group for a
given variable.
Args:
base_ss (dictionary): SS output from baseline run
base_params (OG-Core Specifications class): baseline parameters
object
reform_ss (dictionary): SS output from reform run
reform_params (OG-Core Specifications class): reform parameters
object
var (string): name of variable to plot
plot_title (string): title for plot
path (string): path to save figure to
Returns:
fig (Matplotlib plot object): plot of results by ability type
"""
N = base_params.J
fig, ax = plt.subplots()
ind = np.arange(N) # the x locations for the groups
width = 0.2 # the width of the bars
base_val = (
base_ss[var] * base_params.omega_SS.reshape(base_params.S, 1)
).sum(0)
reform_val = (
reform_ss[var] * reform_params.omega_SS.reshape(reform_params.S, 1)
).sum(0)
var_to_plot = (reform_val - base_val) / base_val
ax.bar(ind, var_to_plot * 100, width, bottom=0)
ax.set_xticks(ind + width / 4)
ax.set_xticklabels(list(lambda_labels(base_params.lambdas).values()))
plt.xticks(rotation=45)
plt.ylabel(r"Percentage Change in " + VAR_LABELS[var])
if plot_title:
plt.title(plot_title, fontsize=15)
# plt.legend(loc=9, bbox_to_anchor=(0.5, -0.15), ncol=2)
if path:
fig_path1 = os.path.join(path)
plt.savefig(fig_path1, bbox_inches="tight", dpi=300)
else:
return fig
plt.close()
[docs]
def tpi_profiles(
base_tpi,
base_params,
reform_tpi=None,
reform_params=None,
by_j=True,
var="n_mat",
num_years=5,
start_year=DEFAULT_START_YEAR,
plot_title=None,
path=None,
):
"""
Plot lifecycle profiles of given variable in the SS.
Args:
base_ss (dictionary): TPI output from baseline run
base_params (OG-Core Specifications class): baseline parameters
object
reform_ss (dictionary): TPI output from reform run
reform_params (OG-Core Specifications class): reform parameters
object
var (string): name of variable to plot
num_year (integer): number of years to compute changes over
start_year (integer): year to start plot
plot_title (string): title for plot
path (string): path to save figure to
Returns:
fig (Matplotlib plot object): plot of lifecycle profiles
"""
assert isinstance(start_year, (int, np.integer))
assert isinstance(num_years, (int, np.integer))
if reform_tpi:
assert base_params.start_year == reform_params.start_year
assert base_params.S == reform_params.S
assert base_params.starting_age == reform_params.starting_age
assert base_params.ending_age == reform_params.ending_age
age_vec = np.arange(
base_params.starting_age, base_params.starting_age + base_params.S
)
fig1, ax1 = plt.subplots()
start_idx = start_year - base_params.start_year
end_idx = start_idx + num_years
if by_j:
cm = plt.get_cmap("coolwarm")
ax1.set_prop_cycle(color=[cm(1.0 * i / 7) for i in range(7)])
for j in range(base_params.J):
plt.plot(
age_vec,
base_tpi[var][start_idx:end_idx, :, j].sum(axis=0) / num_years,
label="Baseline, j = " + str(j),
)
if reform_tpi:
plt.plot(
age_vec,
reform_tpi[var][start_idx:end_idx, :, j].sum(axis=0)
/ num_years,
label="Reform, j = " + str(j),
linestyle="--",
)
else:
base_var = (
base_tpi[var][start_idx:end_idx, :, :]
* base_params.lambdas.reshape(1, 1, base_params.J)
).sum(axis=2).sum(axis=0) / num_years
plt.plot(age_vec, base_var, label="Baseline")
if reform_tpi:
reform_var = (
reform_tpi[var][start_idx:end_idx, :, :]
* reform_params.lambdas.reshape(1, 1, base_params.J)
).sum(axis=2).sum(axis=0) / num_years
plt.plot(age_vec, reform_var, label="Reform", linestyle="--")
plt.xlabel(r"Age")
plt.ylabel(VAR_LABELS[var])
plt.legend(loc=9, bbox_to_anchor=(0.5, -0.15), ncol=2)
if plot_title:
plt.title(plot_title, fontsize=15)
if path:
fig_path1 = os.path.join(path)
plt.savefig(fig_path1, bbox_inches="tight", dpi=300)
else:
return fig1
plt.close()
[docs]
def ss_profiles(
base_ss,
base_params,
reform_ss=None,
reform_params=None,
by_j=True,
var="nssmat",
plot_data=None,
plot_title=None,
path=None,
):
"""
Plot lifecycle profiles of given variable in the SS.
Args:
base_ss (dictionary): SS output from baseline run
base_params (OG-Core Specifications class): baseline parameters
object
reform_ss (dictionary): SS output from reform run
reform_params (OG-Core Specifications class): reform parameters
object
var (string): name of variable to plot
plot_data (array_like): series of data to add to plot
plot_title (string): title for plot
path (string): path to save figure to
Returns:
fig (Matplotlib plot object): plot of lifecycle profiles
"""
if reform_ss:
assert base_params.S == reform_params.S
assert base_params.starting_age == reform_params.starting_age
assert base_params.ending_age == reform_params.ending_age
age_vec = np.arange(
base_params.starting_age, base_params.starting_age + base_params.S
)
fig1, ax1 = plt.subplots()
if by_j:
cm = plt.get_cmap("coolwarm")
ax1.set_prop_cycle(color=[cm(1.0 * i / 7) for i in range(7)])
for j in range(base_params.J):
plt.plot(
age_vec, base_ss[var][:, j], label="Baseline, j = " + str(j)
)
if reform_ss:
plt.plot(
age_vec,
reform_ss[var][:, j],
label="Reform, j = " + str(j),
linestyle="--",
)
else:
base_var = (
base_ss[var][:, :] * base_params.lambdas.reshape(1, base_params.J)
).sum(axis=1)
plt.plot(age_vec, base_var, label="Baseline")
if reform_ss:
reform_var = (
reform_ss[var][:, :]
* reform_params.lambdas.reshape(1, reform_params.J)
).sum(axis=1)
plt.plot(age_vec, reform_var, label="Reform", linestyle="--")
if plot_data is not None:
plt.plot(
age_vec, plot_data, linewidth=2.0, label="Data", linestyle=":"
)
plt.xlabel(r"Age")
plt.ylabel(VAR_LABELS[var])
plt.legend(loc=9, bbox_to_anchor=(0.5, -0.15), ncol=2)
if plot_title:
plt.title(plot_title, fontsize=15)
if path:
fig_path1 = os.path.join(path)
plt.savefig(fig_path1, bbox_inches="tight", dpi=300)
else:
return fig1
plt.close()
[docs]
def plot_all(base_output_path, reform_output_path, save_path):
"""
Function to plot all default output plots.
Args:
base_output_path (str): path to baseline results
reform_output_path (str): path to reform results
save_path (str): path to save plots to
Returns:
None: All output figures saved to disk.
"""
# Make directory in case it doesn't exist
utils.mkdirs(save_path)
# Read in data
# Read in TPI output and parameters
base_tpi = utils.safe_read_pickle(
os.path.join(base_output_path, "TPI", "TPI_vars.pkl")
)
base_ss = utils.safe_read_pickle(
os.path.join(base_output_path, "SS", "SS_vars.pkl")
)
base_params = utils.safe_read_pickle(
os.path.join(base_output_path, "model_params.pkl")
)
reform_tpi = utils.safe_read_pickle(
os.path.join(reform_output_path, "TPI", "TPI_vars.pkl")
)
reform_ss = utils.safe_read_pickle(
os.path.join(reform_output_path, "SS", "SS_vars.pkl")
)
reform_params = utils.safe_read_pickle(
os.path.join(reform_output_path, "model_params.pkl")
)
# Percentage changes in macro vars (Y, K, L, C)
plot_aggregates(
base_tpi,
base_params,
reform_tpi=reform_tpi,
reform_params=reform_params,
var_list=["Y", "K", "L", "C"],
plot_type="pct_diff",
num_years_to_plot=min(base_params.T, 150),
start_year=base_params.start_year,
vertical_line_years=[
base_params.start_year + base_params.tG1,
base_params.start_year + base_params.tG2,
],
plot_title="Percentage Changes in Macro Aggregates",
path=os.path.join(save_path, "MacroAgg_PctChange.png"),
)
# Percentage change in fiscal vars (D, G, TR, Rev)
plot_aggregates(
base_tpi,
base_params,
reform_tpi=reform_tpi,
reform_params=reform_params,
var_list=["D", "TR", "total_tax_revenue"],
plot_type="pct_diff",
num_years_to_plot=min(base_params.T, 150),
start_year=base_params.start_year,
vertical_line_years=[
base_params.start_year + base_params.tG1,
base_params.start_year + base_params.tG2,
],
plot_title="Percentage Changes in Fiscal Variables",
path=os.path.join(save_path, "Fiscal_PctChange.png"),
)
# r and w in baseline and reform -- vertical lines at tG1, tG2
plot_aggregates(
base_tpi,
base_params,
reform_tpi=reform_tpi,
reform_params=reform_params,
var_list=["r"],
plot_type="levels",
num_years_to_plot=min(base_params.T, 150),
start_year=base_params.start_year,
vertical_line_years=[
base_params.start_year + base_params.tG1,
base_params.start_year + base_params.tG2,
],
plot_title="Real Interest Rates Under Baseline and Reform",
path=os.path.join(save_path, "InterestRates.png"),
)
plot_aggregates(
base_tpi,
base_params,
reform_tpi=reform_tpi,
reform_params=reform_params,
var_list=["w"],
plot_type="levels",
num_years_to_plot=min(base_params.T, 150),
start_year=base_params.start_year,
vertical_line_years=[
base_params.start_year + base_params.tG1,
base_params.start_year + base_params.tG2,
],
plot_title="Wage Rates Under Baseline and Reform",
path=os.path.join(save_path, "WageRates.png"),
)
# Gov't spending toGDP in base and reform-- vertical lines at tG1, tG2
plot_gdp_ratio(
base_tpi,
base_params,
reform_tpi,
reform_params,
var_list=["G"],
num_years_to_plot=min(base_params.T, 150),
start_year=base_params.start_year,
vertical_line_years=[
base_params.start_year + base_params.tG1,
base_params.start_year + base_params.tG2,
],
plot_title="Gov't Spending-to-GDP",
path=os.path.join(save_path, "SpendGDPratio.png"),
)
# Debt-GDP in base and reform-- vertical lines at tG1, tG2
plot_gdp_ratio(
base_tpi,
base_params,
reform_tpi,
reform_params,
var_list=["D"],
num_years_to_plot=min(base_params.T, 150),
start_year=base_params.start_year,
vertical_line_years=[
base_params.start_year + base_params.tG1,
base_params.start_year + base_params.tG2,
],
plot_title="Debt-to-GDP",
path=os.path.join(save_path, "DebtGDPratio.png"),
)
# Tax revenue to GDP in base and reform-- vertical lines at tG1, tG2
plot_gdp_ratio(
base_tpi,
base_params,
reform_tpi,
reform_params,
var_list=["total_tax_revenue"],
num_years_to_plot=min(base_params.T, 150),
start_year=base_params.start_year,
vertical_line_years=[
base_params.start_year + base_params.tG1,
base_params.start_year + base_params.tG2,
],
plot_title="Tax Revenue to GDP",
path=os.path.join(save_path, "RevenueGDPratio.png"),
)
# Pct change in c, n, b, y, etr, mtrx, mtry by ability group over 10 years
var_list = [
"c_path",
"n_mat",
"bmat_splus1",
"etr_path",
"mtrx_path",
"mtry_path",
"y_before_tax_mat",
]
title_list = [
"consumption",
"labor supply",
"savings",
"effective tax rates",
"marginal tax rates on labor income",
"marginal tax rates on capital income",
"before tax income",
]
path_list = ["Cons", "Labor", "Save", "ETR", "MTRx", "MTRy", "Income"]
for i, v in enumerate(var_list):
ability_bar(
base_tpi,
base_params,
reform_tpi,
reform_params,
var=v,
num_years=10,
start_year=base_params.start_year,
plot_title="Percentage changes in " + title_list[i],
path=os.path.join(save_path, "PctChange_" + path_list[i] + ".png"),
)
# lifetime profiles, base vs reform, SS for c, n, b, y - not by j
var_list = [
"cssmat",
"nssmat",
"bssmat_splus1",
"etr_ss",
"mtrx_ss",
"mtry_ss",
]
for i, v in enumerate(var_list):
ss_profiles(
base_ss,
base_params,
reform_ss,
reform_params,
by_j=False,
var=v,
plot_title="Lifecycle Profile of " + title_list[i],
path=os.path.join(
save_path, "SSLifecycleProfile_" + path_list[i] + ".png"
),
)
# lifetime profiles, c, n , b, y by j, separately for base and reform
for i, v in enumerate(var_list):
ss_profiles(
base_ss,
base_params,
by_j=True,
var=v,
plot_title="Lifecycle Profile of " + title_list[i],
path=os.path.join(
save_path,
"SSLifecycleProfile_" + path_list[i] + "_Baseline.png",
),
)
ss_profiles(
reform_ss,
reform_params,
by_j=True,
var=v,
plot_title="Lifecycle Profile of " + title_list[i],
path=os.path.join(
save_path, "SSLifecycleProfile_" + path_list[i] + "_Reform.png"
),
)
def inequality_plot(
base_tpi,
base_params,
reform_tpi=None,
reform_params=None,
var="c_path",
ineq_measure="gini",
pctiles=None,
plot_type="levels",
num_years_to_plot=50,
start_year=DEFAULT_START_YEAR,
vertical_line_years=None,
plot_title=None,
path=None,
):
"""
Plot measures of inequality over the time path.
Args:
base_tpi (dictionary): TPI output from baseline run
base_params (OG-Core Specifications class): baseline parameters
object
reform_tpi (dictionary): TPI output from reform run
reform_params (OG-Core Specifications class): reform parameters
object
var(string): name of variable to plot
ineq_measure (string): inequality measure to plot, can be:
'gini': Gini coefficient
'var_of_logs': variance of logs
'pct_ratio': percentile ratio
'top_share': top share of total
pctiles (tuple or None): percentiles for percentile ratios
(numerator, denominator) or percentile for top share (not
required for Gini or var_of_logs)
plot_type (string): type of plot, can be:
'pct_diff': plots percentage difference between baselien
and reform ((reform-base)/base)
'diff': plots difference between baseline and reform
(reform-base)
'levels': plot variables in model units
num_years_to_plot (integer): number of years to include in plot
start_year (integer): year to start plot
vertical_line_years (list): list of integers for years want
vertical lines at
plot_title (string): title for plot
path (string): path to save figure to
Returns:
fig (Matplotlib plot object): plot of inequality measure
"""
assert isinstance(start_year, (int, np.integer))
assert isinstance(num_years_to_plot, int)
assert num_years_to_plot <= base_params.T
# Make sure both runs cover same time period
if reform_tpi:
assert base_params.start_year == reform_params.start_year
assert ineq_measure in ["gini", "var_of_logs", "pct_ratio", "top_share"]
if (ineq_measure == "pct_ratio") | (ineq_measure == "top_share"):
assert pctiles
year_vec = np.arange(start_year, start_year + num_years_to_plot)
# Check that reform included if doing pct_diff or diff plot
if plot_type == "pct_diff" or plot_type == "diff":
assert reform_tpi is not None
fig1, ax1 = plt.subplots()
base_values = np.zeros(num_years_to_plot)
for t in range(num_years_to_plot):
idx = (t + start_year) - base_params.start_year
ineq = Inequality(
base_tpi[var][idx, :, :],
base_params.omega[idx, :],
base_params.lambdas,
base_params.S,
base_params.J,
)
if ineq_measure == "gini":
base_values[t] = ineq.gini()
ylabel = r"Gini Coefficient"
elif ineq_measure == "var_of_logs":
base_values[t] = ineq.var_of_logs()
ylabel = r"var(ln(" + VAR_LABELS[var] + r"))"
elif ineq_measure == "pct_ratio":
base_values[t] = ineq.ratio_pct1_pct2(pctiles[0], pctiles[1])
ylabel = r"Ratio"
elif ineq_measure == "top_share":
base_values[t] = ineq.top_share(pctiles)
ylabel = r"Share of Total " + VAR_LABELS[var]
if reform_tpi:
reform_values = np.zeros_like(base_values)
for t in range(num_years_to_plot):
idx = (t + start_year) - base_params.start_year
ineq = Inequality(
reform_tpi[var][idx, :, :],
reform_params.omega[idx, :],
reform_params.lambdas,
reform_params.S,
reform_params.J,
)
if ineq_measure == "gini":
reform_values[t] = ineq.gini()
elif ineq_measure == "var_of_logs":
reform_values[t] = ineq.var_of_logs()
elif ineq_measure == "pct_ratio":
reform_values[t] = ineq.ratio_pct1_pct2(pctiles[0], pctiles[1])
elif ineq_measure == "top_share":
reform_values[t] = ineq.top_share(pctiles)
if plot_type == "pct_diff":
plot_var = (reform_values - base_values) / base_values
ylabel = r"Pct. change"
plt.plot(year_vec, plot_var)
elif plot_type == "diff":
plot_var = reform_values - base_values
ylabel = r"Difference"
plt.plot(year_vec, plot_var)
elif plot_type == "levels":
plt.plot(year_vec, base_values, label="Baseline")
if reform_tpi:
plt.plot(year_vec, reform_values, label="Reform")
# vertical markers at certain years
if vertical_line_years:
for yr in vertical_line_years:
plt.axvline(x=yr, linewidth=0.5, linestyle="--", color="k")
plt.xlabel(r"Year $t$")
plt.ylabel(ylabel)
if plot_title:
plt.title(plot_title, fontsize=15)
vals = ax1.get_yticks()
if plot_type == "pct_diff":
ticks_loc = ax1.get_yticks().tolist()
ax1.yaxis.set_major_locator(mticker.FixedLocator(ticks_loc))
ax1.set_yticklabels(["{:,.2%}".format(x) for x in ticks_loc])
plt.xlim(
(
base_params.start_year - 1,
base_params.start_year + num_years_to_plot,
)
)
if plot_type == "levels":
plt.legend(loc=9, bbox_to_anchor=(0.5, -0.15), ncol=2)
if path:
fig_path1 = os.path.join(path)
plt.savefig(fig_path1, bbox_inches="tight", dpi=300)
else:
return fig1
plt.close()
def lambda_labels(lambdas):
"""
Creates string labels of percentage groups for ability types given
any number of ability types.
Args:
lambdas (np.array): array of lambdas for each ability type
Returns:
labels (dict): dict of string labels for ability types
"""
lambdas_100 = [x * 100 for x in lambdas]
lambdas_cumsum = list(np.cumsum(lambdas_100))
lambdas_cumsum = [0.00] + lambdas_cumsum
lambda_dict = {}
rounded = [] # list of rounded values, strings
for i in range(len(lambdas_cumsum)):
# condition formatting to number of digits need, but not more than 2
if lambdas_cumsum[i] % 1 == 0:
round_i = f"{lambdas_cumsum[i]:.0f}"
elif lambdas_cumsum[i] % 0.1 == 0:
round_i = f"{lambdas_cumsum[i]:.1f}"
else:
round_i = f"{lambdas_cumsum[i]:.2f}"
rounded.append(round_i)
for i in range(1, len(lambdas_cumsum) - 1):
lambda_dict[i - 1] = rounded[i - 1] + "-" + rounded[i] + "%"
# and do rounding for the top
top_number = 100 - lambdas_cumsum[-2]
if top_number % 1 == 0:
top_number_str = f"{top_number:.0f}"
elif top_number % 0.1 == 0:
top_number_str = f"{top_number:.1f}"
else:
top_number_str = f"{top_number:.2f}"
lambda_dict[i] = "Top " + top_number_str + "%"
return lambda_dict