diff --git a/libs/shared/lib/vis/visualizations/paohvis/components/HyperRangeBlock.tsx b/libs/shared/lib/vis/visualizations/paohvis/components/HyperRangeBlock.tsx index a313a2950ef7e91b0d46ead168332423cf43110b..f0cdcd4b0702294afc0da5117372f77a4948fbac 100644 --- a/libs/shared/lib/vis/visualizations/paohvis/components/HyperRangeBlock.tsx +++ b/libs/shared/lib/vis/visualizations/paohvis/components/HyperRangeBlock.tsx @@ -174,9 +174,10 @@ export const HyperEdgeRangesBlock: React.FC<HyperEdgeRangesBlockProps> = ({ {columnHeaderInformation.map((row, index) => ( <g key={'text-col-' + index} transform={'translate(' + accumulatedWidthHeaders[index] + ',' + 0 + ')'}> <rect width={row.width} height={rowHeight} fill={'hsl(var(--clr-sec--0))'} strokeWidth={0}></rect> - <text x={row.width * marginText} y={rowHeight / 2} dy="0" dominantBaseline="middle" className={classTopTextColumns}> - {row.data[indexRows]} - </text> + + <foreignObject x="0" y="0" width={row.width} height={rowHeight}> + <span className={`${classTopTextColumns}`}>{row.data[indexRows]}</span> + </foreignObject> </g> ))} </g> @@ -208,9 +209,10 @@ export const HyperEdgeRangesBlock: React.FC<HyperEdgeRangesBlockProps> = ({ }} > <rect width={headerData.width} height={rowHeight} fill={'hsl(var(--clr-sec--200))'} opacity={1.0} strokeWidth={0}></rect> - <text x={marginText * headerData.width} y={0.5 * rowHeight} dy="0" dominantBaseline="middle" className={classTopTextColumns}> - {headerData.header} - </text> + + <foreignObject x="0" y="0" width={headerData.width} height={rowHeight}> + <span className={`${classTopTextColumns}`}>{headerData.header}</span> + </foreignObject> {iconComponents[headerIndex] && isHovered && ( <svg xmlns="http://www.w3.org/2000/svg" diff --git a/libs/shared/lib/vis/visualizations/paohvis/components/RowLabels.tsx b/libs/shared/lib/vis/visualizations/paohvis/components/RowLabels.tsx index 425472216e37bd60ab2cb374ef403cb21898f595..d71c0d8aa3794e42fb5d3dee26d5eb2aa58e42b4 100644 --- a/libs/shared/lib/vis/visualizations/paohvis/components/RowLabels.tsx +++ b/libs/shared/lib/vis/visualizations/paohvis/components/RowLabels.tsx @@ -100,9 +100,9 @@ export const RowLabels = ({ fill={indexRows % 2 === 0 ? 'hsl(var(--clr-sec--50))' : 'hsl(var(--clr-sec--0))'} strokeWidth={0} ></rect> - <text x={row.width * marginText} y={rowHeight / 2} dy="0" dominantBaseline="middle" className={classTopTextColums}> - {row.data[indexRows]} - </text> + <foreignObject x="0" y="0" width={row.width} height={rowHeight}> + <span className={`${classTopTextColums}`}>{row.data[indexRows]}</span> + </foreignObject> </g> ))} </g> @@ -153,9 +153,11 @@ export const RowLabels = ({ }} > <rect width={row.width} height={rowHeight} fill={'hsl(var(--clr-sec--200))'} opacity={1.0} strokeWidth={0}></rect> - <text x={marginText * row.width} y={0.5 * rowHeight} dy="0" dominantBaseline="middle" className={classTopTextColums}> - {row.header} - </text> + + <foreignObject x="0" y="0" width={row.width} height={rowHeight}> + <span className={`${classTopTextColums}`}>{row.header}</span> + </foreignObject> + {iconComponents[indexRows] && isHovered && ( <svg xmlns="http://www.w3.org/2000/svg" diff --git a/libs/shared/lib/vis/visualizations/paohvis/docs.mdx b/libs/shared/lib/vis/visualizations/paohvis/docs.mdx deleted file mode 100644 index f6601950532a4117fe058747cd7e564721eb03ba..0000000000000000000000000000000000000000 --- a/libs/shared/lib/vis/visualizations/paohvis/docs.mdx +++ /dev/null @@ -1,45 +0,0 @@ -import { Meta, Unstyled } from '@storybook/blocks'; - -<Meta title="Visualizations/Paohvis" /> - -# Paohvis documentation - -## Components - -1. [MakePaohvisMenu](#MakePaohvisMenu) -2. [RowLabelColumn](#RowLabelColumn) -3. [HyperEdgesRange](#HyperEdgesRange) -4. [PaohvisFilterComponent](#PaohvisFilterComponent) -5. [Important functions](#Importantfunctions) - -## MakePaohvisMenu - -Renders the menu to configure PAOHvis - -## RowLabelColumn - -Renders the left column with row labels - -## HyperEdgesRange - -Renders the table and the hyperedges - -## PaohvisFilterComponent - -Manage the filtering of the hyperedges - -# Important functions: toPaohvisDataParserUsercase - -toPaohvisDataParserUsercase(): Given a paohvis configuration and a queryResult it creates a data structure to make the paohvis visualization. - -1: parseQueryResult(PaohvisAxisInfo, nodeOrder: PaohvisNodeOrder) - -# Important functions: SortUseCase - -Responsible for sorting the data for the ToPaohvisDataParser. Given: - -- nodeOrder: [ alphabetical = 'Alphabetical', degree = 'Degree (amount of hyperedges)', byGroup = 'By Group' ] -- rowNodes: array nodes -- hyperEdgeDegree: nodes with its hyperedge degrees - -SortUseCase.sortNodes(nodeOrder, rowNodes, hyperEdgeDegree) does not return anything, just sorts the nodes array. diff --git a/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx b/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx index 3b2e4d26f4dfdb4e1aac6aec1718ee385881b23f..698e99865ab8b84cf1f4d278371e5f27139cb48e 100644 --- a/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx +++ b/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx @@ -39,7 +39,8 @@ export const TestWithMarieBoucherSample = { ...(await mockData.marieBoucherSample()), updateSettings: () => {}, schema: marieBoucherSampleSchemaRaw, - settings: { + //configuration: PaohVisComponent.configuration, + configuration: { ...PaohVisComponent.settings, rowNode: 'merchant', columnNode: 'merchant', @@ -52,7 +53,7 @@ export const TestWithBig2ndChamber = { ...(await mockData.big2ndChamberQueryResult()), updateSettings: () => {}, schema: big2ndChamberSchemaRaw, - settings: { + configuration: { ...PaohVisComponent.settings, rowNode: 'kamerleden', columnNode: 'commissies', @@ -65,7 +66,7 @@ export const TestWithAirport = { ...(await mockData.bigMockQueryResults()), updateSettings: () => {}, schema: simpleSchemaAirportRaw, - settings: { + configuration: { ...PaohVisComponent.settings, rowNode: 'airports', columnNode: 'airports', diff --git a/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx b/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx index d8591de163526dd9fe9964501624930d6c85f7de..e3206082d04dbad00536f5967bde76243ed83ab1 100644 --- a/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx +++ b/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx @@ -38,11 +38,11 @@ const settings: PaohVisProps = { columnNode: '', attributeRowShow: ['_id', '# Connections'], attributeColumnShow: ['_id', '# Connections'], - numRowsDisplay: 10, + numRowsDisplay: 20, numColumnsDisplay: 30, rowJumpAmount: 3, colJumpAmount: 3, - mergeData: true, + mergeData: false, }; export const PaohVis = ({ data, graphMetadata, schema, settings, updateSettings }: VisualizationPropTypes<PaohVisProps>) => { @@ -115,7 +115,8 @@ export const PaohVis = ({ data, graphMetadata, schema, settings, updateSettings const [widthTotalColumnInformation, setWidthTotalColumnInformation] = useState<number>(0); // text text-sm, font-semibold - const classTopTextColumns = 'font-inter font-medium text-xs stroke-none text-secondary-800'; + const classTopTextColumns = + 'font-inter font-medium text-xs stroke-none text-secondary-800 mx-1 flex items-center overflow-hidden text-ellipsis'; const configStyle = { colorText: 'hsl(var(--clr-sec--800))', @@ -144,17 +145,17 @@ export const PaohVis = ({ data, graphMetadata, schema, settings, updateSettings const onMouseEnterRowLabels = (event: React.MouseEvent<SVGGElement, MouseEvent>) => { const targetClassList = (event.currentTarget as SVGGElement).classList; // all elements - unselect - selectAll('.rowsLabel').selectAll('text').attr('fill', configStyle.colorTextUnselect); + selectAll('.rowsLabel').selectAll('span').style('color', configStyle.colorTextUnselect); selectAll('.' + targetClassList[1]) - .selectAll('text') - .attr('fill', configStyle.colorText); + .selectAll('span') + .style('color', configStyle.colorText); // all hyperedges - unselect const hyperEdgeBlock = selectAll('.hyperEdgeBlock'); hyperEdgeBlock.selectAll('circle').attr('stroke-opacity', '.3'); hyperEdgeBlock.selectAll('line').attr('opacity', '.3'); - selectAll('.text-columns').selectAll('text').attr('fill', configStyle.colorTextUnselect); + selectAll('.text-columns').selectAll('span').style('color', configStyle.colorTextUnselect); // get row selected const rowSelection: number = parseInt(targetClassList[1].substring('row-'.length), 10); @@ -167,8 +168,8 @@ export const PaohVis = ({ data, graphMetadata, schema, settings, updateSettings const classList = Array.from(hyperEdge.classList); // text columns selectAll('.col-' + classList[1].substring('hyperEdge-col-'.length)) - .selectAll('text') - .attr('fill', configStyle.colorText); + .selectAll('span') + .style('color', configStyle.colorText); // hypererdge select('.' + classList[1]) @@ -187,20 +188,20 @@ export const PaohVis = ({ data, graphMetadata, schema, settings, updateSettings .each(function () { const circleInside: number = parseInt(select(this).attr('class').substring('circle-'.length), 10); selectAll('.row-' + (circleInside - (currentPageRows?.startIndexRow ?? 0))) - .selectAll('text') - .attr('fill', configStyle.colorText); + .selectAll('span') + .style('color', configStyle.colorText); }); } }); }; const onMouseLeaveRowLabels = () => { - selectAll('.rowsLabel').selectAll('text').attr('fill', configStyle.colorText); + selectAll('.rowsLabel').selectAll('span').style('color', configStyle.colorText); const hyperEdgeBlock = selectAll('.hyperEdgeBlock'); hyperEdgeBlock.selectAll('circle').attr('stroke-opacity', '1'); hyperEdgeBlock.selectAll('circle').attr('fill', 'white'); hyperEdgeBlock.selectAll('line').attr('opacity', '1'); - selectAll('.colsLabel').selectAll('text').attr('fill', configStyle.colorText); + selectAll('.colsLabel').selectAll('span').style('color', configStyle.colorText); }; const onMouseEnterHyperEdge = (event: React.MouseEvent<SVGGElement, MouseEvent>) => { @@ -211,8 +212,8 @@ export const PaohVis = ({ data, graphMetadata, schema, settings, updateSettings hyperEdgeBlock.selectAll('circle').attr('stroke-opacity', '.3'); hyperEdgeBlock.selectAll('line').attr('opacity', '.3'); // all elements: column text and row text - selectAll('.colsLabel').selectAll('text').attr('fill', configStyle.colorTextUnselect); - selectAll('.rowsLabel').selectAll('text').attr('fill', configStyle.colorTextUnselect); + selectAll('.colsLabel').selectAll('span').style('color', configStyle.colorTextUnselect); + selectAll('.rowsLabel').selectAll('span').style('color', configStyle.colorTextUnselect); // selected elements const hyperEdgeSelected = select('.' + targetClassList[1]); @@ -222,9 +223,10 @@ export const PaohVis = ({ data, graphMetadata, schema, settings, updateSettings // selected elements col text const columnSelection = targetClassList[1].substring('hyperEdge-'.length); + selectAll('.' + columnSelection) - .selectAll('text') - .attr('fill', configStyle.colorText); + .selectAll('span') + .style('color', configStyle.colorText); // selected elements nodes text hyperEdgeSelected.selectAll('circle').each(function (d, i) { @@ -234,15 +236,15 @@ export const PaohVis = ({ data, graphMetadata, schema, settings, updateSettings if (currentPageRows) { const indexNumber = parseInt(index); const rowSelector = `.row-${indexNumber - currentPageRows.startIndexRow}`; - select(rowSelector).selectAll('text').attr('fill', configStyle.colorText); + select(rowSelector).selectAll('span').style('color', configStyle.colorText); } }); }; const onMouseLeaveHyperEdge = () => { // all elements - selectAll('.colsLabel').selectAll('text').attr('fill', configStyle.colorText); - selectAll('.rowsLabel').selectAll('text').attr('fill', configStyle.colorText); + selectAll('.colsLabel').selectAll('span').style('color', configStyle.colorText); + selectAll('.rowsLabel').selectAll('span').style('color', configStyle.colorText); const hyperEdgeBlock = selectAll('.hyperEdgeBlock'); hyperEdgeBlock.selectAll('circle').attr('stroke-opacity', '1'); @@ -506,186 +508,200 @@ export const PaohVis = ({ data, graphMetadata, schema, settings, updateSettings // set new data // for dev env - let labelEdge = graphMetadata.edges.labels[0]; - let edgeSchema = schema.edges.find((obj) => String(obj.key).includes(labelEdge)); - - // with sb - //if ('to' in schema.edges[0]) { // SB - if (true) { - //const toNode = schema.edges[0].to as string; // sb - let toNode = edgeSchema?.target as string; - const columnNodeAttributes = Object.keys(graphMetadata.nodes.types[settings.columnNode].attributes); - - const newData = parseQueryResult(data, settings as PaohVisProps, toNode, settings.mergeData); - // original data without slicing - setNumRowsVisible(Math.min(configPaohvis.rowsMaxPerPage, newData.rowLabels.length)); - - const rowNodes = newData.nodes.filter((obj) => obj['label'].includes(settings.rowNode)); - const columnNodes = newData.nodes.filter((obj) => obj['label'].includes(settings.columnNode)); - - // to keep order of new attributes - prevDisplayAttributesColumns.current = [...columnNodeAttributes]; - - setDataModel({ - pageData: { - rowLabels: newData.rowLabels.slice(0, configPaohvis.rowsMaxPerPage), - hyperEdgeRanges: newData.hyperEdgeRanges.slice(0, configPaohvis.columnsMaxPerPage), - rowDegrees: newData.rowDegrees, - nodes: newData.nodes, - edges: newData.edges, - }, - data: newData, - originalData: newData, - }); + let labelEdge = ''; + let edgeSchema; - // Update lines hyperedges - const newLinePositions = newData.hyperEdgeRanges.slice(0, configPaohvis.columnsMaxPerPage).map((hyperEdgeRange) => { - return intersectionElements( - [0, Math.min(configPaohvis.rowsMaxPerPage, newData.rowLabels.length)], - hyperEdgeRange.hyperEdges.indices, - ); - }); - setLineHyperEdges(newLinePositions); + let toNode = ''; - const originalIndicesColumns = Array.from({ length: newData.hyperEdgeRanges.length + 1 }, (_, index) => index); + let columnNodeAttributes; + let rowNodeAttributes; - setIndicesColumnForRowSort(originalIndicesColumns); - setCurrentPageColumns({ - startIndexColumn: 0, - endIndexColumn: Math.min(configPaohvis.columnsMaxPerPage, newData.hyperEdgeRanges.length), - }); + if (graphMetadata != undefined) { + labelEdge = data.metaData.edges.labels[0]; + edgeSchema = schema.edges.find((obj) => String(obj.key).includes(labelEdge)); + toNode = edgeSchema?.target as string; + columnNodeAttributes = Object.keys(graphMetadata.nodes.types[settings.columnNode].attributes); + rowNodeAttributes = Object.keys(graphMetadata.nodes.types[settings.rowNode].attributes); + } else { + if ('to' in schema.edges[0]) toNode = schema.edges[0].to as string; + columnNodeAttributes = schema.nodes + .find((node: any) => { + return node.name === settings.columnNode; + }) + ?.attributes?.map((attributesStructure: any) => attributesStructure.name); + + rowNodeAttributes = schema.nodes + .find((node: any) => { + return node.name === settings.rowNode; + }) + ?.attributes?.map((attributesStructure: any) => attributesStructure.name); + } - const hyperEdgeRangesKeys = [...newData.hyperEdgeRanges.keys()]; - setPermutationIndicesColumn(hyperEdgeRangesKeys); - setOriginalPermutationIndicesColumn(hyperEdgeRangesKeys); - setCurrentPageRows({ - startIndexRow: 0, - endIndexRow: Math.min(configPaohvis.rowsMaxPerPage, newData.rowLabels.length), - }); + const newData = parseQueryResult(data, settings as PaohVisProps, toNode, settings.mergeData); + // original data without slicing + setNumRowsVisible(Math.min(configPaohvis.rowsMaxPerPage, newData.rowLabels.length)); - // columnInformation - const informationColumnTemporalOriginal: { header: string; data: any[]; width: number }[] = Object.entries( - graphMetadata.nodes.types[settings.columnNode].attributes, - ).map(([k, v]) => { - const mappedData = columnNodes.map((node) => node.attributes[k]); - return { - header: k, - data: mappedData, - width: configPaohvis.maxSizeTextRows, - }; - }); + const rowNodes = newData.nodes.filter((obj) => obj[graphMetadata === undefined ? '_id' : 'label'].includes(settings.rowNode)); + const columnNodes = newData.nodes.filter((obj) => obj[graphMetadata === undefined ? '_id' : 'label'].includes(settings.columnNode)); + // to keep order of new attributes + prevDisplayAttributesColumns.current = [...columnNodeAttributes]; - const columnsIdDegree: { [_id: string]: number } = newData.hyperEdgeRanges.reduce((acc: { [_id: string]: number }, node) => { - acc[node._id] = node.degree; - return acc; - }, {}); + setDataModel({ + pageData: { + rowLabels: newData.rowLabels.slice(0, configPaohvis.rowsMaxPerPage), + hyperEdgeRanges: newData.hyperEdgeRanges.slice(0, configPaohvis.columnsMaxPerPage), + rowDegrees: newData.rowDegrees, + nodes: newData.nodes, + edges: newData.edges, + }, + data: newData, + originalData: newData, + }); - informationColumnTemporalOriginal.push({ - header: '# Connections', - data: Object.values(columnsIdDegree), - width: configPaohvis.maxSizeTextColumns, - }); + // Update lines hyperedges + const newLinePositions = newData.hyperEdgeRanges.slice(0, configPaohvis.columnsMaxPerPage).map((hyperEdgeRange) => { + return intersectionElements([0, Math.min(configPaohvis.rowsMaxPerPage, newData.rowLabels.length)], hyperEdgeRange.hyperEdges.indices); + }); + setLineHyperEdges(newLinePositions); - informationColumnTemporalOriginal.push({ - header: '_id', - data: columnNodes.map((node) => node._id), - width: configPaohvis.maxSizeTextID, //configPaohvis.maxSizeTextRows, - }); + const originalIndicesColumns = Array.from({ length: newData.hyperEdgeRanges.length + 1 }, (_, index) => index); - const informationColumnTemporal: { header: string; data: any[]; width: number }[] = informationColumnTemporalOriginal.map((d) => ({ - ...d, - data: d.data.slice(0, Math.min(configPaohvis.columnsMaxPerPage, newData.hyperEdgeRanges.length)), - })); + setIndicesColumnForRowSort(originalIndicesColumns); + setCurrentPageColumns({ + startIndexColumn: 0, + endIndexColumn: Math.min(configPaohvis.columnsMaxPerPage, newData.hyperEdgeRanges.length), + }); - setPermutationIndicesRow(originalPermutationIndicesRow); + const hyperEdgeRangesKeys = [...newData.hyperEdgeRanges.keys()]; + setPermutationIndicesColumn(hyperEdgeRangesKeys); + setOriginalPermutationIndicesColumn(hyperEdgeRangesKeys); + setCurrentPageRows({ + startIndexRow: 0, + endIndexRow: Math.min(configPaohvis.rowsMaxPerPage, newData.rowLabels.length), + }); - const columnsAttrOrder = prevDisplayAttributesColumns.current; + // columnInformation + const informationColumnTemporalOriginal: { header: string; data: any[]; width: number }[] = Object.entries( + graphMetadata.nodes.types[settings.columnNode].attributes, + ).map(([k, v]) => { + const mappedData = columnNodes.map((node) => node.attributes[k]); + return { + header: k, + data: mappedData, + width: configPaohvis.maxSizeTextRows, + }; + }); - if (columnsAttrOrder) { - // sort them according order of showing them - informationColumnTemporal.sort((a, b) => { - const indexA = columnsAttrOrder.indexOf(a.header); - const indexB = columnsAttrOrder.indexOf(b.header); - return indexA - indexB; - }); + const columnsIdDegree: { [_id: string]: number } = newData.hyperEdgeRanges.reduce((acc: { [_id: string]: number }, node) => { + acc[node._id] = node.degree; + return acc; + }, {}); - informationColumnTemporalOriginal.sort((a, b) => { - const indexA = columnsAttrOrder.indexOf(a.header); - const indexB = columnsAttrOrder.indexOf(b.header); - return indexA - indexB; - }); + informationColumnTemporalOriginal.push({ + header: '# Connections', + data: Object.values(columnsIdDegree), + width: configPaohvis.maxSizeTextColumns, + }); - // select necessary variables to show - const filteredInformationColumnTemporal = informationColumnTemporal.filter((row) => - settings.attributeColumnShow.includes(row.header), - ); + informationColumnTemporalOriginal.push({ + header: '_id', + data: columnNodes.map((node) => node._id), + width: configPaohvis.maxSizeTextID, + }); - // set data - setInformationColumn(filteredInformationColumnTemporal); - setInformationColumnOriginal(informationColumnTemporalOriginal); - setInformationColumnAllData(informationColumnTemporalOriginal); - const totalWidthColumnInformation = filteredInformationColumnTemporal.reduce((acc, row) => acc + row.width, 0); - setWidthTotalColumnInformation(totalWidthColumnInformation); - } else { - console.error(`Nodes for entity are undefined or empty.`); - } + const informationColumnTemporal: { header: string; data: any[]; width: number }[] = informationColumnTemporalOriginal.map((d) => ({ + ...d, + data: d.data.slice(0, Math.min(configPaohvis.columnsMaxPerPage, newData.hyperEdgeRanges.length)), + })); - // rowInformation - entityVertical - // build + setPermutationIndicesRow(originalPermutationIndicesRow); - const informationRowTemporalOriginal: { header: string; data: any[]; width: number }[] = Object.entries( - graphMetadata.nodes.types[settings.rowNode].attributes, - ).map(([k, v]) => { - const mappedData = rowNodes.map((node) => node.attributes[k]); + const columnsAttrOrder = prevDisplayAttributesColumns.current; - return { - header: k, - data: mappedData, - width: configPaohvis.maxSizeTextRows, - }; + if (columnsAttrOrder) { + // sort them according order of showing them + informationColumnTemporal.sort((a, b) => { + const indexA = columnsAttrOrder.indexOf(a.header); + const indexB = columnsAttrOrder.indexOf(b.header); + return indexA - indexB; }); - const idsRows = rowNodes.map((obj) => obj._id); - - informationRowTemporalOriginal.push({ - header: '# Connections', - data: idsRows.map((id) => newData.rowDegrees[id]), - width: configPaohvis.maxSizeTextRows, + informationColumnTemporalOriginal.sort((a, b) => { + const indexA = columnsAttrOrder.indexOf(a.header); + const indexB = columnsAttrOrder.indexOf(b.header); + return indexA - indexB; }); - informationRowTemporalOriginal.push({ - header: '_id', - data: idsRows, - width: configPaohvis.maxSizeTextID, //configPaohvis.maxSizeTextRows, - }); + // select necessary variables to show + const filteredInformationColumnTemporal = informationColumnTemporal.filter((row) => + settings.attributeColumnShow.includes(row.header), + ); - const informationRowTemporal: { header: string; data: any[]; width: number }[] = informationRowTemporalOriginal.map((d) => ({ - ...d, - data: d.data.slice(0, Math.min(configPaohvis.rowsMaxPerPage, newData.rowLabels.length)), - })); + // set data + setInformationColumn(filteredInformationColumnTemporal); + setInformationColumnOriginal(informationColumnTemporalOriginal); + setInformationColumnAllData(informationColumnTemporalOriginal); + const totalWidthColumnInformation = filteredInformationColumnTemporal.reduce((acc, row) => acc + row.width, 0); + setWidthTotalColumnInformation(totalWidthColumnInformation); + } else { + console.error(`Nodes for entity are undefined or empty.`); + } - const objectWithIdHeader = informationRowTemporalOriginal.find((obj) => obj.header === '_id'); - let originalIndices: number[] = []; + // rowInformation - entityVertical + // build - if (objectWithIdHeader) { - originalIndices = [...objectWithIdHeader.data.keys()]; - } else { - console.error("Row Object with header 'id' not found"); - } - setOriginalPermutationIndicesRow(originalIndices); - setIndicesRowsForColumnSort(originalIndices); + const informationRowTemporalOriginal: { header: string; data: any[]; width: number }[] = Object.entries( + graphMetadata.nodes.types[settings.rowNode].attributes, + ).map(([k, v]) => { + const mappedData = rowNodes.map((node) => node.attributes[k]); - // select necessary variables to show - const filteredInformationRowTemporal = informationRowTemporal.filter((row) => settings.attributeRowShow.includes(row.header)); + return { + header: k, + data: mappedData, + width: configPaohvis.maxSizeTextRows, + }; + }); - // set data - setInformationRow(filteredInformationRowTemporal); - setInformationRowOriginal(informationRowTemporalOriginal); - setInformationRowAllData(informationRowTemporalOriginal); - const totalWidthRowInformation = filteredInformationRowTemporal.reduce((acc, row) => acc + row.width, 0); + const idsRows = rowNodes.map((obj) => obj._id); + + informationRowTemporalOriginal.push({ + header: '# Connections', + data: idsRows.map((id) => newData.rowDegrees[id]), + width: configPaohvis.maxSizeTextRows, + }); + + informationRowTemporalOriginal.push({ + header: '_id', + data: idsRows, + width: configPaohvis.maxSizeTextID, //configPaohvis.maxSizeTextRows, + }); + + const informationRowTemporal: { header: string; data: any[]; width: number }[] = informationRowTemporalOriginal.map((d) => ({ + ...d, + data: d.data.slice(0, Math.min(configPaohvis.rowsMaxPerPage, newData.rowLabels.length)), + })); + + const objectWithIdHeader = informationRowTemporalOriginal.find((obj) => obj.header === '_id'); + let originalIndices: number[] = []; - setWidthTotalRowInformation(totalWidthRowInformation); + if (objectWithIdHeader) { + originalIndices = [...objectWithIdHeader.data.keys()]; + } else { + console.error("Row Object with header 'id' not found"); } + setOriginalPermutationIndicesRow(originalIndices); + setIndicesRowsForColumnSort(originalIndices); + + // select necessary variables to show + const filteredInformationRowTemporal = informationRowTemporal.filter((row) => settings.attributeRowShow.includes(row.header)); + + // set data + setInformationRow(filteredInformationRowTemporal); + setInformationRowOriginal(informationRowTemporalOriginal); + setInformationRowAllData(informationRowTemporalOriginal); + const totalWidthRowInformation = filteredInformationRowTemporal.reduce((acc, row) => acc + row.width, 0); + + setWidthTotalRowInformation(totalWidthRowInformation); }, [ settings.rowNode, settings.columnNode, @@ -823,6 +839,7 @@ export const PaohVis = ({ data, graphMetadata, schema, settings, updateSettings return ( <svg + className="m-1" ref={svgRef} style={{ // width: computedSizesSvg.tableWidthWithExtraColumnLabelWidth, @@ -1005,14 +1022,33 @@ const PaohSettings = ({ settings, graphMetadata, updateSettings }: Visualization </div> )} - <Input type="number" label="Row height" value={settings.rowHeight} onChange={(val) => updateSettings({ rowHeight: val })} /> + <Input + type="slider" + label="Row height" + value={settings.rowHeight} + onChange={(val) => updateSettings({ rowHeight: val })} + min={8} + max={30} + step={1} + /> - <Input type="number" label="# Rows" value={settings.numRowsDisplay} onChange={(val) => updateSettings({ numRowsDisplay: val })} /> <Input - type="number" + type="slider" + label="# Rows" + value={settings.numRowsDisplay} + onChange={(val) => updateSettings({ numRowsDisplay: val })} + min={1} + max={40} + step={1} + /> + <Input + type="slider" label="# Columns" value={settings.numColumnsDisplay} onChange={(val) => updateSettings({ numColumnsDisplay: val })} + min={1} + max={60} + step={1} /> <Input type="number" diff --git a/libs/shared/lib/vis/visualizations/paohvis/utils/dataProcessing.tsx b/libs/shared/lib/vis/visualizations/paohvis/utils/dataProcessing.tsx index f8cd33af7a5401004f28d7a989913896ebdb7eda..296210f1288b94fbfe7038db4aa337d73c4b6ca0 100644 --- a/libs/shared/lib/vis/visualizations/paohvis/utils/dataProcessing.tsx +++ b/libs/shared/lib/vis/visualizations/paohvis/utils/dataProcessing.tsx @@ -52,7 +52,6 @@ function parseHyperEdgeRanges( }; }); - //console.log('resultHyperEdgeRanges', resultHyperEdgeRanges); const processedPairs = new Set<string>(); // To avoid processing pairs const toOrFrom = relationTo == columnNode ? 'to' : 'from'; @@ -116,9 +115,18 @@ export function parseQueryResult( const replaceNodeIds: Record<string, string> = {}; const reducedReplaceNodeIds: Record<string, string[]> = {}; const hashAttributesToIdMap: Record<string, string[]> = {}; - let nodesRow: AugmentedNode[] = queryResult.nodes - .filter((node) => node.label == configuration.rowNode) + .filter((node) => { + // some dataset do not have label field + let labelNode = ''; + if (node.label !== undefined) { + labelNode = node.label; + } else { + const idParts = node._id.split('/'); + labelNode = idParts[0]; + } + return labelNode === configuration.rowNode; + }) .map((node) => { const attributes = skipReduceRow ? node.attributes @@ -138,7 +146,16 @@ export function parseQueryResult( }); let nodesColumn: AugmentedNode[] = queryResult.nodes - .filter((node) => node.label == configuration.columnNode) + .filter((node) => { + let labelNode = ''; + if (node.label !== undefined) { + labelNode = node.label; + } else { + const idParts = node._id.split('/'); + labelNode = idParts[0]; + } + return labelNode === configuration.columnNode; + }) .map((node) => { const attributes = skipReduceColumn ? node.attributes