如何使用D3.js基于指定CSV数据绘制分组条形图 解决A/B/C类别拆分问题
D3.js 长格式数据绘制分组条形图解决方案
你之前参考的教程适配的是宽格式CSV(每一行对应一个大分组,每一列存储一个类别的数值),而你当前使用的是长格式CSV,所以需要先调整数据处理逻辑,具体实现步骤如下:
1. 预定义配色映射
按照需求配置tipology和颜色的对应规则:
const colorMap = d3.scaleOrdinal() .domain(["A", "B", "C"]) .range(["red", "blue", "green"]);
2. 数据读取与预处理
读取CSV后先做格式转换、缺失值补全,保证每个大分组下都有A、B、C三类的完整数据:
d3.csv("你的数据文件路径.csv").then(rawData => { // 将value字段转换为数值类型 rawData.forEach(item => item.value = Number(item.value)); // 提取所有大分组、所有类别枚举值 const allGroups = [...new Set(rawData.map(item => item.group))]; const allTipologies = ["A", "B", "C"]; // 补全每个大分组下的三类数据,缺失值填充为0,避免分组缺类 const formattedData = allGroups.map(groupName => { const groupItems = rawData.filter(item => item.group === groupName); const fullItems = allTipologies.map(tip => { const matched = groupItems.find(item => item.tipology === tip); return { group: groupName, tipology: tip, value: matched ? matched.value : 0 } }); return [groupName, fullItems]; }); // 后续比例尺配置、绘图逻辑都在这个回调内执行 })
3. 双X轴比例尺配置
分组条形图需要两层X轴比例尺:外层控制大分组的位置,内层控制每个大分组内三类条形的偏移:
// 画布尺寸可根据需求调整 const width = 600, height = 400, margin = {top: 20, right: 20, bottom: 30, left: 40}; // 外层X比例尺:映射大分组位置 const xGroupScale = d3.scaleBand() .domain(allGroups) .range([margin.left, width - margin.right]) .padding(0.2); // 内层X比例尺:映射大分组内三类条形的位置 const xTipScale = d3.scaleBand() .domain(allTipologies) .range([0, xGroupScale.bandwidth()]) .padding(0.05); // Y比例尺:映射数值高度 const yScale = d3.scaleLinear() .domain([0, d3.max(rawData, item => item.value)]) .range([height - margin.bottom, margin.top]);
4. 绘制条形元素
先为每个大分组创建容器,再在容器内绘制对应三类的条形:
const svg = d3.select("你的svg选择器") .attr("width", width) .attr("height", height); // 绘制大分组容器 const groupContainers = svg.selectAll("g.group-container") .data(formattedData) .join("g") .attr("transform", d => `translate(${xGroupScale(d[0])}, 0)`); // 绘制每个类别条形 groupContainers.selectAll("rect.tip-bar") .data(d => d[1]) .join("rect") .attr("class", "tip-bar") .attr("x", d => xTipScale(d.tipology)) .attr("y", d => yScale(d.value)) .attr("width", xTipScale.bandwidth()) .attr("height", d => height - margin.bottom - yScale(d.value)) .attr("fill", d => colorMap(d.tipology));
内容的提问来源于stack exchange,提问作者Erica
相关产品推荐
相关产品推荐

