【问题标题】:D3.js Grouped bar chart with JSON dataD3.js 带有 JSON 数据的分组条形图
【发布时间】:2017-04-20 08:10:21
【问题描述】:

我是d3.js 的新手。我想在分组条形图中映射JSON 数据,如图所示,例如https://i.stack.imgur.com/9BLVz.png。我知道我的 x 缩放有问题。根据我的图表,x 应该显示月份和 y 轴小时数。它给了我 6 个条形图,但由于某种原因,条形图彼此重叠。有人可以帮我看看吗。

来自 MariaDB 作为对象的 JSON 数据。

[
    {"name":"jhon","hours":"9","months":"August"},
    {"name":"jack","hours":"8","months":"August"},
    {"name":"jhon","hours":"7","months":"July"},
    {"name":"jack","hours":"6","months":"July"},
    {"name":"jhon","hours":"4","months":"June"},
    {"name":"jack","hours":"5","months":"June"}
] 

代码

<!DOCTYPE html>
<meta charset="utf-8">
<style>
    .bar {
      fill: steelblue;
      stroke:black
    }

    .bar:hover {
      fill: brown;
    }

    .axis--x path {
      display: none;
    }

</style>

<svg width="500" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
    var svg = d3.select("svg"),
        margin = {top: 20, right: 20, bottom: 30, left: 40},
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom;

    var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
        y = d3.scaleLinear().rangeRound([height, 0]);

    var g = svg.append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    d3.json("http://localhost:8888/index.php?r=emp/gethours", function(d) {

    var ydomain=d3.extent(d,function(d){return d.hours;});

    x.domain(d.map(function(d,i) {return d.months}));

    y.domain(ydomain);

    g.selectAll(".bar")
        .data(d)
        .enter().append("rect")
        .attr("x", function(d,i) { return x(d.months) })
        .attr("y", function(d) {return y(d.hours); })
        .attr("width", 40)
        .attr("height", function(d) { return height - y(d.hours); })
    });

</script>

建议我修改数据和代码是

为此生成的条形图是https://i.stack.imgur.com/VowEA.png

[{"name":"jhon","hours":"8","months":"June","emp_id":"1"},{"name":"jack","hours":"6","months":"June","emp_id":"2"},{"name":"jhon","hours":"6","months":"July","emp_id":"1"},{"name":"jack","hours":"7","months":"July","emp_id":"2"},{"name":"jhon","hours":"8","months":"August","emp_id":"1"},{"name":"jack","hours":"9","months":"August","emp_id":"2"}]

<style>

.bar {
  fill: steelblue;
  stroke:black
}

.bar:hover {
  fill: brown;
}

.axis--x path {
  display: none;
}

</style>
<svg width="500" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

    var svg = d3.select("svg"),
    margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

                var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
                    y = d3.scaleLinear().rangeRound([height, 0]);



    var g = svg.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var z = d3.scaleOrdinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

    d3.json("http://localhost:8888/index.php?r=emp/gethours", function(d) {


                        var ymaxdomain=d3.max(d,function(d){return parseInt(d.hours);});
                        var x1domain=d3.extent(d,function(d){return parseInt(d.emp_id);});


                        x.domain(d.map(function(d) {return d.months}));
                        y.domain([0,ymaxdomain]);

                        var x1=d3.scaleBand().rangeRound([0, x.bandwidth()]);
                        x1.domain(x1domain);

                         g.selectAll(".bar")
                        .data(d)
                        .enter().append("rect")
                        .attr("x", function(d,i) {console.log(d,i); return (x(d.months)+x1(parseInt(d.emp_id))); })

                        .attr("y", function(d) {return y(d.hours); })
                        .attr("width",x1.bandwidth())
                        .attr("height", function(d) { return height - y(parseInt(d.hours)); })
                        .attr("fill", function(d,i) { return z(d.emp_id); });



                         g.append("g")
                            .attr("class", "axis")
                            .attr("transform", "translate(0," + height + ")")
                            .call(d3.axisBottom(x));


                             g.append("g")
                                .attr("class", "axis")
                                .call(d3.axisLeft(y).ticks(null, "s"))
                                .append("text")
                                .attr("x", 2)
                                .attr("y", y(y.ticks().pop()) + 0.5)
                                .attr("dy", "0.32em")
                                .attr("fill", "#000")
                                .attr("font-weight", "bold")
                                .attr("text-anchor", "start")
                                .text("Hours");





});

</script>

【问题讨论】:

    标签: d3.js bar-chart


    【解决方案1】:

    Json 数据

    [{"name":"jhon","hours":"8","months":"June","emp_id":"1"},
     {"name":"jack","hours":"6","months":"June","emp_id":"2"},
     {"name":"jim","hours":"7","months":"June","emp_id":"3"},
     {"name":"tim","hours":"4","months":"June","emp_id":"4"},
     {"name":"jhon","hours":"6","months":"July","emp_id":"1"},
     {"name":"jack","hours":"7","months":"July","emp_id":"2"},
     {"name":"jim","hours":"8","months":"July","emp_id":"3"},
     {"name":"tim","hours":"6","months":"July","emp_id":"4"},
     {"name":"jhon","hours":"8","months":"August","emp_id":"1"},
     {"name":"jack","hours":"9","months":"August","emp_id":"2"},
     {"name":"jim","hours":"7","months":"August","emp_id":"3"},
     {"name":"tim","hours":"8","months":"August","emp_id":"4"}]
    

    答案 -------------------------------------------- -------------

    分组条形图图像https://i.stack.imgur.com/1ud5S.png

    <!DOCTYPE html>
    <meta charset="utf-8">
    <style>
    
    .bar {
      fill: steelblue;
      stroke:black
    }
    
    .bar:hover {
      fill: brown;
    }
    
    .axis--x path {
      display: none;
    }
    
    </style>
    <svg width="600" height="600"></svg>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script>
    
        var svg = d3.select("svg"),
        margin = {top: 20, right: 20, bottom: 30, left: 40},
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom;
    
                    var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
                        y = d3.scaleLinear().rangeRound([height, 0]);
    
    
    
        var g = svg.append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
        var z = d3.scaleOrdinal()
        .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
    
        d3.json("http://localhost:8888/index.php?r=emp/gethours", function(d) {
    
    
                        var ymaxdomain=d3.max(d,function(d){return d.hours;});
                            x.domain(d.map(function(d) {return d.months}));
                            y.domain([0,ymaxdomain]);
    
                        var x1=d3.scaleBand().rangeRound([0, x.bandwidth()]);
                            x1.domain(d.map(function(d) {return d.emp_id;}));
    
                             g.selectAll(".bar")
                            .data(d)
                            .enter().append("rect")
                            .attr("x", function(d,i) {return (x(d.months)+x1(d.emp_id)); })
    
                            .attr("y", function(d) {return y(d.hours); })
                            .attr("width",x1.bandwidth())
                            .attr("height", function(d) { return height - y(d.hours); })
                            .attr("fill", function(d,i) { return z(d.emp_id); });
    
                                g.append("g")
                                .attr("class", "axis")
                                .attr("transform", "translate(0," + height + ")")
                                .call(d3.axisBottom(x));
    
                                    g.append("g")
                                    .attr("class", "axis")
                                    .call(d3.axisLeft(y))
                                    .append("text")
                                    .attr("x", 2)
                                    .attr("y", y(y.ticks().pop()) + 0.5)
                                    .attr("dy", "0.32em")
                                    .attr("fill", "#000")
                                    .attr("font-weight", "bold")
                                    .attr("text-anchor", "start")
                                    .text("Hours");
    
    });
    
    </script>
    

    【讨论】:

    • 感谢 Lary Ciminera 的帮助。
    【解决方案2】:

    就像在https://bl.ocks.org/mbostock/3887051 中一样,您需要第二个 x 轴来移动每个“组”的矩形。 看看var x1;,它的域名是.rangeRound([0, x0.bandwidth()]);

    在你的代码中你可以做

       var  d = [
            {"name":"jhon","hours":"9","months":"August","group":0},
            {"name":"jack","hours":"8","months":"August","group":1},
            {"name":"jhon","hours":"7","months":"July","group":0},
            {"name":"jack","hours":"6","months":"July","group":1},
            {"name":"jhon","hours":"4","months":"June","group":0},
            {"name":"jack","hours":"5","months":"June","group":1}
        ]
    
    x1.domain([0,1]) 
    ...
    .attr("x", function(d) { return x(d.months)+x1(d.group) })
    

    【讨论】:

    • 感谢 Lary 的解决方案,但是我无法修改我的 JSON 数据,因为它来自带有连接查询的数据库。
    • 你总是可以在你的js中做一个d.forEach来“水合”你的数据,或者根据你的数据创建一个定义组值的函数,你可以在不修改数据的情况下实现它,做你需要一个例子吗?
    • 当然先生,这真的很有帮助。请根据我的数据进行操作,以便我轻松掌握..
    • 上让我看看
    【解决方案3】:

    哦,我发现了你的问题 改变

    var ydomain=d3.extent(d,function(d){return d.hours;});
    

    var ymaxdomain=d3.max(d,function(d){return d.hours;});
        y.domain([0,ymaxdomain]);
    

    y 轴上的最小值是 4 而不是 0

    编辑: 您还必须在定义 x 域之后移动 x1 范围的定义:

        x.domain(d.map(function(d,i) {return d.months}));
    // this should go after
         var x1=d3.scaleBand().rangeRound([0, x.bandwidth()]);
    

    【讨论】:

    • 移动 var x1=d3.scaleBand().rangeRound([0, x.bandwidth()]);在 x.domain(d.map(function(d,i) {return d.months})); 之后
    • 我编辑了我的答案以解决您的第二个轴问题,x1 取决于 x 带宽,该带宽取决于 x 域,因此您必须在之后进行。试试看,对我有用
    • 好吧,我不能再上传图片了。现在他们之间有我不想要的差距。我会删除第二张图片请检查图片的第二个链接,我想提一提你是真是乐于助人的人。
    • 将矩形宽度更改为 x1.bandwidth
    • 我这样做了,多亏了它的工作,但对于更多的日期它不起作用 [{"hours":"5","months":"June","emp_id":"1 "},{"hours":"4","months":"June","emp_id":"2"},{"hours":"6","months":"June","emp_id": "3"},{"hours":"6","months":"July","emp_id":"1"},{"hours":"7","months":"July","emp_id ":"2"},{"hours":"8","months":"July","emp_id":"3"},{"hours":"8","months":"August", "emp_id":"1"},{"hours":"9","months":"August","emp_id":"2"},{"hours":"5","months":"August ","emp_id":"3"}]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-12
    • 1970-01-01
    • 2012-11-28
    • 2014-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多