Skip to content
Closed
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
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,25 @@
- Columns that are explicitly mentioned — the id column, weight column,
covariate columns, and outcome columns — are **not** ignored.

## New Features

- **ASCII comparative histogram (`ascii_comparative_hist`)**
- Added a new plot function that compares multiple distributions against a
baseline using inline visual indicators: `█` for shared mass, `▒` for excess,
and `]` for deficit relative to the baseline. Uses visually distinct fill
characters (`█`, `▒`, `▐`, `░`) for better readability when comparing
multiple datasets.

## Documentation

- **ASCII plot docstring examples and `library="balance"` docs**
- Added rendered text-plot examples to `ascii_plot_bar`, `ascii_plot_hist`,
and `ascii_plot_dist` docstrings. Documented that `library="balance"` only
supports `dist_type="hist_ascii"` in `plot_dist()` and `BalanceDF.plot()`.
- **Updated quickstart tutorial with ASCII plot examples**
- Added cells to `balance_quickstart.ipynb` showing adjusted vs unadjusted
ASCII plots, including numeric variable histograms and comparative
histograms.
- **Improved `keep_columns` documentation**
- Updated docstrings for `has_keep_columns()`, `keep_columns()`, and the
`--keep_columns` argument to clarify that keep columns control which columns
Expand All @@ -28,6 +45,10 @@

## Tests

- **Added end-to-end adjustment test with ASCII plot output**
- `TestAsciiPlotsAdjustmentEndToEnd` runs the full `Sample.from_frame()` →
`set_target()` → `adjust()` → `covars().plot(library="balance")` pipeline
and asserts exact expected ASCII output.
- **Expanded warning coverage for `Sample.from_frame()` ID inference**
- Added assertions that validate all three expected warnings are emitted when inferring an `id` column and default weights, including ID guessing, ID string casting, and automatic weight creation.
- **Added focused unit coverage for IPW helpers**
Expand Down
14 changes: 10 additions & 4 deletions balance/balancedf_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,11 +618,13 @@ def plot(
self: "BalanceDF",
on_linked_samples: bool = True,
**kwargs: Any,
) -> list[Any] | npt.NDArray[Any] | dict[str, Figure] | None:
) -> list[Any] | npt.NDArray[Any] | dict[str, Figure] | str | None:
"""Plots the variables in the df of the BalanceDF object.

See :func:`weighted_comparisons_plots.plot_dist` for details of various arguments that can be passed.
The default plotting engine is plotly, but seaborn can be used for static plots.
The default plotting engine is plotly, but seaborn can be used for static plots, or "balance"
can be used for ASCII text output suitable for LLM consumption (only dist_type="hist_ascii" is supported
with library="balance").

This function is inherited as is when invoking BalanceDFCovars.plot, but some modifications are made when
preparing the data for BalanceDFOutcomes.plot and BalanceDFWeights.plot.
Expand All @@ -634,9 +636,10 @@ def plot(
**kwargs: passed to :func:`weighted_comparisons_plots.plot_dist`.

Returns:
Union[Union[List, np.ndarray], Dict[str, Figure], None]:
Union[Union[List, np.ndarray], Dict[str, Figure], str, None]:
If library="plotly" then returns a dictionary containing plots if return_dict_of_figures is True. None otherwise.
If library="seaborn" then returns None, unless return_axes is True. Then either a list or an np.array of matplotlib axis.
If library="balance" then returns a string with the ASCII text output.

Examples:
.. code-block:: python
Expand Down Expand Up @@ -680,6 +683,9 @@ def plot(

# Returning plotly qq plots:
s3_null.covars().plot(dist_type = "qq")

# ASCII text output (suitable for LLM consumption):
s3_null.covars().plot(library = "balance", dist_type = "hist_ascii")
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

The example shows passing dist_type="hist_ascii" when using library="balance", but the implementation does not validate or use the dist_type parameter for the balance library. The ascii_plot_dist function automatically chooses between histogram and barplot based on variable type and doesn't accept a dist_type parameter.

Either remove the dist_type="hist_ascii" from this example, or add validation in the plot_dist function to warn/error when dist_type is passed with library="balance" since it's ignored.

Suggested change
s3_null.covars().plot(library = "balance", dist_type = "hist_ascii")
s3_null.covars().plot(library = "balance")

Copilot uses AI. Check for mistakes.
"""
if on_linked_samples:
dfs_to_add = self._BalanceDF_child_from_linked_samples()
Expand Down Expand Up @@ -2522,7 +2528,7 @@ def df(self: "BalanceDFWeights") -> pd.DataFrame:
# TODO: maybe add better control if there are no weights for unadjusted or target (the current default shows them in the legend, but not in the figure)
def plot(
self: "BalanceDFWeights", on_linked_samples: bool = True, **kwargs: Any
) -> list[Any] | npt.NDArray[Any] | dict[str, Figure] | None:
) -> list[Any] | npt.NDArray[Any] | dict[str, Figure] | str | None:
"""Plots kde (kernal density estimation) of the weights in a BalanceDFWeights object using seaborn (as default).

It's possible to use other plots using dist_type with arguments such as "hist", "kde" (default), "qq", and "ecdf".
Expand Down
Loading