Skip to content

Instantly share code, notes, and snippets.

@tomgp
Last active March 3, 2016 19:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomgp/eb4079086278ae34844a to your computer and use it in GitHub Desktop.
Save tomgp/eb4079086278ae34844a to your computer and use it in GitHub Desktop.
Modal transport share

Icon array with emojis

A simple example of using the layout and scale functions of my d3 icon array plugin

(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-scale')) :
typeof define === 'function' && define.amd ? define(['exports', 'd3-scale'], factory) :
(factory((global.d3_iconarray = global.d3_iconarray || {}),global.d3));
}(this, function (exports,d3) { 'use strict';
function iconArrayLayout() {
var width = undefined;
var height = undefined;
var widthFirst = true;
var maxDimension = undefined;
function layout(data){
//work our missing height, width stuff
setDimensions(data.length);
return data.map(function(d,i){
return {
data:d,
position:position(i)
};
});
}
function position(i){
if(isNaN(width) || isNaN(height)){
console.log('Warning: width/height undefined')
return 0;
}
if(widthFirst){
return {
x: i % width,
y: Math.floor( i/width )
};
}else{
return {
x: Math.floor( i/height ),
y: i % height
};
}
}
function setDimensions(l){
//neither width or height is defined
if(isNaN(width) && isNaN(height)){
console.log('no width or height');
if(widthFirst){
width = Math.ceil( Math.sqrt(l) );
height = Math.ceil( l / width );
}else{
height = Math.ceil( Math.sqrt(l) );
width = Math.ceil( l / height );
}
}else if(isNaN(width)){ //width undefined
width = Math.ceil( l / height );
}else if(isNaN(height)){ //height undefined
height = Math.ceil( l / width );
}
}
layout.maxDimension = function(x){
var itemPosition = position(x);
if(widthFirst){
var x = Math.max(itemPosition.x, width);
return Math.max(x, itemPosition.y);
}
var y = Math.max(itemPosition.y, height);
return Math.max(y, itemPosition.x);
}
layout.position = function(x){
return position(x);
}
layout.width = function(x){
if(x === undefined) return width;
width = x;
return layout;
};
layout.height = function(x){
if(x === undefined) return height;
height = x;
return layout;
};
layout.widthFirst = function(b){
if(b === undefined) return widthFirst;
widthFirst = b;
return layout;
};
return layout;
};
function iconArrayScale(){
var domain = [0,100];
var range = [0,100];
var gapInterval = 10;
var gapSize = 0; //default no change
var notionalScale = d3.scaleLinear()
.domain(domain)
.range(range);
function scale(domainValue){
var rangeValue = 20;
var adjustedDomainValue = domainValue + Math.floor(domainValue/gapInterval)*gapSize;
//console.log(notionalScale.domain());
return rangeValue = notionalScale(adjustedDomainValue);
}
function rescale(){
//calculate an adjusted domain
var domainLength = (domain[1] - domain[0]) * gapSize;
var gaps = Math.ceil( domainLength/ gapInterval );
var adjustedDomain = [ domain[0], domain[1] + gaps ];
//calculate an adjusted range
notionalScale.domain(adjustedDomain)
.range(range);
}
scale.gapInterval = function(x){
if(!x) return gapInterval;
gapInterval = x;
rescale();
return scale;
};
scale.gapSize = function(x){
if(isNaN(x)) return gapSize;
gapSize = x;
rescale();
return scale;
}
scale.domain = function(array){
if(!array) return domain;
domain = array;
rescale();
return scale;
};
scale.range = function(array){
if(!array) return range;
range = array;
rescale();
return scale;
};
rescale();
return scale;
}
var version = "0.0.1";
exports.version = version;
exports.layout = iconArrayLayout;
exports.scale = iconArrayScale;
}));
<!DOCTYPE html>
<html>
<head>
<title>Transport modal share</title>
<script src="//d3js.org/d3.v4.0.0-alpha.18.min.js" charset="utf-8"></script>
<script type="text/javascript" src="d3-iconarray.js"></script>
<style type="text/css">
*{
font-family: sans-serif;
}
button{
cursor: pointer;
}
svg{display:block;}
.zero{display: none;}
text{
font-size: 20px;
}
hr{
border:none;
border-bottom: 1px solid black;
}
</style>
</head>
<body>
<h1>Modal transport share in cities with more than a million people</h1>
<div id="nav">
</div>
<hr>
<h2 id="chart-title"></h2>
<div id="viz"></div>
<p><a href="https://en.wikipedia.org/wiki/Modal_share">Source: Wikipedia</a></p>
</body>
<script type="text/javascript">
var picto = {
'walking':'🚶',
'cycling':'🚴',
'public transport':'🚌',
'private motor vehicle':'🚗'
};
var categories = ['walking', 'cycling', 'public transport', 'private motor vehicle'];
var width = 600, height = 150, margin = {top:20,left:10,bottom:0,right:10};
var layout = d3_iconarray.layout()
.height(5)
.widthFirst(false);
var xScale = d3_iconarray.scale()
.domain([0,20])
.range([0, width-(margin.left+margin.right)])
.gapSize(1)
.gapInterval(5);
var yScale = d3.scaleLinear()
.domain([0,5])
.range([0,height-(margin.top + margin.bottom)])
d3.tsv('modal-share-data.tsv',function(data){
console.log(data.columns)
d3.select('#nav').selectAll('span.city-button')
.data(data).enter()
.append('span').attr('class','city-button')
.append('button')
.html(function(d){return d.City; })
.on('click', function(d){
draw(d);
})
draw(data.find(function(d){
return (d.City == 'London');
}));
})
function draw(data){
d3.select('#chart-title').text(function(){
return data.City + ' ('+data.year+')';
});
d3.select('#viz')
.selectAll('svg')
.data(categories)
.enter()
.append('svg')
.attr('width', width)
.attr('height', height)
.attr('class','category')
.append('g')
.attr('class','plot')
.attr('transform','translate('+margin.left+','+margin.top+')')
d3.select('#viz')
.selectAll('svg')
.classed('zero', function(d){
return (data[d] == 0);
});
d3.selectAll('svg g.plot')
.call(function(parent){
var join = parent.selectAll('.icon')
.data(function(d){ return layout( expand(data[d], d) ); });
join.exit().remove();
join.enter()
.append('text').attr('class','icon');
join.attr('transform', function(d){
return 'translate(' + xScale(d.position.x) + ',' + yScale(d.position.y) + ')'
}).text(function(d){ return picto[d.data]; })
})
}
function expand(length, category){
return d3.range(0,length,1).map(function(){ return category; })
}
</script>
</html>
Country City walking cycling public transport private motor vehicle year
Australia Adelaide 3 1 10 86 2006
New Zealand Auckland 3 1 6 89 2009-2012
Spain Barcelona 35 12 33 20 2012
China Beijing 21 32 26 21 2005/2011
Germany Berlin 29 15 26 30 2012
Colombia Bogota 15 2 64 19 2008
United States Boston 14 2 35 45 2009
Australia Brisbane 4 1 14 81 2006
Belgium Brussels 25 2.5 28 43 2010
Hungary Budapest 22 2 30 46 2004
United States Chicago 6 1 27 61 2009
South Korea Daejeon 26 2 28 44 2012
United States Dallas 2 0 4 89 2009
India Delhi 21 12 48 19 2008/2011
Germany Hamburg 28 12 18 42 2008
United States Houston 2 0 4 88 2009
United States Indianapolis 2 1 2 92 2009
United States Las Vegas 3 0 3 89 2009
United Kingdom London 21 2 44 34 2011
United States Los Angeles 3 1 11 78 2009
Spain Madrid 36 0 34 30 2006
Australia Melbourne 4 2 14 80 2012
India Mumbai 27 6 52 15 2008/2011
Germany Munich 28 17 21 37 2011
United States New York City 10 1 55 29 2009
Japan Osaka 27 0 34 39 2000
France Paris 61 3 27 9 2010
Australia Perth 3 1 10 86 2006
United States Philadelphia 9 2 25 60 2009
United States Phoenix 2 1 3 88 2009
United States Portland 6 6 12 70 2009
Czech Republic Prague 23 1 43 33 2009
Italy Rome 7 0 24 68 2001
United States San Antonio 2 0 3 90 2009
United States San Diego 3 1 4 85 2009
United States San Francisco 10 3 32 46 2009
United States San Jose 2 1 3 89 2009
United States Seattle 8 3 20 63 2009
China Shanghai 27 20 33 20 2009/2011
Singapore Singapore 22 1 44 33 2011
Australia Sydney 5 1 21 74 2006
Taiwan Taipei 15 4 33 48 2009/2010
Japan Tokyo 23 14 51 12 2008/2009
Canada Toronto 7 2 34 56 2006
Austria Vienna 26 7 39 28 2014
Poland Warsaw 5 1 60 34 2009
United States Washington, D.C. 11 2 37 43 2009
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment