Skip to content

Instantly share code, notes, and snippets.

@sxywu
Last active November 1, 2015 23:26
Show Gist options
  • Save sxywu/b3b3ff937241182ee67e to your computer and use it in GitHub Desktop.
Save sxywu/b3b3ff937241182ee67e to your computer and use it in GitHub Desktop.
visfest block visualization 2
[{"id":"caa2da1ea1558cdc3357","userId":"zanarmstrong","description":"Which is bigger: Africa or North America?","created_at":"2015-05-20T19:42:34Z","updated_at":"2015-09-08T03:23:49Z","thumbnail":"https://gist.githubusercontent.com/zanarmstrong/caa2da1ea1558cdc3357/raw/1537ffa757d44beb270091d2bc5bbdbb5c4b70b4/thumbnail.png","api":{}},{"id":"80f308984b27dbab6a58","userId":"lelandlee","description":"Hexbin Wallpaper 1","created_at":"2015-10-08T19:27:17Z","updated_at":"2015-10-08T19:30:16Z","thumbnail":"https://gist.githubusercontent.com/lelandlee/80f308984b27dbab6a58/raw/fbbbfca20aefe6373da3830c4e119827d84e6535/thumbnail.png","api":{}},{"id":"5605982","userId":"jsundram","description":"BoxyLady2.pjs","created_at":"2013-05-18T22:35:51Z","updated_at":"2015-08-29T13:50:08Z","thumbnail":"https://gist.githubusercontent.com/jsundram/5605982/raw/fc7addc664cf9000090cdf067cd5f0155d4facd7/thumbnail.png","api":{}},{"id":"8d782030e4be9d832be7","userId":"kenpenn","description":"styling SVG markers","created_at":"2014-08-28T17:17:07Z","updated_at":"2015-08-29T14:05:48Z","thumbnail":"https://gist.githubusercontent.com/kenpenn/8d782030e4be9d832be7/raw/b805d0a6de69b561d3301c7b2852fb3a6f4f7a13/thumbnail.png","api":{}},{"id":"14c943d8f198d9f3fef2","userId":"john-guerra","description":"Group-in-a-box algorithm","created_at":"2014-11-07T01:56:19Z","updated_at":"2015-08-29T14:08:47Z","thumbnail":"https://gist.githubusercontent.com/john-guerra/14c943d8f198d9f3fef2/raw/b7853a44cb60e63d5f3b705f2525a97234ca32ef/thumbnail.png","api":{"d3.select":7,"d3.scale.category20":1,"d3.layout.forceInABox":1,"d3.json":1}},{"id":"c69c202db2ace12ad0e1","userId":"jeremycflin","description":"ONA 15 Attendees","created_at":"2015-10-12T22:16:24Z","updated_at":"2015-10-12T22:17:16Z","thumbnail":"https://gist.githubusercontent.com/jeremycflin/c69c202db2ace12ad0e1/raw/98bcfc8a9a43970bc7ca41bb70e48759f94dfb9c/thumbnail.png","api":{"d3.geo.orthographic":1,"d3.geo.path":1,"d3.behavior.zoom":1,"d3.geo.zoom":1,"d3.geom.voronoi":1,"d3.select":7,"d3.behavior.drag":2,"d3.event.sourceEvent.stopPropagation":1}},{"id":"890c4a214e48bedc8755","userId":"jieqianzhang","description":"Horserace tool","created_at":"2015-10-13T17:50:34Z","updated_at":"2015-10-13T18:03:42Z","thumbnail":"https://gist.githubusercontent.com/jieqianzhang/890c4a214e48bedc8755/raw/327fd0ae3f1b7d5dfb020735e1902ff98b39494a/thumbnail.png","api":{"d3.scale.linear":2,"d3.scale.category10":1,"d3.svg.axis":2,"d3.svg.line":1,"d3.select":4,"d3.csv":1,"d3.keys":1,"d3.extent":1,"d3.min":2,"d3.max":2,"d3.svg.symbol":1,"d3.transition":1}},{"id":"b536ee036c8c5ef50a8e","userId":"dhoboy","description":"Seismic Ratings and Collapse Probabilities of California Hospitals","created_at":"2015-09-07T21:56:58Z","updated_at":"2015-09-08T03:08:39Z","thumbnail":"https://gist.githubusercontent.com/dhoboy/b536ee036c8c5ef50a8e/raw/307f365325e6feb1d4c30fc970c9c4762280b4da/thumbnail.png","api":{"d3.csv":1,"d3.select":2,"d3.entries":1,"d3.scale.sqrt":3,"d3.max":4,"d3.scale.quantize":3,"d3.values":1,"d3.round":1}},{"id":"0956c361a6ce22362867","userId":"dannyko","description":"Newton-Raphson Visualization (2D)","created_at":"2014-08-28T23:43:19Z","updated_at":"2015-08-29T14:05:48Z","thumbnail":"https://gist.githubusercontent.com/dannyko/0956c361a6ce22362867/raw/657be2203e082541052e5cd7470d7d89abe85f8e/thumbnail.png","api":{}},{"id":"dfe7c0c8be07a461e6ba","userId":"Golodhros","description":"TDD D3 Template","created_at":"2015-02-21T23:43:49Z","updated_at":"2015-08-29T14:15:54Z","thumbnail":"https://gist.githubusercontent.com/Golodhros/dfe7c0c8be07a461e6ba/raw/aad45945cc8ca39038fa3d2d1e1616f168250e6b/thumbnail.png","api":{"d3.dispatch":1,"d3.rebind":1,"d3.json":1,"d3.tsv":1,"d3.select":1}},{"id":"5e3c1bed7c9cdd2b431c","userId":"curran","description":"Reactive Mixins for Visualizations","created_at":"2015-10-10T02:14:52Z","updated_at":"2015-10-10T02:25:38Z","thumbnail":"https://gist.githubusercontent.com/curran/5e3c1bed7c9cdd2b431c/raw/fc695c9a588c08b79a99aebd69e5c099c1a77c0e/thumbnail.png","api":{"d3.select":1,"d3.extent":2}},{"id":"c2c7128c5226f9199f87","userId":"hwangmoretime","description":"Bar Chart Composed of Images (\"In One Chart\")","created_at":"2015-03-08T09:45:33Z","updated_at":"2015-08-29T14:16:44Z","thumbnail":"https://gist.githubusercontent.com/hwangmoretime/c2c7128c5226f9199f87/raw/70c4f171c403b97986f7ea69437595ef799a9344/thumbnail.png","api":{}},{"id":"4604711cddb0a2054886","userId":"rcrocker13","description":"2015 unconf registration","created_at":"2015-10-15T21:12:17Z","updated_at":"2015-10-15T21:44:38Z","thumbnail":"https://gist.githubusercontent.com/rcrocker13/4604711cddb0a2054886/raw/f92716f7735bca70eda82a2f392478ff16710f13/thumbnail.png","api":{}},{"id":"205c8da5ef4c95306f9b","userId":"MatthewSchumwinger","description":"gathering","created_at":"2015-09-29T01:58:21Z","updated_at":"2015-10-01T16:20:06Z","thumbnail":"https://gist.githubusercontent.com/MatthewSchumwinger/205c8da5ef4c95306f9b/raw/0b66c73fea5ea3863937007ecbc7dc1d4e5eeb3b/thumbnail.png","api":{"d3.select":13,"d3.geo.albers":1,"d3.geo.path":1,"d3.geo.graticule":1,"d3.helper.tooltip":4,"d3.selectAll":5,"d3.behavior.zoom":1,"d3.event.translate.join":1,"d3.mouse":2}},{"id":"230e1eff08ee8d6eaf35","userId":"khoomeister","description":"Map with names on mouseover","created_at":"2015-10-16T05:13:26Z","updated_at":"2015-10-16T05:24:16Z","thumbnail":"https://gist.githubusercontent.com/khoomeister/230e1eff08ee8d6eaf35/raw/cd3fb384393027972873d90eaa99d82559b9c5b8/thumbnail.png","api":{"d3.geo.kavrayskiy7":1,"d3.scale.category20":1,"d3.geo.graticule":1,"d3.geo.path":1,"d3.select":3}},{"id":"230e1eff08ee8d6eaf35","userId":"khoomeister","description":"Map with names on mouseover","created_at":"2015-10-16T05:13:26Z","updated_at":"2015-10-16T05:24:16Z","thumbnail":"https://gist.githubusercontent.com/khoomeister/230e1eff08ee8d6eaf35/raw/cd3fb384393027972873d90eaa99d82559b9c5b8/thumbnail.png","api":{"d3.geo.kavrayskiy7":1,"d3.scale.category20":1,"d3.geo.graticule":1,"d3.geo.path":1,"d3.select":3}},{"id":"a47ed061841c8e8361cb","userId":"hashcacher","description":"all-of-the-games","created_at":"2015-10-16T17:12:21Z","updated_at":"2015-10-16T17:19:07Z","thumbnail":"https://gist.githubusercontent.com/hashcacher/a47ed061841c8e8361cb/raw/b676b699fa1f9a9180ee0a02e2c9927a2b339b20/thumbnail.png","api":{"d3.format":2,"d3.scale.category20c":2,"d3.select":5,"d3.behavior.zoom":1,"d3.layout.pack":1,"d3.json":1,"d3.scale.ordinal":1,"d3.scale.linear":2,"d3.svg.axis":1,"d3.event.stopPropagation":1}},{"id":"b6bdb82045c2aa8225f5","userId":"susielu","description":"Annual Temp - New York 2015","created_at":"2015-10-14T03:50:27Z","updated_at":"2015-10-18T23:17:51Z","thumbnail":"https://gist.githubusercontent.com/susielu/b6bdb82045c2aa8225f5/raw/d4d0326e2c9be4340706aab44f79500c6f3b0135/thumbnail.png","api":{"d3.select":1,"d3.scale.linear":2,"d3.json":1,"d3.min":1,"d3.max":1,"d3.scale.ordinal":1,"d3.legend.color":1}},{"id":"b2a544536a5fb8fc5ce4","userId":"saraquigley","description":"Back where I started","created_at":"2014-09-17T18:11:20Z","updated_at":"2015-10-16T21:54:40Z","thumbnail":"https://gist.githubusercontent.com/saraquigley/b2a544536a5fb8fc5ce4/raw/9bce8e1baf01305a48f9446e8240669b4aeebe2c/thumbnail.png","api":{}},{"id":"1a9be2065a006dc3c9a5","userId":"karenpeng","description":"Clock","created_at":"2015-10-17T22:53:47Z","updated_at":"2015-10-18T02:38:48Z","thumbnail":"https://gist.githubusercontent.com/karenpeng/1a9be2065a006dc3c9a5/raw/1841c33485872df82d6e1eac833f7bf5d93d0405/thumbnail.png","api":{"d3.select":7}},{"id":"28476a3ae1297af52d95","userId":"treboresque","description":"Sierpinski Charlet","created_at":"2015-05-29T22:27:40Z","updated_at":"2015-08-29T14:22:12Z","thumbnail":"https://gist.githubusercontent.com/treboresque/28476a3ae1297af52d95/raw/729f82cc1d3ea7a487fac162cc0aef2a195a3722/thumbnail.png","api":{"d3.min":1,"d3.range":1,"d3.rgb":1}},{"id":"6c3ef6c133e8116b4254","userId":"jhellier","description":"Finding Word Patterns","created_at":"2015-10-17T00:09:44Z","updated_at":"2015-10-17T23:31:36Z","thumbnail":"https://gist.githubusercontent.com/jhellier/6c3ef6c133e8116b4254/raw/618764134b06b2a83024538dcf250c55f83fc704/thumbnail.png","api":{"d3.select":9}}]
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
svg { width: 100%; height: 100%; }
</style>
</head>
<body>
<script>
var margin = {top: 20, right: 10, bottom: 20, left: 10};
var width = 1024 - margin.left - margin.right;
var height = 968 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var nodes = [],
links = [];
var ignoreApi = ['d3.select', 'd3.selectAll'];
var force = d3.layout.force()
.size([width, height])
.charge(function(d) {return d.type === 'api' ? 5 : -Math.pow(d.size, 2)})
.linkStrength(function(d) {return d.strength})
.on('tick', update);
var circle, path, text;
function enter() {
path = svg.selectAll('line')
.data(links).enter().append('line')
.attr('stroke', '#ccc')
.attr('stroke-linecap', 'round');
circle = svg.selectAll('circle')
.data(nodes).enter().append('circle')
.attr('stroke-width', 2)
.call(force.drag);
text = svg.selectAll('text')
.data(_.filter(nodes, function(node) {return node.type === 'api';}))
.enter().append('text')
.attr('text-anchor', 'middle')
.attr('dy', '.35em')
.attr('fill', '#555')
.style({
'font-size': '12px',
'font-family': 'Helvetica',
'font-weight': 600,
'pointer-events': 'none'
});
};
function update() {
circle.attr('r', function(d) {return d.size})
.attr('fill', function(d) {return d.fill || '#fff'})
.attr('fill-opacity', function(d) {return d.type === 'api' ? .25 : 1})
.attr('stroke', function(d) {return d.stroke || 'none'})
.attr('cx', function(d) {return d.x})
.attr('cy', function(d) {return d.y});
text.attr('x', function(d) {return d.x})
.attr('y', function(d) {return d.y + 10})
.text(function(d) {return d.name});
path.attr('stroke-width', function(d) {return d.size})
.attr('x1', function(d) {return d.source.x})
.attr('y1', function(d) {return d.source.y})
.attr('x2', function(d) {return d.target.x})
.attr('y2', function(d) {return d.target.y});
};
d3.json('data.json', function(data) {
var linkStrengths = [];
var api = _.chain(data)
.pluck('api')
.map(function(api) {return _.pairs(api)})
.flatten().compact()
.filter(function(api) {return !_.contains(ignoreApi, api[0])})
.reduce(function(memo, api) {
linkStrengths.push(api[1]);
if (!memo[api[0]]) {
memo[api[0]] = 0;
}
memo[api[0]] += api[1];
return memo;
}, {})
.value();
var colors = d3.scale.category20();
var sizeScale = d3.scale.linear()
.domain([_.min(api), _.max(api)])
.range([5, 40]);
console.log(linkStrengths)
var strengthScale = d3.scale.linear()
.domain([_.min(linkStrengths), _.max(linkStrengths)])
.range([0, 1]);
var radius = 400;
var apiNodes = _.chain(api)
.map(function(count, name) {
api[name] = {
name,
size: sizeScale(count),
fill: colors(name),
fixed: true,
type: 'api'
};
return api[name];
}).sortBy(function(node) {
return -node.size;
}).map(function(node, i) {
var radian = (2 * Math.PI) / _.size(api) * i - (Math.PI / 2);
node.x = radius * Math.cos(radian) + (width / 2);
node.y = radius * Math.sin(radian) + (height / 2);
return node;
}).value();
var blockNodes = _.map(data, function(block) {
var node = {
id: block.id,
title: block.description,
user: block.userId,
image: block.thumbnail,
size: 15,
stroke: '#999'
};
_.each(block.api, function(count, apiName) {
if (_.contains(ignoreApi, apiName)) return;
links.push({
source: node,
target: api[apiName],
size: count,
strength: strengthScale(count)
});
});
return node;
});
nodes = _.union(apiNodes, blockNodes);
force.nodes(nodes).links(links)
.start();
enter();
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment