坐标轴的使用
- 一、坐标轴是什么?
- 二、创建坐标轴的基本步骤
- 1. 准备比例尺
- 2. 创建坐标轴生成器
- 3. 渲染坐标轴
- 三、完整示例:带坐标轴的柱状图
- 四、坐标轴定制
- 1. 刻度数量与格式
- 2. 刻度大小
- 3. 自定义刻度值
- 五、时间坐标轴
- 六、坐标轴样式调整
- 七、常见问题与解决方案
- 1. 坐标轴位置不正确
- 2. 刻度标签重叠
- 3. 坐标轴更新
- 小结
- 下章预告:让图表动起来
坐标轴是数据可视化中不可或缺的元素,它能帮助观众理解数据的尺度和范围。在D3.js中,坐标轴通常与比例尺配合使用,将抽象的数据映射为可视化的刻度标记。
一、坐标轴是什么?
坐标轴是由刻度线、刻度标签和轴线组成的可视化组件,用于表示数据的度量标准。在D3.js中,坐标轴具有以下特点:
-
基于比例尺: 坐标轴需要依赖一个比例尺(如线性比例尺、时间比例尺等)来确定刻度的位置和标签
-
可定制性强: 可以自定义刻度数量、格式、大小等属性
-
方向灵活: 支持上、下、左、右四个方向的坐标轴
二、创建坐标轴的基本步骤
1. 准备比例尺
首先需要定义一个比例尺,这是创建坐标轴的前提:
// 创建比例尺
const xScale = d3.scaleLinear().domain([0, 100]).range([0, 500]);
2. 创建坐标轴生成器
D3提供了四种坐标轴生成器:
// 创建坐标轴生成器
const axisBottom = d3.axisBottom(xScale); // 底部坐标轴
const axisTop = d3.axisTop(xScale); // 顶部坐标轴
const axisLeft = d3.axisLeft(yScale); // 左侧坐标轴
const axisRight = d3.axisRight(yScale); // 右侧坐标轴
3. 渲染坐标轴
将坐标轴添加到SVG中:
// 在SVG中添加坐标轴
svg.append("g").attr("transform", "translate(50, 250)") // 定位坐标轴.call(axisBottom);
三、完整示例:带坐标轴的柱状图
👇 一个完整的柱状图示例,包含X轴和Y轴:
<!DOCTYPE html>
<html>
<head><script src="https://d3js.org/d3.v7.min.js"></script><style>.bar {fill: #4CAF50;transition: all 0.3s;}.bar:hover {fill: #FF5722;}.axis path,.axis line {fill: none;stroke: #333;shape-rendering: crispEdges;}.axis text {font-family: Arial;font-size: 11px;}</style>
</head>
<body><svg width="600" height="400"></svg><script>// 数据集const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];const barPadding = 5;const barWidth = 50;// 选择SVG容器const svg = d3.select("svg");// 创建比例尺const xScale = d3.scaleBand().domain(d3.range(dataset.length)).range([50, 550]).padding(0.1);const yScale = d3.scaleLinear().domain([0, d3.max(dataset)]).range([350, 50]);// 创建坐标轴const xAxis = d3.axisBottom(xScale).tickFormat(d => `项目 ${d + 1}`);const yAxis = d3.axisLeft(yScale);// 绘制柱状图svg.selectAll(".bar").data(dataset).enter().append("rect").attr("class", "bar").attr("x", (d, i) => xScale(i)).attr("y", d => yScale(d)).attr("width", xScale.bandwidth()).attr("height", d => 350 - yScale(d));// 添加X轴svg.append("g").attr("class", "axis").attr("transform", "translate(0, 350)").call(xAxis);// 添加Y轴svg.append("g").attr("class", "axis").attr("transform", "translate(50, 0)").call(yAxis);</script>
</body>
</html>
👇 代码效果:
四、坐标轴定制
1. 刻度数量与格式
// 设置刻度数量和格式
const yAxis = d3.axisLeft(yScale).ticks(5) // 大约5个刻度.tickFormat(d => `${d}个`); // 添加单位
2. 刻度大小
// 调整刻度大小
const xAxis = d3.axisBottom(xScale).tickSizeInner(10) // 内部刻度线长度.tickSizeOuter(20); // 外部刻度线长度
3. 自定义刻度值
// 指定精确的刻度值
const yAxis = d3.axisLeft(yScale).tickValues([0, 15, 30, 45, 60]);
五、时间坐标轴
对于时间数据,可以使用时间比例尺和时间坐标轴:
// 时间数据示例
const timeData = [{date: new Date(2023, 0, 1), value: 30},{date: new Date(2023, 1, 1), value: 40},// 更多数据...
];// 创建时间比例尺
const xTimeScale = d3.scaleTime().domain(d3.extent(timeData, d => d.date)).range([50, 550]);// 创建时间坐标轴
const xTimeAxis = d3.axisBottom(xTimeScale).ticks(d3.timeMonth.every(1)) // 每月一个刻度.tickFormat(d3.timeFormat("%b %Y")); // 格式化为"月 年"// 渲染时间坐标轴
svg.append("g").attr("transform", "translate(0, 350)").call(xTimeAxis);
👇 完整代码示例:
<!DOCTYPE html>
<html>
<head><script src="https://d3js.org/d3.v7.min.js"></script><style>body {font-family: Arial, sans-serif;margin: 20px;}.chart-container {width: 800px;height: 500px;}.axis path,.axis line {fill: none;stroke: #333;shape-rendering: crispEdges;}.axis text {font-size: 12px;}.line {fill: none;stroke: steelblue;stroke-width: 2px;}.dot {fill: steelblue;stroke: #fff;}</style>
</head>
<body><h2>时间序列数据图表</h2><div class="chart-container"><svg width="100%" height="100%"></svg></div><script>// 1. 准备时间序列数据const timeData = [{ date: new Date(2023, 0, 1), value: 30 },{ date: new Date(2023, 1, 1), value: 40 },{ date: new Date(2023, 2, 1), value: 25 },{ date: new Date(2023, 3, 1), value: 35 },{ date: new Date(2023, 4, 1), value: 45 },{ date: new Date(2023, 5, 1), value: 30 },{ date: new Date(2023, 6, 1), value: 50 },{ date: new Date(2023, 7, 1), value: 42 },{ date: new Date(2023, 8, 1), value: 38 },{ date: new Date(2023, 9, 1), value: 47 },{ date: new Date(2023, 10, 1), value: 53 },{ date: new Date(2023, 11, 1), value: 60 }];// 2. 设置SVG尺寸和边距const margin = { top: 40, right: 40, bottom: 60, left: 60 };const width = 800 - margin.left - margin.right;const height = 500 - margin.top - margin.bottom;// 3. 创建SVG容器const svg = d3.select("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom).append("g").attr("transform", `translate(${margin.left},${margin.top})`);// 4. 创建时间比例尺const xTimeScale = d3.scaleTime().domain(d3.extent(timeData, d => d.date)) // 自动计算时间范围.range([0, width]);// 5. 创建数值比例尺const yLinearScale = d3.scaleLinear().domain([0, d3.max(timeData, d => d.value) * 1.1]) // 留出10%空间.range([height, 0]);// 6. 创建时间坐标轴const xAxis = d3.axisBottom(xTimeScale).ticks(d3.timeMonth.every(1)) // 每月一个刻度.tickFormat(d3.timeFormat("%b %Y")); // 格式化为"月 年"// 7. 创建数值坐标轴const yAxis = d3.axisLeft(yLinearScale).ticks(6).tickFormat(d => `${d}单位`);// 8. 渲染X轴svg.append("g").attr("class", "axis x-axis").attr("transform", `translate(0,${height})`).call(xAxis).selectAll("text").attr("transform", "rotate(-45)").attr("dx", "-.8em").attr("dy", ".15em").style("text-anchor", "end");// 9. 渲染Y轴svg.append("g").attr("class", "axis y-axis").call(yAxis);// 10. 添加X轴标签svg.append("text").attr("transform", `translate(${width / 2}, ${height + margin.bottom - 10})`).style("text-anchor", "middle").text("时间");// 11. 添加Y轴标签svg.append("text").attr("transform", "rotate(-90)").attr("y", 0 - margin.left).attr("x", 0 - (height / 2)).attr("dy", "1em").style("text-anchor", "middle").text("数值");// 12. 创建折线生成器const line = d3.line().x(d => xTimeScale(d.date)).y(d => yLinearScale(d.value));// 13. 绘制折线svg.append("path").datum(timeData).attr("class", "line").attr("d", line);// 14. 添加数据点svg.selectAll(".dot").data(timeData).enter().append("circle").attr("class", "dot").attr("cx", d => xTimeScale(d.date)).attr("cy", d => yLinearScale(d.value)).attr("r", 4).append("title") // 添加悬停提示.text(d => `${d3.timeFormat("%Y年%m月%d日")(d.date)}: ${d.value}单位`);// 15. 添加图表标题svg.append("text").attr("x", width / 2).attr("y", 0 - (margin.top / 2)).attr("text-anchor", "middle").style("font-size", "16px").style("font-weight", "bold").text("2023年月度数据趋势");</script>
</body>
</html>
👇 代码效果:
六、坐标轴样式调整
可以通过CSS或D3方法调整坐标轴样式:
/* CSS方式 */
.axis path {stroke: #777;stroke-width: 2px;
}
.axis text {fill: #555;font-size: 12px;
}
.axis line {stroke: #ddd;stroke-dasharray: 2,2;
}
// D3方式
svg.selectAll(".axis path").attr("stroke", "#777").attr("stroke-width", 2);svg.selectAll(".axis text").attr("fill", "#555").attr("font-size", "12px");
七、常见问题与解决方案
1. 坐标轴位置不正确
确保设置了正确的transform属性:
// 底部坐标轴通常需要向下平移
.attr("transform", `translate(0, ${height - margin.bottom})`)
2. 刻度标签重叠
解决方法:
- 减少刻度数量:
.ticks(5)
- 旋转标签:
.selectAll("text").attr("transform", "rotate(-45)")
- 调整标签位置:
.attr("dy", ".35em").attr("dx", "-.8em")
3. 坐标轴更新
当数据变化时,需要重新调用坐标轴:
// 更新比例尺域
xScale.domain(newDomain);// 重新调用坐标轴
svg.select(".x-axis").call(xAxis);
小结
-
核心三要素: 比例尺→生成器→渲染
-
四大方向: Top/Bottom/Left/Right
-
定制关键:
- 刻度控制
.ticks()
- 标签格式化
.tickFormat()
- 样式调整CSS/D3方法
- 刻度控制
-
时间轴要点: 用
scaleTime()
+时间格式化 -
常见技巧:
- 防标签重叠:旋转45度
- 数据更新:先改
domain
再call
- 准确定位:注意
transform