From c5179309fdb61b56a7064ccdda682224cb092485 Mon Sep 17 00:00:00 2001 From: James Dunkerley Date: Fri, 26 Apr 2024 08:52:40 +0100 Subject: [PATCH] Improve Table Viz handling of Numbers (#9793) - Added support for NaN, Infinity and -Infinity in the Table viz. - Simplified the logic so all the formatting in a single place in the Table viz. - Sorted Number formatting for BigInt and < 10000. ![image](https://github.com/enso-org/enso/assets/4699705/1486eb7e-df87-4516-90d0-75fda1e9743d) ![image](https://github.com/enso-org/enso/assets/4699705/e55c0e6b-bd3c-4dcf-a65f-41f8516568a6) --- .../visualizations/TableVisualization.vue | 48 ++++++++++--------- .../0.0.0-dev/src/Table/Visualization.enso | 4 +- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/app/gui2/src/components/visualizations/TableVisualization.vue b/app/gui2/src/components/visualizations/TableVisualization.vue index 0e412a6bc3..0b30619d99 100644 --- a/app/gui2/src/components/visualizations/TableVisualization.vue +++ b/app/gui2/src/components/visualizations/TableVisualization.vue @@ -134,6 +134,12 @@ const selectableRowLimits = computed(() => { }) const wasAutomaticallyAutosized = ref(false) +const numberFormat = new Intl.NumberFormat(undefined, { + style: 'decimal', + maximumFractionDigits: 12, + useGrouping: 'min2' as any, +}) + function setRowLimit(newRowLimit: number) { if (newRowLimit !== rowLimit.value) { rowLimit.value = newRowLimit @@ -158,12 +164,29 @@ function escapeHTML(str: string) { } function cellRenderer(params: ICellRendererParams) { + // Convert's the value into a display string. if (params.value === null) return 'Nothing' else if (params.value === undefined) return '' else if (params.value === '') return 'Empty' - else if (typeof params.value === 'number') - return params.value.toLocaleString(undefined, { maximumFractionDigits: 12 }) - else return escapeHTML(params.value.toString()) + else if (typeof params.value === 'number') return numberFormat.format(params.value) + else if (Array.isArray(params.value)) { + const content = params.value + if (isMatrix({ json: content })) { + return `[Vector ${content.length} rows x ${content[0].length} cols]` + } else if (isObjectMatrix({ json: content })) { + return `[Table ${content.length} rows x ${Object.keys(content[0]).length} cols]` + } else { + return `[Vector ${content.length} items]` + } + } else if (typeof params.value === 'object') { + const valueType = params.value?.type + if (valueType === 'BigInt') return numberFormat.format(BigInt(params.value?.value)) + else if (valueType === 'Float') + return `${params.value?.value ?? 'Unknown'}` + else if ('_display_text_' in params.value && params.value['_display_text_']) + return String(params.value['_display_text_']) + else return `{ ${valueType} Object }` + } else return escapeHTML(params.value.toString()) } function addRowIndex(data: object[]): object[] { @@ -217,25 +240,6 @@ function indexField(): ColDef { /** Return a human-readable representation of an object. */ function toRender(content: unknown) { - if (Array.isArray(content)) { - if (isMatrix({ json: content })) { - return `[Vector ${content.length} rows x ${content[0].length} cols]` - } else if (isObjectMatrix({ json: content })) { - return `[Table ${content.length} rows x ${Object.keys(content[0]).length} cols]` - } else { - return `[Vector ${content.length} items]` - } - } - - if (typeof content === 'object' && content != null) { - const type = 'type' in content ? content.type : undefined - if ('_display_text_' in content && content['_display_text_']) { - return String(content['_display_text_']) - } else { - return `{ ${type} Object }` - } - } - return content } diff --git a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso index 224ad25a44..c8d84d6f96 100644 --- a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso +++ b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso @@ -45,6 +45,8 @@ prepare_visualization y max_rows=1000 = pairs = [['_display_text_', '[Function '+x.to_text+']']] value = JS_Object.from_pairs pairs JS_Object.from_pairs [["json", value]] + _ : Number -> + JS_Object.from_pairs [["json", make_json_for_value x]] _ -> js_value = x.to_js_object value = if js_value.is_a JS_Object . not then js_value else @@ -167,7 +169,7 @@ make_json_for_value val level=0 = case val of Nothing -> Nothing _ : Text -> val _ : Number -> - js_version = val.to_js_object + js_version = if val.is_finite then val.to_js_object else JS_Object.from_pairs [["type", "Float"], ["value", val.to_text]] if js_version.is_a JS_Object . not then js_version else pairs = [['_display_text_', val.to_display_text]] + js_version.field_names.map f-> [f, js_version.get f] JS_Object.from_pairs pairs