我有三个问题:
- 如何在 x 轴上添加刻度,以便它们分隔散点图的分组区域(每年分组的列)?
- 如何将年份作为文本放置在散点图的相应区域下?
- 有没有比手动将每个点的 x 位置添加到输入数据中更优雅的方法来生成散点图?
更多背景信息:我想用 D3.js 可视化从 2014 年到 2020 年按年份分组的六个组织的会议。散点图的每个点代表一次会议,六种颜色与组织相匹配。目前,我已将散点图中每个点的 x 位置手动添加到输入数据文件中,以便年份之间存在差距。
当前代码:
import axios from "axios";
let meetings
let colors = { a: "brown", b: "orange", c: "red", d: "purple", e: "blue", f: "green" };
window.addEventListener("load", () => {
initUI();
});
function initUI() {
// parse input data
axios
.get("assets/example.txt")
.then(async (res) => {
var rawData = res.data
.split("\n")
// filter header row
.filter((row) => (row.indexOf("label") >= 0 ? false : true))
.map((row) => {
var items = row.split(";");
return {
label: items[0],
year: items[1],
xPosition: items[2],
};
});
meetings = addYPositionForAllOrganizations(rawData);
scatterplot = await showScatterPlot(meetings);
})
.then(() => {
// always executed
});
}
// Add counter for amount of meetings for one organziation per year for y axis position
function addYPosition(organizationList) {
organizationList.sort((a, b) => (a.year > b.year) ? 1 : -1)
var yPosition = 1;
var year = 2014;
organizationList.forEach(element => {
if (year < element.year) {
// reset counter for next year
yPosition = 1;
}
element.yPosition = 0;
element.yPosition += yPosition;
yPosition++;
year = element.year;
});
}
function addYPositionForAllOrganizations(data) {
let a = data.filter(row => row.label == "a");
addYPosition(a);
let b = data.filter(row => row.label == "b");
addYPosition(b);
let c = data.filter(row => row.label == "c");
addYPosition(c);
let d = data.filter(row => row.label == "d");
addYPosition(d);
let e = data.filter(row => row.label == "e");
addYPosition(e);
let f = data.filter(row => row.label == "f");
addYPosition(f);
return a.concat(b).concat(c).concat(d).concat(e).concat(f);
}
async function showScatterPlot(data) {
let margin = { top: 10, right: 30, bottom: 100, left: 60 },
width = 1000 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
let svg = d3
.select("#scatter-plot")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Add x axis
var x = d3.scaleLinear().domain([-2, 75]).range([0, width]);
//FIXME this destroys ticks so that they are "invisible"
var xAxis = d3.axisBottom(x).tickValues(2014, 2015, 2016, 2017, 2018, 2019, 2020);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add text label for x axis
svg.append("text")
.attr("transform", "translate(" + (width / 2) + "," + (height - (-100 / 3)) + ")")
.attr("text-anchor", "middle")
.style("font-family", "sans-serif")
.text("Years 2014 - 2020");
// Add y axis
var y = d3.scaleLinear().domain([0.5, 10]).range([height, 0]);
svg.append("g").attr("class", "y axis").call(d3.axisLeft(y));
// Add text label for the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.style("font-family", "sans-serif")
.text("Amount");
// Add meetings as dots
let meetings = svg.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return x(d.xPosition); })
.attr("cy", function (d) { return y(d.yPosition); })
.attr("r", 5.5)
.style("fill", getColorForMeeting);
return { svg, x, y };
}
function getColorForMeeting(data) {
return colors[data.label];
}
<script src="https://d3js.org/d3.v4.js"></script>
<div id="scatter-plot"></div>
正在运行的项目可以在这里进行调查。