Skip to content

Commit

Permalink
Allow on-the-fly vcov adjustment (#35)
Browse files Browse the repository at this point in the history
* Lower tol for tests

* Fix URL

* Pass ... to summary.fixest

* Rather limit to just vcov and alternatives for safety.

* Update tests

* NEWS and version bump
  • Loading branch information
grantmcdermott committed Dec 12, 2023
1 parent 4b97b9d commit c5763e6
Show file tree
Hide file tree
Showing 15 changed files with 580 additions and 22 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: ggfixest
Title: Dedicated ggplot2 methods for fixest objects
Version: 0.0.3.9000
Version: 0.0.3.9001
Authors@R:
c(person(given = "Grant",
family = "McDermott",
Expand Down
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ export(ggiplot)
export(iplot_data)
import(fixest)
import(ggplot2)
importFrom(fixest,coefplot)
importFrom(fixest,iplot)
19 changes: 13 additions & 6 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# ggfixest 0.0.3.9000 (development version)
# ggfixest 0.0.3.9001 (development version)

## New features

- The `aggr_es` function now supports numeric sequences for aggregating
specific period subsets, in addition to the existing keyword strings like "pre"
or "post". This functionality passes through to the higher order functions that
call `aggr_es` under the hood. (#33)

- The `aggr_es` function now supports numeric sequences for aggregating a
specific subset of periods, in addition to the existing keyword strings like
"pre" or "post". This functionality also passes through to the higher order
plotting functions that call `aggr_es` under the hood. For example,
`ggiplot(est, aggr_eff = 6:8)`. (#33)
- Users can now adjust standard errors for model objects on-the-fly at plot
time, by passing an appropriate argument, e.g. `ggcoefplot(est, vcov = "hc1")`.
These on-the-fly adjustments are done via `summary.fixest`, and so the effect is
just the same as passing an adjusted object directly, e.g.
`ggcoefplot(summary(est, vcov = "hc1"))`. However, it may prove more convenient
for simultaneously adjusting a list of multiple models, e.g.
`ggcoefplot(list(est1, est2, est3), vcov = "hc1")`. (#35)

# ggfixest 0.0.3

Expand Down
4 changes: 4 additions & 0 deletions R/ggcoefplot.R
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
#' channel. For example, we can make the CI band lighter with
#' `ci.fill.par = list(alpha = 0.2)` (the default alpha is 0.3).
#' * `dict` a dictionary for overriding coefficient names.
#' * `vcov`, `cluster` or `se` as alternative options for adjusting the
#' standard errors of the model object(s) on the fly. See `summary.fixest` for
#' details. Written here in superseding order; `cluster` will only be
#' considered if `vcov` is not null, etc.
#' @details These functions generally try to mimic the functionality and (where
#' appropriate) arguments of `fixest::coefplot` and `fixest::iplot` as
#' closely as possible. However, by leveraging the ggplot2 API and
Expand Down
31 changes: 25 additions & 6 deletions R/ggiplot.R
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ ggiplot = function(
ref.line.par = list(col = "black", lty = 2, lwd = 0.3)
if (!is.null(dots[["ref.line.par"]])) ref.line.par = utils::modifyList(ref.line.par, dots[["ref.line.par"]])

# VCOV adjustments (if any)
vcov = if (!is.null(dots[['vcov']])) dots[['vcov']] else NULL
cluster = if (!is.null(dots[['cluster']])) dots[['cluster']] else NULL
se = if (!is.null(dots[['se']])) dots[['se']] else NULL

# The next few blocks grab the underlying iplot/coefplot data, contingent on the
# object that was passed into the function (i.e. fixest, fixest_multi, or
Expand All @@ -58,11 +62,21 @@ ggiplot = function(
if (inherits(object, c("fixest", "fixest_multi"))) {

if (length(ci_level) == 1) {
data = iplot_data_func(object, .ci_level = ci_level, .dict = dict, .aggr_es = aggr_eff, .keep = keep, .drop = drop, .group = group, .i.select = i.select)
data = iplot_data_func(
object,
.ci_level = ci_level, .dict = dict, .aggr_es = aggr_eff,
.keep = keep, .drop = drop, .group = group, .i.select = i.select,
.vcov = vcov, .cluster = cluster, .se = se
)
} else {
data = lapply(
ci_level,
function(ci_l) iplot_data_func(object, .ci_level = ci_l, .dict = dict, .aggr_es = aggr_eff, .keep = keep, .drop = drop, .group = group, .i.select = i.select)
function(ci_l) iplot_data_func(
object,
.ci_level = ci_l, .dict = dict, .aggr_es = aggr_eff,
.keep = keep, .drop = drop, .group = group, .i.select = i.select,
.vcov = vcov, .cluster = cluster, .se = se
)
)
data = do.call("rbind", data)
}
Expand All @@ -82,13 +96,18 @@ ggiplot = function(
if (length(ci_level) == 1) {
data = lapply(
object, iplot_data_func,
.ci_level = ci_level, .dict = dict, .aggr_es = aggr_eff, .group = group, .i.select = i.select
.ci_level = ci_level, .dict = dict, .aggr_es = aggr_eff,
.group = group, .i.select = i.select,
.vcov = vcov, .cluster = cluster, .se = se
)
} else {
data = lapply(ci_level, function(ci_l) {
lapply(object, iplot_data_func,
.ci_level = ci_l,
.dict = dict, .aggr_es = aggr_eff, .group = group, .i.select = i.select
lapply(
object, iplot_data_func,
.ci_level = ci_l,
.dict = dict, .aggr_es = aggr_eff,
.group = group, .i.select = i.select,
.vcov = vcov, .cluster = cluster, .se = se
)
})
data = do.call(function(...) Map("rbind", ...), data)
Expand Down
35 changes: 31 additions & 4 deletions R/iplot_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@
#' aggregated mean treatment effects for some subset of the model should be
#' added as a column to the returned data frame. Passed to
#' `aggr_es(..., aggregation = "mean")`.
#' @param .vcov,.cluster,.se Alternative options for adjusting the standard
#' errors of the model object on the fly. See `summary.fixest` for details
#' (although note that the "." period prefix should be ignored in the latter's
#' argument documentation). Written here in superseding order; `.cluster` will
#' only be considered if `.vcov` is not null, etc.
#' @details This function is a wrapper around
#' `fixest::iplot(..., only.params = TRUE)`, but with various checks and tweaks
#' to better facilitate plotting with `ggplot2` and handling of complex object
Expand All @@ -51,6 +56,7 @@
#' relative x-axis positions, and other aesthetic information needed to draw
#' a ggplot2 object.
#' @import ggplot2
#' @importFrom fixest coefplot iplot
#' @export
#' @examples
#' library(fixest)
Expand All @@ -77,7 +83,10 @@ iplot_data = function(
.i.select = 1,
# .aggr_es = c("none", "post", "pre", "both"),
.aggr_es = NULL,
.group = "auto"
.group = "auto",
.vcov = NULL,
.cluster = NULL,
.se = NULL
) {

# .aggr_es = match.arg(.aggr_es)
Expand All @@ -94,7 +103,16 @@ iplot_data = function(
.group = NULL
}

p = fixest::coefplot(object, only.params = TRUE, ci_level = .ci_level, dict = .dict, keep = .keep, drop = .drop, internal.only.i = .internal.only.i, i.select = .i.select)
# Catch VCOV adjustments (if any)
if (!is.null(.vcov)) {
object = summary(object, vcov = .vcov)
} else if (!is.null(.cluster)) {
object = summary(object, cluster = .cluster)
} else if (!is.null(.se)) {
object = summary(object, se = .se)
}

p = coefplot(object, only.params = TRUE, ci_level = .ci_level, dict = .dict, keep = .keep, drop = .drop, internal.only.i = .internal.only.i, i.select = .i.select)
d = p$prms

if (inherits(object, "fixest_multi")) {
Expand Down Expand Up @@ -423,9 +441,18 @@ coefplot_data = function(
.dict = fixest::getFixest_dict(),
.internal.only.i = FALSE,
.i.select = 1,
.aggr_es = "none"
.aggr_es = "none",
.vcov = NULL,
.cluster = NULL,
.se = NULL
) {

iplot_data(object, .ci_level = .ci_level, .dict = .dict, .keep = .keep, .drop = .drop, .internal.only.i = .internal.only.i, .group = .group)
iplot_data(
object,
.ci_level = .ci_level, .dict = .dict,
.keep = .keep, .drop = .drop,
.internal.only.i = .internal.only.i, .group = .group,
.vcov = .vcov, .cluster = .cluster, .se = .se
)

}
2 changes: 1 addition & 1 deletion README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ install.packages("ggfixest", repos = "https://grantmcdermott.r-universe.dev")

## Quickstart

The [package website](http://grantmcdermott.com/ggfixest)
The [package website](https://grantmcdermott.com/ggfixest/)
provides a number of examples in the help documentation. (Also available by
typing `?ggcoefplot` or `?ggiplot` in your R console.) But here are a few
quickstart examples to whet your appetite.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ install.packages("ggfixest", repos = "https://grantmcdermott.r-universe.dev")

## Quickstart

The [package website](http://grantmcdermott.com/ggfixest) provides a
The [package website](https://grantmcdermott.com/ggfixest/) provides a
number of examples in the help documentation. (Also available by typing
`?ggcoefplot` or `?ggiplot` in your R console.) But here are a few
quickstart examples to whet your appetite.
Expand Down
86 changes: 86 additions & 0 deletions inst/tinytest/_tinysnapshot/ggcoefplot_did_iid.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit c5763e6

Please sign in to comment.