Title

bgshade -- Add background shading to twoway plots using either
dummy variable(s) denoting shaded areas and/or precoded NBER recessions.

Syntax

bgshade x/yvar [if] [in] [, options]

where x/yvar is the variable on the x or y axis that the shaded regions
will be added to. if and in statements
apply only to the shaders, not to the plotted variables. x/yvar should be integers
for custom shaders to work well.

options description

twoway(twoway) full twoway command minus shading goes in here*
shaders(varlist and/or NBER) variable used for shading or NBER option
sstyle(added_line_options) include added line suboptions for shaders
legend Include shaded regions in legend
oldshaders Insert shaders using the "old" method
horizontal Insert shaders on the yaxis rather than the x axis

NBER options description

quarter quarterly recessions (using end of period aggregation)
month monthly recessions
week weekly recessions (if first week of month is in recession month)
day daily recessions (mapped to full month)

*twoway() is the only required argument

Description

bgshade plots varlist as a twoway plot which includes
either NBER recession shading whose dates come from
https://fred.stlouisfed.org/series/USREC and/or the dummy variable(s)
specified in shaders() as added lines. Returns the full twoway command,
the list of x/ylines by shader, and the unit lwidth for the added lines.

Options

shaders(namelist) sets the shaded regions. NBER recessions are hard
coded and can be called with any of the NBER options. If you want to plot
your own shaded regions, simply have a dummy variable that = 1 if that observation
should be shaded and = 0 otherwise. It is also possible to leave this option blank,
in which case no shaded areas are plotted.

sstyle(added_line_options) sets any line style options for
the shaded regions. Only some options will have any effect though, these include axis,
style, lstyle, noextend, lpattern, lwidth, and lcolor.

These options are outlined in added_line_options, with the
difference that you specify however many options as you have shaders. If I have two
shaders (var1 and var2) and I want var1 to be green and var2 to be red then I would specify
sstyle(lcolor(green red)). The lwidth option can be specified either for all
shaders or once and will, in the latter case, apply to all shaders.

Note: lwidth sets the unit width. This means that if a shader is 3 units wide and lwidth is 2, the
actual width will be 3*2 = 6. lwidth should only be specified as a number or list of numbers unless
the oldshader option is used, then either *# or # notation are available.

Advanced options:

noxextend() (only for use with oldshaders option) takes a number input or "on" for default
settings. noxextend(on) tells bgshade that the shaded regions
extend off the edge of the plot area to the right or left. bgshade will then
figure out which side is the issue (or both) and take off 25% of the left- or
right-most added line. Setting a number tells bgshade to take off that % of
the added line that is going off the chart.
It is possible to specify any number, but > 100 has the same
functionality as 100 and negative numbers extend, rather than retract the shading.
See the example below and play around with it yourself if you're curious.

intensity() takes a %# or *# input that adjusts the intensity of the shaded
region colors. In Stata 15 the default is %50, in earlier versions the default
is *.4. To shut off intensity shifting, use intensity(*1) or intensity(%100). For further elaboration,
see the Adjust intensity and Adjust opacity sections in colorstyle.
If you specify the oldshaders option, then the defaults will be the same as
pre-Stata 15 defaults.

legend tells bgshade to include the shaded regions in the legend.
bgshade adds the shaders to the legend before the twoway command specified.
This is separate from the notes on the legend suboption of twoway included in bgshade

twoway(string) sets literally any twoway graph you want.
Literally. Does it run as a twoway plot? It will run here. The one exception is
that the legend suboption does have some
extra frills explained below.

oldshaders generally only useful in two cases: First, if you get the too many options
error, then specifying oldshaders will cut down on the total number of options used by
bgshade in the resulting twoway command. Second, if you want to use the
noxextend suboption of sstyle(), it is only supported with oldshaders.

For an explanation of the difference - when using old, bgshade creates
one xline command for each specified shader which each add many 1 x-unit sized lines.
ex: if your shader includes 2, 4 through 7, and 18 through 20 then the xline might look
like xline( 2 4 5 6 7 18 19 20, lwidth(*10) lcolor(gs12) lpattern() lstyle() style()).
This does not look good with Stata 15's new opacity options (the added lines overlap somewhat
and create striped lines. Given this problem, we decided to parse each shader's list
and create xline options for each continuous set of integers, find the midpoint and adjust
the width so that one added line covers each set. The above example would
have xline options as follows:
xline( 2 , lwidth(*10) lcolor(gs12) lpattern() lstyle() style())
xline( 5.5 , lwidth(*40) lcolor(gs12) lpattern() lstyle() style())
xline( 19 , lwidth(*30) lcolor(gs12) lpattern() lstyle() style())

horizontal Specifying horizontal places the shaded areas on the y-axis.
The x/yvar should be set to the y variable on which you want to place the
added lines. Note: you can specify axis(#) within sstyle()
so that the ylines are placed onto an axis that is not the first.

Twoway legend suboption

legend_options are all included, but we have added
functionality to include shaded regions in the legend by adding to the order()
option. Example included below.

If you would rather a wordy explanation: the shaders are added to the legend
automatically and appear first, so if you have 2 shaders and 2 y-variables, your
legend order will be shader1 shader2 yvar1 yvar2 and if you wanted to put your
y-variables first in the legend and not include the shaders,for example, you could specify
order(3 "yvar1" 4 "yvar2").

NBER Options

day, week, month,
and quarter set the period for recession shading to be daily,
weekly, monthly, or quarterly respectively. This only affects the placement of
the shading, not the data you are using. When using quarter, the end of period
aggregation is used, so recession shading may be somewhat left-biased. When using
week or day the first of each month is used, so recession shading may
not extend to the end of the month.

Examples

*basic use
sysuse gnp96
format date %tq
bgshade date if date >= yq(1970,1), legend shaders(quarter) ///
twoway(line gnp96 date if date >= yq(1970,1), title("GNP") lcolor(navy))

*full time series of nber recessions available:
drop _all
set obs 2000
gen date = _n-1280
format date %tm
gen series = sqrt(_n)+runiform()
gen series2 = series*runiform()/2
bgshade date, shaders(month) ///
twoway(line series date, title("All Monthly Recessions"))

*all default shading options
drop _all
set obs 12
gen date = _n-1
gen res1 = inlist(date,4,5,6,7,8,9)
gen res2 = inlist(date,2,3,4,5)
gen res3 = inlist(date,4,9,10,11,12)
gen res4 = inlist(date,5,6,10,11)
gen line1 = sqrt(_n)
gen line2 = _n*_n/20

bgshade date, shaders(res1 res2 res3 res4) ///
twoway(line line1 date || sc line2 date, xlab(-2(2)14) ///
title("All default shading colors and patterns"))

*using extra options in twoway
bgshade date, shaders(res1 res2 res3 res4) ///
twoway(line line1 date, lcolor(magenta) || (sc line2 date, msize(huge)), xlab(-2(2)14) ///
title("Using extra options in twoway"))

*using custom and NBER shaders
bgshade date, shaders(quarter res2 res3 res4) ///
twoway(line line1 date || sc line2 date, xlab(-2(2)14) ///
title("Using custom and NBER shaders") ///
subtitle("We recommend putting nber shaders first because it looks best"))

*sstyle options
bgshade date, shaders(res2 res3 res4) ///
sstyle(noextend lcolor("255 0 0" green blue) lpattern(_ - -_)) ///
twoway(line line1 date || sc line2 date, xlab(-2(2)14) ///
title("Using some sstyle options"))

*legend options
lab var res1 "Shader 1"
lab var res2 "Shader 2"
bgshade date, shaders(res1 res2 res3 res4) legend ///
twoway(line line1 date || sc line2 date, xlab(-2(2)14) ///
title("Add shaders to the legend"))

*mix it up with the legend
bgshade date, shaders(res1 res2 res3 res4) legend ///
twoway(line line1 date || sc line2 date, xlab(-2(2)14) ///
title("Using order legend suboption") ///
legend(order(5 "Square Root of N" 6 "N Squared over 20" 2 "Res2" 4 "Res4") cols(2)))

*more than 4 shaders example
drop res*
forvalues ii = 1/8 {
gen res`ii' = _n == `ii'+2
}

bgshade date, shaders(res1 res2 res3 res4 res5 res6 res7 res8) ///
sstyle(lpattern( l _ l _ l _ l _) lcolor(green blue red magenta orange navy "255 0 0" eltgreen)) ///
twoway(line line1 date || sc line2 date, xlab(0(1)12) ///
title("More than 4 shaders"))

*playing with the shader WIDTH since it's not perfect above
bgshade date, shaders(res1 res2 res3 res4 res5 res6 res7 res8) ///
sstyle(lwidth(10) ///
lpattern( l _ l _ l _ l _) lcolor(green blue red magenta orange navy "255 0 0" eltgreen)) ///
twoway(line line1 date || sc line2 date, xlab(0(1)12) ///
title("Changing all widths"))

*alternative setting each individual shader's width
bgshade date, shaders(res1 res2 res3 res4 res5 res6 res7 res8) ///
sstyle(lwidth(1 4 10 25 1 3 14 7) ///
lpattern( l _ l _ l _ l _) lcolor(green blue red magenta orange navy "255 0 0" eltgreen)) ///
twoway(line line1 date || sc line2 date, xlab(0(1)12) ///
title("Changing individual widths"))

*noxextend example (oldshaders too)
gen res = _n < 3 | _n > 10

bgshade date, shaders(res) sstyle(noxextend(100)) ///
twoway(line line1 date, title("Too hot")) oldshaders
bgshade date, shaders(res) sstyle(noxextend(-100)) ///
twoway(line line1 date, title("Too cold")) oldshaders
bgshade date, shaders(res) sstyle(noxextend(60)) ///
twoway(line line1 date, title("Just right")) oldshaders

*horizontal example
gen yvar = _n
replace res = yvar > 3 & yvar < 5
replace res2 = yvar > 5 & yvar < 7
bgshade yvar, shaders(res res2) ///
twoway(line yvar date) horiz

Future plans

Adding functionality for more customizable color intensity/opacity and noxextend options.
Let us know what you need and please let us know if you find any bugs!

Authors

Eric Haavind-Berman, University of Wisconsin, Madison, ehaavindberman@gmail.com
Aaron Markiewitz, University of Michigan

Many thanks to the wonderful Research Assistants at the Boston Fed for helpful feedback and comments.

Also see

Kit Baum has a great program nbercycles available from SSC which
tackles the same problem as here, but by adding area graphs to your line plot
rather than adding lines and resizing them.