Today, we will look at the GDP data that is released every quarter or so by the Bureau of Economic Analysis (BEA), and get familiar with the BEA API (see the documentation here). For a primer on GDP in general, BEA publishes this guide.
To access the BEA API, we will need two packages, httr and jsonlite.
library(tidyverse)
library(tidyquant)
library(httr)
library(jsonlite)
We also need to know the API address and parameters to get. This information can be found in the API documentation referenced above. We supply our API key, the name of the data set (NIPA), the table name (T10101, which holds GDP data), and a frequency (Q, for quarterly).
&quot;https://apps.bea.gov/api/data/?&amp;UserID=Your-API-Key Here&amp;method=GetData&amp;DataSetName=NIPA&amp;TableName=T10101&amp;Frequency=Q&amp;
Year=ALL&amp;ResultFormat=JSON&quot;
We will pass that URL to the fromJSON() function of the jsonlite package to access the API, and include simplifyDataFrame = FALSE and simplifyMatrix = FALSE to turn off some of the built-in data helpers.
key_string % rename(account = LineDescription, quarter = TimePeriod, percent_change = DataValue) %__% mutate(percent_change = as.numeric(percent_change),
quarter = yq(quarter))
bea_gdp_api is now a tibble that holds the quarterly percentage change for each of the GDP accounts used by the BEA, including total GDP change. Let’s take a closer look at each of the accounts whose data we have.
bea_gdp_api %__% count()
# A tibble: 21 x 2
# Groups: account [21]
account n
1 Durable goods 285
2 Equipment 285
3 Exports 285
4 Federal 285
5 Fixed investment 285
6 Goods 855
7 Government consumption expenditures and gross investment 285
8 Gross domestic product 285
9 Gross domestic product, current dollars 285
10 Gross private domestic investment 285
# ... with 11 more rows
We have 21 accounts or groups, including both Gross domestic product and Gross domestic product, current dollars. What are the other 19 groups? They are the sub-accounts that comprise GDP. Note that n = 855 for the Goods account and the Services account, but we have only 285 quarters of data. That’s because there are three accounts called Goods and Services (we’ll look at these three below).
We can look at the Goods accounts by SeriesCode.
bea_gdp_api %__% group_by(SeriesCode) %__% slice(1) %__% select(account, SeriesCode) %__% filter(account == &quot;Goods&quot;)
# A tibble: 3 x 2
# Groups: SeriesCode [3]
account SeriesCode
1 Goods A253RL 2 Goods A255RL 3 Goods DGDSRL This is why we grabbed the series codes, too. We need a way to figure out the true account for these three things labeled as Goods.
A web search reveals that A253RL is for Real Exports of Goods (a third-level account), A255RL is for Real Imports of Goods (a third-level account), and DGDSRL is a second-level account and the Goods component of Real Personal Consumption and Expenditure (PCE).
Let’s add better account/group names by with case_when().
bea_gdp_api %__% ungroup() %__% mutate(account = case_when(SeriesCode == &quot;A253RL&quot; ~ &quot;Export Goods&quot;,
SeriesCode == &quot;A255RL&quot; ~ &quot;Import Goods&quot;,
SeriesCode == &quot;DGDSRL&quot; ~ &quot;Goods&quot;,
TRUE ~ .$account)) %__% group_by(account) %__% count()
# A tibble: 23 x 2
# Groups: account [23]
account n
1 Durable goods 285
2 Equipment 285
3 Export Goods 285
4 Exports 285
5 Federal 285
6 Fixed investment 285
7 Goods 285
8 Government consumption expenditures and gross investment 285
9 Gross domestic product 285
10 Gross domestic product, current dollars 285
# ... with 13 more rows
We repeat that process for Services, which also had three accounts smooshed into one label.
bea_gdp_api %__% group_by(SeriesCode) %__% slice(1) %__% select(account, SeriesCode) %__% filter(account == &quot;Services&quot;)
# A tibble: 3 x 2
# Groups: SeriesCode [3]
account SeriesCode
1 Services A646RL 2 Services A656RL 3 Services DSERRL Similar to with goods, DSERRL is the services component of PCE and is a second-level account. A656RL is imports of services (a third-level account), and A646RL is exports of services.
Let’s make our changes to both goods and services in the data. I’m also going to replace a few other accounts with shorter names, e.g., I will use “Govt” for “Government consumption expenditures and gross investment”.
bea_gdp_wrangled % ungroup() %__% mutate(account = case_when(SeriesCode == &quot;A253RL&quot; ~ &quot;Export Goods&quot;,
SeriesCode == &quot;A255RL&quot; ~ &quot;Import Goods&quot;,
SeriesCode == &quot;DGDSRL&quot; ~ &quot;Goods&quot;,
SeriesCode == &quot;DSERRL&quot; ~ &quot;Services&quot;,
SeriesCode == &quot;A656RL&quot; ~ &quot;Import Services&quot;,
SeriesCode == &quot;A646RL&quot; ~ &quot;Export Services&quot;,
SeriesCode == &quot;A822RL&quot; ~ &quot;Govt&quot;,
SeriesCode == &quot;A006RL&quot; ~ &quot;Investment&quot;,
SeriesCode == &quot;DPCERL&quot; ~ &quot;PCE&quot;,
TRUE ~ .$account)) %__% group_by(account) %__% select(-SeriesCode)
bea_gdp_wrangled %__% count()
# A tibble: 25 x 2
# Groups: account [25]
account n
1 Durable goods 285
2 Equipment 285
3 Export Goods 285
4 Export Services 285
5 Exports 285
6 Federal 285
7 Fixed investment 285
8 Goods 285
9 Govt 285
10 Gross domestic product 285
# ... with 15 more rows
We now have 25 accounts, each with 285 observations.
Let’s move to some visualization and check out how GDP has changed on a quarterly basis since 2008.
bea_gdp_wrangled %__%
filter(quarter __ &quot;2008-01-01&quot;) %__% filter(account == &quot;Gross domestic product&quot;) %__% mutate(col_blue = if_else(percent_change __ 0, percent_change, as.numeric(NA)),
col_red = if_else(percent_change __ 0, percent_change, as.numeric(NA))) %__%
ggplot(aes(x = quarter)) +
geom_col(aes(y = col_red),
alpha = .85, fill = &quot;pink&quot;, color = &quot;pink&quot;) +
geom_col(aes(y = col_blue),
alpha = .85, fill = &quot;cornflowerblue&quot;, color = &quot;cornflowerblue&quot;) +
ylab(&quot;Quarterly Change (percent)&quot;) +
scale_x_date(breaks = scales::pretty_breaks(n = 20)) +
labs(title = &quot;Quarterly GDP Growth&quot;,
subtitle = &quot;since 2008&quot;,
x = &quot;&quot;,
caption = &quot;www.bea.gov/newsreleases/national/gdp/gdpnewsrelease.htm&quot;) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, hjust = 1),
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5),
plot.caption=element_text(hjust=0))
That’s a nice look at GDP quarterly change since 2008, but let’s go a bit deeper and visualize the four top-level components of GDP, which are personal consumption, net exports (or imports and exports), private investment, and government spending. Here is how each changed in Q2 2018.
bea_gdp_wrangled %__% filter((
account == &quot;PCE&quot; |
account == &quot;Investment&quot; |
account == &quot;Exports&quot; |
account == &quot;Imports&quot; |
account == &quot;Govt&quot;) &amp;
quarter == last(quarter)) %__% mutate(col_blue = if_else(percent_change __ 0, percent_change, as.numeric(NA)),
col_red = if_else(percent_change __ 0, percent_change, as.numeric(NA))) %__%
ggplot(aes(x = reorder(account, percent_change))) +
geom_col(aes(y = col_red),
alpha = .85, fill = &quot;pink&quot;, color = &quot;pink&quot;,
width = .5) +
geom_col(aes(y = col_blue),
alpha = .85, fill = &quot;cornflowerblue&quot;, color = &quot;cornflowerblue&quot;,
width = .5) +
labs(title = paste(last(bea_gdp_api$quarter), &quot;GDP Change&quot;, sep = &quot; &quot;),
subtitle = &quot;by account, and total&quot;, x = &quot;account&quot;, y = &quot;change last quarter&quot;) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, hjust = 1),
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5)) +
scale_y_continuous(breaks = scales::pretty_breaks(n = 10))
We can chart how each account has changed over time as well.
bea_gdp_wrangled %__%
filter(quarter __ &quot;2008-01-01&quot;) %__% filter(
account == &quot;PCE&quot; |
account == &quot;Investment&quot; |
account == &quot;Exports&quot; |
account == &quot;Imports&quot; |
account == &quot;Govt&quot;) %__% mutate(col_blue = if_else(percent_change __ 0, percent_change, as.numeric(NA)),
col_red = if_else(percent_change __ 0, percent_change, as.numeric(NA))) %__%
ggplot(aes(x = quarter)) +
geom_col(aes(y = col_red),
alpha = .85, fill = &quot;pink&quot;, color = &quot;pink&quot;) +
geom_col(aes(y = col_blue),
alpha = .85, fill = &quot;cornflowerblue&quot;, color = &quot;cornflowerblue&quot;) +
ylab(&quot;Quarterly Change (percent)&quot;) +
scale_x_date(breaks = scales::pretty_breaks(n = 5)) +
labs(title = &quot;Quarterly GDP Growth&quot;,
subtitle = &quot;since 2008&quot;,
x = &quot;&quot;,
caption = &quot;more here: www.bea.gov/newsreleases/national/gdp/gdpnewsrelease.htm&quot;) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, hjust = 1),
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5),
plot.caption=element_text(hjust=0)) +
facet_wrap(~account)
Note that these charts are showing the percent change of each account on an absolute basis, not how each has contributed to GDP change.
We will cover that next time and wrap this work to highcharter to make things interactive. See you then!