Chapter 2 - Production (Python Code)#

! pip install --upgrade quantecon_book_networks
Hide code cell output
Requirement already satisfied: quantecon_book_networks in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (1.1)
Requirement already satisfied: numpy in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (1.24.3)
Requirement already satisfied: scipy in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (1.11.1)
Requirement already satisfied: pandas in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (2.0.3)
Requirement already satisfied: matplotlib in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (3.7.2)
Requirement already satisfied: pandas-datareader in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (0.10.0)
Requirement already satisfied: networkx in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (3.1)
Requirement already satisfied: quantecon in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (0.7.1)
Requirement already satisfied: POT in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (0.9.3)
Requirement already satisfied: contourpy>=1.0.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (1.0.5)
Requirement already satisfied: cycler>=0.10 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (0.11.0)
Requirement already satisfied: fonttools>=4.22.0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (4.25.0)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (1.4.4)
Requirement already satisfied: packaging>=20.0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (23.1)
Requirement already satisfied: pillow>=6.2.0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (9.4.0)
Requirement already satisfied: pyparsing<3.1,>=2.3.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (3.0.9)
Requirement already satisfied: python-dateutil>=2.7 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (2.8.2)
Requirement already satisfied: pytz>=2020.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from pandas->quantecon_book_networks) (2023.3.post1)
Requirement already satisfied: tzdata>=2022.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from pandas->quantecon_book_networks) (2023.3)
Requirement already satisfied: lxml in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from pandas-datareader->quantecon_book_networks) (4.9.3)
Requirement already satisfied: requests>=2.19.0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from pandas-datareader->quantecon_book_networks) (2.31.0)
Requirement already satisfied: numba>=0.49.0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon->quantecon_book_networks) (0.57.1)
Requirement already satisfied: sympy in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon->quantecon_book_networks) (1.11.1)
Requirement already satisfied: llvmlite<0.41,>=0.40.0dev0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from numba>=0.49.0->quantecon->quantecon_book_networks) (0.40.0)
Requirement already satisfied: six>=1.5 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from python-dateutil>=2.7->matplotlib->quantecon_book_networks) (1.16.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from requests>=2.19.0->pandas-datareader->quantecon_book_networks) (2.0.4)
Requirement already satisfied: idna<4,>=2.5 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from requests>=2.19.0->pandas-datareader->quantecon_book_networks) (3.4)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from requests>=2.19.0->pandas-datareader->quantecon_book_networks) (1.26.16)
Requirement already satisfied: certifi>=2017.4.17 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from requests>=2.19.0->pandas-datareader->quantecon_book_networks) (2023.7.22)
Requirement already satisfied: mpmath>=0.19 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from sympy->quantecon->quantecon_book_networks) (1.3.0)

We begin with some imports.

import quantecon as qe
import quantecon_book_networks
import quantecon_book_networks.input_output as qbn_io
import quantecon_book_networks.plotting as qbn_plt
import quantecon_book_networks.data as qbn_data
ch2_data = qbn_data.production()
default_figsize = (6, 4)
export_figures = False
import numpy as np
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import matplotlib.colors as plc
from matplotlib import cm
quantecon_book_networks.config("matplotlib")

Multisector Models#

We start by loading a graph of linkages between 15 US sectors in 2021.

Our graph comes as a list of sector codes, an adjacency matrix of sales between the sectors, and a list the total sales of each sector.

In particular, Z[i,j] is the sales from industry i to industry j, and X[i] is the the total sales of each sector i.

codes = ch2_data["us_sectors_15"]["codes"]
Z = ch2_data["us_sectors_15"]["adjacency_matrix"]
X = ch2_data["us_sectors_15"]["total_industry_sales"]

Now we define a function to build coefficient matrices.

Two coefficient matrices are returned. The backward linkage case, where sales between sector i and j are given as a fraction of total sales of sector j. The forward linkage case, where sales between sector i and j are given as a fraction of total sales of sector i.

def build_coefficient_matrices(Z, X):
    """
    Build coefficient matrices A and F from Z and X via 
    
        A[i, j] = Z[i, j] / X[j] 
        F[i, j] = Z[i, j] / X[i]
    
    """
    A, F = np.empty_like(Z), np.empty_like(Z)
    n = A.shape[0]
    for i in range(n):
        for j in range(n):
            A[i, j] = Z[i, j] / X[j]
            F[i, j] = Z[i, j] / X[i]

    return A, F

A, F = build_coefficient_matrices(Z, X)

Backward linkages for 15 US sectors in 2021#

Here we calculate the hub-based eigenvector centrality of our backward linkage coefficient matrix.

centrality = qbn_io.eigenvector_centrality(A)

Now we use the quantecon_book_networks package to produce our plot.

fig, ax = plt.subplots(figsize=(8, 10))
plt.axis("off")
color_list = qbn_io.colorise_weights(centrality, beta=False)
# Remove self-loops
A1 = A.copy()
for i in range(A1.shape[0]):
    A1[i][i] = 0
qbn_plt.plot_graph(A1, X, ax, codes, 
              layout_type='spring',
              layout_seed=5432167,
              tol=0.0,
              node_color_list=color_list) 

if export_figures:
    plt.savefig("figures/input_output_analysis_15.pdf")
plt.show()
_images/0a1ee5bbea6781f1b566788931b056efd36dc0087fc2e7e2fd515f5cd2f663d0.png

Eigenvector centrality of across US industrial sectors#

Now we plot a bar chart of hub-based eigenvector centrality by sector.

fig, ax = plt.subplots(figsize=default_figsize)
ax.bar(codes, centrality, color=color_list, alpha=0.6)
ax.set_ylabel("eigenvector centrality", fontsize=12)
if export_figures:
    plt.savefig("figures/input_output_analysis_15_ec.pdf")
plt.show()
_images/0a55b41a380e4ad4de6fd6ac912ca930ed1c21876f6ca8ed7f048c28ed9e66fe.png

Output multipliers across 15 US industrial sectors#

Output multipliers are equal to the authority-based Katz centrality measure of the backward linkage coefficient matrix.

Here we calculate authority-based Katz centrality using the quantecon_book_networks package.

omult = qbn_io.katz_centrality(A, authority=True)
fig, ax = plt.subplots(figsize=default_figsize)
omult_color_list = qbn_io.colorise_weights(omult,beta=False)
ax.bar(codes, omult, color=omult_color_list, alpha=0.6)
ax.set_ylabel("Output multipliers", fontsize=12)
if export_figures:
    plt.savefig("figures/input_output_analysis_15_omult.pdf")
plt.show()
_images/adcfeca1e95d0386b9ce5041a7be7b4ee6ca17abd02e974f206c9238d3d7bc7c.png

Forward linkages and upstreamness over US industrial sectors#

Upstreamness is the hub-based Katz centrality of the forward linkage coefficient matrix.

Here we calculate hub-based Katz centrality.

upstreamness = qbn_io.katz_centrality(F)

Now we plot the network.

fig, ax = plt.subplots(figsize=(8, 10))
plt.axis("off")
upstreamness_color_list = qbn_io.colorise_weights(upstreamness,beta=False)
# Remove self-loops
for i in range(F.shape[0]):
    F[i][i] = 0
qbn_plt.plot_graph(F, X, ax, codes, 
              layout_type='spring', # alternative layouts: spring, circular, random, spiral
              layout_seed=5432167,
              tol=0.0,
              node_color_list=upstreamness_color_list) 

if export_figures:
    plt.savefig("figures/input_output_analysis_15_fwd.pdf")
plt.show()
_images/9774059369648abcf26aca1154e8436f8cf9421ca179d83c24955eb97d242048.png

Relative upstreamness of US industrial sectors#

Here we produce a barplot of upstreamness.

fig, ax = plt.subplots(figsize=default_figsize)
ax.bar(codes, upstreamness, color=upstreamness_color_list, alpha=0.6)
ax.set_ylabel("upstreamness", fontsize=12)
if export_figures:
    plt.savefig("figures/input_output_analysis_15_up.pdf")
plt.show()
_images/a97f15f5ea5e6f9e5cb41a65b2d93736df8c5653d7222e4f02e15ad9f979c3bb.png

Hub-based Katz centrality of across 15 US industrial sectors#

Next we plot the hub-based Katz centrality of the backward linkage coefficient matrix.

kcentral = qbn_io.katz_centrality(A)
fig, ax = plt.subplots(figsize=default_figsize)
kcentral_color_list = qbn_io.colorise_weights(kcentral,beta=False)
ax.bar(codes, kcentral, color=kcentral_color_list, alpha=0.6)
ax.set_ylabel("Katz hub centrality", fontsize=12)
if export_figures:
    plt.savefig("figures/input_output_analysis_15_katz.pdf")
plt.show()
_images/c2be7fb9a06530e63ff1772b7b0adda524bb6ea7cd486c12896d7a713d2a9e90.png

The Leontief inverse 𝐿 (hot colors are larger values)#

We construct the Leontief inverse matrix from 15 sector adjacency matrix.

I = np.identity(len(A))
L = np.linalg.inv(I - A)

Now we produce the plot.

fig, ax = plt.subplots(figsize=(6.5, 5.5))

ticks = range(len(L))

levels = np.sqrt(np.linspace(0, 0.75, 100))

co = ax.contourf(ticks, 
                    ticks,
                    L,
                    levels,
                    alpha=0.85, cmap=cm.plasma)

ax.set_xlabel('sector $j$', fontsize=12)
ax.set_ylabel('sector $i$', fontsize=12)
ax.set_yticks(ticks)
ax.set_yticklabels(codes)
ax.set_xticks(ticks)
ax.set_xticklabels(codes)

if export_figures:
    plt.savefig("figures/input_output_analysis_15_leo.pdf")
plt.show()
_images/9af04fc36d5c7e2d82040e9e1265110815c2d7692355e4e057b7d6ccfe126a4d.png

Propagation of demand shocks via backward linkages#

We begin by generating a demand shock vector \(d\).

N = len(A)
np.random.seed(1234)
d = np.random.rand(N) 
d[6] = 1  # positive shock to agriculture

Now we simulate the demand shock propagating through the economy.

sim_length = 11
x = d
x_vecs = []
for i in range(sim_length):
    if i % 2 ==0:
        x_vecs.append(x)
    x = A @ x

Finally, we plot the shock propagating through the economy.

fig, axes = plt.subplots(3, 2, figsize=(8, 10))
axes = axes.flatten()

for ax, x_vec, i in zip(axes, x_vecs, range(sim_length)):
    if i % 2 != 0:
        pass
    ax.set_title(f"round {i*2}")
    x_vec_cols = qbn_io.colorise_weights(x_vec,beta=False)
    # remove self-loops
    for i in range(len(A)):
        A[i][i] = 0
    qbn_plt.plot_graph(A, X, ax, codes,
                  layout_type='spring',
                  layout_seed=342156,
                  node_color_list=x_vec_cols,
                  node_size_multiple=0.00028,
                  edge_size_multiple=0.8)

plt.tight_layout()
if export_figures:
    plt.savefig("figures/input_output_analysis_15_shocks.pdf")
plt.show()
_images/192cf097a0f3ed40376b68f8a25973e006c475e6b6e61a6a2959a1ea07f1d490.png

Network for 71 US sectors in 2021#

We start by loading a graph of linkages between 71 US sectors in 2021.

codes_71 = ch2_data['us_sectors_71']['codes']
A_71 = ch2_data['us_sectors_71']['adjacency_matrix']
X_71 = ch2_data['us_sectors_71']['total_industry_sales']

Next we calculate our graph’s properties.

We use hub-based eigenvector centrality as our centrality measure for this plot.

centrality_71 = qbn_io.eigenvector_centrality(A_71)
color_list_71 = qbn_io.colorise_weights(centrality_71,beta=False)

Finally we produce the plot.

fig, ax = plt.subplots(figsize=(10, 12))
plt.axis("off")
# Remove self-loops
for i in range(A_71.shape[0]):
    A_71[i][i] = 0
qbn_plt.plot_graph(A_71, X_71, ax, codes_71,
              node_size_multiple=0.0005,
              edge_size_multiple=4.0,
              layout_type='spring',
              layout_seed=5432167,
              tol=0.01,
              node_color_list=color_list_71)

if export_figures:
    plt.savefig("figures/input_output_analysis_71.pdf")
plt.show()
_images/137265ebcd4eb657cd468ccc9ec591e6507d9c0499a16e456685813566d3eed8.png

Network for 114 Australian industry sectors in 2020#

Next we load a graph of linkages between 114 Australian sectors in 2020.

codes_114 = ch2_data['au_sectors_114']['codes']
A_114 = ch2_data['au_sectors_114']['adjacency_matrix']
X_114 = ch2_data['au_sectors_114']['total_industry_sales']

Next we calculate our graph’s properties.

We use hub-based eigenvector centrality as our centrality measure for this plot.

centrality_114 = qbn_io.eigenvector_centrality(A_114)
color_list_114 = qbn_io.colorise_weights(centrality_114,beta=False)

Finally we produce the plot.

fig, ax = plt.subplots(figsize=(11, 13.2))
plt.axis("off")
# Remove self-loops
for i in range(A_114.shape[0]):
    A_114[i][i] = 0
qbn_plt.plot_graph(A_114, X_114, ax, codes_114,
              node_size_multiple=0.008,
              edge_size_multiple=5.0,
              layout_type='spring',
              layout_seed=5432167,
              tol=0.03,
              node_color_list=color_list_114)

if export_figures:
    plt.savefig("figures/input_output_analysis_aus_114.pdf")
plt.show()
_images/e3b6e22c883c9a1e2a70ccf8025eea70c83b999edbcc1b3a59d30f665f6d33c6.png

GDP growth rates and std. deviations (in parentheses) for 8 countries#

Here we load a pandas DataFrame of GDP growth rates.

gdp_df = ch2_data['gdp_df']
gdp_df.head()
country Brazil United States United Kingdom France Japan Indonesia Argentina Mexico Australia South Africa
year
1961 8.6 2.3 2.677119 4.980112 12.043536 5.740646 5.427843 5.000000 2.482618 3.844734
1962 6.6 6.1 1.102910 6.843470 8.908973 1.841978 -0.852022 4.664415 1.294258 6.177931
1963 0.6 4.4 4.874384 6.233680 8.473642 -2.237030 -5.308197 8.106887 6.216364 7.373709
1964 3.4 5.8 5.533659 6.652100 11.676708 3.529698 10.130298 11.905481 6.980438 7.939609
1965 2.4 6.4 2.142177 4.861508 5.819708 1.081589 10.569433 7.100000 5.980351 6.122798

Now we plot the growth rates and calculate their standard deviations.

fig, axes = plt.subplots(5, 2, figsize=(8, 9))
axes = axes.flatten()

countries = gdp_df.columns
t = np.asarray(gdp_df.index.astype(float))
series = [np.asarray(gdp_df[country].astype(float)) for country in countries]


for ax, country, gdp_data in zip(axes, countries, series):
    
    ax.plot(t, gdp_data)
    ax.set_title(f'{country} (${gdp_data.std():1.2f}$\%)' )
    ax.set_ylabel('\%')
    ax.set_ylim((-12, 14))

plt.tight_layout()
if export_figures:
    plt.savefig("figures/gdp_growth.pdf")
plt.show()
_images/755088190c8746b8f6d0a2da91493984f6af705649c99b4b72ee19e2a83e1d21.png