【问题标题】:Having troubles with Y-axis in D3jsD3js中的Y轴有问题
【发布时间】:2021-09-20 09:37:38
【问题描述】:

我正在使用 D3js 进行这个项目,但现在遇到了一个问题。 当我有更多数据时,我的条形图的条将正确地附加在与名称相同的行中,但是当我从数据库中获取较少的数据时,条将“失去控制”并附加到高于它们的名称并导致错误的视图我的图表。

这是一张图片,如果我加载更多数据会得到什么。

如果我加载较少的数据,这是我的第二张图表。

我真的不明白我在这里缺少什么,但我相信是 Y 轴的高度和条 y 位置的东西。你能帮我解决这个问题吗?

这是我的代码:

var margin = { top: 20, right: 30, bottom: 40, left: 90 },
    width = 360 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform",
        "translate(" + margin.left + "," + margin.top + ")");

// Parse the Data
var data2 = d3.json("/Events/BarChart/4").then(function (data) {
    console.log(data);
    // Add X axis
    var x = d3.scaleLinear()
        .domain([0, 5])
        .range([0, width]);
    svg.append("g")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(x))
        .selectAll("text")
        .attr("transform", "translate(-10,0)rotate(-45)")
        .style("text-anchor", "end")

        ;

    // Y axis
    var y = d3.scaleBand()
        .range([0, height])
        .domain(data.map(function (d) { return d.name; }))

    svg.append("g")
        .call(d3.axisLeft(y))

    //Bars
    svg.selectAll("myRect")
        .data(data)
        .enter()
        .append("rect")
        .attr("x", 4)
        .attr("y", function (d) { return y(d.name) + 10; })
        .attr("width", function (d) { return x(d.value); })
        .attr("height", 20)
        .attr("fill", function (d) {
            if (d.value > 1) {
                return "rgb(51, 80, 92)";
            }
            else if (d.value > 1 && d.value < 4) {
                return "rgb(118, 161, 179)"
            }
            else {
                return "rgb(171, 209, 224)";
            }
        })
})

【问题讨论】:

    标签: d3.js charts data-visualization bar-chart


    【解决方案1】:

    出现问题是因为您手动为每个矩形分配了 20 像素的高度,但您将比例范围设置为 0 - 240(height 的值)。比例尺将范围划分为相等的段(带),一个对应其域中的每个值。当您在域中只有两个值时,它们将有 120 像素的波段(如果有填充则减少)。比例尺“不知道”您为每个条形分配的高度仅为 20 px;毕竟,您告诉它在 0 到 240 的范围内均匀分布值。这些相互矛盾的说明是您的条与轴不对齐的原因。

    使用 d3 比例尺时,如果同时使用轴比例尺和绘制数据本身(矩形/圆/等),您会发现会更容易:这样它们将始终对齐。

    d3 带刻度提供了一种方便的方法:scale.bandwidth(),它返回刻度中带的长度/宽度/高度:最简单的(没有填充)它是范围的大小除以不同的数量值在域中。我们可以使用这个值来设置条形高度:

    var margin = { top: 20, right: 30, bottom: 40, left: 90 },
        width = 360 - margin.left - margin.right,
        height = 300 - margin.top - margin.bottom;
    
    // append the svg object to the body of the page
    var svg = d3.select("#my_dataviz")
        .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform",
            "translate(" + margin.left + "," + margin.top + ")");
    
    var data = [
      {name: "a", value: 1},
      {name: "b", value: 2}
    ]
    
        // Add X axis
        var x = d3.scaleLinear()
            .domain([0, 5])
            .range([0, width]);
        svg.append("g")
            .attr("transform", "translate(0," + height + ")")
            .call(d3.axisBottom(x))
            .selectAll("text")
            .attr("transform", "translate(-10,0)rotate(-45)")
            .style("text-anchor", "end")
    
            ;
    
        // Y axis
        var y = d3.scaleBand()
            .range([0, height])
            .domain(data.map(function (d) { return d.name; }))
    
        svg.append("g")
            .call(d3.axisLeft(y))
    
        //Bars
        svg.selectAll("myRect")
            .data(data)
            .enter()
            .append("rect")
            .attr("x", 4)
            .attr("y", function (d) { return y(d.name); })
            .attr("width", function (d) { return x(d.value); })
            .attr("height", y.bandwidth())
            .attr("fill", function (d) {
                if (d.value > 1) {
                    return "rgb(51, 80, 92)";
                }
                else if (d.value > 1 && d.value < 4) {
                    return "rgb(118, 161, 179)"
                }
                else {
                    return "rgb(171, 209, 224)";
                }
            })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <div id="my_dataviz"></div>

    我还注意到您在每个条的 y 值上添加了 10 个像素:这可能是为了更好地手动对齐条与多个数据条目。通常这会导致问题(除非手动纠正它们): y/x 和 height/width 的 scale(value) 和 scale.bandwidth() 分别生成以轴刻度为中心的条形。如果您想要填充(条之间的空间),最简单的方法是使用比例设置:scale.padding(number) 其中number 是一个介于 0 和 1 之间的值,表示每个段的空部分:

    var margin = { top: 20, right: 30, bottom: 40, left: 90 },
        width = 360 - margin.left - margin.right,
        height = 300 - margin.top - margin.bottom;
    
    // append the svg object to the body of the page
    var svg = d3.select("#my_dataviz")
        .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform",
            "translate(" + margin.left + "," + margin.top + ")");
    
    var data = [
      {name: "a", value: 1},
      {name: "b", value: 2}
    ]
    
        // Add X axis
        var x = d3.scaleLinear()
            .domain([0, 5])
            .range([0, width]);
        svg.append("g")
            .attr("transform", "translate(0," + height + ")")
            .call(d3.axisBottom(x))
            .selectAll("text")
            .attr("transform", "translate(-10,0)rotate(-45)")
            .style("text-anchor", "end")
    
            ;
    
        // Y axis
        var y = d3.scaleBand()
            .range([0, height])
            .padding(0.1)
            .domain(data.map(function (d) { return d.name; }))
    
        svg.append("g")
            .call(d3.axisLeft(y))
    
        //Bars
        svg.selectAll("myRect")
            .data(data)
            .enter()
            .append("rect")
            .attr("x", 4)
            .attr("y", function (d) { return y(d.name); })
            .attr("width", function (d) { return x(d.value); })
            .attr("height", y.bandwidth())
            .attr("fill", function (d) {
                if (d.value > 1) {
                    return "rgb(51, 80, 92)";
                }
                else if (d.value > 1 && d.value < 4) {
                    return "rgb(118, 161, 179)"
                }
                else {
                    return "rgb(171, 209, 224)";
                }
            })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <div id="my_dataviz"></div>

    但是,如果您不想要 120 像素宽的片段怎么办?无论您有多少条,您都希望您的条始终为 20 像素左右。那么我们可以修改尺度的范围来反映域的长度:

    var margin = { top: 20, right: 30, bottom: 40, left: 90 },
        width = 360 - margin.left - margin.right,
        height = 300 - margin.top - margin.bottom;
    
    // append the svg object to the body of the page
    var svg = d3.select("#my_dataviz")
        .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform",
            "translate(" + margin.left + "," + margin.top + ")");
    
    var data = [
      {name: "a", value: 1},
      {name: "b", value: 2}
    ]
    
        // Add X axis
        var x = d3.scaleLinear()
            .domain([0, 5])
            .range([0, width]);
        svg.append("g")
            .attr("transform", "translate(0," + data.length*20 + ")")
            .call(d3.axisBottom(x))
            .selectAll("text")
            .attr("transform", "translate(-10,0)rotate(-45)")
            .style("text-anchor", "end")
    
            ;
    
        // Y axis
        var y = d3.scaleBand()
            .domain(data.map(function (d) { return d.name; }))
            .range([0, data.length*20])
            .padding(0.1);
    
        svg.append("g")
            .call(d3.axisLeft(y))
    
        //Bars
        svg.selectAll("myRect")
            .data(data)
            .enter()
            .append("rect")
            .attr("x", 4)
            .attr("y", function (d) { return y(d.name); })
            .attr("width", function (d) { return x(d.value); })
            .attr("height", y.bandwidth())
            .attr("fill", function (d) {
                if (d.value > 1) {
                    return "rgb(51, 80, 92)";
                }
                else if (d.value > 1 && d.value < 4) {
                    return "rgb(118, 161, 179)"
                }
                else {
                    return "rgb(171, 209, 224)";
                }
            })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <div id="my_dataviz"></div>

    我还更新了 x 轴的变换,您可以进一步调整 svg 高度以更好地调整大小

    【讨论】:

    • 哇!非常感谢您提供所有这些信息。非常感激。早上醒来的感觉真好,看到一个让你几乎无法入睡的问题的解决方案哈哈。再次感谢伙计。
    猜你喜欢
    • 1970-01-01
    • 2014-06-08
    • 1970-01-01
    • 2020-04-20
    • 2013-04-29
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    相关资源
    最近更新 更多