Skip to content
This repository was archived by the owner on Sep 10, 2026. It is now read-only.
Merged
61 changes: 61 additions & 0 deletions mixtape/core/static/mixtape/core/insights/actionsFrequency.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
document.addEventListener('alpine:init', () => {
Alpine.data('actionsFrequency', () => ({
data: [],
layout: {
title: {text: 'Actions VS Frequency'},
autosize: true,
barmode: Object.keys(Alpine.store('insights').actionVFrequency).length > 1 ? 'group' : 'stack',
showlegend: Alpine.store('settings').showPlotLegends,
paper_bgcolor: Alpine.store('theme').backgroundColor,
plot_bgcolor: Alpine.store('theme').backgroundColor,
font: {
color: Alpine.store('theme').fontColor
},
xaxis: {
gridcolor: Alpine.store('theme').gridColor,
linecolor: Alpine.store('theme').gridColor,
zeroline: false,
},
yaxis: {
gridcolor: Alpine.store('theme').gridColor,
linecolor: Alpine.store('theme').gridColor,
zeroline: false,
},
},
config: {
displayModeBar: false,
},
plot: null,
actionVFrequency: Object.keys(Alpine.store('insights').actionVFrequency).length > 1 ? Alpine.store('insights').actionVFrequency : Object.values(Alpine.store('insights').actionVFrequency)[0],
init() {
Object.entries(this.$store.insights.actionVFrequency).forEach(([grouping, values]) => {
this.data.push({
x: Object.keys(values),
y: Object.values(values),
type: 'bar',
name: grouping,
marker: {
line: {
width: 2
}
}
});
});
this.plot = Plotly.react(this.$el, this.data, this.layout, this.config);
this.$watch('$store.settings.showPlotLegends', () => {
this.$nextTick(() => {
Plotly.relayout(
this.$el,
{
autosize: true,
showlegend: this.$store.settings.showPlotLegends
})
});
});
},
resizePlot: _.debounce(function () {
if (!this.$el.querySelector('.plotly')) return;
Plotly.Plots.resize(this.$el);
}, 200, {leading: true}),
}));
});
60 changes: 60 additions & 0 deletions mixtape/core/static/mixtape/core/insights/actionsRewards.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
document.addEventListener('alpine:init', () => {
Alpine.data('actionsRewards', () => ({
data: [],
layout: {
title: {text: 'Actions VS Reward Frequency'},
xaxis: {
title: {text: 'Action'},
gridcolor: Alpine.store('theme').gridColor,
linecolor: Alpine.store('theme').gridColor,
zeroline: false,
},
yaxis: {
title: {text: 'Reward Frequency'},
gridcolor: Alpine.store('theme').gridColor,
linecolor: Alpine.store('theme').gridColor,
zeroline: false,
},
autosize: true,
barmode: Object.keys(Alpine.store('insights').actionVReward).length > 1 ? 'group' : 'stack',
showlegend: Alpine.store('settings').showPlotLegends,
paper_bgcolor: Alpine.store('theme').backgroundColor,
plot_bgcolor: Alpine.store('theme').backgroundColor,
font: {
color: Alpine.store('theme').fontColor
},
},
config: {
displayModeBar: false,
},
plot: null,
actionVReward: Object.keys(Alpine.store('insights').actionVReward).length > 1 ? Alpine.store('insights').actionVReward : Object.values(Alpine.store('insights').actionVReward)[0],
init() {
this.data = Object.entries(this.$store.insights.actionVReward).map(([grouping, values]) => ({
x: Object.keys(values),
y: Object.values(values),
type: 'bar',
name: grouping,
marker: {
line: {
width: 2
}
}
}));
this.plot = Plotly.react(this.$el, this.data, this.layout, this.config);
this.$watch('$store.settings.showPlotLegends', () => {
this.$nextTick(() => {
Plotly.relayout(
this.$el, {
autosize: true,
showlegend: this.$store.settings.showPlotLegends
})
});
});
},
resizePlot: _.debounce(function() {
if (!this.$el.querySelector('.plotly')) return;
Plotly.Plots.resize(this.$el);
}, 200, {leading: true}),
}));
});
177 changes: 177 additions & 0 deletions mixtape/core/static/mixtape/core/insights/clustering.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
document.addEventListener('alpine:init', () => {
Alpine.data('clustering', (key, title) => ({
data: [],
layout: {
title: {text: `Agent ${title}`},
height: 450,
xaxis: {
gridcolor: Alpine.store('theme').gridColor,
linecolor: Alpine.store('theme').gridColor,
zeroline: false,
},
yaxis: {
gridcolor: Alpine.store('theme').gridColor,
linecolor: Alpine.store('theme').gridColor,
zeroline: false,
},
paper_bgcolor: Alpine.store('theme').backgroundColor,
plot_bgcolor: Alpine.store('theme').backgroundColor,
font: {
color: Alpine.store('theme').fontColor
},
},
plot: null,
init() {
if (this.$store.insights.clustering && this.$store.insights.clustering[key]) {
this.buildPlot();
}
this.$watch(
() => this.$store.insights.clustering && this.$store.insights.clustering[key],
(v) => { if (v) { this.buildPlot(); } }
);
Alpine.effect(() => {
if (!this.plot && this.$store.insights.clustering && this.$store.insights.clustering[key]) {
this.buildPlot();
}
if (this.plot) {
const numAgents = this.$store.insights.uniqueAgents.length;
const numEpisodes = this.$store.insights.episodeIds.length;
const currentStep = this.$store.insights.currentStep;

// Get the current plot data
const plotElement = this.$el;
const currentData = plotElement.data;

// Remove the highlight trace if it exists (it will be last, at numEpisodes * numAgents + 1)
if (currentData && currentData.length > (numEpisodes * numAgents + 1)) {
Plotly.deleteTraces(this.$el, [numEpisodes * numAgents + 1]);
}

// Create arrays for the highlighted points
const highlightX = [];
const highlightY = [];
const highlightText = [];

for (let agentIdx = 0; agentIdx < numAgents; agentIdx++) {
for (let episodeIdx = 0; episodeIdx < numEpisodes; episodeIdx++) {
const idx = episodeIdx + agentIdx * numEpisodes;
const agentTrace = currentData && currentData[idx];
if (agentTrace
&& Array.isArray(agentTrace.x)
&& currentStep < agentTrace.x.length
&& (!agentTrace.visible || agentTrace.visible === true)
) {
highlightX.push(agentTrace.x[currentStep]);
highlightY.push(agentTrace.y[currentStep]);
const agents = this.$store.insights.uniqueAgents;
const episodes = this.$store.insights.episodeIds;
highlightText.push(`${agents[agentIdx]} Episode ${episodes[episodeIdx]}`);
}
}
}

// Only add the highlight trace if there are visible points
if (highlightX.length > 0) {
// Add new trace for highlighted points
const textPosition = [
'top left',
'middle left',
'bottom left',
'top center',
'middle center',
'bottom center',
'top right',
'middle right',
'bottom right'
];
Plotly.addTraces(this.$el, [{
x: highlightX,
y: highlightY,
text: highlightText,
type: 'scatter',
mode: 'markers+text',
showlegend: false,
textposition: textPosition,
textfont: {
size: 12,
color: this.$store.theme.fontColor
},
marker: {
color: 'transparent',
size: 20,
line: {
width: 3,
color: 'red'
}
}
}]);
}
}
});
},
resizePlot: _.debounce(function() {
if (!this.$el.querySelector('.plotly')) return;
Plotly.Plots.resize(this.$el);
}, 200, {leading: true}),
buildPlot() {
this.data = [];
const agents = this.$store.insights.uniqueAgents;
const episodes = this.$store.insights.episodeIds;
let clustering = null;
if (this.$store.insights.clustering) {
clustering = this.$store.insights.clustering
}
if (!clustering || !clustering[key]) return;
for (let agentIdx = 0; agentIdx < agents.length; agentIdx++) {
clustering[key].episode_manifolds.forEach((episodeManifold, episodeIdx) => {
const xCoords = [];
const yCoords = [];
episodeManifold.forEach(row => {
const embedding = Array.isArray(row) ? row[agentIdx] : null;
if (embedding && Array.isArray(embedding) && embedding.length >= 2) {
xCoords.push(embedding[0]); yCoords.push(embedding[1]);
}
});
this.data.push({
x: xCoords,
y: yCoords,
type: 'scatter',
mode: 'lines',
colorscale: 'YlOrRd',
line: { opacity: 1, width: 2 },
name: `Episode ${episodes[episodeIdx]} ${agents[agentIdx]}`
});
});
}
this.data.push({
x: clustering[key].all_manifolds_x,
y: clustering[key].all_manifolds_y,
type: 'scatter',
mode: 'markers',
marker: {
color: clustering[key].all_clusters,
cmin: 0,
cmax: 9,
colorscale: 'Viridis',
size: 20,
opacity: Array(clustering[key].all_manifolds_x.length).fill(1)
},
name: 'All Episodes'
});
this.plot = Plotly.newPlot(
this.$el,
this.data,
this.layout,
{ displayModeBar: false, responsive: true }
);
this.$watch('$store.settings.showPlotLegends', () => {
this.$nextTick(() => {
Plotly.relayout(this.$el, {
autosize: true,
showlegend: this.$store.settings.showPlotLegends,
})
});
});
},
}));
});
Loading