forked from tangger/lerobot
[Visualization tool] Fix when dim state != dim action (#415)
This commit is contained in:
@@ -183,9 +183,9 @@
|
|||||||
</td>
|
</td>
|
||||||
<template x-for="(cell, colIndex) in row">
|
<template x-for="(cell, colIndex) in row">
|
||||||
<td x-show="cell" class="border border-slate-700">
|
<td x-show="cell" class="border border-slate-700">
|
||||||
<div class="flex gap-x-2 w-24 justify-between px-2">
|
<div class="flex gap-x-2 w-24 justify-between px-2" :class="{ 'hidden': cell.isNull }">
|
||||||
<input type="checkbox" x-model="cell.checked" @change="updateTableValues()">
|
<input type="checkbox" x-model="cell.checked" @change="updateTableValues()">
|
||||||
<span x-text="`${cell.value.toFixed(2)}`"
|
<span x-text="`${!cell.isNull ? cell.value.toFixed(2) : null}`"
|
||||||
:style="`color: ${cell.color}`"></span>
|
:style="`color: ${cell.color}`"></span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -207,7 +207,9 @@
|
|||||||
dygraph: null,
|
dygraph: null,
|
||||||
currentFrameData: null,
|
currentFrameData: null,
|
||||||
columnNames: ["state", "action", "pred action"],
|
columnNames: ["state", "action", "pred action"],
|
||||||
nColumns: {% if has_policy %}3{% else %}2{% endif %},
|
nColumns: 2,
|
||||||
|
nStates: 0,
|
||||||
|
nActions: 0,
|
||||||
checked: [],
|
checked: [],
|
||||||
dygraphTime: 0.0,
|
dygraphTime: 0.0,
|
||||||
dygraphIndex: 0,
|
dygraphIndex: 0,
|
||||||
@@ -243,17 +245,19 @@
|
|||||||
this.checked = Array(this.colors.length).fill(true);
|
this.checked = Array(this.colors.length).fill(true);
|
||||||
|
|
||||||
const seriesNames = this.dygraph.getLabels().slice(1);
|
const seriesNames = this.dygraph.getLabels().slice(1);
|
||||||
|
this.nStates = seriesNames.findIndex(item => item.startsWith('action_'));
|
||||||
|
this.nActions = seriesNames.length - this.nStates;
|
||||||
const colors = [];
|
const colors = [];
|
||||||
const LIGHTNESS = [30, 65, 85]; // state_lightness, action_lightness, pred_action_lightness
|
const LIGHTNESS = [30, 65, 85]; // state_lightness, action_lightness, pred_action_lightness
|
||||||
let lightnessIdx = 0;
|
// colors for "state" lines
|
||||||
const chunkSize = Math.ceil(seriesNames.length / this.nColumns);
|
for (let hue = 0; hue < 360; hue += parseInt(360/this.nStates)) {
|
||||||
for (let i = 0; i < seriesNames.length; i += chunkSize) {
|
const color = `hsl(${hue}, 100%, ${LIGHTNESS[0]}%)`;
|
||||||
const lightness = LIGHTNESS[lightnessIdx];
|
colors.push(color);
|
||||||
for (let hue = 0; hue < 360; hue += parseInt(360/chunkSize)) {
|
}
|
||||||
const color = `hsl(${hue}, 100%, ${lightness}%)`;
|
// colors for "action" lines
|
||||||
colors.push(color);
|
for (let hue = 0; hue < 360; hue += parseInt(360/this.nActions)) {
|
||||||
}
|
const color = `hsl(${hue}, 100%, ${LIGHTNESS[1]}%)`;
|
||||||
lightnessIdx += 1;
|
colors.push(color);
|
||||||
}
|
}
|
||||||
this.dygraph.updateOptions({ colors });
|
this.dygraph.updateOptions({ colors });
|
||||||
this.colors = colors;
|
this.colors = colors;
|
||||||
@@ -280,37 +284,40 @@
|
|||||||
if (!this.currentFrameData) {
|
if (!this.currentFrameData) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const columnSize = Math.ceil(this.currentFrameData.length / this.nColumns);
|
const rows = [];
|
||||||
return Array.from({
|
const nRows = Math.max(this.nStates, this.nActions);
|
||||||
length: columnSize
|
let rowIndex = 0;
|
||||||
}, (_, rowIndex) => {
|
while(rowIndex < nRows){
|
||||||
const row = [
|
const row = [];
|
||||||
this.currentFrameData[rowIndex] || null,
|
// number of states may NOT match number of actions. In this case, we null-pad the 2D array to make a fully rectangular 2d array
|
||||||
this.currentFrameData[rowIndex + columnSize] || null,
|
const nullCell = { isNull: true };
|
||||||
];
|
const stateValueIdx = rowIndex;
|
||||||
if (this.nColumns === 3) {
|
const actionValueIdx = stateValueIdx + this.nStates; // because this.currentFrameData = [state0, state1, ..., stateN, action0, action1, ..., actionN]
|
||||||
row.push(this.currentFrameData[rowIndex + 2 * columnSize] || null)
|
// row consists of [state value, action value]
|
||||||
}
|
row.push(rowIndex < this.nStates ? this.currentFrameData[stateValueIdx] : nullCell); // push "state value" to row
|
||||||
return row;
|
row.push(rowIndex < this.nActions ? this.currentFrameData[actionValueIdx] : nullCell); // push "action value" to row
|
||||||
});
|
rowIndex += 1;
|
||||||
|
rows.push(row);
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
},
|
},
|
||||||
isRowChecked(rowIndex) {
|
isRowChecked(rowIndex) {
|
||||||
return this.rows[rowIndex].every(cell => cell && cell.checked);
|
return this.rows[rowIndex].every(cell => cell && (cell.isNull || cell.checked));
|
||||||
},
|
},
|
||||||
isColumnChecked(colIndex) {
|
isColumnChecked(colIndex) {
|
||||||
return this.rows.every(row => row[colIndex] && row[colIndex].checked);
|
return this.rows.every(row => row[colIndex] && (row[colIndex].isNull || row[colIndex].checked));
|
||||||
},
|
},
|
||||||
toggleRow(rowIndex) {
|
toggleRow(rowIndex) {
|
||||||
const newState = !this.isRowChecked(rowIndex);
|
const newState = !this.isRowChecked(rowIndex);
|
||||||
this.rows[rowIndex].forEach(cell => {
|
this.rows[rowIndex].forEach(cell => {
|
||||||
if (cell) cell.checked = newState;
|
if (cell && !cell.isNull) cell.checked = newState;
|
||||||
});
|
});
|
||||||
this.updateTableValues();
|
this.updateTableValues();
|
||||||
},
|
},
|
||||||
toggleColumn(colIndex) {
|
toggleColumn(colIndex) {
|
||||||
const newState = !this.isColumnChecked(colIndex);
|
const newState = !this.isColumnChecked(colIndex);
|
||||||
this.rows.forEach(row => {
|
this.rows.forEach(row => {
|
||||||
if (row[colIndex]) row[colIndex].checked = newState;
|
if (row[colIndex] && !row[colIndex].isNull) row[colIndex].checked = newState;
|
||||||
});
|
});
|
||||||
this.updateTableValues();
|
this.updateTableValues();
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user