The 800 largest cities in the world. Compute all geodesic distances between them, feed that to t-sne et voilà.
Original work by Philippe Rivière for Visionscarto.net. Comments and variants very welcome!
(Research block at tsne world.)
forked from Fil's block: tsne world
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src='https://raw.githack.com/karpathy/tsnejs/master/tsne.js'></script>
<style>
body {
margin: 0;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
</style>
</head>
<body>
<script>
const width = 960,
height = 500,
margin = 40,
scalepop = d3.scaleSqrt().domain([0, 100000]).range([0.2, 24]),
scalecountry = d3.scaleOrdinal(d3.schemeCategory20b),
centerx = d3.scaleLinear()
.range([-height / 2 + margin, height / 2 - margin])
centery = d3.scaleLinear()
.range([margin, height - margin]);
centerz = d3.scaleLinear()
.range([-height / 2 + margin, height / 2 - margin]);
d3.csv('cities.csv', function (cities) {
const data = cities
.sort((a, b) => d3.descending(+a[2015], +b[2015]))
.map((d, i) => [+d.Longitude, +d.Latitude, d['Urban Agglomeration'], +d[2015], +d['Country Code']])
.slice(0, 800);
const canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height);
const model = new tsnejs.tSNE({
dim: 3,
perplexity: 30,
});
// initialize data with pairwise distances
const dists = data.map(d => data.map(e => d3.geoDistance(d, e)));
model.initDataDist(dists);
const forcetsne = d3.forceSimulation(
data.map(d => (d.x = width / 2, d.y = height / 2, d))
)
.alphaDecay(0.005)
.alpha(0.1)
.force('tsne', function (alpha) {
// every time you call this, solution gets better
model.step();
// Y is an array of 2-D points that you can plot
let pos = model.getSolution();
let e = performance.now()/2000,
c = Math.cos(e),
s = Math.sin(e);
centerx.domain(d3.extent(pos.map(d => d[0])));
centery.domain(d3.extent(pos.map(d => d[1])));
centerz.domain(d3.extent(pos.map(d => d[2])));
data.forEach((d, i) => {
d.x += 0.1 * (width / 2 + c * centerx(pos[i][0]) + s * centerz(pos[i][2]) - d.x);
d.y += 0.1 * (centery(pos[i][1]) - d.y);
});
})
//.force('collide', d3.forceCollide().radius(d => 0.5 + scalepop(d[3])))
.on('tick', function () {
let nodes = data.map((d, i) => {
return {
x: d.x,
y: d.y,
r: scalepop(d[3]),
color: scalecountry(d[4]),
};
});
draw(canvas, nodes);
});
function draw(canvas, nodes) {
let context = canvas.node().getContext("2d");
context.clearRect(0, 0, width, width);
for (var i = 0, n = nodes.length; i < n; ++i) {
var node = nodes[i];
context.beginPath();
context.moveTo(node.x, node.y);
context.arc(node.x, node.y, node.r, 0, 2 * Math.PI);
context.lineWidth = 0.5;
context.fillStyle = node.color;
context.fill();
}
}
});
</script>
</body>
https://d3js.org/d3.v4.min.js
https://raw.githack.com/karpathy/tsnejs/master/tsne.js