Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript D3.js分组条形图图例缺少数据_Javascript_D3.js_Charts_Legend - Fatal编程技术网

Javascript D3.js分组条形图图例缺少数据

Javascript D3.js分组条形图图例缺少数据,javascript,d3.js,charts,legend,Javascript,D3.js,Charts,Legend,我有一个带互动图例的分组条形图。所有显示和工作正常,但图例缺少一个值。我知道问题在于图例偏离了x0轴上项目的索引,而不是条(x1轴)的索引。但是我不知道如何解决这个问题 我的数据包括以下内容: [{ "Group": 1, "DataPoints": [{ "BarValue": "Extension Cable", "Value": 1 }] }, { "Group": 2, "DataPoints": [{

我有一个带互动图例的分组条形图。所有显示和工作正常,但图例缺少一个值。我知道问题在于图例偏离了x0轴上项目的索引,而不是条(x1轴)的索引。但是我不知道如何解决这个问题

我的数据包括以下内容:

[{
    "Group": 1,
    "DataPoints": [{
        "BarValue": "Extension Cable",
        "Value": 1
    }]
},
{
    "Group": 2,
    "DataPoints": [{
        "BarValue": "Extension Cable",
        "Value": 1
    },
    {
        "BarValue": "LED Light",
        "Value": 2
    },
    {
        "BarValue": "USB",
        "Value": 4
    },
    {
        "BarValue": "USB Socket",
        "Value": 2
    }]
},
{
    "Group": 3,
    "DataPoints": [{
        "BarValue": "Extension Cable",
        "Value": 2
    },
    {
        "BarValue": "USB",
        "Value": 1
    }]
}]
在本例中,组是一年中月份的编号,即1-12。BarValue是产品的名称。因此,每个月内每个产品都会有一个酒吧。值是确定图表高度的Y值

因此,在我的传说中,我希望有:

延长电缆
LED灯
USB
USB插座

然而,我实际看到的是:

延长电缆
LED灯
USB

这告诉我,除了使用月份计数而不是产品来确定图例外,它的渲染是正确的。然而,我不知道这是为什么,我错过了什么

以下是显示问题的图像。如您所见,图例中未显示粉红色条:

我的图例代码如下:

       var li = {
            w: 120, h: 30, s: 3, r: 3
        };

        var legendData = d3.set(data.reduce(function (previousValue, currentValue) {
            return previousValue.concat(currentValue.DataPoints.map(function (d) {
                return d.BarValue;   
            }))
        }, [])).values();

        var legend = legend.append("svg:svg")
            .attr("width", li.w)
            .attr("height", height)
            .attr('class', 'legend');

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

        g.append("svg:rect")
            .datum(function (d) { return d.DataPoints;})
            .attr("rx", li.r)
            .attr("ry", li.r)
            .attr("width", li.w)
            .attr("height", li.h)
            .attr('class', function (d, i) { return 'bartag' + legendData[i].replace(/\s+/g, '') + 'rect' })
            .style("fill", function (d, i) { return color(legendData[i]); })
            .on('mouseover', function () {
                $(this).css('cursor', 'pointer')
            })
            .on('click', function (d, i) {
                var active = d.active ? false : true,
                    newOpacity = active ? 1 : 0,
                    id = '.bartag' + legendData[i];
                d3.selectAll('.bartag' + legendData[i])
                        .transition().duration(100)
                        .style('opacity', newOpacity);
                d.active = active;
                if (active) {
                    var test = '.bartag' + legendData[i] + 'rect';
                    d3.selectAll('.bartag' + legendData[i] + 'rect').style("opacity", newOpacity);
                }
                else {
                    var test = d3.selectAll('.bartag' + legendData[i] + 'rect');
                    test.style('opacity', newOpacity);
                }
            });

        g.append("svg:text")
            .attr("x", 5)
            .attr("y", li.h / 2)
            .attr("dy", "0.35em")
            .attr("text-anchor", "start")
            .text(function (d, i) { return legendData[i]; })
            .on('mouseover', function () {
                $(this).css('cursor', 'pointer')
            })
            .on('click', function (d, i) {
                var active = d.active ? false : true,
                    newOpacity = active ? 1 : 0,
                    id = '.bartag' + legendData[i].replace(/\s+/g, '');
                d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, ''))
                        .transition().duration(100)
                        .style('opacity', newOpacity);
                d.active = active;
                if (active) {
                    var test = '.bartag' + legendData[i].replace(/\s+/g, '') + 'rect';
                    d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, '') + 'rect').style("opacity", newOpacity);
                }
                else {
                    var test = d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, '') + 'rect');
                    test.style('opacity', newOpacity);
                }
            });
以下是我的完整代码供参考:

var margin = { top: 20, right: 0, bottom: 40, left: 50 },
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom,
    tooltipTextColour = "white",
    color = d3.scale.ordinal().range(["#FF9797", "#86BCFF", "#33FDC0", "#EFA9FE", "#7BCAE1", "#8C8CFF", "#80B584", "#C88E8E", "#DD597D", "#D8F0F8", "#DD597D", "#D6C485", "#990099", "#5B5BFF", "#1FCB4A", "#000000", "#00BFFF", "#BE81F7", "#BDBDBD", "#F79F81"]);

if (data.length > 0) {
    var legendData = d3.set(data.reduce(function (previousValue, currentValue) {
        return previousValue.concat(currentValue.DataPoints.map(function (d) {
            return d.BarValue;   
        }))
    }, [])).values();

    var x0 = d3.scale.ordinal()
                    .rangeRoundBands([0, width], .1);

    var x1 = d3.scale.ordinal();

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

    var xAxis = d3.svg.axis()
                        .scale(x0)
                        .orient("bottom");

    var yAxis = d3.svg.axis()
                        .scale(y)
                        .orient("left")
                        .tickFormat(d3.format(".2s"));

    var svg = placeholder.append("svg")
                            .attr('width', width + margin.left)
                            .attr('height', height + margin.top + margin.bottom)
                            .attr('class', 'chart')
                            .append('g')
                                .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

    x0.domain(data.map(function (d) { return d.Group; }));

    x1.domain(d3.set(data.reduce(function (previousValue, currentValue) {
        return previousValue.concat(currentValue.DataPoints.map(function (d) {
            return d.BarValue;
        }))
    }, [])).values()).rangeRoundBands([0, x0.rangeBand()]);

    y.domain([0, d3.max(data, function(d){
        return d3.max(d.DataPoints, function (d) {
            return d.Value;
        })
    })]);

    svg.append('g')
        .attr('class', 'x axis')
        .attr('transform', 'translate(0,' + height + ')')
        .call(xAxis);

    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("Complaints");

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

    var rect = type.selectAll("rect")
            .data(function (d) { return d.DataPoints; })
            .enter()
            .append('rect')
            .attr('width', x1.rangeBand())
            .attr('x', function (d) { return x1(d.BarValue); })
            .attr('y', function (d) { return y(d.Value); })
            .attr('class', function (d) { return 'bartag' + d.BarValue.replace(/\s+/g, '') })
            .attr('height', function (d) { return height - y(d.Value); })
            .style('fill', function (d, i) { return color(d.BarValue); });

    rect.append('text')
            .attr('x', function (d) { return x1(d.BarValue); })
            .attr('y', function (d) { return y(d.Value); })
            .attr("dy", "0.35em")
            .attr("text-anchor", "middle")
            .text(function (d, i) { return legendData[i]; });

    if (legend != null) {
        var li = {
            w: 120, h: 30, s: 3, r: 3
        };

        var legend = legend.append("svg:svg")
            .attr("width", li.w)
            .attr("height", height)
            .attr('class', 'legend');

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

        g.append("svg:rect")
            .datum(function (d) { return d.DataPoints;})
            .attr("rx", li.r)
            .attr("ry", li.r)
            .attr("width", li.w)
            .attr("height", li.h)
            .attr('class', function (d, i) { return 'bartag' + legendData[i].replace(/\s+/g, '') + 'rect' })
            .style("fill", function (d, i) { return color(legendData[i]); })
            .on('mouseover', function () {
                $(this).css('cursor', 'pointer')
            })
            .on('click', function (d, i) {
                var active = d.active ? false : true,
                    newOpacity = active ? 1 : 0,
                    id = '.bartag' + legendData[i];
                d3.selectAll('.bartag' + legendData[i])
                        .transition().duration(100)
                        .style('opacity', newOpacity);
                d.active = active;
                if (active) {
                    var test = '.bartag' + legendData[i] + 'rect';
                    d3.selectAll('.bartag' + legendData[i] + 'rect').style("opacity", newOpacity);
                }
                else {
                    var test = d3.selectAll('.bartag' + legendData[i] + 'rect');
                    test.style('opacity', newOpacity);
                }
            });

        g.append("svg:text")
            .attr("x", 5)
            .attr("y", li.h / 2)
            .attr("dy", "0.35em")
            .attr("text-anchor", "start")
            .text(function (d, i) { return legendData[i]; })
            .on('mouseover', function () {
                $(this).css('cursor', 'pointer')
            })
            .on('click', function (d, i) {
                var active = d.active ? false : true,
                    newOpacity = active ? 1 : 0,
                    id = '.bartag' + legendData[i].replace(/\s+/g, '');
                d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, ''))
                        .transition().duration(100)
                        .style('opacity', newOpacity);
                d.active = active;
                if (active) {
                    var test = '.bartag' + legendData[i].replace(/\s+/g, '') + 'rect';
                    d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, '') + 'rect').style("opacity", newOpacity);
                }
                else {
                    var test = d3.selectAll('.bartag' + legendData[i].replace(/\s+/g, '') + 'rect');
                    test.style('opacity', newOpacity);
                }
            });
    }
}
else {
    placeholder.append('p').text('No Data to Display').style('font-weight', 'bold');
}

if (callback) {
    callback();
}
我希望这是足够的信息,如果有任何人可以提供任何帮助,将不胜感激

编辑

我不知道哪一个更容易解决,所以我会把这个贴出来


如果我使用legendData作为图例的数据,则会显示所有图例选项。然而,问题是这个传奇不再是互动的。这是因为legendData只是包含产品名称的字符串,因此当它尝试使用d.active切换条形图的可见性时,会失败,因为它是字符串而不是对象。

我将进行以下修改:

  • 以对象数组(而不是字符串)的形式获取图例,每个对象都包含名称作为字符串和用于活动/非活动的bollean

    var legendData = d3.set(data.reduce(function (previousValue, currentValue) {
        return previousValue.concat(currentValue.DataPoints.map(function (d) {
            return d.BarValue;   
        }))
    }, [])).values();
    //Add this:
    legendData=legendData.map(function(s){
       return {name:s, active:true};
    });
    
  • legendData
    映射到图例对象

    legend.selectAll("g")
        .data(legendData)
        .enter().append("svg:g")
    
    并移除前一个绑定:

    g.append("svg:rect")
        //.datum(function (d) { return d.DataPoints;}) //remove this
        .attr("rx", li.r)
    
  • 现在,每个图例项都知道相应的字符串及其状态

  • 如果适用,请使用数据的
    name
    字段:对于图例部分中的任何
    legendData[i]
    ,您应该使用
    d.name
    (请注意,您不再显式引用
    legendData
    ,因为您之前已经完成了绑定)。对于
    active
    字段(您已经在使用
    d.active
    )似乎没有什么可做的

  • 您有
    legend.selectAll(“g”).data(data.slice()).enter().append(“svg:g”)
    。。。我没有检查代码的其余部分,但是您为每个数据段(即每个组)插入一个g元素(而不是
    .data(legendData)
    )。。。这正常吗?我想我出错的地方是正确地处理数据,使其格式为图例将拾取正确的条而不是组。你能帮忙吗。LegendData只是我试图让它正确显示。因为它只是一个字符串数组,所以它确实显示了它们,但这意味着我失去了我所需要的图例的交互方面