Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add keep/drop to coefplot and refactor code to improve maintainability #341

Merged
merged 8 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 17 additions & 118 deletions pyfixest/estimation/FixestMulti_.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import functools
import warnings
from importlib import import_module
from typing import Optional, Union

import numpy as np
Expand All @@ -11,7 +13,6 @@
from pyfixest.estimation.fepois_ import Fepois, _check_for_separation
from pyfixest.estimation.FormulaParser import FixestFormulaParser
from pyfixest.estimation.model_matrix_fixest_ import model_matrix_fixest
from pyfixest.report.visualize import coefplot, iplot
from pyfixest.utils.dev_utils import _polars_to_pandas


Expand Down Expand Up @@ -42,6 +43,21 @@ def __init__(self, data: pd.DataFrame) -> None:
self._data.reset_index(drop=True, inplace=True)
self.all_fitted_models = {}

# set functions inherited from other modules
_module = import_module("pyfixest.report")
_tmp = getattr(_module, "coefplot")
self.coefplot = functools.partial(_tmp, models=self.all_fitted_models.values())
self.coefplot.__doc__ = _tmp.__doc__
_tmp = getattr(_module, "iplot")
self.iplot = functools.partial(_tmp, models=self.all_fitted_models.values())
self.iplot.__doc__ = _tmp.__doc__
_tmp = getattr(_module, "summary")
self.summary = functools.partial(_tmp, models=self.all_fitted_models.values())
self.summary.__doc__ = _tmp.__doc__
_tmp = getattr(_module, "etable")
self.etable = functools.partial(_tmp, models=self.all_fitted_models.values())
self.etable.__doc__ = _tmp.__doc__

def _prepare_estimation(
self,
estimation: str,
Expand Down Expand Up @@ -479,14 +495,6 @@ def tidy(self) -> pd.DataFrame:

return res

def summary(self, digits: int = 3) -> None: # noqa: D102
for x in list(self.all_fitted_models.keys()):
fxst = self.all_fitted_models[x]
fxst.summary(digits=digits)

def etable(self, digits: int = 3) -> pd.DataFrame: # noqa: D102
return self.tidy().T.round(digits)

def coef(self) -> pd.Series:
"""
Obtain the coefficients of the fitted models.
Expand Down Expand Up @@ -549,115 +557,6 @@ def confint(self) -> pd.Series:
"""
return self.tidy()[["2.5%", "97.5%"]]

def iplot(
self,
alpha: float = 0.05,
figsize: tuple = (500, 300),
yintercept: Union[int, str, None] = None,
xintercept: Union[int, str, None] = None,
rotate_xticks: int = 0,
title: Optional[str] = None,
coord_flip: Optional[bool] = True,
):
"""
Plot model coefficients.

Plot model coefficients with confidence intervals for variable interactions
specified via the `i()` syntax.

Parameters
----------
alpha : float, optional
The significance level for the confidence intervals. Default is 0.05.
figsize : tuple, optional
The size of the figure. Default is (10, 10).
yintercept : Union[int, str, None], optional
The value at which to draw a horizontal line.
xintercept : Union[int, str, None], optional
The value at which to draw a vertical line.
rotate_xticks : int, optional
The rotation angle for x-axis tick labels. Default is 0.
title : str, optional
The title of the plot. Default is None.
coord_flip : bool, optional
Whether to flip the coordinates of the plot. Default is True.

Returns
-------
lets-plot figure
A lets-plot figure of coefficients (and respective CIs) interacted
via the `i()` syntax.
"""
models = self.all_fitted_models
# get a list, not a dict, as iplot only works with lists
models = [models[x] for x in list(self.all_fitted_models.keys())]

plot = iplot(
models=models,
alpha=alpha,
figsize=figsize,
yintercept=yintercept,
xintercept=xintercept,
rotate_xticks=rotate_xticks,
title=title,
coord_flip=coord_flip,
)

return plot

def coefplot(
self,
alpha: float = 0.05,
figsize: tuple = (500, 300),
yintercept: int = 0,
rotate_xticks: int = 0,
title: Optional[str] = None,
coord_flip: Optional[bool] = True,
):
"""
Plot estimation results.

The plot() method is only defined for single regressions.

Parameters
----------
alpha : float
The significance level for the confidence intervals. Default is 0.05.
figsize : tuple
The size of the figure. Default is (5, 2).
yintercept : float
The value of the y-intercept. Default is 0.
figtitle:str, optional
The title of the figure. Default is None.
figtext : str, optional
The text at the bottom of the figure. Default is None.
title : str, optional
The title of the plot. Default is None.
coord_flip : bool, optional
Whether to flip the coordinates of the plot. Default is True.

Returns
-------
lets-plot figure
A lets-plot figure of regression coefficients.
"""
# get a list, not a dict, as iplot only works with lists
models = self.all_fitted_models
models = [models[x] for x in list(self.all_fitted_models.keys())]

plot = coefplot(
models=models,
figsize=figsize,
alpha=alpha,
yintercept=yintercept,
xintercept=None,
rotate_xticks=rotate_xticks,
title=title,
coord_flip=coord_flip,
)

return plot

def wildboottest(
self,
B: int,
Expand Down
141 changes: 13 additions & 128 deletions pyfixest/estimation/feols_.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import functools
import re
import warnings
from importlib import import_module
Expand Down Expand Up @@ -262,6 +263,18 @@ def __init__(
self._adj_r2 = None
self._adj_r2_within = None

# set functions inherited from other modules
_module = import_module("pyfixest.report")
_tmp = getattr(_module, "coefplot")
self.coefplot = functools.partial(_tmp, models=[self])
self.coefplot.__doc__ = _tmp.__doc__
_tmp = getattr(_module, "iplot")
self.iplot = functools.partial(_tmp, models=[self])
self.iplot.__doc__ = _tmp.__doc__
_tmp = getattr(_module, "summary")
self.summary = functools.partial(_tmp, models=[self])
self.summary.__doc__ = _tmp.__doc__

def get_fit(self) -> None:
"""
Fit an OLS model.
Expand Down Expand Up @@ -728,115 +741,6 @@ def wald_test(self, R=None, q=None, distribution="F") -> None:

return res

def coefplot(
self,
alpha: float = 0.05,
figsize: tuple[int, int] = (500, 300),
yintercept: Optional[float] = 0,
xintercept: Optional[float] = None,
rotate_xticks: int = 0,
coefficients: Optional[list[str]] = None,
title: Optional[str] = None,
coord_flip: Optional[bool] = True,
):
"""
Create a coefficient plot to visualize model coefficients.

Parameters
----------
alpha : float, optional
Significance level for highlighting significant coefficients.
Defaults to None.
figsize : tuple[int, int], optional
Size of the plot (width, height) in inches. Defaults to None.
yintercept : float, optional
Value to set as the y-axis intercept (vertical line). Defaults to None.
xintercept : float, optional
Value to set as the x-axis intercept (horizontal line). Defaults to None.
rotate_xticks : int, optional
Rotation angle for x-axis tick labels. Defaults to None.
coefficients : list[str], optional
List of coefficients to include in the plot.
If None, all coefficients are included.
title : str, optional
Title of the plot. Defaults to None.
coord_flip : bool, optional
Whether to flip the coordinates of the plot. Defaults to None.

Returns
-------
lets-plot figure
A lets-plot figure with coefficient estimates and confidence intervals.
"""
# lazy loading to avoid circular import
visualize_module = import_module("pyfixest.report")
_coefplot = getattr(visualize_module, "coefplot")

plot = _coefplot(
models=[self],
alpha=alpha,
figsize=figsize,
yintercept=yintercept,
xintercept=xintercept,
rotate_xticks=rotate_xticks,
coefficients=coefficients,
title=title,
coord_flip=coord_flip,
)

return plot

def iplot(
self,
alpha: float = 0.05,
figsize: tuple[int, int] = (500, 300),
yintercept: Optional[float] = None,
xintercept: Optional[float] = None,
rotate_xticks: int = 0,
title: Optional[str] = None,
coord_flip: Optional[bool] = True,
):
"""
Create coefficient plots for variables interacted via `i()` syntax.

Parameters
----------
alpha : float, optional
Significance level for visualization options. Defaults to 0.05.
figsize : tuple[int, int], optional
Size of the plot (width, height) in inches. Defaults to (500, 300).
yintercept : float, optional
Value to set as the y-axis intercept (vertical line). Defaults to None.
xintercept : float, optional
Value to set as the x-axis intercept (horizontal line). Defaults to None.
rotate_xticks : int, optional
Rotation angle for x-axis tick labels. Defaults to 0.
title : str, optional
Title of the plot. Defaults to None.
coord_flip : bool, optional
Whether to flip the coordinates of the plot. Defaults to True.

Returns
-------
lets-plot figure
A lets-plot figure with coefficient estimates and confidence intervals.
"""
visualize_module = import_module("pyfixest.report")
_iplot = getattr(visualize_module, "iplot")

plot = _iplot(
models=[self],
alpha=alpha,
figsize=figsize,
yintercept=yintercept,
xintercept=xintercept,
rotate_xticks=rotate_xticks,
title=title,
coord_flip=coord_flip,
)

return plot

def wildboottest(
self,
B: int,
Expand Down Expand Up @@ -1662,25 +1566,6 @@ def resid(self) -> np.ndarray:
"""
return self._u_hat

def summary(self, digits=3) -> None:
"""
Summary of estimated model.

Parameters
----------
digits : int, optional
The number of digits to be displayed. Defaults to 3.

Returns
-------
None
"""
# lazy loading to avoid circular import
summarize_module = import_module("pyfixest.report")
_summary = getattr(summarize_module, "summary")

return _summary(models=self, digits=digits)


def _check_vcov_input(vcov, data):
"""
Expand Down
Loading
Loading