diff --git a/analytics/analytics_package/analytics/static_site/README.md b/analytics/analytics_package/analytics/static_site/README.md index 98166245e..7ce6ee676 100644 --- a/analytics/analytics_package/analytics/static_site/README.md +++ b/analytics/analytics_package/analytics/static_site/README.md @@ -52,9 +52,9 @@ For apps with dataset/project detail tables, a `title_resolver` callback enriche ├── config.json ├── meta.json ├── monthly_traffic.json - ├── pageviews.json - ├── outbound_links.json - ├── filter_selected.json + ├── pageviews.json # top 100 rows + ├── outbound_links.json # top 100 rows + ├── filter_selected.json # top 100 rows ├── file_downloads.json ├── custom_events.json ├── access_requests.json # AnVIL only diff --git a/analytics/analytics_package/analytics/static_site/export.py b/analytics/analytics_package/analytics/static_site/export.py index 3920743fa..28791ddc2 100644 --- a/analytics/analytics_package/analytics/static_site/export.py +++ b/analytics/analytics_package/analytics/static_site/export.py @@ -19,8 +19,16 @@ ) from .fetch import event_key +# Row cap for the exports the template renders as a fixed slice (top 20 +# pageviews and outbound links, top 30 filter selections); 100 leaves headroom +# for UI changes while keeping page-load payloads and monthly regen diffs +# bounded (e.g. AnVIL Portal shipped 1,810 pageviews rows). Event detail tables, +# access requests and search queries stay uncapped on purpose — the template +# renders every one of their rows. +MAX_TABLE_EXPORT_ROWS = 100 -def export_df_as_json(df, col_map, change_col, filename, output_dir): + +def export_df_as_json(df, col_map, change_col, filename, output_dir, max_rows=None): """Export a DataFrame to JSON with column renaming and NaN handling. Args: @@ -29,7 +37,13 @@ def export_df_as_json(df, col_map, change_col, filename, output_dir): change_col: Source column name for the change metric (may be absent). filename: Output JSON filename. output_dir: Output directory. + max_rows: Maximum number of rows to export; the top rows are kept, so + df is expected to be sorted by relevance. None exports all rows. """ + total_rows = 0 if df is None else len(df) + if max_rows is not None and total_rows > max_rows: + df = df.head(max_rows) + print(f" Capped {filename} at top {max_rows} of {total_rows} rows") if df is None or len(df) == 0: records = [] else: @@ -96,6 +110,7 @@ def export_data(data, config, current_month, analytics_start, custom_events, out METRIC_PAGE_VIEWS["change_alias"], "pageviews.json", output_dir, + max_rows=MAX_TABLE_EXPORT_ROWS, ) print("Exporting outbound links data...") @@ -105,6 +120,7 @@ def export_data(data, config, current_month, analytics_start, custom_events, out SYNTHETIC_METRIC_CLICKS["change_alias"], "outbound_links.json", output_dir, + max_rows=MAX_TABLE_EXPORT_ROWS, ) print("Exporting filter selections data...") @@ -114,6 +130,7 @@ def export_data(data, config, current_month, analytics_start, custom_events, out METRIC_EVENT_COUNT["change_alias"], "filter_selected.json", output_dir, + max_rows=MAX_TABLE_EXPORT_ROWS, ) # File downloads