| | <!DOCTYPE html> |
| | <html> |
| | <head> |
| | <meta charset="UTF-8" /> |
| | <title>ARC‐Converted Dataset Visualizer (Upload Local Folder)</title> |
| | <style> |
| | body { |
| | font-family: sans-serif; |
| | margin: 16px; |
| | } |
| | .selector-area { |
| | margin-bottom: 1rem; |
| | } |
| | .grid-canvas { |
| | margin: 4px; |
| | border: 1px solid #ccc; |
| | } |
| | .example-container { |
| | display: inline-block; |
| | margin: 0 16px 16px 0; |
| | vertical-align: top; |
| | } |
| | .puzzle-display { |
| | margin-top: 1rem; |
| | } |
| | .puzzle-id { |
| | font-weight: bold; |
| | margin-bottom: 0.5rem; |
| | } |
| | #groupList, #puzzleList { |
| | margin: 1rem 0; |
| | } |
| | .group-item, .puzzle-item { |
| | cursor: pointer; |
| | margin: 4px 8px 4px 0; |
| | padding: 2px 6px; |
| | border: 1px solid #aaa; |
| | display: inline-block; |
| | } |
| | .group-item:hover, .puzzle-item:hover { |
| | background: #eef; |
| | } |
| | </style> |
| | </head> |
| | <body> |
| | <h1>ARC‐Converted Dataset Visualizer (Local Directory)</h1> |
| |
|
| | <div class="selector-area"> |
| | |
| | <label>Upload ARC Folder:</label> |
| | <input type="file" id="folderInput" |
| | webkitdirectory mozdirectory multiple |
| | onchange="onFolderSelected(event)" /> |
| | <br><br> |
| |
|
| | |
| | <label>Set:</label> |
| | <select id="setSelect" disabled> |
| | <option value="train">train</option> |
| | <option value="test">test</option> |
| | </select> |
| |
|
| | <label> Subset:</label> |
| | <select id="subsetSelect" disabled> |
| | <option value="all">all</option> |
| | </select> |
| |
|
| | <button id="loadBtn" disabled>Load</button> |
| | </div> |
| |
|
| | <div> |
| | <div id="groupList"></div> |
| | <div id="puzzleList"></div> |
| | <div class="puzzle-display" id="puzzleView"></div> |
| | </div> |
| |
|
| | |
| | |
| | |
| | |
| | |
| | <script src="assets/npyjs.js"></script> |
| |
|
| | <script> |
| | |
| | |
| | |
| | |
| | |
| | let filesByPath = {}; |
| | |
| | |
| | let inputsArr, labelsArr; |
| | let puzzleIndicesArr, groupIndicesArr, puzzleIdentifiersArr; |
| | let identifiersJson; |
| | |
| | |
| | let seqLen = 0; |
| | let gridSize = 0; |
| | |
| | |
| | |
| | |
| | |
| | |
| | function onFolderSelected(event) { |
| | filesByPath = {}; |
| | const fileList = event.target.files; |
| | if (!fileList || fileList.length === 0) { |
| | alert("No files selected!"); |
| | return; |
| | } |
| | |
| | |
| | const paths = []; |
| | for (let i = 0; i < fileList.length; i++) { |
| | |
| | const file = fileList[i]; |
| | const relPath = file.webkitRelativePath || file.mozRelativePath || file.name; |
| | paths.push(relPath); |
| | } |
| | |
| | |
| | const idPath = paths.find(p => p.endsWith("identifiers.json")); |
| | if (!idPath) { |
| | alert("Error: No 'identifiers.json' found in the uploaded folder."); |
| | return; |
| | } |
| | |
| | |
| | |
| | |
| | let topDir = ""; |
| | const lastSlash = idPath.lastIndexOf("/"); |
| | if (lastSlash >= 0) { |
| | topDir = idPath.substring(0, lastSlash); |
| | } |
| | |
| | |
| | |
| | |
| | for (let i = 0; i < fileList.length; i++) { |
| | const file = fileList[i]; |
| | let relPath = file.webkitRelativePath || file.mozRelativePath || file.name; |
| | |
| | if (topDir && relPath.startsWith(topDir + "/")) { |
| | relPath = relPath.substring(topDir.length + 1); |
| | } |
| | filesByPath[relPath] = file; |
| | } |
| | |
| | |
| | document.getElementById("setSelect").disabled = false; |
| | document.getElementById("subsetSelect").disabled = false; |
| | document.getElementById("loadBtn").disabled = false; |
| | } |
| | |
| | |
| | document.getElementById("loadBtn").addEventListener("click", async () => { |
| | document.getElementById("groupList").innerHTML = ""; |
| | document.getElementById("puzzleList").innerHTML = ""; |
| | document.getElementById("puzzleView").innerHTML = ""; |
| | |
| | const setName = document.getElementById("setSelect").value; |
| | const subsetName = document.getElementById("subsetSelect").value; |
| | |
| | try { |
| | await loadDataset(setName, subsetName); |
| | buildGroupList(); |
| | } catch (err) { |
| | console.error(err); |
| | alert("Error while loading dataset: " + err); |
| | } |
| | }); |
| | |
| | |
| | |
| | |
| | |
| | async function loadDataset(setName, subsetName) { |
| | const prefix = `${setName}/${subsetName}__`; |
| | |
| | const inputsPath = prefix + "inputs.npy"; |
| | const labelsPath = prefix + "labels.npy"; |
| | const pIdxPath = prefix + "puzzle_indices.npy"; |
| | const gIdxPath = prefix + "group_indices.npy"; |
| | const pIdsPath = prefix + "puzzle_identifiers.npy"; |
| | const identifiersPath = "identifiers.json"; |
| | |
| | |
| | const needed = [inputsPath, labelsPath, pIdxPath, gIdxPath, pIdsPath, identifiersPath]; |
| | for (const f of needed) { |
| | if (!filesByPath[f]) { |
| | throw new Error(`Missing file: ${f}`); |
| | } |
| | } |
| | |
| | |
| | const inputsNpy = await parseNpy(filesByPath[inputsPath]); |
| | const labelsNpy = await parseNpy(filesByPath[labelsPath]); |
| | const puzzleIndicesNpy= await parseNpy(filesByPath[pIdxPath]); |
| | const groupIndicesNpy = await parseNpy(filesByPath[gIdxPath]); |
| | const puzzleIdsNpy = await parseNpy(filesByPath[pIdsPath]); |
| | |
| | inputsArr = inputsNpy.data; |
| | labelsArr = labelsNpy.data; |
| | puzzleIndicesArr = puzzleIndicesNpy.data; |
| | groupIndicesArr = groupIndicesNpy.data; |
| | puzzleIdentifiersArr = puzzleIdsNpy.data; |
| | |
| | |
| | seqLen = inputsNpy.shape[1]; |
| | gridSize = Math.sqrt(seqLen); |
| | |
| | |
| | identifiersJson = await readJsonFile(filesByPath[identifiersPath]); |
| | } |
| | |
| | |
| | |
| | |
| | function parseNpy(file) { |
| | return new Promise((resolve, reject) => { |
| | const reader = new FileReader(); |
| | reader.onload = async () => { |
| | try { |
| | const arrayBuffer = reader.result; |
| | const npy = new npyjs(); |
| | resolve(await npy.parse(arrayBuffer)); |
| | } catch (err) { |
| | reject(err); |
| | } |
| | }; |
| | reader.onerror = err => reject(err); |
| | reader.readAsArrayBuffer(file); |
| | }); |
| | } |
| | |
| | |
| | |
| | |
| | function readJsonFile(file) { |
| | return new Promise((resolve, reject) => { |
| | const reader = new FileReader(); |
| | reader.onload = () => { |
| | try { |
| | const obj = JSON.parse(reader.result); |
| | resolve(obj); |
| | } catch (err) { |
| | reject(err); |
| | } |
| | }; |
| | reader.onerror = (err) => reject(err); |
| | reader.readAsText(file); |
| | }); |
| | } |
| | |
| | |
| | |
| | |
| | function buildGroupList() { |
| | document.getElementById("groupList").innerHTML = "<h3>Groups</h3>"; |
| | const groupListDiv = document.getElementById("groupList"); |
| | |
| | const nGroups = groupIndicesArr.length - 1; |
| | for (let g = 0; g < nGroups; g++) { |
| | const div = document.createElement("span"); |
| | div.className = "group-item"; |
| | div.textContent = `Group ${g}`; |
| | div.onclick = () => onSelectGroup(g); |
| | groupListDiv.appendChild(div); |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | function onSelectGroup(groupIndex) { |
| | document.getElementById("puzzleList").innerHTML = ""; |
| | document.getElementById("puzzleView").innerHTML = ""; |
| | |
| | const puzzleListDiv = document.getElementById("puzzleList"); |
| | puzzleListDiv.innerHTML = `<h4>Puzzles in Group ${groupIndex}</h4>`; |
| | |
| | const firstPuzzle = groupIndicesArr[groupIndex]; |
| | const lastPuzzle = groupIndicesArr[groupIndex + 1]; |
| | |
| | for (let p = firstPuzzle; p < lastPuzzle; p++) { |
| | const puzzleIntId = puzzleIdentifiersArr[p]; |
| | const puzzleStrId = (puzzleIntId < identifiersJson.length) |
| | ? identifiersJson[puzzleIntId] |
| | : "<unknown>"; |
| | |
| | const div = document.createElement("span"); |
| | div.className = "puzzle-item"; |
| | div.textContent = `Puzzle #${p} [ID=${puzzleIntId}: ${puzzleStrId}]`; |
| | div.onclick = () => onSelectPuzzle(p); |
| | puzzleListDiv.appendChild(div); |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | function onSelectPuzzle(puzzleIndex) { |
| | const puzzleView = document.getElementById("puzzleView"); |
| | puzzleView.innerHTML = ""; |
| | |
| | |
| | const puzzleIntId = puzzleIdentifiersArr[puzzleIndex]; |
| | const puzzleStrId = (puzzleIntId < identifiersJson.length) |
| | ? identifiersJson[puzzleIntId] |
| | : "<unknown>"; |
| | |
| | const titleDiv = document.createElement("div"); |
| | titleDiv.className = "puzzle-id"; |
| | titleDiv.textContent = `Puzzle #${puzzleIndex} — ID: ${puzzleStrId}`; |
| | puzzleView.appendChild(titleDiv); |
| | |
| | |
| | const firstExample = puzzleIndicesArr[puzzleIndex]; |
| | const lastExample = puzzleIndicesArr[puzzleIndex + 1]; |
| | |
| | for (let e = firstExample; e < lastExample; e++) { |
| | const inputSeq = slice1D(inputsArr, e*seqLen, (e+1)*seqLen); |
| | const outputSeq = slice1D(labelsArr, e*seqLen, (e+1)*seqLen); |
| | |
| | const inputGrid = decodeGrid(inputSeq); |
| | const outputGrid = decodeGrid(outputSeq); |
| | |
| | const exDiv = document.createElement("div"); |
| | exDiv.className = "example-container"; |
| | exDiv.appendChild(document.createTextNode(`Example ${e}`)); |
| | exDiv.appendChild(document.createElement("br")); |
| | |
| | exDiv.appendChild(renderGrid(inputGrid)); |
| | exDiv.appendChild(renderGrid(outputGrid)); |
| | |
| | puzzleView.appendChild(exDiv); |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | function slice1D(arr, start, end) { |
| | const result = new Uint32Array(end - start); |
| | for (let i = start; i < end; i++) { |
| | result[i - start] = Number(arr[i]); |
| | } |
| | return result; |
| | } |
| | |
| | |
| | |
| | |
| | function decodeGrid(seq) { |
| | const grid = []; |
| | let idx = 0; |
| | for (let r = 0; r < gridSize; r++) { |
| | const row = []; |
| | for (let c = 0; c < gridSize; c++) { |
| | row.push(seq[idx]); |
| | idx++; |
| | } |
| | grid.push(row); |
| | } |
| | return grid; |
| | } |
| | |
| | |
| | |
| | |
| | function renderGrid(grid2d) { |
| | const rows = grid2d.length; |
| | const cols = grid2d[0].length; |
| | const scale = 10; |
| | |
| | const canvas = document.createElement("canvas"); |
| | canvas.width = cols * scale; |
| | canvas.height = rows * scale; |
| | canvas.className = "grid-canvas"; |
| | const ctx = canvas.getContext("2d"); |
| | |
| | for (let r = 0; r < rows; r++) { |
| | for (let c = 0; c < cols; c++) { |
| | const val = grid2d[r][c]; |
| | ctx.fillStyle = indexToColor(val); |
| | ctx.fillRect(c * scale, r * scale, scale, scale); |
| | } |
| | } |
| | return canvas; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | function indexToColor(value) { |
| | if (value === 0) return "#FFFFFF"; |
| | if (value === 1) return "#DDDDDD"; |
| | |
| | |
| | const colorIdx = value - 2; |
| | const palette = [ |
| | "#000000", |
| | "#FF0000", |
| | "#00FF00", |
| | "#0000FF", |
| | "#FFFF00", |
| | "#FFA500", |
| | "#800080", |
| | "#00FFFF", |
| | "#FFC0CB", |
| | "#808080" |
| | ]; |
| | if (colorIdx >= 0 && colorIdx < palette.length) { |
| | return palette[colorIdx]; |
| | } |
| | return "#FFFFFF"; |
| | } |
| | </script> |
| | </body> |
| | </html> |
| |
|