问题
I have a d3 stacked column chart that I'm very happy with. The full code is in a JS Fiddle.
What I'd like to do is lop the last data series off, and set it on its own axis, but ensure that it maintains the same scale. So if this is my data:
var dataset = [
// apples
[{"x": 1, "y": 5 }, { "x": 2, "y": 4 }, { "x": 3, "y": 2 }, { "x": 4, "y": 7 }, { "x": 5, "y": 23 }],
// oranges
[{ "x": 1, "y": 10 }, { "x": 2, "y": 12 }, { "x": 3, "y": 19 }, { "x": 4, "y": 23 }, { "x": 5, "y": 17 }],
// grapes
[{ "x": 1, "y": 22 }, { "x": 2, "y": 28 }, { "x": 3, "y": 32 }, { "x": 4, "y": 35 }, { "x": 5, "y": 43 }],
// carrots
[{"x": 1, "y": 5 }, { "x": 2, "y": 4 }, { "x": 3, "y": 23 }, { "x": 4, "y": 2 }, { "x": 5, "y": 7 }]
];
I'd like to keep apples, oranges and grapes stacked, but I want carrots separated out. Carrots is always the last series. I was hoping I could draw the carrots into the same SVG with this:
var lower_svg = d3.select("#chart")
.append("svg")
.attr("width", w)
.attr("height", b);
var lower_rects = lower_svg.selectAll("rect")
.data(dataset[3])
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", h)
.attr("height", function(d) {
return yScale(d.y);
})
.attr("width", xScale.rangeBand());
But a) that doesn't work (it doesn't draw anything) and b) that calls on the data series 3, which happens to be the last one in this example but isn't always.
And ... if it did work it would draw the carrots twice, once stacked with the other fruits and once below. I only want to draw it once, below.
What I want is to have this chart of various fruit: https://jsfiddle.net/oa7hho9q/17/
And this chart of carrots: https://jsfiddle.net/oa7hho9q/19/
Using the same x and y scales and pulling from the same dataset, where, carrots is just the last series in the set.
回答1:
I have addressed your problem like this:
Step 1:
I pop out the carrot related data.
var carrots = dataset.pop(); store it in variable carrots
Step 2
I make 2 groups
//this g(group) will hold the stacked chart for carrot
var svgcarrot = svg.append("g").attr("transform", "translate(0,200)");
//this g(group) will hold the stacked chart for other fruits
var svg = svg.append("g").attr("transform", "translate(0,-150)");
//you may change the translate to move the chart as per your choice of positioning.
Step3
Make a function to make charts input svg group and its related dataset
//here svg is the group on which you wish to draw the chart.
//dataset is the data for which the chart need to be drawn.
function makeChart(dataset, svg) {
Step4
Inside your makeChart function your usual stack bar chart code.
function makeChart(dataset, svg) {
var stack = d3.layout.stack();
stack(dataset);//set data
xScale = d3.scale.ordinal()
.domain(d3.range(dataset[0].length))
.rangeRoundBands([0, w], 0.05);
yScale = d3.scale.linear()
.domain([0,
d3.max(dataset, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y;
});
})
])
.range([0, h / 2]);//2 chart so height/2
//make groups for fruits
var groups = svg.selectAll("g")
.data(dataset)
.enter()
.append("g")
.style("fill", function(d, i) {
return colors(i);
});
//make rectangles
var rects = groups.selectAll("rect")
.data(function(d) {
return d;
})
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d, i) {
return h - b - (yScale(d.y0 + d.y));
})
.attr("height", function(d) {
return yScale(d.y);
})
.attr("width", xScale.rangeBand());
}
Step 5
Now make your first chart
makeChart(dataset, svg);//note dataset has no carrot data as its popped in step1 also the svg container group made in step 2
makeChart([carrots], svgcarrot);//make carrot chart note the svgcarrot container group made in step 2
working example here
来源:https://stackoverflow.com/questions/36660953/can-i-move-one-data-series-down-to-a-lower-x-axis-programmatically