2016-04-27 27 views
0

積み重なった棒グラフは、すべての積み重ねにラベルがあります。各ラベルには2行のデータがあります。グラフの最初の値の出現を表示できますが、グラフはその2つの値の合計を表示する必要があります。以下は積み上げ棒グラフの値の合計を表示する方法

私のコードです:

var outerWidth = 960; 
    var outerHeight = 500; 
    var margin = { left: 130, top: 44, right: 30, bottom: 47 }; 
    var barPadding = 0.2; 

    var xColumn = "country"; 
    var yColumn = "population"; 
    var colorColumn = "religion"; 
    var layerColumn = colorColumn; 

    var hoveredColorValue; 
    var hoveredStrokeColor = "black"; 

    var innerWidth = outerWidth - margin.left - margin.right; 
    var innerHeight = outerHeight - margin.top - margin.bottom; 

    var svg = d3.select("body").append("svg") 
    .attr("width", outerWidth) 
    .attr("height", outerHeight); 
    var g = svg.append("g") 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

    // This is the layer where the bars are drawn. 
    var baseBarLayer = g.append("g"); 

    // This layer contains a semi-transparent overlay 
    // that fades out the base bars. 
    var overlayRect = g.append("g") 
    .append("rect") 
    .attr("width", innerWidth) 
    .attr("height", innerHeight) 
    .style("pointer-events", "none"); 

    // This contains the subset of bars rendered on top 
    // when you hover over the entries in the color legend. 
    var foregroundBarLayer = g.append("g"); 

    var xAxisG = g.append("g") 
    .attr("class", "x axis") 
    .attr("transform", "translate(0," + innerHeight + ")"); 
    var yAxisG = g.append("g") 
    .attr("class", "y axis"); 
    var colorLegendG = g.append("g") 
    .attr("class", "color-legend") 
    .attr("transform", "translate(596, 0)"); 

    var xScale = d3.scale.ordinal().rangeBands([0, innerWidth], barPadding); 
    var yScale = d3.scale.linear().range([innerHeight, 0]); 
    var colorScale = d3.scale.category10(); 

    var tipNumberFormat = d3.format(","); 
    var tip = d3.tip() 
    .attr("class", "d3-tip") 
    .offset([-10, 0]) 
    .html(function(d) { 
     return [ 
     d[colorColumn], 
     " in ", 
     d[xColumn], 
     ": ", 
     tipNumberFormat(d[yColumn]) 
     ].join(""); 
    }); 
    g.call(tip); 

    // Use a modified SI formatter that uses "B" for Billion. 
    var siFormat = d3.format("s"); 
    var customTickFormat = function (d){ 
    return siFormat(d).replace("G", "B"); 
    }; 

    var xAxis = d3.svg.axis().scale(xScale).orient("bottom") 
    .outerTickSize(0); 
    var yAxis = d3.svg.axis().scale(yScale).orient("left") 
    .ticks(5) 
    .tickFormat(customTickFormat) 
    .outerTickSize(0); 

    var colorLegend = d3.legend.color() 
    .scale(colorScale) 
    .shapePadding(6.24) 
    .shapeWidth(25) 
    .shapeHeight(25) 
    .labelOffset(5); 

    function render(data){ 

    var nested = d3.nest() 
     .key(function (d){ return d[layerColumn]; }) 
     .entries(data); 

    var stack = d3.layout.stack() 
     .y(function (d){ return d[yColumn]; }) 
     .values(function (d){ return d.values; }); 

    var layers = stack(nested.reverse()).reverse(); 

    xScale.domain(layers[0].values.map(function (d){ 
     return d[xColumn]; 
    })); 

    yScale.domain([ 
     0, 
     d3.max(layers, function (layer){ 
     return d3.max(layer.values, function (d){ 
      return d.y0 + d.y; 
     }); 
     }) 
    ]); 

    colorScale.domain(layers.map(function (layer){ 
     return layer.key; 
    })); 

    xAxisG.call(xAxis); 
    yAxisG.call(yAxis); 

    renderBars(baseBarLayer, layers); 

    if(hoveredColorValue){ 
     setOverlayTransparency(0.7); 
     renderBars(foregroundBarLayer, layers.filter(function (layer){ 
     return layer.key === hoveredColorValue; 
     })); 
    } else { 
     setOverlayTransparency(0.0); 
     renderBars(foregroundBarLayer, []); 
    } 

    colorLegendG.call(colorLegend); 

    // Move the text down a bit. 
    colorLegendG.selectAll("text").attr("y", 4); 

    listenForHover(colorLegendG.selectAll("rect"), data); 
    listenForHover(colorLegendG.selectAll("text"), data); 
    } 

    function setOverlayTransparency(alpha){ 
    overlayRect 
     .transition().duration(400) 
     .attr("fill", "rgba(255, 255, 255, " + alpha + ")"); 
    } 

    function renderBars(g, layers){ 
    var layerGs = g.selectAll(".layer").data(layers); 
    layerGs.enter().append("g").attr("class", "layer"); 
    layerGs.exit().remove(); 
    layerGs.style("fill", function (d){ 
     return colorScale(d.key); 
    }); 

    var bars = layerGs.selectAll("rect").data(function (d){ 
     return d.values; 
    }); 
    bars.enter().append("rect") 
     .on("mouseover", tip.show) 
     .on("mouseout", tip.hide); 
    bars.exit().remove(); 
    bars 
     .attr("x", function (d){ return xScale(d[xColumn]); }) 
     .attr("y", function (d){ return yScale(d.y0 + d.y); }) 
     .attr("width", xScale.rangeBand()) 
     .attr("height", function (d){ return innerHeight - yScale(d.y); }); 
    } 

    function listenForHover(selection, data){ 
    selection 
     .on("mouseover", function (d){ 
     hoveredColorValue = d; 
     render(data); 
     }) 
     .on("mouseout", function (d){ 
     hoveredColorValue = null; 
     render(data); 
     }) 
     .style("cursor", "pointer"); 
    } 

    function type(d){ 
    d.population = +d.population; 
    return d; 
    } 

    d3.csv("data.csv", type, render); 

以下はサンプルデータです:

Continent country religion gender population 
Asia China Christian male 68410000 
Asia China Unaffiliated male 700680000 
North America USA Christian male 243060000 
North America USA Unaffiliated male 50980000 
South America Brazil Christian male 173300000 
South America Brazil Unaffiliated male 15410000 
Asia China Christian female 24363526.41 
Asia China Unaffiliated female 52308051.93 
North America USA Christian female 12829311.53 
North America USA Unaffiliated female 17756518.63 
South America Brazil Christian female 85172307.14 
South America Brazil Unaffiliated female 12802705.11 
+0

あなたのコードで動作するfiddle/jsbin/plnkrを提供できますか? – iulian

+0

@iulianはここのフィドルリンクです:https://jsfiddle.net/GM71819/bfz6k3m6/。私はあなたの質問に埋め込まれたサンプルデータを見るように要求するこのfiddlesoに私のcsvをリンクする方法を知らない。 – Glenn

答えて

1

あなたはd3は、単純にするように、あなたはそれを持っている右の後にデータを事前処理する必要がありますそれを取って引く。あなたのrender機能、前工程で使用すると、受信データを、その後

function combineMaleAndFemale (data) { 
    var temp = {}; 
    var result = []; 

    // Add up population from the same continent and country 
    data.forEach(function (value) { 
     var combinedKey = value.Continent + '_' + value.country; 
     if (!temp.hasOwnProperty(combinedKey)) { 
     temp[combinedKey] = value; 
     } else { 
     temp[combinedKey].population += value.population; 
     } 
    }); 

    // Generate an array with combined population values. 
    for (prop in temp) { 
     if (temp.hasOwnProperty(prop)) { 
     result.push(temp[prop]); 
     } 
    } 

    return result; 
    } 

そして、:

はこのためには、次のような機能が必要になります。

function render(data){ 

    var nested = d3.nest() 
     .key(function (d){ return d[layerColumn]; }) 
     .entries(data); 

    // For each religion type, pre-process the data to add up populations. 
    nested.forEach(function(religion) { 
     religion.values = combineMaleAndFemale(religion.values); 
    }); 
    ... 

ここでは、あなたのフィドルのworking forkです。

+0

多くのありがとう。これは完璧に見える。ラジオボタンとドロップダウンを追加してデータをさらにフィルタリングできますか?たとえば、性別のラジオボタンと大陸のドロップダウンを希望します。私はjQueryを使って簡単に行うことができましたが、d3ではデータをフィルタリングするためのメソッドがありますか? – Glenn

+0

'.on( 'click')'イベントハンドラを 'd3'で使うことができます。これは' jQuery'と似ていますが、問題がなければjqueryとd3の両方を組み合わせることができます。 [this](http://bl.ocks.org/d3noob/5d621a60e2d1d02086bf)d3のマウスクリックイベントを処理する例を確認してください。 – iulian

+0

@グレン、私の答えが元の質問に対処したと思われる場合は、それを受け入れられた答えとしておきますか?同じ問題に直面している他の人々が、この解決策が働いていることを知ってください。宜しくお願いします! – iulian