Title: Make Limericks Not Hate
Description: A collection of Limericks made out of the President's tweets.
link
Narrative
Needless to say, this project was super fun to work on (though frustrating at times). Here's a short description of the steps I took to make it:
- Collect a JSON with tweets with certain keywords from : http://www.trumptwitterarchive.com/
- Parse those keywords with Rita.js and break the sentences down into 8-ish syllable long strings with the keyword at the end, eg "bad" or "fake news".
- Key Words: [fake news, wall, bad, winning, loser, stupid]
- Come up with the starting lines for the limericks, because a limerick has the structure of AABBA, I chose to come up with some defaults for the first A, first B and last A, and then inject the parsed sentences into the other remaining A and B, so there would be some continuity and narrative in the limericks
- Program in Rita to construct the limerick and export as a JSON with individual limericks, I essentially mixed and matched my keywords between the A's and B's - so you could find 'news' as A and 'bad' as B and vice versa
- Program a particle system using twitter icon in Basil.js - this would serve as background for the chapter
- Randomly mix and match limericks and place into the document in Basil.
- Huzzah!
Overall, I'm happy with the results I got - in another iteration of this project I'd focus on parsing the tweets in a smarter manner, possibly using sentiment analysis or something else to understand the meaning in the tweet.
Code - Rita.js
var wall;
var stupid;
var sad;
var bad;
var news ;
var loser;
var news_st_end = ['There was once a man who was known to accuse', 'It just seemed like he was confused'];
var news_end = ["Often he'd overuse"];
var bad_st_end = ["There was once a man who was very mad","But now we know he was just a fad"];
var bad_end = ["He was often mad"];
var wall_st_end = ["There was once a man who would often bawl","But to be fair, he wasn't very tall"];
var wall_end = ["He would often call"];
var loser_st_end = ["There was once an old schmoozer","He came to be known as quite the abuser"];
var loser_end = ["He'd often doozer"];
var stupid_st_end = ["There was once a man who wasn't exactly lucid","All of his claims were later disputed"];
var stupid_end = ["He concluded"];
var winning_st_end = ["There was once a man who'd keep singing","Yeah, he was crazy from the beginning"];
var winning_end = ["He'd be grinning"];
var list = ['news', 'bad', 'wall', 'loser', 'stupid', 'winning'];
var stList = [news_st_end, bad_st_end, wall_st_end, loser_st_end, stupid_st_end, winning_st_end];
var endList = [news_end, bad_end, wall_end, loser_end, stupid_end, winning_end];
function preload(){
winning = loadStrings('trump_winning.txt');
wall = loadStrings('trump_wall.txt');
stupid = loadStrings('trump_stupid.txt');
sad = loadStrings('trump_sad.txt');
bad = loadStrings('trump_bad.txt');
news = loadStrings('trump_fake_news.txt');
loser = loadStrings('trump_loser.txt');
}
function setup()
{ var strings = [news, bad, wall, loser, stupid, winning];
createCanvas(300, 300);
background(255);
fill(255);
var json = {};
var temp;
for(var i=0; i<list.length; i++){
for(var j=0; j<list.length; j++){
if(i==j){continue;}
temp = make_limerick(strings[i], strings[j], stList[i], endList[j], list[i]+'+'+list[j]);
json[list[i]+'+'+list[j]] = temp;
}
}
saveJSON(json, 'master');
}
function draw(){
}
function make_limerick(A, B, A_st_end, B_end,name){
var lower = Math.min(A.length, B.length);
result = [];
for(var i=0; i<lower; i++){
var temp = A_st_end[0] + "," + "\n";
temp += "He'd say, " + '"' + cap_first(A[i].trim()) + '"' + "," + "\n";
temp += B_end[0] + "," + "\n";
temp += '"' + cap_first(B[i].trim()) + '"';
temp += "," + "\n";
temp += A_st_end[1] + "."
console.log(temp);
result.push(temp);
}
var txt = parse('%s.json', name);
return result;
}
function cap_first(string)
{
return string.charAt(0).toUpperCase() + string.slice(1);
}
function parse(str) {
var args = [].slice.call(arguments, 1),
i = 0;
return str.replace(/%s/g, function() {
return args[i++];
});
}
function clean_up (stuff){
var master = '';
var expression1 = /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/;
var expression2 = /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9]\.[^\s]{2,})/;
var expression3 = /(@[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)/;
var expression4 = /^[ \t]+|[ \t]+$/;
var expression5 = /a@(foo|bar|baz)\b/;
var regex1 = new RegExp(expression1);
var regex2 = new RegExp(expression2);
var regex3 = new RegExp(expression3);
var regex4 = new RegExp(expression4);
var regex5 = new RegExp(expression5);
for(var i=0; i < 100; i++){ var cur_text = stuff[i].text; var rs = new RiString(cur_text); rs.replaceAll(regex1, " "); rs.replaceAll(regex2, " "); rs.replaceAll(regex3, " "); rs.replaceAll(regex4, ""); rs.toLowerCase(); if(rs._text.search("stupid") != -1 ){ var tokens = RiTa.tokenize(rs._text); var badIndex = tokens.indexOf("stupid"); if(badIndex > 5){
tokens = tokens.slice(badIndex-10, badIndex+1);
var token_string = ''
for(var j=0; j<tokens.length; j++){
token_string += tokens[j];
token_string += ' ';
}
master+=token_string;
master+= '\n'
}
}
}
return master;
} |
var wall;
var stupid;
var sad;
var bad;
var news ;
var loser;
var news_st_end = ['There was once a man who was known to accuse', 'It just seemed like he was confused'];
var news_end = ["Often he'd overuse"];
var bad_st_end = ["There was once a man who was very mad","But now we know he was just a fad"];
var bad_end = ["He was often mad"];
var wall_st_end = ["There was once a man who would often bawl","But to be fair, he wasn't very tall"];
var wall_end = ["He would often call"];
var loser_st_end = ["There was once an old schmoozer","He came to be known as quite the abuser"];
var loser_end = ["He'd often doozer"];
var stupid_st_end = ["There was once a man who wasn't exactly lucid","All of his claims were later disputed"];
var stupid_end = ["He concluded"];
var winning_st_end = ["There was once a man who'd keep singing","Yeah, he was crazy from the beginning"];
var winning_end = ["He'd be grinning"];
var list = ['news', 'bad', 'wall', 'loser', 'stupid', 'winning'];
var stList = [news_st_end, bad_st_end, wall_st_end, loser_st_end, stupid_st_end, winning_st_end];
var endList = [news_end, bad_end, wall_end, loser_end, stupid_end, winning_end];
function preload(){
winning = loadStrings('trump_winning.txt');
wall = loadStrings('trump_wall.txt');
stupid = loadStrings('trump_stupid.txt');
sad = loadStrings('trump_sad.txt');
bad = loadStrings('trump_bad.txt');
news = loadStrings('trump_fake_news.txt');
loser = loadStrings('trump_loser.txt');
}
function setup()
{ var strings = [news, bad, wall, loser, stupid, winning];
createCanvas(300, 300);
background(255);
fill(255);
var json = {};
var temp;
for(var i=0; i<list.length; i++){
for(var j=0; j<list.length; j++){
if(i==j){continue;}
temp = make_limerick(strings[i], strings[j], stList[i], endList[j], list[i]+'+'+list[j]);
json[list[i]+'+'+list[j]] = temp;
}
}
saveJSON(json, 'master');
}
function draw(){
}
function make_limerick(A, B, A_st_end, B_end,name){
var lower = Math.min(A.length, B.length);
result = [];
for(var i=0; i<lower; i++){
var temp = A_st_end[0] + "," + "\n";
temp += "He'd say, " + '"' + cap_first(A[i].trim()) + '"' + "," + "\n";
temp += B_end[0] + "," + "\n";
temp += '"' + cap_first(B[i].trim()) + '"';
temp += "," + "\n";
temp += A_st_end[1] + "."
console.log(temp);
result.push(temp);
}
var txt = parse('%s.json', name);
return result;
}
function cap_first(string)
{
return string.charAt(0).toUpperCase() + string.slice(1);
}
function parse(str) {
var args = [].slice.call(arguments, 1),
i = 0;
return str.replace(/%s/g, function() {
return args[i++];
});
}
function clean_up (stuff){
var master = '';
var expression1 = /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/;
var expression2 = /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9]\.[^\s]{2,})/;
var expression3 = /(@[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)/;
var expression4 = /^[ \t]+|[ \t]+$/;
var expression5 = /a@(foo|bar|baz)\b/;
var regex1 = new RegExp(expression1);
var regex2 = new RegExp(expression2);
var regex3 = new RegExp(expression3);
var regex4 = new RegExp(expression4);
var regex5 = new RegExp(expression5);
for(var i=0; i < 100; i++){ var cur_text = stuff[i].text; var rs = new RiString(cur_text); rs.replaceAll(regex1, " "); rs.replaceAll(regex2, " "); rs.replaceAll(regex3, " "); rs.replaceAll(regex4, ""); rs.toLowerCase(); if(rs._text.search("stupid") != -1 ){ var tokens = RiTa.tokenize(rs._text); var badIndex = tokens.indexOf("stupid"); if(badIndex > 5){
tokens = tokens.slice(badIndex-10, badIndex+1);
var token_string = ''
for(var j=0; j<tokens.length; j++){
token_string += tokens[j];
token_string += ' ';
}
master+=token_string;
master+= '\n'
}
}
}
return master;
}
Code - Basil.js
#include "../../bundle/basil.js";
// Version for basil.js v.1.1.0
// Load a data file containing your book's content. This is expected
// to be located in the "data" folder adjacent to your .indd and .jsx.
// In this example (an alphabet book), our data file looks like:
// [
// {
// "title": "A",
// "image": "a.jpg",
// "caption": "Ant"
// }
// ]
var jsonString;
var jsonData;
//--------------------------------------------------------
function setup() {
// Load the jsonString.
jsonString = b.loadString("master.json");
// Clear the document at the very start.
b.clear (b.doc());
var offset = 0;
for(var f=0; f<25; f++){
// Make a title page.
var pageNum = 0;
b.addPage();
var birds = generateBirds();
b.fill(0,0,0);
b.textSize(30);
b.textFont("Helvetica","Bold");
b.textAlign(Justification.LEFT_ALIGN);
b.text("Build Limericks Not Walls", 100,390,450,36);
var obj = b.JSON.decode(jsonString);
var list = ['news', 'bad', 'wall', 'loser', 'stupid', 'winning'];
for(var i=0; i<6; i++){
b.textFont("Helvetica","Regular");
b.textSize(16);
var curBroadTopic = list[i];
for(var j=0; j<4; j++){
var rand = Math.floor(Math.random() * 6);
while(rand == i){
rand = Math.floor(Math.random() * 6);
}
var curSpecificTopic = curBroadTopic + "+" + list[rand];
var curValList = obj[curSpecificTopic];
var randomVal = Math.floor(Math.random() * curValList.length-1);
curVal = curValList[randomVal];
if(j%2 == 0){
b.addPage();
pageNum += 1;
moveBirds(birds,pageNum);
b.textFont("Helvetica","Bold");
var curTopicSplit = curSpecificTopic.split('+');
b.textSize(16);
b.text(curTopicSplit[0].toUpperCase(),60,60,400,100);
b.textSize(16);
b.textFont("Helvetica","Regular");
while(curVal === undefined){
var randVal = Math.floor(Math.random() * curValList.length-1);
curVal = curValList[randVal];
}
b.text(curVal,60,150,500,200);
}
else{
while(curVal === undefined){
var randVal = Math.floor (Math.random() * curValList.length-1);
curVal = curValList[randVal];
}
b.text(curVal,60,400,500,200);
}
}
offset+= 1;
// b.savePDF(f.toString());
// for(var i=0; i<13; i++){
// b.removePage();
// }
}
}
};
function randomN(seed) {
var x = Math.sin(seed++) * 10000;
return x - Math.floor(x);
}
function generateBirds(){
var birds = [];
var posx;
var posy;
for(var i=0; i<7; i++){
posx = Math.floor(randomN(i) * 436);
posy = Math.floor(randomN(1000-i) * 300);
birds.push([posx, posy]);
var angle = Math.atan((648-posy)/(432-posx));
b.pushMatrix();
b.noStroke();
b.rotate(angle);
var anImage = b.image("twit.png", posx, posy, 15, 15);
anImage.fit(FitOptions.PROPORTIONALLY);
b.opacity(anImage, 50);
b.popMatrix();
}
return birds;
}
function moveBirds(birds,pageNum){
for(var i=0; i<birds.length; i++){
var curBird = birds[i];
var posx = curBird[0]+(30*pageNum);
var posy = curBird[1]+(50*pageNum);
var angle = Math.atan((576-posy)/(400-posx));
b.pushMatrix();
b.noStroke();
b.rotate(angle);
var anImage = b.image('twit.png', posx, posy, 15, 15);
anImage.fit(FitOptions.PROPORTIONALLY);
b.opacity(anImage, 50);
b.popMatrix();
}
}
// This makes it all happen:
b.go(); |
#include "../../bundle/basil.js";
// Version for basil.js v.1.1.0
// Load a data file containing your book's content. This is expected
// to be located in the "data" folder adjacent to your .indd and .jsx.
// In this example (an alphabet book), our data file looks like:
// [
// {
// "title": "A",
// "image": "a.jpg",
// "caption": "Ant"
// }
// ]
var jsonString;
var jsonData;
//--------------------------------------------------------
function setup() {
// Load the jsonString.
jsonString = b.loadString("master.json");
// Clear the document at the very start.
b.clear (b.doc());
var offset = 0;
for(var f=0; f<25; f++){
// Make a title page.
var pageNum = 0;
b.addPage();
var birds = generateBirds();
b.fill(0,0,0);
b.textSize(30);
b.textFont("Helvetica","Bold");
b.textAlign(Justification.LEFT_ALIGN);
b.text("Build Limericks Not Walls", 100,390,450,36);
var obj = b.JSON.decode(jsonString);
var list = ['news', 'bad', 'wall', 'loser', 'stupid', 'winning'];
for(var i=0; i<6; i++){
b.textFont("Helvetica","Regular");
b.textSize(16);
var curBroadTopic = list[i];
for(var j=0; j<4; j++){
var rand = Math.floor(Math.random() * 6);
while(rand == i){
rand = Math.floor(Math.random() * 6);
}
var curSpecificTopic = curBroadTopic + "+" + list[rand];
var curValList = obj[curSpecificTopic];
var randomVal = Math.floor(Math.random() * curValList.length-1);
curVal = curValList[randomVal];
if(j%2 == 0){
b.addPage();
pageNum += 1;
moveBirds(birds,pageNum);
b.textFont("Helvetica","Bold");
var curTopicSplit = curSpecificTopic.split('+');
b.textSize(16);
b.text(curTopicSplit[0].toUpperCase(),60,60,400,100);
b.textSize(16);
b.textFont("Helvetica","Regular");
while(curVal === undefined){
var randVal = Math.floor(Math.random() * curValList.length-1);
curVal = curValList[randVal];
}
b.text(curVal,60,150,500,200);
}
else{
while(curVal === undefined){
var randVal = Math.floor (Math.random() * curValList.length-1);
curVal = curValList[randVal];
}
b.text(curVal,60,400,500,200);
}
}
offset+= 1;
// b.savePDF(f.toString());
// for(var i=0; i<13; i++){
// b.removePage();
// }
}
}
};
function randomN(seed) {
var x = Math.sin(seed++) * 10000;
return x - Math.floor(x);
}
function generateBirds(){
var birds = [];
var posx;
var posy;
for(var i=0; i<7; i++){
posx = Math.floor(randomN(i) * 436);
posy = Math.floor(randomN(1000-i) * 300);
birds.push([posx, posy]);
var angle = Math.atan((648-posy)/(432-posx));
b.pushMatrix();
b.noStroke();
b.rotate(angle);
var anImage = b.image("twit.png", posx, posy, 15, 15);
anImage.fit(FitOptions.PROPORTIONALLY);
b.opacity(anImage, 50);
b.popMatrix();
}
return birds;
}
function moveBirds(birds,pageNum){
for(var i=0; i<birds.length; i++){
var curBird = birds[i];
var posx = curBird[0]+(30*pageNum);
var posy = curBird[1]+(50*pageNum);
var angle = Math.atan((576-posy)/(400-posx));
b.pushMatrix();
b.noStroke();
b.rotate(angle);
var anImage = b.image('twit.png', posx, posy, 15, 15);
anImage.fit(FitOptions.PROPORTIONALLY);
b.opacity(anImage, 50);
b.popMatrix();
}
}
// This makes it all happen:
b.go();