Built with blockbuilder.org
Last active
April 28, 2016 22:57
openvis tweets #1
This file contains 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
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.10.0/d3-legend.js"></script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.11.2/lodash.js'></script> | |
<link href='https://fonts.googleapis.com/css?family=Lora' rel='stylesheet' type='text/css'> | |
<style> | |
body { | |
font-family: 'Lora', serif; | |
margin:0; | |
} | |
#vis { | |
width:600px; | |
height: 2400px; | |
} | |
#body { | |
height: 100%; | |
position: fixed; | |
top: 0; | |
left: 650px; | |
right: 0px; | |
overflow: scroll; | |
} | |
#legend { | |
width: 100%; | |
height: 75px; | |
} | |
.tweet { | |
padding: 10px; | |
} | |
text { | |
font-size: .8em; | |
} | |
</style> | |
</head> | |
<body> | |
<svg id='vis'></svg> | |
<div id='body'> | |
<div> | |
Tweets with #openvisconf or @openvisconf. Click on the pies to view tweets. | |
</div> | |
<svg id='legend' /> | |
<div id='title'></div> | |
<div id='content'></div> | |
</div> | |
<script> | |
d3.json('https://raw.githubusercontent.com/sxywu/fishy/master/clean-results_min.json', function(tweets) { | |
var radius = 40; | |
var width = radius * 2 + 40; | |
var take = 100; | |
var perRow = 5; | |
var color = d3.scale.ordinal() | |
.domain(['original', 'RT']) | |
.range(['#0088CC', '#F89406']); | |
var dateFormat = d3.time.format('%x %I:%M%p'); | |
// group the tweets by user, then sort and take top 100 | |
var usersSorted = _.chain(tweets.results) | |
.groupBy(function(t) { | |
t.date = new Date(t.postedTime); | |
return t.actor.preferredUsername | |
}).sortBy(function(t) {return -t.length}) | |
.take(take) | |
.map(function(t) { | |
return { | |
tweets: t, | |
username: t[0].actor.preferredUsername, | |
length: t.length | |
}; | |
}).value(); | |
// calculate the radius for each user | |
var minRadius = d3.min(usersSorted, function(d) {return d.length}); | |
var maxRadius = d3.max(usersSorted, function(d) {return d.length}); | |
var radiusScale = d3.scale.log() | |
.domain([minRadius, maxRadius]) | |
.range([radius / 4, radius]); | |
_.each(usersSorted, function(user) { | |
user.type = _.chain(user.tweets) | |
.groupBy(function(tweet) { | |
return tweet.body.match(/^RT/) || 'original' | |
}).map(function(tweets, type) { | |
return { | |
type: type, | |
tweets: tweets, | |
radius: radiusScale(user.length) | |
}; | |
}).sortBy(function(type) { | |
return type.type === 'original' ? -1 : 1; | |
}).value(); | |
}); | |
// | |
var legend = d3.legend.color() | |
.shape("circle") | |
.shapePadding(10) | |
.scale(color); | |
d3.select('#legend') | |
.append('g') | |
.attr('transform', "translate(20,20)") | |
.call(legend); | |
var content = d3.select('#content'); | |
var title = d3.select('#title'); | |
// draw pies for each user | |
var pie = d3.layout.pie() | |
.value(function(type) {return type.tweets.length}) | |
.sort(null); | |
var arc = d3.svg.arc() | |
.innerRadius(function(type) {return type.data.radius * 0.5}) | |
.outerRadius(function(type) {return type.data.radius * 0.8}); | |
var svg = d3.select('svg'); | |
var circle = svg.selectAll('g') | |
.data(usersSorted) | |
.enter().append('g') | |
.attr('transform', function(d, i) { | |
return 'translate(' + ((i % perRow) * width + width / 2) + | |
',' + (Math.floor(i / perRow) * width + width / 2) + ')' | |
}); | |
var pie = circle.selectAll('path') | |
.data(function(d) {return pie(d.type)}) | |
.enter().append('path') | |
.attr("fill", function(type) {return color(type.data.type)}) | |
.attr("d", arc) | |
.style('cursor', 'pointer') | |
.on('click', function(type) { | |
// opacity for selected pie | |
pie.attr('fill-opacity', 0.45); | |
d3.select(this) | |
.attr('fill-opacity', 1); | |
// put in the title | |
var user = type.data.tweets[0].actor.displayName; | |
var tweetLength = type.data.tweets.length; | |
var tweetType = type.data.type; | |
title.text(user + ' (' + tweetLength + ' ' + tweetType + ')'); | |
console.log(type.data) | |
// add the tweets | |
var data = content.selectAll('.tweet') | |
.data(type.data.tweets); | |
data.enter().append('div') | |
.classed('tweet', true); | |
data.exit().remove(); | |
// with the way data inheritance works | |
// it's just easier to first remove all children | |
// and then re-append them .____. | |
data.selectAll('div').remove(); | |
data.append('div') | |
.text(function(d) {return dateFormat(d.date)}); | |
data.append('div') | |
.style('cursor', 'pointer') | |
.on('click', function(d) { | |
window.open(d.link, '_new'); | |
}).text(function(d) {console.log(d); return d.body}); | |
}); | |
circle.append('text') | |
.attr('y', radius) | |
.attr('text-anchor', 'middle') | |
.attr('dy', '.35em') | |
.style('cursor', 'pointer') | |
.text(function(d) { | |
return d.username + ' (' + d.tweets.length + ')'; | |
}).on('click', function(d) { | |
window.open('http://twitter.com/' + d.username, '_new'); | |
}); | |
}); | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment