TBC!
One of a set of hierarchical charts I have written for the dc.js library.
Data from https://unstats.un.org/
xxxxxxxxxx
<html lang="en">
<head>
<title>dc.js - Pack Layout Example</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/dc/3.0.6/dc.min.css"/>
<style>
.oversize { display: none }
.pack-element { stroke: black; stroke-width: 0.5px }
svg text { font-size: 10px; stroke: none }
select {
margin-bottom: .25rem;
}
label {
display: block;
}
.chart-div {
margin-right: 20px;
}
.chart-div.pie {
width: 280px;
}
.page {
margin: 0 5rem;
}
</style>
</head>
<body>
<div class="page">
<h2>dc.js Pack Layout Implementation</h2>
<div id="test"></div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter2/1.4.6/crossfilter.min.js"></script>
<script type="text/javascript" src="dc.min.js"></script>
<script type="text/javascript">
function add_chart ( id, title, ctype, div_class ) {
if ( ! ctype ) ctype = id
if ( ! title ) title = id
if ( ! div_class ) div_class = ''
d3.select('#test')
.append('div')
.classed('chart-div ' + div_class, true)
.attr('id', id)
.append('h4')
.text( title );
return dc[ctype + 'Chart']('#' + id );
}
var tr = {
global: 'Global Name',
region: 'Region Name',
subregion: 'Sub-region Name',
intermed_region: 'Intermediate Region Name',
country: 'Country or Area',
ldc: 'Least Developed Countries (LDC)',
lldc: 'Land Locked Developing Countries (LLDC)',
sids: 'Small Island Developing States (SIDS)',
dev: 'Developed / Developing Countries'
},
popstats_tr = {
year: 'Year',
country: 'Country / territory of asylum/residence',
location: 'Location Name',
female_0_4: 'Female 0-4',
female_5_11: 'Female 5-11',
female_5_17: 'Female 5-17',
female_12_17: 'Female 12-17',
female_18_59: 'Female 18-59',
female_60: 'Female 60+',
f_unknown: 'F: Unknown',
f_total: 'F: Total',
male_0_4: 'Male 0-4',
male_5_11: 'Male 5-11',
male_5_17: 'Male 5-17',
male_12_17: 'Male 12-17',
male_18_59: 'Male 18-59',
male_60: 'Male 60+',
m_unknown: 'M: Unknown',
m_total: 'M: Total',
ppl_total: 'Total number of people'
}
Promise.all([
d3.csv('countries-regions.csv', function (d) {
return {
global: d['Global Name'],
region: d['Region Name'],
subregion: d['Sub-region Name'],
intermed_region: d['Intermediate Region Name'],
country: d['Country or Area'],
};
}),
d3.csv('unhcr_popstats_export_demographics_all_data.csv', function (d) {
return {
year: +d['Year'],
country: d['Country / territory of asylum/residence'],
location: d['Location Name'],
// female_0_4: +d['Female 0-4'],
// female_5_11: +d['Female 5-11'],
// female_5_17: +d['Female 5-17'],
// female_12_17: +d['Female 12-17'],
// female_18_59: +d['Female 18-59'],
// female_60: +d['Female 60+'],
// f_unknown: +d['F: Unknown'],
f_total: +d['F: Total'],
// male_0_4: +d['Male 0-4'],
// male_5_11: +d['Male 5-11'],
// male_5_17: +d['Male 5-17'],
// male_12_17: +d['Male 12-17'],
// male_18_59: +d['Male 18-59'],
// male_60: +d['Male 60+'],
// m_unknown: +d['M: Unknown'],
m_total: +d['M: Total']
};
})
])
.then( function(data) {
var cntrls = {}
var padding = d3.select('#test').append('div')
padding.append('label')
.attr('for', 'padding')
.text('padding value');
padding
.append('text')
.text(' 0 ');
cntrls['padding'] = padding
.append('input')
.attr('type', 'range')
.attr('name', 'pad')
.attr('id', 'padding')
.attr('min', 0)
.attr('max', 10)
.attr('value', 0)
padding
.append('text')
.text(' 10 ');
var chart_ix = {};
var loc_ix = {}
data[0].forEach( c => loc_ix[c.country] = c );
var alt_names = {
'Serbia and Kosovo (S/RES/1244 (1999))': 'Serbia',
'Swaziland': 'Eswatini',
'Bonaire': "Bonaire, Sint Eustatius and Saba",
'United Kingdom': 'United Kingdom of Great Britain and Northern Ireland'
}
var get_country = function (c) {
if ( loc_ix[c] ) {
return c;
}
else if ( alt_names[c] ) {
return alt_names[c];
}
console.log(c);
}
var ndx = crossfilter( data[1].filter( d => d.year !== 2017 ) ),
xf_dim = {
country: ndx.dimension( d => {
var c = get_country(d.country)
d.global = loc_ix[c].global ? loc_ix[c].global : 'World'
d.region = loc_ix[ c ].region ? loc_ix[ c ].region : 'unspecified'
d.subregion = loc_ix[c].subregion ? loc_ix[c].subregion : 'unspecified'
d.ppl_total = d.f_total + d.m_total
return [ d.global, d.region, d.subregion, d.country ]
}),
m_total: ndx.dimension( d => d.m_total ),
f_total: ndx.dimension( d => d.f_total ),
ppl_total: ndx.dimension( d => d.ppl_total ),
year: ndx.dimension( d => d.year ),
region: ndx.dimension( d => d.region )
}
chart_ix.pack = add_chart( 'pack', "UNHCR's populations of concern by geolocation, 2010-2016", 'pack');
chart_ix.row = add_chart( 'row', 'Region' );
var pies = [ 'year' ]
pies.forEach( n => chart_ix[n] = add_chart( n, tr[n], 'pie', 'pie' ) )
var i = 0;
// set up colour scales
var num = xf_dim.region.group().top(Infinity).map( () => ++i )
var spectral = d3.schemeSpectral[num.length]
var spectralite = d3.schemeSpectral[num.length].map( x => d3.color(x).darker(0.2).hex() )
var colDomain = xf_dim.region.group().top(Infinity).map( x => x.key )
.concat(
xf_dim.region.group().top(Infinity).map( x => '_' + x.key ),
xf_dim.region.group().top(Infinity).map( x => '__' + x.key ),
[ 'World', '_undefined' ] )
var specscale = d3.scaleOrdinal().domain( colDomain )
.range( spectral.concat(
d3.schemeSpectral[num.length].map( x => d3.color(x).darker(0.1).hex()),
d3.schemeSpectral[num.length].map( x => d3.color(x).darker(0.2).hex()),
[ '#999', 'none' ]
) )
var colorAcc = function (d) {
var key = (d.key[3] ? '' : d.key[2] ? '_' : '__') + d.key[1]
if ( d.key[1] === undefined || d.key[1] === 'unspecified') {
return d.key[0]
}
return key
}
chart_ix.pack
.width(800)
.height(800)
.dimension(xf_dim.country)
.group( xf_dim.country.group().reduceSum( d => d.ppl_total ) )
.colors( specscale )
.colorAccessor( colorAcc )
chart_ix.row
.width(500)
.height(300)
.colorAccessor( function(d){ return specscale( d.key ) })
.colors( specscale )
.dimension(xf_dim.region)
.group(xf_dim.region.group())
.legend(dc.legend())
var year_cols = d3.scaleOrdinal()
.domain( ndx.dimension( d => d.year ).group().top(Infinity).map( d => d.key ).sort( (a,b) => a-b ) )
.range( d3.schemeGnBu[7] )
pies.forEach( function(p) {
chart_ix[p]
.width(280)
.height(250)
.innerRadius(25)
.dimension(xf_dim[p])
.group(xf_dim[p].group().reduceSum( d => d.ppl_total ) )
.drawPaths(true)
.externalRadiusPadding(50)
.externalLabels(25)
.legend(dc.legend())
.ordering(dc.pluck('year'))
.colorAccessor(dc.pluck('key'))
.colors(year_cols)
})
dc.renderAll();
cntrls.padding.on('change', function (e) {
chart_ix.pack.layout.padding( this.value ).redraw();
});
});
</script>
</div>
</body>
</html>
https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js
https://cdnjs.cloudflare.com/ajax/libs/crossfilter2/1.4.6/crossfilter.min.js