whylabs/whylogs-python

View on GitHub
python/whylogs/viz/html/js/whylogs-script.js

Summary

Maintainability
F
1 wk
Test Coverage
"use strict";

(function () {
  const MESSAGES = {
    error: {
      noInputElementFound: "It seems we could not find the file input element.",
      noBrowserSupport: "This browser does not seem to support the `files` property of file inputs.",
      noFileSelected: "Please select a file.",
      noProfileSelected: "Please select a profile.",
      fileAPINotSupported: "The file API is not supported on this browser yet.",
      invalidJSONFile:
        "The JSON file you are trying to load does not match the expected whylogs format. Please check the file and try again.",
    },
  };

  // HTML Elements
  const $selectedReferenceProfile = $(".wl__selected-reference-profile");
  const $selectedProfile = $(".wl__selected-profile");
  const $removeReferenceProfileButton = $("#remove-reference-profile-button")
  const $featureFileName = $(".wl__feature-file-name")
  const $notifCircleContainer = $(".notif-circle-container")
  const $boxes = $('input[name=checkbox]:checked');
  const $closeIcon = $("#close-icon");
  const $openSignUpText = $("#open-sign-up-text")
  const $signUpText = $(".sign-up-text");
  const $dropdownArrowIcon = $("#dropdown-arrow-icon");
  const $referenceJsonForm = $("#reference-json-form");
  const $referencefileInput = $("#reference-file-input");
  const $compareProfile = $("#compare-profile");
  const $featureCount = $(".wl__feature-count");
  const $sidebarFeatureNameList = $(".wl__sidebar-feature-name-list");
  const $featureCountDiscrete = $(".wl__feature-count--discrete");
  const $featureCountNonDiscrete = $(".wl__feature-count--non-discrete");
  const $featureCountUnknown = $(".wl__feature-count--unknown");
  const $tableBody = $(".wl__table-body");
  const $featureSearch = $("#wl__feature-search");
  const $featureFilterInput = $(".wl__feature-filter-input");
  const $jsonForm = $("#json-form");
  const $fileInput = $("#file-input");
  const $tableContent = $("#table-content");
  const $tableMessage = $("#table-message");
  const $sidebarContent = $("#sidebar-content");
  const $multiProfileWrap = $("#sidebar-content-multi-profile");
  const $propertyPanelTitle = $(".wl-property-panel__title");
  const $propertyPanelProfileName = $(".wl-property-panel__table-th-profile");
  const $filterOptions = $(".filter-options");

  // Constants and variables
  let featureSearchValue = "";
  let isActiveInferredType = {};
  let propertyPanelData = [];
  let referencePropertyPanelData = [];
  let jsonData = {};
  let referenceJsonData = {};
  let dataForRead = {};
  let featureDataForTableForAllProfiles = {};
  let numOfProfilesBasedOnType = {};
  let selectedProfiles = [];
  selectedProfiles.push("0");
  // Util functions

  function debounce(func, wait, immediate) {
    let timeout;

    return function () {
      const context = this;
      const args = arguments;
      const later = function () {
        timeout = null;
        if (!immediate) func.apply(context, args);
      };

      const callNow = immediate && !timeout;
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
      if (callNow) func.apply(context, args);
    };
  }

  function handleSearch() {
    const tableBodyChildrens = $tableBody.children();
    const featureListChildren = $sidebarFeatureNameList.children();
    let featureCount = 0;
    for (let i = 0; i < tableBodyChildrens.length; i++) {
      const name = tableBodyChildrens[i].dataset.featureName.toLowerCase();
      const type = tableBodyChildrens[i].dataset.inferredType.toLowerCase();

      if (isActiveInferredType[type] && name.startsWith(featureSearchValue)) {
        tableBodyChildrens[i].style.display = "";
        featureCount++;
      } else {
        tableBodyChildrens[i].style.display = "none";
      }
    }

    if (jsonData) {
      for (let i = 0; i < featureListChildren.length; i++) {
        const name = featureListChildren[i].dataset.featureName.toLowerCase();
        const type = featureListChildren[i].dataset.inferredType.toLowerCase();
        if (isActiveInferredType[type] && name.startsWith(featureSearchValue)) {
          featureListChildren[i].style.display = "";
        } else {
          featureListChildren[i].style.display = "none";
        }
      }
    }
    $featureCount.html(featureCount);
  }

  function fixNumberTo(number, decimals = 3) {
    return parseFloat(number).toFixed(decimals);
  }

  function getQuantileValues(data) {
    return {
      min: fixNumberTo(data[0]),
      firstQuantile: fixNumberTo(data[3]),
      median: fixNumberTo(data[4]),
      thirdQuantile: fixNumberTo(data[5]),
      max: fixNumberTo(data[8]),
    };
  }

  function formatLabelDate(timestamp) {
    const date = new Date(timestamp);
    const format = d3.timeFormat("%Y-%m-%d %I:%M:%S %p %Z");
    return format(date);
  }

  function scrollToFeatureName(event) {
    const TABLE_HEADER_OFFSET = 90;
    const $tableWrap = $(".wl-table-wrap");
    const featureNameId = event.currentTarget.dataset.featureNameId;
    const currentOffsetTop = $tableWrap.scrollTop();
    const offsetTop = $('[data-scroll-to-feature-name="' + featureNameId + '"]').offset().top;

    $tableWrap.animate(
      {
        scrollTop: currentOffsetTop + offsetTop - TABLE_HEADER_OFFSET,
      },
      500,
    );
  }

  const chipElement = (chip) => `<span class="wl-table-cell__bedge">${chip}</span>`;
  const chipElementTableData = (value) => `<td class="wl-property-panel__table-td" >${chipElement(value)}</td>`;

  const chartBoxElement = (chartTitle, chart) => `
    <div class="chart-box-wrap mb-4">
      <div class="chart-box" id="chart-box">
        <div class="chart-box-title display-flex">${chartTitle}</div>
        <div class="svg-container">${chart}</div>
      </div>
    </div>
  `

  const frequentItemBoxElement = (chartTitle, items) => `
    <div class="frequent-item-box-wrap mb-4">
      <div class="frequent-item-box display-flex" id="chart-box">
          <tbody class="wl-property-panel__frequent-items">
            ${items}
          </tbody>
        </div>
    </div>
  `

  const colorsForDistingushingCharts = (color, text) => `
    <div class="colors-for-distingushing-charts">
      <div class="circle-color" style="background: ${color};"></div>
      <text alignment-baseline="middle" style="font-size: 15px;">${text}</text>
    </div>
  `

  class GenerateChartParams {
    constructor(height, width, data, bottomMargin=20, topMargin=5) {
      this.MARGIN = {
        TOP: topMargin,
        RIGHT: 5,
        BOTTOM: bottomMargin,
        LEFT: 55,
      };
      this.SVG_WIDTH = width;
      this.SVG_HEIGHT = height;
      this.CHART_WIDTH = this.SVG_WIDTH - this.MARGIN.LEFT - this.MARGIN.RIGHT;
      this.CHART_HEIGHT = this.SVG_HEIGHT - this.MARGIN.TOP - this.MARGIN.BOTTOM;
      this.svgEl = d3.create("svg").attr("width", this.SVG_WIDTH).attr("height", this.SVG_HEIGHT);
      this.maxYValue = d3.max(data, (d) => Math.abs(d.axisY));
      this.xScale = d3
        .scaleBand()
        .domain(data.map((d) => d.axisX))
        .range([this.MARGIN.LEFT, this.MARGIN.LEFT + this.CHART_WIDTH]);
      this.yScale = d3
        .scaleLinear()
        .domain([0, this.maxYValue * 1.02])
        .range([this.CHART_HEIGHT, 0]);
    }
  }

  const referenceProfilePanelHeight = () => {
    const pageHeight = $(document).height() - 48;
    if ($(".clickable-test-feature-wrap").height() <= pageHeight) {
      $(".clickable-test-feature-wrap").css("height", pageHeight)
    } else {
      $(".clickable-test-feature-wrap").css("height", "auto")
    }
  }

  function getGraphHtml(data, height = 75, width = 350, index = 0, referenceProfile = false, propertyPanelGraph = false) {
    const sizes = new GenerateChartParams(height, width, data, 5)
    let {
      MARGIN,
      CHART_HEIGHT,
      svgEl,
      maxYValue,
      xScale,
      yScale
    } = sizes
    const color = ["#369BAC", '#2683C9']

    if (propertyPanelGraph) {
     svgEl = d3.create("svg").attr("width", width).attr("height", height);
    }

    // Add the y Axis
    if (!referenceProfile) {
      svgEl
        .append("g")
        .attr("transform", "translate(" + MARGIN.LEFT + ", " + MARGIN.TOP + ")")
        .call(d3.axisLeft(yScale).tickValues([0, maxYValue/2, maxYValue]));
    }

    const gChart = svgEl.append("g");
    gChart
      .selectAll(".bar")
      .data(data)
      .enter()
      .append("rect")
      .classed("bar", true)
      .attr("width", xScale.bandwidth() - 1)
      .attr("height", (d) => CHART_HEIGHT - yScale(d.axisY))
      .attr("x", (d) => xScale(d.axisX))
      .attr("y", (d) => yScale(d.axisY) + MARGIN.TOP)
      .attr("fill", color[index]);

    return svgEl._groups[0][0].outerHTML;
  }

  function generateDoubleHistogramChart(currentWidth, histogramData, overlappedHistogramData) {
    let yFormat,
        xFormat;

    const sizes = new GenerateChartParams(230, currentWidth, histogramData)
    let {
      MARGIN,
      SVG_WIDTH,
      SVG_HEIGHT,
      CHART_WIDTH,
      CHART_HEIGHT,
      svgEl,
      xScale,
      yScale
    } = sizes

    svgEl = d3.create("svg")
    .attr("preserveAspectRatio", "xMinYMin meet")
    .attr("viewBox", "0 0 600 400")
    .classed("svg-content-responsive", true)

    const xAxis = d3.axisBottom(xScale).ticks(SVG_WIDTH / 80, xFormat).tickSizeOuter(0);
    const yAxis = d3.axisLeft(yScale).ticks(CHART_HEIGHT / 40, yFormat);
    yFormat = yScale.tickFormat(100, yFormat);

    svgEl.append("g")
      .attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`)
      .call(yAxis)
      .call(g => g.select(".domain").remove())
      .call(g => g.selectAll(".tick line")
          .attr("x2", CHART_WIDTH)
          .attr("stroke-opacity", 0.1))
      .call(g => g.append("text")
          .attr("x", -MARGIN.LEFT)
          .attr("y", 10)
          .attr("fill", "currentColor")
          .attr("text-anchor", "start"));

          svgEl.append("g").append("g")
        .attr("transform", `translate(0,${SVG_HEIGHT - MARGIN.BOTTOM})`)
        .call(xAxis)
        .call(g => g.select(".domain").remove())
        .call(g => g.selectAll(".tick line").remove())
        .call(g => g.append("text")
            .attr("x", SVG_WIDTH - MARGIN.RIGHT)
            .attr("y", 27)
            .attr("fill", "currentColor")
            .attr("text-anchor", "end"));

      const gChart = svgEl.append("g");
      gChart
      .selectAll(".bar")
      .data(histogramData)
      .enter()
      .append("rect")
      .classed("bar", true)
      .attr("width", xScale.bandwidth())
      .attr("height", (d) => CHART_HEIGHT - yScale(d.axisY))
      .attr("x", (d) => xScale(d.axisX))
      .attr("y", (d) => yScale(d.axisY) + MARGIN.TOP)
      .attr("fill", "#369BAC")
      .style("opacity","0.6");

      const gChart1 = svgEl.append("g");
      gChart1
        .selectAll(".bar")
        .data(overlappedHistogramData)
        .enter()
        .append("rect")
        .classed("bar", true)
        .attr("width", xScale.bandwidth())
        .attr("height", (d) => CHART_HEIGHT - yScale(d.axisY))
        .attr("x", (d) => xScale(d.axisX))
        .attr("y", (d) => yScale(d.axisY) + MARGIN.TOP)
        .attr("fill", "#2683C9")
        .style("opacity", "0.6");

    return svgEl._groups[0][0].outerHTML;
  }

  function generateBarChart(currentWidth, histogramData, overlappedHistogramData) {
    let yFormat,
        xFormat;
    const data = histogramData.map((profile, index) => {
      return {
        group: index,
        profile: profile.axisY,
        reference_profile: overlappedHistogramData[index].axisY
      }
    }).slice(0, 20)

    const sizes = new GenerateChartParams(230, currentWidth, histogramData, undefined, 1)
    let {
      MARGIN,
      SVG_WIDTH,
      SVG_HEIGHT,
      CHART_WIDTH,
      CHART_HEIGHT,
      svgEl,
      xScale,
      yScale
    } = sizes

    svgEl = d3.create("svg")
    .attr("preserveAspectRatio", "xMinYMin meet")
    .attr("viewBox", "0 0 600 400")
    .classed("svg-content-responsive", true)

    const subgroups = ['profile', 'reference_profile']

    xScale.padding([0.3])

    const xAxis = d3.axisBottom(xScale).ticks(SVG_WIDTH / 80, xFormat).tickSizeOuter(0);
    const yAxis = d3.axisLeft(yScale).ticks(SVG_HEIGHT / 40, yFormat);
    yFormat = yScale.tickFormat(100, yFormat);

    svgEl.append("g")
      .attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`)
      .call(yAxis)
      .call(g => g.select(".domain").remove())
      .call(g => g.selectAll(".tick line")
          .attr("x2", CHART_WIDTH)
          .attr("stroke-opacity", 0.1))
      .call(g => g.append("text")
          .attr("x", -MARGIN.LEFT)
          .attr("y", 10)
          .attr("fill", "currentColor")
          .attr("text-anchor", "start"));

    svgEl.append("g")
        .attr("transform", `translate(0,${SVG_HEIGHT - MARGIN.BOTTOM})`)
        .call(xAxis)
        .call(g => g.select(".domain").remove())
        .call(g => g.selectAll(".tick line").remove())
        .call(g => g.append("text")
            .attr("x", SVG_WIDTH - MARGIN.RIGHT)
            .attr("y", 27)
            .attr("fill", "currentColor")
            .attr("text-anchor", "end"));
    // Another scale for subgroup position?
    const xSubgroup = d3.scaleBand()
      .domain(subgroups)
      .range([0, xScale.bandwidth()])

    // color palette = one color per subgroup
    const color = d3.scaleOrdinal()
      .domain(subgroups)
      .range(['#369BAC', '#2683C9'])

    svgEl.append("g")
       .selectAll("g")
       // Enter in data = loop group per group
       .data(data)
       .enter()
       .append("g")
         .attr("transform", function(d) { return "translate(" + xScale(d.group) + ",0)"; })
       .selectAll("rect")
       .data(function(d) { return subgroups.map(function(key) { return {key: key, value: d[key]}; }); })
       .enter().append("rect")
         .attr("x", function(d) { return xSubgroup(d.key); })
         .attr("y", function(d) { return yScale(d.value); })
         .attr("width", xSubgroup.bandwidth())
         .attr("height", function(d) { return (CHART_HEIGHT - yScale(d.value)); })
         .attr("fill", function(d) { return color(d.key); })
         .style("opacity", "0.6");


     return svgEl._groups[0][0].outerHTML;
  }

  function generatePositiveNegativeChart(currentWidth, histogramData, overlappedHistogramData) {
    const data = histogramData.map((value, index) => {
      const difference = value.axisY - overlappedHistogramData[index].axisY
      const negativeValues = difference < 0 ? difference : 0
      return [+value.axisY, negativeValues]
    }).flat().slice(0, 20)

    let yFormat,
        xFormat;

    const sizes = new GenerateChartParams(230, currentWidth, histogramData, undefined, 1)
    let {
     MARGIN,
     SVG_WIDTH,
     SVG_HEIGHT,
     CHART_WIDTH,
     CHART_HEIGHT,
     svgEl
    } = sizes

    svgEl = d3.create("svg")
    .attr("preserveAspectRatio", "xMinYMin meet")
    .attr("viewBox", "0 0 600 400")
    .classed("svg-content-responsive", true)

    const y0 = Math.max(Math.abs(d3.min(data)), Math.abs(d3.max(data)));

    const yScale = d3.scaleLinear()
        .domain([-y0 * 1.02, y0 * 1.02])
        .range([CHART_HEIGHT,0])

    const xScale = d3.scaleBand()
        .domain(d3.range(data.length)) // so that chart's height has 102% height of the maximum value
        .rangeRound([MARGIN.LEFT, SVG_WIDTH])
        .padding([0.1]);

    const xAxis = d3.axisBottom(xScale).ticks(SVG_WIDTH / 80, xFormat).tickSizeOuter(0);
    const yAxis = d3.axisLeft(yScale).ticks(CHART_HEIGHT / 40, yFormat);
    yFormat = yScale.tickFormat(100, yFormat);

      svgEl.append("g")
      .attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`)
      .call(yAxis)
      .call(g => g.select(".domain").remove())
      .call(g => g.selectAll(".tick line")
      .attr("x2", CHART_WIDTH )
      .attr("stroke-opacity", 0.1))
      .call(g => g.append("text")
      .attr("x", - MARGIN.LEFT)
      .attr("y", 10)
      .attr("fill", "currentColor")
      .attr("text-anchor", "start"));

      svgEl
      .append("g")
      .attr("transform", `translate(0,${SVG_HEIGHT - MARGIN.BOTTOM})`)
      .call(xAxis)
      .call(g => g.select(".domain").remove())
      .call(g => g.selectAll(".tick>line").remove())
      .call(g => g.append("text")
          .attr("x", SVG_WIDTH - MARGIN.RIGHT)
          .attr("y", 27)
          .attr("fill", "currentColor")
          .attr("text-anchor", "end"));

    svgEl.selectAll(".bar")
        .data(data)
      .enter().append("rect")
        .attr("class", function(d) { return d < 0 ? "bar negative" : "bar positive"; })
        .attr("y", function(d) { return yScale(Math.max(0, d)); })
        .attr("x", function(d, i) { return xScale(i); })
        .attr("height", function(d) { return Math.abs(yScale(d) - yScale(0)); })
        .attr("width", xScale.bandwidth());

        return svgEl._groups[0][0].outerHTML;
  }

  function numericalDriftChart(getDoubleHistogramChart) {
    let colorsForDistingushingChartHTMLElement = '';

    colorsForDistingushingChartHTMLElement +=`
      <p>Data Distribution Chart</p>
      <div class="display-flex">
        ${colorsForDistingushingCharts("#369BAC", "Current")}
        ${colorsForDistingushingCharts("#2683C9", "Reference")}
      </div>
    `
    $(".clickable-test-feature-body").html(`
      ${chartBoxElement(colorsForDistingushingChartHTMLElement, getDoubleHistogramChart)}
    `);
  }

  function categoricalDriftChart(getBarChart, getPositiveNegative) {
    $(".clickable-test-feature-body").html(`
      ${chartBoxElement('<p>Bar Chart</p>', getBarChart)}
      ${chartBoxElement('<p>Difference Bar Chart</p>', getPositiveNegative)}
    `);
  }

  function sortWithIndeces(toSort) {
    for (let i = 0; i < toSort.length; i++) {
      toSort[i] = [toSort[i], i];
    }
    toSort.sort((left, right) => {
      return  right[0] < left[0] ? -1 : 1;
    });
    toSort.sortIndices = [];
    for (let j = 0; j < toSort.length; j++) {
      toSort.sortIndices.push(toSort[j][1]);
      toSort[j] = toSort[j][0];
    }
    return toSort;
  }

  const getProfileCharts = (key, getDoubleHistogramChart, getBarChart, getPositiveNegative) => {
    if (jsonData.columns[key].numberSummary.isDiscrete) {
      $("#page-button").text("Categorical Data")
      categoricalDriftChart(getBarChart, getPositiveNegative)
    } else {
      $("#page-button").text("Numerical Data")
      numericalDriftChart(getDoubleHistogramChart)
    }
  }

  function openReferencePropertyPanel(referenceItems, items, profileItems, key, chart, getDoubleHistogramChart, getBarChart, getPositiveNegative) {
    const chartInfoItem = (drift, driftName) => `
      <div class="info">
          <div>${drift}</div>
          <p>${driftName}</p>
     </div>
    `
    const $clickableTestFeatureWrap = $(".clickable-test-feature-wrap");
    const $pagesButtons = $(".page-button");
    const $pagesButton = $pagesButtons[0];
    let chipString = "",
        frequentItemString = "",
        referenceFrequentItemString = "";

    $pagesButtons.removeClass("activ-pages-button")
    $($pagesButton).addClass("activ-pages-button")
    $tableContent.addClass("d-none")
    $clickableTestFeatureWrap.removeClass("d-none")

    // frequentItemString += `${items.forEach((item) => {chipElementTableData(item.value)})}`
    const sortedItems = items.map((item) => +Object.values(item)[0])
    // .sort((a,b) => +b.value - (+a.value))
    sortWithIndeces(sortedItems).sortIndices.forEach(
      (item) => {
        frequentItemString += `
          ${frequentItemBoxElement('',chipElementTableData(items[item].value))}
        `
        referenceFrequentItemString += `
          ${frequentItemBoxElement('',chipElementTableData(referenceItems[item].value))}
        `
      }
    );

    $("#page-button").on("click", function () {
      getProfileCharts(
        key,
        getDoubleHistogramChart,
        getBarChart,
        getPositiveNegative
      )
      $(".clickable-test-feature-body").removeClass("d-none");
      $(".frequent-items-body").html(``);
      referenceProfilePanelHeight()
    })

    getProfileCharts(
      key,
      getDoubleHistogramChart,
      getBarChart,
      getPositiveNegative
    )
    $(".clickable-test-feature-body").removeClass("d-none");
    $(".frequent-items-body").html(``);

    $("#frequent-item-button").on("click", function () {
      $(".frequent-items-body").html(`
      <div class="display-flex">
        <div class="fequent-items-wrap">
          <div class="chart-box-title frequent-item-box-to-title display-flex">
            items
          </div>
          ${frequentItemString}
        </div>
        <div class="fequent-items-wrap">
          <div class="chart-box-title frequent-item-box-to-title display-flex">
            reference profile items
          </div>
          ${referenceFrequentItemString}
        </div>
      </div>
    `);

    $(".clickable-test-feature-body").addClass("d-none");

    referenceProfilePanelHeight()
    })


    $("#chart").html(chart);

    chipString += `
      ${chartInfoItem(profileItems.numberSummary.count.toString(), "Total Count")}
      ${chartInfoItem(fixNumberTo(profileItems.numberSummary.mean), "Mean")}
    `
    $(".chart-info").html(chipString);
    referenceProfilePanelHeight()
  }

  function openProfilePropertyPanel(items, infType, chart) {
    $("#wl-property-panel__chart").html(chart);
    let chipString = "";
    const chipElementEstimation = (count) =>
      `<td class="wl-property-panel__table-td wl-property-panel__table-td-profile" >${count}</td>`;
    items.forEach((item) => {
      chipString += `
    <tr class="wl-property-panel__table-tr">
      ${chipElementTableData(item.value)}
      ${chipElementEstimation(item.count)}
    </tr>
    `;
    });
    $(".wl-property-panel__frequent-items").html(chipString);
    if (infType === "non-discrete") {
      $propertyPanelTitle.html("Histogram data:");
      $propertyPanelProfileName.html("Bin values");
    } else if (infType === "discrete") {
      $propertyPanelTitle.html("Frequent items:");
      $propertyPanelProfileName.html("Counts");
    }

    $(".wl-property-panel").addClass("wl-property-panel--open");
    $(".wl-table-wrap").addClass("wl-table-wrap--narrow");
  }

  function openPropertyPanel(referenceItems, items, infType, feature) {
    let getGraph = null,
        getPropertyPanelGraph = null,
        getDoubleHistogramChart,
        getBarChart,
        getPositiveNegative,
        currentWidth = 600,
        propertyPanelGraph = true;


    if (referencePropertyPanelData[feature[0]][0]) {
      getDoubleHistogramChart = generateDoubleHistogramChart(currentWidth, feature[1].chartData[0], feature[1].chartData[1])
      getBarChart = generateBarChart(currentWidth, feature[1].chartData[0], feature[1].chartData[1])
      getPositiveNegative = generatePositiveNegativeChart(currentWidth, feature[1].chartData[0], feature[1].chartData[1])
      items = referencePropertyPanelData[feature[0]][0]
      getGraph = getGraphHtml(feature[1].chartData[1], 50, 280, 0, true, propertyPanelGraph)
    }

    getPropertyPanelGraph = getPropertyPanelGraphHtml(jsonData.columns[feature[0]], feature[0])

    if (jsonData) {
      if (items.length > 0 && items !== "undefined") {
        if (referencePropertyPanelData[feature[0]][0]) {
          openReferencePropertyPanel(
            referenceItems,
            items,
            referenceJsonData.columns[feature[0]],
            feature[0],
            getGraph,
            getDoubleHistogramChart,
            getBarChart,
            getPositiveNegative
          )
        } else {
          openProfilePropertyPanel(items, infType, getPropertyPanelGraph)
        }
      } else {

      }
    }
  }

  function handleClosePropertyPanel() {
    $(".wl-property-panel").removeClass("wl-property-panel--open");
    $(".wl-table-wrap").removeClass("wl-table-wrap--narrow");
    $(".wl-property-panel__frequent-items").html("");
  }

  function getPropertyPanelGraphHtml (column) {
    let chartString = "";
    const freqData = [];
    const histData = [];

    const freqChart = (chart) =>
      `<div class="wl-property-panel__chart--single"><div class="wl-property-panel__chart-title">Frequent Items Data</div>${chart}</div>`;
    const histChart = (chart) =>
      `<div class="wl-property-panel__chart--single"><div class="wl-property-panel__chart-title">Histogram Data</div>${chart}</div>`;

    if (column.numberSummary) {
      if (column.frequentItems && column.frequentItems.items) {
        column.frequentItems.items.forEach((item, index) => {
          freqData.push({
            axisY: item.estimate,
            axisX: index,
          });
        });
      }

      if (column.numberSummary.histogram && column.numberSummary.histogram.counts) {
        column.numberSummary.histogram.counts.slice(0, 30).forEach((count, index) => {
          histData.push({
            axisY: count,
            axisX: index,
          });
        });
      }
      if (column.numberSummary.isDiscrete) {
        if (freqData.length > 0) chartString += freqChart(getGraphHtml(freqData, 130));
        if (histData.length > 0) chartString += histChart(getGraphHtml(histData, 130));
      } else {
        if (histData.length > 0) chartString += histChart(getGraphHtml(histData, 130));
        if (freqData.length > 0) chartString += freqChart(getGraphHtml(freqData, 130));
      }
    }
    return chartString;
  }

  function sidebarContentHeight() {
    const $sidebarContentPadding = +$("#sidebar-content-single-profile").css("padding").replace('px','') * 2
    const $sidebarContentHeight = $("#sidebar-content-single-profile").height() + $sidebarContentPadding
    const $sidebar = $(".sidebar")

    $sidebar.css("margin-bottom", `${$sidebarContentHeight}px`)
  }

  function checkCurrentProfile(item, referenceItem) {
    if (referenceJsonData && Object.values(referenceJsonData)) {
      return referenceItem
    } else {
      return item
    }
  }

  // Override and populate HTML element values
  function updateHtmlElementValues() {
    $notifCircleContainer.addClass("d-none")
    $dropdownArrowIcon.css("transform","rotate(180deg)")
    $filterOptions.removeClass("d-none");

    checkCurrentProfile(true, false) ?
    $("#dif-from-ref").addClass("d-none"):
    $("#dif-from-ref").removeClass("d-none")

    sidebarContentHeight()
    $sidebarFeatureNameList.html("");
    $tableMessage.addClass("d-none");
    Object.entries(featureDataForTableForAllProfiles).forEach((feature) => {
      // strings for tableToShow
      let tempChartDataString = "";
      let referenceTempChartDataString = "";
      feature[1].chartData.forEach((chartData, index) => {
        if (selectedProfiles.includes(String(index))) {
          tempChartDataString += `<div>${
            chartData.length > 0
              ? getGraphHtml(feature[1].chartData[0])
              : '<span class="wl-table-cell__bedge-wrap">No data to show the chart</span>'
          }</div>`;
          if (feature[1].chartData[1] && feature[1].chartData[1].length > 0) {
            referenceTempChartDataString+= `<div>${
              chartData.length > 0
                ? getGraphHtml(feature[1].chartData[1], ...[,,], 1, true)
                : '<span class="wl-table-cell__bedge-wrap">No data to show the chart</span>'
            }</div>`;
          }
        }
      });

      let diffFromRef = "";
      feature[1].frequentItemsElemString.forEach((frequentItemElemString, index) => {
        if (selectedProfiles.includes(String(index))) {
          diffFromRef += ` <div class="wl-table-cell__bedge-wrap">${Math.floor(Math.random() * 10)}</div>`;
        }
      });

      let freaquentItemsElmString = "";
      feature[1].frequentItemsElemString.forEach((frequentItemElemString, index) => {
        if (selectedProfiles.includes(String(index))) {
          freaquentItemsElmString += ` <div class="wl-table-cell__bedge-wrap text-align-center">${frequentItemElemString}</div>`;
        }
      });
      let inferredTypeString = "";
      feature[1].inferredType.forEach((inferredType, index) => {
        if (selectedProfiles.includes(String(index))) {
          inferredType ? (inferredTypeString += `<div>${inferredType}</div>`) : (inferredTypeString += `<div>-</div>`);
        }
      });
      let totalCountString = "";
      feature[1].totalCount.forEach((totalCount, index) => {
        if (selectedProfiles.includes(String(index))) {
          totalCount ? (totalCountString += `<div>${totalCount}</div>`) : (totalCountString += `<div>-</div>`);
        }
      });
      let nullRationString = "";
      feature[1].nullRatio.forEach((nullRatio, index) => {
        if (selectedProfiles.includes(String(index))) {
          nullRatio ? (nullRationString += `<div> ${nullRatio}</div>`) : (nullRationString += `<div>-</div>`);
        }
      });
      let estUniqueValString = "";
      feature[1].estUniqueVal.map((estUniqueVal, index) => {
        if (selectedProfiles.includes(String(index))) {
          estUniqueVal ? (estUniqueValString += `<div>${estUniqueVal}</div>`) : (estUniqueValString += `<div>$-</div>`);
        }
      });
      let meanString = "";
      feature[1].mean.forEach((mean, index) => {
        if (selectedProfiles.includes(String(index))) {
          mean ? (meanString += `<div>${mean}</div>`) : (meanString += `<div>-</div>`);
        }
      });
      let stddevString = "";
      feature[1].stddev.forEach((stddev, index) => {
        if (selectedProfiles.includes(String(index))) {
          stddev ? (stddevString += `<div>${stddev}</div>`) : (stddevString += `<div>-</div>`);
        }
      });
      let dataTypeString = "";
      feature[1].dataType.forEach((dataType, index) => {
        if (selectedProfiles.includes(String(index))) {
          dataType ? (dataTypeString += `<div>${dataType}</div>`) : (dataTypeString += `<div>-</div>`);
        }
      });
      let dataTypeCountString = "";
      feature[1].dataTypeCount.forEach((dataTypeCount, index) => {
        if (selectedProfiles.includes(String(index))) {
          dataTypeCount
            ? (dataTypeCountString += `<div>${dataTypeCount}</div>`)
            : (dataTypeCountString += `<div>-</div>`);
        }
      });
      let quantilesMinString = "";
      feature[1].quantiles.forEach((quantiles, index) => {
        if (selectedProfiles.includes(String(index))) {
          quantiles.min
            ? (quantilesMinString += `<div>${quantiles.min}</div>`)
            : (quantilesMinString += `<div>-</div>`);
        }
      });
      let quantilesMedianString = "";
      feature[1].quantiles.forEach((quantiles, index) => {
        if (selectedProfiles.includes(String(index))) {
          quantiles.median
            ? (quantilesMedianString += `<div>${quantiles.median}</div>`)
            : (quantilesMedianString += `<div>-</div>`);
        }
      });
      let quantilesThirdQuantileString = "";
      feature[1].quantiles.forEach((quentiles, index) => {
        if (selectedProfiles.includes(String(index))) {
          quentiles.thirdQuantile
            ? (quantilesThirdQuantileString += `<div>${quentiles.thirdQuantile}</div>`)
            : (quantilesThirdQuantileString += `<div>-</div>`);
        }
      });
      let quantilesMaxString = "";
      feature[1].quantiles.forEach((quantiles, index) => {
        if (selectedProfiles.includes(String(index))) {
          quantiles.max
            ? (quantilesMaxString += `<div>${quantiles.max}</div>`)
            : (quantilesMaxString += `<div>-</div>`);
        }
      });
      let quantilesFirsString = "";
      feature[1].quantiles.forEach((quantiles, index) => {
        if (selectedProfiles.includes(String(index))) {
          quantiles.firstQuantile
            ? (quantilesFirsString += `<div>${quantiles.firstQuantile}</div>`)
            : (quantilesFirsString += `<div>-</div>`);
        }
      });

      const showButton = selectedProfiles.some(
        (profile) => profile !== null && feature[1].inferredType[profile].toLowerCase() !== "unknown",
      );

      const $tableRow = $(
        `
      <li class="wl-table-row${showButton ? " wl-table-row--clickable" : ""}" data-feature-name="${
          feature[0]
        }" data-inferred-type="${
          feature[1].inferredType[parseInt(selectedProfiles[0] || "0")]
        }" data-scroll-to-feature-name="${feature[0]}" style="display: none;">
        <div class="wl-table-cell">
          <div class="wl-table-cell__title-wrap">
            <h4 class="wl-table-cell__title">${feature[0]}</h4>
          </div>
          <div class="wl-table-cell__graph-wrap">
            <div class="display-flex">` +
            tempChartDataString +
            referenceTempChartDataString +
            `</div>
          </div></div>
          <div class="wl-table-cell wl-table-cell--top-spacing align-middle ${checkCurrentProfile(`d-none`, ``)}" style="max-width: 270px; padding-right: 18px">` +
          checkCurrentProfile(``, diffFromRef) +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle">` +
          freaquentItemsElmString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle">` +
          inferredTypeString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle text-end">` +
          totalCountString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle text-end">` +
          nullRationString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle text-end">` +
          estUniqueValString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle">` +
          dataTypeString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle">` +
          dataTypeCountString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle text-end">` +
          meanString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle text-end">` +
          stddevString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle text-end">` +
          quantilesMinString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle text-end">` +
          quantilesFirsString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle text-end">` +
          quantilesMedianString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle text-end">` +
          quantilesThirdQuantileString +
          `</div><div class="wl-table-cell wl-table-cell--top-spacing align-middle text-end">` +
          quantilesMaxString +
          `</div></li>`,
      );

      if (jsonData) {
        const $tableRowButton = $(`<button class="wl-table-cell__title-button" type="button">View details</button>`);
        $tableRowButton.on(
          "click",
          openPropertyPanel.bind(
            this,
            referencePropertyPanelData[feature[0]][0],
            propertyPanelData[feature[0]][0],
            feature[1].inferredType[0].toLowerCase(),
            feature
          ),
        );
        $tableRow.find(".wl-table-cell__title-wrap").append($tableRowButton);
      }
      // Update data table rows/columns
      $tableBody.append($tableRow);

      $sidebarFeatureNameList.append(
        `
          <li id="filter-list-item" class="wl_filter-list-item list-group-item js-list-group-item" data-feature-name="${feature[0]}" data-inferred-type="${feature[1].inferredType}">
            <div class="arrow-icon-container">
              <div class="wl_list-item-dot"></div>
              <img
                class="d-none wl_arrow-icon"
                src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iMTMiIHZpZXdCb3g9IjAgMCAxMiAxMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggb3BhY2l0eT0iMC44IiBkPSJNNiAwLjY4NzVDMi43ODkwNiAwLjY4NzUgMC4xODc1IDMuMjg5MDYgMC4xODc1IDYuNUMwLjE4NzUgOS43MTA5NCAyLjc4OTA2IDEyLjMxMjUgNiAxMi4zMTI1QzkuMjEwOTQgMTIuMzEyNSAxMS44MTI1IDkuNzEwOTQgMTEuODEyNSA2LjVDMTEuODEyNSAzLjI4OTA2IDkuMjEwOTQgMC42ODc1IDYgMC42ODc1Wk01LjMyMDMxIDQuMDYyNUM1LjA4NTk0IDMuODUxNTYgNS4wODU5NCAzLjQ3NjU2IDUuMjk2ODggMy4yNjU2Mkw1LjU1NDY5IDMuMDA3ODFDNS43ODkwNiAyLjc3MzQ0IDYuMTQwNjIgMi43NzM0NCA2LjM1MTU2IDMuMDA3ODFMOS40Njg3NSA2LjEyNUM5LjY3OTY5IDYuMzM1OTQgOS42Nzk2OSA2LjY4NzUgOS40Njg3NSA2Ljg5ODQ0TDYuMzUxNTYgMTAuMDE1NkM2LjE0MDYyIDEwLjIyNjYgNS43ODkwNiAxMC4yMjY2IDUuNTU0NjkgMTAuMDE1Nkw1LjI5Njg4IDkuNzU3ODFDNS4wODU5NCA5LjU0Njg4IDUuMDg1OTQgOS4xNzE4OCA1LjMyMDMxIDguOTYwOTRMNy4wNzgxMiA3LjI1SDIuODEyNUMyLjQ4NDM4IDcuMjUgMi4yNSA3LjAxNTYyIDIuMjUgNi42ODc1VjYuMzEyNUMyLjI1IDYuMDA3ODEgMi40ODQzOCA1Ljc1IDIuODEyNSA1Ljc1SDcuMDc4MTJMNS4zMjAzMSA0LjA2MjVaIiBmaWxsPSIjMEU3Mzg0Ii8+Cjwvc3ZnPgo="
              />
            </div>
            <span data-feature-name-id="${feature[0]}" >${feature[0]}</span>
          </li>
        `,
      );
    });

    if (jsonData) {
      const countDiscrete = Object.values(numOfProfilesBasedOnType).reduce(
        (acc, feature) => (acc += feature.discrete.length),
        0,
      );
      const countNonDiscrete = Object.values(numOfProfilesBasedOnType).reduce(
        (acc, feature) => (acc += feature.nonDiscrete.length),
        0,
      );
      const countUnknown = Object.values(numOfProfilesBasedOnType).reduce(
        (acc, feature) => (acc += feature.unknown.length),
        0,
      );

      $featureCountDiscrete.html(countDiscrete);
      $featureCountNonDiscrete.html(countNonDiscrete);
      $featureCountUnknown.html(countUnknown);
      $selectedProfile.html(formatLabelDate(+dataForRead.properties[0].dataTimestamp));
      if (checkCurrentProfile(false, true) && dataForRead.properties[1]) {
        $selectedReferenceProfile.html(formatLabelDate(+dataForRead.properties[1].dataTimestamp))
      }
    }
  }

  function renderList() {
    const tableBodyChildrens = $tableBody.children();
    const featureListChildren = $sidebarFeatureNameList.children();
    let featureCount = 0;
    $.each($featureFilterInput, (_, filterInput) => {
      isActiveInferredType[filterInput.value.toLowerCase()] = filterInput.checked;
    });

    for (let i = 0; i < tableBodyChildrens.length; i++) {
      const type = tableBodyChildrens[i].dataset.inferredType.toLowerCase();

      if (isActiveInferredType[type]) {
        tableBodyChildrens[i].style.display = "";
        featureCount++;
      }
    }
    for (let i = 0; i < featureListChildren.length; i++) {
      const type = featureListChildren[i].dataset.inferredType.toLowerCase();

      if (isActiveInferredType[type]) {
        featureListChildren[i].style.display = "";
      }
    }
    $featureCount.html(featureCount);
  }

  function getDataForRead(dataForRead, jsonData, referneceData) {
    if (!dataForRead.properties) {
      dataForRead.properties = [];
    }
    dataForRead.properties.push(jsonData.properties);

    Object.entries(jsonData.columns).forEach((feature) => {
      let tempFeatureName = feature[0];
      if (!dataForRead.columns) {
        dataForRead.columns = [];
      }
      if (!dataForRead.columns[tempFeatureName]) dataForRead.columns[tempFeatureName] = [];
        dataForRead.columns[tempFeatureName].push(feature[1]);
          if (
            referneceData &&
            referneceData.columns[tempFeatureName].numberSummary
          ) {
            dataForRead.properties.push(referenceJsonData.properties)
            const {
              numberSummary,
              frequentItems,
              ...referenceDataForRead
            } = dataForRead.columns[tempFeatureName][0]
            dataForRead.columns[tempFeatureName].push({
              ...referenceDataForRead,
              referenceNumberSummary: referneceData.columns[tempFeatureName].numberSummary,
              referenceFrequentItems: referneceData.columns[tempFeatureName].frequentItems
            })
          }
    });
    return dataForRead
  }

  function mapProfileDataToReadData(jsonData, dataForRead, referneceData) {
    try {
      dataForRead = getDataForRead(dataForRead, jsonData, referneceData)
    } catch (e) {
      alert("You selected wrong reference profile. Please select again.")
      removeReferenceProfile()
    }
    makeFeatureDataForAllProfilesToShowOnTable(
      featureDataForTableForAllProfiles,
      dataForRead,
      numOfProfilesBasedOnType,
    );
  }


  function makeFeatureDataForAllProfilesToShowOnTable(
    featureDataForTableForAllProfiles,
    dataForRead,
    numOfProfilesBasedOnType,
  ) {
    if (Object.keys(featureDataForTableForAllProfiles).length !== 0) {
      featureDataForTableForAllProfiles = {};
    }
    if (Object.keys(numOfProfilesBasedOnType).length !== 0) {
      numOfProfilesBasedOnType = {};
    }
    Object.entries(dataForRead.columns).map((feature) => {
      if (!featureDataForTableForAllProfiles[feature[0]]) {
        featureDataForTableForAllProfiles[feature[0]] = {
          totalCount: [],
          inferredType: [],
          nullRatio: [],
          estUniqueVal: [],
          dataType: [],
          dataTypeCount: [],
          quantiles: [],
          mean: [],
          stddev: [],
          chartData: [],
          refereneChartData: [],
          frequentItemsElemString: [],
        };
        numOfProfilesBasedOnType[feature[0]] = {
          discrete: [],
          nonDiscrete: [],
          unknown: [],
        };
        propertyPanelData[feature[0]] = [];
        referencePropertyPanelData[feature[0]] = [];
      }
      let iteration = 0;
      feature[1].forEach((tempFeatureValues) => {
        if (tempFeatureValues.numberSummary) {
          let inffTypeTemp = tempFeatureValues.numberSummary.isDiscrete ? "Discrete" : "Non-Discrete";
          tempFeatureValues.numberSummary.isDiscrete
            ? numOfProfilesBasedOnType[feature[0]].discrete.push(feature[0])
            : numOfProfilesBasedOnType[feature[0]].nonDiscrete.push(feature[0]);
          featureDataForTableForAllProfiles[feature[0]].totalCount.push(tempFeatureValues.numberSummary.count);
          featureDataForTableForAllProfiles[feature[0]].inferredType.push(inffTypeTemp);
          featureDataForTableForAllProfiles[feature[0]].quantiles.push(
            getQuantileValues(tempFeatureValues.numberSummary.quantiles.quantileValues),
          );
          featureDataForTableForAllProfiles[feature[0]].mean.push(fixNumberTo(tempFeatureValues.numberSummary.mean));
          featureDataForTableForAllProfiles[feature[0]].stddev.push(
            fixNumberTo(tempFeatureValues.numberSummary.stddev),
          );
        } else {
          numOfProfilesBasedOnType[feature[0]].unknown.push(feature[0]);
          featureDataForTableForAllProfiles[feature[0]].inferredType.push("Unknown");
          featureDataForTableForAllProfiles[feature[0]].totalCount.push("-");
          let quantiles = {
            min: "-",
            firstQuantile: "-",
            median: "-",
            thirdQuantile: "-",
            max: "-",
          };
          featureDataForTableForAllProfiles[feature[0]].quantiles.push(quantiles);
          featureDataForTableForAllProfiles[feature[0]].mean.push("-");
          featureDataForTableForAllProfiles[feature[0]].stddev.push("-");
        }
        featureDataForTableForAllProfiles[feature[0]].estUniqueVal.push(
          feature[1].uniqueCount ? fixNumberTo(tempFeatureValues.uniqueCount.estimate) : "-",
        );
        featureDataForTableForAllProfiles[feature[0]].nullRatio.push(
          tempFeatureValues.schema.typeCounts.NULL ? tempFeatureValues.schema.typeCounts.NULL : "0",
        );
        featureDataForTableForAllProfiles[feature[0]].dataType.push(tempFeatureValues.schema.inferredType.type);
        featureDataForTableForAllProfiles[feature[0]].dataTypeCount.push(
          tempFeatureValues.schema.typeCounts[featureDataForTableForAllProfiles[feature[0]].dataType],
        );

        featureDataForTableForAllProfiles[feature[0]].chartData[iteration] = [];
        featureDataForTableForAllProfiles[feature[0]].frequentItemsElemString[iteration] = "";
        if (
          featureDataForTableForAllProfiles[feature[0]].inferredType[iteration] === "Discrete" &&
          tempFeatureValues.frequentItems &&
          tempFeatureValues.frequentItems.items.length
        ) {
          // Chart
          tempFeatureValues.frequentItems.items.forEach((item, index) => {
            featureDataForTableForAllProfiles[feature[0]].chartData[iteration].push({
              axisY: item.estimate,
              axisX: index,
            });
          });
          if (tempFeatureValues.referenceFrequentItems) {
            tempFeatureValues.referenceFrequentItems.items.forEach((item, index) => {
              featureDataForTableForAllProfiles[feature[0]].chartData[1].push({
                axisY: item.estimate,
                axisX: index,
              });
            });
          }

          // Frequent item chips / bedge
          propertyPanelData[feature[0]][iteration] = tempFeatureValues.frequentItems.items.reduce((acc, item) => {
            acc.push({
              value: item.jsonValue,
              count: item.estimate,
            });
            return acc;
          }, []);

          const slicedFrequentItems = tempFeatureValues.frequentItems.items.slice(0, 5);
          for (let fi = 0; fi < slicedFrequentItems.length; fi++) {
            featureDataForTableForAllProfiles[feature[0]].frequentItemsElemString[iteration] +=
              '<span class="wl-table-cell__bedge">' + slicedFrequentItems[fi].jsonValue + "</span>";
          }
        } else {
          if (featureDataForTableForAllProfiles[feature[0]].inferredType[iteration] === "Non-Discrete") {
            // Chart
            if (tempFeatureValues.numberSummary) {
              // Histogram chips / bedge
              propertyPanelData[feature[0]][0] = tempFeatureValues.numberSummary.histogram.counts.reduce(
                (acc, value, index) => {
                  acc.push({
                    value: value,
                    count: tempFeatureValues.numberSummary.histogram.bins[index],
                  });
                  return acc;
                },
                [],
              );

              tempFeatureValues.numberSummary.histogram.counts.slice(0, 30).forEach((count, index) => {
                featureDataForTableForAllProfiles[feature[0]].chartData[0].push({
                  axisY: count,
                  axisX: index,
                });
              });
            }

            // Frequent item chips / bedge
            featureDataForTableForAllProfiles[feature[0]].frequentItemsElemString[iteration] = "No data to show";
          } else {
            featureDataForTableForAllProfiles[feature[0]].frequentItemsElemString[iteration] = "No data to show";
            featureDataForTableForAllProfiles[feature[0]].chartData[iteration] = [];
            propertyPanelData[feature[0]] = [];
          }
          if (tempFeatureValues.referenceNumberSummary) {
            referencePropertyPanelData[feature[0]][0] = tempFeatureValues.referenceNumberSummary.histogram.counts.reduce(
              (acc, value, index) => {
                acc.push({
                  value: value,
                  count: tempFeatureValues.referenceNumberSummary.histogram.bins[index],
                });
                return acc;
              },
              [],
            );

            tempFeatureValues.referenceNumberSummary.histogram.counts.slice(0, 30).forEach((count, index) => {
              featureDataForTableForAllProfiles[feature[0]].chartData[1].push({
                axisY: count,
                axisX: index,
              });
            });
          }
        }
        if(tempFeatureValues.referenceFrequentItems &&
           featureDataForTableForAllProfiles[feature[0]].inferredType[0] === "Discrete"
        ){
               featureDataForTableForAllProfiles[feature[0]].chartData[1] = []
               tempFeatureValues.referenceFrequentItems.items.forEach((item, index) => {
                 featureDataForTableForAllProfiles[feature[0]].chartData[1].push({
                   axisY: item.estimate,
                   axisX: index,
                 });
               });
           }
        iteration += 1;
      });
    });
    $featureCount.html(Object.values(featureDataForTableForAllProfiles).length);
  }

  function updateTableMessage(message) {
    $tableMessage.find("p").html(message);
  }

  function compareArrays(array, target) {
    if (array.length !== target.length) return false;

    array.sort();
    target.sort();

    for (let i = 0; i < array.length; i++) {
      if (array[i] !== target[i]) {
        return false;
      }
    }
    return true;
  }

  function checkJSONValidityForSingleProfile(data) {
    const VALID_KEY_NAMES = ["properties", "columns"];
    const keys = Object.keys(data);

    return keys.length === 2 && compareArrays(VALID_KEY_NAMES, keys);
  }

  function hasFalseValue(array) {
    return array.some((obj) => checkJSONValidityForSingleProfile(obj) === false);
  }

  function checkJSONValidityForMultiProfile(data) {
    const values = Object.values(data);

    if (!values && !values.length) return false;
    if (hasFalseValue(values)) return false;

    return true;
  }

  function showDataVisibility() {
    $tableMessage.addClass("d-none");
    $sidebarContent.removeClass("d-none");
    $tableContent.removeClass("d-none");
  }

  function hideDataVisibility() {
    $tableMessage.removeClass("d-none");
    $sidebarContent.addClass("d-none");
    $tableContent.addClass("d-none");
    $compareProfile.removeClass("d-none");
  }

  function addFileName() {
    const fileName = $fileInput.val().split('\\').pop();
    if (fileName) {
      $featureFileName.html(fileName.split('.json'))
    }
  }

  function removeReferenceProfile() {
    referenceJsonData = undefined
    dataForRead = {};
    featureDataForTableForAllProfiles = {};
    numOfProfilesBasedOnType = {};

    $(".reference-table-head").addClass("d-none")

    mapProfileDataToReadData(jsonData, dataForRead, referenceJsonData);
    $tableBody.html("");
    updateHtmlElementValues();
    renderList();
    $(".wl-selected-profile").addClass("d-none")
    $(".wl-compare-profile").removeClass("d-none")
  }

  function loadFile(inputId, jsonForm) {
    isActiveInferredType = {};
    $featureFilterInput.html("");
    $sidebarFeatureNameList.html("");
    $tableBody.html("");
    $(".form-check-input").prop("checked", true);
    addFileName()
    if (typeof window.FileReader !== "function") {
      updateTableMessage(MESSAGES.error.fileAPINotSupported);
      return;
    }
    dataForRead = {};
    featureDataForTableForAllProfiles = {};
    numOfProfilesBasedOnType = {};

    handleClosePropertyPanel();
    const input = document.getElementById(inputId);
    if (!input) {
      updateTableMessage(MESSAGES.error.noInputElementFound);
    } else if (!input.files) {
      updateTableMessage(MESSAGES.error.noBrowserSupport);
    } else if (!input.files[0]) {
      updateTableMessage(MESSAGES.error.noFileSelected);
    } else {
      const file = input.files[0];
      const fr = new FileReader();
      fr.onload = (e) => receivedText(e, jsonForm, inputId);
      fr.readAsText(file);
    }
  }

  function receivedText(e, jsonForm, inputId) {
    const lines = e.target.result;
    let data = JSON.parse(lines);
    if (inputId === "file-input") {
      if (checkJSONValidityForMultiProfile(data)) {
        jsonData = Object.values(data)[0]
      } else {
        jsonData = data;
      }
      removeReferenceProfile()
      $(".reference-table-head").addClass("d-none")
      $(".wl-selected-profile").addClass("d-none")
      $compareProfile.removeClass("d-none");
    } else {
      if (checkJSONValidityForMultiProfile(data)) {
        referenceJsonData = Object.values(data)[0]
      } else {
        referenceJsonData = data;
      }
      $(".reference-table-head").removeClass("d-none")
      $(".wl-selected-profile").removeClass("d-none")
      $(".wl-compare-profile").addClass("d-none")
    }
    mapProfileDataToReadData(jsonData, dataForRead, referenceJsonData);
    if (data) {
      $(".compare-select").addClass("d-none");
      $multiProfileWrap.removeClass("d-none");
      selectedProfiles[0] = "0";
      $tableBody.html("");
      updateHtmlElementValues();
      renderList();
      showDataVisibility();
      jsonForm.trigger("reset");
    } else {
      $tableBody.html("");
      updateTableMessage(MESSAGES.error.invalidJSONFile);
      hideDataVisibility();
      return;
    }
  }

  function checkedBoxes() {
    const item = Object.values($boxes).find(
      function(value) {
        return $('#' + $(value)[0].id).is(":checked")
      }
    );

    if (item) {
      $notifCircleContainer.removeClass("d-none")
    }
  }

  $removeReferenceProfileButton.on("click", removeReferenceProfile)

  $(document).on("click", ".page-button", function(e) {
    const $pagesButtons = $(".page-button"),
      $pagesButtonIndex = $pagesButtons.index(e.target),
      $pagesButton = $(".page-button")[$pagesButtonIndex]

    $pagesButtons.removeClass("activ-pages-button")
    $($pagesButton).addClass("activ-pages-button")
  })

  $(window).ready(function() {
    sidebarContentHeight()
  })

  $("#property-panel-close-icon").on("click", function (e) {
    const $clickableTestFeatureWrap = $(".clickable-test-feature-wrap")

    $tableContent.removeClass("d-none")
    $clickableTestFeatureWrap.addClass("d-none")
  });

  $dropdownArrowIcon.on("click", function () {
    const filterClass = $filterOptions.attr("class");

    if (filterClass.indexOf("d-none") > 0) {
      $notifCircleContainer.addClass("d-none")
      $filterOptions.removeClass("d-none");
      $("#dropdown-container").css("background-color", '#FFF')
      $dropdownArrowIcon.css("transform","rotate(180deg)")
    } else {
      $filterOptions.addClass("d-none");
      checkedBoxes()
      $("#dropdown-container").css("background-color", 'none')
      $dropdownArrowIcon.css("transform","rotate(0)")
    }
  });

  $closeIcon.on("click", function () {
    $signUpText.addClass("d-none");
    sidebarContentHeight()
    $(".open-sign-up-text-notif-container").removeClass("d-none")
  });

  $openSignUpText.on("click", function () {
    $signUpText.removeClass("d-none");
    sidebarContentHeight()
    $(".open-sign-up-text-notif-container").addClass("d-none")
  });


  $(document).on("click", ".js-list-group-item span", function (e) {
    const listItem = $("li>span"),
      listItemIndex = listItem.index(e.target),
      $listItemDot = $(".wl_list-item-dot")[listItemIndex],
      $arrowIcon = $(".wl_arrow-icon")[listItemIndex]

    listItem.css("padding-left", "15px")
    $(".wl_list-item-dot").removeClass("d-none")
    $(".wl_arrow-icon").addClass("d-none")
    $($arrowIcon).removeClass("d-none")
    $($listItemDot).addClass("d-none")
    $(listItem[listItemIndex]).css("padding-left", "8px")
  });

  // Bind event listeners
  $fileInput.on("change", () => loadFile("file-input", $jsonForm));
  $referencefileInput.on("change", () => loadFile("reference-file-input", $referenceJsonForm));

  $(document).on("click", ".js-list-group-item span", scrollToFeatureName);
  $featureSearch.on(
    "input",
    debounce((event) => {
      featureSearchValue = event.target.value.toLowerCase();
      handleSearch();
    }, 300),
  );
  $featureFilterInput.on("change", (event) => {
    const filterType = event.target.value.toLowerCase();
    const isChecked = event.target.checked;

    isActiveInferredType[filterType] = isChecked;
    handleSearch();
  });
  $(".wl-property-panel__button").on("click", handleClosePropertyPanel);
})();