2.Joins - yuanlii/data-visualization-d3 GitHub Wiki
attach or ‘join’ each array element to each element of the selection. This creates a close relationship between your data and graphical elements which makes data-driven modification of the elements straightforward.
join data to svg elements:
d3.selectAll('circle')
.data(scores);now can manipulate the circles according to the joined data:
d3.selectAll('circle')
.attr('r', function(d) {
return d.score;
});Example: sets the radius of each circle to each person’s score. entire code:
<html>
<head>
<link rel="stylesheet" href="index.css">
<title>Learn D3.js</title>
</head>
<style>
body {
font-family: "Helvetica Neue", Helvetica, sans-serif;
font-size: 14px;
color: #333;
}
circle {
fill: #ddd;
}
</style>
<body>
<svg width='800' height='140'>
<g transform="translate(70, 70)">
<circle r="40" />
<circle r="40" cx="120" />
<circle r="40" cx="240" />
<circle r="40" cx="360" />
<circle r="40" cx="480" />
</g>
</svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<!-- reference to index.js -->
<script>
var scores = [
{
"name": "Andy",
"score": 37
},
{
"name": "Beth",
"score": 39
},
{
"name": "Craig",
"score": 31
},
{
"name": "Diane",
"score": 35
},
{
"name": "Evelyn",
"score": 38
}
];
d3.selectAll('circle')
.data(scores)
.attr('r',function(d){
return d.score
});
</script>
</body>
</html>A common pattern is to encapsulate the above behaviour of adding, removing and updating DOM elements in a single function:
- more to see this link
function update(data) {
var u = d3.select('#content')
.selectAll('div')
.data(data);
u.enter()
.append('div')
.classed('new', true)
.text(function(d) {
return d;
});
u.text(function(d) {
return d;
})
.classed('new', false);
u.exit().remove();
}When we do a data join D3 binds the first array element to the first element in the selection, the second array element to the second element in the selection and so on.
can providing .data with a key function: with a key function as below:
var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var i = 25;
function doInsert() {
if(i < 0)
return;
var myData = letters.slice(i).split('');
i--;
update(myData);
}
function update(data) {
var u = d3.select('#content')
.selectAll('div')
// key function --> so the position will change orderly
.data(data, function(d) {
return d;
});
u.enter()
.append('div')
.merge(u)
.transition()
.style('left', function(d, i) {
return i * 32 + 'px';
})
.text(function(d) {
return d;
});
}
doInsert();Without a key function:
var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var i = 25;
function doInsert() {
if(i < 0)
return;
var myData = letters.slice(i).split('');
i--;
update(myData);
}
function update(data) {
var u = d3.select('#content')
.selectAll('div')
// without key function --> position will jump (change abruptly)
.data(data);
u.enter()
.append('div')
.merge(u)
.transition()
.style('left', function(d, i) {
return i * 32 + 'px';
})
.text(function(d) {
return d;
});
}
doInsert();
Once we’ve joined data to a selection we can modify elements by passing a function into the likes of .style and .attr
- 可以在.attr() 或是 .style()里面定义function
d3.selectAll('circle')
.attr('r', function(d) {
return d;
});一个例子:
var myData = [ 10, 40, 20, 30, 50 ];
// Do the join
s.data(myData);
// update radius
s.attr('r', function(d) {
return d;
});以上在.attr里面定义function,该function会跑n次(n=data中element的个数);
还可以给element划分不同的class e.g., class为high的填充orange
- 需要在style里设定不同class的不同style:
circle.high {
fill: orange;
}entire code:
var myData = [ 10, 40, 20, 30, 50 ];
var s = d3.selectAll('circle');
// Do the data join
s.data(myData);
// Modify the selected elements
s.attr('r', function(d) {
return d;
})
.classed('high', function(d) {
return d >= 40;
})
.attr('cx', function(d, i) {
return i * 120;
});假如有一个array,可以join用常用的格式:
var cities = [
{ name: 'London', population: 8674000},
{ name: 'New York', population: 8406000},
{ name: 'Sydney', population: 4293000},
{ name: 'Paris', population: 2244000},
{ name: 'Beijing', population: 11510000}
];
var s = d3.selectAll('circle');
s.data(cities);
d will represent the joined object. e.g., for the first elem in the selection, d is { name: 'London', population: 8674000} 每个d都是array里的一个object;
举个例子:用population数字控制circle的r:
s.attr('r', function(d) {
// 设置circle不同的半径大小;因为population本身太大,需要用一个scale
var scaleFactor = 0.000005;
return d.population * scaleFactor;
})
// 设置circle不同的位置
.attr('cx', function(d, i) {
return i * 120;
});
示例:Build an interactive bar chart that represent country population 重点:
- 鼠标hover over, bar chart会从蓝色变成orange
- text elements和rect elements的处理
entire code:
<html>
<head>
<link rel="stylesheet" href="index.css">
<title>Learn D3.js</title>
</head>
<style>
body {
font-family: "Helvetica Neue", Helvetica, sans-serif;
font-size: 14px;
color: #333;
}
rect {
fill: steelblue;
}
text {
text-anchor: end;
}
/* build-in function for hovering effect */
rect:hover {
fill: orange;
}
</style>
<body>
<svg width='800' height='200'>
<g transform="translate(70, 70)">
<rect />
<rect />
<rect />
<rect />
<rect />
</g>
<g transform="translate(70, 70)">
<text />
<text />
<text />
<text />
<text />
</g>
</svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<!-- reference to index.js -->
<script>
var cities = [
{ name: 'London', population: 8674000},
{ name: 'New York', population: 8406000},
{ name: 'Sydney', population: 4293000},
{ name: 'Paris', population: 2244000},
{ name: 'Beijing', population: 11510000}
];
d3.selectAll('rect')
.data(cities)
// can set height all at once at the end; instead of setting attributes one by one in the svg container
.attr('height', 19)
.attr('width', function(d) {
var scaleFactor = 0.00004;
return d.population * scaleFactor;
})
.attr('y', function(d, i) {
return i * 20;
})
// Join cities to text elements and modify content and position
d3.selectAll('text')
.data(cities)
.attr('y', function(d, i) {
return i * 20 + 13;
})
.attr('x', -4)
.text(function(d) {
return d.name;
});
</script>
</body>
</html>If only a few instances, t’s useful to join a single bit of data with a selection. .datum => join it to a single element e.g.:
d3.select('path#my-map')
.datum(featureCollection);Most of the time .data will be used for data joins; 少数情况可以用.datum