| <!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> |
|
|