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.
Files changed (111) hide show
  1. expdpy-0.2.0/.gitignore +43 -0
  2. expdpy-0.2.0/.streamlit/config.toml +7 -0
  3. expdpy-0.2.0/LICENSE +25 -0
  4. expdpy-0.2.0/PKG-INFO +203 -0
  5. expdpy-0.2.0/README.md +159 -0
  6. expdpy-0.2.0/deploy/expdpy/README.md +63 -0
  7. expdpy-0.2.0/pyproject.toml +218 -0
  8. expdpy-0.2.0/src/expdpy/__init__.py +147 -0
  9. expdpy-0.2.0/src/expdpy/_assets/favicon.png +0 -0
  10. expdpy-0.2.0/src/expdpy/_assets/favicon.svg +12 -0
  11. expdpy-0.2.0/src/expdpy/_assets/logo-navbar.svg +14 -0
  12. expdpy-0.2.0/src/expdpy/_assets/logo.png +0 -0
  13. expdpy-0.2.0/src/expdpy/_assets/logo.svg +14 -0
  14. expdpy-0.2.0/src/expdpy/_corr.py +80 -0
  15. expdpy-0.2.0/src/expdpy/_estimation/__init__.py +38 -0
  16. expdpy-0.2.0/src/expdpy/_estimation/_capture.py +26 -0
  17. expdpy-0.2.0/src/expdpy/_estimation/_fit.py +56 -0
  18. expdpy-0.2.0/src/expdpy/_estimation/_formula.py +50 -0
  19. expdpy-0.2.0/src/expdpy/_estimation/_results.py +30 -0
  20. expdpy-0.2.0/src/expdpy/_estimation/_spec.py +112 -0
  21. expdpy-0.2.0/src/expdpy/_estimation/_tidy.py +35 -0
  22. expdpy-0.2.0/src/expdpy/_estimation/_vcov.py +52 -0
  23. expdpy-0.2.0/src/expdpy/_theme.py +201 -0
  24. expdpy-0.2.0/src/expdpy/_types.py +505 -0
  25. expdpy-0.2.0/src/expdpy/_validation.py +43 -0
  26. expdpy-0.2.0/src/expdpy/app/__init__.py +766 -0
  27. expdpy-0.2.0/src/expdpy/app/_components.py +282 -0
  28. expdpy-0.2.0/src/expdpy/app/_config_io.py +63 -0
  29. expdpy-0.2.0/src/expdpy/app/_export_nb.py +234 -0
  30. expdpy-0.2.0/src/expdpy/app/_sample.py +124 -0
  31. expdpy-0.2.0/src/expdpy/app/_state.py +102 -0
  32. expdpy-0.2.0/src/expdpy/app/_udv.py +179 -0
  33. expdpy-0.2.0/src/expdpy/app/_upload.py +43 -0
  34. expdpy-0.2.0/src/expdpy/app/_varcat.py +100 -0
  35. expdpy-0.2.0/src/expdpy/by_group.py +313 -0
  36. expdpy-0.2.0/src/expdpy/coefplot.py +236 -0
  37. expdpy-0.2.0/src/expdpy/correlation.py +152 -0
  38. expdpy-0.2.0/src/expdpy/data/__init__.py +103 -0
  39. expdpy-0.2.0/src/expdpy/data/expdpy_config_kuznets.json +54 -0
  40. expdpy-0.2.0/src/expdpy/data/gapminder.parquet +0 -0
  41. expdpy-0.2.0/src/expdpy/data/gapminder_data_def.parquet +0 -0
  42. expdpy-0.2.0/src/expdpy/data/kuznets.parquet +0 -0
  43. expdpy-0.2.0/src/expdpy/data/kuznets_data_def.parquet +0 -0
  44. expdpy-0.2.0/src/expdpy/data/staggered_did.parquet +0 -0
  45. expdpy-0.2.0/src/expdpy/data/staggered_did_data_def.parquet +0 -0
  46. expdpy-0.2.0/src/expdpy/did.py +405 -0
  47. expdpy-0.2.0/src/expdpy/distributions.py +130 -0
  48. expdpy-0.2.0/src/expdpy/estimation.py +282 -0
  49. expdpy-0.2.0/src/expdpy/fwl.py +284 -0
  50. expdpy-0.2.0/src/expdpy/inference.py +92 -0
  51. expdpy-0.2.0/src/expdpy/missing.py +117 -0
  52. expdpy-0.2.0/src/expdpy/outliers.py +180 -0
  53. expdpy-0.2.0/src/expdpy/panel_models.py +244 -0
  54. expdpy-0.2.0/src/expdpy/pedagogy/__init__.py +43 -0
  55. expdpy-0.2.0/src/expdpy/pedagogy/_format.py +88 -0
  56. expdpy-0.2.0/src/expdpy/pedagogy/_interpret.py +355 -0
  57. expdpy-0.2.0/src/expdpy/pedagogy/_mixin.py +44 -0
  58. expdpy-0.2.0/src/expdpy/pedagogy/_registry.py +121 -0
  59. expdpy-0.2.0/src/expdpy/pedagogy/_text/__init__.py +11 -0
  60. expdpy-0.2.0/src/expdpy/pedagogy/_text/causal.py +65 -0
  61. expdpy-0.2.0/src/expdpy/pedagogy/_text/correlation.py +77 -0
  62. expdpy-0.2.0/src/expdpy/pedagogy/_text/outliers.py +53 -0
  63. expdpy-0.2.0/src/expdpy/pedagogy/_text/regression.py +257 -0
  64. expdpy-0.2.0/src/expdpy/pedagogy/_text/tables.py +51 -0
  65. expdpy-0.2.0/src/expdpy/postestimation.py +202 -0
  66. expdpy-0.2.0/src/expdpy/py.typed +0 -0
  67. expdpy-0.2.0/src/expdpy/regression.py +201 -0
  68. expdpy-0.2.0/src/expdpy/sandbox.py +307 -0
  69. expdpy-0.2.0/src/expdpy/scatter.py +207 -0
  70. expdpy-0.2.0/src/expdpy/streamlit_app/__init__.py +106 -0
  71. expdpy-0.2.0/src/expdpy/streamlit_app/_context.py +99 -0
  72. expdpy-0.2.0/src/expdpy/streamlit_app/_entry.py +57 -0
  73. expdpy-0.2.0/src/expdpy/streamlit_app/_handoff.py +149 -0
  74. expdpy-0.2.0/src/expdpy/streamlit_app/_launcher.py +103 -0
  75. expdpy-0.2.0/src/expdpy/streamlit_app/_pages.py +424 -0
  76. expdpy-0.2.0/src/expdpy/streamlit_app/_pipeline.py +99 -0
  77. expdpy-0.2.0/src/expdpy/streamlit_app/_render.py +221 -0
  78. expdpy-0.2.0/src/expdpy/streamlit_app/_run.py +9 -0
  79. expdpy-0.2.0/src/expdpy/streamlit_app/_sidebar.py +258 -0
  80. expdpy-0.2.0/src/expdpy/streamlit_app/_widgets.py +95 -0
  81. expdpy-0.2.0/src/expdpy/tables.py +348 -0
  82. expdpy-0.2.0/src/expdpy/trends.py +263 -0
  83. expdpy-0.2.0/streamlit_app.py +15 -0
  84. expdpy-0.2.0/tests/conftest.py +42 -0
  85. expdpy-0.2.0/tests/fixtures/goldens.json +97 -0
  86. expdpy-0.2.0/tests/fixtures/make_fixture.py +42 -0
  87. expdpy-0.2.0/tests/fixtures/make_goldens.R +60 -0
  88. expdpy-0.2.0/tests/fixtures/sample.csv +161 -0
  89. expdpy-0.2.0/tests/test_app.py +201 -0
  90. expdpy-0.2.0/tests/test_coefplot.py +111 -0
  91. expdpy-0.2.0/tests/test_data.py +97 -0
  92. expdpy-0.2.0/tests/test_did.py +133 -0
  93. expdpy-0.2.0/tests/test_estimation.py +168 -0
  94. expdpy-0.2.0/tests/test_estimation_engine.py +203 -0
  95. expdpy-0.2.0/tests/test_fwl.py +120 -0
  96. expdpy-0.2.0/tests/test_glm.py +67 -0
  97. expdpy-0.2.0/tests/test_graphs.py +134 -0
  98. expdpy-0.2.0/tests/test_hardening.py +39 -0
  99. expdpy-0.2.0/tests/test_inference.py +52 -0
  100. expdpy-0.2.0/tests/test_kuznets_showcase.py +55 -0
  101. expdpy-0.2.0/tests/test_outliers.py +94 -0
  102. expdpy-0.2.0/tests/test_panel_models.py +120 -0
  103. expdpy-0.2.0/tests/test_pedagogy.py +174 -0
  104. expdpy-0.2.0/tests/test_postestimation.py +84 -0
  105. expdpy-0.2.0/tests/test_regression.py +73 -0
  106. expdpy-0.2.0/tests/test_sandbox.py +57 -0
  107. expdpy-0.2.0/tests/test_streamlit_app.py +198 -0
  108. expdpy-0.2.0/tests/test_tables.py +93 -0
  109. expdpy-0.2.0/tests/test_theme.py +81 -0
  110. expdpy-0.2.0/tests/test_vs_expandar.py +108 -0
  111. expdpy-0.2.0/tests/test_vs_fwlplot.py +84 -0
@@ -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/
@@ -0,0 +1,7 @@
1
+ # Streamlit configuration for the ExPdPy app (local runs and Community Cloud).
2
+ [server]
3
+ # Maximum upload size in MB for the in-app data uploader.
4
+ maxUploadSize = 200
5
+
6
+ [theme]
7
+ base = "light"
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
+ [![CI](https://github.com/cmg777/expdpy/actions/workflows/ci.yml/badge.svg)](https://github.com/cmg777/expdpy/actions/workflows/ci.yml)
53
+ [![codecov](https://codecov.io/gh/cmg777/expdpy/branch/main/graph/badge.svg)](https://codecov.io/gh/cmg777/expdpy)
54
+ [![Docs](https://github.com/cmg777/expdpy/actions/workflows/docs.yml/badge.svg)](https://cmg777.github.io/expdpy/)
55
+ [![GitHub release](https://img.shields.io/github/v/release/cmg777/expdpy?include_prereleases&label=release)](https://github.com/cmg777/expdpy/releases)
56
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://github.com/cmg777/expdpy)
57
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
58
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](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
+ [![CI](https://github.com/cmg777/expdpy/actions/workflows/ci.yml/badge.svg)](https://github.com/cmg777/expdpy/actions/workflows/ci.yml)
9
+ [![codecov](https://codecov.io/gh/cmg777/expdpy/branch/main/graph/badge.svg)](https://codecov.io/gh/cmg777/expdpy)
10
+ [![Docs](https://github.com/cmg777/expdpy/actions/workflows/docs.yml/badge.svg)](https://cmg777.github.io/expdpy/)
11
+ [![GitHub release](https://img.shields.io/github/v/release/cmg777/expdpy?include_prereleases&label=release)](https://github.com/cmg777/expdpy/releases)
12
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://github.com/cmg777/expdpy)
13
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
14
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](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.