Skip to content

Instantly share code, notes, and snippets.

@ghabs
Last active December 31, 2015 09:29
Show Gist options
  • Save ghabs/7967309 to your computer and use it in GitHub Desktop.
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…
<!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>
// 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);
}
});
});
.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;
}
[
{
"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