The ExPdPy Shiny app
No installation required — try the app live in your browser:
The hosted app runs Shiny for Python on shinyapps.io and starts with a file-upload dialog — there is no bundled data, so you bring your own CSV / Excel / Parquet. To try it with the panel used throughout these docs:
- Download the sample: kuznets.csv (880 rows × 21 columns).
- Open the live app and use Upload to select
kuznets.csv. - Explore the descriptive tables, distributions, correlations and scatter (the N-shaped Kuznets curve), and the regression builder.
The hosted free-tier instance has limited compute time and memory, so heavy operations may be slow or time out, and the app may sleep when idle. For the full, fast experience — and larger datasets — run the app locally (install and launch instructions below).
The ExPdPy app wraps the analytical functions in an interactive, no-code interface (built with Shiny for Python). It is provided by the app extra. The package is not on PyPI yet, so install it from GitHub:
pip install "expdpy[app] @ git+https://github.com/cmg777/expdpy.git"
# or, with uv:
uv pip install "expdpy[app] @ git+https://github.com/cmg777/expdpy.git"Once published to PyPI, pip install "expdpy[app]" will work directly.
Using the app
Launching on a DataFrame
from expdpy.app import ExPdPy
from expdpy.data import load_kuznets, load_kuznets_data_def, get_config
ExPdPy(
load_kuznets(),
df_def=load_kuznets_data_def(), # identifies the panel dimensions (country x year)
config_list=get_config("kuznets"), # opens on the N-shaped Kuznets curve
)This opens a browser with a sidebar (sample, subset filter, outlier treatment, save/load config, notebook export) and a stack of analysis cards: descriptive statistics, histogram, extreme observations, correlations, time trends, scatter plot, by-group views and a regression builder.
Cross-sectional data
If you do not provide a time-series identifier, the time-trend components are dropped. For example, a single year of kuznets is cross-sectional:
ExPdPy(load_kuznets().query("year == 2025")) # no ts_id -> cross-sectionalStarting from an upload dialog
Call ExPdPy() with no data to start with an in-app file upload (CSV/Excel/parquet):
ExPdPy()Reproducible export
The Export notebook + data button downloads a zip containing the prepared analysis sample (parquet) plus a Jupyter notebook and a .py script that recreate every displayed component with expdpy calls — so an analysis done in the app can be reproduced in code.
Saving configurations
Save config downloads the current analysis configuration as JSON (optionally encrypted when store_encrypted=True); Load config restores it. You can also pass a configuration at launch:
from expdpy.data import load_kuznets, load_kuznets_data_def, get_config
ExPdPy(
load_kuznets(),
df_def=load_kuznets_data_def(),
config_list=get_config("kuznets"),
)Customizing the app
Selecting and ordering components
The components argument controls which analysis cards appear and in what order. Pass a list (order matters) or a {name: bool} mapping:
from expdpy.app import ExPdPy
from expdpy.data import load_kuznets, load_kuznets_data_def
ExPdPy(
load_kuznets(),
df_def=load_kuznets_data_def(),
components=["descriptive_table", "scatter_plot", "regression"],
)The available component names are:
bar_chart, missing_values, descriptive_table, histogram, ext_obs, by_group_bar_graph, by_group_violin_graph, trend_graph, quantile_trend_graph, by_group_trend_graph, corrplot, scatter_plot, regression.
(Time-series components are automatically dropped for cross-sectional data.)
Advanced mode — building analysis variables
Provide a var_def frame to compute the analysis sample from the base data. Each row’s var_def is a safe expression (column references plus + - * / ** %, comparisons, & |, and the functions isna, exp, log, lag, lead). lag/lead are panel-aware (they shift within cs_id groups ordered by ts_id).
import pandas as pd
from expdpy.app import ExPdPy
from expdpy.data import load_kuznets, load_kuznets_data_def
var_def = pd.DataFrame(
{
"var_name": ["country", "year", "gdp_pc_growth"],
"var_def": ["country", "year", "(gdp_pc - lag(gdp_pc, 1)) / lag(gdp_pc, 1)"],
"type": ["cs_id", "ts_id", "numeric"],
"can_be_na": [False, False, True],
}
)
ExPdPy(load_kuznets(), df_def=load_kuznets_data_def(), var_def=var_def)Expressions are evaluated with a restricted AST walker — never eval/exec. Attribute access, subscripting, lambdas and imports are rejected, which is strictly safer than R’s sandboxed eval.
Disabling app features
ExPdPy(
load_kuznets(),
df_def=load_kuznets_data_def(),
export_nb_option=False, # hide notebook export
save_settings_option=False, # hide config save/load
)