Гистограмма d3js: могут ли две полосы представлять две разные категории / переменные?

У меня есть данные, которые выглядят примерно так:

var data = {

     { name: Andrew,
       date: 12/08/07,
       alpha: 1.2,
       beta: 3.4
     },
     { name: Fred,
       date: 14/12/06,
       alpha: 1.7,
       beta: 2.8
     }
};

Я хочу, чтобы гистограмма с именами на оси х и каждое имя имели две полосы: одну для альфы и одну для беты. Все примеры, с которыми я сталкивался, имеют сгруппированные столбцы внутри категории / формата (например, все столбцы, представляющие даты и т. Д.), И поэтому их решения не сильно помогают. Я достиг этого далеко:

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

    var x1 = d3.scale.ordinal();

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

    var color = d3.scale.ordinal()
            .range([ "#6b486b", "#ff8c00"]);

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

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

    var svg = d3.select("#punchcard").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 ageNames = ["Alpha", "Beta"];

    x0.domain(patient_names);
    x1.domain(ageNames).rangeRoundBands([0, x0.rangeBand()], 0);
    console.log(patientList);


    console.log(data);

    var alpha_max = d3.max(data, function(d) {return parseFloat(d.alpha); });
    var beta_max = d3.max(data, function(d) { return parseFloat(d.beta); });

    console.log(alpha_max);
    console.log(beta_max);
    var y_domain = [ alpha_max, beta_max];

    y.domain([0, parseFloat(d3.max(y_domain))+0.5]);

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

    svg.selectAll("bars")
        .data(data)
        .enter().append("rect")
        .attr("transform", function(d) { return "translate(" + x0(d.name)+",0)";})
        .style("fill", "#ff8c00")
        .attr("x", function(d) { return x1(d.alpha); })
        .attr("width", x1.rangeBand())      
        .attr("y", function(d) { return y(d.alpha); })
        .attr("height", function(d) { return height - y(d.alpha); });

    svg.selectAll("bars")
        .data(data)
        .enter().append("rect")
        .style("fill", "#6b486b")
        .attr("transform", function(d) { return "translate(" + x0(d.name)+",0)";})
        .attr("x", function(d) { return x1(d.beta); })
        .attr("width", x1.rangeBand())      
        .attr("y", function(d) { return y(d.beta); })
        .attr("height", function(d) { return height - y(d.beta); });


var legend = svg.selectAll(".legend")
      .data(ageNames.slice().reverse())
    .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; });

Этот код накладывает альфа и бета бары, а не друг на друга. Я часами смотрел на различные примеры, но до сих пор не могу понять, как это сделать.

Заранее спасибо!

1 ответ

Решение

Вы можете создать структуру данных вложенного массива с одним объектом для каждой переменной, используя функцию отображения во втором соединении данных.

Сначала вы присоединяете свои группы к массиву объектов данных, а затем динамически создаете подмассив для каждой группы, используя функцию во вложенном соединении данных:

var propertyNames = ["Alpha", "Beta"];

var groups = plottingArea.selectAll("g.groups")
                .data(data);

/* and handle the enter selection, classes, etc */

var bars = groups.selectAll("rect.bars")
                .data( function(d) {
                   //the `d` value is the data object for the *group*
                   //this function needs to return an array of data objects
                   //representing each bar in the group

                   return propertyNames.map( function(property){
                      //to get one bar for each variable, start with the
                      //array of variable names, and use a map function
                      //to create data objects for each:

                      return { type: property,
                               value: d[property],
                               name: d.name,
                               date: d.date
                             };

                   });

                });

Остальная часть кода должна следовать стандартной сгруппированной структуре гистограммы. Внутренние объекты данных, которые вы создаете, должны содержать все данные, необходимые для правильного расположения и цвета каждой полосы.

Другие вопросы по тегам