No matching tweets yet...
<div class="row">
<div id="plot" class="col-md-8"></div>
<div id="tweets" class="col-md-4">
<h2>Tweets</h2>
<p><i>No matching tweets yet...</i></p>
</div>
</div>
<link rel="stylesheet" type="text/css" href="demo.css">
<script src="https://cdn.pubnub.com/pubnub.min.js"></script>
<script type="text/javascript" src="demo.js"></script>
g.xaxis text, g.yaxis text {
font-size: 10pt;
}
text.xaxis-label, text.yaxis-label {
font-size: 12pt;
font-weight: bold;
}
rect.bar {
stroke: rgb(0, 0, 0);
stroke-width: 1;
}
rect.bar.Happy {
fill: rgb(49,163,84);
}
rect.bar.Sad {
fill: rgb(49,84,163);
}
rect.bar.Trump {
fill: #fe9929;
}
rect.bar.Clinton {
fill: #2c7fb8;
}
rect.bar.Perez {
fill: #c51b8a;
}
rect.bar.Ellison {
fill: #31a354;
}
rect.bar.Oscars {
fill: #ffeda0;
}
rect.bar.Moonlight {
fill: #034e7b;
}
rect.bar.La {
fill: #f768a1;
}
// Keep track of recent tweets
var TWEETS_TO_SHOW = 8;
var tweets = [];
// Keep a total count of tweets we've seen
var tweet_count = 0;
/*var word_counts = {
'Happy': 0,
'Sad': 0
};*/
// Terms we search tweets for
var word_counts = {
'Trump': 0,
'Clinton': 0,
'Perez': 0,
'Ellison': 0,
'Oscars': 0,
'Moonlight': 0,
'La La Land': 0
};
// Parameters for our plot
var svg_width = 800;
var svg_height = 800;
var left_margin = 90;
var text_height = 12;
var margin = 40;
var plot_width = svg_width - margin - left_margin;
var plot_height = svg_height - 2 * margin;
// Create the SVG
var svg = d3.select('#plot').append('svg')
.attr('width', svg_width)
.attr('height', svg_height);
// Make an x scale and axis for our term bars
var xscale = d3.scaleBand()
.paddingInner(0.3)
.paddingOuter(0.3)
.domain(Object.keys(word_counts))
.range([left_margin, left_margin + plot_width]);
var xaxis = d3.axisBottom(xscale);
// Make a y scale and axis for our percentages
var yscale = d3.scaleLinear()
.domain([0, 0.01])
.range([margin + plot_height, margin]);
var yaxis = d3.axisLeft(yscale).tickFormat(d3.format(".1%"));
// Add the x axis
svg.append('g')
.attr('class', 'xaxis')
.attr('transform', 'translate(0, ' + (margin + plot_height) + ')')
.call(xaxis);
// Add the y axis
svg.append('g')
.attr('class', 'yaxis')
.attr('transform', 'translate(' + left_margin + ', 0)')
.call(yaxis);
// Add the x axis label
svg.append('text')
.attr('class', 'xaxis-label')
.attr('transform', 'translate(' + (left_margin + plot_width/2) + ', ' + (svg_height) + ')')
.attr('text-anchor', 'middle')
.text('Term');
// Add the y axis label
svg.append('text')
.attr('class', 'yaxis-label')
.attr('transform', 'translate(' + text_height + ', ' + (margin + plot_height/2) + ') rotate(-90)')
.attr('text-anchor', 'middle')
.text('Percent of Tweets Containing Term');
// Subscribe to the PubNub twitter feed
PUBNUB.init({
subscribe_key: 'sub-c-78806dd4-42a6-11e4-aed8-02ee2ddab7fe'
}).subscribe({
channel: 'pubnub-twitter',
message: function(msg) {
// Count this tweet
tweet_count++;
// Look for our terms
var words_found = 0;
for(var key in word_counts) {
if(msg.text.toLowerCase().includes(key.toLowerCase())) {
word_counts[key]++;
words_found++;
}
}
// Did we find any matching terms? If so, update the list of matching tweets
if(words_found > 0) {
tweets.unshift(msg);
tweets = tweets.slice(0, TWEETS_TO_SHOW);
update_tweets();
}
// Update our plot every 20 tweets, or when we find one of our words
// We could update on every tweet, but that makes my browser run slowly
if(words_found > 0 || tweet_count % 20 == 0) {
update_plot();
}
}
});
function update_tweets() {
// Make a data join between <p> tags and our tweets array
var join = d3.select('#tweets').selectAll('p').data(tweets);
join.enter()
.append('p') // For new tweets, append a <p> tag
.merge(join) // For all <p> elements, set the text and opacity
.html(d => '<b>' + d.user.screen_name + ':</b> ' + d.text)
.attr('style', (d, i) => 'opacity: ' + (1 - i / TWEETS_TO_SHOW));
}
function update_plot() {
// Update our yscale
yscale.domain([0, Math.max(0.01, d3.max(Object.values(word_counts)) / tweet_count)])
.nice();
// Re-generate the y axis with our new y scale
d3.select('g.yaxis')
.transition().duration(500) // Use a transition so the y axis changes smoothly
.call(yaxis);
// Make a data join between rectangles and our word count data.
// We use the d3.entries function to transform our object:
// {'Happy': 0, 'Sad': 0} becomes [{key: 'Happy', value: 0}, {key: 'Sad', value: 0}]
var join = svg.selectAll('rect').data(d3.entries(word_counts));
join.enter() // For new bars, create a rect with zero height at the bottom of the bar chart
.append('rect')
.attr('class', d => 'bar ' + d.key)
.attr('x', d => xscale(d.key))
.attr('y', yscale(0))
.attr('height', 0)
.attr('width', xscale.bandwidth())
.merge(join) // Update *all* rects to be the right height, but use a transition
.transition().duration(500)
// Move the bar down 0.5 so the bar outline overlaps the axis line
.attr('y', d => yscale(d.value / tweet_count) + 0.5)
.attr('height', d => yscale(0) - yscale(d.value / tweet_count));
}