【问题标题】:Missing Rect Objects in D3 Bar ChartD3 条形图中缺少矩形对象
【发布时间】:2020-06-22 15:33:55
【问题描述】:

我一直致力于创建一个简单的 D3 条形图可视化,但由于某种原因,条形(矩形)没有出现在我的可视化中。可视化使用 .csv 作为用于可视化的原始数据。我可以开始使用的图表的唯一部分是轴,但即使我在绘制轴时更改函数调用的顺序,它们也会消失。

我尝试使用.selectAll("rect") 函数调用以及.join("rect").append("rect") 函数调用,但似乎没有任何效果。我写的代码如下。我尝试了许多在线资源来确定 rect 对象无法显示的原因。

我正在使用 d3.js API 版本 5。

<script>
    var margin = { top: 30, right: 30, bottom: 30, left: 30 },
        width = 1000 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

    var svg = d3.select('body').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 + ')');

    //defines the x-axis which is based on a numerical format
    var xScale = d3.scaleLinear()
        .rangeRound([0, width]);

    //defines the y-axis which is based on a numerical format    
    var yScale = d3.scaleLinear()
        .rangeRound([height, 0]);


    d3.csv("http://raw.githubusercontent.com/naija-queen/Raw-Data/master/crashing.csv").then(function (data) {
        //sets the domain of the x-axis
        xScale.domain([0, d3.max(data, function(d){
            return (Number(d.episode));
        })])

        //sets the domain of the y-axis
        yScale.domain([0, d3.max(data, function(d){
            return (Number(d.percent));
        })])

        //draws the x-axis
        svg.append('g')
        .attr("transform", "translate(0," + height + ")")
        //.ticks() command allows you to define how many ticks you want to see in the visualization
        .call(d3.axisBottom(xScale).ticks(16))

        //draws the y-axis
        svg.append("g")
        //for some reason moving arround the function call below makes the y-axis disappear
        .call(d3.axisLeft(yScale))
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("text-anchor", "end")
        .text("Percent Watched");

        //parts of a bar chart
        svg.append('bar')
        .attr("fill", "lightskyblue")
        .selectAll("rect")
        .data(data)
        .join("rect")
        // d => is basically function(d){}
        .attr("x", d => xScale(Number(d.episode)))
        .attr("y", d => yScale(Number(d.percent)))
        .attr("width", 20)
        .attr("height", d => yScale(0) - yScale(Number(d.percent)));          
    });

</script>

我是 D3 的新手,所以请尽可能解释一下你的答案。

【问题讨论】:

    标签: javascript d3.js svg bar-chart data-visualization


    【解决方案1】:

    你的问题就在这里:

    svg.append('bar')
        .attr("fill", "lightskyblue")
        .selectAll("rect")
        .data(data)
        .join("rect")
    

    您正在向 SVG 附加一个 bar 元素 - 这不是一个有效的 SVG 元素,它不会渲染,它的子元素(您要绘制的矩形)也不会渲染。

    我只是打算使用enter 选择(join 结合了 enter/exit/update 的功能,但我们应该先了解 enter 功能):

       svg
        .selectAll(null) 
        .data(data)
        .enter()
        .append("rect")    
        .attr("...")
    

    输入选择会在 DOM 中为数据数组中的每个项目创建一个元素,该元素在 DOM 中还没有对应的元素。我可以用selectAll("rect") 选择所有rect 元素,但是对于我选择的每个已经存在的元素,将不会输入数据数组中的一项。所以我什么都不选择:.selectAll(null),它创建了一个不包含 DOM 元素的空选择。这样,数据数组中的每个项目都会被输入,而不管 DOM 中已经存在什么。

    在你的情况下,使用selectAll("rect") 很好,因为svg.selectAll("rect") 不会选择rects

    现在我绑定数据数组:.data(data)

    然后我访问输入选择:.enter()。这将返回一个占位符的选择。由于我们没有选择任何内容,因此为数据数组中的每个项目创建一个占位符。现在我可以添加带有.append("rect") 的SVG 元素。有了这个,我可以选择新创建的矩形。现在我可以根据需要修改它们,例如,通过使用绑定基准来设置它们的宽度/高度、x/y 等。

    为简单起见,我在这里只介绍了使用输入选择。如果我使用 selectAll("rect") 并且 rects 已经存在,那么现在我有可能更新和/或退出选择 - 这将允许更新数据数组中有相应项目的现有矩形或退出不再对应的元素数据数组中的项目。

    var margin = { top: 30, right: 30, bottom: 30, left: 30 },
            width = 600 - margin.left - margin.right,
            height = 300 - margin.top - margin.bottom;
    
        var svg = d3.select('body').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 + ')');
    
        //defines the x-axis which is based on a numerical format
        var xScale = d3.scaleLinear()
            .rangeRound([0, width]);
    
        //defines the y-axis which is based on a numerical format    
        var yScale = d3.scaleLinear()
            .rangeRound([height, 0]);
    
    
        d3.csv("http://raw.githubusercontent.com/naija-queen/Raw-Data/master/crashing.csv").then(function (data) {
            //sets the domain of the x-axis
            xScale.domain([0, d3.max(data, function(d){
                return (Number(d.episode));
            })])
    
            //sets the domain of the y-axis
            yScale.domain([0, d3.max(data, function(d){
                return (Number(d.percent));
            })])
    
            //draws the x-axis
            svg.append('g')
            .attr("transform", "translate(0," + height + ")")
            //.ticks() command allows you to define how many ticks you want to see in the visualization
            .call(d3.axisBottom(xScale).ticks(16))
    
            //draws the y-axis
            svg.append("g")
            //for some reason moving arround the function call below makes the y-axis disappear
            .call(d3.axisLeft(yScale))
            .append("text")
            .attr("transform", "rotate(-90)")
            .attr("y", 6)
            .attr("text-anchor", "end")
            .text("Percent Watched");
    
            //parts of a bar chart
            svg
            .selectAll(null)
            .data(data)
            .enter()
            .append("rect")
            .attr("fill", "lightskyblue")
            // d => is basically function(d){}
            .attr("x", d => xScale(Number(d.episode)))
            .attr("y", d => yScale(Number(d.percent)))
            .attr("width", 20)
            .attr("height", d => yScale(0) - yScale(Number(d.percent)));          
        });
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"&gt;&lt;/script&gt;

    此外,如果您希望输入的元素包含在父 g 中,您可以使用 selectAll 嵌套 g,例如:

    svg
     .append("g")
     .selectAll(null) 
     .data(data)
     .enter()
     .append("rect")    
     .attr("...")
    

    【讨论】:

    • 非常感谢!长方形终于出现了。也谢谢你的解释!
    猜你喜欢
    • 1970-01-01
    • 2019-04-12
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    • 2022-09-17
    • 1970-01-01
    • 2013-12-24
    相关资源
    最近更新 更多