diff --git a/plots.py b/plots.py index 5abf602..066f8b5 100644 --- a/plots.py +++ b/plots.py @@ -98,7 +98,11 @@ class QualtricsPlotsMixin: return "_".join(parts) def _get_filter_description(self) -> str: - """Generate a human-readable description of active filters.""" + """Generate a human-readable description of active filters. + + Includes sample size (from _last_sample_size) prepended to the filter text. + Format: "Sample size: | Filters: ..." or "Sample size: " if no filters. + """ parts = [] # Mapping of attribute name to (display_name, value, options_attr) @@ -137,12 +141,21 @@ class QualtricsPlotsMixin: val_str = ", ".join(clean_values) # Use UPPERCASE for category name to distinguish from values parts.append(f"{display_name.upper()}: {val_str}") - + + # Get sample size (stored by _ensure_dataframe) + sample_size = getattr(self, '_last_sample_size', None) + sample_prefix = f"Sample size: {sample_size}" if sample_size is not None else "" + if not parts: - return "" + # No filters active - return just sample size (or empty string if no sample size) + return sample_prefix # Join with clear separator - double space for visual break - return "Filters: " + " — ".join(parts) + filter_text = "Filters: " + " — ".join(parts) + + if sample_prefix: + return f"{sample_prefix} | {filter_text}" + return filter_text def _add_filter_footnote(self, chart: alt.Chart) -> alt.Chart: """Add a footnote with active filters to the chart. @@ -248,13 +261,19 @@ class QualtricsPlotsMixin: return chart def _ensure_dataframe(self, data: pl.LazyFrame | pl.DataFrame | None) -> pl.DataFrame: - """Ensure data is an eager DataFrame, collecting if necessary.""" + """Ensure data is an eager DataFrame, collecting if necessary. + + Also stores the sample size on self._last_sample_size for use in filter descriptions. + """ df = data if data is not None else getattr(self, 'data_filtered', None) if df is None: raise ValueError("No data provided and self.data_filtered is None.") if isinstance(df, pl.LazyFrame): - return df.collect() + df = df.collect() + + # Store sample size for filter description + self._last_sample_size = df.height return df def _clean_voice_label(self, col_name: str) -> str: