Skip to content
Open
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
67 changes: 67 additions & 0 deletions .github/workflows/snapshot-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Snapshot Tests

on:
push:
branches:
- master
paths:
- 'pyfixest/report/**'
- 'pyfixest/estimation/decomposition.py'
- 'tests/test_etable_snapshot.py'
- 'tests/test_plots_snapshot.py'
- 'tests/__snapshots__/**'
pull_request:
branches:
- master
paths:
- 'pyfixest/report/**'
- 'pyfixest/estimation/decomposition.py'
- 'tests/test_etable_snapshot.py'
- 'tests/test_plots_snapshot.py'
- 'tests/__snapshots__/**'
schedule:
# Run weekly on Mondays at 6:00 UTC to catch dependency-induced regressions
- cron: '0 6 * * 1'
workflow_dispatch:

jobs:
snapshot-test:
name: "Snapshot Tests"
runs-on: macos-14 # ARM-based macOS
continue-on-error: true # Warn only - does not block merge
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Snapshot tests that don't block merges may allow visual regressions to slip through. Consider making these blocking once stabilized.

Suggested change
continue-on-error: true # Warn only - does not block merge
continue-on-error: ${{ github.event_name == 'schedule' }} # Allow failures on scheduled runs; block merges on push/PR

Copilot uses AI. Check for mistakes.
steps:
- name: Checkout source
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Setup pixi
uses: prefix-dev/setup-pixi@v0.8.3
with:
pixi-version: v0.41.4
cache: true

- name: Compile Rust extension
run: |
pixi run -e snapshot maturin-develop

- name: Run snapshot tests
id: snapshot_tests
run: |
pixi run -e snapshot snapshot-test

- name: Report snapshot status
if: failure()
run: |
echo "::warning::Snapshot tests failed. Run 'pixi run -e snapshot snapshot-update' locally to update snapshots if the changes are intentional."

- name: Upload snapshot artifacts on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: snapshot-failures
path: tests/__snapshots__/
retention-days: 7
1 change: 1 addition & 0 deletions coverage.json

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions docs/changelog.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ fit3 = pf.feols("Y ~ X1 + X2 | f1", data = df)

### Migration to maketables

The table functionality in pyfixest now uses [maketables](https://py-econometrics.github.io/maketables/). `maketables` is a spin-off of
The table functionality in pyfixest now uses the [maketables](https://py-econometrics.github.io/maketables/) package internally. `maketables` is a spin-off of
pyfixest internal functions, but supports more packages in the Python eco-system (e.g. `statsmodels` and `linearmorels`). Due to it's close
connection to `pyfixest`, the API of `pf.etable()` remains unchanged.

**Changes:**

- `pf.etable()` now uses `maketables.ETable` internally. The API remains unchanged for backward compatibility.
- Because the function is not at the core of `pyixest` functionality, we will deprecate `pf.dtable()`.
- Because this function is not at the core of `pyixest` functionality, we will deprecate `pf.dtable()`.
A `FutureWarning` is now emitted. The function has been moved to `maketables` and can be used by calling `maketables.DTable()` directly.
- The same applies for `pf.make_table()`, which has been an internal utility function to create tables. An equivalent function now lives in
`maketables.MTable()`.
Expand All @@ -46,7 +47,7 @@ maketables.DTable(df, vars=["Y", "X1"])
pf.make_table(df, type="gt", caption="My Table")
# After:
import maketables
maketables.MTable(df, caption="My Table").make(type="gt")
maketables.MTable(df, caption="My Table").to_gt()
```

### Other Changes
Expand Down
2 changes: 1 addition & 1 deletion docs/resources.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Textbooks / textbook chapters that we still want to cover:
If you are teaching with pyfixest, we'd love to hear from you!

- Econometrics II (taught by Vladislav Morozov at UBonn): Great intro to fixed effects estimation theory. Slides on fixed effects [here](https://vladislav-morozov.github.io/econometrics-2/slides/panel/fe.html#/title-slide), full class notes [here](https://vladislav-morozov.github.io/econometrics-2/), [github repository](https://github.com/vladislav-morozov/econometrics-2)
- Empirical Economics (taught at University of Utrecht 2025-2026) - MSc class in empirical economics.
- Empirical Economics (taught at University of Utrecht 2025-2026) - MSc class in empirical economics.
- ECON 526 - MA-level course in quantitative economics, data science, and causal inference in economics, taught at the University of Brisith Columbia. [Class notes here](https://github.com/ubcecon/ECON526/tree/main_2025)


Expand Down
25 changes: 24 additions & 1 deletion docs/table-layout.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ Starting with pyfixest 0.41.0 (currently in development), the table functionalit
The `pf.etable()` API remains unchanged. `pf.dtable()` is deprecated (use `DTable()` directly) and `pf.make_table()` has been removed (use `maketables.MTable()` directly).
:::

Pyfixest comes with functions to generate publication-ready tables. Regression tables are generated with `pf.etable()`, which can output different formats, for instance using the [Great Tables](https://posit-dev.github.io/great-tables/articles/intro.html) package or generating formatted LaTex Tables using [booktabs](https://ctan.org/pkg/booktabs?lang=en). Descriptive statistics tables can be created with `DTable()` and custom tables with `maketables.MTable()`.
::: {.callout-note}
## Migration Notice
Starting with pyfixest 0.41.0 (currently in development), the table functionality is powered by [maketables](https://py-econometrics.github.io/maketables/).
The `pf.etable()` API remains unchanged. `pf.dtable()` is deprecated (use `DTable()` directly) and `pf.make_table()` has been removed (use `maketables.MTable()` directly).
:::

Pyfixest comes with functions to generate publication-ready tables. Regression tables are generated with `pf.etable()`, which can output different formats, for instance using the [Great Tables](https://posit-dev.github.io/great-tables/articles/intro.html) package or generating formatted LaTex Tables using [booktabs](https://ctan.org/pkg/booktabs?lang=en). Descriptive statistics tables can be created with `DTable()` and custom tables with `maketables.MTable()`.

To begin, we load some libraries and fit a set of regression models.
Expand All @@ -24,6 +31,8 @@ import pandas as pd
import pylatex as pl # for the latex table; note: not a dependency of pyfixest - needs manual installation
from maketables import DTable
from great_tables import loc, style # great_tables is used by maketables internally
from maketables import DTable
from great_tables import loc, style # great_tables is used by maketables internally
from IPython.display import FileLink, display

import pyfixest as pf
Expand Down Expand Up @@ -120,10 +129,12 @@ pf.etable(
)
```

To obtain latex output use `type = "tex"`. If you want to save the table as a tex file, you can use the `file_name=` argument to specify the respective path where it should be saved. Etable will use latex packages `booktabs`, `threeparttable`, `makecell`, and `tabularx` for the table layout, so don't forget to include these packages in your latex document.
To obtain latex output use `type = "tex"`. If you want to save the table as a tex file, you can use the `file_name=` argument to specify the respective path where it should be saved. Etable will use latex packages `booktabs`, `threeparttable`, `makecell`, and `tabularx` for the table layout, so don't forget to include these packages in your latex document.

```{python}
# LaTex output (include latex packages booktabs, threeparttable, makecell, and tabularx in your document):
# LaTex output (include latex packages booktabs, threeparttable, makecell, and tabularx in your document):
tab = pf.etable(
[fit1, fit2, fit3, fit4, fit5, fit6],
signif_code=[0.01, 0.05, 0.1],
Expand All @@ -145,6 +156,7 @@ def make_pdf(tab, file):
doc.packages.append(pl.Package("threeparttable"))
doc.packages.append(pl.Package("makecell"))
doc.packages.append(pl.Package("tabularx"))
doc.packages.append(pl.Package("tabularx"))

with (
doc.create(pl.Section("A PyFixest LateX Table")),
Expand Down Expand Up @@ -342,17 +354,20 @@ format:

::: {.callout-warning}
## Deprecation Notice
`pf.dtable()` will be deprecated in the future. Please use `DTable` from the `maketables` package.
`pf.dtable()` will be deprecated in the future. Please use from the `maketables` package.
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incomplete sentence - missing the function name after 'Please use'. Should be 'Please use DTable() from the maketables package.'

Suggested change
`pf.dtable()` will be deprecated in the future. Please use from the `maketables` package.
`pf.dtable()` will be deprecated in the future. Please use `DTable()` from the `maketables` package.

Copilot uses AI. Check for mistakes.
:::

The function `DTable()` allows to display descriptive statistics for a set of variables in the same layout.
The function `DTable()` allows to display descriptive statistics for a set of variables in the same layout.

## Basic Usage of DTable
## Basic Usage of DTable
Specify the variables you want to display the descriptive statistics for. You can also use a dictionary to rename the variables and add a caption.



```{python}
DTable(
DTable(
data,
vars=["Y", "Y2", "X1", "X2"],
Expand All @@ -367,6 +382,7 @@ Choose the set of statistics to be displayed with `stats`. You can use any panda


```{python}
DTable(
DTable(
data,
vars=["Y", "Y2", "X1", "X2"],
Expand All @@ -389,6 +405,7 @@ data["occupation"] = np.random.choice(["Blue collar", "White collar"], data.shap
# Drop nan values to have balanced data
data.dropna(inplace=True)

DTable(
DTable(
data,
vars=["Y", "Y2", "X1", "X2"],
Expand All @@ -408,6 +425,7 @@ You can also hide the display of the statistics labels in the header with `hide_


```{python}
DTable(
DTable(
data,
vars=["Y", "Y2", "X1", "X2"],
Expand All @@ -426,6 +444,7 @@ You can also split by characteristics in both columns and rows. Note that you ca


```{python}
DTable(
DTable(
data,
vars=["Y", "Y2", "X1", "X2"],
Expand All @@ -442,6 +461,7 @@ And you can again export descriptive statistics tables also to LaTex:


```{python}
dtab = DTable(
dtab = DTable(
data,
vars=["Y", "Y2", "X1", "X2"],
Expand Down Expand Up @@ -522,6 +542,7 @@ style_presentation = {


```{python}
t1 = DTable(
t1 = DTable(
data,
vars=["Y", "Y2", "X1", "X2"],
Expand All @@ -542,6 +563,7 @@ t2 = pf.etable(

```{python}
display(t1.make(type="gt", gt_style=style_print))
display(t1.make(type="gt", gt_style=style_print))
display(t2.tab_options(**style_print))
```

Expand All @@ -561,5 +583,6 @@ style_printDouble = {
"table_width": "14cm",
}
display(t1.make(type="gt", gt_style=style_printDouble))
display(t1.make(type="gt", gt_style=style_printDouble))
display(t2.tab_options(**style_printDouble))
```
Loading
Loading