diff --git a/change/@ni-nimble-components-9a663b6a-ecb5-4698-bd2c-77cb3281255a.json b/change/@ni-nimble-components-9a663b6a-ecb5-4698-bd2c-77cb3281255a.json new file mode 100644 index 0000000000..fa428c7976 --- /dev/null +++ b/change/@ni-nimble-components-9a663b6a-ecb5-4698-bd2c-77cb3281255a.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "New Wafer Map Component API. Introduced `diesTable` and two rendering strategies switched by this input", + "packageName": "@ni/nimble-components", + "email": "33986780+munteannatan@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/package-lock.json b/package-lock.json index 49f8bf3100..faf8b3fe9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9725,15 +9725,6 @@ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", "dev": true }, - "node_modules/@swc/helpers": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.6.tgz", - "integrity": "sha512-aYX01Ke9hunpoCexYAgQucEpARGQ5w/cqHFrIR+e9gdKb1QWTsVJuTJ2ozQzIAxLyRQe/m+2RqzkyOOGiMKRQA==", - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@swc/types": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", @@ -10328,18 +10319,6 @@ "@types/node": "*" } }, - "node_modules/@types/command-line-args": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.3.tgz", - "integrity": "sha512-uv0aG6R0Y8WHZLTamZwtfsDLVRnOa+n+n5rEvFWL5Na5gZ8V2Teab/duDPFzIIIhs9qizDpcavCusCLJZu62Kw==", - "peer": true - }, - "node_modules/@types/command-line-usage": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.4.tgz", - "integrity": "sha512-BwR5KP3Es/CSht0xqBcUXS3qCAUVXwpRKsV2+arxeb65atasuXG9LykC9Ab10Cw3s2raH92ZqOeILaQbsB2ACg==", - "peer": true - }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -11872,26 +11851,6 @@ "node": ">= 8" } }, - "node_modules/apache-arrow": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-15.0.0.tgz", - "integrity": "sha512-e6aunxNKM+woQf137ny3tp/xbLjFJS2oGQxQhYGqW6dGeIwNV1jOeEAeR6sS2jwAI2qLO83gYIP2MBz02Gw5Xw==", - "peer": true, - "dependencies": { - "@swc/helpers": "^0.5.2", - "@types/command-line-args": "^5.2.1", - "@types/command-line-usage": "^5.0.2", - "@types/node": "^20.6.0", - "command-line-args": "^5.2.1", - "command-line-usage": "^7.0.1", - "flatbuffers": "^23.5.26", - "json-bignum": "^0.0.3", - "tslib": "^2.6.2" - }, - "bin": { - "arrow2csv": "bin/arrow2csv.cjs" - } - }, "node_modules/app-root-dir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz", @@ -17677,12 +17636,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/flatbuffers": { - "version": "23.5.26", - "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-23.5.26.tgz", - "integrity": "sha512-vE+SI9vrJDwi1oETtTIFldC/o9GsVKRM+s6EL0nQgxXlYV1Vc4Tk30hj4xGICftInKQKj1F3up2n8UbIVobISQ==", - "peer": true - }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", @@ -20828,15 +20781,6 @@ "node": ">=4" } }, - "node_modules/json-bignum": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/json-bignum/-/json-bignum-0.0.3.tgz", - "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==", - "peer": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -33230,6 +33174,7 @@ "@types/d3-selection": "^3.0.0", "@types/d3-zoom": "^3.0.0", "@types/markdown-it": "^13.0.0", + "apache-arrow": "^15.0.0", "comlink": "4.4.1", "d3-array": "^3.2.2", "d3-random": "^3.0.1", diff --git a/packages/nimble-components/src/utilities/tests/wafer-sets.ts b/packages/nimble-components/src/utilities/tests/wafer-sets.ts new file mode 100644 index 0000000000..8ab580a700 --- /dev/null +++ b/packages/nimble-components/src/utilities/tests/wafer-sets.ts @@ -0,0 +1,10 @@ +export const expectedColIndex: number[] = [0, 1, 1, 1, 2]; + +export const expectedRowIndex: number[] = [1, 1, 0, 2, 1]; + +export const expectedValues: number[] = [ + 88.55000305175781, 90.54000091552734, 92.55999755859375, 95.56999969482422, + 85.76000213623047 +]; + +export const expectedTags: string[][] = [['g'], ['k'], ['n'], ['s'], ['c']]; diff --git a/packages/nimble-components/src/wafer-map/modules/wafer-map-converter.ts b/packages/nimble-components/src/wafer-map/modules/wafer-map-converter.ts new file mode 100644 index 0000000000..6097f86cc4 --- /dev/null +++ b/packages/nimble-components/src/wafer-map/modules/wafer-map-converter.ts @@ -0,0 +1,45 @@ +import { Field, List, Table, Utf8, vectorFromArray } from 'apache-arrow'; +import type { WaferMapDie, WaferMapLayerData } from '../types'; + +/** + * This class is used to convert old wafer map data to new wafer map data + */ +export class WaferMapConverter { + public static toApacheTable(waferMapDies: WaferMapDie[]): Table { + const layers = this.populateLayers(waferMapDies); + + const columnData = { + colIndex: vectorFromArray(new Int32Array(layers.colIndex)), + rowIndex: vectorFromArray(new Int32Array(layers.rowIndex)), + value: vectorFromArray(new Float32Array(layers.values)), + tags: vectorFromArray( + layers.tags, + new List(new Field('', new Utf8())) + ) + }; + + const table = new Table(columnData); + + return table; + } + + public static populateLayers( + waferMapDies: WaferMapDie[] + ): WaferMapLayerData { + const layers: WaferMapLayerData = { + colIndex: [], + rowIndex: [], + values: [], + tags: [] + }; + + waferMapDies.forEach((die, index) => { + layers.colIndex.push(die.x); + layers.rowIndex.push(die.y); + layers.values.push(parseFloat(die.value)); + layers.tags[index] = die.tags ?? []; + }); + + return layers; + } +} diff --git a/packages/nimble-components/src/wafer-map/tests/wafer-map-converter.spec.ts b/packages/nimble-components/src/wafer-map/tests/wafer-map-converter.spec.ts new file mode 100644 index 0000000000..1b5c1f9834 --- /dev/null +++ b/packages/nimble-components/src/wafer-map/tests/wafer-map-converter.spec.ts @@ -0,0 +1,69 @@ +import { + Field, + List, + Table, + Utf8, + vectorFromArray, + Float32, + Int32 +} from 'apache-arrow'; +import { WaferMapConverter } from '../modules/wafer-map-converter'; +import type { WaferMapDie } from '../types'; +import { generateWaferData } from './data-generator'; +import { + goodValueGenerator, + highlightedValueGenerator +} from './value-generator'; +import { + expectedTags, + expectedValues, + expectedRowIndex, + expectedColIndex +} from '../../utilities/tests/wafer-sets'; + +describe('WaferMap Converter', () => { + const seed = 1; + const waferMapDies: WaferMapDie[] = generateWaferData( + 2, + goodValueGenerator(seed), + highlightedValueGenerator(seed) + ); + + it('should populate the wafer layers', () => { + const layers = WaferMapConverter.populateLayers(waferMapDies); + expect(layers.colIndex).toEqual(expectedColIndex); + expect(layers.rowIndex).toEqual(expectedRowIndex); + expect(layers.values).toEqual( + expectedValues.map(value => parseFloat(value.toFixed(2))) + ); + expect(layers.tags).toEqual(expectedTags); + }); + + it('should convert wafer map data and types to apache arrow table', () => { + const table = WaferMapConverter.toApacheTable(waferMapDies); + + const computedTable = new Table({ + colIndex: vectorFromArray(new Int32Array(expectedColIndex)), + rowIndex: vectorFromArray(new Int32Array(expectedRowIndex)), + value: vectorFromArray(new Float32Array(expectedValues)), + tags: vectorFromArray( + expectedTags, + new List(new Field('', new Utf8())) + ) + }); + + expect(table).toEqual(computedTable); + + const columnNames = table.schema.fields.map(field => field.name); + expect(columnNames).toEqual(['colIndex', 'rowIndex', 'value', 'tags']); + + const columnTypes = table.schema.fields.map(field => (field.type as Field).toString()); + const expectedTypes = [ + new Int32(), + new Int32(), + new Float32(), + new List(new Field('', new Utf8())) + ].map(type => type.toString()); + expect(columnTypes).toEqual(expectedTypes); + }); +}); diff --git a/packages/nimble-components/src/wafer-map/types.ts b/packages/nimble-components/src/wafer-map/types.ts index bd9a4ac975..c9c1b4d3ad 100644 --- a/packages/nimble-components/src/wafer-map/types.ts +++ b/packages/nimble-components/src/wafer-map/types.ts @@ -88,6 +88,14 @@ export interface WaferMapValidity extends ValidityObject { readonly invalidDiesTableSchema: boolean; } +export interface WaferMapLayerData { + colIndex: number[]; + rowIndex: number[]; + values: number[]; + tags: string[][]; + readonly invalidDiesTableSchema: boolean; +} + // Apache arrow probably should not be using a Record and index types on TypeMap // because in strict checking they end up required. // See: https://github.com/apache/arrow/issues/12663#issuecomment-1088244575