Skip to content

Instantly share code, notes, and snippets.

@georgwiese
Created November 3, 2023 13:01
Show Gist options
  • Save georgwiese/af06566dd187533b16cd90b590492bfd to your computer and use it in GitHub Desktop.
Save georgwiese/af06566dd187533b16cd90b590492bfd to your computer and use it in GitHub Desktop.
Mostly ChatGPT-written CSV viewer that works well for Powdr-exported execution traces
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSV Viewer</title>
<style>
.headerCell {
position: sticky;
top: 0;
background-color: white;
cursor: pointer;
}
.highlight {
background-color: lightgrey;
}
.monospace {
font-family: 'Courier New', monospace;
}
</style>
</head>
<body>
<input type="file" id="fileInput" />
<table id="dataTable" border="1"></table>
<script>
document.getElementById('fileInput').addEventListener('change', function (e) {
let file = e.target.files[0];
if (file) {
let reader = new FileReader();
reader.readAsText(file, 'UTF-8');
reader.onload = function (evt) {
parseCSV(evt.target.result);
}
}
});
function parseCSV(data) {
let rows = data.split('\n');
let table = document.getElementById('dataTable');
table.innerHTML = ''; // Clear the table
let headers = rows[0].split(',');
let sortedHeaders = headers.slice().sort((a, b) => {
let aPrefix = a.split('.').slice(0, -1).join('.');
let bPrefix = b.split('.').slice(0, -1).join('.');
return aPrefix.localeCompare(bPrefix);
});
let headerRow = table.insertRow();
sortedHeaders.forEach((header) => {
let cell = headerRow.insertCell();
let parts = header.split('.');
cell.innerHTML = parts.map((part, index) => `<span data-namespace="${parts.slice(0, index + 1).join('.')}">${part}</span>`).join('<br/>');
cell.className = 'headerCell monospace';
let spans = cell.querySelectorAll("span");
spans.forEach(span => {
span.addEventListener('click', function () {
toggleNamespaceVisibility(span.dataset.namespace);
});
});
});
for (let i = 1; i < rows.length; i++) {
let tableRow = table.insertRow();
// Split the row into cells and store it.
let rowData = rows[i].split(',');
// Create an array of indices [0, 1, 2, ..., n] and sort it according to the headers' order.
let sortedIndices = rowData
.map((_, index) => index) // Create an array of indices
.sort((a, b) => {
// Use the indices to get the headers and then sort
let aHeader = headers[a];
let bHeader = headers[b];
return sortedHeaders.indexOf(aHeader) - sortedHeaders.indexOf(bHeader);
});
// Use the sorted indices to append cells in the correct order
sortedIndices.forEach(cellIndex => {
let cellData = rowData[cellIndex];
let cell = tableRow.insertCell();
cell.innerHTML = cellData;
cell.className = 'monospace';
if (cellData !== '0x0') {
cell.classList.add('highlight');
}
});
}
}
function toggleNamespaceVisibility(namespace) {
console.log(`toggleNamespaceVisibility: ${namespace}`);
let table = document.getElementById('dataTable');
let isAnyColumnHidden = false;
let num_columns = 0;
// 1. Determine if any column in the target namespace is currently visible.
Array.from(table.rows[0].cells).forEach((cell, cellIndex) => {
let span = cell.querySelector(`span[data-namespace="${namespace}"]`);
if (span) {
num_columns++;
isAnyColumnHidden = isAnyColumnHidden || cell.style.display === 'none';
}
});
console.log(`isAnyColumnHidden: ${isAnyColumnHidden}`);
console.log(`num_columns: ${num_columns}`);
// Decide our display rule based on the visibility status
let shouldDisplay = isAnyColumnHidden ? '' : 'none';
let isFirstColumnInNamespace = true;
Array.from(table.rows).forEach((row, rowIndex) => {
Array.from(row.cells).forEach((cell, cellIndex) => {
let headerCell = table.rows[0].cells[cellIndex];
let span = headerCell.querySelector(`span[data-namespace="${namespace}"]`);
if (span) {
// For the header row
if (rowIndex === 0) {
cell.style.display = shouldDisplay;
// If we are about to hide this column and it's the first in the namespace
if (!isAnyColumnHidden && isFirstColumnInNamespace) {
isFirstColumnInNamespace = false;
cell.style.display = '';
}
}
// For data rows
else if (num_columns > 1) {
cell.style.display = shouldDisplay;
// If we are about to hide the columns and this is the first one, show '...'
if (!isAnyColumnHidden && isFirstColumnInNamespace) {
cell.setAttribute('data-original-header', cell.innerHTML);
cell.innerHTML = '...';
isFirstColumnInNamespace = false;
cell.style.display = '';
} else if (isAnyColumnHidden && cell.getAttribute('data-original-header')) {
// If expanding columns, restore the original header if there's one saved
cell.innerHTML = cell.getAttribute('data-original-header');
cell.removeAttribute('data-original-header');
}
}
}
});
isFirstColumnInNamespace = true; // Reset for the next row
});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment