In an attempt to encode as much information on screen at the same time while using as many different kinds of scales and symbols, I have created this scatterplot masterpiece.
This scatterplot uses:
People placed on scatterplot by age and income.
Most of the data here is made up.
xxxxxxxxxx
<html>
<head>
<title>D3 in Action Chapter 6 - Example 1</title>
<meta charset="utf-8" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="superformula.js" type="text/JavaScript"></script>
<script src="chernoff.js" type="text/JavaScript"></script>
</head>
<style>
svg {
height: 850px;
width: 900px;
border: 1px solid gray;
}
g.am-axis text {
font-size: 8px;
}
.domain {
fill: none;
}
.tick > line{
stroke: black;
stroke-width: 1px;
stroke-opacity: .25;
}
g.face > path {
fill: white;
stroke: black;
stroke-width: 1px;
}
</style>
<body>
<div id="viz">
<svg>
</svg>
</div>
Shirt icon from Megan Mitchell via the Noun Project
<div/>
</body>
<footer>
<script>
var face = d3.chernoff()
.face(function(d) { return (Math.random() * 0.25) + 0.75 })
.hair(-1)
.mouth(function(d) { return happinessScale(d.happiness) })
.nosew(function(d) { return (Math.random() * 0.25) + 0.75 })
.noseh(function(d) { return (Math.random() * 0.25) + 0.75 })
.eyew(function(d) { return (Math.random() * 0.25) + 0.75 })
.eyeh(function(d) { return (Math.random() * 0.25) + 0.75 })
.brow(function(d) { return (Math.random() * 0.25) - 0.5 });
dataset = [
{label: "Susie", happiness: 95, fashion: 20, salary: 95000, age: 22, city: "San Francisco", industry: "Tech", exercise: 90},
{label: "Randy", happiness: 75, fashion: 1, salary: 15000, age: 7, city: "San Francisco", industry: "Entertainment", exercise: 200},
{label: "Sheila", happiness: 15, fashion: 750, salary: 45000, age: 41, city: "Rio", industry: "Sales", exercise: 130},
{label: "Nathan", happiness: 50, fashion: 50, salary: 220000, age: 40, city: "Timbuktu", industry: "Crime", exercise: 300},
{label: "Porsche", happiness: 1, fashion: 150, salary: 70000, age: 53, city: "Mumbai", industry: "Space Exploration", exercise: 0},
{label: "Jafar", happiness: 60, fashion: 100, salary: 60000, age: 84, city: "Jakarta", industry: "Administration", exercise: 10},
{label: "Rigel", happiness: 20, fashion: 100, salary: 50000, age: 74, city: "Beijing", industry: "Education", exercise: 120},
{label: "Prim", happiness: 30, fashion: 800, salary: 20000, age: 24, city: "San Francisco", industry: "Tech", exercise: 300},
{label: "Roy", happiness: 50, fashion: 500, salary: 20000, age: 28, city: "Atlanta", industry: "Crime", exercise: 200},
{label: "Tim", happiness: 5, fashion: 10, salary: 200000, age: 54, city: "New York", industry: "Tech", exercise: 0},
{label: "Sully", happiness: 100, fashion: 50, salary: 50000, age: 39, city: "Alexandria", industry: "Entertainment", exercise: 400},
{label: "Hal", happiness: 40, fashion: 110, salary: 150000, age: 29, city: "Jakarta", industry: "Service", exercise: 40},
{label: "Pip", happiness: 66, fashion: 180, salary: 180000, age: 45, city: "New York", industry: "Sales", exercise: 60},
{label: "Cicero", happiness: 68, fashion: 660, salary: 90000, age: 80, city: "Mumbai", industry: "Space Exploration", exercise: 80},
{label: "Leonard", happiness: 43, fashion: 680, salary: 45000, age: 55, city: "Alexandria", industry: "Construction", exercise: 150},
{label: "Aditi", happiness: 22, fashion: 300, salary: 86000, age: 55, city: "Beijing", industry: "Art", exercise: 10},
{label: "Jie", happiness: 10, fashion: 25, salary: 110000, age: 18, city: "Atlanta", industry: "Art", exercise: 50},
];
cities = ["San Francisco", "New York", "Atlanta", "Rio", "Beijing", "Paris", "Mumbai", "Timbuktu", "Alexandria", "Jakarta"];
industries = ["Tech", "Service", "Entertainment", "Construction", "Administration", "Sales", "Education", "Art", "Crime", "Space Exploration"]
exerciseValues = dataset.map(function (d) {return d.exercise});
happinessScale = d3.scale.linear().domain([1,100]).range([-1,1]);
ageScale = d3.scale.linear().domain([1,100]).range([0,800]);
fashionScaleN3 = d3.scale.linear().domain([20,200,1000]).range([2,-8,-8]).clamp(true);
fashionScaleN2 = d3.scale.linear().domain([20,200,1000]).range([2,1,-1]).clamp(true);
fashionScaleN1 = d3.scale.linear().domain([20,200,1000]).range([2,0.8,10]).clamp(true);
fashionScaleM = d3.scale.linear().domain([20,200,1000]).range([4,1,8]).clamp(true);
salaryScale = d3.scale.linear().domain([0,250000]).range([800,0]).clamp(true);
cityScale = d3.scale.category20c().domain(cities);
industryScale = d3.scale.category20b().domain(industries);
exerciseScale = d3.scale.quantile().domain(exerciseValues)
.range(["#d73027","#fc8d59","#fee08b","#ffffbf","#d9ef8b","#91cf60","#1a9850"]);
xAxis = d3.svg.axis().scale(ageScale).orient("bottom").tickSize(800).ticks(4);
d3.select("svg").append("g").attr("id", "xAxisG").call(xAxis);
yAxis = d3.svg.axis().scale(salaryScale).orient("right").ticks(10).tickSize(800).tickSubdivide(10);
d3.select("svg").append("g").attr("id", "yAxisG").call(yAxis);
d3.select("svg").selectAll("g.people").data(dataset)
.enter()
.append("g")
.attr("class", "people");
people = d3.selectAll("g.people");
people
.attr("transform", function(d) {return "translate(" + (ageScale(d.age) - 21) + "," + (salaryScale(d.salary) - 60) + ")"})
people
.append("path")
.style("fill", function (d) {return cityScale(d.city)})
.attr("transform", "translate(20,48)")
.attr("d", "m 34.356212,6.8922268 c -0.0033,-0.0074 -0.0056,-0.0122 -0.01064,-0.02037 -0.03993,-0.07659 -0.07171,-0.137708 -0.103488,-0.194748 0.01549,0.02771 0.02852,0.05296 0.044,0.08067 -0.740694,-1.410493 -1.482202,-2.820988 -2.231045,-4.2274097 -1.819547,-3.42071617 -3.626057,-6.8789144 -5.709614,-10.1513306 -3.13878,-4.9306225 -8.874469,-5.7348725 -13.974579,-3.6651695 -3.3107122,1.3428639 -9.0195112,7.5584964 -11.48278516,7.5584964 -2.46246014,0 -7.92680614,-6.2156325 -11.23833284,-7.5584964 -5.080555,-2.06237 -10.766538,-1.246711 -13.891465,3.6651695 -2.084372,3.2724162 -3.890067,6.73061443 -5.712874,10.1513306 -0.767584,1.4447197 -1.528647,2.8926977 -2.289713,4.3406767 -0.456312,0.870254 -1.009591,1.583241 -0.620911,2.596909 0.62417,1.6247992 2.178894,2.9318092 3.574722,3.8827322 1.656579,1.127745 3.678208,2.052594 5.722651,1.99148 0.357718,-0.01142 1.342049,-0.01393 1.575094,-0.330013 0.324308,-0.43594 0.589947,-0.924848 0.870253,-1.390123 1.193749,-1.980073 2.35979,-3.9772562 3.525017,-5.9752542 -1.35264,9.5866442 -2.526016,19.2001762 -3.527461,28.8291912 -0.440829,4.238005 -0.852326,8.4809 -1.131818,12.730312 -0.152384,2.310899 -0.214305,1.654949 -0.09534,2.506462 0.123861,0.875957 1.090262,1.17419 1.86192,1.375457 2.04363,0.532908 14.2980731,1.219822 21.47359184,1.219822 7.16492496,0 19.56441116,-0.686914 21.60804116,-1.219822 0.770028,-0.200452 1.655764,-0.514167 1.861918,-1.375457 0.148301,-0.624986 0.05622,-0.195563 -0.09534,-2.506462 -0.280306,-4.249412 -0.692618,-8.492307 -1.132633,-12.730312 -1.001444,-9.6282 -2.174821,-19.242547 -3.527462,-28.8291912 1.166858,1.997184 2.330456,3.9951812 3.525831,5.9752542 0.281122,0.465275 0.545132,0.953368 0.86781,1.390123 0.235489,0.31616 1.217378,0.318605 1.578353,0.330013 2.044445,0.06112 4.064443,-0.863735 5.721022,-1.99148 1.395829,-0.950923 2.952181,-2.257933 3.576352,-3.8827322 0.386236,-1.005519 -0.154825,-1.715249 -0.611134,-2.575723 z m -58.346109,6.9954382 c -0.361792,0.527204 -2.253045,-0.144232 -4.223338,-1.498498 -1.971108,-1.355087 -3.27486,-2.8796612 -2.913068,-3.4068642 0.363419,-0.52639 2.254674,0.144232 4.224152,1.4984982 1.971108,1.355085 3.274044,2.880474 2.912254,3.406864 z m 44.607836,37.555359 c 0,0.963146 -8.777503,1.556352 -19.64834116,1.554722 -10.87083754,0.0016 -19.64834084,-0.593207 -19.64834084,-1.554722 0,-0.963147 8.7775033,-0.903662 19.64834084,-0.902847 10.86920816,-0.0033 19.64834116,-0.06112 19.64834116,0.902847 z m 10.01688,-39.053857 c -1.970293,1.354271 -3.860732,2.025702 -4.224153,1.498498 -0.360975,-0.52639 0.940331,-2.052592 2.912254,-3.406864 1.970294,-1.3542712 3.860732,-2.0248882 4.223339,-1.4984982 0.362605,0.528019 -0.941147,2.0525922 -2.91144,3.4068642 z");
people
.append("g")
.attr("class", "pattern")
.attr("transform", "translate(5,42)")
.each(function (d) {
var superPattern = d3.superformula()
.param("m", fashionScaleM(d.fashion))
.param("n1", fashionScaleN1(d.fashion))
.param("n2", fashionScaleN2(d.fashion))
.param("n3", fashionScaleN3(d.fashion))
.param("b", 1)
.param("a", 1)
.size(25);
d3.select(this).selectAll("path.superpattern").data(d3.range(20))
.enter()
.append("path")
.attr("transform", function (d, i) {
var yPos = (Math.floor(i/5) * 15) + 3;
var xPos = i%5;
return "translate(" + (xPos * 8) + "," + (yPos) + ")"; })
.attr("d", superPattern)
.style("fill", industryScale(d.industry))
.style("stroke", industryScale(d.industry))
.style("stroke-width", 0.5)
.style("stroke-opacity", 0.5);
})
people
.append("g")
.attr("class", "face")
.attr("transform", "scale(.3)")
.call(face);
people.select("path.face")
.style("fill", function (d) {console.log(d, d.exercise, exerciseScale, exerciseScale(d.exercise)); return exerciseScale(d.exercise)})
.style("stroke", "none");
people.append("text")
.attr("y", 65)
.attr("x", 20)
.style("text-anchor", "middle")
.text(function (d) {return d.label})
.style("stroke", "white")
.style("stroke-width", "4px")
.style("stroke-opacity", .85)
people.append("text")
.attr("y", 65)
.attr("x", 20)
.style("text-anchor", "middle")
.text(function (d) {return d.label})
</script>
</footer>
</html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js