lrberge / fixest

Fixed-effects estimations
https://lrberge.github.io/fixest/
373 stars 59 forks source link

ggiplot #179

Closed grantmcdermott closed 3 years ago

grantmcdermott commented 3 years ago

UPDATE: I ended up porting this to a dedicated (one function!) package here: https://github.com/grantmcdermott/ggiplot @lrberge I'm happy to keep this as a separate package or roll it into the main fixest codebase, as you see fit.

Invoking some infamous "this is more of a comment than a question" energy... but see #125 and I'm sure that several other users have wondered about a ggplot2 equivalent of iplot().

Personally, I think iplot() is fantastic and covers 99% of my needs out-of-the-box. But I recently ran into a situation where hacking the base graphics API to do what I wanted (i.e. grouped faceting of a list of multi_fixest objects) was too much of a PITA. So I ended up writing a thin(ish) wrapper around iplot() that produces ggplot2 objects and can harness the associated infrastructure. The resulting ggiplot() function package can be found here:

Some examples borrowing from the intro vignette:

library(ggiplot) # remotes::install_github('grantmcdermott/ggiplot')
library(fixest)
library(ggplot2)

## Vanilla TWFE
est_did = feols(y ~ x1 + i(period, treat, 5) | id + period, base_did)
ggiplot(est_did)

ggiplot(est_did, geom_style = 'errorbar', pt.join = TRUE) ## Another option

ggiplot(est_did, geom_style = 'ribbon') ## And another

## Staggered rollout
res_twfe = feols(y ~ x1 + i(time_to_treatment, treated, ref = c(-1, -1000)) | id + year, base_stagg)
res_sa20 = feols(y ~ x1 + sunab(year_treated, year) | id + year, base_stagg)
ggiplot(list('TWFE' = res_twfe, 'Sun & Abraham (2020)' = res_sa20), ref.line = -1)

ggiplot(list('TWFE' = res_twfe, 'Sun & Abraham (2020)' = res_sa20), ref.line = -1, multi_style = 'facet')

## A fancier example showing off some of ggiplot's extra features (grouped facetting, etc.)
base_stagg_grp = base_stagg
base_stagg_grp$grp = ifelse(base_stagg_grp$id %% 2 == 0, 'Evens', 'Odds')
res_twfe_grp = feols(y ~ x1 + i(time_to_treatment, treated, ref = c(-1, -1000)) | id + year, base_stagg_grp, split = ~ grp)
res_sa20_grp = feols(y ~ x1 + sunab(year_treated, year) | id + year, base_stagg_grp, split = ~ grp)
ggiplot(list('TWFE' = res_twfe_grp, 'Sun & Abraham (2020)' = res_sa20_grp), 
    ref.line = -1,
    main = 'Super duper plot',
    xlab = 'Time to treatment',
    multi_style = 'facet',
    geom_style = 'ribbon',
    theme = theme_minimal() + 
        theme(text = element_text(family = 'HersheySans'), 
            plot.title = element_text(hjust = 0.5),
            legend.position = 'none'))

Created on 2021-08-12 by the reprex package (v2.0.0)

Feel free to close immediately. I'm mostly writing this issue so that anyone searching for "ggplot2 equivalent of iplot" will have a reference.

24thronin commented 3 years ago

Hi Grant, I was just about to write a wrapper of my own to do exactly this because I want to layer some annotations on top of iplot. Thanks for making this public! Best, John

lrberge commented 3 years ago

That's really awesome Grant! The problem of how to handle multiple models out of the box sits on my desk for a while now and you've found very nice solutions.

I'm closing but it could be nice to talk about ggplot inclusion at some point. Great work again: creating a public repo+package is really ace.