Last active
December 23, 2015 07:59
-
-
Save seanjtaylor/6604307 to your computer and use it in GitHub Desktop.
Creds Viz take 2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<style> | |
rect.background { | |
fill: #EEE; | |
} | |
line.rule { | |
stroke: #FFF; | |
} | |
text.labels { | |
} | |
rect.vote { | |
} | |
rect.selected { | |
fill: white; | |
} | |
</style> | |
</head> | |
<body> | |
<svg> | |
</svg> | |
<br /> | |
Toggle Ordering: <input type="button" id="x-order" value="Ordinal"></input> | |
<br /> | |
Toggle Levels: <input type="button" id="y-diff" value="Probability"></input> | |
<br /> | |
Toggle Grouped: <input type="button" id="grouped" value="Not Grouped"></input> | |
<br /> <var id="point"></var> | |
</body> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.2.2/d3.v3.min.js"></script> | |
<script type="text/javascript"> | |
data = [{"pr": [0.4887518980531451], "q": 198, "p": 100, "u": "user:1", "cs": [0, 198], "dt": 1362002296.244313, "out": 1}, {"pr": [0.4777419929494981], "q": 194, "p": 100, "u": "user:1", "cs": [0, 392], "dt": 1362002297.15593, "out": 1}, {"pr": [0.4669799475900601], "q": 190, "p": 100, "u": "user:1", "cs": [0, 582], "dt": 1362002298.131446, "out": 1}, {"pr": [0.4564740857547256], "q": 186, "p": 100, "u": "user:1", "cs": [0, 768], "dt": 1362002299.053804, "out": 1}, {"pr": [0.4462314413902582], "q": 182, "p": 100, "u": "user:1", "cs": [0, 950], "dt": 1362002299.834792, "out": 1}, {"pr": [0.43620192214251935], "q": 179, "p": 100, "u": "user:1", "cs": [0, 1129], "dt": 1362002300.612833, "out": 1}, {"pr": [0.42639107453895414], "q": 176, "p": 100, "u": "user:1", "cs": [0, 1305], "dt": 1362002301.475644, "out": 1}, {"pr": [0.4168035487806823], "q": 173, "p": 100, "u": "user:1", "cs": [0, 1478], "dt": 1362002302.241639, "out": 1}, {"pr": [0.407443137803258], "q": 170, "p": 100, "u": "user:1", "cs": [0, 1648], "dt": 1362002303.044344, "out": 1}, {"pr": [0.3983128198171432], "q": 167, "p": 100, "u": "user:1", "cs": [0, 1815], "dt": 1362002303.838559, "out": 1}, {"pr": [0.389360766050778], "q": 165, "p": 100, "u": "user:1", "cs": [0, 1980], "dt": 1362002304.66829, "out": 1}, {"pr": [0.3805898296312972], "q": 163, "p": 100, "u": "user:1", "cs": [0, 2143], "dt": 1362002305.419034, "out": 1}, {"pr": [0.3720554203704833], "q": 160, "p": 100, "u": "user:1", "cs": [0, 2303], "dt": 1362002306.294308, "out": 1}, {"pr": [0.3637052339620581], "q": 158, "p": 100, "u": "user:1", "cs": [0, 2461], "dt": 1362002307.00364, "out": 1}, {"pr": [0.3780214784774396], "q": 270, "p": 100, "u": "user:79", "cs": [270, 2461], "dt": 1362097070.392947, "out": 0}, {"pr": [0.39201177524645336], "q": 260, "p": 100, "u": "user:79", "cs": [530, 2461], "dt": 1362097072.847491, "out": 0}, {"pr": [0.405688448673852], "q": 251, "p": 100, "u": "user:79", "cs": [781, 2461], "dt": 1362097074.466855, "out": 0}, {"pr": [0.41907033794980597], "q": 243, "p": 100, "u": "user:79", "cs": [1024, 2461], "dt": 1362097079.664115, "out": 0}, {"pr": [0.4321261306868008], "q": 235, "p": 100, "u": "user:79", "cs": [1259, 2461], "dt": 1362097081.050202, "out": 0}, {"pr": [0.44488397296379667], "q": 228, "p": 100, "u": "user:79", "cs": [1487, 2461], "dt": 1362097081.999775, "out": 0}, {"pr": [0.45737642937902717], "q": 222, "p": 100, "u": "user:79", "cs": [1709, 2461], "dt": 1362097083.52105, "out": 0}, {"pr": [0.46958306002339806], "q": 216, "p": 100, "u": "user:119", "cs": [1925, 2461], "dt": 1362982825.403441, "out": 0}, {"pr": [0.4814857413970002], "q": 210, "p": 100, "u": "user:124", "cs": [2135, 2461], "dt": 1363031950.177088, "out": 0}, {"pr": [0.4931254332354658], "q": 205, "p": 100, "u": "user:124", "cs": [2340, 2461], "dt": 1363031951.993299, "out": 0}, {"pr": [0.5044885157856556], "q": 200, "p": 100, "u": "user:124", "cs": [2540, 2461], "dt": 1363031953.333297, "out": 0}, {"pr": [0.5156199157230156], "q": 196, "p": 100, "u": "user:124", "cs": [2736, 2461], "dt": 1363031954.089252, "out": 0}, {"pr": [0.5265092102186909], "q": 192, "p": 100, "u": "user:124", "cs": [2928, 2461], "dt": 1363031955.47486, "out": 0}, {"pr": [0.5371473344866333], "q": 188, "p": 100, "u": "user:124", "cs": [3116, 2461], "dt": 1363031956.327959, "out": 0}, {"pr": [0.547526538084062], "q": 184, "p": 100, "u": "user:71", "cs": [3300, 2461], "dt": 1363048305.660753, "out": 0}, {"pr": [0.5352256373010753], "q": 218, "p": 100, "u": "user:146", "cs": [3300, 2679], "dt": 1363576413.143957, "out": 1}, {"pr": [0.5232219179306447], "q": 212, "p": 100, "u": "user:149", "cs": [3300, 2891], "dt": 1363656534.298865, "out": 1}, {"pr": [0.5339250688397637], "q": 189, "p": 100, "u": "user:149", "cs": [3489, 2891], "dt": 1363656541.768242, "out": 0}, {"pr": [0.5443716021266337], "q": 185, "p": 100, "u": "user:149", "cs": [3674, 2891], "dt": 1363656545.990622, "out": 0}, {"pr": [0.5321148186183294], "q": 217, "p": 100, "u": "user:149", "cs": [3674, 3108], "dt": 1363656547.323686, "out": 1}, {"pr": [0.5201595199384199], "q": 211, "p": 100, "u": "user:149", "cs": [3674, 3319], "dt": 1363656548.348152, "out": 1}, {"pr": [0.5309263793052534], "q": 190, "p": 100, "u": "user:149", "cs": [3864, 3319], "dt": 1363656549.538274, "out": 0}, {"pr": [0.5414388209791797], "q": 186, "p": 100, "u": "user:149", "cs": [4050, 3319], "dt": 1363656551.647232, "out": 0}, {"pr": [0.5517458796316836], "q": 183, "p": 100, "u": "user:149", "cs": [4233, 3319], "dt": 1363656553.642795, "out": 0}, {"pr": [0.561840835092455], "q": 180, "p": 100, "u": "user:149", "cs": [4413, 3319], "dt": 1363656554.930644, "out": 0}, {"pr": [0.5716622594453787], "q": 176, "p": 100, "u": "user:149", "cs": [4589, 3319], "dt": 1363656555.817018, "out": 0}, {"pr": [0.5588173309729533], "q": 230, "p": 100, "u": "user:149", "cs": [4589, 3549], "dt": 1363656558.168185, "out": 1}, {"pr": [0.5462875400979932], "q": 223, "p": 100, "u": "user:149", "cs": [4589, 3772], "dt": 1363656559.115906, "out": 1}, {"pr": [0.5340381803161751], "q": 217, "p": 100, "u": "user:149", "cs": [4589, 3989], "dt": 1363656560.03778, "out": 1}, {"pr": [0.5444843412876504], "q": 185, "p": 100, "u": "user:149", "cs": [4774, 3989], "dt": 1363656562.17308, "out": 0}, {"pr": [0.554723098218698], "q": 182, "p": 100, "u": "user:118", "cs": [4956, 3989], "dt": 1363897874.809114, "out": 0}, {"pr": [0.564748025859154], "q": 179, "p": 100, "u": "user:118", "cs": [5135, 3989], "dt": 1363897875.753546, "out": 0}, {"pr": [0.5745536304643416], "q": 176, "p": 100, "u": "user:118", "cs": [5311, 3989], "dt": 1363897879.95441, "out": 0}, {"pr": [0.5616170264245689], "q": 232, "p": 100, "u": "user:153", "cs": [5311, 4221], "dt": 1364690240.241184, "out": 1}, {"pr": [0.5489900482546072], "q": 225, "p": 100, "u": "user:146", "cs": [5311, 4446], "dt": 1366248577.421973, "out": 1}, {"pr": [0.5366387549568554], "q": 219, "p": 100, "u": "user:8", "cs": [5311, 4665], "dt": 1366345490.163138, "out": 1}, {"pr": [0.5470760606848712], "q": 185, "p": 100, "u": "user:185", "cs": [5496, 4665], "dt": 1373510535.358066, "out": 0}, {"pr": [0.5572478545985555], "q": 181, "p": 100, "u": "user:1", "cs": [5677, 4665], "dt": 1373510573.170755, "out": 0}, {"pr": [0.5672044918069048], "q": 178, "p": 100, "u": "user:1", "cs": [5855, 4665], "dt": 1373510573.952507, "out": 0}, {"pr": [0.5769407348571504], "q": 175, "p": 100, "u": "user:1", "cs": [6030, 4665], "dt": 1373510574.780651, "out": 0}, {"pr": [0.5864522300256834], "q": 172, "p": 100, "u": "user:1", "cs": [6202, 4665], "dt": 1373510575.570258, "out": 0}, {"pr": [0.595735466962288], "q": 169, "p": 100, "u": "user:1", "cs": [6371, 4665], "dt": 1373510576.371747, "out": 0}, {"pr": [0.6048420564550759], "q": 167, "p": 100, "u": "user:188", "cs": [6538, 4665], "dt": 1374713306.458774, "out": 0}, {"pr": [0.6137148419797863], "q": 164, "p": 100, "u": "user:188", "cs": [6702, 4665], "dt": 1374713308.742282, "out": 0}, {"pr": [0.6224059197809644], "q": 162, "p": 100, "u": "user:188", "cs": [6864, 4665], "dt": 1374713312.441157, "out": 0}, {"pr": [0.6309131806066465], "q": 160, "p": 100, "u": "user:188", "cs": [7024, 4665], "dt": 1374713315.324642, "out": 0}, {"pr": [0.6391826051783509], "q": 157, "p": 100, "u": "user:188", "cs": [7181, 4665], "dt": 1374824970.417369, "out": 0}, {"pr": [0.6472665360900266], "q": 155, "p": 100, "u": "user:188", "cs": [7336, 4665], "dt": 1374824971.537634, "out": 0}, {"pr": [0.6552156919248883], "q": 154, "p": 100, "u": "user:188", "cs": [7490, 4665], "dt": 1374824973.56478, "out": 0}, {"pr": [0.6629773994158226], "q": 152, "p": 100, "u": "user:188", "cs": [7642, 4665], "dt": 1374824976.381457, "out": 0}, {"pr": [0.6705517991954939], "q": 150, "p": 100, "u": "user:188", "cs": [7792, 4665], "dt": 1374925034.327889, "out": 0}, {"pr": [0.6779394010913482], "q": 148, "p": 100, "u": "user:188", "cs": [7940, 4665], "dt": 1374925035.996325, "out": 0}, {"pr": [0.6851900825938111], "q": 147, "p": 100, "u": "user:188", "cs": [8087, 4665], "dt": 1375084246.708778, "out": 0}, {"pr": [0.6922547765894579], "q": 145, "p": 100, "u": "user:188", "cs": [8232, 4665], "dt": 1375084293.981616, "out": 0}, {"pr": [0.6991827237997876], "q": 144, "p": 100, "u": "user:188", "cs": [8376, 4665], "dt": 1375085342.520309, "out": 0}, {"pr": [0.7059265892345513], "q": 142, "p": 100, "u": "user:188", "cs": [8518, 4665], "dt": 1375085343.327875, "out": 0}, {"pr": [0.7125348674101749], "q": 141, "p": 100, "u": "user:188", "cs": [8659, 4665], "dt": 1375090502.690305, "out": 0}] | |
/* | |
function groupby(seq, keyfunc){ | |
var lastkey = null | |
var key, item | |
var result = [] | |
for (var i = 0; i < seq.length; i++) { | |
item = seq[i] | |
key = keyfunc(item) | |
if (key == lastkey){ | |
result[result.length-1][1].push(item) | |
} | |
else { | |
result.push([key, [item]]) | |
lastkey = key | |
} | |
} | |
return result | |
} | |
*/ | |
function labelEndsSession(seq, keyfunc) { | |
var sessionId = 0; | |
var last = seq[0]; | |
for (var i = 0; i < (seq.length-1); i++) { | |
seq[i].sessionId = sessionId; | |
if (keyfunc(seq[i]) != keyfunc(seq[i+1])) { | |
seq[i].endsSession = true; | |
sessionId += 1; | |
seq[i].last = last; | |
last = seq[i]; | |
} else { | |
seq[i].endsSession = false; | |
} | |
} | |
seq[seq.length-1].endsSession = true; | |
seq[seq.length-1].sessionId = sessionId; | |
seq[i].last = last; | |
} | |
function update(data, o) { | |
// 1. if it's diff mode, ignore the first observation | |
// 2. if it's grouped mode, ignore the ones that don't end a session | |
opacity = function(d, i) { | |
return (o.diff && i == 0) || (o.grouped && !d.endsSession) ? 1e-6 : 1; | |
} | |
if (o.ordinal) { | |
if (o.grouped) { | |
// ordinal AND grouped | |
var ngroups = d3.sum(data, function(d) { return d.endsSession ? 1 : 0 }) | |
o.xOrder.domain([0, ngroups-1]) | |
var xAttr = function(d, i) { return o.xOrder(d.sessionId) } | |
} else { | |
// ordinal AND NOT grouped | |
o.xOrder.domain([0, data.length-1]); | |
var xAttr = function(d, i) { return o.xOrder(i) } | |
} | |
var wAttr = function(d, i) { | |
return d3.min([15, d3.round(o.w / o.xOrder.domain()[1])]) | |
} | |
} else { | |
// time scale | |
var xAttr = function(d, i) { return o.xTime(d.dt) } | |
var wAttr = function(d, i) { return 10 } | |
} | |
if (o.diff) { | |
// diffed | |
diffProb = function(d, i) { | |
if (d.endsSession && o.grouped) { | |
var end = d.pr[0] | |
var start = d.last.pr[0] | |
return 100*(end - start) | |
} else if (!o.grouped && i > 0) { | |
// not grouped | |
return 100*(d.pr[0] - data[i-1].pr[0]) | |
} else { | |
// grouped and NOT ends session, so ignore it | |
return 0 | |
} | |
} | |
var yrange = d3.extent(data, diffProb) | |
o.yDiff.domain([d3.min([yrange[0], -1]), d3.max([yrange[1], 1])]) | |
var yAttr = function(d, i) { | |
var diff = diffProb(d, i) | |
return diff > 0 ? o.yDiff(diff) : o.yDiff(0) | |
} | |
function abs(d) { return d > 0 ? d : -d } | |
var hAttr = function(d, i) { return abs(o.yDiff(diffProb(d, i)) - o.yDiff(0)) } | |
var yTicks = o.yDiff.ticks(5) | |
} else { | |
// absolute scale | |
var yAttr = function(d, i) { return o.yProb(100*d.pr[0]) } | |
var hAttr = function(d, i) { return 10 } | |
var yTicks = [25, 50, 75] | |
} | |
var y = function(d) { return o.diff ? o.yDiff(d) : o.yProb(d) } | |
var yLab = function(d) { return (o.diff && d > 0) ? '+' + d : d } | |
var yRule = o.svg.selectAll('g.y').data(yTicks) | |
var yTrans = yRule.transition().duration(250) | |
yTrans.select('line') | |
.attr('y1', y) | |
.attr('y2', y) | |
yTrans.select('text') | |
.attr('y', y) | |
.text(function(d) { return d }) | |
var yEnter = yRule.enter() | |
.append('g') | |
.attr('class', 'y') | |
yEnter.append('line') | |
.attr('class', 'rule') | |
.attr('x1', o.xOrder.range()[0]) | |
.attr('x2', o.xOrder.range()[1]) | |
.attr('y1', y) | |
.attr('y2', y) | |
yEnter.append('text') | |
.attr("class", "labels") | |
.attr("x", 0) | |
.attr("y", y) | |
.attr("text-anchor", "right") | |
.text(yLab) | |
yRule.exit().remove() | |
var rects = o.svg.selectAll('rect.vote').data(data) | |
// update existing elements | |
rects.transition() | |
.duration(750) | |
.attr('x', xAttr) | |
.attr('y', yAttr) | |
.attr('width', wAttr) | |
.attr('height', hAttr) | |
.style("fill-opacity", opacity) | |
var legend = o.svg.selectAll('g.legend').data([data[data.length-1]]) | |
legend.enter() | |
.append('g') | |
.attr('class', 'legend') | |
.append('text') | |
.attr('x', 0) | |
.attr('y', 50) | |
.text(function(d) { | |
return d.u + ' -> ' + d.pr[0] + ' at ' + d.dt; | |
}) | |
rects.enter() | |
.append('rect') | |
.attr('class', 'vote') | |
.attr('width', wAttr) | |
.attr('height', hAttr) | |
.attr('x', xAttr) | |
.attr('y', yAttr) | |
.style("fill-opacity", opacity) | |
.attr('fill', function(d) { return o.userColor(d.u) }) | |
rects.exit().remove() | |
} | |
function init(data) { | |
var m = [30, 30, 30, 30], // margins: top right bottom left | |
w = 538 - m[1] - m[3], // width | |
h = 400 - m[0] - m[2] // height | |
// default state | |
options = { | |
diff: 0, | |
grouped: 0, | |
ordinal: 0, // gets reversed immediately | |
yProb: d3.scale.linear().range([h, 0]).domain([0,100]), | |
yDiff: d3.scale.linear().range([h, 0]).domain([-.25,.25]), | |
xTime: d3.scale.linear().range([20, w-10]), | |
xOrder: d3.scale.linear().range([20, w-10]), | |
userColor: d3.scale.category20c(), | |
svg: d3.select('svg').attr("width", w).attr("height", h), | |
w: w, | |
h: h | |
} | |
options.svg.append("rect") | |
.attr("width", w) | |
.attr("height", h) | |
.attr("class", "background") | |
// setup our three toggle buttons | |
var toggleOrder = function() { | |
options.ordinal = 1 - options.ordinal | |
d3.select('#x-order').attr('value', ['Time', 'Ordinal'][options.ordinal]) | |
update(data, options) | |
} | |
var toggleDiff = function() { | |
options.diff = 1 - options.diff | |
d3.select('#y-diff').attr('value', ['Probability', 'Change'][options.diff]) | |
update(data, options) | |
} | |
var toggleGrouped = function() { | |
options.grouped = 1 - options.grouped | |
d3.select('#grouped').attr('value', ['Not Grouped', 'Grouped'][options.grouped]) | |
update(data, options) | |
} | |
d3.select('#x-order').on('click', toggleOrder) | |
d3.select('#y-diff').on('click', toggleDiff) | |
d3.select('#grouped').on('click', toggleGrouped) | |
options.xTime.domain(d3.extent(data, function(d, i) { return d.dt })); | |
labelEndsSession(data, function(d) { return d.u}); | |
toggleOrder() | |
} | |
data[0] = {pr: [0.50], cs: [0,0], u: 'user:0', dt: 1362002206.244313} | |
init(data) | |
</script> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data = [{"pr": [0.4887518980531451], "q": 198, "p": 100, "u": "user:1", "cs": [0, 198], "dt": 1362002296.244313, "out": 1}, {"pr": [0.4777419929494981], "q": 194, "p": 100, "u": "user:1", "cs": [0, 392], "dt": 1362002297.15593, "out": 1}, {"pr": [0.4669799475900601], "q": 190, "p": 100, "u": "user:1", "cs": [0, 582], "dt": 1362002298.131446, "out": 1}, {"pr": [0.4564740857547256], "q": 186, "p": 100, "u": "user:1", "cs": [0, 768], "dt": 1362002299.053804, "out": 1}, {"pr": [0.4462314413902582], "q": 182, "p": 100, "u": "user:1", "cs": [0, 950], "dt": 1362002299.834792, "out": 1}, {"pr": [0.43620192214251935], "q": 179, "p": 100, "u": "user:1", "cs": [0, 1129], "dt": 1362002300.612833, "out": 1}, {"pr": [0.42639107453895414], "q": 176, "p": 100, "u": "user:1", "cs": [0, 1305], "dt": 1362002301.475644, "out": 1}, {"pr": [0.4168035487806823], "q": 173, "p": 100, "u": "user:1", "cs": [0, 1478], "dt": 1362002302.241639, "out": 1}, {"pr": [0.407443137803258], "q": 170, "p": 100, "u": "user:1", "cs": [0, 1648], "dt": 1362002303.044344, "out": 1}, {"pr": [0.3983128198171432], "q": 167, "p": 100, "u": "user:1", "cs": [0, 1815], "dt": 1362002303.838559, "out": 1}, {"pr": [0.389360766050778], "q": 165, "p": 100, "u": "user:1", "cs": [0, 1980], "dt": 1362002304.66829, "out": 1}, {"pr": [0.3805898296312972], "q": 163, "p": 100, "u": "user:1", "cs": [0, 2143], "dt": 1362002305.419034, "out": 1}, {"pr": [0.3720554203704833], "q": 160, "p": 100, "u": "user:1", "cs": [0, 2303], "dt": 1362002306.294308, "out": 1}, {"pr": [0.3637052339620581], "q": 158, "p": 100, "u": "user:1", "cs": [0, 2461], "dt": 1362002307.00364, "out": 1}, {"pr": [0.3780214784774396], "q": 270, "p": 100, "u": "user:79", "cs": [270, 2461], "dt": 1362097070.392947, "out": 0}, {"pr": [0.39201177524645336], "q": 260, "p": 100, "u": "user:79", "cs": [530, 2461], "dt": 1362097072.847491, "out": 0}, {"pr": [0.405688448673852], "q": 251, "p": 100, "u": "user:79", "cs": [781, 2461], "dt": 1362097074.466855, "out": 0}, {"pr": [0.41907033794980597], "q": 243, "p": 100, "u": "user:79", "cs": [1024, 2461], "dt": 1362097079.664115, "out": 0}, {"pr": [0.4321261306868008], "q": 235, "p": 100, "u": "user:79", "cs": [1259, 2461], "dt": 1362097081.050202, "out": 0}, {"pr": [0.44488397296379667], "q": 228, "p": 100, "u": "user:79", "cs": [1487, 2461], "dt": 1362097081.999775, "out": 0}, {"pr": [0.45737642937902717], "q": 222, "p": 100, "u": "user:79", "cs": [1709, 2461], "dt": 1362097083.52105, "out": 0}, {"pr": [0.46958306002339806], "q": 216, "p": 100, "u": "user:119", "cs": [1925, 2461], "dt": 1362982825.403441, "out": 0}, {"pr": [0.4814857413970002], "q": 210, "p": 100, "u": "user:124", "cs": [2135, 2461], "dt": 1363031950.177088, "out": 0}, {"pr": [0.4931254332354658], "q": 205, "p": 100, "u": "user:124", "cs": [2340, 2461], "dt": 1363031951.993299, "out": 0}, {"pr": [0.5044885157856556], "q": 200, "p": 100, "u": "user:124", "cs": [2540, 2461], "dt": 1363031953.333297, "out": 0}, {"pr": [0.5156199157230156], "q": 196, "p": 100, "u": "user:124", "cs": [2736, 2461], "dt": 1363031954.089252, "out": 0}, {"pr": [0.5265092102186909], "q": 192, "p": 100, "u": "user:124", "cs": [2928, 2461], "dt": 1363031955.47486, "out": 0}, {"pr": [0.5371473344866333], "q": 188, "p": 100, "u": "user:124", "cs": [3116, 2461], "dt": 1363031956.327959, "out": 0}, {"pr": [0.547526538084062], "q": 184, "p": 100, "u": "user:71", "cs": [3300, 2461], "dt": 1363048305.660753, "out": 0}, {"pr": [0.5352256373010753], "q": 218, "p": 100, "u": "user:146", "cs": [3300, 2679], "dt": 1363576413.143957, "out": 1}, {"pr": [0.5232219179306447], "q": 212, "p": 100, "u": "user:149", "cs": [3300, 2891], "dt": 1363656534.298865, "out": 1}, {"pr": [0.5339250688397637], "q": 189, "p": 100, "u": "user:149", "cs": [3489, 2891], "dt": 1363656541.768242, "out": 0}, {"pr": [0.5443716021266337], "q": 185, "p": 100, "u": "user:149", "cs": [3674, 2891], "dt": 1363656545.990622, "out": 0}, {"pr": [0.5321148186183294], "q": 217, "p": 100, "u": "user:149", "cs": [3674, 3108], "dt": 1363656547.323686, "out": 1}, {"pr": [0.5201595199384199], "q": 211, "p": 100, "u": "user:149", "cs": [3674, 3319], "dt": 1363656548.348152, "out": 1}, {"pr": [0.5309263793052534], "q": 190, "p": 100, "u": "user:149", "cs": [3864, 3319], "dt": 1363656549.538274, "out": 0}, {"pr": [0.5414388209791797], "q": 186, "p": 100, "u": "user:149", "cs": [4050, 3319], "dt": 1363656551.647232, "out": 0}, {"pr": [0.5517458796316836], "q": 183, "p": 100, "u": "user:149", "cs": [4233, 3319], "dt": 1363656553.642795, "out": 0}, {"pr": [0.561840835092455], "q": 180, "p": 100, "u": "user:149", "cs": [4413, 3319], "dt": 1363656554.930644, "out": 0}, {"pr": [0.5716622594453787], "q": 176, "p": 100, "u": "user:149", "cs": [4589, 3319], "dt": 1363656555.817018, "out": 0}, {"pr": [0.5588173309729533], "q": 230, "p": 100, "u": "user:149", "cs": [4589, 3549], "dt": 1363656558.168185, "out": 1}, {"pr": [0.5462875400979932], "q": 223, "p": 100, "u": "user:149", "cs": [4589, 3772], "dt": 1363656559.115906, "out": 1}, {"pr": [0.5340381803161751], "q": 217, "p": 100, "u": "user:149", "cs": [4589, 3989], "dt": 1363656560.03778, "out": 1}, {"pr": [0.5444843412876504], "q": 185, "p": 100, "u": "user:149", "cs": [4774, 3989], "dt": 1363656562.17308, "out": 0}, {"pr": [0.554723098218698], "q": 182, "p": 100, "u": "user:118", "cs": [4956, 3989], "dt": 1363897874.809114, "out": 0}, {"pr": [0.564748025859154], "q": 179, "p": 100, "u": "user:118", "cs": [5135, 3989], "dt": 1363897875.753546, "out": 0}, {"pr": [0.5745536304643416], "q": 176, "p": 100, "u": "user:118", "cs": [5311, 3989], "dt": 1363897879.95441, "out": 0}, {"pr": [0.5616170264245689], "q": 232, "p": 100, "u": "user:153", "cs": [5311, 4221], "dt": 1364690240.241184, "out": 1}, {"pr": [0.5489900482546072], "q": 225, "p": 100, "u": "user:146", "cs": [5311, 4446], "dt": 1366248577.421973, "out": 1}, {"pr": [0.5366387549568554], "q": 219, "p": 100, "u": "user:8", "cs": [5311, 4665], "dt": 1366345490.163138, "out": 1}, {"pr": [0.5470760606848712], "q": 185, "p": 100, "u": "user:185", "cs": [5496, 4665], "dt": 1373510535.358066, "out": 0}, {"pr": [0.5572478545985555], "q": 181, "p": 100, "u": "user:1", "cs": [5677, 4665], "dt": 1373510573.170755, "out": 0}, {"pr": [0.5672044918069048], "q": 178, "p": 100, "u": "user:1", "cs": [5855, 4665], "dt": 1373510573.952507, "out": 0}, {"pr": [0.5769407348571504], "q": 175, "p": 100, "u": "user:1", "cs": [6030, 4665], "dt": 1373510574.780651, "out": 0}, {"pr": [0.5864522300256834], "q": 172, "p": 100, "u": "user:1", "cs": [6202, 4665], "dt": 1373510575.570258, "out": 0}, {"pr": [0.595735466962288], "q": 169, "p": 100, "u": "user:1", "cs": [6371, 4665], "dt": 1373510576.371747, "out": 0}, {"pr": [0.6048420564550759], "q": 167, "p": 100, "u": "user:188", "cs": [6538, 4665], "dt": 1374713306.458774, "out": 0}, {"pr": [0.6137148419797863], "q": 164, "p": 100, "u": "user:188", "cs": [6702, 4665], "dt": 1374713308.742282, "out": 0}, {"pr": [0.6224059197809644], "q": 162, "p": 100, "u": "user:188", "cs": [6864, 4665], "dt": 1374713312.441157, "out": 0}, {"pr": [0.6309131806066465], "q": 160, "p": 100, "u": "user:188", "cs": [7024, 4665], "dt": 1374713315.324642, "out": 0}, {"pr": [0.6391826051783509], "q": 157, "p": 100, "u": "user:188", "cs": [7181, 4665], "dt": 1374824970.417369, "out": 0}, {"pr": [0.6472665360900266], "q": 155, "p": 100, "u": "user:188", "cs": [7336, 4665], "dt": 1374824971.537634, "out": 0}, {"pr": [0.6552156919248883], "q": 154, "p": 100, "u": "user:188", "cs": [7490, 4665], "dt": 1374824973.56478, "out": 0}, {"pr": [0.6629773994158226], "q": 152, "p": 100, "u": "user:188", "cs": [7642, 4665], "dt": 1374824976.381457, "out": 0}, {"pr": [0.6705517991954939], "q": 150, "p": 100, "u": "user:188", "cs": [7792, 4665], "dt": 1374925034.327889, "out": 0}, {"pr": [0.6779394010913482], "q": 148, "p": 100, "u": "user:188", "cs": [7940, 4665], "dt": 1374925035.996325, "out": 0}, {"pr": [0.6851900825938111], "q": 147, "p": 100, "u": "user:188", "cs": [8087, 4665], "dt": 1375084246.708778, "out": 0}, {"pr": [0.6922547765894579], "q": 145, "p": 100, "u": "user:188", "cs": [8232, 4665], "dt": 1375084293.981616, "out": 0}, {"pr": [0.6991827237997876], "q": 144, "p": 100, "u": "user:188", "cs": [8376, 4665], "dt": 1375085342.520309, "out": 0}, {"pr": [0.7059265892345513], "q": 142, "p": 100, "u": "user:188", "cs": [8518, 4665], "dt": 1375085343.327875, "out": 0}, {"pr": [0.7125348674101749], "q": 141, "p": 100, "u": "user:188", "cs": [8659, 4665], "dt": 1375090502.690305, "out": 0}] | |
/* | |
function groupby(seq, keyfunc){ | |
var lastkey = null | |
var key, item | |
var result = [] | |
for (var i = 0; i < seq.length; i++) { | |
item = seq[i] | |
key = keyfunc(item) | |
if (key == lastkey){ | |
result[result.length-1][1].push(item) | |
} | |
else { | |
result.push([key, [item]]) | |
lastkey = key | |
} | |
} | |
return result | |
} | |
*/ | |
function labelEndsSession(seq, keyfunc) { | |
var sessionId = 0; | |
var last = seq[0]; | |
for (var i = 0; i < (seq.length-1); i++) { | |
seq[i].sessionId = sessionId; | |
if (keyfunc(seq[i]) != keyfunc(seq[i+1])) { | |
seq[i].endsSession = true; | |
sessionId += 1; | |
seq[i].last = last; | |
last = seq[i]; | |
} else { | |
seq[i].endsSession = false; | |
} | |
} | |
seq[seq.length-1].endsSession = true; | |
seq[seq.length-1].sessionId = sessionId; | |
seq[i].last = last; | |
} | |
function update(data, o) { | |
// 1. if it's diff mode, ignore the first observation | |
// 2. if it's grouped mode, ignore the ones that don't end a session | |
opacity = function(d, i) { | |
return (o.diff && i == 0) || (o.grouped && !d.endsSession) ? 1e-6 : 1; | |
} | |
if (o.ordinal) { | |
if (o.grouped) { | |
// ordinal AND grouped | |
var ngroups = d3.sum(data, function(d) { return d.endsSession ? 1 : 0 }) | |
o.xOrder.domain([0, ngroups-1]) | |
var xAttr = function(d, i) { return o.xOrder(d.sessionId) } | |
} else { | |
// ordinal AND NOT grouped | |
o.xOrder.domain([0, data.length-1]); | |
var xAttr = function(d, i) { return o.xOrder(i) } | |
} | |
var wAttr = function(d, i) { | |
return d3.min([15, d3.round(o.w / o.xOrder.domain()[1])]) | |
} | |
} else { | |
// time scale | |
var xAttr = function(d, i) { return o.xTime(d.dt) } | |
var wAttr = function(d, i) { return 10 } | |
} | |
if (o.diff) { | |
// diffed | |
diffProb = function(d, i) { | |
if (d.endsSession && o.grouped) { | |
var end = d.pr[0] | |
var start = d.last.pr[0] | |
return 100*(end - start) | |
} else if (!o.grouped && i > 0) { | |
// not grouped | |
return 100*(d.pr[0] - data[i-1].pr[0]) | |
} else { | |
// grouped and NOT ends session, so ignore it | |
return 0 | |
} | |
} | |
var yrange = d3.extent(data, diffProb) | |
o.yDiff.domain([d3.min([yrange[0], -1]), d3.max([yrange[1], 1])]) | |
var yAttr = function(d, i) { | |
var diff = diffProb(d, i) | |
return diff > 0 ? o.yDiff(diff) : o.yDiff(0) | |
} | |
function abs(d) { return d > 0 ? d : -d } | |
var hAttr = function(d, i) { return abs(o.yDiff(diffProb(d, i)) - o.yDiff(0)) } | |
var yTicks = o.yDiff.ticks(5) | |
} else { | |
// absolute scale | |
var yAttr = function(d, i) { return o.yProb(100*d.pr[0]) } | |
var hAttr = function(d, i) { return 10 } | |
var yTicks = [25, 50, 75] | |
} | |
var y = function(d) { return o.diff ? o.yDiff(d) : o.yProb(d) } | |
var yLab = function(d) { return (o.diff && d > 0) ? '+' + d : d } | |
var yRule = o.svg.selectAll('g.y').data(yTicks) | |
var yTrans = yRule.transition().duration(250) | |
yTrans.select('line') | |
.attr('y1', y) | |
.attr('y2', y) | |
yTrans.select('text') | |
.attr('y', y) | |
.text(function(d) { return d }) | |
var yEnter = yRule.enter() | |
.append('g') | |
.attr('class', 'y') | |
yEnter.append('line') | |
.attr('class', 'rule') | |
.attr('x1', o.xOrder.range()[0]) | |
.attr('x2', o.xOrder.range()[1]) | |
.attr('y1', y) | |
.attr('y2', y) | |
yEnter.append('text') | |
.attr("class", "labels") | |
.attr("x", 0) | |
.attr("y", y) | |
.attr("text-anchor", "right") | |
.text(yLab) | |
yRule.exit().remove() | |
var rects = o.svg.selectAll('rect.vote').data(data) | |
// update existing elements | |
rects.transition() | |
.duration(750) | |
.attr('x', xAttr) | |
.attr('y', yAttr) | |
.attr('width', wAttr) | |
.attr('height', hAttr) | |
.style("fill-opacity", opacity) | |
var legend = o.svg.selectAll('g.legend').data([data[data.length-1]]) | |
legend.enter() | |
.append('g') | |
.attr('class', 'legend') | |
.append('text') | |
.attr('x', 0) | |
.attr('y', 50) | |
.text(function(d) { | |
return d.u + ' -> ' + d.pr[0] + ' at ' + d.dt; | |
}) | |
rects.enter() | |
.append('rect') | |
.attr('class', 'vote') | |
.attr('width', wAttr) | |
.attr('height', hAttr) | |
.attr('x', xAttr) | |
.attr('y', yAttr) | |
.style("fill-opacity", opacity) | |
.attr('fill', function(d) { return o.userColor(d.u) }) | |
rects.exit().remove() | |
} | |
function init(data) { | |
var m = [30, 30, 30, 30], // margins: top right bottom left | |
w = 538 - m[1] - m[3], // width | |
h = 400 - m[0] - m[2] // height | |
// default state | |
options = { | |
diff: 0, | |
grouped: 0, | |
ordinal: 0, // gets reversed immediately | |
yProb: d3.scale.linear().range([h, 0]).domain([0,100]), | |
yDiff: d3.scale.linear().range([h, 0]).domain([-.25,.25]), | |
xTime: d3.scale.linear().range([20, w-10]), | |
xOrder: d3.scale.linear().range([20, w-10]), | |
userColor: d3.scale.category20c(), | |
svg: d3.select('svg').attr("width", w).attr("height", h), | |
w: w, | |
h: h | |
} | |
options.svg.append("rect") | |
.attr("width", w) | |
.attr("height", h) | |
.attr("class", "background") | |
// setup our three toggle buttons | |
var toggleOrder = function() { | |
options.ordinal = 1 - options.ordinal | |
d3.select('#x-order').attr('value', ['Time', 'Ordinal'][options.ordinal]) | |
update(data, options) | |
} | |
var toggleDiff = function() { | |
options.diff = 1 - options.diff | |
d3.select('#y-diff').attr('value', ['Probability', 'Change'][options.diff]) | |
update(data, options) | |
} | |
var toggleGrouped = function() { | |
options.grouped = 1 - options.grouped | |
d3.select('#grouped').attr('value', ['Not Grouped', 'Grouped'][options.grouped]) | |
update(data, options) | |
} | |
d3.select('#x-order').on('click', toggleOrder) | |
d3.select('#y-diff').on('click', toggleDiff) | |
d3.select('#grouped').on('click', toggleGrouped) | |
options.xTime.domain(d3.extent(data, function(d, i) { return d.dt })); | |
labelEndsSession(data, function(d) { return d.u}); | |
toggleOrder() | |
} | |
data[0] = {pr: [0.50], cs: [0,0], u: 'user:0', dt: 1362002206.244313} | |
init(data) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment