我有一段规范化堆积条形图的代码。我想将它转换为标准化的horzintal堆积条形图。
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
rect.bordered {
stroke: #E6E6E6;
stroke-width: 2px;
}
body {
font-size: 9pt;
font-family: Consolas, courier;
}
text.axis {
fill: #000;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
.legend line {
stroke: #000;
shape-rendering: crispEdges;
}
form {
position: absolute;
right: 10px;
top: 10px;
}
</style>
<script src="http://d3js.org/d3.v3.js" type="text/javascript"></script>
<title></title>
</head>
<body>
<form>
</form>
<div id="chart"></div>
<script type="text/javascript">
var margin = {top: 20, right: 231, bottom: 140, left: 40},
width = 1000 - margin.left - margin.right,
height = 800 - margin.top - margin.bottom;
var xscale = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var yscale = d3.scale.linear()
.rangeRound([height, 0]);
var colors = d3.scale.ordinal()
.range(["3b5999", "ff5700", "55acee", "0077B5", "ff0084", "3f729b", "34465d","FFFC00","bd081c","dd4b39"]);
var xaxis = d3.svg.axis()
.scale(xscale)
.orient("bottom");
var yaxis = d3.svg.axis()
.scale(yscale)
.orient("left")
.tickFormat(d3.format(".0%")); // **
var svg = d3.select("body").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 + ")");
// load and handle the data
d3.csv("a.csv", function(error, data) {
// rotate the data
var categories = d3.keys(data[0]).filter(function(key) { return key !== "Day"; });
var parsedata = categories.map(function(name) { return { "Day": name }; });
data.forEach(function(d) {
parsedata.forEach(function(pd) {
pd[d["Day"]] = d[pd["Day"]];
});
});
// map column headers to colors (except for 'Day' and 'Base: All Respondents')
colors.domain(d3.keys(parsedata[0]).filter(function(key) { return key !== "Day" && key !== "Base: All Respondents"; }));
// add a 'responses' parameter to each row that has the height percentage values for each rect
parsedata.forEach(function(pd) {
var y0 = 0;
// colors.domain() is an array of the column headers (text)
// pd.responses will be an array of objects with the column header
// and the range of values it represents
pd.responses = colors.domain().map(function(response) {
var responseobj = {response: response, y0: y0, yp0: y0};
y0 += +pd[response];
responseobj.y1 = y0;
responseobj.yp1 = y0;
return responseobj;
});
// y0 is now the sum of all the values in the row for this category
// convert the range values to percentages
pd.responses.forEach(function(d) { d.yp0 /= y0; d.yp1 /= y0; });
// save the total
pd.totalresponses = pd.responses[pd.responses.length - 1].y1;
});
// sort by the value in 'Right Direction'
// parsedata.sort(function(a, b) { return b.responses[0].yp1 - a.responses[0].yp1; });
// ordinal-ly map categories to x positions
xscale.domain(parsedata.map(function(d) { return d.Day; }));
// add the x axis and rotate its labels
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xaxis)
.selectAll("text")
.attr("y", 5)
.attr("x", 7)
.attr("dy", ".35em")
.attr("transform", "rotate(65)")
.style("text-anchor", "start");
// add the y axis
svg.append("g")
.attr("class", "y axis")
.call(yaxis);
// create svg groups ("g") and place them
var category = svg.selectAll(".category")
.data(parsedata)
.enter().append("g")
.attr("class", "category")
.attr("transform", function(d) { return "translate(" + xscale(d.Day) + ",0)"; });
// draw the rects within the groups
category.selectAll("rect")
.data(function(d) { return d.responses; })
.enter().append("rect")
.attr("width", xscale.rangeBand())
.attr('fill-opacity', 0.7)
.attr("y", function(d) { return yscale(d.yp1); })
.attr("height", function(d) { return yscale(d.yp0) - yscale(d.yp1); })
.style("fill", function(d) { return colors(d.response); });
// position the legend elements
var legend = svg.selectAll(".legend")
.data(colors.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(20," + ((height - 18) - (i * 20)) + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", colors);
legend.append("text")
.attr("x", width + 10)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d) { return d; });
// animation
d3.selectAll("input").on("change", handleFormClick);
function handleFormClick() {
if (this.value === "bypercent") {
transitionPercent();
} else {
transitionCount();
}
}
// transition to 'percent' presentation
function transitionPercent() {
// reset the yscale domain to default
yscale.domain([0, 1]);
// create the transition
var trans = svg.transition().duration(250);
// transition the bars
var categories = trans.selectAll(".category");
categories.selectAll("rect")
.attr("y", function(d) { return yscale(d.yp1); })
.attr("height", function(d) { return yscale(d.yp0) - yscale(d.yp1); });
// change the y-axis
// set the y axis tick format
yaxis.tickFormat(d3.format(".0%"));
svg.selectAll(".y.axis").call(yaxis);
}
// transition to 'count' presentation
function transitionCount() {
// set the yscale domain
yscale.domain([0, d3.max(parsedata, function(d) { return d.totalresponses; })]);
// create the transition
var transone = svg.transition()
.duration(250);
// transition the bars (step one)
var categoriesone = transone.selectAll(".category");
categoriesone.selectAll("rect")
.attr("y", function(d) { return this.getBBox().y + this.getBBox().height - (yscale(d.y0) - yscale(d.y1)) })
.attr("height", function(d) { return yscale(d.y0) - yscale(d.y1); });
// transition the bars (step two)
var transtwo = transone.transition()
.delay(350)
.duration(350)
.ease("bounce");
var categoriestwo = transtwo.selectAll(".category");
categoriestwo.selectAll("rect")
.attr("y", function(d) { return yscale(d.y1); });
// change the y-axis
// set the y axis tick format
yaxis.tickFormat(d3.format(".2s"));
svg.selectAll(".y.axis").call(yaxis);
}
});
d3.select(self.frameElement).style("height", (height + margin.top + margin.bottom) + "px");
</script>
</body>
我应该做出哪些改变?我尝试在初始化中交换xscale和yscale变量。但我仍然没有得到所需的输出。我会感谢任何帮助/建议。
编辑:D3.js Stacked Bar Chart, from vertical to horizontal这也不起作用。
以上代码的灵感来自http://bl.ocks.org/tmaybe/6144082示例,我只对标准化/百分比版本感兴趣。