From 4e1703746213c802ae0818de89df56ae371f8e64 Mon Sep 17 00:00:00 2001
From: Marcos Pieras <pieras.marcos@gmail.com>
Date: Thu, 11 Jul 2024 17:33:20 +0000
Subject: [PATCH] fix: stories and updates table and barplot for non data

---
 .../components/DesignGuides/styleGuide.mdx    |   9 +-
 .../lib/components/buttons/overview.mdx       |  90 +++--
 .../charts/barplot/barplot.stories.tsx        |   9 +-
 .../lib/components/charts/barplot/index.tsx   | 334 +++++++-----------
 .../components/charts/scatterplot/index.tsx   |  35 --
 .../scatterplot/scatterplot.stories.tsx       |  23 --
 libs/shared/lib/components/icon/overview.mdx  |  16 +-
 .../shared/lib/components/inputs/overview.mdx |   4 +-
 .../lib/components/pagination/overview.mdx    |   2 +-
 .../lib/components/tooltip/Overview.mdx       |  36 ++
 libs/shared/lib/components/tooltip/index.tsx  |   2 +
 .../components/tooltip/tooltip.stories.tsx    |   2 +-
 .../query-result/typesMockQueryResults.json   | 174 ++++++++-
 .../nodelinkvis/components/query2NL.tsx       |  20 +-
 .../tablevis/components/Table.tsx             |  71 ++--
 .../tablevis/components/table.module.scss     |   6 +
 .../tablevis/tablevis.stories.tsx             |  19 +-
 .../vis/visualizations/tablevis/tablevis.tsx  |  92 +++--
 18 files changed, 557 insertions(+), 387 deletions(-)
 delete mode 100644 libs/shared/lib/components/charts/scatterplot/index.tsx
 delete mode 100644 libs/shared/lib/components/charts/scatterplot/scatterplot.stories.tsx
 create mode 100644 libs/shared/lib/components/tooltip/Overview.mdx

diff --git a/libs/shared/lib/components/DesignGuides/styleGuide.mdx b/libs/shared/lib/components/DesignGuides/styleGuide.mdx
index a7e82a621..f461cac58 100644
--- a/libs/shared/lib/components/DesignGuides/styleGuide.mdx
+++ b/libs/shared/lib/components/DesignGuides/styleGuide.mdx
@@ -35,6 +35,7 @@ import {
   KeyboardArrowUp as KeyboardArrowUpIcon,
   CheckCircle as CheckCircleIcon,
 } from '@mui/icons-material';
+import { ArrowBack } from '@mui/icons-material';
 
 <Meta title="Design guide" />
 
@@ -641,12 +642,12 @@ this is a hsl color, if you want to use this color in a css file you can use the
 GraphPolaris uses [Material UI](https://mui.com/material-ui/material-icons/) through an Icon component, where the Material UI icon is specified along its size:
 
 <div className="w-32 m-5 mx-auto">
-  <Icon name="ArrowBack" size={32} />
+  <Icon component={<ArrowBack />} size={32} />
 </div>
 
 ```jsx
-import { Icon } from '@graphpolaris/shared/lib/components/icon';
-<Icon name="ArrowBack" size={32} />;
+import Icon from '@graphpolaris/shared/lib/components/icon';
+<Icon component={<ArrowBack />} size={32} />;
 ```
 
 There are 5 types of Icons in Material UI:
@@ -751,9 +752,7 @@ We ditinguish two usage scenarios:
     iconName="ArrowForward"
     iconPosition="leading"
     onClick={() => {
-      // Add your code to handle the button click event here
       console.log('Button clicked!');
-      // You can perform any desired actions or state updates here
     }}
   />
 </div>
diff --git a/libs/shared/lib/components/buttons/overview.mdx b/libs/shared/lib/components/buttons/overview.mdx
index 810e45683..9fba35c6f 100644
--- a/libs/shared/lib/components/buttons/overview.mdx
+++ b/libs/shared/lib/components/buttons/overview.mdx
@@ -11,66 +11,60 @@ A button is used a lot in GP.
 
 [//]: # '<Canvas of={ButtonStories.Primary} />'
 
-<Canvas>
-  <Story id="components-button--primary" name="Primary Button">
-    {ButtonStories.Primary.args}
-  </Story>
-  <Story id="components-button--secondary" name="Secondary Button">
-    {ButtonStories.Secondary.args}
-  </Story>
-  <Story id="components-button--danger" name="Danger Button">
-    {ButtonStories.Danger.args}
-  </Story>
-</Canvas>
-
-<Canvas>
-  <Story id="components-button--solid" name="Solid Button">
-    {ButtonStories.Solid.args}
-  </Story>
-  <Story id="components-button--outline" name="Outline Button">
-    {ButtonStories.Outline.args}
-  </Story>
-  <Story id="components-button--ghost" name="Ghost Button">
-    {ButtonStories.Ghost.args}
-  </Story>
-</Canvas>
-
-<Canvas>
-  <Story id="components-button--icon-button" name="Icon Button">
-    {ButtonStories.IconButton.args}
-  </Story>
-</Canvas>
-
 <div className="grid grid-cols-2 gap-4">
 
   <div className="flex flex-col gap-3">
-    <Button type="primary" variant="solid" label="Click me" onClick={() => alert('Button clicked')} />
-    <Button type="primary" variant="outline" label="Click me" onClick={() => alert('Button clicked')} />
-    <Button type="primary" variant="ghost" label="Click me" onClick={() => alert('Button clicked')} />
+    <Button variantType="primary" variant="solid" label="Click me" onClick={() => alert('Button clicked')} />
+    <Button variantType="primary" variant="outline" label="Click me" onClick={() => alert('Button clicked')} />
+    <Button variantType="primary" variant="ghost" label="Click me" onClick={() => alert('Button clicked')} />
   </div>
   <div className="flex flex-col gap-3">
-    <Button type="secondary" variant="solid" label="Click me" onClick={() => alert('Button clicked')} />
-    <Button type="secondary" variant="outline" label="Click me" onClick={() => alert('Button clicked')} />
-    <Button type="secondary" variant="ghost" label="Click me" onClick={() => alert('Button clicked')} />
+    <Button variantType="secondary" variant="solid" label="Click me" onClick={() => alert('Button clicked')} />
+    <Button variantType="secondary" variant="outline" label="Click me" onClick={() => alert('Button clicked')} />
+    <Button variantType="secondary" variant="ghost" label="Click me" onClick={() => alert('Button clicked')} />
   </div>
   <div className="flex flex-col gap-3">
-    <Button type="danger" variant="solid" label="Click me" onClick={() => alert('Button clicked')} />
-    <Button type="danger" variant="outline" label="Click me" onClick={() => alert('Button clicked')} />
-    <Button type="danger" variant="ghost" label="Click me" onClick={() => alert('Button clicked')} />
+    <Button variantType="danger" variant="solid" label="Click me" onClick={() => alert('Button clicked')} />
+    <Button variantType="danger" variant="outline" label="Click me" onClick={() => alert('Button clicked')} />
+    <Button variantType="danger" variant="ghost" label="Click me" onClick={() => alert('Button clicked')} />
   </div>
   <div className="flex flex-col gap-3">
-    <Button type="primary" variant="solid" label="Click me" onClick={() => alert('Button clicked')} disabled />
-    <Button type="secondary" variant="outline" label="Click me" onClick={() => alert('Button clicked')} disabled />
-    <Button type="danger" variant="ghost" label="Click me" onClick={() => alert('Button clicked')} disabled />
+    <Button variantType="primary" variant="solid" label="Click me" onClick={() => alert('Button clicked')} disabled />
+    <Button variantType="secondary" variant="outline" label="Click me" onClick={() => alert('Button clicked')} disabled />
+    <Button variantType="danger" variant="ghost" label="Click me" onClick={() => alert('Button clicked')} disabled />
   </div>
   <div className="flex flex-row gap-3 col-span-2">
-    <Button type="primary" size="lg" label="Click me" iconName="NavigateBefore" onClick={() => alert('Button clicked')} />
-    <Button type="primary" size="md" label="Click me" iconName="ArrowForward" iconPlacement="trailing" onClick={() => alert('Button clicked')} />
-    <Button type="danger" size="sm" label="Click me" iconName="DeleteOutline" onClick={() => alert('Button clicked')} />
-    <Button type="primary" size="xs" label="Click me" rounded onClick={() => alert('Button clicked')} />
+    <Button variantType="primary" size="lg" label="Click me" iconName="NavigateBefore" onClick={() => alert('Button clicked')} />
+    <Button variantType="primary" size="md" label="Click me" iconName="ArrowForward" iconPlacement="trailing" onClick={() => alert('Button clicked')} />
+    <Button variantType="danger" size="sm" label="Click me" iconName="DeleteOutline" onClick={() => alert('Button clicked')} />
+    <Button variantType="primary" size="xs" label="Click me" rounded onClick={() => alert('Button clicked')} />
   </div>
   <div className="col-span-2">
-    <Button block type="primary" size="md" label="Click me" onClick={() => alert('Button clicked')} />
+    <Button block variantType="primary" size="md" label="Click me" onClick={() => alert('Button clicked')} />
   </div>
 </div>
-variantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantTypevariantType
+
+## Usage
+
+<div className="my-10 col-span-2">
+  <Button
+    block
+    variantType="primary"
+    size="md"
+    label="Click me"
+    iconName="ArrowForward"
+    iconPlacement="trailing"
+    onClick={() => alert('Button clicked')}
+  />
+</div>
+
+```jsx
+<Button
+  variantType="primary"
+  size="md"
+  label="Click me"
+  iconName="ArrowForward"
+  iconPlacement="trailing"
+  onClick={() => alert('Button clicked')}
+/>
+```
diff --git a/libs/shared/lib/components/charts/barplot/barplot.stories.tsx b/libs/shared/lib/components/charts/barplot/barplot.stories.tsx
index c7c7da834..a63d88829 100644
--- a/libs/shared/lib/components/charts/barplot/barplot.stories.tsx
+++ b/libs/shared/lib/components/charts/barplot/barplot.stories.tsx
@@ -15,12 +15,15 @@ export const CategoricalData = {
   args: {
     data: [
       { category: 'Category A', count: 250 },
+      { category: 'NoData', count: 100 },
       { category: 'Category B', count: 20 },
       { category: 'Category C', count: 15 },
     ],
     numBins: 5,
     typeBarPlot: 'categorical',
-    axis: true,
+    marginPercentage: { top: 0.1, right: 0, left: 0, bottom: 0 },
+    axis: false,
+    name: 'mock1',
   },
 };
 
@@ -34,7 +37,9 @@ export const NumericalData = {
       { category: 'Data Point 5', count: 8 },
     ],
     numBins: 5,
+    marginPercentage: { top: 0.1, right: 0, left: 0, bottom: 0 },
     typeBarPlot: 'numerical',
-    axis: true,
+    axis: false,
+    name: 'mock2',
   },
 };
diff --git a/libs/shared/lib/components/charts/barplot/index.tsx b/libs/shared/lib/components/charts/barplot/index.tsx
index 97ecf9f26..ba038b94e 100644
--- a/libs/shared/lib/components/charts/barplot/index.tsx
+++ b/libs/shared/lib/components/charts/barplot/index.tsx
@@ -1,21 +1,6 @@
-import React, { LegacyRef, useEffect, useRef, useState } from 'react';
-import { BarPlotTooltip } from '@graphpolaris/shared/lib/components/tooltip';
-import {
-  Axis,
-  Bin,
-  NumberValue,
-  axisBottom,
-  axisLeft,
-  bin,
-  extent,
-  format,
-  max,
-  range,
-  scaleBand,
-  scaleLinear,
-  select,
-  Selection,
-} from 'd3';
+import React, { useEffect, useMemo, useRef, useState } from 'react';
+import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@graphpolaris/shared/lib/components/tooltip';
+import { axisLeft, bin, extent, format, max, range, scaleBand, scaleLinear, select } from 'd3';
 
 export type BarPlotProps = {
   data: { category: string; count: number }[];
@@ -31,246 +16,173 @@ export type BarPlotProps = {
   maxBarsCount?: number;
   strokeWidth?: number;
   axis?: boolean;
+  name: string;
 };
 
-export const BarPlot = ({ typeBarPlot, numBins, data, marginPercentage, className, maxBarsCount, strokeWidth, axis }: BarPlotProps) => {
+export const BarPlot = ({ typeBarPlot, numBins, data, marginPercentage, className, maxBarsCount, axis, name }: BarPlotProps) => {
   const svgRef = useRef<SVGSVGElement | null>(null);
+  const groupMarginRef = useRef<SVGGElement | null>(null);
+
   const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
-  const [tooltipData, setTooltipData] = useState<{ x: number; y: number; content: { category: string; count: number } } | null>(null);
 
   useEffect(() => {
-    if (!svgRef.current) return;
+    function handleResize() {
+      if (svgRef.current) {
+        setDimensions({ width: svgRef.current.getBoundingClientRect().width, height: svgRef.current.getBoundingClientRect().height });
+      }
+    }
 
-    const bounds = svgRef.current.getBoundingClientRect();
-    const widthSVG: number = bounds.width;
-    const heightSVG: number = bounds.height;
+    window.addEventListener('resize', handleResize);
+    if (svgRef.current) new ResizeObserver(handleResize).observe(svgRef.current);
 
-    setDimensions({ width: widthSVG, height: heightSVG });
-    const svgPlot = select(svgRef.current);
+    return () => {
+      window.removeEventListener('resize', handleResize);
+    };
+  }, []);
 
-    svgPlot.selectAll('*').remove();
+  const dataRects = useMemo(() => {
+    if (!svgRef.current || dimensions.width === 0 || dimensions.height === 0) return [];
+    const { width, height } = dimensions;
+    const widthSVG: number = width;
+    const heightSVG: number = height;
 
-    let groupMargin: Selection<SVGGElement, unknown, null, undefined>;
-    let widthSVGwithinMargin: number = 0.0;
-    let heightSVGwithinMargin: number = 0.0;
+    const svgPlot = select(svgRef.current);
 
-    // BarPlot for categorical data
-    if (typeBarPlot == 'categorical') {
-      if (!marginPercentage)
-        marginPercentage = {
-          top: 0.19,
-          right: 0.02,
-          bottom: 0.19,
-          left: 0.19,
-        };
-      let margin = {
-        top: marginPercentage.top * heightSVG,
-        right: marginPercentage.right * widthSVG,
-        bottom: marginPercentage.bottom * heightSVG,
-        left: marginPercentage.left * widthSVG,
+    if (!marginPercentage)
+      marginPercentage = {
+        top: 0.19,
+        right: 0.02,
+        bottom: 0.19,
+        left: 0.19,
       };
+    let margin = {
+      top: marginPercentage.top * heightSVG,
+      right: marginPercentage.right * widthSVG,
+      bottom: marginPercentage.bottom * heightSVG,
+      left: marginPercentage.left * widthSVG,
+    };
+    select(groupMarginRef.current).attr('transform', `translate(${margin.left},${margin.top})`);
+    let widthSVGwithinMargin = widthSVG - margin.left - margin.right;
+    let heightSVGwithinMargin = heightSVG - margin.top - margin.bottom;
+
+    if (typeBarPlot === 'categorical') {
+      const defs = svgPlot.append('defs');
+
+      defs
+        .append('pattern')
+        .attr('id', 'diagonalHatch')
+        .attr('width', 6)
+        .attr('height', 6)
+        .attr('patternTransform', 'rotate(45 0 0)')
+        .attr('patternUnits', 'userSpaceOnUse')
+        .append('rect')
+        .attr('width', 2)
+        .attr('height', 6)
+        .attr('transform', 'translate(0,0)')
+        .attr('fill', '#cccccc');
 
-      groupMargin = svgPlot.append('g').attr('transform', `translate(${margin.left},${margin.top})`);
-      widthSVGwithinMargin = widthSVG - margin.left - margin.right;
-      heightSVGwithinMargin = heightSVG - margin.top - margin.bottom;
-
-      // Data processing
       const dataFiltered = data.filter((item) => item.category !== undefined);
       const dataSorted = dataFiltered.sort((a, b) => b.count - a.count);
       const dataTopCounts = dataSorted.filter((item, i) => !maxBarsCount || i < maxBarsCount);
       const maxCount = max(dataTopCounts, (d) => d.count) ?? 1;
       const xScale = scaleBand()
         .range([0, widthSVGwithinMargin])
-        .domain(
-          dataTopCounts.map(function (d) {
-            return d.category;
-          }),
-        )
-        .padding(0.2);
+        .domain(dataTopCounts.map((d) => d.category))
+        .padding(0.1);
 
-      // send this
       const yScale = scaleLinear().domain([0, maxCount]).range([heightSVGwithinMargin, 0]);
 
-      // here out to axis component
-      const yAxis1 = axisLeft(yScale).tickValues([0]).tickFormat(format('d')); // to show 0 without decimanls
-      let yAxis2: Axis<NumberValue>;
-
+      let yAxis2;
       if (maxCount < 10) {
         yAxis2 = axisLeft(yScale).tickValues([maxCount]).tickFormat(format('d'));
       } else {
         yAxis2 = axisLeft(yScale).tickValues([maxCount]).tickFormat(format('.2s'));
       }
 
-      groupMargin
-        .selectAll<SVGRectElement, Bin<string, number>>('barplotCats')
-        .data(dataTopCounts)
-        .enter()
-        .append('rect')
-        .attr('x', (d) => xScale(d.category) || 0)
-        .attr('y', (d) => yScale(d.count))
-        .attr('width', xScale.bandwidth())
-        .attr('height', (d) => heightSVGwithinMargin - yScale(d.count))
-        .attr('class', 'hover:stroke-black hover:stroke-2 hover:stroke-secondary-400 fill-secondary-400')
-        .on('mouseover', (event, d) => {
-          setTooltipData({ x: event.layerX + 10, y: event.layerY - 28, content: d });
-        })
-        .on('mousemove', (event, d) => {
-          if (tooltipData) {
-            setTimeout(() => {
-              setTooltipData((prevTooltipData) => {
-                if (prevTooltipData) {
-                  return {
-                    ...prevTooltipData,
-                    x: event.pageX + 10,
-                    y: event.pageY - 28,
-                  };
-                }
-                return prevTooltipData;
-              });
-            }, 16);
-          }
-        })
-        .on('mouseleave', (d) => {
-          setTooltipData(null);
-        });
-
-      if (axis) {
-        groupMargin.append('g').call(yAxis1);
-        groupMargin.append('g').call(yAxis2);
-      }
-
-      // Barplot for numerical data
+      const scaledData = dataTopCounts.map((d, i) => ({
+        x: xScale(d.category) || 0,
+        y: yScale(d.count),
+        width: xScale.bandwidth(),
+        height: heightSVGwithinMargin - yScale(d.count),
+        category: d.category,
+        count: d.count,
+        key: `${name}-${i}`,
+      }));
+
+      return scaledData;
     } else {
-      if (!marginPercentage)
-        marginPercentage = {
-          top: 0.19,
-          right: 0.02,
-          bottom: 0.19,
-          left: 0.19,
-        };
-      let margin = {
-        top: marginPercentage.top * heightSVG,
-        right: marginPercentage.right * widthSVG,
-        bottom: marginPercentage.bottom * heightSVG,
-        left: marginPercentage.left * widthSVG,
-      };
-
-      groupMargin = svgPlot.append('g').attr('transform', `translate(${margin.left},${margin.top})`);
-      widthSVGwithinMargin = widthSVG - margin.left - margin.right;
-      heightSVGwithinMargin = heightSVG - margin.top - margin.bottom;
       const dataCount = data.map((obj) => obj.count);
 
       const extentData = extent(dataCount);
       const [min, max] = extentData as [number, number];
 
-      const xScale = scaleLinear().range([0, widthSVGwithinMargin]).domain([min, max]); //.nice();
-
-      // histogram -> deprecated
-      // On bin(), .thresholds(x.ticks(numBins)). Creates artifacts: not full rects on the plot
-      // CHECK THIS: https://dev.to/kevinlien/d3-histograms-and-fixing-the-bin-problem-4ac5
+      const xScale = scaleLinear().range([0, widthSVGwithinMargin]).domain([min, max]);
 
       const rangeTH: number[] = range(min, max, (max - min) / numBins);
-
-      if (rangeTH.length != numBins) {
+      if (rangeTH.length !== numBins) {
         rangeTH.pop();
       }
 
       const histogram = bin()
-        .value(function (d) {
-          return d;
-        })
+        .value((d) => d)
         .domain([min, max])
         .thresholds(rangeTH);
 
       const bins = histogram(dataCount);
-      const extentBins: [number, number] = extent(bins, (d) => d.length) as [number, number];
-
-      const yScale = scaleLinear()
-        .range([heightSVGwithinMargin, 0])
-        .domain([0, extentBins[1]] as [number, number]);
-
-      groupMargin
-        .selectAll<SVGRectElement, Bin<number, number>>('barplotbins')
-        .data(bins)
-        .enter()
-        .append('rect')
-        .attr('x', 0)
-        .attr('stroke', 'none')
-        .attr('fill', 'hsl(var(--clr-sec--400))')
-        .attr('transform', (d) => 'translate(' + xScale(d.x0 || 0) + ',' + yScale(d.length) + ')')
-        .attr('width', (d) => xScale(d.x1 || 0) - xScale(d.x0 || 0))
-        .attr('height', (d) => heightSVGwithinMargin - yScale(d.length));
-
-      const xAxis = axisBottom(xScale)
-        //.tickValues([Math.round((min + max) / 2.0), max])
-        .tickValues([max])
-        .tickFormat(format('.2s'));
-
-      let xAxis2: Axis<NumberValue>;
-
-      if (min < 10) {
-        xAxis2 = axisBottom(xScale).tickValues([min]).tickFormat(format('d'));
-      } else {
-        xAxis2 = axisBottom(xScale).tickValues([min]).tickFormat(format('.2s'));
-      }
-
-      groupMargin
-        .append('g')
-        .attr('transform', 'translate(0,' + heightSVGwithinMargin + ')')
-        .call(xAxis2);
-
-      groupMargin
-        .append('g')
-        .attr('transform', 'translate(0,' + heightSVGwithinMargin + ')')
-        .call(xAxis);
-
-      const yAxis1 = axisLeft(yScale).tickValues([0]).tickFormat(format('d')); // to show 0 without decimanls
-      //const yAxis2 = axisLeft(yScale).tickValues([extentBins[1]]).tickFormat(format('.2s'));
-
-      let yAxis2: Axis<NumberValue>;
-
-      if (extentBins[1] < 10) {
-        yAxis2 = axisLeft(yScale).tickValues([extentBins[1]]).tickFormat(format('d'));
-      } else {
-        yAxis2 = axisLeft(yScale).tickValues([extentBins[1]]).tickFormat(format('.2s'));
-      }
+      const extentBins = extent(bins, (d) => d.length) as [number, number];
+
+      const yScale = scaleLinear().range([heightSVGwithinMargin, 0]).domain([0, extentBins[1]]);
+
+      const scaledData = bins.map((d, i) => {
+        const x0 = d.x0 || 0;
+        const x1 = d.x1 || 0;
+        parseFloat(x1.toFixed(2));
+        return {
+          x: xScale(x0),
+          y: yScale(d.length),
+          width: xScale(x1) - xScale(x0),
+          height: heightSVGwithinMargin - yScale(d.length),
+          category: `[${parseFloat(x0.toFixed(2))},${parseFloat(x1.toFixed(2))}]`,
+          count: d.length,
+          key: `${name}-${i}`,
+        };
+      });
 
-      if (axis) {
-        // two axis for each number, it solves the 0.0 problem with ".2s" notatation
-        groupMargin.append('g').call(yAxis1);
-        groupMargin.append('g').call(yAxis2);
-      }
+      return scaledData;
     }
-
-    svgPlot.selectAll('.domain').style('stroke', 'hsl(var(--clr-sec--400))');
-    svgPlot.selectAll('.tick line').style('stroke', 'hsl(var(--clr-sec--400))');
-    svgPlot.selectAll('.tick text').attr('class', 'font-mono').style('stroke', 'none').style('fill', 'hsl(var(--clr-sec--500))');
-
-    groupMargin
-      .append('rect')
-      .attr('x', 0.0)
-      .attr('y', 0.0)
-      .attr('width', widthSVGwithinMargin)
-      .attr('height', heightSVGwithinMargin)
-      .attr('rx', 0)
-      .attr('ry', 0)
-      .attr('stroke-width', strokeWidth || 0)
-      .attr('fill', 'none')
-      .attr('stroke', 'hsl(var(--clr-sec--400))');
-  }, [data, svgRef]);
+  }, [data, dimensions, marginPercentage, numBins, typeBarPlot, axis, name]);
 
   return (
-    <div className={!!className ? className : ''}>
-      <svg ref={svgRef} className="" width="100%" height="100%"></svg>
-      {tooltipData && (
-        <BarPlotTooltip x={tooltipData.x} y={tooltipData.y}>
-          <div>
-            <span>{tooltipData.content.category.toString()}</span>: <span>{tooltipData.content.count}</span>
-          </div>
-        </BarPlotTooltip>
-      )}
-    </div>
+    <TooltipProvider delayDuration={300}>
+      <div className={className || ''}>
+        <svg ref={svgRef} width="100%" height="100%">
+          <g ref={groupMarginRef}>
+            {dataRects?.map((d) => (
+              <Tooltip key={d.key}>
+                <TooltipTrigger asChild>
+                  <rect
+                    x={d.x}
+                    y={d.y}
+                    width={d.width}
+                    height={d.height}
+                    stroke={'hsl(var(--clr-sec--400))'}
+                    strokeWidth={d.category === 'NoData' ? '0.2' : '0'}
+                    fill={d.category === 'NoData' ? 'url(#diagonalHatch)' : 'hsl(var(--clr-sec--400))'}
+                    className={'hover:fill-accent'}
+                  />
+                </TooltipTrigger>
+                <TooltipContent>
+                  <div>
+                    <strong>Category:</strong> {d.category}
+                    <br />
+                    <strong>Count:</strong> {d.count}
+                  </div>
+                </TooltipContent>
+              </Tooltip>
+            ))}
+          </g>
+        </svg>
+      </div>
+    </TooltipProvider>
   );
 };
-
-export default BarPlot;
diff --git a/libs/shared/lib/components/charts/scatterplot/index.tsx b/libs/shared/lib/components/charts/scatterplot/index.tsx
deleted file mode 100644
index d65989f00..000000000
--- a/libs/shared/lib/components/charts/scatterplot/index.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import React, { useEffect, useRef } from 'react';
-import * as d3 from 'd3';
-
-export interface ScatterplotProps {
-  data: { x: number; y: number }[];
-}
-
-const Scatterplot: React.FC<ScatterplotProps> = ({ data }) => {
-  const svgRef = useRef<SVGSVGElement | null>(null);
-
-  useEffect(() => {
-    if (svgRef.current) {
-      const svg = d3.select(svgRef.current);
-
-      svg
-        .selectAll('circle')
-        .data(data)
-        .enter()
-        .append('circle')
-        .attr('cx', (d) => d.x * 30)
-        .attr('cy', (d) => 100 - d.y * 10)
-        .attr('r', 5)
-        .attr('fill', 'red');
-    }
-  }, [data]);
-
-  return (
-    <div>
-      <h2>Scatterplot</h2>
-      <svg ref={svgRef} width={300} height={120}></svg>
-    </div>
-  );
-};
-
-export default Scatterplot;
diff --git a/libs/shared/lib/components/charts/scatterplot/scatterplot.stories.tsx b/libs/shared/lib/components/charts/scatterplot/scatterplot.stories.tsx
deleted file mode 100644
index 271cda53d..000000000
--- a/libs/shared/lib/components/charts/scatterplot/scatterplot.stories.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from 'react';
-import { Meta } from '@storybook/react';
-import Scatterplot, { ScatterplotProps } from '.';
-
-const Component: Meta<typeof Scatterplot> = {
-  title: 'Visual charts/Charts/Scatterplot',
-  //tags: ['autodocs'],
-  component: Scatterplot,
-};
-
-export default Component;
-
-export const ScatterplotInput = {
-  args: {
-    data: [
-      { x: 1, y: 3 },
-      { x: 2, y: 7 },
-      { x: 3, y: 2 },
-      { x: 4, y: 5 },
-      { x: 5, y: 8 },
-    ],
-  },
-};
diff --git a/libs/shared/lib/components/icon/overview.mdx b/libs/shared/lib/components/icon/overview.mdx
index d03354ff2..5dd08be20 100644
--- a/libs/shared/lib/components/icon/overview.mdx
+++ b/libs/shared/lib/components/icon/overview.mdx
@@ -1,6 +1,8 @@
 import { Canvas, Meta, Story } from '@storybook/blocks';
 import * as IconStories from './icon.stories';
-import { Icon } from '.';
+import { Icon } from '../icon';
+
+import { ArrowBack } from '@mui/icons-material';
 
 <Meta title="Components/Icon" component={Icon} />
 
@@ -11,8 +13,10 @@ The `Icon` component is used to display icons in the application in one of the f
 
 ## Usage
 
-<Canvas>
-  <Story id="components-icon--default" name="Default Icon">
-    {IconStories.Default.args}
-  </Story>
-</Canvas>
+<div className="w-52 m-5">
+  <Icon component={<ArrowBack />} size={24} />
+</div>
+
+```jsx
+<Icon component={<ArrowBack />} size={24} />
+```
diff --git a/libs/shared/lib/components/inputs/overview.mdx b/libs/shared/lib/components/inputs/overview.mdx
index 8f26649d2..8f4c2df27 100644
--- a/libs/shared/lib/components/inputs/overview.mdx
+++ b/libs/shared/lib/components/inputs/overview.mdx
@@ -7,9 +7,9 @@ export const components = {
 
 <Meta title="Components/inputs" component={Input} />
 
-# Pagination
+# Inputs
 
-A pagination component for navigating through pages.
+Different types of inputs:
 
 # Form Input Demo
 
diff --git a/libs/shared/lib/components/pagination/overview.mdx b/libs/shared/lib/components/pagination/overview.mdx
index 9401f95be..9804a7cb0 100644
--- a/libs/shared/lib/components/pagination/overview.mdx
+++ b/libs/shared/lib/components/pagination/overview.mdx
@@ -1,5 +1,5 @@
 import { Canvas, Meta, Story } from '@storybook/blocks';
-import Pagination from '.';
+import { Pagination } from '.';
 import * as PaginationStories from './pagination.stories';
 
 <Meta title="Components/pagination" component={Pagination} />
diff --git a/libs/shared/lib/components/tooltip/Overview.mdx b/libs/shared/lib/components/tooltip/Overview.mdx
new file mode 100644
index 000000000..369f13159
--- /dev/null
+++ b/libs/shared/lib/components/tooltip/Overview.mdx
@@ -0,0 +1,36 @@
+import { Canvas, Meta, Story } from '@storybook/blocks';
+
+import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './index';
+
+<Meta title="Components/Tooltip" component={Tooltip} />
+
+## Usage
+
+<div>
+  <TooltipProvider delayDuration={0}>
+    <div className="flex justify-center items-center py-16">
+      <Tooltip>
+        <TooltipTrigger>
+          <div className="mx-auto">Hover over me</div>
+        </TooltipTrigger>
+        <TooltipContent side={'bottom'}>
+          <p>This is a tooltip</p>
+        </TooltipContent>
+      </Tooltip>
+    </div>
+  </TooltipProvider>
+</div>
+
+```jsx
+    <div className="flex justify-center items-center py-16">
+      <Tooltip>
+        <TooltipTrigger>
+          <div className="mx-auto">Hover over me</div>
+        </TooltipTrigger>
+        <TooltipContent side={"bottom"}>
+          <p>This is a tooltip</p>
+        </TooltipContent>
+      </Tooltip>
+    </div>
+  </TooltipProvider>
+```
diff --git a/libs/shared/lib/components/tooltip/index.tsx b/libs/shared/lib/components/tooltip/index.tsx
index 4024bdf57..126981134 100644
--- a/libs/shared/lib/components/tooltip/index.tsx
+++ b/libs/shared/lib/components/tooltip/index.tsx
@@ -2,6 +2,7 @@
 
 export * from './Tooltip';
 
+/*
 export interface BarTooltipProps {
   x: number;
   y: number;
@@ -18,3 +19,4 @@ export const BarPlotTooltip = ({ x, y, children }: BarTooltipProps) => {
     </div>
   );
 };
+*/
diff --git a/libs/shared/lib/components/tooltip/tooltip.stories.tsx b/libs/shared/lib/components/tooltip/tooltip.stories.tsx
index cdc1ad9aa..2bd6e90db 100644
--- a/libs/shared/lib/components/tooltip/tooltip.stories.tsx
+++ b/libs/shared/lib/components/tooltip/tooltip.stories.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { Meta } from '@storybook/react';
+import { Meta, StoryObj } from '@storybook/react';
 import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './index';
 
 export default {
diff --git a/libs/shared/lib/mock-data/query-result/typesMockQueryResults.json b/libs/shared/lib/mock-data/query-result/typesMockQueryResults.json
index ad7e20722..5aa034ef2 100644
--- a/libs/shared/lib/mock-data/query-result/typesMockQueryResults.json
+++ b/libs/shared/lib/mock-data/query-result/typesMockQueryResults.json
@@ -1 +1,173 @@
-{"edges":[{"from":"worker/1","_id":"onderdeel_van/1100","_key":"1100","_rev":"_cYl_jTO--O","to":"worker/3","attributes":{}},{"from":"worker/3","_id":"onderdeel_van/662","_key":"662","_rev":"_cYl_jR2--G","to":"worker/5","attributes":{}}],"nodes":[{"_id":"worker/1","_key":"1","_rev":"_cYl-Qmq-_H","attributes":{"name":"John Doe","age":30,"height":175.5,"sacked":false,"birthdate":"1992-03-15","startingSchedule":"08:00:00","commutingDuration":"PT1H","firstLogin":"2023-12-20T09:30:00Z"}},{"_id":"worker/2","_key":"2","_rev":"_cYl-Qmq--5","attributes":{"name":"Bob Johnson","age":35,"height":180.2,"sacked":false,"birthdate":"1987-06-10","startingSchedule":"07:45:00","commutingDuration":"PT1H15M","firstLogin":"2023-12-18T10:00:00Z"}},{"_id":"worker/3","_key":"3","_rev":"_cYl-Qmq--3","attributes":{"name":"Jane Smith","age":28,"height":162,"sacked":true,"birthdate":"1995-08-20","startingSchedule":"09:30:00","commutingDuration":"PT45M","firstLogin":"2023-12-19T08:45:00Z"}},{"_id":"worker/4","_key":"4","_rev":"_cYl-Qmq--z","attributes":{"name":"Bob Knee","age":35,"height":180.2,"sacked":false,"birthdate":"1987-06-10","startingSchedule":"07:45:00","commutingDuration":"PT1H15M","firstLogin":"2023-10-18T10:00:00Z"}},{"_id":"worker/5","_key":"5","_rev":"_cYl-Qmq--x","attributes":{"name":"Alice Brown","age":25,"height":155.8,"sacked":true,"birthdate":"1998-01-05","startingSchedule":"08:30:00","commutingDuration":"PT30M","firstLogin":"2023-12-17T11:15:00Z"}},{"_id":"worker/6","_key":"6","_rev":"_cYl-Qmq--v","attributes":{"name":"Michael Davis","age":40,"height":170,"sacked":false,"birthdate":"1982-11-25","startingSchedule":"08:15:00","commutingDuration":"PT1H30M","firstLogin":"2023-12-16T12:30:00Z"}},{"_id":"worker/7","_key":"7","_rev":"_cYl-Qmq--p","attributes":{"name":"Sophia Turner","age":27,"height":168.5,"sacked":false,"birthdate":"1994-07-08","startingSchedule":"09:00:00","commutingDuration":"PT45M","firstLogin":"2023-12-15T14:00:00Z"}},{"_id":"worker/8","_key":"8","_rev":"_cYl-Qmq--n","attributes":{"name":"David Miller","age":34,"height":185,"sacked":true,"birthdate":"1989-04-30","startingSchedule":"07:30:00","commutingDuration":"PT1H","firstLogin":"2023-12-14T15:15:00Z"}},{"_id":"worker/9","_key":"9","_rev":"_cYl-Qmq--l","attributes":{"name":"Olivia Harris","age":31,"height":160.5,"sacked":false,"birthdate":"1992-12-15","startingSchedule":"09:45:00","commutingDuration":"PT1H15M","firstLogin":"2023-12-13T16:30:00Z"}},{"_id":"worker/10","_key":"10","_rev":"_cYl-Qmq--j","attributes":{"name":"Daniel Lee","age":29,"height":175,"sacked":true,"birthdate":"1994-09-20","startingSchedule":"08:00:00","commutingDuration":"PT30M","firstLogin":"2023-12-12T17:45:00Z"}},{"_id":"worker/11","_key":"11","_rev":"_cYl-Qmq--f","attributes":{"name":"Emily White","age":33,"height":163.5,"sacked":false,"birthdate":"1989-06-18","startingSchedule":"08:45:00","commutingDuration":"PT1H30M","firstLogin":"2023-12-11T19:00:00Z"}}]}
\ No newline at end of file
+{
+  "edges": [
+    { "from": "worker/1", "_id": "onderdeel_van/1100", "_key": "1100", "_rev": "_cYl_jTO--O", "to": "worker/3", "attributes": {} },
+    { "from": "worker/3", "_id": "onderdeel_van/662", "_key": "662", "_rev": "_cYl_jR2--G", "to": "worker/5", "attributes": {} }
+  ],
+  "nodes": [
+    {
+      "_id": "worker/1",
+      "_key": "1",
+      "_rev": "_cYl-Qmq-_H",
+      "attributes": {
+        "name": "John Doe",
+        "age": 30,
+        "height": 175.5,
+        "sacked": false,
+        "birthdate": "1992-03-15",
+        "startingSchedule": "08:00:00",
+        "commutingDuration": "PT1H",
+        "firstLogin": "2023-12-20T09:30:00Z"
+      }
+    },
+    {
+      "_id": "worker/2",
+      "_key": "2",
+      "_rev": "_cYl-Qmq--5",
+      "attributes": {
+        "name": "Bob Johnson",
+        "age": 35,
+        "height": 180.2,
+        "sacked": false,
+        "birthdate": "",
+        "startingSchedule": "07:45:00",
+        "commutingDuration": "PT1H15M",
+        "firstLogin": "2023-12-18T10:00:00Z"
+      }
+    },
+    {
+      "_id": "worker/3",
+      "_key": "3",
+      "_rev": "_cYl-Qmq--3",
+      "attributes": {
+        "name": "Jane Smith",
+        "age": 28,
+        "height": 162,
+        "sacked": true,
+        "birthdate": "1995-08-20",
+        "startingSchedule": "09:30:00",
+        "commutingDuration": "PT45M",
+        "firstLogin": "2023-12-19T08:45:00Z"
+      }
+    },
+    {
+      "_id": "worker/4",
+      "_key": "4",
+      "_rev": "_cYl-Qmq--z",
+      "attributes": {
+        "name": "Bob Knee",
+        "age": 35,
+        "height": 180.2,
+        "sacked": false,
+        "birthdate": "1987-06-10",
+        "startingSchedule": "07:45:00",
+        "commutingDuration": "PT1H15M",
+        "firstLogin": "2023-10-18T10:00:00Z"
+      }
+    },
+    {
+      "_id": "worker/5",
+      "_key": "5",
+      "_rev": "_cYl-Qmq--x",
+      "attributes": {
+        "name": "Alice Brown",
+        "age": 25,
+        "height": 155.8,
+        "sacked": true,
+        "birthdate": "1998-01-05",
+        "startingSchedule": "08:30:00",
+        "commutingDuration": "PT30M",
+        "firstLogin": "2023-12-17T11:15:00Z"
+      }
+    },
+    {
+      "_id": "worker/6",
+      "_key": "6",
+      "_rev": "_cYl-Qmq--v",
+      "attributes": {
+        "name": "Michael Davis",
+        "age": 40,
+        "height": 170,
+        "sacked": false,
+        "birthdate": "1982-11-25",
+        "startingSchedule": "08:15:00",
+        "commutingDuration": "PT1H30M",
+        "firstLogin": "2023-12-16T12:30:00Z"
+      }
+    },
+    {
+      "_id": "worker/7",
+      "_key": "7",
+      "_rev": "_cYl-Qmq--p",
+      "attributes": {
+        "name": "Sophia Turner",
+        "age": 27,
+        "height": 168.5,
+        "sacked": false,
+        "birthdate": "1994-07-08",
+        "startingSchedule": "09:00:00",
+        "commutingDuration": "PT45M",
+        "firstLogin": "2023-12-15T14:00:00Z"
+      }
+    },
+    {
+      "_id": "worker/8",
+      "_key": "8",
+      "_rev": "_cYl-Qmq--n",
+      "attributes": {
+        "name": "David Miller",
+        "age": 34,
+        "height": 185,
+        "sacked": true,
+        "birthdate": "1989-04-30",
+        "startingSchedule": "07:30:00",
+        "commutingDuration": "PT1H",
+        "firstLogin": "2023-12-14T15:15:00Z"
+      }
+    },
+    {
+      "_id": "worker/9",
+      "_key": "9",
+      "_rev": "_cYl-Qmq--l",
+      "attributes": {
+        "name": "Olivia Harris",
+        "age": 31,
+        "height": 160.5,
+        "sacked": false,
+        "birthdate": "1992-12-15",
+        "startingSchedule": "09:45:00",
+        "commutingDuration": "PT1H15M",
+        "firstLogin": "2023-12-13T16:30:00Z"
+      }
+    },
+    {
+      "_id": "worker/10",
+      "_key": "10",
+      "_rev": "_cYl-Qmq--j",
+      "attributes": {
+        "name": "Daniel Lee",
+        "age": 29,
+        "height": 175,
+        "sacked": true,
+        "birthdate": "1994-09-20",
+        "startingSchedule": "08:00:00",
+        "commutingDuration": "PT30M",
+        "firstLogin": "2023-12-12T17:45:00Z"
+      }
+    },
+    {
+      "_id": "worker/11",
+      "_key": "11",
+      "_rev": "_cYl-Qmq--f",
+      "attributes": {
+        "name": "Emily White",
+        "age": 33,
+        "height": 163.5,
+        "sacked": false,
+        "birthdate": "",
+        "startingSchedule": "08:45:00",
+        "commutingDuration": "PT1H30M",
+        "firstLogin": "2023-12-11T19:00:00Z"
+      }
+    }
+  ]
+}
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/components/query2NL.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/components/query2NL.tsx
index ef0aba7b5..2c6d73ce6 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/components/query2NL.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/components/query2NL.tsx
@@ -156,11 +156,23 @@ export function parseQueryResult(queryResult: GraphQueryResult, ml: ML, options:
   let communityDetectionInResult = false;
   let shortestPathInResult = false;
   let linkPredictionInResult = false;
-
   for (let i = 0; i < queryResult.nodes.length; i++) {
     // Assigns a group to every entity type for color coding
     const nodeId = queryResult.nodes[i]._id;
-    const entityType = queryResult.nodes[i].label;
+    // for datasets without label, label is included in id. eg. "kamerleden/112"
+    //const entityType = queryResult.nodes[i].label;
+    let entityType: string;
+    const node = queryResult.nodes[i];
+
+    if (node.label === undefined) {
+      if (node.attributes.labels !== undefined && Array.isArray(node.attributes.labels)) {
+        entityType = node.attributes.labels[0];
+      } else {
+        entityType = node._id.split('/')[0];
+      }
+    } else {
+      entityType = node.label;
+    }
 
     // The preferred text to be shown on top of the node
     let preferredText = nodeId;
@@ -180,10 +192,12 @@ export function parseQueryResult(queryResult: GraphQueryResult, ml: ML, options:
     if (queryResult.nodes[i].attributes.label !== undefined) preferredText = queryResult.nodes[i].attributes.label as string;
     if (queryResult.nodes[i].attributes.naam !== undefined) preferredText = queryResult.nodes[i].attributes.naam as string;
 
+    //const labelTemplate = queryResult.nodes[i].label == undefined ? queryResult.nodes[i]._id.split('/')[0] : queryResult.nodes[i].label;
+
     let radius = options.defaultRadius || 5;
     let data: NodeType = {
       _id: queryResult.nodes[i]._id,
-      label: queryResult.nodes[i].label,
+      label: entityType,
       attributes: queryResult.nodes[i].attributes,
       type: typeNumber,
       displayInfo: preferredText,
diff --git a/libs/shared/lib/vis/visualizations/tablevis/components/Table.tsx b/libs/shared/lib/vis/visualizations/tablevis/components/Table.tsx
index 0f9759061..365d3fe68 100644
--- a/libs/shared/lib/vis/visualizations/tablevis/components/Table.tsx
+++ b/libs/shared/lib/vis/visualizations/tablevis/components/Table.tsx
@@ -27,7 +27,8 @@ type Data2RenderI = {
   showBarPlot?: boolean;
 };
 
-const THRESHOLD_WIDTH = 100;
+const THRESHOLD_WIDTH = 50;
+const NODATASTRING = 'NoData';
 
 export const Table = ({ data, itemsPerPage, showBarPlot, showAttributes, selectedEntity, maxBarsCount }: TableProps) => {
   const maxUniqueValues = 29;
@@ -44,8 +45,11 @@ export const Table = ({ data, itemsPerPage, showBarPlot, showAttributes, selecte
   } | null>(null);
   const [data2Render, setData2Render] = useState<Data2RenderI[]>([]);
   const dataColumns = useMemo(() => {
-    if (showAttributes && showAttributes.length > 0) {
-      return showAttributes.filter((attr) => Object.keys(data[0].attribute).includes(attr));
+    // sort to keep original order
+    const showAttributesCopy = [...showAttributes].sort((a, b) => a.localeCompare(b));
+
+    if (showAttributesCopy && showAttributesCopy.length > 0) {
+      return showAttributesCopy.filter((attr) => Object.keys(data[0].attribute).includes(attr));
     }
     return Object.keys(data[0].attribute);
   }, [data, showAttributes, selectedEntity]);
@@ -155,7 +159,6 @@ export const Table = ({ data, itemsPerPage, showBarPlot, showAttributes, selecte
         data: [],
         numElements: 0,
       };
-
       if (
         firstRowData.type[dataColumn] === 'string' ||
         firstRowData.type[dataColumn] === 'date' ||
@@ -163,7 +166,26 @@ export const Table = ({ data, itemsPerPage, showBarPlot, showAttributes, selecte
         firstRowData.type[dataColumn] === 'datetime' ||
         firstRowData.type[dataColumn] === 'time'
       ) {
-        const groupedData = group(data, (d) => d.attribute[dataColumn]);
+        const groupedData = group(data, (d) => {
+          const value = d.attribute[dataColumn];
+
+          if (typeof value === 'object' && value !== null) {
+            if (Object.keys(value).length === 0) {
+              return NODATASTRING;
+            } else {
+              return value;
+            }
+          } else {
+            if (value === undefined || value === '') {
+              return NODATASTRING;
+            } else if (Array.isArray(value)) {
+              return value.toString();
+            } else {
+              return value;
+            }
+          }
+        });
+
         categoryCounts = Array.from(groupedData, ([category, items]) => ({
           category: category as string,
           count: items.length,
@@ -177,19 +199,7 @@ export const Table = ({ data, itemsPerPage, showBarPlot, showAttributes, selecte
           newData2Render.data = categoryCounts;
           newData2Render.showBarPlot = true;
         }
-      } else if (firstRowData.type[dataColumn] === 'bool') {
-        const groupedData = group(data, (d) => d.attribute[dataColumn]);
-
-        categoryCounts = Array.from(groupedData, ([category, items]) => ({
-          category: category as string,
-          count: items.length,
-        }));
-
-        newData2Render.numElements = categoryCounts.length;
-        newData2Render.data = categoryCounts;
-        newData2Render.showBarPlot = true;
-
-        // number: float and int
+        // boolean
       } else if (firstRowData.type[dataColumn] === 'bool') {
         const groupedData = group(data, (d) => d.attribute[dataColumn]);
 
@@ -228,8 +238,10 @@ export const Table = ({ data, itemsPerPage, showBarPlot, showAttributes, selecte
       return newData2Render;
     });
 
-    setData2Render(_data2Render);
-  }, [currentPage, data, sortedData, selectedEntity, maxBarsCount]);
+    const _data2RenderSorted = _data2Render.sort((a, b) => a.name.localeCompare(b.name));
+
+    setData2Render(_data2RenderSorted);
+  }, [currentPage, data, sortedData, selectedEntity, maxBarsCount, showAttributes]);
 
   return (
     <>
@@ -277,6 +289,7 @@ export const Table = ({ data, itemsPerPage, showBarPlot, showAttributes, selecte
                                   data={data2Render[index].data}
                                   marginPercentage={{ top: 0.1, right: 0, left: 0, bottom: 0 }}
                                   className="h-[4rem] max-h-[4rem]"
+                                  name={data2Render[index].name}
                                 />
                               ) : (
                                 <BarPlot
@@ -286,6 +299,7 @@ export const Table = ({ data, itemsPerPage, showBarPlot, showAttributes, selecte
                                   marginPercentage={{ top: 0.1, right: 0, left: 0, bottom: 0 }}
                                   className="h-[4rem] max-h-[4rem]"
                                   maxBarsCount={maxBarsCount}
+                                  name={data2Render[index].name}
                                 />
                               )
                             ) : (
@@ -304,11 +318,24 @@ export const Table = ({ data, itemsPerPage, showBarPlot, showAttributes, selecte
                 {currentPage.currentData.map((item, rowIndex) => (
                   <tr key={rowIndex}>
                     {dataColumns.map((col, colIndex) => (
-                      <td className="border-light" data-datatype={item.type[col]} key={colIndex}>
+                      <td
+                        className={`px-4 py-2 ${
+                          item.attribute[col] === undefined ||
+                          ((typeof item.attribute[col] !== 'object' || Array.isArray(item.attribute[col])) &&
+                            (item.attribute[col] as any).toString().trim() === '') ||
+                          (typeof item.attribute[col] === 'object' &&
+                            item.attribute[col] !== null &&
+                            Object.keys(item.attribute[col] as object).length === 0)
+                            ? styles['diagonal-lines']
+                            : 'border-light'
+                        }`}
+                        data-datatype={item.type[col]}
+                        key={colIndex}
+                      >
                         {item.attribute[col] !== undefined &&
                         (typeof item.attribute[col] !== 'object' || Array.isArray(item.attribute[col]))
                           ? (item.attribute[col] as any).toString()
-                          : ' '}
+                          : ''}
                       </td>
                     ))}
                   </tr>
diff --git a/libs/shared/lib/vis/visualizations/tablevis/components/table.module.scss b/libs/shared/lib/vis/visualizations/tablevis/components/table.module.scss
index d1447b756..a78018bb8 100644
--- a/libs/shared/lib/vis/visualizations/tablevis/components/table.module.scss
+++ b/libs/shared/lib/vis/visualizations/tablevis/components/table.module.scss
@@ -1,3 +1,9 @@
+.diagonal-lines {
+  border: 1px solid white;
+  background:
+    repeating-linear-gradient(-45deg, transparent, transparent 6px, #eaeaea 6px, #eaeaea 8px),
+    /* Gray diagonal lines */ linear-gradient(to bottom, transparent, transparent); /* Vertical gradient */
+}
 .table-container {
   @apply w-full relative overflow-x-auto;
 }
diff --git a/libs/shared/lib/vis/visualizations/tablevis/tablevis.stories.tsx b/libs/shared/lib/vis/visualizations/tablevis/tablevis.stories.tsx
index 9b36447bf..4a003577e 100644
--- a/libs/shared/lib/vis/visualizations/tablevis/tablevis.stories.tsx
+++ b/libs/shared/lib/vis/visualizations/tablevis/tablevis.stories.tsx
@@ -39,7 +39,11 @@ export const TestWithAirport = {
   args: {
     ...(await mockData.bigMockQueryResults()),
     schema: simpleSchemaAirportRaw,
-    settings: { ...TableComponent.settings, displayEntity: 'airports' },
+    settings: {
+      ...TableComponent.settings,
+      displayAttributes: ['city', 'country', 'lat', 'long', 'name', 'state', 'vip'],
+      displayEntity: 'airports',
+    },
   },
 };
 
@@ -47,15 +51,22 @@ export const TestWithBig2ndChamber = {
   args: {
     ...(await mockData.big2ndChamberQueryResult()),
     schema: big2ndChamberSchemaRaw,
-    settings: { ...TableComponent.settings, displayEntity: 'kamerleden' },
+    settings: {
+      ...TableComponent.settings,
+      displayAttributes: ['naam', 'anc', 'img', 'leeftijd', 'height', 'partij', 'woonplaats'],
+      displayEntity: 'kamerleden',
+    },
   },
 };
-
 export const TestWithTypesMock = {
   args: {
     ...(await mockData.typesMockQueryResults()),
     schema: typesMockSchemaRaw,
-    settings: { ...TableComponent.settings, displayEntity: 'worker' },
+    settings: {
+      ...TableComponent.settings,
+      displayAttributes: ['name', 'age', 'height', 'sacked', 'birthdate', 'startingSchedule', 'commutingDuration', 'firstLogin'],
+      displayEntity: 'worker',
+    },
   },
 };
 
diff --git a/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx b/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx
index f92d97beb..def795508 100644
--- a/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx
+++ b/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx
@@ -1,11 +1,11 @@
 import React, { useEffect, useMemo, useRef, useState } from 'react';
 import { Table, AugmentedNodeAttributes } from './components/Table';
-import { SchemaAttribute } from '../../../schema';
 import { VisualizationPropTypes, VISComponentType, VisualizationSettingsPropTypes } from '../../common';
 import { Input } from '@graphpolaris/shared/lib/components/inputs';
 import { SettingsContainer } from '@graphpolaris/shared/lib/vis/components/config';
 import { Button } from '@graphpolaris/shared/lib/components/buttons';
 import { ArrowDropDown } from '@mui/icons-material';
+import { useSearchResultData } from '@graphpolaris/shared/lib/data-access';
 
 export type TableProps = {
   id: string;
@@ -28,31 +28,76 @@ const settings: TableProps = {
 };
 
 export const TableVis = ({ data, schema, settings, updateSettings, graphMetadata }: VisualizationPropTypes<TableProps>) => {
+  const searchResults = useSearchResultData();
   const ref = useRef<HTMLDivElement>(null);
-
   useEffect(() => {
-    if (!graphMetadata.nodes.labels.includes(settings.displayEntity)) {
-      updateSettings({ displayEntity: graphMetadata.nodes.labels[0] });
+    if (graphMetadata != undefined) {
+      if (!graphMetadata.nodes.labels.includes(settings.displayEntity)) {
+        updateSettings({
+          displayEntity: graphMetadata.nodes.labels[0],
+          displayAttributes: Object.keys(graphMetadata.nodes.types[graphMetadata.nodes.labels[0]].attributes),
+        });
+      }
     }
-  }, [graphMetadata.nodes.labels, data, settings]);
+  }, [graphMetadata, data, settings]);
+
+  const attributesArray = useMemo<AugmentedNodeAttributes[]>(() => {
+    //const similiarityThreshold = 0.9;
+    let displayAttributesSorted: string[];
+
+    displayAttributesSorted = [...settings.displayAttributes].sort((a, b) => a.localeCompare(b));
+
+    const dataNodes = (searchResults?.nodes?.length ?? 0) === 0 ? data.nodes : searchResults.nodes;
 
-  const attributesArray = useMemo<AugmentedNodeAttributes[]>(
-    () =>
-      data.nodes
-        .filter((node) => node.label === settings.displayEntity)
+    return (
+      dataNodes
+        .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 === settings.displayEntity;
+        })
+        ///.filter((obj) => obj.similarity === undefined || obj.similarity >= similiarityThreshold)
         .map((node) => {
-          const types: SchemaAttribute[] =
-            schema.nodes.find((n) => n.key === node.label)?.attributes?.attributes ??
-            schema.edges.find((r) => r.key === node.label)?.attributes?.attributes ??
-            [];
-
-          return {
-            attribute: node.attributes,
-            type: Object.fromEntries(types.map((t) => [t.name, t.type])),
-          };
-        }),
-    [data.nodes, settings.displayEntity],
-  );
+          // get attributes filtered and sorted
+          const filteredAttributes = Object.fromEntries(
+            Object.entries(node.attributes)
+              .filter(([attr]) => settings.displayAttributes.includes(attr))
+              .sort(([attrA], [attrB]) => settings.displayAttributes.indexOf(attrA) - settings.displayAttributes.indexOf(attrB)),
+          );
+
+          // doubled types structure to handle discrepancies in schema object in sb and dev env.
+
+          let types =
+            schema.nodes.find((n: any) => {
+              let labelNode = node.label;
+              return labelNode === n.key;
+            })?.attributes?.attributes ??
+            schema.nodes.find((n: any) => {
+              let labelNode = node.label;
+
+              return labelNode === n.name;
+            })?.attributes;
+
+          if (types) {
+            return {
+              attribute: filteredAttributes,
+              type: Object.fromEntries(types.map((t: any) => [t.name, t.type])),
+            };
+          } else {
+            return {
+              attribute: filteredAttributes,
+              type: {},
+            };
+          }
+        })
+    );
+  }, [data.nodes, settings.displayEntity, settings.displayAttributes, searchResults]);
 
   return (
     <div className="h-full w-full" ref={ref}>
@@ -81,11 +126,12 @@ const TableSettings = ({ settings, graphMetadata, updateSettings }: Visualizatio
   const toggleCollapseAttr = () => {
     setAreCollapsedAttr(!areCollapsedAttr);
   };
+
   const selectedNodeAttributes = useMemo(() => {
     if (settings.displayEntity) {
       const nodeType = graphMetadata.nodes.types[settings.displayEntity];
       if (nodeType && nodeType.attributes) {
-        return Object.keys(nodeType.attributes);
+        return Object.keys(nodeType.attributes).sort((a, b) => a.localeCompare(b));
       }
     }
     return [];
@@ -95,7 +141,7 @@ const TableSettings = ({ settings, graphMetadata, updateSettings }: Visualizatio
     if (graphMetadata && graphMetadata.nodes && graphMetadata.nodes.labels.length > 0) {
       updateSettings({ displayAttributes: selectedNodeAttributes });
     }
-  }, [selectedNodeAttributes]);
+  }, [selectedNodeAttributes, graphMetadata]);
 
   return (
     <SettingsContainer>
-- 
GitLab