You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

D3.js v5分组柱状图:实现x.domain标签与数据分离

Grouped Bar Chart with D3.js v5 (Separate X-Domain from Data)

Got it, let's build this grouped bar chart step by step, making sure we keep the x-axis domain labels fully independent from the raw data structure. Here's a complete, working implementation tailored to your data:

1. Basic HTML Setup

First, add an SVG container to your page where the chart will render:

<svg id="groupedBarChart" width="800" height="500"></svg>

2. D3.js Implementation

Here's the JavaScript code, with detailed comments explaining each key part:

// Your provided raw data
var groupeddata = [
  { Title: "Dummy Data", ID: "46", RFU: 20291, Name: "Name1", barcolor: "#ff7f00"},
  { Title: "Dummy Data", ID: "50", RFU: 15000, Name: "Name2", barcolor: "#ff7f00"},
  { Title: "Dummy Data", ID: "40", RFU: 14000, Name: "Name3", barcolor: "#ff7f00"},
  { Title: "Dummy Data2", ID: "46", RFU: 21000, Name: "Name1", barcolor: "#8B008B"},
  { Title: "Dummy Data2", ID: "50", RFU: 18095, Name: "Name2", barcolor: "#8B008B"},
  { Title: "Dummy Data2", ID: "40", RFU: 16000, Name: "Name3", barcolor: "#8B008B"}
];

// Set up SVG dimensions and margins
const svg = d3.select("#groupedBarChart");
const margin = { top: 30, right: 30, bottom: 60, left: 60 };
const width = +svg.attr("width") - margin.left - margin.right;
const height = +svg.attr("height") - margin.top - margin.bottom;
const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);

// --- Core part: Separate x-axis domain labels from data ---
// Extract unique category names (these become our x-axis labels)
const xLabels = [...new Set(groupeddata.map(d => d.Name))];
// Extract unique group titles (these define our bar series)
const groups = [...new Set(groupeddata.map(d => d.Title))];
const groupCount = groups.length;

// Create scales
// Main x-scale for category labels (Name1, Name2, Name3)
const x0 = d3.scaleBand()
  .domain(xLabels)
  .range([0, width])
  .padding(0.2);

// Secondary x-scale for positioning bars within each category
const x1 = d3.scaleBand()
  .domain(groups)
  .range([0, x0.bandwidth()])
  .padding(0.1);

// Y-scale for RFU values
const y = d3.scaleLinear()
  .domain([0, d3.max(groupeddata, d => d.RFU)])
  .nice() // Rounds the domain to a clean number
  .range([height, 0]);

// Add axes
g.append("g")
  .attr("transform", `translate(0,${height})`)
  .call(d3.axisBottom(x0))
  .selectAll("text")
  .attr("y", 10)
  .attr("x", -5)
  .attr("text-anchor", "end")
  .attr("transform", "rotate(-45)"); // Rotate labels to avoid overlap

g.append("g")
  .call(d3.axisLeft(y))
  .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", -50)
  .attr("fill", "#000")
  .attr("text-anchor", "middle")
  .text("RFU Value");

// --- Draw the grouped bars ---
// First, group data by category Name for easier iteration
const dataByCategory = d3.group(groupeddata, d => d.Name);

// Loop through each category and draw its bars
dataByCategory.forEach((categoryData, categoryName) => {
  const baseX = x0(categoryName);
  
  g.selectAll(`.bar-${categoryName}`)
    .data(categoryData)
    .enter()
    .append("rect")
    .attr("class", `bar-${categoryName}`)
    .attr("x", d => baseX + x1(d.Title))
    .attr("y", d => y(d.RFU))
    .attr("width", x1.bandwidth())
    .attr("height", d => height - y(d.RFU))
    .attr("fill", d => d.barcolor);
});

// Add a legend for clarity
const legend = g.append("g")
  .attr("transform", `translate(${width - 150}, 0)`);

groups.forEach((group, index) => {
  const legendRow = legend.append("g")
    .attr("transform", `translate(0, ${index * 25})`);
  
  legendRow.append("rect")
    .attr("width", 15)
    .attr("height", 15)
    .attr("fill", groupeddata.find(d => d.Title === group).barcolor);
  
  legendRow.append("text")
    .attr("x", 20)
    .attr("y", 12)
    .style("font-size", "12px")
    .text(group);
});

Key Details on Separating X-Domain from Data

  • We pull xLabels directly from the Name field using new Set() to get unique values—this ensures the x-axis domain is completely decoupled from other data fields like Title or ID.
  • Two x-scales work together: x0 handles the main category positioning, while x1 slots each group's bar into the category's space.
  • Using d3.group() (available in D3 v5+) simplifies mapping raw data to the grouped bar structure, making updates to data or labels straightforward.

This implementation will render a clean, functional grouped bar chart where you can modify the x-axis labels or data independently without breaking the chart's structure.

内容的提问来源于stack exchange,提问作者Coola

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:10:59