我正在关注Horizontal stack bar
用于填充数据。如何在每个条形的末尾添加每个条形图的值。例如
以上屏幕截图适用于普通水平条形图。但我期待堆叠条形图。让我知道在哪里我可以修改代码,在上面链接给出的代码中每个堆叠水平条的末尾都有这个值
由于 普拉萨德
答案 0 :(得分:0)
你的意思是这样的吗?
参见示例 - fiddle
var data = [
{
"interest_rate":"< 4%",
"Default":60,
"Charge-off":20,
"Current":456,
"30 days":367.22,
"60 days":222,
"90 days":198,
"Default":60
},
{
"interest_rate":"4-7.99%",
"Charge-off":2,
"Default":30,
"Current":271,
"30 days":125,
"60 days":78,
"90 days":72
}
];
var margin = {
top: 20,
right: 20,
bottom: 40,
left: 60
},
width = 450 - margin.left - margin.right,
height = 315 - margin.top - margin.bottom,
that = this;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .3);
var y = d3.scale.linear().rangeRound([height, 0]);
var color = d3.scale.category20();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left").tickFormat(d3.format(".0%"));
var svg = d3.select(".viz-portfolio-delinquent-status").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 + ")");
color.domain(d3.keys(data[0]).filter(function (key) {
return key !== "interest_rate";
}));
data.forEach(function (d) {
var y0 = 0;
d.rates = color.domain().map(function (name) {
console.log();;
return {
name: name,
y0: y0,
y1: y0 += +d[name],
amount: d[name]
};
});
d.rates.forEach(function (d) {
d.y0 /= y0;
d.y1 /= y0;
});
console.log(data);
});
data.sort(function (a, b) {
return b.rates[0].y1 - a.rates[0].y1;
});
x.domain(data.map(function (d) {
return d.interest_rate;
}));
svg.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")").call(xAxis);
svg.append("g").attr("class", "y axis").call(yAxis);
var interest_rate = svg.selectAll(".interest-rate").data(data).enter().append("g").attr("class", "interest-rate").attr("transform", function (d) {
return "translate(" + x(d.interest_rate) + ",0)";
});
interest_rate.selectAll("rect").data(function (d) {
return d.rates;
}).enter().append("rect").attr("width", x.rangeBand()).attr("y", function (d) {
return y(d.y1);
}).attr("height", function (d) {
return y(d.y0) - y(d.y1);
}).style("fill", function (d) {
return color(d.name);
}).on('mouseover', function (d) {
var total_amt;
total_amt = d.amount;
console.log('----');
d3.select(".chart-tip").style('opacity', '1').html('Amount: <strong>$' + that.numberWithCommas(total_amt.toFixed(2)) + '</strong>');
}).on('mouseout', function () {
d3.select(".chart-tip").style('opacity', '0');
});
var legend = svg.selectAll(".legend").data(color.domain().slice().reverse()).enter().append("g").attr("class", "legend").attr("transform", function (d, i) {
return "translate(" + i * -70 + ",283)";
});
legend.append("rect").attr("x", width + -53).attr("width", 10).attr("height", 10).style("fill", color);
legend.append("text").attr("x", width - 40).attr("y", 5).attr("width", 40).attr("dy", ".35em").style("text-anchor", "start").text(function (d) {
return d;
});
&#13;
h1 {
font-family: helvetica, arial, sans-serif;
text-align:center;
margin-top: 80px;
}
.viz-portfolio-delinquent-status {
font-family: helvetica, arial, sans-serif;
margin: 0 auto;
font-size: 10px;
width: 450px;
height: 300px
}
path { fill: #83B0EA;}
.domain {
fill: none;
stroke: #000;
stroke-width: 1px;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<h1>D3 Stacked Bar Chart Example</h1>
<div class="viz-portfolio-delinquent-status"></div>
&#13;
答案 1 :(得分:0)
为了生成每个柱的总计数,您需要执行两个步骤:
date
和总和的对象数组。引用您已链接的d3示例,我们需要对disease
,wounds
和other
的键中的整数求和。<text>
元素,并使用预先存在的比例正确定位它们。您可以将我们转换的数据存储在名为totals
的变量中:
var totals = d3.nest()
.key(function(d) {
return d.date;
})
.rollup(function(d) {
return d3.sum(d, function(g) {
return g.disease + g.wounds + g.other;
});
})
.entries(data);
上面代码的解释:我们基本上想要根据日期执行摘要,在这种情况下,我们可以使用d3.nest()
函数。密钥将是日期,我们使用d3.nest().rollup()
来执行disease
,wounds
和other
密钥中值的总和。
这将按以下格式创建一个对象数组:totals = [{key: <date>, value: <total>}, {...}]
。请注意,日期现在存储在key
和value
中的总计中。
我们将totals
绑定到新创建的对象,并从中创建新的<text>
元素:
var totalLabels = svg.append('g').attr('class', 'totals');
totalLabels.selectAll('.total')
.data(totals)
.enter().append('text')
.attr('class', 'total')
.attr("y", function(d) {
// Retrieve the correct vertical coordinates based on the date (stored as d.key)
// Plus some pixel offset so that the text is centered vertically relative to bar
return yScale(parseDate(d.key)) + yScale.bandwidth() - 2;
})
.attr("x", function(d) {
// Retrieve the horizontal coordinates based on total (stored as d.value)
// Add 5px offset so the label does not 'stick' to end of stacked bar
return xScale(d.value) + 5;
})
.text(function(d) {
// Inject total as text content (stored as d.value)
return d.value;
});
对上述代码的解释:
<g>
包装来存储您的所有文字标签totals
将.data(totals)
绑定到文本标签来创建文本标签。我们输入数据,并附加<text>
标签xScale
和yScale
。您只需将总计传递到xScale
,即xScale(d.value)
,将日期传递到yScale
,即yScale(parseDate(d.key))
。d3.text()
将文字注入元素,并将总计作为文字内容,即d.value
。使用以下代码,我们可以创建您已链接的d3.js示例的修改,您可以在其中将总计追加到堆积条形图的末尾:
请参阅下面的概念验证示例:
var initStackedBarChart = {
draw: function(config) {
me = this,
domEle = config.element,
stackKey = config.key,
data = config.data,
margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
parseDate = d3.timeParse("%m/%Y"),
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
xScale = d3.scaleLinear().rangeRound([0, width]),
yScale = d3.scaleBand().rangeRound([height, 0]).padding(0.1),
color = d3.scaleOrdinal(d3.schemeCategory20),
xAxis = d3.axisBottom(xScale),
yAxis = d3.axisLeft(yScale).tickFormat(d3.timeFormat("%b")),
svg = d3.select("#" + domEle).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 stack = d3.stack()
.keys(stackKey)
.offset(d3.stackOffsetNone);
var layers = stack(data);
data.sort(function(a, b) {
return b.total - a.total;
});
yScale.domain(data.map(function(d) {
return parseDate(d.date);
}));
xScale.domain([0, d3.max(layers[layers.length - 1], function(d) {
return d[0] + d[1];
})]).nice();
var layer = svg.selectAll(".layer")
.data(layers)
.enter().append("g")
.attr("class", "layer")
.style("fill", function(d, i) {
return color(i);
});
layer.selectAll("rect")
.data(function(d) {
return d;
})
.enter().append("rect")
.attr("y", function(d) {
return yScale(parseDate(d.data.date));
})
.attr("x", function(d) {
return xScale(d[0]);
})
.attr("height", yScale.bandwidth())
.attr("width", function(d) {
return xScale(d[1]) - xScale(d[0])
});
var totals = d3.nest()
.key(function(d) {
return d.date;
})
.rollup(function(d) {
return d3.sum(d, function(g) {
return g.disease + g.wounds + g.other;
});
})
.entries(data);
var totalLabels = svg.append('g').attr('class', 'totals');
totalLabels.selectAll('.total')
.data(totals)
.enter().append('text')
.attr('class', 'total')
.attr("y", function(d) {
// Retrieve the correct vertical coordinates based on the date (stored as d.key)
// Plus some pixel offset so that the text is centered vertically relative to bar
return yScale(parseDate(d.key)) + yScale.bandwidth() - 2;
})
.attr("x", function(d) {
// Retrieve the horizontal coordinates based on total (stored as d.value)
// Add pixel offset so labels don't stick to end of stacked bars
return xScale(d.value) + 5;
})
.text(function(d) {
// Inject total as text content (stored as d.value)
return d.value;
});
svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + (height + 5) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis axis--y")
.attr("transform", "translate(0,0)")
.call(yAxis);
}
}
var data = [{
"date": "4/1854",
"total": 8571,
"disease": 1,
"wounds": 0,
"other": 5
}, {
"date": "5/1854",
"total": 23333,
"disease": 12,
"wounds": 0,
"other": 9
}, {
"date": "6/1854",
"total": 28333,
"disease": 11,
"wounds": 0,
"other": 6
}, {
"date": "7/1854",
"total": 28772,
"disease": 359,
"wounds": 0,
"other": 23
}, {
"date": "8/1854",
"total": 30246,
"disease": 828,
"wounds": 1,
"other": 30
}, {
"date": "9/1854",
"total": 30290,
"disease": 788,
"wounds": 81,
"other": 70
}, {
"date": "10/1854",
"total": 30643,
"disease": 503,
"wounds": 132,
"other": 128
}, {
"date": "11/1854",
"total": 29736,
"disease": 844,
"wounds": 287,
"other": 106
}, {
"date": "12/1854",
"total": 32779,
"disease": 1725,
"wounds": 114,
"other": 131
}, {
"date": "1/1855",
"total": 32393,
"disease": 2761,
"wounds": 83,
"other": 324
}, {
"date": "2/1855",
"total": 30919,
"disease": 2120,
"wounds": 42,
"other": 361
}, {
"date": "3/1855",
"total": 30107,
"disease": 1205,
"wounds": 32,
"other": 172
}, {
"date": "4/1855",
"total": 32252,
"disease": 477,
"wounds": 48,
"other": 57
}, {
"date": "5/1855",
"total": 35473,
"disease": 508,
"wounds": 49,
"other": 37
}, {
"date": "6/1855",
"total": 38863,
"disease": 802,
"wounds": 209,
"other": 31
}, {
"date": "7/1855",
"total": 42647,
"disease": 382,
"wounds": 134,
"other": 33
}, {
"date": "8/1855",
"total": 44614,
"disease": 483,
"wounds": 164,
"other": 25
}, {
"date": "9/1855",
"total": 47751,
"disease": 189,
"wounds": 276,
"other": 20
}, {
"date": "10/1855",
"total": 46852,
"disease": 128,
"wounds": 53,
"other": 18
}, {
"date": "11/1855",
"total": 37853,
"disease": 178,
"wounds": 33,
"other": 32
}, {
"date": "12/1855",
"total": 43217,
"disease": 91,
"wounds": 18,
"other": 28
}, {
"date": "1/1856",
"total": 44212,
"disease": 42,
"wounds": 2,
"other": 48
}, {
"date": "2/1856",
"total": 43485,
"disease": 24,
"wounds": 0,
"other": 19
}, {
"date": "3/1856",
"total": 46140,
"disease": 15,
"wounds": 0,
"other": 35
}];
var key = ["wounds", "other", "disease"];
initStackedBarChart.draw({
data: data,
key: key,
element: 'stacked-bar'
});
&#13;
.axis text {
font: 10px sans-serif;
}
.axis line,
.axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.path-line {
fill: none;
stroke: yellow;
stroke-width: 1.5px;
}
svg {
background: #f0f0f0;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<h2>Stacked Bar Chart - d3.v4 implementation</h2>
<div id='stacked-bar'></div>
&#13;