expdpy 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- expdpy-0.2.0/.gitignore +43 -0
- expdpy-0.2.0/.streamlit/config.toml +7 -0
- expdpy-0.2.0/LICENSE +25 -0
- expdpy-0.2.0/PKG-INFO +203 -0
- expdpy-0.2.0/README.md +159 -0
- expdpy-0.2.0/deploy/expdpy/README.md +63 -0
- expdpy-0.2.0/pyproject.toml +218 -0
- expdpy-0.2.0/src/expdpy/__init__.py +147 -0
- expdpy-0.2.0/src/expdpy/_assets/favicon.png +0 -0
- expdpy-0.2.0/src/expdpy/_assets/favicon.svg +12 -0
- expdpy-0.2.0/src/expdpy/_assets/logo-navbar.svg +14 -0
- expdpy-0.2.0/src/expdpy/_assets/logo.png +0 -0
- expdpy-0.2.0/src/expdpy/_assets/logo.svg +14 -0
- expdpy-0.2.0/src/expdpy/_corr.py +80 -0
- expdpy-0.2.0/src/expdpy/_estimation/__init__.py +38 -0
- expdpy-0.2.0/src/expdpy/_estimation/_capture.py +26 -0
- expdpy-0.2.0/src/expdpy/_estimation/_fit.py +56 -0
- expdpy-0.2.0/src/expdpy/_estimation/_formula.py +50 -0
- expdpy-0.2.0/src/expdpy/_estimation/_results.py +30 -0
- expdpy-0.2.0/src/expdpy/_estimation/_spec.py +112 -0
- expdpy-0.2.0/src/expdpy/_estimation/_tidy.py +35 -0
- expdpy-0.2.0/src/expdpy/_estimation/_vcov.py +52 -0
- expdpy-0.2.0/src/expdpy/_theme.py +201 -0
- expdpy-0.2.0/src/expdpy/_types.py +505 -0
- expdpy-0.2.0/src/expdpy/_validation.py +43 -0
- expdpy-0.2.0/src/expdpy/app/__init__.py +766 -0
- expdpy-0.2.0/src/expdpy/app/_components.py +282 -0
- expdpy-0.2.0/src/expdpy/app/_config_io.py +63 -0
- expdpy-0.2.0/src/expdpy/app/_export_nb.py +234 -0
- expdpy-0.2.0/src/expdpy/app/_sample.py +124 -0
- expdpy-0.2.0/src/expdpy/app/_state.py +102 -0
- expdpy-0.2.0/src/expdpy/app/_udv.py +179 -0
- expdpy-0.2.0/src/expdpy/app/_upload.py +43 -0
- expdpy-0.2.0/src/expdpy/app/_varcat.py +100 -0
- expdpy-0.2.0/src/expdpy/by_group.py +313 -0
- expdpy-0.2.0/src/expdpy/coefplot.py +236 -0
- expdpy-0.2.0/src/expdpy/correlation.py +152 -0
- expdpy-0.2.0/src/expdpy/data/__init__.py +103 -0
- expdpy-0.2.0/src/expdpy/data/expdpy_config_kuznets.json +54 -0
- expdpy-0.2.0/src/expdpy/data/gapminder.parquet +0 -0
- expdpy-0.2.0/src/expdpy/data/gapminder_data_def.parquet +0 -0
- expdpy-0.2.0/src/expdpy/data/kuznets.parquet +0 -0
- expdpy-0.2.0/src/expdpy/data/kuznets_data_def.parquet +0 -0
- expdpy-0.2.0/src/expdpy/data/staggered_did.parquet +0 -0
- expdpy-0.2.0/src/expdpy/data/staggered_did_data_def.parquet +0 -0
- expdpy-0.2.0/src/expdpy/did.py +405 -0
- expdpy-0.2.0/src/expdpy/distributions.py +130 -0
- expdpy-0.2.0/src/expdpy/estimation.py +282 -0
- expdpy-0.2.0/src/expdpy/fwl.py +284 -0
- expdpy-0.2.0/src/expdpy/inference.py +92 -0
- expdpy-0.2.0/src/expdpy/missing.py +117 -0
- expdpy-0.2.0/src/expdpy/outliers.py +180 -0
- expdpy-0.2.0/src/expdpy/panel_models.py +244 -0
- expdpy-0.2.0/src/expdpy/pedagogy/__init__.py +43 -0
- expdpy-0.2.0/src/expdpy/pedagogy/_format.py +88 -0
- expdpy-0.2.0/src/expdpy/pedagogy/_interpret.py +355 -0
- expdpy-0.2.0/src/expdpy/pedagogy/_mixin.py +44 -0
- expdpy-0.2.0/src/expdpy/pedagogy/_registry.py +121 -0
- expdpy-0.2.0/src/expdpy/pedagogy/_text/__init__.py +11 -0
- expdpy-0.2.0/src/expdpy/pedagogy/_text/causal.py +65 -0
- expdpy-0.2.0/src/expdpy/pedagogy/_text/correlation.py +77 -0
- expdpy-0.2.0/src/expdpy/pedagogy/_text/outliers.py +53 -0
- expdpy-0.2.0/src/expdpy/pedagogy/_text/regression.py +257 -0
- expdpy-0.2.0/src/expdpy/pedagogy/_text/tables.py +51 -0
- expdpy-0.2.0/src/expdpy/postestimation.py +202 -0
- expdpy-0.2.0/src/expdpy/py.typed +0 -0
- expdpy-0.2.0/src/expdpy/regression.py +201 -0
- expdpy-0.2.0/src/expdpy/sandbox.py +307 -0
- expdpy-0.2.0/src/expdpy/scatter.py +207 -0
- expdpy-0.2.0/src/expdpy/streamlit_app/__init__.py +106 -0
- expdpy-0.2.0/src/expdpy/streamlit_app/_context.py +99 -0
- expdpy-0.2.0/src/expdpy/streamlit_app/_entry.py +57 -0
- expdpy-0.2.0/src/expdpy/streamlit_app/_handoff.py +149 -0
- expdpy-0.2.0/src/expdpy/streamlit_app/_launcher.py +103 -0
- expdpy-0.2.0/src/expdpy/streamlit_app/_pages.py +424 -0
- expdpy-0.2.0/src/expdpy/streamlit_app/_pipeline.py +99 -0
- expdpy-0.2.0/src/expdpy/streamlit_app/_render.py +221 -0
- expdpy-0.2.0/src/expdpy/streamlit_app/_run.py +9 -0
- expdpy-0.2.0/src/expdpy/streamlit_app/_sidebar.py +258 -0
- expdpy-0.2.0/src/expdpy/streamlit_app/_widgets.py +95 -0
- expdpy-0.2.0/src/expdpy/tables.py +348 -0
- expdpy-0.2.0/src/expdpy/trends.py +263 -0
- expdpy-0.2.0/streamlit_app.py +15 -0
- expdpy-0.2.0/tests/conftest.py +42 -0
- expdpy-0.2.0/tests/fixtures/goldens.json +97 -0
- expdpy-0.2.0/tests/fixtures/make_fixture.py +42 -0
- expdpy-0.2.0/tests/fixtures/make_goldens.R +60 -0
- expdpy-0.2.0/tests/fixtures/sample.csv +161 -0
- expdpy-0.2.0/tests/test_app.py +201 -0
- expdpy-0.2.0/tests/test_coefplot.py +111 -0
- expdpy-0.2.0/tests/test_data.py +97 -0
- expdpy-0.2.0/tests/test_did.py +133 -0
- expdpy-0.2.0/tests/test_estimation.py +168 -0
- expdpy-0.2.0/tests/test_estimation_engine.py +203 -0
- expdpy-0.2.0/tests/test_fwl.py +120 -0
- expdpy-0.2.0/tests/test_glm.py +67 -0
- expdpy-0.2.0/tests/test_graphs.py +134 -0
- expdpy-0.2.0/tests/test_hardening.py +39 -0
- expdpy-0.2.0/tests/test_inference.py +52 -0
- expdpy-0.2.0/tests/test_kuznets_showcase.py +55 -0
- expdpy-0.2.0/tests/test_outliers.py +94 -0
- expdpy-0.2.0/tests/test_panel_models.py +120 -0
- expdpy-0.2.0/tests/test_pedagogy.py +174 -0
- expdpy-0.2.0/tests/test_postestimation.py +84 -0
- expdpy-0.2.0/tests/test_regression.py +73 -0
- expdpy-0.2.0/tests/test_sandbox.py +57 -0
- expdpy-0.2.0/tests/test_streamlit_app.py +198 -0
- expdpy-0.2.0/tests/test_tables.py +93 -0
- expdpy-0.2.0/tests/test_theme.py +81 -0
- expdpy-0.2.0/tests/test_vs_expandar.py +108 -0
- expdpy-0.2.0/tests/test_vs_fwlplot.py +84 -0
expdpy-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
.env
|
|
11
|
+
|
|
12
|
+
# Tooling caches
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.mypy_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.hypothesis/
|
|
17
|
+
.coverage
|
|
18
|
+
coverage.xml
|
|
19
|
+
htmlcov/
|
|
20
|
+
|
|
21
|
+
# pixi
|
|
22
|
+
.pixi/
|
|
23
|
+
|
|
24
|
+
# Docs build
|
|
25
|
+
docs/_site/
|
|
26
|
+
docs/.quarto/
|
|
27
|
+
docs/objects.json
|
|
28
|
+
docs/reference/
|
|
29
|
+
!docs/reference/.gitkeep
|
|
30
|
+
|
|
31
|
+
# OS / editor
|
|
32
|
+
.DS_Store
|
|
33
|
+
.idea/
|
|
34
|
+
.vscode/
|
|
35
|
+
|
|
36
|
+
# R
|
|
37
|
+
.Rhistory
|
|
38
|
+
.RData
|
|
39
|
+
.Rproj.user
|
|
40
|
+
|
|
41
|
+
# Vendored reference R packages (reference only — not part of the expdpy package)
|
|
42
|
+
/ExPanDaR/
|
|
43
|
+
/fwlplot-r/
|
expdpy-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Carlos Mendez
|
|
4
|
+
|
|
5
|
+
expdpy is a Python port of the ExPanDaR R package
|
|
6
|
+
(Copyright (c) Joachim Gassen, https://github.com/trr266/ExPanDaR), which is
|
|
7
|
+
also released under the MIT License.
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
expdpy-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: expdpy
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Explore your panel data interactively — a Python port of the ExPanDaR R package.
|
|
5
|
+
Project-URL: Homepage, https://github.com/cmg777/expdpy
|
|
6
|
+
Project-URL: Documentation, https://cmg777.github.io/expdpy/
|
|
7
|
+
Project-URL: Repository, https://github.com/cmg777/expdpy
|
|
8
|
+
Project-URL: Issues, https://github.com/cmg777/expdpy/issues
|
|
9
|
+
Author: Carlos Mendez
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: econometrics,exploratory data analysis,fixed effects,panel data,plotly,pyfixest,visualization
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: great-tables>=0.9
|
|
24
|
+
Requires-Dist: numpy>=1.24
|
|
25
|
+
Requires-Dist: pandas<3,>=2.0
|
|
26
|
+
Requires-Dist: plotly>=5.18
|
|
27
|
+
Requires-Dist: pyarrow>=14
|
|
28
|
+
Requires-Dist: pyfixest>=0.60
|
|
29
|
+
Requires-Dist: scipy>=1.10
|
|
30
|
+
Requires-Dist: statsmodels>=0.14
|
|
31
|
+
Provides-Extra: app
|
|
32
|
+
Requires-Dist: cryptography>=42; extra == 'app'
|
|
33
|
+
Requires-Dist: nbformat>=5.9; extra == 'app'
|
|
34
|
+
Requires-Dist: openpyxl>=3.1; extra == 'app'
|
|
35
|
+
Requires-Dist: shiny>=1.0; extra == 'app'
|
|
36
|
+
Requires-Dist: shinywidgets>=0.3; extra == 'app'
|
|
37
|
+
Provides-Extra: panel
|
|
38
|
+
Requires-Dist: linearmodels>=6; extra == 'panel'
|
|
39
|
+
Provides-Extra: streamlit
|
|
40
|
+
Requires-Dist: nbformat>=5.9; extra == 'streamlit'
|
|
41
|
+
Requires-Dist: openpyxl>=3.1; extra == 'streamlit'
|
|
42
|
+
Requires-Dist: streamlit>=1.40; extra == 'streamlit'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
<p align="center">
|
|
48
|
+
<img src="https://raw.githubusercontent.com/cmg777/expdpy/main/docs/images/hero.webp" alt="expdpy — A Python library to explore panel data interactively" width="100%">
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<!-- badges: start -->
|
|
52
|
+
[](https://github.com/cmg777/expdpy/actions/workflows/ci.yml)
|
|
53
|
+
[](https://codecov.io/gh/cmg777/expdpy)
|
|
54
|
+
[](https://cmg777.github.io/expdpy/)
|
|
55
|
+
[](https://github.com/cmg777/expdpy/releases)
|
|
56
|
+
[](https://github.com/cmg777/expdpy)
|
|
57
|
+
[](https://opensource.org/licenses/MIT)
|
|
58
|
+
[](https://github.com/astral-sh/ruff)
|
|
59
|
+
<!-- badges: end -->
|
|
60
|
+
|
|
61
|
+
**expdpy** is a Python library for interactive, exploratory analysis of **panel and
|
|
62
|
+
cross-sectional data**. It pairs a set of composable analytical functions — that return
|
|
63
|
+
interactive [Plotly](https://plotly.com/python/) figures and publication-quality
|
|
64
|
+
[Great Tables](https://posit-dev.github.io/great-tables/) — with **two no-code `ExPdPy` web
|
|
65
|
+
apps** that bring the same workflow to the browser, no code required.
|
|
66
|
+
|
|
67
|
+
It is built on the modern Python data and econometrics stack:
|
|
68
|
+
|
|
69
|
+
- **[Plotly](https://plotly.com/python/)** — interactive figures
|
|
70
|
+
- **[pyfixest](https://github.com/py-econometrics/pyfixest)** — fixed-effects / clustered regressions
|
|
71
|
+
- **[Great Tables](https://posit-dev.github.io/great-tables/)** — publication-quality tables
|
|
72
|
+
- **[Streamlit](https://streamlit.io/)** and **[Shiny for Python](https://shiny.posit.co/py/)** — the two no-code `ExPdPy` apps
|
|
73
|
+
|
|
74
|
+
## Features
|
|
75
|
+
|
|
76
|
+
### Composable analytical functions
|
|
77
|
+
|
|
78
|
+
Descriptive, correlation and extreme-observation tables; histograms and category bar charts;
|
|
79
|
+
time trends and quantile trends; by-group bar, violin and trend views; scatter plots with an
|
|
80
|
+
optional LOESS smoother; and a missing-value heatmap across the panel. Each function takes a
|
|
81
|
+
`pandas` DataFrame and returns an interactive Plotly figure or a Great Tables object you can
|
|
82
|
+
drop straight into a notebook or report.
|
|
83
|
+
|
|
84
|
+
### Panel-aware econometrics
|
|
85
|
+
|
|
86
|
+
OLS with **multi-way fixed effects** and **clustered standard errors** via
|
|
87
|
+
[pyfixest](https://github.com/py-econometrics/pyfixest), publication-ready coefficient tables,
|
|
88
|
+
and **Frisch–Waugh–Lovell** partial-regression plots that show a single coefficient net of all
|
|
89
|
+
controls and fixed effects. Winsorize or truncate outliers with `treat_outliers`.
|
|
90
|
+
|
|
91
|
+
### Two no-code apps — Streamlit & Shiny
|
|
92
|
+
|
|
93
|
+
The same exploration workflow in two frontends: a sidebar **sample pipeline** (subset filters,
|
|
94
|
+
outlier treatment), component selection and ordering, and live, point-and-click analysis. The
|
|
95
|
+
[Streamlit app](https://cmg777.github.io/expdpy/streamlit.html) organises the components into a
|
|
96
|
+
multipage layout with native, sortable tables and deploys to
|
|
97
|
+
[Streamlit Community Cloud](https://streamlit.io/cloud) in one click; the
|
|
98
|
+
[Shiny app](https://cmg777.github.io/expdpy/shiny.html) stacks every component in one scrolling
|
|
99
|
+
view. See [Streamlit vs Shiny](https://cmg777.github.io/expdpy/explanation/streamlit-vs-shiny.html)
|
|
100
|
+
for a side-by-side comparison.
|
|
101
|
+
|
|
102
|
+
### Reproducibility & safety
|
|
103
|
+
|
|
104
|
+
Any in-app exploration exports to a **runnable bundle** — a Jupyter notebook, a `.py` script
|
|
105
|
+
and the prepared data (parquet) — that recreates every displayed result with `expdpy` calls.
|
|
106
|
+
Analysis configurations **save, load and interchange between the two apps**. New variables can
|
|
107
|
+
be defined live through a **restricted-AST expression evaluator** (never `eval`/`exec`) with
|
|
108
|
+
**panel-aware `lag`/`lead`** that shift within each cross-section.
|
|
109
|
+
|
|
110
|
+
### Bundled panel datasets
|
|
111
|
+
|
|
112
|
+
`expdpy.data` ships ready-to-explore panels — **`kuznets`** (the flagship N-shaped
|
|
113
|
+
Kuznets-curve demo) and `gapminder` — with `kuznets` shipping a preset configuration that
|
|
114
|
+
opens an app directly on the worked example. See the
|
|
115
|
+
[kuznets dataset](https://cmg777.github.io/expdpy/explanation/kuznets-dataset.html) page for
|
|
116
|
+
the data dictionary.
|
|
117
|
+
|
|
118
|
+
## Installation
|
|
119
|
+
|
|
120
|
+
The package is not on PyPI yet — install the latest version straight from GitHub:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Core analytical functions:
|
|
124
|
+
pip install "git+https://github.com/cmg777/expdpy.git"
|
|
125
|
+
|
|
126
|
+
# ...with the interactive ExPdPy app (Streamlit):
|
|
127
|
+
pip install "expdpy[streamlit] @ git+https://github.com/cmg777/expdpy.git"
|
|
128
|
+
|
|
129
|
+
# ...with the interactive ExPdPy app (Shiny):
|
|
130
|
+
pip install "expdpy[app] @ git+https://github.com/cmg777/expdpy.git"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Using [uv](https://docs.astral.sh/uv/):
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
uv pip install "git+https://github.com/cmg777/expdpy.git"
|
|
137
|
+
uv pip install "expdpy[streamlit] @ git+https://github.com/cmg777/expdpy.git" # Streamlit
|
|
138
|
+
uv pip install "expdpy[app] @ git+https://github.com/cmg777/expdpy.git" # Shiny
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Pin to a branch, tag, or commit for reproducible installs:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
pip install "git+https://github.com/cmg777/expdpy.git@main"
|
|
145
|
+
# pip install "git+https://github.com/cmg777/expdpy.git@v0.1.0" # once a release is tagged
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
> **Coming soon (PyPI):** once published, `pip install expdpy` /
|
|
149
|
+
> `pip install "expdpy[streamlit]"` / `pip install "expdpy[app]"` will work directly.
|
|
150
|
+
|
|
151
|
+
## At a glance
|
|
152
|
+
|
|
153
|
+
The lead example throughout the docs is the bundled `kuznets` panel (80 countries ×
|
|
154
|
+
2015–2025): a synthetic dataset, rich in control variables, whose regional inequality traces
|
|
155
|
+
an **N-shaped Kuznets curve** in income — it rises, falls, then rises again at very high
|
|
156
|
+
income.
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
import expdpy as ex
|
|
160
|
+
from expdpy.data import load_kuznets
|
|
161
|
+
|
|
162
|
+
df = load_kuznets()
|
|
163
|
+
# The N-shaped regional Kuznets curve: regional inequality vs (log) GDP per capita
|
|
164
|
+
ex.prepare_scatter_plot(
|
|
165
|
+
df, x="log_gdp_pc", y="gini_regional", color="continent", size="population", loess=1
|
|
166
|
+
)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Launch the same data in the interactive app, pre-configured to open on the curve:
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from expdpy.streamlit_app import ExPdPy # or: from expdpy.app import ExPdPy
|
|
173
|
+
from expdpy.data import load_kuznets, load_kuznets_data_def, get_config
|
|
174
|
+
|
|
175
|
+
ExPdPy(load_kuznets(), df_def=load_kuznets_data_def(), config_list=get_config("kuznets"))
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Head to the [Quickstart](https://cmg777.github.io/expdpy/quickstart.html) to see every
|
|
179
|
+
function in action, the
|
|
180
|
+
[kuznets dataset](https://cmg777.github.io/expdpy/explanation/kuznets-dataset.html) page for
|
|
181
|
+
the data dictionary, or the [Streamlit](https://cmg777.github.io/expdpy/streamlit.html) /
|
|
182
|
+
[Shiny](https://cmg777.github.io/expdpy/shiny.html) guides to launch the interactive apps.
|
|
183
|
+
|
|
184
|
+
## Documentation
|
|
185
|
+
|
|
186
|
+
Full documentation, tutorials, and the API reference live at
|
|
187
|
+
**https://cmg777.github.io/expdpy/**.
|
|
188
|
+
|
|
189
|
+
## Acknowledgements
|
|
190
|
+
|
|
191
|
+
expdpy began as a Python port of the excellent
|
|
192
|
+
[ExPanDaR](https://github.com/trr266/ExPanDaR) package by Joachim Gassen and the
|
|
193
|
+
TRR 266 Accounting for Transparency project, and its foundations remain deeply inspired by
|
|
194
|
+
that work. Over time it has grown functionality beyond the original — two interactive
|
|
195
|
+
frontends (Streamlit **and** Shiny), a restricted-AST expression evaluator with panel-aware
|
|
196
|
+
`lag`/`lead`, pyfixest-based fixed-effects regressions with Frisch–Waugh–Lovell plots, and
|
|
197
|
+
reproducible notebook / script / data export — and it will keep evolving. We are grateful to
|
|
198
|
+
the ExPanDaR authors; please cite the original work when using `expdpy` in research (see
|
|
199
|
+
[`CITATION.cff`](CITATION.cff)).
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
MIT — see [`LICENSE`](LICENSE).
|
expdpy-0.2.0/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/cmg777/expdpy/main/docs/images/hero.webp" alt="expdpy — A Python library to explore panel data interactively" width="100%">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<!-- badges: start -->
|
|
8
|
+
[](https://github.com/cmg777/expdpy/actions/workflows/ci.yml)
|
|
9
|
+
[](https://codecov.io/gh/cmg777/expdpy)
|
|
10
|
+
[](https://cmg777.github.io/expdpy/)
|
|
11
|
+
[](https://github.com/cmg777/expdpy/releases)
|
|
12
|
+
[](https://github.com/cmg777/expdpy)
|
|
13
|
+
[](https://opensource.org/licenses/MIT)
|
|
14
|
+
[](https://github.com/astral-sh/ruff)
|
|
15
|
+
<!-- badges: end -->
|
|
16
|
+
|
|
17
|
+
**expdpy** is a Python library for interactive, exploratory analysis of **panel and
|
|
18
|
+
cross-sectional data**. It pairs a set of composable analytical functions — that return
|
|
19
|
+
interactive [Plotly](https://plotly.com/python/) figures and publication-quality
|
|
20
|
+
[Great Tables](https://posit-dev.github.io/great-tables/) — with **two no-code `ExPdPy` web
|
|
21
|
+
apps** that bring the same workflow to the browser, no code required.
|
|
22
|
+
|
|
23
|
+
It is built on the modern Python data and econometrics stack:
|
|
24
|
+
|
|
25
|
+
- **[Plotly](https://plotly.com/python/)** — interactive figures
|
|
26
|
+
- **[pyfixest](https://github.com/py-econometrics/pyfixest)** — fixed-effects / clustered regressions
|
|
27
|
+
- **[Great Tables](https://posit-dev.github.io/great-tables/)** — publication-quality tables
|
|
28
|
+
- **[Streamlit](https://streamlit.io/)** and **[Shiny for Python](https://shiny.posit.co/py/)** — the two no-code `ExPdPy` apps
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
### Composable analytical functions
|
|
33
|
+
|
|
34
|
+
Descriptive, correlation and extreme-observation tables; histograms and category bar charts;
|
|
35
|
+
time trends and quantile trends; by-group bar, violin and trend views; scatter plots with an
|
|
36
|
+
optional LOESS smoother; and a missing-value heatmap across the panel. Each function takes a
|
|
37
|
+
`pandas` DataFrame and returns an interactive Plotly figure or a Great Tables object you can
|
|
38
|
+
drop straight into a notebook or report.
|
|
39
|
+
|
|
40
|
+
### Panel-aware econometrics
|
|
41
|
+
|
|
42
|
+
OLS with **multi-way fixed effects** and **clustered standard errors** via
|
|
43
|
+
[pyfixest](https://github.com/py-econometrics/pyfixest), publication-ready coefficient tables,
|
|
44
|
+
and **Frisch–Waugh–Lovell** partial-regression plots that show a single coefficient net of all
|
|
45
|
+
controls and fixed effects. Winsorize or truncate outliers with `treat_outliers`.
|
|
46
|
+
|
|
47
|
+
### Two no-code apps — Streamlit & Shiny
|
|
48
|
+
|
|
49
|
+
The same exploration workflow in two frontends: a sidebar **sample pipeline** (subset filters,
|
|
50
|
+
outlier treatment), component selection and ordering, and live, point-and-click analysis. The
|
|
51
|
+
[Streamlit app](https://cmg777.github.io/expdpy/streamlit.html) organises the components into a
|
|
52
|
+
multipage layout with native, sortable tables and deploys to
|
|
53
|
+
[Streamlit Community Cloud](https://streamlit.io/cloud) in one click; the
|
|
54
|
+
[Shiny app](https://cmg777.github.io/expdpy/shiny.html) stacks every component in one scrolling
|
|
55
|
+
view. See [Streamlit vs Shiny](https://cmg777.github.io/expdpy/explanation/streamlit-vs-shiny.html)
|
|
56
|
+
for a side-by-side comparison.
|
|
57
|
+
|
|
58
|
+
### Reproducibility & safety
|
|
59
|
+
|
|
60
|
+
Any in-app exploration exports to a **runnable bundle** — a Jupyter notebook, a `.py` script
|
|
61
|
+
and the prepared data (parquet) — that recreates every displayed result with `expdpy` calls.
|
|
62
|
+
Analysis configurations **save, load and interchange between the two apps**. New variables can
|
|
63
|
+
be defined live through a **restricted-AST expression evaluator** (never `eval`/`exec`) with
|
|
64
|
+
**panel-aware `lag`/`lead`** that shift within each cross-section.
|
|
65
|
+
|
|
66
|
+
### Bundled panel datasets
|
|
67
|
+
|
|
68
|
+
`expdpy.data` ships ready-to-explore panels — **`kuznets`** (the flagship N-shaped
|
|
69
|
+
Kuznets-curve demo) and `gapminder` — with `kuznets` shipping a preset configuration that
|
|
70
|
+
opens an app directly on the worked example. See the
|
|
71
|
+
[kuznets dataset](https://cmg777.github.io/expdpy/explanation/kuznets-dataset.html) page for
|
|
72
|
+
the data dictionary.
|
|
73
|
+
|
|
74
|
+
## Installation
|
|
75
|
+
|
|
76
|
+
The package is not on PyPI yet — install the latest version straight from GitHub:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Core analytical functions:
|
|
80
|
+
pip install "git+https://github.com/cmg777/expdpy.git"
|
|
81
|
+
|
|
82
|
+
# ...with the interactive ExPdPy app (Streamlit):
|
|
83
|
+
pip install "expdpy[streamlit] @ git+https://github.com/cmg777/expdpy.git"
|
|
84
|
+
|
|
85
|
+
# ...with the interactive ExPdPy app (Shiny):
|
|
86
|
+
pip install "expdpy[app] @ git+https://github.com/cmg777/expdpy.git"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Using [uv](https://docs.astral.sh/uv/):
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
uv pip install "git+https://github.com/cmg777/expdpy.git"
|
|
93
|
+
uv pip install "expdpy[streamlit] @ git+https://github.com/cmg777/expdpy.git" # Streamlit
|
|
94
|
+
uv pip install "expdpy[app] @ git+https://github.com/cmg777/expdpy.git" # Shiny
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Pin to a branch, tag, or commit for reproducible installs:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install "git+https://github.com/cmg777/expdpy.git@main"
|
|
101
|
+
# pip install "git+https://github.com/cmg777/expdpy.git@v0.1.0" # once a release is tagged
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
> **Coming soon (PyPI):** once published, `pip install expdpy` /
|
|
105
|
+
> `pip install "expdpy[streamlit]"` / `pip install "expdpy[app]"` will work directly.
|
|
106
|
+
|
|
107
|
+
## At a glance
|
|
108
|
+
|
|
109
|
+
The lead example throughout the docs is the bundled `kuznets` panel (80 countries ×
|
|
110
|
+
2015–2025): a synthetic dataset, rich in control variables, whose regional inequality traces
|
|
111
|
+
an **N-shaped Kuznets curve** in income — it rises, falls, then rises again at very high
|
|
112
|
+
income.
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
import expdpy as ex
|
|
116
|
+
from expdpy.data import load_kuznets
|
|
117
|
+
|
|
118
|
+
df = load_kuznets()
|
|
119
|
+
# The N-shaped regional Kuznets curve: regional inequality vs (log) GDP per capita
|
|
120
|
+
ex.prepare_scatter_plot(
|
|
121
|
+
df, x="log_gdp_pc", y="gini_regional", color="continent", size="population", loess=1
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Launch the same data in the interactive app, pre-configured to open on the curve:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from expdpy.streamlit_app import ExPdPy # or: from expdpy.app import ExPdPy
|
|
129
|
+
from expdpy.data import load_kuznets, load_kuznets_data_def, get_config
|
|
130
|
+
|
|
131
|
+
ExPdPy(load_kuznets(), df_def=load_kuznets_data_def(), config_list=get_config("kuznets"))
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Head to the [Quickstart](https://cmg777.github.io/expdpy/quickstart.html) to see every
|
|
135
|
+
function in action, the
|
|
136
|
+
[kuznets dataset](https://cmg777.github.io/expdpy/explanation/kuznets-dataset.html) page for
|
|
137
|
+
the data dictionary, or the [Streamlit](https://cmg777.github.io/expdpy/streamlit.html) /
|
|
138
|
+
[Shiny](https://cmg777.github.io/expdpy/shiny.html) guides to launch the interactive apps.
|
|
139
|
+
|
|
140
|
+
## Documentation
|
|
141
|
+
|
|
142
|
+
Full documentation, tutorials, and the API reference live at
|
|
143
|
+
**https://cmg777.github.io/expdpy/**.
|
|
144
|
+
|
|
145
|
+
## Acknowledgements
|
|
146
|
+
|
|
147
|
+
expdpy began as a Python port of the excellent
|
|
148
|
+
[ExPanDaR](https://github.com/trr266/ExPanDaR) package by Joachim Gassen and the
|
|
149
|
+
TRR 266 Accounting for Transparency project, and its foundations remain deeply inspired by
|
|
150
|
+
that work. Over time it has grown functionality beyond the original — two interactive
|
|
151
|
+
frontends (Streamlit **and** Shiny), a restricted-AST expression evaluator with panel-aware
|
|
152
|
+
`lag`/`lead`, pyfixest-based fixed-effects regressions with Frisch–Waugh–Lovell plots, and
|
|
153
|
+
reproducible notebook / script / data export — and it will keep evolving. We are grateful to
|
|
154
|
+
the ExPanDaR authors; please cite the original work when using `expdpy` in research (see
|
|
155
|
+
[`CITATION.cff`](CITATION.cff)).
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT — see [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Deploy the expdpy Shiny app to shinyapps.io
|
|
2
|
+
|
|
3
|
+
This folder is a self-contained [rsconnect-python](https://docs.posit.co/rsconnect-python/) bundle
|
|
4
|
+
that publishes the **Shiny** app (`expdpy.app.ExPdPy`) to [shinyapps.io](https://www.shinyapps.io/)
|
|
5
|
+
in **upload mode** — visitors bring their own data; no bundled dataset is shown.
|
|
6
|
+
|
|
7
|
+
| File | Purpose |
|
|
8
|
+
|------|---------|
|
|
9
|
+
| `app.py` | Module-level `app = ExPdPy(run=False)` — the entrypoint shinyapps.io serves (`app:app`). |
|
|
10
|
+
| `requirements.txt` | Installs `expdpy[app]` from the public GitHub repo (tracks `main`). |
|
|
11
|
+
|
|
12
|
+
## One-time: install the deploy CLI
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
uv tool install rsconnect-python # or: pixi global install rsconnect-python
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## One-time: register your shinyapps.io account
|
|
19
|
+
|
|
20
|
+
Get the token/secret from shinyapps.io → **Account → Tokens**. Run this yourself so the secret stays
|
|
21
|
+
private (it is not stored in this repo):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
rsconnect add --account <ACCOUNT> --name shinyapps --token <TOKEN> --secret <SECRET>
|
|
25
|
+
rsconnect list # verify
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
> `--name shinyapps` here is the **server/account nickname** (a local alias for your shinyapps.io
|
|
29
|
+
> account) — *not* the app name. The published app's URL slug comes from the **deploy folder basename**
|
|
30
|
+
> (`deploy/expdpy` → `…/expdpy/`).
|
|
31
|
+
|
|
32
|
+
## Deploy (and redeploy)
|
|
33
|
+
|
|
34
|
+
Run from the repo root. `--python` points at the Pixi 3.12 interpreter so the recorded Python version
|
|
35
|
+
satisfies `requires-python>=3.10`. The bundle's `requirements.txt` is used as-is.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
rsconnect deploy shiny deploy/expdpy \
|
|
39
|
+
--name shinyapps \
|
|
40
|
+
--entrypoint app:app \
|
|
41
|
+
--title expdpy \
|
|
42
|
+
--python /Users/carlos/GitHub/expdpy/.pixi/envs/default/bin/python
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
rsconnect prints the live URL (`https://<account>.shinyapps.io/expdpy/`) when the build finishes (the
|
|
46
|
+
first build is slow — heavy deps). Subsequent runs of this command update the same app in place; add
|
|
47
|
+
`--new` only to force the creation of a brand-new app.
|
|
48
|
+
|
|
49
|
+
## Local smoke test (same entrypoint shinyapps.io uses)
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pixi run shiny run deploy/expdpy/app.py # then open http://127.0.0.1:8000
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Notes
|
|
56
|
+
|
|
57
|
+
- **Tracking `main`:** shinyapps.io caches the Python env by the `requirements.txt` hash. With the
|
|
58
|
+
unpinned git URL, pushing new commits to `main` won't necessarily reinstall `expdpy` on a later
|
|
59
|
+
redeploy. To force an update, pin a commit in `requirements.txt`
|
|
60
|
+
(`...expdpy.git@<sha>`) — that changes the hash and triggers a rebuild.
|
|
61
|
+
- **Free tier:** ~1 GB RAM / limited active hours / max 5 apps. The dependency set
|
|
62
|
+
(pyfixest/statsmodels/scipy/plotly) is memory-heavy; move to a paid instance if the build or
|
|
63
|
+
runtime struggles.
|