D3 WORKSHOP
DATA
DRIVEN
DOCUMENTS
“D3 is not a compatibility layer,
so if your browser doesn't support
standards, you're out of luck.
Sorry!”
CREATE YOUR OWN VISUALIZATIONS
D3 IS NOT A CHARTING LIBRARY
For basic visualizations like "bar chart"use:
highcharts
jqPlot
nvd3
...
SOURCE OF INSPIRATION
bl.ock.org
COLLISION DETECTION
see details
CHORD DIAGRAM
0k
5k
10k
15k
20k
25k
0k
5k
10k
15k
20k
0k
5k
10k
15k
20k
25k
30k
35k
40k
0k
5k
see details
FLEXIBLE TRANSITIONS
AAPL
AMZN
IBM
MSFT
see details
COOL... BUT
I STILL WANNA BAR CHART!
DATA
vardata=[3,5,1,7,9];
USAGE
barChart(data);
SIMPLE BAR CHART
CREATE HOST PAGE
<!DOCTYPEhtml>
<html>
<head>
<title>Barchart</title>
<styletype="text/css">
div{
height:100px;
background-color:green;
margin-bottom:10px;
color:white;
line-height:100px;
font-size:72px;
text-align:right;
padding-right:10px;
}
</style>
</head>
<body></body>
<scriptsrc="../lib/d3.js"charset="utf-8"></script>
<script>window.data=[3,5,1,7,9]</script>
<scriptsrc="bar.live.js"></script>
</html>
NO D3
data.forEach(function(d){
varbar=document.createElement('div');
document.body.appendChild(bar);
bar.style.setProperty('width',d*100+'px');
bar.innerText=d;
});
MIN D3
data.forEach(function(d){
d3.select('body').append('div')
.style('width',d*100+'px')
.text(d);
});
MAX D3
CREATE 3 DIVS
varbody=d3.select('body');
body.append('div');
body.append('div');
body.append('div');
MODIFY DIVS
functionbarChart(){
body.selectAll('div')
.style( 'background-color','blue')
.text( 'Hello');
}
DATA JOIN
//JOIN
varbinding=body.selectAll('div')
.data(data);
binding.style('background-color','blue')
.style('width',function(d){returnd*50+'px';})
.text(function(d){returnd;});
ENTER
//JOIN
varbinding=body.selectAll('div')
.data(data);
//ENTER
binding.enter().append('div');
UPDATE + ENTER
//JOIN
varbinding=body.selectAll('div')
.data(data);
//UPDATE
binding.style('background-color','blue')
//ENTER
binding.enter().append('div');
//ENTER+UPDATE
binding.style('width',function(d){returnd*50+'px';})
.text(function(d){returnd;});
EXIT
//JOIN
varbinding=body.selectAll('div')
.data(data);
...
//EXIT
binding.exit().remove();
GENERAL UPDATE PATTERN
functionbarChart(data){
//JOIN
varbinding=body.selectAll('div')
.data(data);
//UPDATE
binding.style('background-color','blue');
//ENTER
binding.enter().append('div');
//UPDATE+ENTER
binding.style('width',function(d){returnd*50+'px';})
.text(function(d){returnd;});
//EXIT
binding.exit().style('background-color','red').remove();
}
MORE ABOUT SELECTIONS AND JOINS
Three Little Circles
Thinkingwith Joins
How Selections Work
SCALES
Scales are functions thatmap from an inputdomainto an output
range.
learn more
SCALES
varscale=d3.scale.linear()
.domain([20,80])
.range([0,120]);
scale(50);//return60
SCALE BAR CHART
varscale=d3.scale.linear()
.domain([0,d3.max(data)])//->inelephants
.range([0,document.body.clientWidth]);//->inpx
...
//UPDATE+ENTER
binding.style('width',function(d){returnscale(d)+'px';})
.text(function(d){returnd;});
TRANSITIONS
INTERPOLATE VALUES OVER TIME
numbers
colors
geometric transforms
strings with embedded numbers (e.g., "96px")
learn more
SVG <CIRCLE>
<svgwidth="800"height="800">
<circlecx="400"cy="400"r="200"fill="blue"></circle>
</svg>
MAKE CIRCLE ALIVE
varstate1={r:100,fill:'red',cx:200,cy:200,opacity:0.5};
varstate2={r:300,fill:'blue',cx:400,cy:400,opacity:1};
varcircle=d3.select('circle');
functionapplyState(state){
circle.transition()
.duration(2500)
.ease('elastic')
.attr('r',state.r)
.attr('fill',state.fill)
.attr('cx',state.cx)
.attr('cy',state.cy)
.style('opacity',state.opacity);
}
TRANSITION DEMO
LET'S APPLY IT TO BAR CHART
//ENTER
bars.enter().append('div')
.style('width',0);
//ENTER+UPDATE
bars.text(function(d){returnd;})
.transition()
.style('width',function(d){returnscale(d)+'px';});
BREAK
DONUT CHART
SVG <PATH>
<svgwidth="190px"height="160px">
<pathd="M1080Q52.510,9580T18080"stroke="black"fill="transparent"/>
</svg>
SVG <G>
The g elementis acontainer used to group objects.
Transformations applied to the gelementare performed on allof
its child elements.
<svgwidth="250"height="100">
<circlecx="50"cy="50"r="45"/>
<gstroke="green"fill="white"transform="translate(90,0)">
<circlecx="50"cy="50"r="45"/>
<circlecx="80"cy="50"r="45"/>
</g>
</svg>
D3 LAYOUTS
Layouts are reusable algorithms thatgenerate data, notdisplay.
see more
FORCE LAYOUT
TREE LAYOUT
TREEMAP LAYOUT
CHORD LAYOUT
AND SOME MORE...
PIE LAYOUT
varpie=d3.layout.pie();
pie([20,50,100]);
/*result->
[
{"data":20,"value":20,"startAngle":5.54,"endAngle":6.28},
{"data":50,"value":50,"startAngle":3.71,"endAngle":5.54},
{"data":100,"value":100,"startAngle":0,"endAngle":3.71}
]
*/
ARC GENERATOR
vararc=d3.svg.arc().innerRadius(r/2).outerRadius(r);
arc({"startAngle":0,"endAngle":3.71});
//->"M0,-20A20,2001,1-10.76581016580034,16.85518707917385L-5.38290508290017,8.4275
DEMO DONUT CHART V.1
ADD COLORS
varcolor=d3.scale.category10();
color(0);//->"#1f77b4"
DEMO DONUT CHART V.2
ADD LABELS
//translatetoarc'scenter
text.attr('transform',function(d){
return'translate('+arc.centroid(d)+')';
})
//centerhorizontally
.attr('text-anchor','middle')
//centervertically
.attr('dy','.35em')
DEMO DONUT CHART V.3
ARC TWEEN
see details
DEMO DONUT CHART V.4
BREAK
Original:
LET'S DRAW BELARUS
Let’s Make aMap
FINDING DATA SOURCES
Government;)
GeoCommons
NaturalEarthData
States, Provinces
Populated Places
NATURAL EARTH
ESRI SHAPEFILE
Popular geospatialvector dataformatfor geographic
information system software.
Binary
Bunch of files (*.dbf, *.shp, ...)
Notin JSON:)
GEOJSON
{
"type":"FeatureCollection",
"features":[{
"type":"Feature",
"properties":{},
"geometry":{
"type":"Polygon",
"coordinates":[
[
[27.4603271484375,53.92698552779884],
[27.5537109375,53.97870483500941],
[27.740478515625,53.930219863940025],
[27.696533203125,53.81038242731128],
[27.4932861328125,53.80713881129993],
[27.4603271484375,53.92698552779884]
]
]
}
}]
}
Learn more...
TOPOJSON
Extension of GeoJSONthatencodes topology.
Join shared lines into arcs.
BENEFITS:
smaller size (80%smaller)
automatic mesh generation
TOPOJSON
{
"type":"Topology",
"objects":{
"collection":{
"type":"GeometryCollection",
"geometries":[{
"type":"Polygon",
"arcs":[
[0]
]
}]
}
},
"arcs":[
[
[0,6985],
[3333,3014],
[6666,-2826],
[-1568,-6984],
[-7255,-189],
[-1176,6985]
]
],
"transform":{
"scale":[0.000028017938512601262,0.00001715831820276837],
"translate":[27.4603271484375,53.80713881129993]
},
"bbox":[27.4603271484375,53.80713881129993,27.740478515625,53.97870483500941]
INSTALLING TOOLS
GDAL/OGR2OGR
TOPOJSON
HTTP SERVER
GDAL/OGR2OGR
UBUNTU
add-apt-repositoryppa:ubuntugis/ppa
apt-getupdate
apt-getinstallgdal-bin
GDAL/OGR2OGR
MAC
brewinstallgdal
GDAL/OGR2OGR
WIN
gdal.msi
TOPOJSON
npminstall–gtopojson
HTTP SERVER
npminstall–ghttp-server
CONVERTING TO GEOJSON
ogr2ogr
-fGeoJSON
-where"iso_a2='BY'"
states.geojson
ne_10m_admin_1_states_provinces.shp
ogr2ogr
-fGeoJSON
-where"iso_a2='BY'"
places.geojson
ne_10m_populated_places.shp
ISO 3166-1 alpha-2
CONVERTING TO TOPOJSON
topojson
--id-propertyiso_3166_2
-pname=NAME
-pname
-obelarus.topojson
states.geojson
places.geojson
ISO 3166-2
LOADING DATA
d3.json('belarus.topojson',function(error,data){
console.log(data);
}
SVG VS CANVAS
D3 supportboth of them.
DEMO MAP V.1
CONVERTING TOPOJSON BACK TO GEOJSON
varstates=topojson.feature(data,data.objects.states);
PROJECTION DEMO
see details
PROJECTION
varprojection=d3.geo.mercator()
.translate([400,400])
.rotate([-27.55,0])
.center([0,53.916667])
.scale(2200);
GEO PATH GENERATOR
varpath=d3.geo.path()
.projection(projection);
DEMO MAP V.2
DRAWING BOUNDARIES
varmesh=topojson.mesh(
belarus,belarus.objects.states,
function(a,b){returna!==b;}
);
svg.append('path')
.datum(mesh)
.attr('d',path)
.attr('class','state-boundary');
DRAWING PLACES
POINTS
varplaces=topojson.feature(data,data.objects.places);
//POINTS
svg.append('path')
.datum(places)
.attr('d',path)
.attr('class','place-point');
DRAWING PLACES
LABELS
//LABELS
svg.selectAll('.place-label')
.data(places.features)
.enter().append('text')
.attr('class',function(d){
return'place-label'+d.properties.name;
})
.attr('transform',function(d){
return'translate('+projection(d.geometry.coordinates)+')';
})
.attr('dy',function(d){
if(d.properties.name==='Maladzyechna'){
return'-0.35em'
}
return'.35em';
})
.attr('dx',7)
.text(function(d){returnd.properties.name;});
DEMO MAP V.3
HELPFUL TOOLS
MapShaper
GeoJSON.IO
QGIS
BYE BYE

D3 workshop