analyze_marginal_effects_plot

source

analyze_marginal_effects_plot(
    df,
    dv,
    focal,
    moderator,
    *,
    controls=None,
    feffects=None,
    clusters=None,
    at=None,
    n_points=50,
    alpha=0.05,
    title=None,
)

Plot the marginal effect of focal across moderator for an interaction model.

Fits dv ~ focal * moderator (+ controls) (| fixed effects) via pyfixest, then traces the marginal effect of focalb_focal + b_interaction * moderator — across the moderator’s observed range, with a delta-method confidence band. Also reports the average marginal effect (evaluated at the sample-mean moderator).

Parameters

Name Type Description Default
df pd.DataFrame Data frame containing the data. required
dv str Dependent (outcome) variable name. required
focal str The focal regressor whose marginal effect is traced. required
moderator str The moderating variable it is interacted with. required
controls Sequence[str] | None Additional exogenous control variable names. None
feffects Sequence[str] | None Fixed-effects variable names absorbed by pyfixest. None
clusters Sequence[str] | None Cluster variable name(s) for cluster-robust standard errors (and hence the band). None
at Sequence[float] | None Explicit moderator values at which to evaluate the marginal effect. Defaults to an evenly spaced grid over the moderator’s observed range. None
n_points int Number of grid points when at is not given (default 50). 50
alpha float Significance level for the confidence band (default 0.05 → 95%). 0.05
title str | None Optional figure title. None

Returns

Name Type Description
MarginalEffectsResult df (the grid: <moderator>, me, se, ci_lower, ci_upper), fig (the Plotly figure), focal / moderator, and ame / ame_se (the average marginal effect and its standard error).

Raises

Name Type Description
NotImplementedError If the dependent variable is non-numeric.
ValueError If no interaction term between focal and moderator is estimated.

Examples

Does the gradient of inequality in income depend on trade openness? Trace the marginal effect of log GDP per capita across the range of the trade share:

import expdpy as ex
from expdpy.data import load_kuznets, load_kuznets_data_def

df = ex.set_labels(load_kuznets(), load_kuznets_data_def(), set_panel=True)
result = ex.analyze_marginal_effects_plot(
    df, dv="gini_regional", focal="log_gdp_pc", moderator="trade_share"
)
result.fig
result.ame
print(result.interpret())
The marginal association of **log_gdp_pc** with the outcome is not constant — it depends on **trade_share** (their interaction).
Across the observed range it moves from 0.0254 at trade_share = 0.198 to -0.0765 at trade_share = 1.42.
The association switches sign near trade_share = 0.502: log_gdp_pc relates to the outcome in opposite directions below and above that point.
Averaged over the sample, the marginal association is -0.00904 (statistically significant at the 1% level).

_These are associations, not causal effects. A causal reading needs a research design — see `explain('correlation_vs_causation')`._