A look at the auto sector, according to the Supplemental Estimates for Motor Vehicles from the U.S. Bureau of Economic Analysis.
import pandas as pd
import altair as alt
from io import BytesIO
from urllib.request import urlopen, Request
from urllib.error import HTTPError
uaString = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36'
try:
# Download from BEA (if available)
req = Request("https://apps.bea.gov/national/xls/gap_hist.xlsx", data=None, headers={ 'User-Agent': uaString })
data = urlopen(req)
except HTTPError:
# Fallback to IPFS archive (Nov 2021 data)
req = Request("https://cloudflare-ipfs.com/ipfs/QmQhaiTkWc6Akx2qZ6yC1qafYDEGkQDWVSp47zmwdYH6vE", data=None, headers={ 'User-Agent': uaString })
data = urlopen(req)
df_ts_raw = pd.read_excel(BytesIO(data.read()), engine='openpyxl', sheet_name=None) #[0].iloc[:-1]
clean = lambda s: str(s).replace(".", "").replace(" ", " ").replace("-", "")
def relabel(df):
tmp = df.copy()
tmp.columns = ['Month', 'Year'] + [clean(c) for c in df.iloc[2, :].values][2:]
tmp = tmp.iloc[4:]
tmp = tmp.dropna(how='all')
tmp = tmp.dropna(how='all', axis=1)
tmp[tmp.columns[2:]] = tmp[tmp.columns[2:]].applymap(pd.to_numeric)
tmp = tmp[tmp['Year'] != ' ']
tmp['dt'] = pd.to_datetime(tmp['Month'] + "-" + tmp['Year'].apply(int).apply(str), format="%B-%Y", errors='coerce')
return tmp.iloc[:, 2:]
def doChart(df, metric = 'US Production', title=None, color='blue'):
return alt.Chart(df).mark_line(color=color).encode(
alt.X('dt:T', axis=alt.Axis(title='')),
alt.Y(f'{metric}:Q')
).properties(
title=f'Historical {title} [{metric}]' if title else f'Historical {metric}',
width=750,
height=400,
background='white'
)
def doYoyChart(df, metric = 'US Production', title=None, color='teal'):
yoy = df[['dt', metric]].set_index('dt').dropna().pct_change(12).apply(lambda v: v * 100).reset_index()
return alt.Chart(yoy[yoy[metric] < 350]).mark_bar(width=1, color=color).encode(
alt.X('dt:T', axis=alt.Axis(title='')),
alt.Y(f'{metric}:Q', axis=alt.Axis(title='Year-over-year Growth [%]')),
color=alt.condition(f"datum['{metric}'] < 0",
alt.value('tomato'),
alt.value(color)
),
tooltip=[alt.Tooltip('dt:T', title='Date', format='%b %Y'), alt.Tooltip(f'{metric}:Q', title='YoY Change [%]', format=',.02f')]
).properties(
title=f'Change in {title} [{metric}]' if title else f'Change in {metric}',
width=750,
height=400,
background='white'
)
%%capture
df_domestic_autos = relabel(df_ts_raw['Table 1'])
#df_domestic_autos.tail()
doChart(df_domestic_autos, 'Not seasonally adjusted (Thousands)', 'Domestic Autos', 'navy')
doYoyChart(df_domestic_autos[-180:], 'Not seasonally adjusted (Thousands)', 'Domestic Auto Sales', color='indigo')
df_foreign_autos = relabel(df_ts_raw['Table 2'])
#df_foreign_autos.head()
doChart(df_foreign_autos, 'Not seasonally adjusted (Thousands)', 'Foreign Autos')
doYoyChart(df_foreign_autos, 'Not seasonally adjusted (Thousands)', 'Foreign Autos')
df_light_trucks = relabel(df_ts_raw['Table 3'])
#df_light_trucks.head()
doChart(df_light_trucks, 'Not seasonally adjusted (Thousands)', 'Light Trucks')
doYoyChart(df_light_trucks, 'Not seasonally adjusted (Thousands)', 'Light Trucks')
df_foreign_light_trucks = relabel(df_ts_raw['Table 4'])
#df_foreign_light_trucks.head()
doChart(df_foreign_light_trucks, 'Not seasonally adjusted (Thousands)', 'Foreign Light Trucks')
doYoyChart(df_foreign_light_trucks, 'Not seasonally adjusted (Thousands)', 'Foreign Light Trucks')
df_heavy_trucks = relabel(df_ts_raw['Table 5'])
#df_heavy_trucks.head()
doChart(df_heavy_trucks, 'Not seasonally adjusted (Thousands)', 'Heavy Trucks')
doYoyChart(df_heavy_trucks, 'Not seasonally adjusted (Thousands)', 'Heavy Trucks')
df_light_vehicle = relabel(df_ts_raw['Table 6'])
#df_light_vehicle.head()
doChart(df_light_vehicle, 'Autos not seasonally adjusted (Thousands)', 'Autos')
doYoyChart(df_light_vehicle, 'Autos not seasonally adjusted (Thousands)', 'Autos')
df_domestic_production = relabel(df_ts_raw['Table 7'])
#df_domestic_production.head()
doChart(df_domestic_production, 'Not seasonally adjusted (Thousands)', 'Domestic Production')
doYoyChart(df_domestic_production, 'Not seasonally adjusted (Thousands)', 'Domestic Production')
%%capture
na_imports = df_ts_raw['Table 8'] #.head(10)
na_imports = na_imports.dropna(how='all', axis=1)
cols = ["-".join(map(clean, c)) for c in zip(['Canada']*3 + ['Mexico']*3, list(na_imports.iloc[3, :].values)[2:])]
na_imports.columns = ['Month', 'Year'] + cols
na_imports = na_imports.iloc[5:]
na_imports = na_imports.dropna(how='all')
#print(na_imports.dtypes)
na_imports = na_imports.set_index(['Month', 'Year']).applymap(pd.to_numeric).reset_index()
na_imports = na_imports[na_imports['Year'] != ' ']
na_imports['dt'] = pd.to_datetime(na_imports['Month'] + "-" + na_imports['Year'].apply(int).apply(str), format="%B-%Y", errors='coerce')
na_imports = na_imports.iloc[:, 2:]
na_imports = na_imports.groupby('dt').last().reset_index()
#na_imports.tail(40)
doChart(na_imports, 'Canada-Not seasonally adjusted (Thousands)', 'Canada Imports')
doChart(na_imports, 'Mexico-Not seasonally adjusted (Thousands)', 'Mexico Imports')
doYoyChart(na_imports, 'Canada-Not seasonally adjusted (Thousands)', 'Canada Imports')
doYoyChart(na_imports, 'Mexico-Not seasonally adjusted (Thousands)', 'Mexico Imports')
na_exports = df_ts_raw['Table 9'] #.head(10)
na_exports = na_exports.dropna(how='all', axis=1)
na_exports.columns = ['Month', 'Year'] + [clean(c) for c in na_exports.iloc[3, :].values][2:]
na_exports = na_exports.iloc[5:]
na_exports = na_exports.dropna(how='all')
na_exports[na_exports.columns[2:]] = na_exports[na_exports.columns[2:]].applymap(pd.to_numeric)
na_exports = na_exports[na_exports['Year'] != ' ']
na_exports['dt'] = pd.to_datetime(na_exports['Month'] + "-" + na_exports['Year'].apply(int).apply(str), format="%B-%Y", errors='coerce')
na_exports = na_exports.iloc[:, 2:]
#na_exports.head()
doChart(na_exports, 'Not seasonally adjusted (Thousands)', 'Exports')
doYoyChart(na_exports, 'Not seasonally adjusted (Thousands)', 'Exports')
df_domestic = df_ts_raw['Table 10'] #.head()
df_domestic = df_domestic.dropna(how='all', axis=1)
df_domestic.columns = ['Month', 'Year'] + [str(c).replace(".", "") for c in df_domestic.iloc[4, :].values][2:]
df_domestic = df_domestic.iloc[7:]
df_domestic = df_domestic.dropna(how='all')
df_domestic[df_domestic.columns[2:]] = df_domestic[df_domestic.columns[2:]].applymap(pd.to_numeric)
df_domestic = df_domestic[df_domestic['Year'] != ' ']
df_domestic['dt'] = pd.to_datetime(df_domestic['Month'] + "-" + df_domestic['Year'].apply(int).apply(str), format="%B-%Y", errors='coerce')
df_domestic = df_domestic.iloc[:, 2:]
#df_domestic.head()
doChart(df_domestic, 'US Production')
c = doYoyChart(df_domestic, 'US Production')
c.save('autos.png')
c.display()
doChart(df_domestic, 'Canadian Imports')
doYoyChart(df_domestic, 'Canadian Imports')
doChart(df_domestic, 'Mexican Imports')
doYoyChart(df_domestic, 'Mexican Imports')