From 269243ca9fb825fa6862298ef311f51fa1194b86 Mon Sep 17 00:00:00 2001
From: MarcosPierasNL <pieras.marcos@gmail.com>
Date: Fri, 7 Mar 2025 09:58:22 +0100
Subject: [PATCH] feat: update separator in populate template

---
 src/utils/insights.ts | 220 +++++++++++++++++++++---------------------
 1 file changed, 110 insertions(+), 110 deletions(-)

diff --git a/src/utils/insights.ts b/src/utils/insights.ts
index 621474e..7d91960 100644
--- a/src/utils/insights.ts
+++ b/src/utils/insights.ts
@@ -1,10 +1,10 @@
-import { scaleOrdinal, scaleQuantize } from "d3";
-import { JSDOM } from "jsdom";
-import svg2img from "svg2img";
-import "canvas";
-import { visualizationColors, type GraphQueryResultFromBackend, type GraphQueryResultMetaFromBackend } from "ts-common";
+import { scaleOrdinal, scaleQuantize } from 'd3';
+import { JSDOM } from 'jsdom';
+import svg2img from 'svg2img';
+import 'canvas';
+import { visualizationColors, type GraphQueryResultFromBackend, type GraphQueryResultMetaFromBackend } from 'ts-common';
 
-import { type PlotType } from "plotly.js";
+import { type PlotType } from 'plotly.js';
 
 const dom = new JSDOM();
 
@@ -20,41 +20,41 @@ dom.window.HTMLCanvasElement.prototype.getContext = function () {
   return null;
 };
 dom.window.URL.createObjectURL = function () {
-  return "";
+  return '';
 };
 
 export enum VariableType {
-  statistic = "statistic",
-  visualization = "visualization",
+  statistic = 'statistic',
+  visualization = 'visualization',
 }
 
 async function replaceAllAsync(string: string, regexp: RegExp, replacerFunction: CallableFunction) {
-  const replacements = await Promise.all(Array.from(string.matchAll(regexp), (match) => replacerFunction(...match)));
+  const replacements = await Promise.all(Array.from(string.matchAll(regexp), match => replacerFunction(...match)));
   let i = 0;
   return string.replace(regexp, () => replacements[i++]);
 }
 
 export async function populateTemplate(html: string, result: GraphQueryResultMetaFromBackend, openVisualizationArray: any[]) {
-  const regex = / *?{\{ *?(\w*?):([\w ]*?) *?\}\} *?/gm;
+  const regex = / *?{\{ *?(\w*?):([\w • ]*?) *?\}\} *?/gm;
 
   return replaceAllAsync(html, regex, async (_: string, _type: string, name: string) => {
     const type = VariableType[_type as keyof typeof VariableType];
 
     switch (type) {
       case VariableType.statistic: {
-        const [nodeType, feature, statistic] = name.split(" ");
+        const [nodeType, feature, statistic] = name.split(' • ');
         const node = result.metaData.nodes.types[nodeType];
         const attribute = node?.attributes[feature].statistics as any;
-        if (attribute == null) return "";
+        if (attribute == null) return '';
         const value = attribute[statistic];
         return ` ${value} `;
       }
 
       case VariableType.visualization: {
-        const activeVisualization = openVisualizationArray.find((x) => x.name == name); // TODO: enforce type
+        const activeVisualization = openVisualizationArray.find(x => x.name == name); // TODO: enforce type
 
         if (!activeVisualization) {
-          throw new Error("Tried to render non-existing visualization");
+          throw new Error('Tried to render non-existing visualization');
         }
         const xAxisData = getAttributeValues(result, activeVisualization.selectedEntity, activeVisualization.xAxisLabel!);
         let yAxisData: (string | number)[] = [];
@@ -72,9 +72,9 @@ export async function populateTemplate(html: string, result: GraphQueryResultMet
         const stack = activeVisualization.stack;
         const showAxis = true;
 
-        const xAxisLabel = "";
-        const yAxisLabel = "";
-        const zAxisLabel = "";
+        const xAxisLabel = '';
+        const yAxisLabel = '';
+        const zAxisLabel = '';
 
         const plotType = activeVisualization.plotType;
 
@@ -88,7 +88,7 @@ export async function populateTemplate(html: string, result: GraphQueryResultMet
           zAxisLabel,
           showAxis,
           groupBy,
-          stack
+          stack,
         );
 
         const layout2 = {
@@ -98,11 +98,11 @@ export async function populateTemplate(html: string, result: GraphQueryResultMet
           title: activeVisualization.title,
         };
 
-        const { newPlot } = await import("plotly.js");
-        const plot = await newPlot(dom.window.document.createElement("div"), plotData, layout2);
-        const svgString = plot.querySelector("svg")?.outerHTML;
+        const { newPlot } = await import('plotly.js');
+        const plot = await newPlot(dom.window.document.createElement('div'), plotData, layout2);
+        const svgString = plot.querySelector('svg')?.outerHTML;
         if (!svgString) {
-          return "";
+          return '';
         }
         const dataURI = await svgToBase64(svgString);
 
@@ -116,19 +116,19 @@ const svgToBase64 = (svgString: string) => {
   return new Promise((resolve, reject) => {
     svg2img(svgString, (error: any, buffer: Buffer) => {
       if (error != null) reject(error);
-      resolve(buffer.toString("base64"));
+      resolve(buffer.toString('base64'));
     });
   });
 };
 
-export const plotTypeOptions = ["bar", "scatter", "line", "histogram", "pie"] as const;
+export const plotTypeOptions = ['bar', 'scatter', 'line', 'histogram', 'pie'] as const;
 export type SupportedPlotType = (typeof plotTypeOptions)[number];
 
 const groupByTime = (xAxisData: string[], groupBy: string, additionalVariableData?: (string | number)[]) => {
   // Function to parse the date-time string into a JavaScript Date object
   const parseDate = (dateStr: string) => {
     // Remove nanoseconds part and use just the standard "YYYY-MM-DD HH:MM:SS" part
-    const cleanedDateStr = dateStr.split(".")[0];
+    const cleanedDateStr = dateStr.split('.')[0];
     return new Date(cleanedDateStr);
   };
 
@@ -137,15 +137,15 @@ const groupByTime = (xAxisData: string[], groupBy: string, additionalVariableDat
     const date = parseDate(dateStr);
     let groupKey: string;
 
-    if (groupBy === "yearly") {
+    if (groupBy === 'yearly') {
       groupKey = date.getFullYear().toString(); // Group by year (e.g., "2012")
-    } else if (groupBy === "quarterly") {
+    } else if (groupBy === 'quarterly') {
       const month = date.getMonth() + 1; // Adjust month for zero-indexed months
       const quarter = Math.floor((month - 1) / 3) + 1; // Calculate quarter (Q1-Q4)
       groupKey = `${date.getFullYear()}-Q${quarter}`;
-    } else if (groupBy === "monthly") {
+    } else if (groupBy === 'monthly') {
       // Group by month, e.g., "2012-07"
-      groupKey = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, "0")}`;
+      groupKey = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}`;
     } else {
       // Default case: group by year (or some other grouping logic)
       groupKey = date.getFullYear().toString();
@@ -154,7 +154,7 @@ const groupByTime = (xAxisData: string[], groupBy: string, additionalVariableDat
     // Initialize the group if it doesn't exist
     if (!acc[groupKey]) {
       acc[groupKey] = additionalVariableData
-        ? typeof additionalVariableData[0] === "number"
+        ? typeof additionalVariableData[0] === 'number'
           ? 0 // Initialize sum for numbers
           : [] // Initialize array for strings
         : 0; // Initialize count for no additional data
@@ -162,9 +162,9 @@ const groupByTime = (xAxisData: string[], groupBy: string, additionalVariableDat
 
     // Aggregate additional variable if provided
     if (additionalVariableData) {
-      if (typeof additionalVariableData[index] === "number") {
+      if (typeof additionalVariableData[index] === 'number') {
         acc[groupKey] = (acc[groupKey] as number) + (additionalVariableData[index] as number);
-      } else if (typeof additionalVariableData[index] === "string") {
+      } else if (typeof additionalVariableData[index] === 'string') {
         acc[groupKey] = [...(acc[groupKey] as string[]), additionalVariableData[index] as string];
       }
     } else {
@@ -183,7 +183,7 @@ const groupByTime = (xAxisData: string[], groupBy: string, additionalVariableDat
 };
 
 const computeStringTickValues = (xValues: any[], maxTicks: number, maxLabelLength: number): any[] => {
-  const truncatedValues = xValues.map((label) => (label.length > maxLabelLength ? `${label.slice(0, maxLabelLength)}…` : label));
+  const truncatedValues = xValues.map(label => (label.length > maxLabelLength ? `${label.slice(0, maxLabelLength)}…` : label));
 
   return truncatedValues;
 };
@@ -198,17 +198,17 @@ export const preparePlotData = (
   zAxisLabel?: string,
   showAxis = true,
   groupBy?: string,
-  stack?: boolean
+  stack?: boolean,
 ): { plotData: Partial<Plotly.PlotData>[]; layout: Partial<Plotly.Layout> } => {
-  const primaryColor = "#a2aab9"; // '--clr-sec--400'
+  const primaryColor = '#a2aab9'; // '--clr-sec--400'
   const lengthLabelsX = 7; // !TODO computed number of elements based
   const lengthLabelsY = 8; // !TODO computed number of elements based
   const mainColors = visualizationColors.GPCat.colors[14];
 
   const sharedTickFont = {
-    family: "monospace",
+    family: 'monospace',
     size: 12,
-    color: "#374151", // !TODO get GP value
+    color: '#374151', // !TODO get GP value
   };
 
   let xValues: (string | number)[] = [];
@@ -218,19 +218,19 @@ export const preparePlotData = (
   let colorDataZ: string[] = [];
   let colorbar: any = {};
 
-  if (zAxisData && zAxisData.length > 0 && typeof zAxisData[0] === "number") {
+  if (zAxisData && zAxisData.length > 0 && typeof zAxisData[0] === 'number') {
     const mainColorsSeq = visualizationColors.GPSeq.colors[9];
-    const numericZAxisData = zAxisData.filter((item): item is number => typeof item === "number");
+    const numericZAxisData = zAxisData.filter((item): item is number => typeof item === 'number');
     const zMin = numericZAxisData.reduce((min, val) => (val < min ? val : min), zAxisData[0]);
     const zMax = numericZAxisData.reduce((max, val) => (val > max ? val : max), zAxisData[0]);
 
     // !TODO: option to have a linear or quantize scale
     colorScale = scaleQuantize<string>().domain([zMin, zMax]).range(mainColorsSeq);
 
-    colorDataZ = zAxisData?.map((item) => colorScale(item) || primaryColor);
+    colorDataZ = zAxisData?.map(item => colorScale(item) || primaryColor);
 
     colorbar = {
-      title: "Color Legend",
+      title: 'Color Legend',
       tickvals: [zMin, zMax],
       ticktext: [`${zMin}`, `${zMax}`],
     };
@@ -240,13 +240,13 @@ export const preparePlotData = (
     if (zAxisData && uniqueZAxisData) {
       colorScale = scaleOrdinal<string>().domain(uniqueZAxisData.map(String)).range(mainColors);
 
-      colorDataZ = zAxisData?.map((item) => colorScale(String(item)) || primaryColor);
+      colorDataZ = zAxisData?.map(item => colorScale(String(item)) || primaryColor);
       const sortedDomain = uniqueZAxisData.sort();
       colorbar = {
-        title: "Color Legend",
+        title: 'Color Legend',
         tickvals: sortedDomain,
-        ticktext: sortedDomain.map((val) => String(val)),
-        tickmode: "array",
+        ticktext: sortedDomain.map(val => String(val)),
+        tickmode: 'array',
       };
     }
   }
@@ -286,17 +286,17 @@ export const preparePlotData = (
   let truncatedYLabels: string[] = [];
   let yAxisRange: number[] = [];
 
-  if (typeof xValues[0] === "string") {
+  if (typeof xValues[0] === 'string') {
     truncatedXLabels = computeStringTickValues(xValues, 2, lengthLabelsX);
   }
 
-  if (typeof yValues[0] === "string" && (plotType === "scatter" || plotType === "line")) {
+  if (typeof yValues[0] === 'string' && (plotType === 'scatter' || plotType === 'line')) {
     truncatedYLabels = computeStringTickValues(yValues, 2, lengthLabelsY);
   }
   const plotData = (() => {
     switch (plotType) {
-      case "bar":
-        if (typeof xAxisData[0] === "string" && groupBy == undefined) {
+      case 'bar':
+        if (typeof xAxisData[0] === 'string' && groupBy == undefined) {
           const frequencyMap = xAxisData.reduce((acc, item) => {
             acc[item] = (acc[item] || 0) + 1;
             return acc;
@@ -315,36 +315,36 @@ export const preparePlotData = (
 
           return [
             {
-              type: "bar" as PlotType,
+              type: 'bar' as PlotType,
               x: xValues,
               y: yValues,
               marker: {
                 color: colorDataZ?.length != 0 ? colorDataZ : primaryColor,
               },
               customdata: sortedLabels,
-              hovertemplate: "<b>%{customdata}</b>: %{y}<extra></extra>",
+              hovertemplate: '<b>%{customdata}</b>: %{y}<extra></extra>',
             },
           ];
         } else {
           return [
             {
-              type: "bar" as PlotType,
+              type: 'bar' as PlotType,
               x: xValues,
               y: yValues,
               marker: { color: primaryColor },
               customdata: xValues,
-              hovertemplate: "<b>%{customdata}</b>: %{y}<extra></extra>",
+              hovertemplate: '<b>%{customdata}</b>: %{y}<extra></extra>',
             },
           ];
         }
 
-      case "scatter":
+      case 'scatter':
         return [
           {
-            type: "scatter" as PlotType,
+            type: 'scatter' as PlotType,
             x: xValues,
             y: yValues,
-            mode: "markers" as const,
+            mode: 'markers' as const,
             marker: {
               color: zAxisData && zAxisData.length > 0 ? colorDataZ : primaryColor,
               size: 7,
@@ -352,30 +352,30 @@ export const preparePlotData = (
             },
             customdata:
               xValues.length === 0
-                ? yValues.map((y) => `Y: ${y}`)
+                ? yValues.map(y => `Y: ${y}`)
                 : yValues.length === 0
-                ? xValues.map((x) => `X: ${x}`)
+                ? xValues.map(x => `X: ${x}`)
                 : xValues.map((x, index) => {
                     const zValue = zAxisData && zAxisData.length > 0 ? zAxisData[index] : null;
                     return zValue ? `X: ${x} | Y: ${yValues[index]} | Color: ${zValue}` : `X: ${x} | Y: ${yValues[index]}`;
                   }),
-            hovertemplate: "<b>%{customdata}</b><extra></extra>",
+            hovertemplate: '<b>%{customdata}</b><extra></extra>',
           },
         ];
-      case "line":
+      case 'line':
         return [
           {
-            type: "scatter" as PlotType,
+            type: 'scatter' as PlotType,
             x: xValues,
             y: yValues,
-            mode: "lines" as const,
+            mode: 'lines' as const,
             line: { color: primaryColor },
-            customdata: xValues.map((label) => (label === "undefined" || label === "null" || label === "" ? "nonData" : "")),
-            hovertemplate: "<b>%{customdata}</b><extra></extra>",
+            customdata: xValues.map(label => (label === 'undefined' || label === 'null' || label === '' ? 'nonData' : '')),
+            hovertemplate: '<b>%{customdata}</b><extra></extra>',
           },
         ];
-      case "histogram":
-        if (typeof xAxisData[0] === "string") {
+      case 'histogram':
+        if (typeof xAxisData[0] === 'string') {
           if (zAxisData && zAxisData?.length > 0) {
             const frequencyMap = xAxisData.reduce(
               (acc, item, index) => {
@@ -394,7 +394,7 @@ export const preparePlotData = (
                 acc[item].colors.push(color);
                 acc[item].zValues.push(zAxisData[index].toString());
                 // Group and count zValues
-                const zValue = zAxisData[index] || "(Empty)";
+                const zValue = zAxisData[index] || '(Empty)';
                 acc[item].zValueCounts[zValue] = (acc[item].zValueCounts[zValue] || 0) + 1;
 
                 return acc;
@@ -407,7 +407,7 @@ export const preparePlotData = (
                   zValues: string[];
                   zValueCounts: Record<string, number>; // To store grouped counts
                 }
-              >
+              >,
             );
             const colorToLegendName = new Map();
             const sortedCategories = Object.entries(frequencyMap).sort((a, b) => b[1].count - a[1].count);
@@ -430,13 +430,13 @@ export const preparePlotData = (
               });
             });
 
-            sortedLabels = sortedCategories.map((element) => element[0]);
+            sortedLabels = sortedCategories.map(element => element[0]);
 
             const traces = Array.from(colorToLegendName.entries()).map(([color, legendName]) => {
               const colorData = tracesByColor[color];
               const categoryCountMap: Record<string, number> = {};
 
-              sortedLabels.forEach((label) => {
+              sortedLabels.forEach(label => {
                 categoryCountMap[label] = frequencyMap[label].count;
               });
               const yValues = colorData.x.map((label, idx) => {
@@ -446,20 +446,20 @@ export const preparePlotData = (
               });
 
               const customdata = colorData.x.map((label, idx) => {
-                const colorTranslation = colorToLegendName.get(color) === " " ? "(Empty)" : colorToLegendName.get(color);
+                const colorTranslation = colorToLegendName.get(color) === ' ' ? '(Empty)' : colorToLegendName.get(color);
                 const percentage = ((100 * frequencyMap[label].zValueCounts[colorTranslation]) / frequencyMap[label].count).toFixed(1);
-                return [label, !stack ? frequencyMap[label]?.zValueCounts[colorTranslation] || 0 : percentage, colorTranslation || " "];
+                return [label, !stack ? frequencyMap[label]?.zValueCounts[colorTranslation] || 0 : percentage, colorTranslation || ' '];
               });
               return {
                 x: colorData.x,
                 y: yValues,
-                type: "bar" as PlotType,
+                type: 'bar' as PlotType,
                 name: legendName,
                 marker: { color: color },
                 customdata: customdata,
                 hovertemplate:
-                  "<b>X: %{customdata[0]}</b><br>" + "<b>Y: %{customdata[1]}</b><br>" + "<b>Color: %{customdata[2]}</b><extra></extra>",
-                ...(stack ? { stackgroup: "one" } : {}),
+                  '<b>X: %{customdata[0]}</b><br>' + '<b>Y: %{customdata[1]}</b><br>' + '<b>Color: %{customdata[2]}</b><extra></extra>',
+                ...(stack ? { stackgroup: 'one' } : {}),
               };
             });
 
@@ -477,19 +477,19 @@ export const preparePlotData = (
 
             return [
               {
-                type: "bar" as PlotType,
+                type: 'bar' as PlotType,
                 x: sortedLabels,
                 y: sortedFrequencies,
                 marker: { color: primaryColor },
                 customdata: sortedLabels,
-                hovertemplate: "<b>%{customdata}</b>: %{y}<extra></extra>",
+                hovertemplate: '<b>%{customdata}</b>: %{y}<extra></extra>',
               },
             ];
           }
         } else {
           if (zAxisData && zAxisData?.length > 0) {
             const binCount = 20; // Number of bins (you can make this configurable)
-            const numericXAxisData = xAxisData.map((val) => Number(val)).filter((val) => !isNaN(val));
+            const numericXAxisData = xAxisData.map(val => Number(val)).filter(val => !isNaN(val));
 
             const xMin = numericXAxisData.reduce((min, val) => Math.min(min, val), Infinity);
             const xMax = numericXAxisData.reduce((max, val) => Math.max(max, val), -Infinity);
@@ -505,7 +505,7 @@ export const preparePlotData = (
 
             // Assign data points to bins
             numericXAxisData.forEach((xValue, index) => {
-              const zValue = zAxisData ? zAxisData[index] || "(Empty)" : "(Empty)";
+              const zValue = zAxisData ? zAxisData[index] || '(Empty)' : '(Empty)';
               const binIndex = Math.floor((xValue - xMin) / binSize);
               const bin = bins[Math.min(binIndex, bins.length - 1)]; // Ensure the last value falls into the final bin
 
@@ -539,23 +539,23 @@ export const preparePlotData = (
               const colorData = tracesByColor[color];
               const customdata = colorData.x.map((binLabel, idx) => {
                 const countForColor = colorData.y[idx];
-                const percentage = stack ? countForColor.toFixed(1) + "%" : countForColor.toFixed(0);
+                const percentage = stack ? countForColor.toFixed(1) + '%' : countForColor.toFixed(0);
                 return [binLabel, countForColor, percentage, legendName];
               });
 
               return {
                 x: colorData.x,
                 y: colorData.y,
-                type: "bar" as PlotType,
+                type: 'bar' as PlotType,
                 name: legendName,
                 marker: { color },
                 customdata,
                 autobinx: true,
                 hovertemplate:
-                  "<b>Bin: %{customdata[0]}</b><br>" +
-                  "<b>Count/Percentage: %{customdata[2]}</b><br>" +
-                  "<b>Group: %{customdata[3]}</b><extra></extra>",
-                ...(stack ? { stackgroup: "one" } : {}),
+                  '<b>Bin: %{customdata[0]}</b><br>' +
+                  '<b>Count/Percentage: %{customdata[2]}</b><br>' +
+                  '<b>Group: %{customdata[3]}</b><extra></extra>',
+                ...(stack ? { stackgroup: 'one' } : {}),
               };
             });
 
@@ -564,7 +564,7 @@ export const preparePlotData = (
             // No zAxisData, simple histogram logic
             return [
               {
-                type: "histogram" as PlotType,
+                type: 'histogram' as PlotType,
                 x: xAxisData,
                 marker: { color: primaryColor },
                 customdata: xAxisData,
@@ -572,10 +572,10 @@ export const preparePlotData = (
             ];
           }
         }
-      case "pie":
+      case 'pie':
         return [
           {
-            type: "pie" as PlotType,
+            type: 'pie' as PlotType,
             labels: xValues.map(String),
             values: xAxisData,
             marker: { colors: mainColors },
@@ -587,22 +587,22 @@ export const preparePlotData = (
   })();
 
   const layout: Partial<Plotly.Layout> = {
-    barmode: "stack",
+    barmode: 'stack',
     xaxis: {
       title: {
-        text: showAxis ? (xAxisLabel ? xAxisLabel : "") : "",
+        text: showAxis ? (xAxisLabel ? xAxisLabel : '') : '',
         standoff: 30,
       },
       tickfont: sharedTickFont,
       showgrid: false,
       visible: showAxis,
-      ...(typeof xAxisData[0] === "string" || (plotType === "histogram" && sortedLabels.length > 0)
-        ? { type: "category", categoryarray: sortedLabels, categoryorder: "array" }
+      ...(typeof xAxisData[0] === 'string' || (plotType === 'histogram' && sortedLabels.length > 0)
+        ? { type: 'category', categoryarray: sortedLabels, categoryorder: 'array' }
         : {}),
       showline: true,
       zeroline: false,
-      tickvals: typeof xValues[0] == "string" ? xValues : undefined,
-      ticktext: typeof xValues[0] == "string" ? truncatedXLabels : undefined,
+      tickvals: typeof xValues[0] == 'string' ? xValues : undefined,
+      ticktext: typeof xValues[0] == 'string' ? truncatedXLabels : undefined,
     },
 
     yaxis: {
@@ -612,24 +612,24 @@ export const preparePlotData = (
       zeroline: false,
       tickfont: sharedTickFont,
       title: {
-        text: showAxis ? (yAxisLabel ? yAxisLabel : "") : "",
+        text: showAxis ? (yAxisLabel ? yAxisLabel : '') : '',
         standoff: 30,
       },
-      tickvals: typeof yValues[0] === "string" && (plotType === "scatter" || plotType === "line") ? yValues : undefined,
-      ticktext: typeof yValues[0] === "string" && (plotType === "scatter" || plotType === "line") ? truncatedYLabels : undefined,
+      tickvals: typeof yValues[0] === 'string' && (plotType === 'scatter' || plotType === 'line') ? yValues : undefined,
+      ticktext: typeof yValues[0] === 'string' && (plotType === 'scatter' || plotType === 'line') ? truncatedYLabels : undefined,
     },
     font: {
-      family: "Inter",
+      family: 'Inter',
       size: 12,
-      color: "#374151",
+      color: '#374151',
     },
     hoverlabel: {
-      bgcolor: "rgba(255, 255, 255, 0.8)",
-      bordercolor: "rgba(0, 0, 0, 0.2)",
+      bgcolor: 'rgba(255, 255, 255, 0.8)',
+      bordercolor: 'rgba(0, 0, 0, 0.2)',
       font: {
-        family: "monospace",
+        family: 'monospace',
         size: 14,
-        color: "#374151",
+        color: '#374151',
       },
     },
   };
@@ -639,21 +639,21 @@ export const preparePlotData = (
 export const getAttributeValues = (
   query: GraphQueryResultFromBackend,
   selectedEntity: string,
-  attributeKey: string | number | undefined
+  attributeKey: string | number | undefined,
 ): any[] => {
   if (!selectedEntity || !attributeKey) {
     return [];
   }
 
-  if (attributeKey == " ") {
+  if (attributeKey == ' ') {
     return [];
   }
   return query.nodes
-    .filter((item) => item.label === selectedEntity)
-    .map((item) => {
+    .filter(item => item.label === selectedEntity)
+    .map(item => {
       // Check if the attribute exists, return its value if it does, or an empty string otherwise
-      return item.attributes && attributeKey in item.attributes && item.attributes[attributeKey] != ""
+      return item.attributes && attributeKey in item.attributes && item.attributes[attributeKey] != ''
         ? item.attributes[attributeKey]
-        : "NoData";
+        : 'NoData';
     });
 };
-- 
GitLab