diff options
author | Peter Wu <peter@lekensteyn.nl> | 2014-06-12 17:07:34 +0200 |
---|---|---|
committer | Peter Wu <peter@lekensteyn.nl> | 2014-06-12 17:07:34 +0200 |
commit | b1262d77a3dfd57701b45a0f215314b5b3ebdd5a (patch) | |
tree | 59db9f64db0cc75d82fb4e8c33f7f65128486208 | |
parent | 0180fc32695249d471259ed67a6b0245b082b324 (diff) | |
download | d3viz-b1262d77a3dfd57701b45a0f215314b5b3ebdd5a.tar.gz |
Add visualizer for hashtags vs users brands prefs
./run-psql csv "WITH q AS ($(cat queries/userbrand.sql))
SELECT brand, lhashtag as hashtag, sum, total, percentage FROM q" > drugs.csv
-rw-r--r-- | addicted-brands.html | 77 | ||||
-rw-r--r-- | js/addicted-brands.js | 130 |
2 files changed, 207 insertions, 0 deletions
diff --git a/addicted-brands.html b/addicted-brands.html new file mode 100644 index 0000000..d8f9d9c --- /dev/null +++ b/addicted-brands.html @@ -0,0 +1,77 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<title>Addicted Brands</title> +</head> +<style> +html, body { + padding: 0; + margin: 0; +} +#legenda { display: none; } +/* +#legenda { + position: fixed; +} +#legenda span { + color: white; + width: 100px; + display: block; +} +#charts { + margin-left: 100px; +} +*/ +/* graphs and bars */ +.graph { + position: relative; + height: 200px; + background: #eee; + padding: 5px; + margin: 3px; + width: 300px; + display: inline-block; + border-radius: 16px; +} +.graph .hashtag:before { + content: '#'; +} +.graph .hashtag { + font-weight: bold; + text-shadow: #ccc -1px -1px; +} +.graph .bar { + text-align: center; + background: red; + position: absolute; + width: 40px; + bottom: 1em; + border-top-left-radius: 6px; + border-top-right-radius: 6px; +} +.graph .perc { + position: absolute; + top: -1em; +} +.graph .details { + color: white; + text-shadow: #999 0 0 9px; +} +.graph .brand { + position: absolute; + bottom: -1em; + font-size: smaller; + left: 0; +} +</style> +<link rel="stylesheet" href="svg.css"> +<body> + +<div id="legenda"></div> +<div id="charts"></div> + +<script src="lib/d3.js"></script> +<script src="js/addicted-brands.js"></script> +</body> +</html> diff --git a/js/addicted-brands.js b/js/addicted-brands.js new file mode 100644 index 0000000..69f2412 --- /dev/null +++ b/js/addicted-brands.js @@ -0,0 +1,130 @@ +/* jshint devel:true, browser:true */ +/* global d3 */ +'use strict'; + +// scaling factor to enlarge bars to fit the canvas. +var FACTOR = 9; + +function main() { + d3.csv('drugs.csv') + .row(function (d) { + return { + hashtag: d.hashtag, + brand: d.brand, + sum: +d.sum, + total: +d.total, + percentage: FACTOR * d.sum / d.total + //percentage: d.percentage / 100 + }; + }) + .get(function (errors, rows) { + if (errors) { + console.log('Failed to load CSV:', errors); + return; + } + processData(rows); + }); +} + +function processData(rows) { + // map from hashtags to a map from brands to percentages + // { hashtag: String, brands: [ { brand: String, percent: int }... ] } + var data = {}; + // values of the data map + var dataArr = []; + var brands = ['samsung', 'apple', 'htc', 'sony', 'lg', 'huawei']; + var colors = ["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c"]; + + rows.forEach(function (d) { + if (!(d.hashtag in data)) { + data[d.hashtag] = { + hashtag: d.hashtag, + brands: [] + }; + dataArr.push(data[d.hashtag]); + } + data[d.hashtag].brands.push({ + brand: d.brand, + percentage: d.percentage, + // extra details + sum: d.sum + }); + + // Find all available brands, add brand as key with dummy value + if (brands.indexOf(d.brand) < 0) { + console.log('AAAAAH! Unknown brand, adding:', d.brand); + brands.push(d.brand); + } + }); + console.log(data); + + d3.select('#legenda') + .selectAll('span') + .data(brands) + .enter() + .append('span') + .style('background', function (d, i) { + return colors[i]; + }) + .text(function (brand) { + return brand; + }); + + var graph = d3.select('#charts').selectAll('.graph') + .data(dataArr, keyFnHashtag) + .enter() + .append('div') + .attr('class', 'graph'); + + graph.append('span') + .attr('class', 'hashtag') + .text(function (d) { + return d.hashtag; + }); + + // bars! + var bar = graph.selectAll('.bar') + .data(function (d) { + return d.brands; + }) + .enter() + // bar itself + .append('div') + .attr('class', 'bar') + .text(function (d) { + return d.percent; + }) + .style('background', function (d) { + return colors[brands.indexOf(d.brand)]; + }) + .style('left', function (d) { + return (10 + 50 * brands.indexOf(d.brand)) + 'px'; + }) + .style('height', function (d) { + return (150 * d.percentage) + 'px'; + }); + // text with percentage + bar.append('span') + .attr('class', 'perc') + .text(function (d) { + return (100 * d.percentage / FACTOR).toFixed(2); + }); + // number of users mentioning this tag with this brand preference + bar.append('span') + .attr('class', 'details') + .text(function (d) { + return d.sum; + }); + // brand name + bar.append('span') + .attr('class', 'brand') + .text(function (d) { + return d.brand; + }); +} + +function keyFnHashtag(d) { + return d.hashtag; +} + +main(); |