Skip to content

Commit 702fbae

Browse files
committed
started implementing an experimental tabular display mode
1 parent 70c6556 commit 702fbae

1 file changed

Lines changed: 162 additions & 0 deletions

File tree

v3/js/pytutor.js

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ var curVisualizerID = 1; // global to uniquely identify each ExecutionVisualizer
112112
// pyCrazyMode - run with Py2crazy, which provides expression-level
113113
// granularity instead of line-level granularity (HIGHLY EXPERIMENTAL!)
114114
// hideCode - hide the code display and show only the data structure viz
115+
// tabularView - render a tabular view of ALL steps at once (EXPERIMENTAL)
115116
function ExecutionVisualizer(domRootID, dat, params) {
116117
this.curInputCode = dat.code.rtrim(); // kill trailing spaces
117118
this.curTrace = dat.trace;
@@ -193,6 +194,7 @@ function ExecutionVisualizer(domRootID, dat, params) {
193194
this.drawParentPointers = (this.params.drawParentPointers == true);
194195
this.textualMemoryLabels = (this.params.textualMemoryLabels == true);
195196
this.showOnlyOutputs = (this.params.showOnlyOutputs == true);
197+
this.tabularView = (this.params.tabularView == true);
196198

197199
this.executeCodeWithRawInputFunc = this.params.executeCodeWithRawInputFunc;
198200

@@ -353,6 +355,11 @@ ExecutionVisualizer.prototype.render = function() {
353355
</table>\
354356
</div>';
355357

358+
// override
359+
if (myViz.tabularView) {
360+
codeVizHTML = '<div id="optTabularView"></div>';
361+
}
362+
356363
var vizHeaderHTML =
357364
'<div id="vizHeader">\
358365
<textarea class="vizTitleText" id="vizTitleEditor" cols="60" rows="1"></textarea>\
@@ -613,6 +620,11 @@ ExecutionVisualizer.prototype.render = function() {
613620
this.renderPyCodeOutput();
614621
}
615622

623+
// EXPERIMENTAL!
624+
if (this.tabularView) {
625+
this.renderTabularView();
626+
}
627+
616628
this.updateOutput();
617629

618630
this.hasRendered = true;
@@ -2073,6 +2085,10 @@ var rightwardNudgeHack = true; // suggested by John DeNero, toggle with global
20732085
ExecutionVisualizer.prototype.renderDataStructures = function(curEntry, curToplevelLayout) {
20742086
var myViz = this; // to prevent confusion of 'this' inside of nested functions
20752087

2088+
if (myViz.tabularView) {
2089+
return; // return EARLY!!!
2090+
}
2091+
20762092
myViz.resetJsPlumbManager(); // very important!!!
20772093

20782094
// for simplicity (but sacrificing some performance), delete all
@@ -2804,6 +2820,152 @@ ExecutionVisualizer.prototype.renderDataStructures = function(curEntry, curTople
28042820
}
28052821

28062822

2823+
// render a tabular visualization where each row is an execution step,
2824+
// and each column is a variable
2825+
ExecutionVisualizer.prototype.renderTabularView = function() {
2826+
var myViz = this; // to prevent confusion of 'this' inside of nested functions
2827+
2828+
myViz.resetJsPlumbManager(); // very important!!!
2829+
2830+
var allGlobalVars = [];
2831+
// Key: function name
2832+
// Value: list of ordered variables for function
2833+
var funcNameToOrderedVars = {};
2834+
var orderedFuncNames = []; // function names in order of appearance
2835+
2836+
// iterate through the entire trace and find all global variables, and
2837+
// all local variables in all functions, in order of appearance in the trace
2838+
$.each(myViz.curTrace, function(i, elt) {
2839+
$.each(elt.ordered_globals, function(i, g) {
2840+
// don't add duplicates into this list,
2841+
// but need to use a list to maintain ORDERING
2842+
if ($.inArray(g, allGlobalVars) === -1) {
2843+
allGlobalVars.push(g);
2844+
}
2845+
});
2846+
2847+
$.each(elt.stack_to_render, function(i, sf) {
2848+
var funcVarsList = funcNameToOrderedVars[sf.func_name];
2849+
if (funcVarsList === undefined) {
2850+
funcVarsList = [];
2851+
funcNameToOrderedVars[sf.func_name] = funcVarsList;
2852+
orderedFuncNames.push(sf.func_name);
2853+
}
2854+
$.each(sf.ordered_varnames, function(i, v) {
2855+
// don't add duplicates into this list,
2856+
// but need to use a list to maintain ORDERING
2857+
// (ignore the special __return__ value)
2858+
if ($.inArray(v, funcVarsList) === -1 && v !== '__return__') {
2859+
funcVarsList.push(v);
2860+
}
2861+
});
2862+
});
2863+
});
2864+
2865+
/*
2866+
console.log("allGlobalVars:", allGlobalVars);
2867+
console.log("orderedFuncNames:", orderedFuncNames);
2868+
$.each(funcNameToOrderedVars, function(k, v) {
2869+
console.log("funcNameToOrderedVars[", k, "] =", v);
2870+
});
2871+
*/
2872+
2873+
var allVarNames = [];
2874+
2875+
$.each(allGlobalVars, function(i, e) {
2876+
allVarNames.push(e);
2877+
});
2878+
$.each(orderedFuncNames, function(i, funcName) {
2879+
$.each(funcNameToOrderedVars[funcName], function(i, v) {
2880+
allVarNames.push(funcName + ':' + v);
2881+
});
2882+
});
2883+
console.log(allVarNames);
2884+
2885+
// get the values of all objects in trace entry e
2886+
function getAllOrderedValues(curEntry) {
2887+
var allVarValues = [];
2888+
2889+
$.each(allGlobalVars, function(i, e) {
2890+
allVarValues.push(curEntry.globals[e]);
2891+
});
2892+
2893+
// for local variables, grab only the values in the highlighted
2894+
// frame (if any)
2895+
var highlightedFrame = null;
2896+
$.each(curEntry.stack_to_render, function(i, sf) {
2897+
if (sf.is_highlighted) {
2898+
highlightedFrame = sf;
2899+
}
2900+
});
2901+
2902+
$.each(orderedFuncNames, function(i, funcName) {
2903+
$.each(funcNameToOrderedVars[funcName], function(i, v) {
2904+
var found = false;
2905+
if (highlightedFrame && funcName == highlightedFrame.func_name) {
2906+
var obj = highlightedFrame.encoded_locals[v];
2907+
if (obj) {
2908+
allVarValues.push(obj);
2909+
found = true;
2910+
}
2911+
}
2912+
2913+
// push an empty value if not found since we want everything to
2914+
// align with allVarNames
2915+
if (!found) {
2916+
allVarValues.push(undefined);
2917+
}
2918+
});
2919+
});
2920+
2921+
// TODO: also walk up parent pointers to also display variable
2922+
// values in enclosing frames
2923+
2924+
return allVarValues;
2925+
}
2926+
2927+
2928+
var tblRoot = myViz.domRootD3.select("#optTabularView");
2929+
var tbl = tblRoot.append("table");
2930+
var tHead = tbl.append('thead').append('tr');
2931+
tHead.selectAll('thead td')
2932+
.data(allVarNames)
2933+
.enter()
2934+
.append('td')
2935+
.html(function(d) { return d; })
2936+
2937+
var tBody = tbl.append('tbody');
2938+
2939+
var stepsAndTraceEntries = [];
2940+
$.each(myViz.curTrace, function(i, e) {
2941+
stepsAndTraceEntries.push([i, e]);
2942+
});
2943+
2944+
var tr = tBody.selectAll('tbody tr')
2945+
.data(stepsAndTraceEntries)
2946+
.enter()
2947+
.append("tr")
2948+
.attr("step", function(d, i) { return i; });
2949+
2950+
var td = tr.selectAll("td")
2951+
.data(function(e) { return getAllOrderedValues(e[1]); })
2952+
.enter()
2953+
.append("td")
2954+
.each(function(obj, i) {
2955+
$(this).empty();
2956+
// TODO: fixme -- this is super kludgy; must be a better way
2957+
var step = parseInt($(this).closest('tr').attr('step'));
2958+
2959+
if (obj === undefined) {
2960+
// keep this table cell EMPTY
2961+
}
2962+
else {
2963+
myViz.renderNestedObject(obj, step, $(this), 'tabular');
2964+
}
2965+
});
2966+
}
2967+
2968+
28072969
// rendering functions, which all take a d3 dom element to anchor the
28082970
// new element to render
28092971
ExecutionVisualizer.prototype.renderPrimitiveObject = function(obj, d3DomElement) {

0 commit comments

Comments
 (0)