如何在D3.js中生成小倍数?2×2条形图代码无显示求助
解决D3.js 2×2小倍数条形图无内容显示的问题
我懂你这种卡壳的感觉——折腾D3做小倍数,查了一堆教程还是啥都出不来,太挫败了!咱们先从你给出的代码片段和常见坑点入手,一步步搞定这个2×2的条形图小倍数。
先排查常见的无内容原因
你代码运行没显示东西,大概率是这几个问题里的一个:
- 数据没按分组结构处理,小倍数需要把数据拆成4组对应每个子图
- 没正确创建子图的布局容器,或者子图的位置计算错误,内容被移出SVG视野
- 比例尺没有针对每个子图单独设置,导致条形尺寸/位置异常(比如高度为0)
- 代码不完整(你给的代码到
var m...就断了),关键的绑定数据、绘制元素的部分缺失
完整的2×2小倍数条形图示例代码
我给你写了一个可直接运行的示例,每一步都标了注释,你可以对照着改自己的代码:
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://d3js.org/d3.v4.min.js"></script> <style type="text/css"> rect { transition: fill 0.3s; } rect:hover { fill: #2257b2; } </style> </head> <body> <script type="text/javascript"> // ---------------------- 1. 设置参数和数据 ---------------------- // 单个小图的尺寸 const panelWidth = 250; const panelHeight = 150; // 小图内部边距(轴和标题的空间) const margin = { top: 20, right: 20, bottom: 30, left: 40 }; // 小图之间的间距 const panelGap = { x: 30, y: 30 }; // 整体SVG的总尺寸(2列×2行 + 间距) const totalWidth = panelWidth * 2 + panelGap.x * 3; const totalHeight = panelHeight * 2 + panelGap.y * 3; // 示例数据:4组数据,对应2×2的4个小图 const dataset = [ { group: "组1", values: [12, 28, 18, 35] }, { group: "组2", values: [25, 15, 30, 22] }, { group: "组3", values: [8, 19, 27, 14] }, { group: "组4", values: [32, 10, 21, 29] } ]; // ---------------------- 2. 创建SVG容器 ---------------------- const svg = d3.select("body") .append("svg") .attr("width", totalWidth) .attr("height", totalHeight); // ---------------------- 3. 创建小倍数容器 ---------------------- // 为每组数据创建一个g元素(小图容器) const panels = svg.selectAll(".panel") .data(dataset) .enter() .append("g") .attr("class", "panel") .attr("transform", (d, i) => { // 计算每个小图的位置:2列布局,i%2是列索引,Math.floor(i/2)是行索引 const x = panelGap.x + (i % 2) * (panelWidth + panelGap.x); const y = panelGap.y + Math.floor(i / 2) * (panelHeight + panelGap.y); return `translate(${x}, ${y})`; }); // ---------------------- 4. 为每个小图绘制内容 ---------------------- panels.each(function(d) { const currentPanel = d3.select(this); // 针对当前组的数据创建比例尺 // X轴:条形的类别(用values的索引) const xScale = d3.scaleBand() .domain(d3.range(d.values.length)) .range([margin.left, panelWidth - margin.right]) .padding(0.1); // 条形之间的间距 // Y轴:数值范围 const yScale = d3.scaleLinear() .domain([0, d3.max(d.values)]) // 从0到当前组的最大值 .range([panelHeight - margin.bottom, margin.top]); // 注意D3的Y轴是从上到下的 // 绘制条形 currentPanel.selectAll("rect") .data(d.values) .enter() .append("rect") .attr("x", (val, idx) => xScale(idx)) .attr("y", val => yScale(val)) .attr("width", xScale.bandwidth()) .attr("height", val => panelHeight - margin.bottom - yScale(val)) .attr("fill", "#4287f5"); // 添加X轴 currentPanel.append("g") .attr("transform", `translate(0, ${panelHeight - margin.bottom})`) .call(d3.axisBottom(xScale)); // 添加Y轴 currentPanel.append("g") .attr("transform", `translate(${margin.left}, 0)`) .call(d3.axisLeft(yScale)); // 添加小图标题 currentPanel.append("text") .attr("x", panelWidth / 2) .attr("y", margin.top / 2) .attr("text-anchor", "middle") .style("font-weight", "bold") .text(d.group); }); </script> </body> </html>
对你的代码的调整建议
- 补全代码结构:你原来的代码只到
var m...,要确保包含数据定义、SVG创建、小图布局、比例尺设置和元素绘制的完整流程 - 检查数据结构:确保你的数据是按组拆分的(比如4组,每组对应一个小图),这样才能绑定到每个小图容器上
- 验证位置计算:用
transform定位每个小图时,要确认X/Y坐标的计算是正确的,避免小图被放到SVG外面 - 单独设置比例尺:每个小图的比例尺要基于当前组的数据计算,不要用全局的比例尺(除非你需要统一的刻度范围)
内容的提问来源于stack exchange,提问作者santoku
相关产品推荐
相关产品推荐

