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

D3.js简单柱状图数值显示颠倒问题排查求助

柱状图数值颠倒问题排查与修复

问题描述

现有300个样本数据:260个未订阅有线电视,40个已订阅,对应占比87%和13%。使用D3.js绘制柱状图时,出现数值颠倒问题:已订阅柱子显示87%、未订阅显示13%,无法定位代码缺陷。

原始代码

const rowConverter = (row) => {
    row = {
        age: parseInt(row.age),
        gender: row.gender,
        income: parseInt(row.income),
        kids: parseInt(row.kids),
        ownHome: row.ownHome === "true",
        subscribed: row.subscribed === "true",
        segment: row.segment
    }
    return { ...row };
};

const dataset = await d3.csv("./data/CableTVSubscribersData.csv", rowConverter);
const margin = {
    top: 40,
    bottom: 40,
    left: 60,
    right: 20
};
const width = 800 - margin.left - margin.right;
const height = 600 - margin.top - margin.bottom;

let subscribedCounter = 0;
let notSubscribedCounter = 0;

dataset.forEach(data => {
    if (data.subscribed) {
        subscribedCounter++
    }
    else {
        notSubscribedCounter++;
    }
});
let barChartRows = [
    {
        name: "Subscribed",
        amount: subscribedCounter
    },
    {
        name: "Not Subscribed",
        amount: notSubscribedCounter
    },
];

const dataset2 = barChartRows;
const barNames = dataset2.map((d) => d.name)

const svg = d3.select(".graph1")
    .append("svg")
    .attr("width", width + margin.left)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")


svg.append('rect')
    .attr("width", width + margin.left)
    .attr("height", height + margin.top + margin.bottom)
    .style("fill", "#e6e6e6");

let xScale2 = d3.scaleBand()
.domain(barNames)
.rangeRound([0, width- margin.left ]);

let yScale2 = d3.scaleLinear()
    .domain([0, 1])
    .rangeRound([height - margin.top, 0]);

let xAxis2 = d3.axisBottom(xScale2);
let yAxis2 = d3.axisLeft(yScale2);


let xAxisGroup = svg.append('g')
    .attr('class', 'groupAxis')
    .attr('transform', `translate(${margin.left + margin.right}, ${height})`)
    .call(xAxis2);

let yAxisGroup = svg.append('g')
    .attr('class', 'incomeAxis')
    .attr('transform', `translate(${margin.left + margin.right},${margin.top})`)
    .call(yAxis2)
    .selectAll("text")
    .text(function (d) { return d3.format(".0%")(d) });

console.log(dataset2);
svg.selectAll('.bar')
    .data(dataset2)
    .join(
        enter => enter
        .append('rect')
        .attr("class",(d) => d.name)
        .attr('x',(d) => xScale2(d.name)+(margin.left + margin.right)*2+10})
        .attr('y',(d) => height - yScale2(d.amount/300))
        .attr('width',150)
        .attr('height',(d) => yScale2(d.amount/300)})
    )

问题根源

  1. 柱子坐标与高度计算逻辑错误:
    • SVG坐标系中y轴数值向下递增,你设置的yScale2.rangeRound([height - margin.top, 0])意味着:数值0对应底部(更大的y像素值),数值1对应顶部(更小的y像素值)。
    • 原始代码中,柱子y坐标用height - yScale2(d.amount/300)会让占比越高的柱子位置越靠下;高度用yScale2(d.amount/300)会让占比越高的柱子高度越小,直接导致数值显示颠倒。
  2. x坐标偏移量不合理:原始x坐标的额外偏移会导致柱子与x轴刻度错位。

修复方案

修改柱子绘制部分的坐标与高度计算逻辑,同时优化x坐标和宽度设置:

svg.selectAll('.bar')
    .data(dataset2)
    .join(
        enter => enter
        .append('rect')
        .attr("class",(d) => d.name)
        // 修正x坐标,与x轴刻度对齐
        .attr('x',(d) => margin.left + margin.right + xScale2(d.name))
        // 修正y坐标:从y轴起始位置(margin.top)开始,根据刻度值定位柱子顶部
        .attr('y',(d) => margin.top + yScale2(d.amount/300))
        // 使用scaleBand的带宽自动适配宽度,避免固定值导致重叠
        .attr('width', xScale2.bandwidth())
        // 修正高度:柱子底部在height位置,减去顶部y坐标得到正确高度
        .attr('height',(d) => (height - margin.top) - yScale2(d.amount/300))
    )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 00:20:53