D3绘制散点图
效果图
数据来自:https://www.worldbank.org/
完整代码(不含Initialize初始化数据的函数):
<script src="https://d3js.org/d3.v5.js"></script>
<script>
let w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
w *= 0.98;
h *= 0.9;
let T = new Array();
let NAME = new Array();
let RANGE = new Array();
let Data = new Array();
// [1] -> population of age range 0~14
// [2] -> population of age range 15~64
// [3] -> population of age range 65+
initialize();
//初始化数据
// 内部空间
let inner = {top: 50, right: 50, bottom: 50, left: 50};
// 坐标轴的定义
let xScale = d3.scaleLinear()
.domain([1960, 2018])
.range([0, w - inner.left - inner.right])
.nice();
let xAxis = d3.axisBottom(xScale);
let yScale = d3.scaleLinear()
.domain([0, 100])
.range([h - inner.top - inner.bottom, 0])
.nice();
let yAxis = d3.axisLeft(yScale);
let svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h)
.append("g");
svg.append("g")
.attr("transform", "translate(" + inner.left + "," + (h - inner.bottom) + ")")
.call(xAxis);
svg.append("g")
.attr("transform", "translate(" + inner.left + "," + (inner.top) + ")")
.call(yAxis);
// 重画某一条线上的数据
function F(v, t) {
svg.append("g")
.selectAll("circle")
.data(Data[t])
.enter()
.append("circle")
.attr("fill", function (d) {
if (d[0] === v) return T[d[0] - 1];
})
.attr("cx", function (d) {
if (d[0] === v) return inner.left + xScale(d[1]);
})
.attr("cy", function (d) {
if (d[0] === v) return inner.top + yScale(d[2]);
})
.attr("r", 2);
}
// 根据点击次数处理效果
function FF(v) {
svg.selectAll("circle").remove();
for (let k = 1; k <= 3; ++k) {
for (let i = 1; i <= 13; ++i) {
if (cnt[i] > 0 && cnt[i] % 2 === 1) {
if (ct[k] > 0 && ct[k] % 2 === 1) {
F(i, k);
}
}
}
}
}
// 定义可选的国家的方块
let svg2 = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500);
let cnt = new Array();
let ct = new Array();
for (i = 1; i <= 13; ++i) {
cnt[i] = 0;
}
for (i = 1; i <= 3; ++i) ct[i] = 0;
svg2.selectAll("rect")
.data(NAME)
.enter()
.append("rect")
.attr("y", function (d, i) {
return i * 20;
})
.attr("x", function (d) {
return 20;
})
.attr("width", 20)
.attr("height", 20)
.attr("fill", function (d, i) {
return T[i];
})
.on("click", function (d, i) {
cnt[i + 1]++;
FF();
});
svg2.selectAll("text")
.data(NAME)
.enter()
.append("text")
.attr("transform", function (d, i) {
return "translate(" + (40) + "," + (i * 20 + 15) + ")";
})
.attr("fill", 'black')
.attr("font-size", 10)
.text(function (d, i) {
return NAME[i];
});
// 定义选择的数据种类的方块
let svg3 = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500);
svg3.selectAll("rect")
.data(RANGE)
.enter()
.append("rect")
.attr("y", function (d, i) {
return 20;
})
.attr("x", function (d, i) {
return 40 * i + 5;
})
.attr("width", 20)
.attr("height", 20)
.attr("fill", "red")
.on("click", function (d, i) {
ct[i + 1]++;
FF();
});
svg3.selectAll("text")
.data(RANGE)
.enter()
.append("text")
.attr("text-anchor", "middle")
.attr("transform", function (d, i) {
return "translate(" + (i * 40 + 15) + "," + (60) + ")";
})
.attr("fill", 'black')
.attr("font-size", 10)
.text(function (d, i) {
return RANGE[i];
});
</script>
代码解释:
let w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
w *= 0.98;
h *= 0.9;
获得网页页面上的可视区域。
// 坐标轴的定义
let xScale = d3.scaleLinear()
.domain([1960, 2018])
.range([0, w - inner.left - inner.right])
.nice();
let xAxis = d3.axisBottom(xScale);
let yScale = d3.scaleLinear()
.domain([0, 100])
.range([h - inner.top - inner.bottom, 0])
.nice();
let yAxis = d3.axisLeft(yScale);
domain即值域,表示数据的范围。其中的数据可以是一个区间,也可以是一个数组,可以是离散的数据。
range即映射范围,设置刻度的输出范围值的指定数组。
nice修改规模域,使边界延伸到最近的整数值。
// 重画某一条线上的数据
function F(v, t) {
svg.append("g")
.selectAll("circle")
.data(Data[t])
.enter()
.append("circle")
.attr("fill", function (d) {
if (d[0] === v) return T[d[0] - 1];
})
.attr("cx", function (d) {
if (d[0] === v) return inner.left + xScale(d[1]);
})
.attr("cy", function (d) {
if (d[0] === v) return inner.top + yScale(d[2]);
})
.attr("r", 2);
}
以圆圈的形式绘制散点图。cx,cy表示坐标位置。r表示半径大小。
借助匿名函数来选择满足要求。
后面额外添加了两个画布,一个用来表示每个国家对应的颜色。颜色用矩形的形式呈现,后面添加文本。
svg2.selectAll("rect")
.data(NAME)
.enter()
.append("rect")
.attr("y", function (d, i) {
return i * 20;
})
.attr("x", function (d) {
return 20;
})
.attr("width", 20)
.attr("height", 20)
.attr("fill", function (d, i) {
return T[i];
})
.on("click", function (d, i) {
cnt[i + 1]++;
FF();
});
矩形设置了点击的事件处理,即点击该矩形后显示该国家的数据。
同时增添了一个svg3,用来选择呈现哪一部分的数据。