diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Breakout_With_Line_Series_Stacked_Right_Axis_Only.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Breakout_With_Line_Series_Stacked_Right_Axis_Only.png index 050c0eb82689b0181a3437230c53a55f288e2414..b7c042245692cde3b61a353694336fb4233c86df 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Breakout_With_Line_Series_Stacked_Right_Axis_Only.png and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Breakout_With_Line_Series_Stacked_Right_Axis_Only.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Data_Labels_Negatives.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Data_Labels_Negatives.png index d25c7d2214e1e64ae40031b4e9b4f3bf5eb7051c..bc7994f226af19ccc9de697391ba90c763293c95 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Data_Labels_Negatives.png and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Data_Labels_Negatives.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Min_Height_Limit.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Min_Height_Limit.png new file mode 100644 index 0000000000000000000000000000000000000000..1268bb54fac55f654018993ccb781ca4d045863c Binary files /dev/null and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Min_Height_Limit.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Stack_Linear_X_Axis.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Stack_Linear_X_Axis.png index b896c15505b739708c05eea68a8658477a96bbef..8ada5b539f691d305e7938ce551a879ff02a6ac4 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Stack_Linear_X_Axis.png and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Stack_Linear_X_Axis.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Combo_Stacked_Bars_Areas.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Combo_Stacked_Bars_Areas.png index d04410b6c08d494d3f320f874fb9331bd26c6bbf..0ad68bd97d70b8f04d28ae9d2cd8bbb26e8e9737 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ComboChart_Combo_Stacked_Bars_Areas.png and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Combo_Stacked_Bars_Areas.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Histogram_Ticks_45_Degrees.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Histogram_Ticks_45_Degrees.png index 44d068f1ebc5f92b387e2dba3233717fa86e0bf9..990a86c0123355932165138b970272179f73b51b 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ComboChart_Histogram_Ticks_45_Degrees.png and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Histogram_Ticks_45_Degrees.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Histogram_Ticks_90_Degrees.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Histogram_Ticks_90_Degrees.png index ade54ac0e1b550a5d063451cd78227488060e653..d1461041914e20f961d7307e2ed2a7f81ce7de73 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ComboChart_Histogram_Ticks_90_Degrees.png and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Histogram_Ticks_90_Degrees.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Line_Log_Y_Scale.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Line_Log_Y_Scale.png index 65935412e7796f446f4649c23f2b975794f6d3e5..bbec40c3db1107a6e919901ce76dcec4473801f0 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ComboChart_Line_Log_Y_Scale.png and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Line_Log_Y_Scale.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Log_Y_Scale_Custom_Y_Axis_Range.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Log_Y_Scale_Custom_Y_Axis_Range.png index 3f9663bced367c6e538ad63f87fd213f0c5f2f43..6422a4391729baf93883155923c40b5e1403fea9 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ComboChart_Log_Y_Scale_Custom_Y_Axis_Range.png and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Log_Y_Scale_Custom_Y_Axis_Range.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Pow_Y_Scale_Custom_Y_Axis_Range.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Pow_Y_Scale_Custom_Y_Axis_Range.png index d0ae5ea65466540a7748f8a3275c671ca72994ac..f0e929dc2ff0bb6308b04640359dc8f914d6e4c2 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ComboChart_Pow_Y_Scale_Custom_Y_Axis_Range.png and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Pow_Y_Scale_Custom_Y_Axis_Range.png differ diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Trend_Combo.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Trend_Combo.png index 4b2568d86451fd35fc648fd616a5a599366a544c..9b4e12c36ddba667d8208166ee014fa094c05631 100644 Binary files a/.loki/reference/chrome_laptop_static_viz_ComboChart_Trend_Combo.png and b/.loki/reference/chrome_laptop_static_viz_ComboChart_Trend_Combo.png differ diff --git a/.loki/reference/chrome_laptop_viz_LineChart_Default.png b/.loki/reference/chrome_laptop_viz_LineChart_Default.png index 4d3030b04f80cd3f1fdd96d57c7287896f1cea1b..fec1060892e9b1d92dda5a2d346c2a1ec7d2e4ef 100644 Binary files a/.loki/reference/chrome_laptop_viz_LineChart_Default.png and b/.loki/reference/chrome_laptop_viz_LineChart_Default.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 0c95be526ef2114d39a17e0ae3091240e3fc5adf..b25f524202bc1a61273314a8bc34aa8e8b907146 100644 --- a/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx +++ b/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx @@ -755,6 +755,13 @@ BarStackedLabelsNullVsZero.args = { renderingContext, }; +export const BarMinHeightLimit = Template.bind({}); +BarMinHeightLimit.args = { + rawSeries: data.barMinHeightLimit 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/stories-data/bar-min-height-limit.json b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-min-height-limit.json new file mode 100644 index 0000000000000000000000000000000000000000..c8917fa7718b9c66888e0eb35aca660eb877002a --- /dev/null +++ b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-min-height-limit.json @@ -0,0 +1,239 @@ +[ + { + "card": { + "original_card_id": 324, + "public_uuid": null, + "parameter_usage_count": 0, + "created_at": "2024-05-25T01:52:38.995041Z", + "parameters": [], + "metabase_version": "v0.48.1-SNAPSHOT (683ce7f)", + "collection": { + "metabase.models.collection.root/is-root?": true, + "authority_level": null, + "name": "Our analytics", + "is_personal": false, + "id": "root", + "can_write": true + }, + "visualization_settings": { + "graph.dimensions": ["X"], + "graph.series_order_dimension": null, + "graph.series_order": null, + "graph.show_values": true, + "graph.metrics": ["Y"] + }, + "collection_preview": true, + "entity_id": "pQcB_6Cjn77S5-8s728_5", + "display": "bar", + "parameter_mappings": [], + "id": 324, + "dataset_query": { + "database": 1, + "type": "native", + "native": { + "template-tags": {}, + "query": "SELECT\n 1 x,\n 100000000 y\nUNION ALL\nSELECT\n 2,\n 100\nUNION ALL\nSELECT\n 3,\n 1\nUNION ALL\nSELECT\n 4,\n 0\nUNION ALL\nSELECT\n 5,\n NULL" + } + }, + "cache_ttl": null, + "embedding_params": null, + "made_public_by_id": null, + "updated_at": "2024-06-01T01:48:03.142878Z", + "moderation_reviews": [], + "creator_id": 1, + "average_query_time": 113.46031746031746, + "type": "question", + "last_used_at": "2024-06-01T01:48:03.141264Z", + "dashboard_count": 0, + "last_query_start": "2024-06-01T01:48:03.118893Z", + "name": "min-height-test", + "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/Integer" + } + ], + "name": "X", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 5, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 1, + "q1": 1.75, + "q3": 4.25, + "max": 5, + "sd": 1.5811388300841898, + "avg": 3 + } + } + } + }, + { + "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": 5, + "nil%": 0.2 + }, + "type": { + "type/Number": { + "min": 0, + "q1": 0.5, + "q3": 50000050, + "max": 100000000, + "sd": 49999983.16668867, + "avg": 25000025.25 + } + } + } + } + ], + "table_id": null, + "collection_position": null, + "view_count": 62, + "archived": false, + "description": null, + "cache_invalidated_at": null, + "displayIsLocked": true + }, + "data": { + "rows": [ + [1, 100000000], + [2, 100], + [3, 1], + [4, 0], + [5, null] + ], + "cols": [ + { + "display_name": "X", + "source": "native", + "field_ref": [ + "field", + "X", + { + "base-type": "type/Integer" + } + ], + "name": "X", + "base_type": "type/Integer", + "effective_type": "type/Integer" + }, + { + "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\n 1 x,\n 100000000 y\nUNION ALL\nSELECT\n 2,\n 100\nUNION ALL\nSELECT\n 3,\n 1\nUNION ALL\nSELECT\n 4,\n 0\nUNION ALL\nSELECT\n 5,\n NULL" + }, + "format-rows?": true, + "results_timezone": "America/Montevideo", + "requested_timezone": "Etc/GMT", + "results_metadata": { + "columns": [ + { + "display_name": "X", + "field_ref": [ + "field", + "X", + { + "base-type": "type/Integer" + } + ], + "name": "X", + "base_type": "type/Integer", + "effective_type": "type/Integer", + "semantic_type": null, + "fingerprint": { + "global": { + "distinct-count": 5, + "nil%": 0 + }, + "type": { + "type/Number": { + "min": 1, + "q1": 1.75, + "q3": 4.25, + "max": 5, + "sd": 1.5811388300841898, + "avg": 3 + } + } + } + }, + { + "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": 5, + "nil%": 0.2 + }, + "type": { + "type/Number": { + "min": 0, + "q1": 0.5, + "q3": 50000050, + "max": 100000000, + "sd": 49999983.16668867, + "avg": 25000025.25 + } + } + } + } + ] + }, + "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 615991b573fab26121f92e81809c112e93404785..f7a6b2189a7c72ca928e3df693103cf31d394540 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 @@ -25,6 +25,7 @@ import barHistogramXScale from "./bar-histogram-x-scale.json"; import barLinearXScale from "./bar-linear-x-scale.json"; import barLogYScaleStackedNegative from "./bar-log-y-scale-stacked-negative.json"; import barLogYScaleStacked from "./bar-log-y-scale-stacked.json"; +import barMinHeightLimit from "./bar-min-height-limit.json"; import barOrdinalXScaleAutoRotatedLabels from "./bar-ordinal-x-scale-auto-rotated-labels.json"; import barOrdinalXScale from "./bar-ordinal-x-scale.json"; import barRelativeDatetimeOrdinalScale from "./bar-relative-datetime-ordinal-scale.json"; @@ -208,4 +209,5 @@ export const data = { barStackedSeriesLabelsAndTotalsOrdinal, barStackedSeriesLabelsNormalizedAutoCompactness, barStackedLabelsNullVsZero, + barMinHeightLimit, }; diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/axis.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/axis.ts index f551f8e5e10f126e88f74a5566237a3b4ed1e462..7bd1e3c2d11ccbed4b2e746ba4ea4db2caa92498 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/model/axis.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/axis.ts @@ -335,12 +335,12 @@ const getYAxisSplit = ( const calculateStackedExtent = ( seriesKeys: DataKey[], - data: ChartDataset, + dataset: ChartDataset, ): Extent => { let min = 0; let max = 0; - data.forEach(entry => { + dataset.forEach(entry => { let positiveStack = 0; let negativeStack = 0; seriesKeys.forEach(key => { @@ -362,12 +362,12 @@ const calculateStackedExtent = ( function calculateNonStackedExtent( seriesKeys: DataKey[], - data: ChartDataset, + dataset: ChartDataset, ): Extent { let min = Infinity; let max = -Infinity; - data.forEach(entry => { + dataset.forEach(entry => { seriesKeys.forEach(key => { const value = entry[key]; if (typeof value === "number") { @@ -491,7 +491,7 @@ export function getYAxisModel( seriesKeys: string[], seriesNames: string[], stackModels: StackModel[], - dataset: ChartDataset, + trasnformedDataset: ChartDataset, settings: ComputedVisualizationSettings, columnByDataKey: Record<DataKey, DatasetColumn>, stackType: StackType, @@ -502,7 +502,12 @@ export function getYAxisModel( return null; } - const extent = getYAxisExtent(seriesKeys, stackModels, dataset, stackType); + const extent = getYAxisExtent( + seriesKeys, + stackModels, + trasnformedDataset, + stackType, + ); const column = columnByDataKey[seriesKeys[0]]; const label = getYAxisLabel(seriesNames, settings); const formatter = getYAxisFormatter( @@ -526,6 +531,7 @@ export function getYAxisModel( export function getYAxesModels( seriesModels: SeriesModel[], dataset: ChartDataset, + transformedDataset: ChartDataset, settings: ComputedVisualizationSettings, columnByDataKey: Record<DataKey, DatasetColumn>, isAutoSplitSupported: boolean, @@ -581,7 +587,7 @@ export function getYAxesModels( leftAxisSeriesKeys, leftAxisSeriesNames, leftStackModels, - dataset, + transformedDataset, settings, columnByDataKey, settings["stackable.stack_type"] ?? null, @@ -592,7 +598,7 @@ export function getYAxesModels( rightAxisSeriesKeys, rightAxisSeriesNames, rightStackModels, - dataset, + transformedDataset, settings, columnByDataKey, settings["stackable.stack_type"] === "normalized" diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.ts index 12ee5ef85ea7637ac09faf110ec03c1bfb4f90a5..b4ed5f3858caed563a8d5c1e024758e497cbb455 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.ts @@ -441,16 +441,8 @@ function getStackedDataLabelTransform( } function getBarSeriesDataLabelTransform( - settings: ComputedVisualizationSettings, - seriesModels: SeriesModel[], + barSeriesModels: SeriesModel[], ): ConditionalTransform { - const barSeriesModels = seriesModels.filter(seriesModel => { - const seriesSettings = settings.series( - seriesModel.legacySeriesSettingsObjectKey, - ); - return seriesSettings.display === "bar"; - }); - return { condition: barSeriesModels.length > 0, fn: (datum: Datum) => { @@ -476,6 +468,27 @@ function getBarSeriesDataLabelTransform( }; } +/** + * Replaces zero values with nulls for bar series so that we can use minHeight ECharts option + * to set minimum bar height for all non-zero values because it applies to bars with zero values too. + */ +function getBarSeriesZeroToNullTransform( + barSeriesModels: SeriesModel[], +): ConditionalTransform { + return { + condition: barSeriesModels.length > 0, + fn: (datum: Datum) => { + const transforedDatum = { ...datum }; + + barSeriesModels.forEach(({ dataKey }) => { + transforedDatum[dataKey] = datum[dataKey] === 0 ? null : datum[dataKey]; + }); + + return transforedDatum; + }, + }; +} + export function filterNullDimensionValues( dataset: ChartDataset, showWarning?: ShowWarning, @@ -660,6 +673,12 @@ export const applyVisualizationSettingsDataTransformations = ( settings: ComputedVisualizationSettings, showWarning?: ShowWarning, ) => { + const barSeriesModels = seriesModels.filter(seriesModel => { + const seriesSettings = settings.series( + seriesModel.legacySeriesSettingsObjectKey, + ); + return seriesSettings.display === "bar"; + }); const seriesDataKeys = seriesModels.map(seriesModel => seriesModel.dataKey); if ( @@ -714,7 +733,7 @@ export const applyVisualizationSettingsDataTransformations = ( }), }, getStackedDataLabelTransform(settings, seriesDataKeys), - getBarSeriesDataLabelTransform(settings, seriesModels), + getBarSeriesDataLabelTransform(barSeriesModels), { condition: settings["stackable.stack_type"] != null && @@ -725,6 +744,7 @@ export const applyVisualizationSettingsDataTransformations = ( ?.seriesKeys ?? [], ), }, + getBarSeriesZeroToNullTransform(barSeriesModels), ]); }; diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts index 5cb72cf7fe16a9810dc3d0b967e082314178188f..19679bccef5fbfa350f5cef0e665da9d3c2a0aab 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts @@ -156,7 +156,7 @@ export const getCartesianChartModel = ( const dataDensity = getComboChartDataDensity( seriesModels, stackModels, - transformedDataset, + dataset, seriesLabelsFormatters, stackedLabelsFormatters, settings, @@ -165,6 +165,7 @@ export const getCartesianChartModel = ( const { leftAxisModel, rightAxisModel } = getYAxesModels( seriesModels, + dataset, transformedDataset, settings, columnByDataKey, diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts index b1aa389ab347d03455c043057868ad174e246d1a..a2e5dcede4154bd4c990055102527386ed325bdd 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts @@ -286,7 +286,7 @@ export function getStackTotalValue( stackDataKeys: DataKey[], signKey: StackTotalDataKey, ): number | null { - let stackValue: number | null = null; + let stackValue: number | null = data[signKey] != null ? 0 : null; stackDataKeys.forEach(stackDataKey => { const seriesValue = data[stackDataKey]; if ( diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/option/series.ts b/frontend/src/metabase/visualizations/echarts/cartesian/option/series.ts index 9abbad6896f39ae98c808ed59b9ec73e32b2fb76..a5748c41f8d56154ab9e40dbbf32cbd320302ae9 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/option/series.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/option/series.ts @@ -37,7 +37,7 @@ import type { ComputedVisualizationSettings, RenderingContext, } from "metabase/visualizations/types"; -import type { SeriesSettings } from "metabase-types/api"; +import type { RowValue, SeriesSettings } from "metabase-types/api"; import type { ChartMeasurements, @@ -157,6 +157,7 @@ export function getDataLabelFormatter( chartWidth: number, settings?: ComputedVisualizationSettings, chartDataDensity?: ChartDataDensity, + accessor?: (datum: Datum) => RowValue, ) { const getShowLabel = getShowLabelFn( chartWidth, @@ -166,13 +167,10 @@ export function getDataLabelFormatter( ); return (params: CallbackDataParams) => { - const value = (params.data as Datum)[dataKey]; + const datum = params.data as Datum; + const value = accessor != null ? accessor(datum) : datum[dataKey]; - if (!getShowLabel(params)) { - return ""; - } - - if (typeof value !== "number") { + if (!getShowLabel(params) || typeof value !== "number") { return ""; } @@ -469,6 +467,7 @@ const buildEChartsBarSeries = ( z: Z_INDEXES.series, yAxisIndex, barGap: 0, + barMinHeight: 1, stack, barWidth: computeBarWidth( xAxisModel, @@ -517,25 +516,35 @@ const buildEChartsBarSeries = ( return seriesOption; } - const labelOptions = ["+" as const, "-" as const].map(sign => ({ - ...getDataLabelSeriesOption( - getBarSeriesDataLabelKey(seriesModel.dataKey, sign), - seriesOption, - settings, - getDataLabelFormatter( - seriesModel.dataKey, - yAxisScaleTransforms, - labelFormatter, - chartWidth, - settings, - chartDataDensity, - ), - sign === "+" ? "top" : "bottom", - renderingContext, - false, - ), - type: "bar", // ensure type is bar for typescript - })) as BarSeriesOption[]; + const labelOptions: BarSeriesOption[] = ["+" as const, "-" as const].map( + sign => { + const labelDataKey = getBarSeriesDataLabelKey(seriesModel.dataKey, sign); + return { + ...getDataLabelSeriesOption( + getBarSeriesDataLabelKey(seriesModel.dataKey, sign), + seriesOption, + settings, + getDataLabelFormatter( + seriesModel.dataKey, + yAxisScaleTransforms, + labelFormatter, + chartWidth, + settings, + chartDataDensity, + datum => { + const value = datum[seriesModel.dataKey]; + const isZero = value === null && datum[labelDataKey] != null; + return isZero ? 0 : value; + }, + ), + sign === "+" ? "top" : "bottom", + renderingContext, + false, + ), + type: "bar", // ensure type is bar for typescript + }; + }, + ); if (seriesOption?.label != null) { seriesOption.label.show = false; 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 a03f9748b400307fc107a38c091f3ad7ff90504c..de65493964245de67a295f6b63b77c4e0072148f 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/scatter/model/index.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/scatter/model/index.ts @@ -107,6 +107,7 @@ export function getScatterPlotModel( const { leftAxisModel, rightAxisModel } = getYAxesModels( seriesModels, + dataset, transformedDataset, settings, columnByDataKey,