diff --git a/app/src/components/data/FeatureTable.js b/app/src/components/data/FeatureTable.js
index bac4ef4..fe65d0a 100644
--- a/app/src/components/data/FeatureTable.js
+++ b/app/src/components/data/FeatureTable.js
@@ -1,6 +1,6 @@
import { useEffect, React } from "react";
import Box from "@mui/material/Box";
-import { DataGrid } from "@mui/x-data-grid";
+import { DataGrid as MuiDataGrid } from "@mui/x-data-grid";
import { Card, CardContent, Typography } from "@mui/material";
import styled from "@emotion/styled";
@@ -12,11 +12,125 @@ const CellContent = styled.span`
`;
const ChartBox = styled.div`
- width: 400px;
- height: 100px;
+ width: 200px;
+ height: 50px;
`;
-function StackedBarChart({ data, chartId }) {
+const DataGrid = styled(MuiDataGrid)`
+ & .MuiDataGrid-row > .MuiDataGrid-cell {
+ overflow: visible !important;
+ }
+`;
+
+// External tooltip handler
+// See https://www.chartjs.org/docs/latest/samples/tooltip/html.html
+const getOrCreateTooltip = (chart) => {
+ let tooltipEl = chart.canvas.parentNode.querySelector("div");
+
+ if (!tooltipEl) {
+ tooltipEl = document.createElement("div");
+ tooltipEl.style.background = "rgba(0, 0, 0, 0.7)";
+ tooltipEl.style.borderRadius = "3px";
+ tooltipEl.style.color = "white";
+ tooltipEl.style.opacity = 1;
+ tooltipEl.style.pointerEvents = "none";
+ tooltipEl.style.position = "absolute";
+ tooltipEl.style.transform = "translate(-50%, 0)";
+ tooltipEl.style.transition = "all .1s ease";
+
+ const table = document.createElement("table");
+ table.style.margin = "0px";
+
+ tooltipEl.appendChild(table);
+ chart.canvas.parentNode.appendChild(tooltipEl);
+ }
+
+ return tooltipEl;
+};
+
+const externalTooltipHandler = (context) => {
+ // Tooltip Element
+ const { chart, tooltip } = context;
+ const tooltipEl = getOrCreateTooltip(chart);
+
+ // Hide if no tooltip
+ if (tooltip.opacity === 0) {
+ tooltipEl.style.opacity = 0;
+ return;
+ }
+
+ // Set Text
+ if (tooltip.body) {
+ const titleLines = tooltip.title || [];
+ const bodyLines = tooltip.body.map((b) => b.lines);
+
+ const tableHead = document.createElement("thead");
+
+ titleLines.forEach((title) => {
+ const tr = document.createElement("tr");
+ tr.style.borderWidth = 0;
+
+ const th = document.createElement("th");
+ th.style.borderWidth = 0;
+ const text = document.createTextNode(title);
+
+ th.appendChild(text);
+ tr.appendChild(th);
+ tableHead.appendChild(tr);
+ });
+
+ const tableBody = document.createElement("tbody");
+ bodyLines.forEach((body, i) => {
+ const colors = tooltip.labelColors[i];
+
+ const span = document.createElement("span");
+ span.style.background = colors.backgroundColor;
+ span.style.borderColor = colors.borderColor;
+ span.style.borderWidth = "2px";
+ span.style.marginRight = "10px";
+ span.style.height = "10px";
+ span.style.width = "10px";
+ span.style.display = "inline-block";
+
+ const tr = document.createElement("tr");
+ tr.style.backgroundColor = "inherit";
+ tr.style.borderWidth = 0;
+
+ const td = document.createElement("td");
+ td.style.borderWidth = 0;
+
+ const text = document.createTextNode(body);
+
+ td.appendChild(span);
+ td.appendChild(text);
+ tr.appendChild(td);
+ tableBody.appendChild(tr);
+ });
+
+ const tableRoot = tooltipEl.querySelector("table");
+
+ // Remove old children
+ while (tableRoot.firstChild) {
+ tableRoot.firstChild.remove();
+ }
+
+ // Add new children
+ tableRoot.appendChild(tableHead);
+ tableRoot.appendChild(tableBody);
+ }
+
+ const { offsetLeft: positionX, offsetTop: positionY } = chart.canvas;
+
+ // Display, position, and set styles for font
+ tooltipEl.style.opacity = 1;
+ tooltipEl.style.left = positionX + tooltip.caretX + "px";
+ tooltipEl.style.top = positionY + tooltip.caretY + "px";
+ tooltipEl.style.font = tooltip.options.bodyFont.string;
+ tooltipEl.style.padding =
+ tooltip.options.padding + "px " + tooltip.options.padding + "px";
+};
+
+function StackedBarChart({ data, chartId, showX, targets }) {
useEffect(() => {
if (!data) {
return;
@@ -33,7 +147,7 @@ function StackedBarChart({ data, chartId }) {
);
const datasets = transposedData.map((data, index) => ({
- label: `Class ${index + 1}`,
+ label: targets[index],
data: data,
borderWidth: 1,
}));
@@ -48,6 +162,7 @@ function StackedBarChart({ data, chartId }) {
scales: {
x: {
stacked: true,
+ display: showX,
},
y: {
stacked: true,
@@ -58,6 +173,11 @@ function StackedBarChart({ data, chartId }) {
legend: {
display: false,
},
+ tooltip: {
+ enabled: false,
+ position: "nearest",
+ external: externalTooltipHandler,
+ },
},
responsive: true,
maintainAspectRatio: false,
@@ -69,62 +189,18 @@ function StackedBarChart({ data, chartId }) {
};
}, [data]);
- return ;
+ return ;
}
-const columns = [
- { field: "id", headerName: "Index", type: "number", width: 90 },
- {
- field: "name",
- headerName: "Feature Name",
- width: 200,
- editable: true,
- valueGetter: (params) =>
- `${params.row.name} ${params.row.target === "1" ? "(target)" : ""}`,
- renderCell: (params) => {
- const isBold = params.row.target === "1";
- return {params.value};
- },
- },
- {
- field: "type",
- headerName: "Type",
- width: 100,
- editable: true,
- },
- {
- field: "distinct",
- headerName: "Distinct values",
- type: "number",
- width: 110,
- editable: true,
- },
- {
- field: "missing",
- headerName: "Missing values",
- type: "number",
- width: 110,
- editable: true,
- },
- {
- field: "distr",
- headerName: "Distribution",
- width: 400,
- renderCell: (params) => {
- const chartId = `chart-${params.row.id}`; // Assuming each row has a unique 'id'
- return (
-
-
-
- );
- },
- },
-];
-
const FeatureTable = ({ data }) => {
+ // Check for targets
+ let targets = [];
// Define the rows for the grid
const rows = data.map((feature) => {
const id = feature.index; // Rename index to id
+ if (feature.target === "1") {
+ targets = feature.distr[0];
+ }
return {
id,
...Object.keys(feature).reduce((acc, key) => {
@@ -134,6 +210,60 @@ const FeatureTable = ({ data }) => {
};
});
+ const columns = [
+ { field: "id", headerName: "Index", type: "number", width: 90 },
+ {
+ field: "name",
+ headerName: "Feature Name",
+ width: 200,
+ editable: true,
+ valueGetter: (params) =>
+ `${params.row.name} ${params.row.target === "1" ? "(target)" : ""}`,
+ renderCell: (params) => {
+ const isBold = params.row.target === "1";
+ return {params.value};
+ },
+ },
+ {
+ field: "type",
+ headerName: "Type",
+ width: 100,
+ editable: true,
+ },
+ {
+ field: "distinct",
+ headerName: "Distinct values",
+ type: "number",
+ width: 110,
+ editable: true,
+ },
+ {
+ field: "missing",
+ headerName: "Missing values",
+ type: "number",
+ width: 110,
+ editable: true,
+ },
+ {
+ field: "distr",
+ headerName: "Distribution",
+ width: 200,
+ renderCell: (params) => {
+ const chartId = `chart-${params.row.id}`; // Assuming each row has a unique 'id'
+ return (
+
+
+
+ );
+ },
+ },
+ ];
+
return (
@@ -145,7 +275,6 @@ const FeatureTable = ({ data }) => {
rows={rows}
columns={columns}
getRowId={(row) => row.index}
- getRowHeight={(row) => 100}
sortModel={[
{
field: "id",