Skip to content

Instantly share code, notes, and snippets.

@asm-jaime
Created May 8, 2018 20:16
Show Gist options
  • Save asm-jaime/d7842d4d716bfcd451759d53e05cf977 to your computer and use it in GitHub Desktop.
Save asm-jaime/d7842d4d716bfcd451759d53e05cf977 to your computer and use it in GitHub Desktop.
12345 mutations and diffs
<!DOCTYPE html><html><head><style type="text/css">
#main_wrapper {
margin: 0;
padding: 0;
overflow: none;
}
.nvtooltip {
position: absolute;
background-color: rgba(255,255,255,1);
padding: 10px;
border: 1px solid #ddd;
font-family: Arial;
font-size: 13px;
transition: opacity 500ms linear;
-moz-transition: opacity 500ms linear;
-webkit-transition: opacity 500ms linear;
transition-delay: 500ms
-moz-transition-delay: 500ms;
-webkit-transition-delay: 500ms;
-moz-box-shadow: 4px 4px 12px rgba(0,0,0,.5);
-webkit-box-shadow: 4px 4px 12px rgba(0,0,0,.5);
box-shadow: 4px 4px 12px rgba(0,0,0,.5);
-moz-border-radius: 15px;
border-radius: 15px;
}
.nvtooltip h3 {
margin: 0;
padding: 0;
text-align: center;
}
.nvtooltip p {
margin: 0;
padding: 0;
text-align: center;
}
.nvtooltip span {
display: inline-block;
margin: 2px 0;
}
text {
font: 12px sans-serif;
}
.legend .series {
cursor: pointer;
}
.legend circle {
stroke-width: 2px;
}
.legend .disabled circle {
fill-opacity: 0;
}
.axis path {
fill: none;
stroke: #000;
stroke-opacity: .75;
shape-rendering: crispEdges;
}
.axis path.domain {
stroke-opacity: .75;
}
.axis line {
fill: none;
stroke: #000;
stroke-opacity: .25;
shape-rendering: crispEdges;
}
.axis line.zero {
stroke-opacity: .75;
}
.point-paths path {
stroke-opacity: 0;
fill-opacity: 0;
}
.lines path {
fill: none;
stroke-width: 1.5px;
stroke-linecap: round;
transition: stroke-width 250ms linear;
-moz-transition: stroke-width 250ms linear;
-webkit-transition: stroke-width 250ms linear;
transition-delay: 250ms
-moz-transition-delay: 250ms;
-webkit-transition-delay: 250ms;
}
.line.hover path {
stroke-width: 6px;
}
.lines .point {
transition: stroke-width 250ms linear;
-moz-transition: stroke-width 250ms linear;
-webkit-transition: stroke-width 250ms linear;
}
.lines .point.hover {
stroke-width: 20px;
stroke-opacity: .5;
}</style></head><body><script src="https://d3js.org/d3.v2.min.js"></script><script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script><script>
function log(text) {
if (console && console.log) console.log(text);
return text;
}
(function($) {
var nvtooltip = window.nvtooltip = {};
nvtooltip.show = function(pos, content, gravity, dist) {
var container = $('<div class="nvtooltip">');
gravity = gravity || 's';
dist = dist || 20;
container
.html(content)
.css({ left: -1000, top: -1000, opacity: 0 })
.appendTo('body');
var height = container.height() + parseInt(container.css('padding-top')) + parseInt(container.css('padding-bottom')),
width = container.width() + parseInt(container.css('padding-left')) + parseInt(container.css('padding-right')),
windowWidth = $(window).width(),
windowHeight = $(window).height(),
scrollTop = $('body').scrollTop(),
left, top;
switch (gravity) {
case 'e':
case 'w':
case 'n':
left = pos[0] - (width / 2);
top = pos[1] + dist;
if (left < 0) left = 5;
if (left + width > windowWidth) left = windowWidth - width - 5;
if (scrollTop + windowHeight < top + height) top = pos[1] - height - dist;
break;
case 's':
left = pos[0] - (width / 2);
top = pos[1] - height - dist;
if (left < 0) left = 5;
if (left + width > windowWidth) left = windowWidth - width - 5;
if (scrollTop > top) top = pos[1] + dist;
break;
}
container
.css({
left: left,
top: top,
opacity: 1
});
};
nvtooltip.cleanup = function() {
var tooltips = $('.nvtooltip');
// remove right away, but delay the show with css
tooltips.css({
'transition-delay': '0 !important',
'-moz-transition-delay': '0 !important',
'-webkit-transition-delay': '0 !important'
});
tooltips.css('opacity', 0);
setTimeout(function() {
tooltips.remove()
}, 500);
};
})(jQuery);
var nv = { models: {} };
nv.models.legend = function() {
var margin = { top: 5, right: 0, bottom: 5, left: 10 },
width = 400,
height = 20,
color = d3.scale.category10().range(),
dispatch = d3.dispatch('legendClick', 'legendMouseover', 'legendMouseout');
function chart(selection) {
selection.each(function(data) {
var wrap = d3.select(this).selectAll('g.legend').data([data]);
var gEnter = wrap.enter().append('g').attr('class', 'legend').append('g');
var g = wrap.select('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var series = g.selectAll('.series')
.data(function(d) { return d });
var seriesEnter = series.enter().append('g').attr('class', 'series')
.on('click', function(d, i) {
dispatch.legendClick(d, i);
})
.on('mouseover', function(d, i) {
dispatch.legendMouseover(d, i);
})
.on('mouseout', function(d, i) {
dispatch.legendMouseout(d, i);
});
seriesEnter.append('circle')
.style('fill', function(d, i) { return d.color || color[i % 10] })
.style('stroke', function(d, i) { return d.color || color[i % 10] })
.attr('r', 5);
seriesEnter.append('text')
.text(function(d) { return d.label })
.attr('text-anchor', 'start')
.attr('dy', '.32em')
.attr('dx', '8');
series.classed('disabled', function(d) { return d.disabled });
series.exit().remove();
var ypos = 5,
newxpos = 5,
maxwidth = 0,
xpos;
series
.attr('transform', function(d, i) {
var length = d3.select(this).select('text').node().getComputedTextLength() + 28;
xpos = newxpos;
if (width < margin.left + margin.right + xpos + length) {
newxpos = xpos = 5;
ypos += 20;
}
newxpos += length;
if (newxpos > maxwidth) maxwidth = newxpos;
return 'translate(' + xpos + ',' + ypos + ')';
});
//position legend as far right as possible within the total width
g.attr('transform', 'translate(' + (width - margin.right - maxwidth) + ',' + margin.top + ')');
height = margin.top + margin.bottom + ypos + 15;
});
return chart;
}
chart.dispatch = dispatch;
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.color = function(_) {
if (!arguments.length) return color;
color = _;
return chart;
};
return chart;
}
nv.models.line = function() {
var margin = { top: 0, right: 0, bottom: 0, left: 0 },
width = 960,
height = 500,
dotRadius = function() { return 2.5 },
color = d3.scale.category10().range(),
//Create semi-unique ID incase user doesn't select one
id = Math.floor(Math.random() * 10000),
x = d3.scale.linear(),
y = d3.scale.linear(),
dispatch = d3.dispatch("pointMouseover", "pointMouseout"),
x0, y0;
function chart(selection) {
selection.each(function(data) {
var seriesData = data.map(function(d) { return d.data });
x0 = x0 || x;
y0 = y0 || y;
//add series data to each point for future ease of use
data = data.map(function(series, i) {
series.data = series.data.map(function(point) {
point.series = i;
return point;
});
return series;
});
x.domain(d3.extent(d3.merge(seriesData), function(d) { return d[0] }))
.range([0, width - margin.left - margin.right]);
y.domain(d3.extent(d3.merge(seriesData), function(d) { return d[1] }))
.range([height - margin.top - margin.bottom, 0]);
var vertices = d3.merge(data.map(function(line, lineIndex) {
return line.data.map(function(point, pointIndex) {
var pointKey = line.label + '-' + point[0];
return [x(point[0]), y(point[1]), lineIndex, pointIndex]; //adding series index to point because data is being flattened
})
}));
var wrap = d3.select(this).selectAll('g.d3line').data([data]);
var gEnter = wrap.enter().append('g').attr('class', 'd3line').append('g');
gEnter.append('g').attr('class', 'lines');
gEnter.append('g').attr('class', 'point-clips');
gEnter.append('g').attr('class', 'point-paths');
var g = wrap.select('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var voronoiClip = gEnter.append('g').attr('class', 'voronoi-clip')
.append('clipPath')
.attr('id', 'voronoi-clip-path-' + id)
.append('rect');
wrap.select('.voronoi-clip rect')
.attr('x', -10)
.attr('y', -10)
.attr('width', width - margin.left - margin.right + 20)
.attr('height', height - margin.top - margin.bottom + 20);
wrap.select('.point-paths')
.attr('clip-path', 'url(#voronoi-clip-path-' + id + ')');
var pointClips = wrap.select('.point-clips').selectAll('.clip-path')
.data(vertices);
pointClips.enter().append('clipPath').attr('class', 'clip-path')
.append('circle')
.attr('r', 25);
pointClips.exit().remove();
pointClips
.attr('id', function(d, i) { return 'clip-' + id + '-' + d[2] + '-' + d[3] })
.attr('transform', function(d) { return 'translate(' + d[0] + ',' + d[1] + ')' });
var voronoi = d3.geom.voronoi(vertices).map(function(d, i) {
return { 'data': d, 'series': vertices[i][2], 'point': vertices[i][3] }
});
var pointPaths = wrap.select('.point-paths').selectAll('path')
.data(voronoi);
pointPaths.enter().append('path')
.attr('class', function(d, i) { return 'path-' + i; });
pointPaths.exit().remove();
pointPaths
.attr('clip-path', function(d) { return 'url(#clip-' + id + '-' + d.series + '-' + d.point + ')'; })
.attr('d', function(d) { return 'M' + d.data.join(',') + 'Z'; })
.on('mouseover', function(d) {
dispatch.pointMouseover({
point: data[d.series].data[d.point],
series: data[d.series],
pos: [x(data[d.series].data[d.point][0]) + margin.left, y(data[d.series].data[d.point][1]) + margin.top],
pointIndex: d.point,
seriesIndex: d.series
});
})
.on('mouseout', function(d) {
dispatch.pointMouseout({
point: d,
series: data[d.series],
pointIndex: d.point,
seriesIndex: d.series
});
});
dispatch.on('pointMouseover.point', function(d) {
wrap.select('.line-' + d.seriesIndex + ' .point-' + d.pointIndex)
.classed('hover', true);
});
dispatch.on('pointMouseout.point', function(d) {
wrap.select('.line-' + d.seriesIndex + ' .point-' + d.pointIndex)
.classed('hover', false);
});
var lines = wrap.select('.lines').selectAll('.line')
.data(function(d) { return d }, function(d) { return d.label });
lines.enter().append('g')
.style('stroke-opacity', 1e-6)
.style('fill-opacity', 1e-6);
d3.transition(lines.exit())
.style('stroke-opacity', 1e-6)
.style('fill-opacity', 1e-6)
.remove();
lines.attr('class', function(d, i) { return 'line line-' + i })
.classed('hover', function(d) { return d.hover })
.style('fill', function(d, i) { return color[i % 10] })
.style('stroke', function(d, i) { return color[i % 10] })
d3.transition(lines)
.style('stroke-opacity', 1)
.style('fill-opacity', .5);
var paths = lines.selectAll('path')
.data(function(d, i) { return [d.data] });
paths.enter().append('path')
.attr('d', d3.svg.line()
.x(function(d) { return x0(d[0]) })
.y(function(d) { return y0(d[1]) })
);
paths.exit().remove();
d3.transition(paths)
.attr('d', d3.svg.line()
.x(function(d) { return x(d[0]) })
.y(function(d) { return y(d[1]) })
);
var points = lines.selectAll('circle.point')
.data(function(d) { return d.data });
points.enter().append('circle')
.attr('cx', function(d) { return x0(d[0]) })
.attr('cy', function(d) { return y0(d[1]) });
points.exit().remove();
points.attr('class', function(d, i) { return 'point point-' + i });
d3.transition(points)
.attr('cx', function(d) { return x(d[0]) })
.attr('cy', function(d) { return y(d[1]) })
.attr('r', dotRadius());
});
x0 = x;
y0 = y;
return chart;
}
nv.strip = function(s) {
return s.replace(/(\s|&)/g, '');
}
chart.dispatch = dispatch;
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.dotRadius = function(_) {
if (!arguments.length) return dotRadius;
dotRadius = d3.functor(_);
return chart;
};
chart.color = function(_) {
if (!arguments.length) return color;
color = _;
return chart;
};
chart.id = function(_) {
if (!arguments.length) return id;
id = _;
return chart;
};
return chart;
}
nv.models.lineWithLegend = function() {
var margin = { top: 30, right: 10, bottom: 50, left: 60 },
width = 960,
height = 500,
dotRadius = function() { return 2.5 },
xAxisLabelText = false,
yAxisLabelText = false,
color = d3.scale.category10().range(),
dispatch = d3.dispatch('showTooltip', 'hideTooltip');
var x = d3.scale.linear(),
y = d3.scale.linear(),
xAxis = d3.svg.axis().scale(x).orient('bottom'),
yAxis = d3.svg.axis().scale(y).orient('left'),
legend = nv.models.legend().height(30).color(color),
lines = nv.models.line();
function chart(selection) {
selection.each(function(data) {
var series = data.filter(function(d) { return !d.disabled })
.map(function(d) { return d.data });
x.domain(d3.extent(d3.merge(series), function(d) { return d[0] }))
.range([0, width - margin.left - margin.right]);
y.domain(d3.extent(d3.merge(series), function(d) { return d[1] }))
.range([height - margin.top - margin.bottom, 0]);
lines
.width(width - margin.left - margin.right)
.height(height - margin.top - margin.bottom)
.color(data.map(function(d, i) {
return d.color || color[i % 10];
}).filter(function(d, i) { return !data[i].disabled }))
xAxis
.ticks(width / 100)
.tickSize(-(height - margin.top - margin.bottom), 0);
yAxis
.ticks(height / 36)
.tickSize(-(width - margin.right - margin.left), 0);
var wrap = d3.select(this).selectAll('g.wrap').data([data]);
var gEnter = wrap.enter().append('g').attr('class', 'wrap d3lineWithLegend').append('g');
gEnter.append('g').attr('class', 'legendWrap');
gEnter.append('g').attr('class', 'x axis');
gEnter.append('g').attr('class', 'y axis');
gEnter.append('g').attr('class', 'linesWrap');
legend.dispatch.on('legendClick', function(d, i) {
d.disabled = !d.disabled;
if (!data.filter(function(d) { return !d.disabled }).length) {
data.forEach(function(d) {
d.disabled = false;
});
}
selection.transition().call(chart)
});
legend.dispatch.on('legendMouseover', function(d, i) {
d.hover = true;
selection.transition().call(chart)
});
legend.dispatch.on('legendMouseout', function(d, i) {
d.hover = false;
selection.transition().call(chart)
});
lines.dispatch.on('pointMouseover.tooltip', function(e) {
dispatch.showTooltip({
point: e.point,
series: e.series,
pos: [e.pos[0] + margin.left, e.pos[1] + margin.top],
seriesIndex: e.seriesIndex,
pointIndex: e.pointIndex
});
});
lines.dispatch.on('pointMouseout.tooltip', function(e) {
dispatch.hideTooltip(e);
});
legend
.color(color)
.width(width / 2 - margin.right);
wrap.select('.legendWrap')
.datum(data)
.attr('transform', 'translate(' + (width / 2 - margin.left) + ',' + (-legend.height()) + ')')
.call(legend);
margin.top = legend.height(); //need to re-render to see update
var g = wrap.select('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var linesWrap = wrap.select('.linesWrap')
.datum(data.filter(function(d) { return !d.disabled }));
d3.transition(linesWrap).call(lines);
var xAxisLabel = g.select('.x.axis').selectAll('text.axislabel')
.data([xAxisLabelText || null]);
xAxisLabel.enter().append('text').attr('class', 'axislabel')
.attr('text-anchor', 'middle')
.attr('x', x.range()[1] / 2)
.attr('y', margin.bottom - 20);
xAxisLabel.exit().remove();
xAxisLabel.text(function(d) { return d });
g.select('.x.axis')
.attr('transform', 'translate(0,' + y.range()[0] + ')')
.call(xAxis)
.selectAll('line.tick')
.filter(function(d) { return !d })
.classed('zero', true);
var yAxisLabel = g.select('.y.axis').selectAll('text.axislabel')
.data([yAxisLabelText || null]);
yAxisLabel.enter().append('text').attr('class', 'axislabel')
.attr('transform', 'rotate(-90)')
.attr('text-anchor', 'middle')
.attr('y', 20 - margin.left);
yAxisLabel.exit().remove();
yAxisLabel
.attr('x', -y.range()[0] / 2)
.text(function(d) { return d });
g.select('.y.axis')
.call(yAxis)
.selectAll('line.tick')
.filter(function(d) { return !d })
.classed('zero', true);
});
return chart;
}
chart.dispatch = dispatch;
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.color = function(_) {
if (!arguments.length) return color;
color = _;
return chart;
};
chart.dotRadius = function(_) {
if (!arguments.length) return dotRadius;
dotRadius = d3.functor(_);
lines.dotRadius = d3.functor(_);
return chart;
};
//Expose the x-axis' tickFormat method.
chart.xAxis = {};
d3.rebind(chart.xAxis, xAxis, 'tickFormat');
chart.xAxis.label = function(_) {
if (!arguments.length) return xAxisLabelText;
xAxisLabelText = _;
return chart;
}
// Expose the y-axis' tickFormat method.
chart.yAxis = {};
d3.rebind(chart.yAxis, yAxis, 'tickFormat');
chart.yAxis.label = function(_) {
if (!arguments.length) return yAxisLabelText;
yAxisLabelText = _;
return chart;
}
return chart;
}
$(document).ready(function() {
var margin = { top: 30, right: 10, bottom: 50, left: 60 },
chart = nv.models.lineWithLegend()
.xAxis.label('X->')
.width(width(margin))
.height(height(margin))
.yAxis.label('Y->');
var svg = d3.select('body')
.append('div').attr('id', 'main_wrapper')
.append('svg')
.datum([{"data":[[0,12345],[1,12354],[2,12435],[3,12453],[4,12534],[5,12543],[6,13245],[7,13254],[8,13425],[9,13452],[10,13524],[11,13542],[12,14235],[13,14253],[14,14325],[15,14352],[16,14523],[17,14532],[18,15234],[19,15243],[20,15324],[21,15342],[22,15423],[23,15432],[24,21345],[25,21354],[26,21435],[27,21453],[28,21534],[29,21543],[30,23145],[31,23154],[32,23415],[33,23451],[34,23514],[35,23541],[36,24135],[37,24153],[38,24315],[39,24351],[40,24513],[41,24531],[42,25134],[43,25143],[44,25314],[45,25341],[46,25413],[47,25431],[48,31245],[49,31254],[50,31425],[51,31452],[52,31524],[53,31542],[54,32145],[55,32154],[56,32415],[57,32451],[58,32514],[59,32541],[60,34125],[61,34152],[62,34215],[63,34251],[64,34512],[65,34521],[66,35124],[67,35142],[68,35214],[69,35241],[70,35412],[71,35421],[72,41235],[73,41253],[74,41325],[75,41352],[76,41523],[77,41532],[78,42135],[79,42153],[80,42315],[81,42351],[82,42513],[83,42531],[84,43125],[85,43152],[86,43215],[87,43251],[88,43512],[89,43521],[90,45123],[91,45132],[92,45213],[93,45231],[94,45312],[95,45321],[96,51234],[97,51243],[98,51324],[99,51342],[100,51423],[101,51432],[102,52134],[103,52143],[104,52314],[105,52341],[106,52413],[107,52431],[108,53124],[109,53142],[110,53214],[111,53241],[112,53412],[113,53421],[114,54123],[115,54132],[116,54213],[117,54231],[118,54312],[119,54321]],"label":"permutations"},{"data":[[0,0],[1,9],[2,81],[3,18],[4,81],[5,9],[6,702],[7,9],[8,171],[9,27],[10,72],[11,18],[12,693],[13,18],[14,72],[15,27],[16,171],[17,9],[18,702],[19,9],[20,81],[21,18],[22,81],[23,9],[24,5913],[25,9],[26,81],[27,18],[28,81],[29,9],[30,1602],[31,9],[32,261],[33,36],[34,63],[35,27],[36,594],[37,18],[38,162],[39,36],[40,162],[41,18],[42,603],[43,9],[44,171],[45,27],[46,72],[47,18],[48,5814],[49,9],[50,171],[51,27],[52,72],[53,18],[54,603],[55,9],[56,261],[57,36],[58,63],[59,27],[60,1584],[61,27],[62,63],[63,36],[64,261],[65,9],[66,603],[67,18],[68,72],[69,27],[70,171],[71,9],[72,5814],[73,18],[74,72],[75,27],[76,171],[77,9],[78,603],[79,18],[80,162],[81,36],[82,162],[83,18],[84,594],[85,27],[86,63],[87,36],[88,261],[89,9],[90,1602],[91,9],[92,81],[93,18],[94,81],[95,9],[96,5913],[97,9],[98,81],[99,18],[100,81],[101,9],[102,702],[103,9],[104,171],[105,27],[106,72],[107,18],[108,693],[109,18],[110,72],[111,27],[112,171],[113,9],[114,702],[115,9],[116,81],[117,18],[118,81],[119,9]],"label":"differents"}])
svg.transition().duration(500)
.attr('width', width(margin))
.attr('height', height(margin))
.call(chart);
chart.dispatch.on('showTooltip', function(e) {
var offset = $('#main_wrapper').offset(), // { left: 0, top: 0 }
left = e.pos[0] + offset.left,
top = e.pos[1] + offset.top,
formatter = d3.format(".04f");
var content = '<h3>' + e.series.label + '</h3>' +
'<p>' +
'<span class="value">[' + e.point[0] + ', ' + formatter(e.point[1]) + ']</span>' +
'</p>';
nvtooltip.show([left, top], content);
});
chart.dispatch.on('hideTooltip', function(e) {
nvtooltip.cleanup();
});
$(window).resize(function() {
var margin = chart.margin();
chart
.width(width(margin))
.height(height(margin));
d3.select('#main_wrapper svg')
.attr('width', width(margin))
.attr('height', height(margin))
.call(chart);
});
function width(margin) {
var w = $(window).width() - 40;
return ((w - margin.left - margin.right - 20) < 0) ? margin.left + margin.right + 2 : w;
}
function height(margin) {
var h = $(window).height() - 40;
return (h - margin.top - margin.bottom - 20 < 0) ?
margin.top + margin.bottom + 2 : h;
}
});
</script></body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment