This is an automated email from the ASF dual-hosted git repository.

michaelsmolina pushed a commit to branch 5.0
in repository https://gitbox.apache.org/repos/asf/superset.git

commit c7cc436b0ba07beffbb1961eab7683afd6e44786
Author: Michael S. Molina <[email protected]>
AuthorDate: Fri Feb 14 09:04:23 2025 -0300

    fix: Decimal values for Histogram bins (#32253)
    
    (cherry picked from commit ffe9244458d03995b760638e9bb5b347c0cc68d6)
---
 .../src/sections/chartTitle.tsx                    |  2 +-
 .../src/Histogram/controlPanel.tsx                 | 57 +++++++++++++++++++++-
 .../src/Histogram/transformProps.ts                | 37 +++++++++-----
 .../plugin-chart-echarts/src/Histogram/types.ts    |  2 +
 superset/utils/pandas_postprocessing/histogram.py  |  3 +-
 .../pandas_postprocessing/test_histogram.py        | 48 ++++++++++--------
 6 files changed, 112 insertions(+), 37 deletions(-)

diff --git 
a/superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx
 
b/superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx
index e8cda4991f..6c8d08364c 100644
--- 
a/superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx
+++ 
b/superset-frontend/packages/superset-ui-chart-controls/src/sections/chartTitle.tsx
@@ -54,7 +54,7 @@ export const titleControls: ControlPanelSectionConfig = {
           type: 'SelectControl',
           freeForm: true,
           clearable: true,
-          label: t('X AXIS TITLE BOTTOM MARGIN'),
+          label: t('X Axis Title Margin'),
           renderTrigger: true,
           default: TITLE_MARGIN_OPTIONS[0],
           choices: formatSelectOptions(TITLE_MARGIN_OPTIONS),
diff --git 
a/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/controlPanel.tsx 
b/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/controlPanel.tsx
index a347694f1b..d4e8d4b86d 100644
--- 
a/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/controlPanel.tsx
+++ 
b/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/controlPanel.tsx
@@ -27,7 +27,9 @@ import {
   formatSelectOptionsForRange,
   dndGroupByControl,
   columnsByType,
-  sections,
+  D3_FORMAT_OPTIONS,
+  D3_FORMAT_DOCS,
+  D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT,
 } from '@superset-ui/chart-controls';
 import { showLegendControl, showValueControl } from '../controls';
 
@@ -105,7 +107,6 @@ const config: ControlPanelConfig = {
         ],
       ],
     },
-    sections.titleControls,
     {
       label: t('Chart Options'),
       expanded: true,
@@ -113,6 +114,58 @@ const config: ControlPanelConfig = {
         ['color_scheme'],
         [showValueControl],
         [showLegendControl],
+        [
+          {
+            name: 'x_axis_title',
+            config: {
+              type: 'TextControl',
+              label: t('X Axis Title'),
+              renderTrigger: true,
+              default: '',
+              description: t('Changing this control takes effect instantly'),
+            },
+          },
+        ],
+        [
+          {
+            name: 'x_axis_format',
+            config: {
+              type: 'SelectControl',
+              freeForm: true,
+              label: t('X Axis Format'),
+              renderTrigger: true,
+              default: 'SMART_NUMBER',
+              choices: D3_FORMAT_OPTIONS,
+              description: `${D3_FORMAT_DOCS} 
${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`,
+            },
+          },
+        ],
+        [
+          {
+            name: 'y_axis_title',
+            config: {
+              type: 'TextControl',
+              label: t('Y Axis Title'),
+              renderTrigger: true,
+              default: '',
+              description: t('Changing this control takes effect instantly'),
+            },
+          },
+        ],
+        [
+          {
+            name: 'y_axis_format',
+            config: {
+              type: 'SelectControl',
+              freeForm: true,
+              label: t('Y Axis Format'),
+              renderTrigger: true,
+              default: 'SMART_NUMBER',
+              choices: D3_FORMAT_OPTIONS,
+              description: `${D3_FORMAT_DOCS} 
${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`,
+            },
+          },
+        ],
       ],
     },
   ],
diff --git 
a/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/transformProps.ts
 
b/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/transformProps.ts
index df8fe3b156..388e79ae94 100644
--- 
a/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/transformProps.ts
+++ 
b/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/transformProps.ts
@@ -25,7 +25,7 @@ import {
   CategoricalColorNamespace,
   NumberFormats,
   getColumnLabel,
-  getNumberFormatter,
+  getValueFormatter,
   tooltipHtml,
 } from '@superset-ui/core';
 import { HistogramChartProps, HistogramTransformedProps } from './types';
@@ -41,6 +41,7 @@ export default function transformProps(
   const refs: Refs = {};
   let focusedSeries: number | undefined;
   const {
+    datasource: { currencyFormats = {}, columnFormats = {} },
     formData,
     height,
     hooks,
@@ -58,19 +59,33 @@ export default function transformProps(
     showLegend,
     showValue,
     sliceId,
+    xAxisFormat,
     xAxisTitle,
     yAxisTitle,
+    yAxisFormat,
   } = formData;
   const { data } = queriesData[0];
   const colorFn = CategoricalColorNamespace.getScale(colorScheme);
-  const formatter = getNumberFormatter(
-    normalize ? NumberFormats.FLOAT_2_POINT : NumberFormats.INTEGER,
-  );
+
+  const formatter = (format: string) =>
+    getValueFormatter(
+      column,
+      currencyFormats,
+      columnFormats,
+      format,
+      undefined,
+    );
+  const xAxisFormatter = formatter(xAxisFormat);
+  const yAxisFormatter = formatter(yAxisFormat);
+
   const percentFormatter = getPercentFormatter(NumberFormats.PERCENT_2_POINT);
   const groupbySet = new Set(groupby);
-  const xAxisData: string[] = Object.keys(data[0]).filter(
-    key => !groupbySet.has(key),
-  );
+  const xAxisData: string[] = Object.keys(data[0])
+    .filter(key => !groupbySet.has(key))
+    .map(key => {
+      const array = key.split(' - ').map(value => parseFloat(value));
+      return `${xAxisFormatter(array[0])} '-' ${xAxisFormatter(array[1])}`;
+    });
   const barSeries: BarSeriesOption[] = data.map(datum => {
     const seriesName =
       groupby.length > 0
@@ -91,7 +106,7 @@ export default function transformProps(
         position: 'top',
         formatter: params => {
           const { value } = params;
-          return formatter.format(value as number);
+          return yAxisFormatter.format(value as number);
         },
       },
     };
@@ -108,7 +123,7 @@ export default function transformProps(
     const title = params[0].name;
     const rows = params.map(param => {
       const { marker, seriesName, value } = param;
-      return [`${marker}${seriesName}`, formatter.format(value as number)];
+      return [`${marker}${seriesName}`, yAxisFormatter.format(value as 
number)];
     });
     if (groupby.length > 0) {
       const total = params.reduce(
@@ -122,7 +137,7 @@ export default function transformProps(
           ),
         );
       }
-      const totalRow = ['Total', formatter.format(total)];
+      const totalRow = ['Total', yAxisFormatter.format(total)];
       if (!normalize) {
         totalRow.push(percentFormatter.format(1));
       }
@@ -159,7 +174,7 @@ export default function transformProps(
       type: 'value',
       nameLocation: 'middle',
       axisLabel: {
-        formatter: (value: number) => formatter.format(value),
+        formatter: (value: number) => yAxisFormatter.format(value),
       },
     },
     series: barSeries,
diff --git 
a/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/types.ts 
b/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/types.ts
index ca6c16d79e..ab3d4b75c2 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/types.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/types.ts
@@ -28,7 +28,9 @@ export type HistogramFormData = QueryFormData & {
   sliceId: number;
   showLegend: boolean;
   showValue: boolean;
+  xAxisFormat: string;
   xAxisTitle: string;
+  yAxisFormat: string;
   yAxisTitle: string;
 };
 
diff --git a/superset/utils/pandas_postprocessing/histogram.py 
b/superset/utils/pandas_postprocessing/histogram.py
index f55f0d0762..8ef9abadc7 100644
--- a/superset/utils/pandas_postprocessing/histogram.py
+++ b/superset/utils/pandas_postprocessing/histogram.py
@@ -60,8 +60,7 @@ def histogram(
 
     # convert the bin edges to strings
     bin_edges_str = [
-        f"{int(bin_edges[i])} - {int(bin_edges[i+1])}"
-        for i in range(len(bin_edges) - 1)
+        f"{bin_edges[i]} - {bin_edges[i+1]}" for i in range(len(bin_edges) - 1)
     ]
 
     def hist_values(series: Series) -> np.ndarray:
diff --git a/tests/unit_tests/pandas_postprocessing/test_histogram.py 
b/tests/unit_tests/pandas_postprocessing/test_histogram.py
index ee0261a9fa..9246a06df0 100644
--- a/tests/unit_tests/pandas_postprocessing/test_histogram.py
+++ b/tests/unit_tests/pandas_postprocessing/test_histogram.py
@@ -35,7 +35,13 @@ def test_histogram_no_groupby():
     )
     result = histogram(data_with_no_groupings, "a", [], bins)
     assert result.shape == (1, bins)
-    assert result.columns.tolist() == ["1 - 2", "2 - 4", "4 - 6", "6 - 8", "8 
- 10"]
+    assert result.columns.tolist() == [
+        "1.0 - 2.8",
+        "2.8 - 4.6",
+        "4.6 - 6.4",
+        "6.4 - 8.2",
+        "8.2 - 10.0",
+    ]
     assert result.values.tolist() == [[2, 2, 2, 2, 2]]
 
 
@@ -44,11 +50,11 @@ def test_histogram_with_groupby():
     assert result.shape == (2, bins + 1)
     assert result.columns.tolist() == [
         "group",
-        "1 - 2",
-        "2 - 4",
-        "4 - 6",
-        "6 - 8",
-        "8 - 10",
+        "1.0 - 2.8",
+        "2.8 - 4.6",
+        "4.6 - 6.4",
+        "6.4 - 8.2",
+        "8.2 - 10.0",
     ]
     assert result.values.tolist() == [["A", 2, 0, 2, 0, 2], ["B", 0, 2, 0, 2, 
0]]
 
@@ -58,11 +64,11 @@ def test_histogram_with_groupby_and_normalize():
     assert result.shape == (2, bins + 1)
     assert result.columns.tolist() == [
         "group",
-        "1 - 2",
-        "2 - 4",
-        "4 - 6",
-        "6 - 8",
-        "8 - 10",
+        "1.0 - 2.8",
+        "2.8 - 4.6",
+        "4.6 - 6.4",
+        "6.4 - 8.2",
+        "8.2 - 10.0",
     ]
     assert result.values.tolist() == [
         ["A", 0.2, 0.0, 0.2, 0.0, 0.2],
@@ -75,11 +81,11 @@ def test_histogram_with_groupby_and_cumulative():
     assert result.shape == (2, bins + 1)
     assert result.columns.tolist() == [
         "group",
-        "1 - 2",
-        "2 - 4",
-        "4 - 6",
-        "6 - 8",
-        "8 - 10",
+        "1.0 - 2.8",
+        "2.8 - 4.6",
+        "4.6 - 6.4",
+        "6.4 - 8.2",
+        "8.2 - 10.0",
     ]
     assert result.values.tolist() == [["A", 2, 2, 4, 4, 6], ["B", 0, 2, 2, 4, 
4]]
 
@@ -89,11 +95,11 @@ def 
test_histogram_with_groupby_and_cumulative_and_normalize():
     assert result.shape == (2, bins + 1)
     assert result.columns.tolist() == [
         "group",
-        "1 - 2",
-        "2 - 4",
-        "4 - 6",
-        "6 - 8",
-        "8 - 10",
+        "1.0 - 2.8",
+        "2.8 - 4.6",
+        "4.6 - 6.4",
+        "6.4 - 8.2",
+        "8.2 - 10.0",
     ]
     assert result.values.tolist() == [
         [

Reply via email to