diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Data_Labels_Timeseries.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Data_Labels_Timeseries.png index 6bd24c7d2c051f70ba10b85bec3f2419ddd11cbf..5b5c5d5c22125becc9f28efe001ff35b28ac8e51 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Data_Labels_Timeseries.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Data_Labels_Timeseries.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Enourmous_Dataset.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Enourmous_Dataset.png index d54f38d0d63dac9c1aa1140a46d9b27e17e8c0b0..16977549a77e2101f139c1ec9bb1ed45db2699ad 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Enourmous_Dataset.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Enourmous_Dataset.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Linear_Null_Dimension.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Linear_Null_Dimension.png index 6664451378f0289dc97381ca9bd3e49942a473d4..6fad481367c3466dc26a756e20577550e0c10bee 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Linear_Null_Dimension.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Linear_Null_Dimension.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Log_Y_Scale.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Log_Y_Scale.png index 7f9381c8ca3405b5bee4fe8aafe52919c3effa14..b53af6c1f038d103fbf6981404de674091aca5d8 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Log_Y_Scale.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Log_Y_Scale.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Log_Y_Scale_Negative.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Log_Y_Scale_Negative.png index 93d22c297ae88277eeccb6aa90285b8254d98e09..0aa146c8bbfb5cb82d961ea3ae3474b20a1db5e7 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Log_Y_Scale_Negative.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Log_Y_Scale_Negative.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Native_Time_Series_Quarter.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Native_Time_Series_Quarter.png index 42e0a40f7b23760289f385e405347d6352123197..ba63bc2676c68ed589b3239ef9575471a4e9415d 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Native_Time_Series_Quarter.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Native_Time_Series_Quarter.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Native_Time_Series_With_Gaps.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Native_Time_Series_With_Gaps.png index 88924cd7f15b4a30812065c8924ec6d4a7471c8d..e5a99e84889ce8894a46633014d0a770289be0fc 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Native_Time_Series_With_Gaps.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Native_Time_Series_With_Gaps.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Negative_Only.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Negative_Only.png index fdaffa9c1e34501ba1fcf599ea21b28bc9c6f196..7f9fe784545e9eefe8a2919711420567d00d2e61 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Negative_Only.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Negative_Only.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_No_Total_Timeseries.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_No_Total_Timeseries.png index 4df87e86d79d618b7ee7858060de636898822aac..edd47109bb6c5c8c1530f8b5ce082251760cd867 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_No_Total_Timeseries.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_No_Total_Timeseries.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Nulls.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Nulls.png index 3e007e1971cc6baadff505f3fc8859f0af41a8d0..49f46c1e29123969eb78348ccd6f4f0a8938dbc7 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Nulls.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Nulls.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Pow_Y_Scale_Negative_Only.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Pow_Y_Scale_Negative_Only.png index 93d22c297ae88277eeccb6aa90285b8254d98e09..0aa146c8bbfb5cb82d961ea3ae3474b20a1db5e7 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Pow_Y_Scale_Negative_Only.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Pow_Y_Scale_Negative_Only.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Structured_Time_Series_Year.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Structured_Time_Series_Year.png index a9dfb5170cde58998360a0ea529615fd83cb8f37..c14296f3b734d234c54958c264999c35c43771b4 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Structured_Time_Series_Year.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Structured_Time_Series_Year.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Time_X_Scale_Two_Bars_Without_Total.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Time_X_Scale_Two_Bars_Without_Total.png index 0ef77d698ec832f296f4bbf130b881c3587a2d0f..b2cd1917b5ad14a8b954a37ab00763f0afbb2f38 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Time_X_Scale_Two_Bars_Without_Total.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Time_X_Scale_Two_Bars_Without_Total.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Timeseries_X_Scale.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Timeseries_X_Scale.png index 0521c8e23e9f8b743e1529f12b482dd9ebf57d8d..65cd04095e9fdaef820bd53aecd8de592ae2871b 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Timeseries_X_Scale.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Timeseries_X_Scale.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Timeseries_X_Scale_Unsorted.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Timeseries_X_Scale_Unsorted.png index 0521c8e23e9f8b743e1529f12b482dd9ebf57d8d..65cd04095e9fdaef820bd53aecd8de592ae2871b 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Timeseries_X_Scale_Unsorted.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Timeseries_X_Scale_Unsorted.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Two_Bars_With_Total.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Two_Bars_With_Total.png new file mode 100644 index 0000000000000000000000000000000000000000..5dd35dc5b09b96e3ac1088e8136501dc0e55b98a Binary files /dev/null and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Two_Bars_With_Total.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Unaggregated_Linear.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Unaggregated_Linear.png index 15c5918ddee27219d8e5ba22184c6bc6be2130d7..65bcb457dfd76b78f9e86236dd67c94174ad2c53 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Unaggregated_Linear.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Unaggregated_Linear.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Unaggregated_Timeseries.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Unaggregated_Timeseries.png index 6ef63467be3f78cb4d6b75d7e33bc8a865b49a8c..489c82d3b81d23687c9decbe0efee30dc2e5a9d9 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Unaggregated_Timeseries.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Unaggregated_Timeseries.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Auto_Compact_With_Data_Labels.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Auto_Compact_With_Data_Labels.png index df0684eb9032caccb22d91e8ccf5dbbe47fe4ba4..9dd5e899b8d4850f2f48ef72d3fef9290a167edc 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Auto_Compact_With_Data_Labels.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Auto_Compact_With_Data_Labels.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Compact_Without_Data_Labels.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Compact_Without_Data_Labels.png index 6d9134726bd5e082fdda013fa68fdd084adbb403..b7c6e11fdbd459e11350647e02860dfa20d58b4d 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Compact_Without_Data_Labels.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Compact_Without_Data_Labels.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Full_With_Data_Labels.png b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Full_With_Data_Labels.png index 8b744b33e8fccd2945a843a47504eee9acaa7f59..5ee3137e925f09a4ae18c2bb0aaf5e666d0aa05b 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Full_With_Data_Labels.png and b/.loki/reference/chrome_laptop_static_viz_WaterfallChart_Y_Axis_Full_With_Data_Labels.png differ diff --git a/frontend/src/metabase/static-viz/components/WaterfallChart/WaterfallChart.stories.tsx b/frontend/src/metabase/static-viz/components/WaterfallChart/WaterfallChart.stories.tsx index b73a59ee9215155cd4269ce16cf37e3471e535a6..daf26ee33d94afa380dc7f4bcbb8278a04a743d8 100644 --- a/frontend/src/metabase/static-viz/components/WaterfallChart/WaterfallChart.stories.tsx +++ b/frontend/src/metabase/static-viz/components/WaterfallChart/WaterfallChart.stories.tsx @@ -294,3 +294,10 @@ OrdinalNullDimension.args = { dashcardSettings: {}, renderingContext, }; + +export const TwoBarsWithTotal = Template.bind({}); +TwoBarsWithTotal.args = { + rawSeries: data.twoBarsWithTotal as any, + dashcardSettings: {}, + renderingContext, +}; diff --git a/frontend/src/metabase/static-viz/components/WaterfallChart/stories-data/index.ts b/frontend/src/metabase/static-viz/components/WaterfallChart/stories-data/index.ts index 6e90f9db2c29a4dcbb6c29e94fd902a833dcaccb..94f3f5f63a9ed657fdd6f5bfb7c991f2ba96b75c 100644 --- a/frontend/src/metabase/static-viz/components/WaterfallChart/stories-data/index.ts +++ b/frontend/src/metabase/static-viz/components/WaterfallChart/stories-data/index.ts @@ -30,6 +30,7 @@ import timeXScaleTwoBarsWithoutTotal from "./time-x-scale-two-bars-without-total import timeSeriesDataAsOrdinalXScale from "./timeseries-data-as-ordinal-x-scale.json"; import timeseriesXScaleUnsorted from "./timeseries-x-scale-unsorted.json"; import timeseriesXScale from "./timeseries-x-scale.json"; +import twoBarsWithTotal from "./two-bars-with-total.json"; import unaggregatedLinear from "./unaggregated-linear.json"; import unaggregatedOrdinal from "./unaggregated-ordinal.json"; import unaggregatedTimeseries from "./unaggregated-timeseries.json"; @@ -76,4 +77,5 @@ export const data = { nullXAxisValue, linearNullDimension, ordinalNullDimension, + twoBarsWithTotal, }; diff --git a/frontend/src/metabase/static-viz/components/WaterfallChart/stories-data/two-bars-with-total.json b/frontend/src/metabase/static-viz/components/WaterfallChart/stories-data/two-bars-with-total.json new file mode 100644 index 0000000000000000000000000000000000000000..475492e3d678bd1228802d059942af11adf1a5c8 --- /dev/null +++ b/frontend/src/metabase/static-viz/components/WaterfallChart/stories-data/two-bars-with-total.json @@ -0,0 +1,220 @@ +[ + { + "card": { + "public_uuid": null, + "parameter_usage_count": 0, + "created_at": "2024-04-21T19:26:31.592185Z", + "parameters": [], + "metabase_version": "v0.48.1-SNAPSHOT (6fcf88a)", + "collection": null, + "visualization_settings": { + "graph.dimensions": ["X"], + "graph.metrics": ["Y"] + }, + "collection_preview": true, + "entity_id": "4UsZswM_N9jcnpvE_Ecsi", + "display": "waterfall", + "parameter_mappings": [], + "id": 172, + "dataset_query": { + "database": 1, + "type": "native", + "native": { + "template-tags": {}, + "query": "SELECT '2022-01-01' x, 10 y\nunion all SELECT '2022-01-02', 10" + } + }, + "cache_ttl": null, + "embedding_params": null, + "made_public_by_id": null, + "updated_at": "2024-04-21T19:26:31.592185Z", + "moderation_reviews": [], + "creator_id": 1, + "average_query_time": null, + "type": "question", + "dashboard_count": 0, + "last_query_start": null, + "name": "waterfall corner case 2 bars with total", + "query_type": "native", + "collection_id": null, + "enable_embedding": false, + "database_id": 1, + "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": 2, + "nil%": 0 + }, + "type": { + "type/Text": { + "percent-json": 0, + "percent-url": 0, + "percent-email": 0, + "percent-state": 0, + "average-length": 10 + } + } + } + }, + { + "display_name": "Y", + "field_ref": [ + "field", + "Y", + { + "base-type": "type/Integer" + } + ], + "name": "Y", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 10, + "q1": 10, + "q3": 10, + "max": 10, + "sd": 0, + "avg": 10 + } + } + } + } + ], + "table_id": null, + "collection_position": null, + "archived": false, + "description": null, + "cache_invalidated_at": null, + "displayIsLocked": true + }, + "data": { + "rows": [ + ["2022-01-01", 10], + ["2022-01-02", 10] + ], + "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": "Y", + "source": "native", + "field_ref": [ + "field", + "Y", + { + "base-type": "type/Integer" + } + ], + "name": "Y", + "base_type": "type/Integer", + "effective_type": "type/Integer" + } + ], + "native_form": { + "params": null, + "query": "SELECT '2022-01-01' x, 10 y\nunion all SELECT '2022-01-02', 10" + }, + "format-rows?": true, + "results_timezone": "America/Montevideo", + "requested_timezone": "Pacific/Guam", + "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": 2, + "nil%": 0 + }, + "type": { + "type/Text": { + "percent-json": 0, + "percent-url": 0, + "percent-email": 0, + "percent-state": 0, + "average-length": 10 + } + } + } + }, + { + "display_name": "Y", + "field_ref": [ + "field", + "Y", + { + "base-type": "type/Integer" + } + ], + "name": "Y", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 1, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 10, + "q1": 10, + "q3": 10, + "max": 10, + "sd": 0, + "avg": 10 + } + } + } + } + ] + }, + "insights": null + } + } +] diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/model/axis.ts b/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/model/axis.ts index 87cd598489f456214cab56824c8748747e4f9591..b41cfdbe0d67ab38c9ce81c06bf3f9229ee4a3aa 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/model/axis.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/model/axis.ts @@ -1,4 +1,3 @@ -import dayjs from "dayjs"; import { t } from "ttag"; import type { @@ -26,7 +25,7 @@ const getTotalTimeSeriesXValue = ({ }: TimeSeriesXAxisModel) => { const [, lastDate] = range; const { unit, count } = interval; - return lastDate.add(count, unit).toISOString(); + return lastDate.add(count, unit); }; export const getWaterfallXAxisModel = ( @@ -53,15 +52,15 @@ export const getWaterfallXAxisModel = ( if (isTimeSeriesAxis(xAxisModel)) { const totalXValue = getTotalTimeSeriesXValue(xAxisModel); - const range: DateRange = [xAxisModel.range[0], dayjs(totalXValue)]; - const intervalsCount = xAxisModel.intervalsCount; + const range: DateRange = [xAxisModel.range[0], totalXValue]; + const intervalsCount = xAxisModel.intervalsCount + 1; const formatter = (valueRaw: RowValue) => { - const dateValue = tryGetDate(valueRaw); - if (dateValue == null) { + const value = tryGetDate(valueRaw); + if (value == null) { return ""; } - if (dateValue.isSame(dayjs(totalXValue), xAxisModel.interval.unit)) { + if (value.isSame(totalXValue, xAxisModel.interval.unit)) { return t`Total`; } @@ -72,7 +71,7 @@ export const getWaterfallXAxisModel = ( ...xAxisModel, range, intervalsCount, - totalXValue, + totalXValue: totalXValue.toISOString(), formatter, }; } @@ -80,6 +79,8 @@ export const getWaterfallXAxisModel = ( if (isNumericAxis(xAxisModel)) { const totalXValue = xAxisModel.extent[1] + xAxisModel.interval; const extent: Extent = [xAxisModel.extent[0], totalXValue]; + const intervalsCount = xAxisModel.intervalsCount + 1; + const formatter = (valueRaw: RowValue) => { if (valueRaw === totalXValue) { return t`Total`; @@ -91,6 +92,7 @@ export const getWaterfallXAxisModel = ( return { ...xAxisModel, totalXValue, + intervalsCount, extent, formatter, }; diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/model/dataset.ts b/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/model/dataset.ts index 2554ad15614c23e799bd28edd32c345801530900..941f9b00f5f307b50ee026dddf22c2678b6a91fd 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/model/dataset.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/model/dataset.ts @@ -87,6 +87,16 @@ export const getWaterfallDataset = ( ); } + if (isTimeSeriesAxis(xAxisModel)) { + transformedDataset = replaceValues( + transformedDataset, + (dataKey: DataKey, value: RowValue) => + dataKey === X_AXIS_DATA_KEY + ? xAxisModel.toEChartsAxisValue(value) + : value, + ); + } + return replaceValues( transformedDataset, (dataKey: DataKey, value: RowValue) => diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/option/index.ts b/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/option/index.ts index d2478f6a984f9398db4cefbe11fbc6095bfe1b87..ba4b85cca1fc8ea21461dc357a648a99a2e44269 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/option/index.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/waterfall/option/index.ts @@ -136,14 +136,14 @@ export const buildEChartsWaterfallSeries = ( }, z: CHART_STYLE.series.zIndex, renderItem: (_params, api) => { - const dataIndex = api.value(0); - const barStart = api.value(1); - const barEnd = api.value(2); + const xValue = api.value(0); + const yStart = api.value(1); + const yEnd = api.value(2); - const startCoord = api.coord([dataIndex, barStart]); - const endCoord = api.coord([dataIndex, barEnd]); + const startCoord = api.coord([xValue, yStart]); + const endCoord = api.coord([xValue, yEnd]); const rectHeight = startCoord[1] - endCoord[1]; - const isIncrease = barEnd >= barStart; + const isIncrease = yEnd >= yStart; const fill = isIncrease ? settings["waterfall.increase_color"]