diff --git a/libs/shared/lib/statistics/graphStatistics.ts b/libs/shared/lib/statistics/graphStatistics.ts index 7f2db7998d8e9a62f21100d3b714c4906a9aaf6f..8e1d79c189333e2dedc2bdacce8ad03e0b3dee92 100644 --- a/libs/shared/lib/statistics/graphStatistics.ts +++ b/libs/shared/lib/statistics/graphStatistics.ts @@ -10,12 +10,14 @@ const getGraphStatistics = (graph: GraphQueryResultFromBackend): GraphStatistics const density = n_nodes < 2 ? 0 : (n_edges * 2) / (n_nodes * (n_nodes - 1)); + // general nodes and edges statistics const metaData: GraphStatistics = { topological: { density, self_loops: 0 }, nodes: { labels: [], count: n_nodes, types: {} }, edges: { labels: [], count: n_edges, types: {} }, }; + // attributes based statistics nodes.forEach((node) => { const nodeType = getNodeLabel(node); if (!metaData.nodes.labels.includes(nodeType)) { @@ -25,7 +27,6 @@ const getGraphStatistics = (graph: GraphQueryResultFromBackend): GraphStatistics if (!metaData.nodes.types[nodeType]) { metaData.nodes.types[nodeType] = { count: 0, attributes: {} }; } - metaData.nodes.types[nodeType].count++; Object.entries(node.attributes).forEach(([attributeId, attributeValue]) => { @@ -34,7 +35,6 @@ const getGraphStatistics = (graph: GraphQueryResultFromBackend): GraphStatistics if (!metaData.nodes.types[nodeType].attributes[attributeId]) { metaData.nodes.types[nodeType].attributes[attributeId] = { attributeType, statistics: initializeStatistics(attributeType) }; } - updateStatistics(metaData.nodes.types[nodeType].attributes[attributeId], attributeValue); }); }); diff --git a/libs/shared/lib/statistics/statistics.types.ts b/libs/shared/lib/statistics/statistics.types.ts index 78a0ee3395e31c72d26404a415c2d7a7dadd3523..49d9274afb28ca2e52c784f690da1f1bfc12e7b8 100644 --- a/libs/shared/lib/statistics/statistics.types.ts +++ b/libs/shared/lib/statistics/statistics.types.ts @@ -67,6 +67,7 @@ type CategoricalStats = { uniqueItems: number; values: string[]; mode: string; + count: number; }; type TemporalStats = { @@ -77,6 +78,7 @@ type TemporalStats = { type ArrayStats = { length: number; + count: number; }; type ObjectStats = { diff --git a/libs/shared/lib/statistics/tests/attributeStats.spec.ts b/libs/shared/lib/statistics/tests/attributeStats.spec.ts index da290a2d8bb7de2dea68704c1a6e25266486e7e5..fc95f0f61a88d8fbc18a4b4b9dba5b356bbdf649 100644 --- a/libs/shared/lib/statistics/tests/attributeStats.spec.ts +++ b/libs/shared/lib/statistics/tests/attributeStats.spec.ts @@ -12,10 +12,11 @@ import type { ArrayStats, BooleanStats, CategoricalStats, NumericalStats, Tempor describe('updateArrayStats', () => { it('should update the length of the array', () => { - const stats: ArrayStats = { length: 0 }; + const stats: ArrayStats = { length: 0, count: 0 }; const value = [1, 2, 3]; updateArrayStats(stats, value); expect(stats.length).toBe(3); + expect(stats.count).toBe(1); }); }); @@ -37,7 +38,7 @@ describe('updateBooleanStats', () => { describe('updateCategoricalStats', () => { it('should update mode and unique items count', () => { - const stats: CategoricalStats = { uniqueItems: 0, values: [], mode: '' }; + const stats: CategoricalStats = { uniqueItems: 0, values: [], mode: '', count: 0 }; updateCategoricalStats(stats, 'apple'); updateCategoricalStats(stats, 'banana'); updateCategoricalStats(stats, 'apple'); @@ -45,6 +46,7 @@ describe('updateCategoricalStats', () => { expect(stats.values).toEqual(['apple', 'banana', 'apple']); expect(stats.uniqueItems).toBe(2); expect(stats.mode).toBe('apple'); + expect(stats.count).toBe(3); }); }); @@ -86,7 +88,7 @@ describe('updateObjectStats', () => { describe('initializeStatistics', () => { it('should initialize statistics for string type', () => { const stats = initializeStatistics('string'); - expect(stats).toEqual({ uniqueItems: 0, values: [], mode: '' }); + expect(stats).toEqual({ uniqueItems: 0, values: [], mode: '', count: 0 }); }); it('should initialize statistics for boolean type', () => { @@ -96,7 +98,7 @@ describe('initializeStatistics', () => { it('should initialize statistics for number type', () => { const stats = initializeStatistics('number'); - expect(stats).toEqual({ min: Infinity, max: -Infinity, average: 0 }); + expect(stats).toEqual({ min: Infinity, max: -Infinity, average: 0, count: 0 }); }); it('should throw an error for an unknown type', () => { diff --git a/libs/shared/lib/statistics/utils/attributeStats/array.ts b/libs/shared/lib/statistics/utils/attributeStats/array.ts index c6a7dc55d26d75f745b1f2675d301dea59f535ee..0cbea69b8c88409b952daea2e7aa3cbd2333a693 100644 --- a/libs/shared/lib/statistics/utils/attributeStats/array.ts +++ b/libs/shared/lib/statistics/utils/attributeStats/array.ts @@ -2,6 +2,7 @@ import { ArrayStats } from '../../statistics.types'; const updateArrayStats = (stats: ArrayStats, value: any[]) => { stats.length = value.length; + stats.count++; }; export { updateArrayStats }; diff --git a/libs/shared/lib/statistics/utils/attributeStats/categorical.ts b/libs/shared/lib/statistics/utils/attributeStats/categorical.ts index fc9b128ce8b25c03b49557e0ce471719062bb1d1..e28b91aa6006a553c4b898398a4775f7ae4f49b4 100644 --- a/libs/shared/lib/statistics/utils/attributeStats/categorical.ts +++ b/libs/shared/lib/statistics/utils/attributeStats/categorical.ts @@ -11,6 +11,7 @@ const updateCategoricalStats = (stats: CategoricalStats, value: string | boolean frequencyMap[val] = (frequencyMap[val] || 0) + 1; }); stats.mode = Object.keys(frequencyMap).reduce((a, b) => (frequencyMap[a] > frequencyMap[b] ? a : b)); + stats.count++; }; export { updateCategoricalStats }; diff --git a/libs/shared/lib/statistics/utils/attributeStats/initialize.ts b/libs/shared/lib/statistics/utils/attributeStats/initialize.ts index 4f93930d50644426fa02fc1ea4ceffa6c401e771..c9b018646a869cba123378f2eb6c2537a95608a1 100644 --- a/libs/shared/lib/statistics/utils/attributeStats/initialize.ts +++ b/libs/shared/lib/statistics/utils/attributeStats/initialize.ts @@ -7,6 +7,7 @@ const initializeStatistics = <T extends AttributeType>(type: T): AttributeTypeSt uniqueItems: 0, values: [], mode: '', + count: 0, } as unknown as AttributeTypeStats<T>; case 'boolean': return { @@ -18,6 +19,7 @@ const initializeStatistics = <T extends AttributeType>(type: T): AttributeTypeSt min: Infinity, max: -Infinity, average: 0, + count: 0, } as unknown as AttributeTypeStats<T>; case 'date': case 'time': @@ -31,6 +33,7 @@ const initializeStatistics = <T extends AttributeType>(type: T): AttributeTypeSt case 'array': return { length: 0, + count: 0, } as unknown as AttributeTypeStats<T>; case 'object': return {