:::note Generated reference Generated from honeyframeapi 0.1.8 — do not edit by hand. :::
honeyframeapi.statistics
Statistics worksheets — run the EDA cards from code.
A Honeyframe dataset's Statistics tab hosts persisted worksheets of analysis cards. This module is the same surface for a notebook or a script: one method per card type, computed against the dataset's real data by the platform (Postgres warehouse datasets run on the app session, uploaded-file datasets on DuckDB over their Parquet — identical SQL either way).
ds = client.get_project(1).get_dataset("fact_orders")
ds.statistics.univariate("age") # summary + histogram
ds.statistics.correlation(["age", "order_value", "cost"])
ds.statistics.ttest_2samp("order_value", "store_key") # Welch
ds.statistics.pca(["age", "order_value", "cost"], n_components=2)
Every card is also reachable generically, which is what you want when the card type is itself data (a sweep over a config table):
for spec in my_cards:
ds.statistics.compute(spec["type"], **spec["params"])
A worksheet is the persisted version — the same rows the Statistics tab shows, so a worksheet built here is editable in the UI and vice versa:
ws = ds.statistics.create_worksheet("Length-of-stay EDA")
ws.add_card("univariate", column="order_value")
ws.add_card("anova_1way", column="order_value", group="store_key")
for entry in ws.compute_all():
print(entry["card"]["type"], entry["result"])
The 17 card types, exactly as the platform's CARD_TYPES defines them, are in
CARD_TYPES. An unknown type raises ValueError here rather than
costing a 400 round-trip; the per-card methods below document each one's
parameters and result keys.
Two honest limits worth knowing before you build on this:
- Worksheets only exist on a migrated tenant. The platform degrades a
missing
honeyframe.dataset_worksheetstable to an empty list, soDatasetStatistics.list_worksheetsreturning[]can mean "none yet" or "this install has not run the worksheet migration". Ad-hocDatasetStatistics.computeneeds no table and works either way. - Warehouse + uploaded-file datasets only in v1. A lakehouse or external
connector dataset raises
HoneyframeValidationErrorcarrying the platform's reason — it never silently returns a partial answer.
Backed by /api/statistics. Docs: https://docs.honeyframe.io/
class DatasetStatistics
DatasetStatistics(dataset)
The statistics surface of one dataset: ad-hoc cards + saved worksheets.
Reached as dataset.statistics; holds no state of its own, so it is free
to construct.
DatasetStatistics.list_worksheets()
list_worksheets() -> list
Saved worksheets for this dataset, oldest first.
An empty list can also mean the install has not run the worksheet
migration — the platform degrades a missing table to [] so the
Statistics tab still reads correctly.
DatasetStatistics.create_worksheet()
create_worksheet(name: str = 'Worksheet 1') -> StatisticsWorksheet
Create an empty worksheet on this dataset and return its handle.
DatasetStatistics.get_worksheet()
get_worksheet(worksheet_id: int) -> StatisticsWorksheet
Return a worksheet handle. Cards are fetched on first use (there is no per-worksheet GET — the handle reads through the list endpoint).
DatasetStatistics.compute()
compute(card_type: str, **params: Any) -> dict
Compute any card type against this dataset, without saving it.
card_type must be one of CARD_TYPES — a typo raises
ValueError here. params are the card's own parameters; the
typed methods below are thin wrappers over this call and document them.
Unrecognised parameters are forwarded as-is, so a parameter the platform
gains later needs no SDK release.
DatasetStatistics.compute_config()
compute_config(card: dict) -> dict
Compute a {type, params} (or {id, type, params}) card config —
the stored shape, so a worksheet card round-trips through this.
DatasetStatistics.univariate()
univariate(column: str) -> dict
One column's summary — any type.
Returns {type, column, numeric, stats} with stats =
{count, non_null, nulls, distinct} plus {min, max, avg, stddev}
when the column is numeric. Numeric columns also carry histogram
(20 equal-width bins: {bucket, low, high, count}); non-numeric ones
carry topk ({value, count}, top 20). Values the caller is not
cleared to see are masked by the platform, never dropped.
DatasetStatistics.correlation()
correlation(columns: list) -> dict
Pairwise Pearson correlation across 2–12 numeric columns.
Returns {type, columns, matrix} — matrix is the full symmetric
square (diagonal 1.0); a pair with no overlapping non-null rows is
None, not 0.
DatasetStatistics.scatter_fit()
scatter_fit(x: str, y: str) -> dict
Two numeric columns with a least-squares line.
Returns {type, x, y, points, sampled, fit}; fit =
{slope, intercept, r, n} is computed from SQL regr_* aggregates
over every row, while points is capped at the first 2,000 rows
the engine returns — so sampled=True means the plotted points are
partial (and unordered, not a random draw), while the fit is not.
DatasetStatistics.quantile_table()
quantile_table(columns: list) -> dict
Quantiles per numeric column (up to 12 columns).
Returns {type, columns, quantiles, values} — quantiles is the
probability grid the platform uses (0, .05, .25, .5, .75, .95, .99, 1)
and values[i][j] is columns[i] at quantiles[j].
DatasetStatistics.cdf_plot()
cdf_plot(column: str) -> dict
Empirical cumulative distribution of one numeric column.
Returns {type, column, points, method} — points is
[[value, probability], …] on a 100-step percentile grid.
DatasetStatistics.fit_distribution()
fit_distribution(column: str) -> dict
Normal + lognormal fit overlaid on the histogram.
Returns {type, column, n, total, bins, bin_width, normal, lognormal, ks_note}. Each bin carries the observed count and the fitted
normal (and lognormal) expected count. lognormal is None
when the column is not strictly positive — the platform omits the fit
rather than inventing one. Compare fits by ks_distance (lower is
better).
DatasetStatistics.shapiro_wilk()
shapiro_wilk(column: str) -> dict
Shapiro-Wilk normality test (Royston 1992 / AS R94).
Returns {type, column, available, …}. When available is True:
{w, p, n, sampled, note, method} — over 5,000 non-null values the
test runs on a random 5,000-value subsample (sampled=True, with
note saying so) because the approximation is only valid there. When
False, reason says why — an honest unavailable result, never a
fabricated statistic. Check available before reading p.
DatasetStatistics.chi2_independence_test()
chi2_independence_test(column_a: str, column_b: str) -> dict
Chi-square test of independence between two categorical columns.
Returns {type, column_a, column_b, row_levels, col_levels, table, chi2, p, dof, …}. Low-cardinality only (≤50 levels per dimension);
a wider pair is a validation error naming the cap. Level labels are
masked per the caller's identity; the statistic is computed on the raw
levels.
DatasetStatistics.ttest_2samp()
ttest_2samp(column: str, group: str) -> dict
Welch two-sample t-test of column across exactly 2 groups.
Returns {type, column, group, groups, t, df, p} — groups is
[{name, n, mean, var}, …]. A grouping column with any count other
than 2 distinct values is a validation error listing what was found.
DatasetStatistics.mann_whitney_u()
mann_whitney_u(column: str, group: str) -> dict
Mann-Whitney U (Wilcoxon rank-sum) — the non-parametric counterpart
of ttest_2samp, also exactly 2 groups.
Returns {type, column, group, groups, u, p, n1, n2, sampled, small_sample, …}. small_sample=True flags that the normal
approximation is rough at this n — the platform surfaces it rather than
hiding it; sampled=True means a per-group cap (10,000 values) was
hit.
DatasetStatistics.paired_ttest()
paired_ttest(column_x: str, column_y: str) -> dict
Paired (dependent-samples) t-test over two numeric columns measured on the same rows.
Returns {type, column_x, column_y, available, …} — when
available is True: {t, p, n, mean_diff, sampled, …}. Rows where
either column is NULL are dropped as incomplete pairs; fewer than 2
complete pairs comes back available=False with a reason.
DatasetStatistics.anova_1way()
anova_1way(column: str, group: str) -> dict
One-way ANOVA — does column's mean differ across the groups?
Returns {type, column, group, groups, groups_cap, f, p, df_between, df_within, …}; groups is [{name, n, mean, var}, …]. Needs 2–50
groups (groups_cap); a higher-cardinality grouping column is a
validation error, not a 50-row truncation.
DatasetStatistics.levene_test()
levene_test(column: str, group: str) -> dict
Levene's test for equal variance, Brown-Forsythe (median-centered).
Returns {type, column, group, groups, groups_cap, sampled, center, w, p, df_between, df_within, k, n_total}. Run it before leaning on a
test that assumes equal variances — anova_1way's F-test.
DatasetStatistics.ks_test_2samp()
ks_test_2samp(column: str, group: str) -> dict
Two-sample Kolmogorov-Smirnov test — distribution shape across exactly 2 groups (where the t-test compares only means).
Returns {type, column, group, groups, sampled, d, p, n1, n2, …}.
sampled=True means a pull/per-group cap was reached, so d is
over a sample.
DatasetStatistics.acf_plot()
acf_plot(date_column: str, value_column: str, *, agg: str = 'sum', max_lag: Optional[int] = None) -> dict
Autocorrelation of a daily-resampled series.
agg ∈ AGGREGATIONS is how rows collapse per calendar day.
sum/count zero-fill missing days (a day with no rows genuinely
measures 0); avg drops them (a missing day has no average, and
zero-filling would fabricate a downward trend) — gap_filled reports
how many were filled. max_lag is clamped server-side to 1–30.
Returns {type, date_column, value_column, agg, n, gap_filled, conf, acf, range} — conf is the ±95% white-noise band, so a lag matters
when abs(acf[lag]) > conf.
DatasetStatistics.mann_kendall_test()
mann_kendall_test(date_column: str, value_column: str, *, agg: str = 'sum') -> dict
Mann-Kendall monotonic-trend test on a daily-resampled series.
Same agg resampling (and gap-filling rule) as acf_plot.
Returns {type, date_column, value_column, agg, gap_filled, range, trend, s, z, p, tau, …}. The p-value is the method's own normal
approximation — labelled as such by the platform, not presented as
exact.
DatasetStatistics.pca()
pca(columns: list, *, n_components: Optional[int] = None, standardize: bool = True, color_by: Optional[str] = None) -> dict
Principal Component Analysis over 2–12 numeric columns.
n_components defaults to min(5, len(columns)) server-side and
may not exceed the column count. standardize=True (the default)
runs the decomposition on the correlation matrix — leave it on when the
columns are in different units, or the largest-scale column dominates
PC1. color_by tints the projection by another column's value.
Returns {type, columns, color_by, n_total, dropped_nulls, sampled, constant_columns, points, point_colors, points_sampled, n_components, n_columns, standardize, total_variance, explained_variance, explained_variance_ratio, cumulative_variance_ratio, loadings, center, scale}.
Rows with a NULL in any selected column are excluded — dropped_nulls
says how many. points is the PC1×PC2 projection and is empty at
n_components=1 (there is no PC2; a flat line would read as real
structure). constant_columns names zero-variance columns, which
carry no information into the fit.
class StatisticsWorksheet
StatisticsWorksheet(statistics: DatasetStatistics, worksheet_id: int, *, name: str = '', cards: Optional[list] = None, _data: Optional[dict] = None)
A saved worksheet: an ordered list of {id, type, params} cards.
The same rows the dataset's Statistics tab reads, so a worksheet authored
here opens in the UI (and edits made there show up on reload).
Results are never stored — compute_all recomputes against live
data.
StatisticsWorksheet.reload()
reload() -> StatisticsWorksheet
Re-read this worksheet through the dataset's list endpoint (there is
no per-worksheet GET). Raises ValueError when the id is not on
this dataset — including after someone else deleted it.
StatisticsWorksheet.cards
property
cards: list
The stored card configs, in worksheet order (fetched on first use).
StatisticsWorksheet.get_card()
get_card(card_id: str) -> dict
One stored card config by its id.
StatisticsWorksheet.rename()
rename(name: str) -> StatisticsWorksheet
Rename the worksheet (truncated to 200 chars server-side).
StatisticsWorksheet.set_cards()
set_cards(cards: list) -> StatisticsWorksheet
Replace the whole card list. Every card is validated here first, so a bad type cannot overwrite a good worksheet with a rejected write.
Accepts configs from stat_card (or any {id, type, params}
dict); a card without an id gets a fresh uuid4 so the UI and
remove_card can address it.
StatisticsWorksheet.add_card()
add_card(card_type: str, **params: Any) -> dict
Append one card and persist the worksheet. Returns the new card
config (its id is what compute_card takes).
StatisticsWorksheet.update_card()
update_card(card_id: str, **params: Any) -> dict
Replace a stored card's parameters (the type is unchanged) and persist. Returns the updated config.
StatisticsWorksheet.remove_card()
remove_card(card_id: str) -> StatisticsWorksheet
Remove one card by id and persist. Raises when no card has that id — a silent no-op would read as a successful delete.
StatisticsWorksheet.delete()
delete() -> None
Delete the worksheet and its card configs.
StatisticsWorksheet.compute_card()
compute_card(card_id: str) -> dict
Compute one stored card against live data.
StatisticsWorksheet.compute_all()
compute_all() -> list
Compute every card, in worksheet order.
Returns [{"card": <config>, "result": <payload>}, …]. A card the
platform rejects (too-high cardinality, a dropped column) raises — the
error names the card's own reason, and swallowing it would hand back a
worksheet that looks complete. Use compute_card per card when
you want to continue past one.
Functions
validate_card_type()
validate_card_type(card_type: Any) -> str
Return card_type if the platform has such a card, else raise.
Raises ValueError naming the nearest match and the full list — a
typo is a local failure, not a 400 from the server.
validate_card()
validate_card(card_type: Any, params: Optional[dict] = None) -> str
Validate a card type + its parameters client-side. Returns the type.
Checks the type against CARD_TYPES, that every required parameter is
present and non-empty, the structural columns minimums, and agg
against AGGREGATIONS. Everything else is left to the server, which
owns the column/type/cardinality rules and reports them with real numbers.
stat_card()
stat_card(card_type: str, **params: Any) -> dict
Build one validated worksheet-card config: {id, type, params}.
The id is a fresh uuid4 — the same shape the Statistics tab generates —
and is what StatisticsWorksheet.remove_card and
StatisticsWorksheet.compute_card address a card by. Use this when
writing a whole worksheet at once with
StatisticsWorksheet.set_cards.
Constants
| Name | Value |
|---|---|
AGGREGATIONS | ('sum', 'avg', 'count') |
Verified against honeyframeapi 0.1.8.