Last active
December 31, 2015 09:29
-
-
Save ghabs/7967309 to your computer and use it in GitHub Desktop.
This is a small program I wrote when I was interested in exploring my text message data and visualizing the frequency. It loads data from a JSON file, creates a scatterplot, and calls an external sentiment API to see if the messages were positive or negative. You can see it ‘live’ here: hsapp.s3-website-us-east-1.amazonaws.com (Firefox only, sin…
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> | |
<html lang="en"> | |
<meta charset="utf-8"> | |
<head> | |
<!-- JS --> | |
<script src="jquery.js"></script> | |
<script type="text/javascript" src="underscore.js"></script> | |
<script type="text/javascript" src="d3.v3.js"></script> | |
<script type="text/javascript" src="main.js"></script> | |
<!-- CSS --> | |
<link rel="stylesheet" type="text/css" href="bootstrap.css"> | |
<link rel="stylesheet" type="text/css" href="style.css"> | |
</head> | |
<body> | |
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation"> | |
<div class="container"> | |
<div class="navbar-header"> | |
<div class="navbar-brand">Text Dashboard</div> | |
</div> | |
<div class="navbar-form navbar-left" role="search"> | |
<input type="text" id = "search" placeholder="Search for Name"> | |
</div> | |
</div> | |
</div> | |
<div class="container"> | |
<div class="row"> | |
<div class="row"> | |
<div class="col-md-4"> | |
<div class="sidebar-offcanvas" id="sidebar" role="navigation"> | |
<div id="list" class="list-group"></div> | |
</div> | |
</div> | |
<div class="col-md-8"> | |
<div id="dash"></div> | |
<ul id="messages"></ul> | |
</div> | |
</div> | |
</div> | |
</div> | |
</body> | |
</html> |
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
// Global Variables | |
var json; | |
/** | |
* Lib Utilities | |
**/ | |
function forEach(array, action) { | |
for (var i = 0; i < array.length; i++) | |
action(array[i]); | |
} | |
function add(a, b) { | |
return a + b; | |
} | |
function reduce(combine, base, array) { | |
forEach(array, function (element) { | |
base = combine(base, element); | |
}); | |
return base; | |
} | |
function sum(numbers){ | |
return reduce(add, 0, numbers); | |
} | |
function average(array) { | |
var total = array.length | |
return (sum(array) / total) | |
} | |
/* | |
*loads in data from json file, stores it in global variable, and | |
*calls the dashboard function | |
*/ | |
function loadData (url){ | |
$.getJSON(url) | |
.done(function(data){ | |
json = data; | |
dash(data); | |
}) | |
} | |
// Iterates through JSON file and lists out contacts | |
function dash (data) { | |
for (var i = data.length - 1; i >= 0; i--) { | |
$('#list').append('<p><a class="list-group-item">' + data[i].contact_name); | |
} | |
} | |
//after person is clicked or searched for, will find it in json | |
function loadPerson (name) { | |
var person = _.findWhere(json, {contact_name: name}); | |
$('#messages').empty(); | |
$('#dash').empty().append(name); | |
$('#dash').append('<p>Average Message Length (in chars): ' + average(lengthMessage(person))); | |
textDateGraph(yMessage(person.messages)); | |
appendMessages(person); | |
} | |
//Gets the length of each message | |
function lengthMessage (person) { | |
var newArray = person.messages; | |
var lengthArray = []; | |
for (var i = newArray.length - 1; i >= 0; i--) { | |
lengthArray.push(newArray[i].content.length); | |
} | |
return lengthArray; | |
} | |
//sorts and calls api | |
function appendMessages (person) { | |
var newArray = person.messages; | |
newArray = newArray.sort(function(a, b){ | |
var dOne = new Date(a.date), dTwo=new Date(b.date); | |
return dOne-dTwo; | |
}); | |
for (var i = newArray.length - 1; i >= 0; i--) { | |
apiCall(newArray[i].content, newArray[i].date) | |
} | |
} | |
//makes a call to sentiment processing api | |
function apiCall (content, date) { | |
$.ajax({ | |
url: 'https://japerk-text-processing.p.mashape.com/sentiment/', // The URL to the API. You can get this by clicking on "Show CURL example" from an API profile | |
type: 'POST', | |
data: {text: content}, | |
datatype: 'json', | |
success: function(data) { | |
var parsed = $.parseJSON(data) | |
newAppend(content, parsed, date); | |
}, | |
error: function(err) { alert(err); }, | |
beforeSend: function(xhr) { | |
xhr.setRequestHeader('X-Mashape-Authorization', 'HZAMZr7fzsph5GrAA6t4stN2AUbCYnjH'); // Enter here your Mashape key | |
} | |
}); | |
} | |
function newAppend (content, msg, date) { | |
$('#messages').append('<h5>' + content); | |
$('#messages').append('<li>' + date); | |
$('#messages').append('<li> Sentiment: ' + msg.label + "<hr>"); | |
} | |
/* | |
Extracts list of dates and counts the number that happened on same day | |
*/ | |
function yMessage (arr) { | |
var seen = {}; | |
var arrDates = _.pluck(arr, 'date'); | |
for (var i = 0; i < arrDates.length; i++ ) { | |
var n = arrDates[i]; | |
seen[n] = seen[n] ? seen[n] + 1 : 1; | |
} | |
return _.pairs(seen); | |
} | |
// Creates Chart of Message Frequency | |
function textDateGraph(dataset) { | |
var padding = 60, | |
width = 800, | |
height = 350, | |
minDate = new Date([dataset[0][0]]), | |
maxDate = new Date([dataset[dataset.length-1][0]]), | |
xScale = d3.time.scale().domain([minDate, maxDate]).range([padding, width - padding]), | |
yScale = d3.scale.linear().domain([0, d3.max(dataset, function(d) { return d[1]; })]) | |
.range([height - padding, padding]); | |
var xAxis = d3.svg.axis() | |
.orient('bottom') | |
.scale(xScale) | |
.tickFormat(d3.time.format('%d %B')); | |
var yAxis = d3.svg.axis() | |
.orient('left') | |
.scale(yScale); | |
//Create SVG element | |
var svg = d3.select('#dash') | |
.append('svg') | |
.attr('width', width) | |
.attr('height', height); | |
svg.append('g') | |
.attr('transform', 'translate('+ padding +',0)') | |
.attr('class', 'axis') | |
.call(yAxis); | |
svg.append('g').attr('class', 'xaxis axis') // two classes, one for css formatting, one for selection below | |
.attr('transform', 'translate(0,' + (height - padding)+ ')') | |
.call(xAxis) | |
.selectAll("text") | |
.style("text-anchor", "end") | |
.attr("dx", "-.8em") | |
.attr("dy", ".15em") | |
.attr("transform", function(d) { | |
return "rotate(-65)" | |
}); | |
svg.selectAll('circle') | |
.data(dataset) | |
.enter() | |
.append('circle') | |
.attr('cx', function(d) { return xScale(new Date(d[0])); }) | |
.attr('cy', function(d) { return yScale(d[1]); }) .attr('r', 3.5); | |
} | |
//On load sets up list of contacts and search | |
$(document).ready(function() | |
{ | |
loadData('test.json'); | |
$('#list').on('click','p', function(){ | |
var name = $(this).find('a.list-group-item').text(); | |
loadPerson(name); | |
}); | |
$('#search').keypress(function (e) { | |
if (e.keyCode == 13) { | |
var search = $("#search").val(); | |
loadPerson(search); | |
} | |
}); | |
}); |
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
.axis path, | |
.axis line { | |
fill: none; | |
stroke: black; | |
shape-rendering: crispEdges; | |
} | |
.axis text { | |
font-family: sans-serif; | |
font-size: 11px; | |
} | |
body { | |
padding-top: 70px; | |
} | |
#search { width: 200px; } | |
/* | |
* Off Canvas | |
* -------------------------------------------------- | |
*/ | |
.row-offcanvas-left | |
.sidebar-offcanvas { | |
left: -50%; /* 6 columns */ | |
} | |
.row-offcanvas-left.active { | |
left: 50%; /* 6 columns */ | |
} | |
.sidebar-offcanvas { | |
position: absolute; | |
top: 0; | |
width: 25%; /* 6 columns */ | |
height: 100%; | |
} | |
#list { | |
height: 100%; | |
margin-top: 70px; | |
} |
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
[ | |
{ | |
"contact_name": "Joanna Smith", | |
"phone_number": "+15555551", | |
"messages": [ | |
{ | |
"content": "Hahah also have class until 7 ugh! And I'd say Wednesday but I never know if have work.", | |
"date": "01\/01\/13" | |
}, | |
{ | |
"content": "Sorry! Busy school/work/teaching schedule. How about Saturday?", | |
"date": "01\/01\/13" | |
}, | |
{ | |
"content": "Cool! See you then!", | |
"date": "01\/01\/13" | |
}, | |
{ | |
"content": "Where are you?", | |
"date": "01\/04\/13" | |
}, | |
{ | |
"content": "Lets definitely go to the movies after", | |
"date": "01\/04\/13" | |
}, | |
{ | |
"content": "Hey I'm in back!", | |
"date": "01\/05\/13" | |
}, | |
{ | |
"content": "By the table with the wooden gnome", | |
"date": "01\/05\/13" | |
} | |
] | |
}, | |
{ | |
"contact_name": "John Smith", | |
"phone_number": "+15555552", | |
"messages": [ | |
{ | |
"content": "Can you still talk tonight?", | |
"date": "01\/03\/13" | |
}, | |
{ | |
"content": "Sounds good", | |
"date": "01\/03\/13" | |
}, | |
{ | |
"content": "Looks like Stein and Merill bought after reading our email", | |
"date": "01\/04\/13" | |
} | |
] | |
}, | |
{ | |
"contact_name": "Jenny Smith", | |
"phone_number": "+15555552", | |
"messages": [ | |
{ | |
"content": "How was that burger?", | |
"date": "01\/03\/13" | |
}, | |
{ | |
"content": "I didn't like mine, kind of gross", | |
"date": "01\/04\/13" | |
}, | |
{ | |
"content": "Ok a restaurant sounds good!", | |
"date": "01\/03\/13" | |
}, | |
{ | |
"content": "Too greasy, would not go back", | |
"date": "01\/04\/13" | |
}, | |
{ | |
"content": "I'll see you soon!", | |
"date": "01\/08\/13" | |
} | |
] | |
} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment