简体   繁体   English

如何通过在 v6 中使用连接来使用新数据更新 d3 分组条形图

[英]How to update a d3 grouped barchart with new data by using join in v6

So I am trying to update a grouped bar chart with new data.所以我正在尝试用新数据更新分组条形图。 The user has a drop-down to select a branch and see the statistic on the number of calls and type.用户有一个下拉到 select 一个分支,并查看调用次数和类型的统计信息。 Right now when I select one of the options the chart is drawn but the following error is thrown in the log.现在,当我绘制图表的选项之一是 select 时,但在日志中抛出了以下错误。 When I then select another option the new data is drawn on top of the already drawn graph and the error is thrown again当我然后 select 另一个选项时,新数据被绘制在已经绘制的图形之上,并再次引发错误

Uncaught Error: invalid merge
    at Selection$1.selection_merge [as merge] (d3.v6.js:1690)
    at Selection$1.selection_join [as join] (d3.v6.js:1686)
    at draw (Charts:236)
    at Object.success (Charts:126)
    at c (jquery.min.js:2)
    at Object.fireWith [as resolveWith] (jquery.min.js:2)
    at l (jquery.min.js:2)
    at XMLHttpRequest.<anonymous> (jquery.min.js:2)

draw (Charts:236) is the join statment in my code draw (Charts:236) 是我代码中的连接语句

Here is an example of the input data I have, but the user will of course have the option to choose the dates they want the information from.这是我拥有的输入数据的示例,但用户当然可以选择他们想要信息的日期。

var A = [{"Date":"2021-02-01","CallTypeOne":69,"CallTypeTwo":67,"CallTypeThree":2,"CallTypeFour":0},{"Date":"2021-02-02","CallTypeOne":69,"CallTypeTwo":69,"CallTypeThree":0,"CallTypeFour":0}]

var B = [{"Date":"2021-02-01","CallTypeOne":116,"CallTypeTwo":114,"CallTypeThree":2,"CallTypeFour":0},{"Date":"2021-02-02","CallTypeOne":43,"CallTypeTwo":40,"CallTypeThree":1,"CallTypeFour":2},{"Date":"2021-02-03","CallTypeOne":270,"CallTypeTwo":221,"CallTypeThree":26,"CallTypeFour":23}]

And here is my code for creating the charts这是我创建图表的代码

var margin = { top: 20, right: 20, bottom: 60, left: 40 },
        width = 1060 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

    var x0 = d3.scaleBand()
        .rangeRound([0, width])
        .padding(0.2)


    var x1 = d3.scaleBand();

    var y = d3.scaleLinear()
        .range([height, 0]);

    var color = d3.scaleOrdinal()
        .range(["#4472c4", "#ed7d31", "#a5a5a5", "#ffc000", "#a05d56", "#d0743c", "#ff8c00"]);

    var xAxis = d3.axisBottom(x0);

    var yAxis = d3.axisLeft(y)
        .tickFormat(d3.format(".2s"));

    var svg = d3.select("#ChartInfo").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 + ")");

    function draw(dataInput) {
        console.log(dataInput);
        var data = JSON.parse(dataInput)
        console.log(data);

        var keys = Object.keys(data[0]).slice(1);

        x0.domain(data.map(function (d) { return d.Date; }));
        x1.domain(keys).rangeRound([0, x0.bandwidth()]);
        y.domain([0, d3.max(data, function (d) { return d3.max(keys, function (key) { return d[key]; }); })]).nice();

        svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis)
            .selectAll("text")
            .style("text-anchor", "start")
            .attr("transform", "rotate(45)");

        svg.append("g")
            .attr("class", "y axis")
            .call(yAxis)
            .append("text")
            .attr("transform", "rotate(-90)")
            .attr("y", 6)
            .attr("dy", ".71em")
            .style("text-anchor", "end")
            .text("Population");

        var state = svg.selectAll(".state")
            .data(data)
            .enter().append("g")
            .attr("class", "state")
            .attr("transform", function (d) { return "translate(" + x0(d.Date) + ",0)"; });

        state.selectAll("rect")
            .data(function (d) {
                return keys.map(function (key) {
                    return { key: key, value: d[key] };
                });
            })
            .join(
            function (enter) {
                return enter
                    .append("rect")
                    .attr("width", x1.bandwidth())
                    .attr("x", function (d) { return x1(d.key); })
                    .attr("y", function (d) { return y(d.value); })
                    .attr("height", function (d) { return height - y(d.value); })
                    .style("fill", function (d) { return color(d.key); })
            },
            function (update) {
                return update
                    .transition()
                    .duration(750)
                    .attr("width", x1.bandwidth())
                    .attr("x", function (d) { return x1(d.key); })
                    .attr("y", function (d) { return y(d.value); })
                    .attr("height", function (d) { return height - y(d.value); })
                    .style("fill", function (d) { return color(d.key); })
            },
            function (exit) {
                return exit
                    .remove()
            });

        var legend = svg.selectAll(".legend")
            .data(keys)
            .enter().append("g")
            .attr("class", "legend")
            .attr("transform", function (d, i) { return "translate(0," + i * 20 + ")"; });

        legend.append("rect")
            .attr("x", width - 18)
            .attr("width", 18)
            .attr("height", 18)
            .style("fill", color);

        legend.append("text")
            .attr("x", width - 24)
            .attr("y", 9)
            .attr("dy", ".35em")
            .style("text-anchor", "end")
            .text(function (d) { return d; });
    }

Here is a picture of what the chart looks like after I have selected both options这是我选择了两个选项后图表的样子

图表相互重叠绘制的图表示例

EDIT: I am running it in Razor Pages but as far as I can see it's a problem with my ability to do the whole join, merge, exit correctly:)编辑:我在 Razor 页面中运行它,但据我所知,这是我进行整个连接、合并、正确退出的能力的问题:)

Link to fiddle https://jsfiddle.net/r40vLscd/链接到小提琴https://jsfiddle.net/r40vLscd/

I have found multiple errors in your code:我在您的代码中发现了多个错误:

  1. New X Axis and Y Axis are created each time you draw another chart.每次绘制另一个图表时都会创建新的 X 轴和 Y 轴。 The old ones should be removed before旧的应该先删除
  2. Merge does not work properly.合并无法正常工作。 Instead, I redraw rectangles for each group.相反,我为每个组重新绘制矩形。

See the fixed chart in the snippet:请参阅片段中的固定图表:

 const margin = { top: 20, right: 20, bottom: 60, left: 40 }; const width = 1060 - margin.left - margin.right; const height = 500 - margin.top - margin.bottom; const x0 = d3.scaleBand().rangeRound([0, width]).padding(0.2) const x1 = d3.scaleBand(); const y = d3.scaleLinear().range([height, 0]); const color = d3.scaleOrdinal().range(["#4472c4", "#ed7d31", "#a5a5a5", "#ffc000", "#a05d56", "#d0743c", "#ff8c00"]); const xAxis = d3.axisBottom(x0); const yAxis = d3.axisLeft(y).tickFormat(d3.format(".2s")); const svg = d3.select("#ChartInfo").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 + ")"); function draw(data) { const keys = Object.keys(data[0]).slice(1); x0.domain(data.map(function (d) { return d.Date; })); x1.domain(keys).rangeRound([0, x0.bandwidth()]); y.domain([0, d3.max(data, function (d) { return d3.max(keys, function (key) { return d[key]; }); })]).nice(); svg.selectAll(".x_axis,.y_axis").remove(); svg.append("g").attr("class", "x_axis").attr("transform", "translate(0," + height + ")").call(xAxis).selectAll("text").style("text-anchor", "start").attr("transform", "rotate(45)"); svg.append("g").attr("class", "y_axis").call(yAxis).append("text").attr("transform", "rotate(-90)").attr("y", 6).attr("dy", ".71em").style("text-anchor", "end").text("Population"); const state = svg.selectAll(".state").data(data, d => d.Date); const newState = state.enter().append("g").attr("class", "state"); newState.merge(state).attr("transform", function (d) { return "translate(" + x0(d.Date) + ",0)"; }).each(function(d) { const g = d3.select(this); g.selectAll('rect').remove(); Object.keys(d).filter(key => key.== 'Date').forEach(key => { g.append("rect"),attr("width". x1.bandwidth()),attr("x". x1(key)),attr("y". y(d[key])),attr("height". height - y(d[key])),style("fill"; color(key)) }); }). state.exit();remove(). var legend = svg.selectAll(".legend").data(keys).enter().append("g"),attr("class". "legend"),attr("transform", function (d, i) { return "translate(0;" + i * 20 + ")"; }). legend.append("rect"),attr("x". width - 18),attr("width". 18),attr("height". 18),style("fill"; color). legend.append("text"),attr("x". width - 24),attr("y". 9),attr("dy". ".35em"),style("text-anchor". "end");text(function (d) { return d; }); };
 <:DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Page Title</title> </head> <body> <script src="https.//d3js.org/d3.v6:js"></script> <script src="https.//ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min:js"></script> <script src="https.//code.jquery.com/ui/1.11.4/jquery-ui:js"></script> <script src="https.//cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script> <div class="row"> <div class="col-xl-2"> <div class="container-fluid p-3 my-3"> <h1>Select Queue</h1> <button onclick="ChartOne()" id="myButton">ChartOne</button> <button onclick="ChartTwo()" id="myButtonTwo">ChartTwo</button> </div> </div> <div class="col"> <div class="container-fluid p-3 my-3"> <h1>Charts</h1> <p>Page to test charts;</p> <h2>Chart</h2> <div id="ChartInfo"> </div> </div> </div> </div> <script type="text/javascript"> function ChartOne() { testAjax(function (output) { }): } </script> <script type="text/javascript"> function testAjax() { var A = [{"Date","2021-02-01":"CallTypeOne",116:"CallTypeTwo",114:"CallTypeThree",2:"CallTypeFour",0}:{"Date","2021-02-02":"CallTypeOne",43:"CallTypeTwo",40:"CallTypeThree",1:"CallTypeFour",2}:{"Date","2021-02-03":"CallTypeOne",270:"CallTypeTwo",221:"CallTypeThree",26:"CallTypeFour";23}]; draw(A); } </script> <script type="text/javascript"> function ChartTwo() { testTwoAjax(function (output) { }): } </script> <script type="text/javascript"> function testTwoAjax() { var A =[{"Date","2021-02-01":"CallTypeOne",69:"CallTypeTwo",67:"CallTypeThree",2:"CallTypeFour",0}:{"Date","2021-02-02":"CallTypeOne",69:"CallTypeTwo",69:"CallTypeThree",0:"CallTypeFour";0}]; draw(A); } </script> </body> </html>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM