diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Combo_Data_Labels_Auto_Compactness_Propagates_From_Line.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Combo_Data_Labels_Auto_Compactness_Propagates_From_Line.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ca7b9e96f48ffca375fcb224c3af927d728668 Binary files /dev/null and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Combo_Data_Labels_Auto_Compactness_Propagates_From_Line.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Combo_Data_Labels_Auto_Compactness_Propagates_From_Totals.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Combo_Data_Labels_Auto_Compactness_Propagates_From_Totals.png new file mode 100644 index 0000000000000000000000000000000000000000..a29f4c1f4539bb1be5e14407653e6beaf26974ba Binary files /dev/null and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Combo_Data_Labels_Auto_Compactness_Propagates_From_Totals.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Auto_Y_Axis_Exclude_Zero_With_Goal.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Auto_Y_Axis_Exclude_Zero_With_Goal.png index d7cf26ae4c2f5eb7b9e67667902258981fed1d7e..817205b9109ce76ba9c9de0065001f7ec59d5f57 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Auto_Y_Axis_Exclude_Zero_With_Goal.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Auto_Y_Axis_Exclude_Zero_With_Goal.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Bubble_Size.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Bubble_Size.png index 3b6c9a55aef71a974e8ecc5b48cd518103e08225..72c12fd24e819567a9c069f5ffcb7e0476b5f2be 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Bubble_Size.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Bubble_Size.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range.png index b6171cbca9421f10ceb70de20b33418cedc2a6f0..fec9a41274f0c141e3453b6f67e74b932ab7baf9 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range_With_Column_Scaling.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range_With_Column_Scaling.png index aa99581b6449fdd59442fc51b5ac90dbf63ab568..9e9050ba17f143b4876eb7d30cd75fafd88558e3 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range_With_Column_Scaling.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Custom_Y_Axis_Range_With_Column_Scaling.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Default.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Default.png index a1dd32200b21564b1e4c368d04ddc7195fdd2f52..47a3e1cf90211839a726eb2d0bbeef921036255a 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Default.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Default.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Goal_Line.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Goal_Line.png index 0004430a8f9e10743b70f339948383a0bf268139..74ff856b52fca4e7c2a05760060aecedef5de120 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Goal_Line.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Goal_Line.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Histogram_X_Scale.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Histogram_X_Scale.png index c0143dc5d8c8909b90dc464ab9c61b482dac9883..28c0c2eea028fd7612592f3dccf52da3b18d542c 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Histogram_X_Scale.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Histogram_X_Scale.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale.png index 276e32158b1af1c062f2bc8273182b9a0161298d..d89d7561e24698ad70ab5c2c3299c7cd04593383 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale_At_One.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale_At_One.png index bcd2eea965b1039fbe39a051381eea4c23d31b08..925ff52be6efe85c224b6efc8ad44b1babea1498 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale_At_One.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Log_X_Scale_At_One.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout.png index f13497bb6a0be2dc9055f3f9edd37f6f05981aba..1dfc079918bec92322cd667b62a5abfec3095779 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout_Bubble_Size.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout_Bubble_Size.png index fc6c2da5149dda6eaa94855dea2b90a1aa073e33..1f302631555245a282420a79946d3672b6f2ca75 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout_Bubble_Size.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Dimension_Breakout_Bubble_Size.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Metric_Series.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Metric_Series.png index b0df2c704a8d223355d4265dce793363245458e4..e3497dec04108437ecbb21a54dee584479786283 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Metric_Series.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Multi_Metric_Series.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Ordinal_X_Scale.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Ordinal_X_Scale.png index 619c43d0ff7db38afc0529a12bd3060f8f2f0dd0..ebbadd64d2243e959d75b8cf3c1ef7ad6367319d 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Ordinal_X_Scale.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Ordinal_X_Scale.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale.png index 11a9cd2c90e9f55bd354888e519294c9e1fb656a..7a5db44ff5e9686b7a5d284830a13a14cf10e3b3 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale_Multi_Series.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale_Multi_Series.png index bb632f931ca851f2cbc52e8c831aaa6e4840fe6e..378c1b8f1f691a01c95ec746a1d7f2e0a8cfca9b 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale_Multi_Series.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Power_X_Scale_Multi_Series.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Timeseries_X_Scale.png b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Timeseries_X_Scale.png index 92a43880ef02625c0933bc40eec5f0dc0f617f1f..ed4f2f0d115168f6b0a0b67a26ed030d428f0a84 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Timeseries_X_Scale.png and b/.loki/reference/chrome_laptop_static_viz_ScatterPlot_Timeseries_X_Scale.png differ diff --git a/.loki/reference/chrome_laptop_viz_LineChart_Embedding_Huge_Font.png b/.loki/reference/chrome_laptop_viz_LineChart_Embedding_Huge_Font.png index 14b197ab2b87b64bd1a0aaa417f41c5bd90814f0..a313f12bc813a6a5e4df116c6985639e52de4cf2 100644 Binary files a/.loki/reference/chrome_laptop_viz_LineChart_Embedding_Huge_Font.png and b/.loki/reference/chrome_laptop_viz_LineChart_Embedding_Huge_Font.png differ diff --git a/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx b/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx index c263d901d40cb7b38d9d00f6cba6a54976fe8103..92f5f30ec57d50810f4022f95b7a17d76a486bde 100644 --- a/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx +++ b/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx @@ -769,6 +769,24 @@ BarMinHeightLimit.args = { renderingContext, }; +export const ComboDataLabelsAutoCompactnessPropagatesFromLine = Template.bind( + {}, +); +ComboDataLabelsAutoCompactnessPropagatesFromLine.args = { + rawSeries: data.comboDataLabelsAutoCompactnessPropagatesFromLine as any, + dashcardSettings: {}, + renderingContext, +}; + +export const ComboDataLabelsAutoCompactnessPropagatesFromTotals = Template.bind( + {}, +); +ComboDataLabelsAutoCompactnessPropagatesFromTotals.args = { + rawSeries: data.comboDataLabelsAutoCompactnessPropagatesFromTotals as any, + dashcardSettings: {}, + renderingContext, +}; + export const Default = Template.bind({}); Default.args = { rawSeries: data.messedUpAxis as any, diff --git a/frontend/src/metabase/static-viz/components/ComboChart/settings.ts b/frontend/src/metabase/static-viz/components/ComboChart/settings.ts index 354575281b379e72e92d56774f3f1f1b3cc9cdc7..12fad5b230c92085d8ff9de3e8db7dc65e7fc719 100644 --- a/frontend/src/metabase/static-viz/components/ComboChart/settings.ts +++ b/frontend/src/metabase/static-viz/components/ComboChart/settings.ts @@ -34,6 +34,7 @@ import { isXAxisScaleValid, isYAxisUnpinFromZeroValid, isShowStackValuesValid, + getDefaultDataLabelsFormatting, } from "metabase/visualizations/shared/settings/cartesian-chart"; import { SERIES_COLORS_SETTING_KEY, @@ -202,6 +203,12 @@ export const computeStaticComboChartSettings = ( isShowStackValuesValid(seriesDisplays, settings), ); + fillWithDefaultValue( + settings, + "graph.label_value_formatting", + getDefaultDataLabelsFormatting(), + ); + fillWithDefaultValue( settings, "graph.series_order", diff --git a/frontend/src/metabase/static-viz/components/ComboChart/stories-data/combo-data-labels-auto-compactness-propagates-from-line.json b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/combo-data-labels-auto-compactness-propagates-from-line.json new file mode 100644 index 0000000000000000000000000000000000000000..97da15283e053092b9ff384f9dbc51618f97ffb3 --- /dev/null +++ b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/combo-data-labels-auto-compactness-propagates-from-line.json @@ -0,0 +1,393 @@ +[ + { + "card": { + "original_card_id": 370, + "public_uuid": null, + "parameter_usage_count": 0, + "created_at": "2024-06-05T04:03:11.645973Z", + "parameters": [], + "metabase_version": "v0.1.7-SNAPSHOT (cc8afe3)", + "collection": { + "metabase.models.collection.root/is-root?": true, + "authority_level": null, + "name": "Our analytics", + "is_personal": false, + "id": "root", + "can_write": true + }, + "visualization_settings": { + "stackable.stack_type": "stacked", + "graph.show_values": true, + "graph.label_value_formatting": "auto", + "series_settings": { + "Y3_LINE_FULL": { + "display": "line" + }, + "Y3_LINE_COMPACT": { + "display": "line" + } + }, + "graph.show_stack_values": "series", + "graph.dimensions": ["X"], + "graph.metrics": ["Y1_FULL", "Y2_FULL", "Y3_LINE_COMPACT"] + }, + "collection_preview": true, + "entity_id": "mPZpZ2XzGAebGrZ17iiYp", + "display": "bar", + "parameter_mappings": [], + "id": 370, + "dataset_query": { + "database": 1, + "type": "native", + "native": { + "template-tags": {}, + "query": "select 'foo' x, 500000 y1_full, 500000 y2_full, 1000000 y3_line_compact\nunion all select 'bar', 500000, 500000, 1000000\nunion all select 'baz', 500000, 500000, 1000000\n\n" + } + }, + "cache_ttl": null, + "embedding_params": null, + "made_public_by_id": null, + "updated_at": "2024-06-05T04:03:11.645973Z", + "moderation_reviews": [], + "creator_id": 1, + "average_query_time": null, + "type": "question", + "last_used_at": null, + "dashboard_count": 0, + "last_query_start": null, + "name": "line compact formatting propagates to stack", + "query_type": "native", + "collection_id": null, + "enable_embedding": false, + "database_id": 1, + "trashed_from_collection_id": null, + "can_write": true, + "initially_published_at": null, + "result_metadata": [ + { + "display_name": "X", + "field_ref": [ + "field", + "X", + { + "base-type": "type/Text" + } + ], + "name": "X", + "base_type": "type/Text", + "effective_type": "type/Text", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 3, + "nil%": 0 + }, + "type": { + "type/Text": { + "percent-json": 0, + "percent-url": 0, + "percent-email": 0, + "percent-state": 0, + "average-length": 3 + } + } + } + }, + { + "display_name": "Y1_FULL", + "field_ref": [ + "field", + "Y1_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y1_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 500000, + "q1": 500000, + "q3": 500000, + "max": 500000, + "sd": 0, + "avg": 500000 + } + } + } + }, + { + "display_name": "Y2_FULL", + "field_ref": [ + "field", + "Y2_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y2_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 500000, + "q1": 500000, + "q3": 500000, + "max": 500000, + "sd": 0, + "avg": 500000 + } + } + } + }, + { + "display_name": "Y3_LINE_COMPACT", + "field_ref": [ + "field", + "Y3_LINE_COMPACT", + { + "base-type": "type/Integer" + } + ], + "name": "Y3_LINE_COMPACT", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 1000000, + "q1": 1000000, + "q3": 1000000, + "max": 1000000, + "sd": 0, + "avg": 1000000 + } + } + } + } + ], + "can_run_adhoc_query": true, + "table_id": null, + "collection_position": null, + "view_count": 0, + "archived": false, + "description": null, + "cache_invalidated_at": null, + "displayIsLocked": true + }, + "data": { + "rows": [ + ["foo", 500000, 500000, 1000000], + ["bar", 500000, 500000, 1000000], + ["baz", 500000, 500000, 1000000] + ], + "cols": [ + { + "display_name": "X", + "source": "native", + "field_ref": [ + "field", + "X", + { + "base-type": "type/Text" + } + ], + "name": "X", + "base_type": "type/Text", + "effective_type": "type/Text" + }, + { + "display_name": "Y1_FULL", + "source": "native", + "field_ref": [ + "field", + "Y1_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y1_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer" + }, + { + "display_name": "Y2_FULL", + "source": "native", + "field_ref": [ + "field", + "Y2_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y2_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer" + }, + { + "display_name": "Y3_LINE_COMPACT", + "source": "native", + "field_ref": [ + "field", + "Y3_LINE_COMPACT", + { + "base-type": "type/Integer" + } + ], + "name": "Y3_LINE_COMPACT", + "base_type": "type/Integer", + "effective_type": "type/Integer" + } + ], + "native_form": { + "params": null, + "query": "select 'foo' x, 500000 y1_full, 500000 y2_full, 1000000 y3_line_compact\nunion all select 'bar', 500000, 500000, 1000000\nunion all select 'baz', 500000, 500000, 1000000" + }, + "format-rows?": true, + "results_timezone": "America/Montevideo", + "requested_timezone": "Etc/GMT", + "results_metadata": { + "columns": [ + { + "display_name": "X", + "field_ref": [ + "field", + "X", + { + "base-type": "type/Text" + } + ], + "name": "X", + "base_type": "type/Text", + "effective_type": "type/Text", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 3, + "nil%": 0 + }, + "type": { + "type/Text": { + "percent-json": 0, + "percent-url": 0, + "percent-email": 0, + "percent-state": 0, + "average-length": 3 + } + } + } + }, + { + "display_name": "Y1_FULL", + "field_ref": [ + "field", + "Y1_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y1_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 500000, + "q1": 500000, + "q3": 500000, + "max": 500000, + "sd": 0, + "avg": 500000 + } + } + } + }, + { + "display_name": "Y2_FULL", + "field_ref": [ + "field", + "Y2_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y2_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 500000, + "q1": 500000, + "q3": 500000, + "max": 500000, + "sd": 0, + "avg": 500000 + } + } + } + }, + { + "display_name": "Y3_LINE_COMPACT", + "field_ref": [ + "field", + "Y3_LINE_COMPACT", + { + "base-type": "type/Integer" + } + ], + "name": "Y3_LINE_COMPACT", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 1000000, + "q1": 1000000, + "q3": 1000000, + "max": 1000000, + "sd": 0, + "avg": 1000000 + } + } + } + } + ] + }, + "insights": null + } + } +] diff --git a/frontend/src/metabase/static-viz/components/ComboChart/stories-data/combo-data-labels-auto-compactness-propagates-from-totals.json b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/combo-data-labels-auto-compactness-propagates-from-totals.json new file mode 100644 index 0000000000000000000000000000000000000000..497b6b61941c2baf8d56e731ec9d156ef85e9555 --- /dev/null +++ b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/combo-data-labels-auto-compactness-propagates-from-totals.json @@ -0,0 +1,385 @@ +[ + { + "card": { + "public_uuid": null, + "parameter_usage_count": 0, + "created_at": "2024-06-05T04:04:06.447222Z", + "parameters": [], + "metabase_version": "v0.1.7-SNAPSHOT (cc8afe3)", + "collection": null, + "visualization_settings": { + "stackable.stack_type": "stacked", + "graph.show_values": true, + "graph.label_value_formatting": "auto", + "series_settings": { + "Y3_LINE_FULL": { + "display": "line" + }, + "Y3_LINE_COMPACT": { + "display": "line" + } + }, + "graph.show_stack_values": "all", + "graph.dimensions": ["X"], + "graph.metrics": ["Y1_FULL", "Y2_FULL", "Y3_LINE_FULL"] + }, + "collection_preview": true, + "entity_id": "MdQ7wxzTzrF62rRxpyi4y", + "display": "bar", + "parameter_mappings": [], + "id": 372, + "dataset_query": { + "database": 1, + "type": "native", + "native": { + "template-tags": {}, + "query": "select 'foo' x, 500000 y1_full, 500000 y2_full, 500000 y3_line_full\nunion all select 'bar', 500000, 500000, 500000\nunion all select 'baz', 500000, 500000, 500000\n\n" + } + }, + "cache_ttl": null, + "embedding_params": null, + "made_public_by_id": null, + "updated_at": "2024-06-05T04:04:06.447222Z", + "moderation_reviews": [], + "creator_id": 1, + "average_query_time": null, + "type": "question", + "last_used_at": null, + "dashboard_count": 0, + "last_query_start": null, + "name": "stack totals compact propagates", + "query_type": "native", + "collection_id": null, + "enable_embedding": false, + "database_id": 1, + "trashed_from_collection_id": null, + "can_write": true, + "initially_published_at": null, + "result_metadata": [ + { + "display_name": "X", + "field_ref": [ + "field", + "X", + { + "base-type": "type/Text" + } + ], + "name": "X", + "base_type": "type/Text", + "effective_type": "type/Text", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 3, + "nil%": 0 + }, + "type": { + "type/Text": { + "percent-json": 0, + "percent-url": 0, + "percent-email": 0, + "percent-state": 0, + "average-length": 3 + } + } + } + }, + { + "display_name": "Y1_FULL", + "field_ref": [ + "field", + "Y1_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y1_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 500000, + "q1": 500000, + "q3": 500000, + "max": 500000, + "sd": 0, + "avg": 500000 + } + } + } + }, + { + "display_name": "Y2_FULL", + "field_ref": [ + "field", + "Y2_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y2_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 500000, + "q1": 500000, + "q3": 500000, + "max": 500000, + "sd": 0, + "avg": 500000 + } + } + } + }, + { + "display_name": "Y3_LINE_FULL", + "field_ref": [ + "field", + "Y3_LINE_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y3_LINE_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 500000, + "q1": 500000, + "q3": 500000, + "max": 500000, + "sd": 0, + "avg": 500000 + } + } + } + } + ], + "can_run_adhoc_query": true, + "table_id": null, + "collection_position": null, + "view_count": 0, + "archived": false, + "description": null, + "cache_invalidated_at": null, + "displayIsLocked": true + }, + "data": { + "rows": [ + ["foo", 500000, 500000, 500000], + ["bar", 500000, 500000, 500000], + ["baz", 500000, 500000, 500000] + ], + "cols": [ + { + "display_name": "X", + "source": "native", + "field_ref": [ + "field", + "X", + { + "base-type": "type/Text" + } + ], + "name": "X", + "base_type": "type/Text", + "effective_type": "type/Text" + }, + { + "display_name": "Y1_FULL", + "source": "native", + "field_ref": [ + "field", + "Y1_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y1_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer" + }, + { + "display_name": "Y2_FULL", + "source": "native", + "field_ref": [ + "field", + "Y2_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y2_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer" + }, + { + "display_name": "Y3_LINE_FULL", + "source": "native", + "field_ref": [ + "field", + "Y3_LINE_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y3_LINE_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer" + } + ], + "native_form": { + "params": null, + "query": "select 'foo' x, 500000 y1_full, 500000 y2_full, 500000 y3_line_full\nunion all select 'bar', 500000, 500000, 500000\nunion all select 'baz', 500000, 500000, 500000" + }, + "format-rows?": true, + "results_timezone": "America/Montevideo", + "requested_timezone": "Etc/GMT", + "results_metadata": { + "columns": [ + { + "display_name": "X", + "field_ref": [ + "field", + "X", + { + "base-type": "type/Text" + } + ], + "name": "X", + "base_type": "type/Text", + "effective_type": "type/Text", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 3, + "nil%": 0 + }, + "type": { + "type/Text": { + "percent-json": 0, + "percent-url": 0, + "percent-email": 0, + "percent-state": 0, + "average-length": 3 + } + } + } + }, + { + "display_name": "Y1_FULL", + "field_ref": [ + "field", + "Y1_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y1_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 500000, + "q1": 500000, + "q3": 500000, + "max": 500000, + "sd": 0, + "avg": 500000 + } + } + } + }, + { + "display_name": "Y2_FULL", + "field_ref": [ + "field", + "Y2_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y2_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 500000, + "q1": 500000, + "q3": 500000, + "max": 500000, + "sd": 0, + "avg": 500000 + } + } + } + }, + { + "display_name": "Y3_LINE_FULL", + "field_ref": [ + "field", + "Y3_LINE_FULL", + { + "base-type": "type/Integer" + } + ], + "name": "Y3_LINE_FULL", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 500000, + "q1": 500000, + "q3": 500000, + "max": 500000, + "sd": 0, + "avg": 500000 + } + } + } + } + ] + }, + "insights": null + } + } +] diff --git a/frontend/src/metabase/static-viz/components/ComboChart/stories-data/index.ts b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/index.ts index d550f156b370ccdc705da3cda24cfa414f7f8f0c..53eeed5589af9e8aa604bcd508da0b1c11aefed8 100644 --- a/frontend/src/metabase/static-viz/components/ComboChart/stories-data/index.ts +++ b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/index.ts @@ -47,6 +47,8 @@ import barTwoDaysOfWeek from "./bar-two-days-of-week.json"; import barsBreakoutSortedWithNegativeValuesPowerYAxis from "./bars-breakout-sorted-with-negative-values-power-y-axis.json"; import breakoutNullAndEmptyString from "./breakout-null-and-empty-string.json"; import combinedBarTimeSeriesDifferentGranularityWithBreakout from "./combined-bar-timeseries-different-granularity-with-breakout.json"; +import comboDataLabelsAutoCompactnessPropagatesFromLine from "./combo-data-labels-auto-compactness-propagates-from-line.json"; +import comboDataLabelsAutoCompactnessPropagatesFromTotals from "./combo-data-labels-auto-compactness-propagates-from-totals.json"; import comboHistogram from "./combo-histogram.json"; import comboStackedBarsAreasNormalized from "./combo-stacked-bars-areas-normalized.json"; import comboStackedBarsAreas from "./combo-stacked-bars-areas.json"; @@ -212,4 +214,6 @@ export const data = { barStackedSeriesLabelsNormalizedAutoCompactness, barStackedLabelsNullVsZero, barMinHeightLimit, + comboDataLabelsAutoCompactnessPropagatesFromLine, + comboDataLabelsAutoCompactnessPropagatesFromTotals, }; diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/axis.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/axis.ts index 1fe0e35002aa7581ed9cf4ef625b6f172ffe7c63..cd2ae08857978b43ca48de330f049451843753fc 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/model/axis.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/axis.ts @@ -540,7 +540,7 @@ export function getYAxesModels( columnByDataKey: Record<DataKey, DatasetColumn>, isAutoSplitSupported: boolean, stackModels: StackModel[], - compactSeriesDataKeys: DataKey[], + isCompactFormatting: boolean, renderingContext: RenderingContext, ) { const seriesDataKeys = seriesModels.map(seriesModel => seriesModel.dataKey); @@ -575,17 +575,6 @@ export function getYAxesModels( stackModel => stackModel.axis === "left", ); - const leftAxisFormattingOptions = getYAxisFormattingOptions({ - compactSeriesDataKeys, - axisSeriesKeysSet: leftAxisSeriesKeysSet, - settings, - }); - const rightAxisFormattingOptions = getYAxisFormattingOptions({ - compactSeriesDataKeys, - axisSeriesKeysSet: rightAxisSeriesKeysSet, - settings, - }); - return { leftAxisModel: getYAxisModel( leftAxisSeriesKeys, @@ -596,7 +585,7 @@ export function getYAxesModels( columnByDataKey, settings["stackable.stack_type"] ?? null, renderingContext, - leftAxisFormattingOptions, + { compact: isCompactFormatting }, ), rightAxisModel: getYAxisModel( rightAxisSeriesKeys, @@ -609,7 +598,7 @@ export function getYAxesModels( ? null : settings["stackable.stack_type"] ?? null, renderingContext, - rightAxisFormattingOptions, + { compact: isCompactFormatting }, ), }; } diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts index 15afdc7b0d85d1c5e7793d9759e818c03e7f4bfc..eab5ac0d6170d432fbdcc1f6e1f029452a3d2465 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts @@ -14,8 +14,7 @@ import { getCardsSeriesModels, getComboChartDataDensity, getDimensionModel, - getSeriesLabelsFormatters, - getStackedLabelsFormatters, + getFormatters, } from "metabase/visualizations/echarts/cartesian/model/series"; import type { CartesianChartModel, @@ -137,23 +136,17 @@ export const getCartesianChartModel = ( showWarning, ); - const { formatters: seriesLabelsFormatters, compactSeriesDataKeys } = - getSeriesLabelsFormatters( - seriesModels, - stackModels, - scaledDataset, - settings, - renderingContext, - ); - - const { formatters: stackedLabelsFormatters, compactStackedSeriesDataKeys } = - getStackedLabelsFormatters( - seriesModels, - stackModels, - scaledDataset, - settings, - renderingContext, - ); + const { + seriesLabelsFormatters, + stackedLabelsFormatters, + isCompactFormatting, + } = getFormatters( + seriesModels, + stackModels, + scaledDataset, + settings, + renderingContext, + ); const dataDensity = getComboChartDataDensity( seriesModels, @@ -173,7 +166,7 @@ export const getCartesianChartModel = ( columnByDataKey, true, stackModels, - [...compactSeriesDataKeys, ...compactStackedSeriesDataKeys], + isCompactFormatting, renderingContext, ); diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts index 9494386bf678fd9ec39bc208f6cf56cdf86bb692..3c0572c0ab161ae1ef204e18adadd2b3a0f6946d 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts @@ -551,19 +551,13 @@ export function getDisplaySeriesSettingsByDataKey( return seriesSettingsByKey; } -export const getStackedLabelsFormatters = ( +const getStackTotalsFormatters = ( seriesModels: SeriesModel[], stackModels: StackModel[], dataset: ChartDataset, settings: ComputedVisualizationSettings, renderingContext: RenderingContext, -): { - formatters: StackedSeriesFormatters; - compactStackedSeriesDataKeys: DataKey[]; -} => { - const formatters: StackedSeriesFormatters = {}; - const compactStackedSeriesDataKeys: DataKey[] = []; - +) => { const hasDataLabels = settings["graph.show_values"] && settings["stackable.stack_type"] === "stacked" && @@ -571,13 +565,13 @@ export const getStackedLabelsFormatters = ( settings["graph.show_stack_values"] === "all"); if (!hasDataLabels) { - return { formatters, compactStackedSeriesDataKeys }; + return []; } - stackModels.forEach(({ display: stackName, seriesKeys }) => { + return stackModels.map(({ display: stackName, seriesKeys }) => { const seriesModel = seriesModels.find(s => s.dataKey === seriesKeys[0]); if (!seriesModel) { - return []; + throw new Error(`Missing series model for data key: ${seriesKeys[0]}`); } const compactFormatter = createSeriesLabelsFormatter( @@ -595,36 +589,35 @@ export const getStackedLabelsFormatters = ( renderingContext, ); - // if either positive or negative need to be compact formatted - // compact format both - const isCompact = [ - POSITIVE_STACK_TOTAL_DATA_KEY, - NEGATIVE_STACK_TOTAL_DATA_KEY, - ] - .map(signKey => { - const getValue = (datum: Datum) => - getStackTotalValue(datum, seriesKeys, signKey); - - return shouldRenderCompact( - dataset, - getValue, - compactFormatter, - fullFormatter, - settings, - ); - }) - .some(isCompact => isCompact); - - if (isCompact) { - compactStackedSeriesDataKeys.push(seriesKeys[0]); + let isCompact: boolean; + if (settings["graph.label_value_formatting"] === "auto") { + // if either positive or negative need to be compact formatted + // compact format both + isCompact = [POSITIVE_STACK_TOTAL_DATA_KEY, NEGATIVE_STACK_TOTAL_DATA_KEY] + .map(signKey => { + const getValue = (datum: Datum) => + getStackTotalValue(datum, seriesKeys, signKey); + + return shouldRenderCompact( + dataset, + getValue, + compactFormatter, + fullFormatter, + settings, + ); + }) + .some(isCompact => isCompact); + } else { + isCompact = settings["graph.label_value_formatting"] === "compact"; } - const stackedFormatter = isCompact ? compactFormatter : fullFormatter; - - formatters[stackName] = stackedFormatter; + return { + stackName, + isCompact, + compactFormatter, + fullFormatter, + }; }); - - return { formatters, compactStackedSeriesDataKeys }; }; const createSeriesLabelsFormatter = ( @@ -673,13 +666,18 @@ const getSeriesLabelsFormattingInfo = ( settings, renderingContext, ); - const isCompact = shouldRenderCompact( - dataset, - getValue, - compactFormatter, - fullFormatter, - settings, - ); + let isCompact: boolean; + if (settings["graph.label_value_formatting"] === "auto") { + isCompact = shouldRenderCompact( + dataset, + getValue, + compactFormatter, + fullFormatter, + settings, + ); + } else { + isCompact = settings["graph.label_value_formatting"] === "compact"; + } return { dataKey: seriesModel.dataKey, @@ -690,21 +688,15 @@ const getSeriesLabelsFormattingInfo = ( }); }; -export const getSeriesLabelsFormatters = ( +const getSeriesLabelsFormatters = ( seriesModels: SeriesModel[], stackModels: StackModel[], dataset: ChartDataset, settings: ComputedVisualizationSettings, renderingContext: RenderingContext, -): { - formatters: SeriesFormatters; - compactSeriesDataKeys: DataKey[]; -} => { - const formatters: SeriesFormatters = {}; - const compactSeriesDataKeys: DataKey[] = []; - +) => { if (!settings["graph.show_values"]) { - return { formatters, compactSeriesDataKeys }; + return []; } const seriesModelsWithLabels = seriesModels.filter(seriesModel => { @@ -722,51 +714,94 @@ export const getSeriesLabelsFormatters = ( seriesModel => !stackedSeriesKeys.has(seriesModel.dataKey), ); - getSeriesLabelsFormattingInfo( + const nonStackedSeriesFormattingInfo = getSeriesLabelsFormattingInfo( nonStackedSeries, dataset, settings, renderingContext, - ).forEach(({ isCompact, compactFormatter, fullFormatter, dataKey }) => { - formatters[dataKey] = isCompact ? compactFormatter : fullFormatter; - isCompact && compactSeriesDataKeys.push(dataKey); - }); + ); // Bar stack series formatters const shouldShowStackedBarSeriesLabels = settings["graph.show_stack_values"] === "series" || settings["graph.show_stack_values"] === "all"; - if (shouldShowStackedBarSeriesLabels) { - const barStackSeriesKeys = new Set( - stackModels.find(stackModel => stackModel.display === "bar") - ?.seriesKeys ?? [], - ); - const barStackSeries = seriesModelsWithLabels.filter(seriesModel => - barStackSeriesKeys.has(seriesModel.dataKey), - ); - const barSeriesLabelsFormattingInfo = getSeriesLabelsFormattingInfo( - barStackSeries, - dataset, - settings, - renderingContext, - ); - const shouldApplyCompactFormattingToBarStack = - barSeriesLabelsFormattingInfo.some(({ isCompact }) => isCompact); + if (!shouldShowStackedBarSeriesLabels) { + return nonStackedSeriesFormattingInfo; + } - barSeriesLabelsFormattingInfo.forEach( - ({ compactFormatter, fullFormatter, dataKey }) => { - formatters[dataKey] = shouldApplyCompactFormattingToBarStack - ? compactFormatter - : fullFormatter; + const barStackSeriesKeys = new Set( + stackModels.find(stackModel => stackModel.display === "bar")?.seriesKeys ?? + [], + ); + const barStackSeries = seriesModelsWithLabels.filter(seriesModel => + barStackSeriesKeys.has(seriesModel.dataKey), + ); + const barSeriesLabelsFormattingInfo = getSeriesLabelsFormattingInfo( + barStackSeries, + dataset, + settings, + renderingContext, + ); - shouldApplyCompactFormattingToBarStack && - compactSeriesDataKeys.push(dataKey); - }, - ); - } + return [...nonStackedSeriesFormattingInfo, ...barSeriesLabelsFormattingInfo]; +}; - return { formatters, compactSeriesDataKeys }; +export const getFormatters = ( + seriesModels: SeriesModel[], + stackModels: StackModel[], + dataset: ChartDataset, + settings: ComputedVisualizationSettings, + renderingContext: RenderingContext, +): { + stackedLabelsFormatters: StackedSeriesFormatters; + seriesLabelsFormatters: SeriesFormatters; + isCompactFormatting: boolean; +} => { + const stackTotalsFormattersInfo = getStackTotalsFormatters( + seriesModels, + stackModels, + dataset, + settings, + renderingContext, + ); + + const seriesLabelsFormattersInfo = getSeriesLabelsFormatters( + seriesModels, + stackModels, + dataset, + settings, + renderingContext, + ); + + const isCompactFormatting = + settings["graph.label_value_formatting"] === "compact" || + stackTotalsFormattersInfo.some(({ isCompact }) => isCompact) || + seriesLabelsFormattersInfo.some(({ isCompact }) => isCompact); + + return { + isCompactFormatting, + stackedLabelsFormatters: stackTotalsFormattersInfo.reduce( + (formatterByStackName, formattingInfo) => { + formatterByStackName[formattingInfo.stackName] = isCompactFormatting + ? formattingInfo.compactFormatter + : formattingInfo.fullFormatter; + + return formatterByStackName; + }, + {} as StackedSeriesFormatters, + ), + seriesLabelsFormatters: seriesLabelsFormattersInfo.reduce( + (formatterBySeriesKey, formattingInfo) => { + formatterBySeriesKey[formattingInfo.dataKey] = isCompactFormatting + ? formattingInfo.compactFormatter + : formattingInfo.fullFormatter; + + return formatterBySeriesKey; + }, + {} as SeriesFormatters, + ), + }; }; export const getWaterfallLabelFormatter = ( diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/scatter/model/index.ts b/frontend/src/metabase/visualizations/echarts/cartesian/scatter/model/index.ts index 93ab2c5e7877aafb28ee171670b7e774db9bba9c..c25c269acf129a51505396029888a5d5adf98214 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/scatter/model/index.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/scatter/model/index.ts @@ -115,7 +115,7 @@ export function getScatterPlotModel( columnByDataKey, false, [], - [], + false, renderingContext, ); diff --git a/frontend/src/metabase/visualizations/lib/settings/graph.js b/frontend/src/metabase/visualizations/lib/settings/graph.js index eac79c2a8299306be16fb979cc80cf76ea4e8c41..d0206bc1e99611fb8e1d33398ce76838a76e640a 100644 --- a/frontend/src/metabase/visualizations/lib/settings/graph.js +++ b/frontend/src/metabase/visualizations/lib/settings/graph.js @@ -33,6 +33,7 @@ import { getDefaultLegendIsReversed, getDefaultShowDataLabels, getDefaultDataLabelsFrequency, + getDefaultDataLabelsFormatting, getDefaultIsAutoSplitEnabled, getDefaultColumns, getDefaultDimensionFilter, @@ -390,7 +391,7 @@ export const GRAPH_DISPLAY_VALUES_SETTINGS = { { name: t`Full`, value: "full" }, ], }, - default: "auto", + default: getDefaultDataLabelsFormatting(), }, }; diff --git a/frontend/src/metabase/visualizations/shared/settings/cartesian-chart.ts b/frontend/src/metabase/visualizations/shared/settings/cartesian-chart.ts index 39ba18e82b758aa1431a68318ba962f830a445e3..954f67a6ad651317a271ee5822b0b061df4a8801 100644 --- a/frontend/src/metabase/visualizations/shared/settings/cartesian-chart.ts +++ b/frontend/src/metabase/visualizations/shared/settings/cartesian-chart.ts @@ -254,6 +254,7 @@ export const getDefaultLegendIsReversed = ( export const getDefaultShowDataLabels = () => false; export const getDefaultDataLabelsFrequency = () => "fit"; +export const getDefaultDataLabelsFormatting = () => "auto"; export const getAvailableXAxisScales = ( [{ data }]: RawSeries,