【发布时间】:2021-03-06 13:32:25
【问题描述】:
问题
我正在尝试在 D3 (v5) 中获得一个堆叠条形图,以便为不同的组提供单独的彩色条(我可以这样做,图 1),每个堆栈都有不同的颜色(取决于图 2)。
我无法找到一种方法来获取图 3 中的堆栈着色(即我希望组颜色的不同阴影随不同的堆栈高度而变化)示例(除了我希望不同的组具有不同的颜色即不重复,因为他们在这里)。
在我提供的代码示例中,有两组数据。一个简单的集合,帮助处理数据:
Animal,Group,A,B,C,D
Dog,Domestic,10,10,20,5
Cat,Domestic,20,5,10,10
Mouse,Pest,75,5,35,0
Lion,Africa,5,5,30,25
Elephant,Africa,15,15,20,20
Whale,Marine,35,20,10,45
Shark,Marine,45,55,0, 60
Fish,Marine,20, 5,30,10
还有a bigger set 我实际上正在尝试使用。
这是我正在尝试开发的bl.ocks.org 代码:
// set the dimensions and margins of the graph
const margin = {
top: 90,
right: 20,
bottom: 30,
left: 40
},
width = 960 - margin.left - margin.right,
height = 960 - margin.top - margin.bottom;
const svg = d3.select("#my_dataviz")
.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 + ")");
const y = d3.scaleBand()
.range([0, height])
.padding(0.1);
const x = d3.scaleLinear()
.range([0, width]);
const z = d3.scaleOrdinal()
.range(["none", "lightsteelblue", "steelblue", "darksteelblue"]);
d3.csv("https://gist.githubusercontent.com/JimMaltby/844ca313589e488b249b86ead0d621a9/raw/f328ad6291ffd3c9767a2dbdba5ce8ade59a5dfa/TimeBarDummyFormat.csv", d3.autoType, (d, i, columns) => {
var i = 3;
var t = 0;
for (; i < columns.length; ++i)
t += d[columns[i]] = +d[columns[i]];
d.total = t;
return d;
}
).then(function(data) {
const keys = data.columns.slice(3); // takes the column names, ignoring the first 3 items = ["EarlyMin","EarlyAll", "LateAll", "LateMax"]
// List of groups = species here = value of the first column called group -> I show them on the X axis
const Groups = d3.map(data, d => d.Group);
y.domain(data.map(d => d.Ser));
x.domain([2000, d3.max(data, d => d.total)]).nice();
z.domain(keys);
svg.append("g")
.selectAll("g")
.data(d3.stack().keys(keys)(data))
.enter().append("g")
.attr("fill", d => z(d.key)) //Color is assigned here because you want everyone for the series to be the same color
.selectAll("rect")
.data(d => d)
.enter()
.append("rect")
.attr("y", d => y(d.data.Ser))
.attr("x", d => x(d[0]))
.attr("height", y.bandwidth())
.attr("width", d => x(d[1]) - x(d[0]));
svg.append("g")
.attr("transform", "translate(0,0)")
.call(d3.axisTop(x));
svg.append("g")
.call(d3.axisLeft(y));
});
.bar {
fill: rgb(70, 131, 180);
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="my_dataviz"></div>
JSFiddle: https://jsfiddle.net/yq7bkvdL/
我的尝试
我觉得我只是缺少一些简单的东西,但我是一个编码新手,而且我的编码非常初级,所以我无法解决。
我想我要么将填充 attr 放在错误的位置。或者是我不明白如何在d3.stack的嵌套/分层数据中选择键。
我尝试了各种方法,都没有成功:
1.多种颜色
我已经尝试编写一个函数来创建一个颜色数组,通过迭代(使用forEach)“键”和“组”值/名称并将它们连接起来创建一个可以与 d3 Scale 一起使用的数组(序数)选择正确的颜色。例如,对于第一个数据集,它将创建一个数组ColoursID[DomesticA, DomesticB, DomesticC, DomesticD,PestA, PestB...],然后匹配ColourS["grey", "lightgreen", "green", "darkgreen", "yellow", ...]中的颜色
以下是这样做的尝试,以及注释掉的各种其他探索。
// List of groups = species here = value of the first column called group -> I show them on the X axis
const stack = d3.stack().keys(stackKeys)(data);
//const Groups = d3.map(data, d => d.Group);
//const ColourID = d3.map(data, d => d.Group && d.key);
// const stackID = stack.data // //stack[3].key = "D" // [2][6].data.Group = "Marine"
// const Test1 = Object.entries(stack).forEach(d => d.key);
const stackB = stack.forEach(function(d,i,j){
//var a = Object.keys(d)//= list of 3rd Level keys "0,..7,key,index"
//var a = Object.keys(d).forEach((key) => key) "undefined"
//var a = d.key //= "D" for all
d.forEach(function(d,i){
//var a = d.keys // = "function keys{} ([native code])"
//var a = Object.keys(d)
//var a = Object.keys(d) //= list of 2nd Level keys "0,1,data"
var b = data[i]["Group"]
d.forEach(function(d){
//var a = [d]["key"] // = "undefined"
//var a = Object.keys(d).forEach((key) => d[key]) // = "undefined"
var a = Object.keys(d) //= ""
// var a = d.keys //= "undefined"
data[i]["colourID"] = b + " a" + "-b " + a //d.key
})
})
});
console.log(stack)
svg.append("g")
.selectAll("g")
.data(stack)
.enter().append("g")
//.attr("fill", d => z(d.data.Group) ) //Color is assigned here because you want everyone for the series to be the same color
.selectAll("rect")
.data(d => d)
.enter().append("rect")
.attr("fill", d => colourZ(d.data.colourID)) //Color is assigned here because you want each Group to be a different colour **how do you vary the blocks?**
.attr("y", d => y(d.data.Animal) ) //uses the Column of data Animal to seperate bars
.attr("x", d=> x(d[0]) ) //
.attr("height", y.bandwidth() ) //
.attr("width", d=> x(d[1]) - x(d[0])); //
VizHub 代码:https://vizhub.com/JimMaltby/373f1dbb42ad453787dc0055dee7db81?file=index.js
2。创建第二个色阶:
我在这里使用了建议 (d3.js-adding different colors to one bar in stacked bar chart),添加了一个 if 函数来选择不同的色标,方法是添加以下代码:
//-----------------------------BARS------------------------------//
// append the rectangles for the bar chart
svg.append("g")
.selectAll("g")
.data(stack)
.enter().append("g")
//Color is assigned here because you want everyone for the series to be the same color
.selectAll("rect")
.data(d => d)
.enter().append("rect")
.attr("fill", d =>
d.data.Group == "Infrastructure"
? z2(d.key)
: z(d.key))
//.attr("class", "bar")
.attr("y", d => y(d.data.Ser) ) //Vert2Hor **x to y** **x(d.data.Ser) to y(d.data.Ser)**
.attr("x", d=> x(d[0]) ) //Vert2Hor **y to x** **y(d[1]) to x(d[0])**
.attr("height", y.bandwidth() ) //Vert2Hor **"width" to "height"** **x.bandwidth to y.bandwidth**
.attr("width", d=> x(d[1]) - x(d[0])); //Vert2Hor **"height" to "width"** **y(d[0]) - y(d[1]) to x(d[1]) - x(d[0])**
3.一个大的 IF 函数填充。
如果这是解决方案,我将不胜感激 a. 让它发挥作用,然后 b. 采用更有效的方式来实现它
在这里,我似乎又在努力选择“堆栈”数据数组的“键”。您会注意到,我一直在尝试不同的方法来选择此处代码中的密钥,但没有成功:(。
.attr("fill", function(d,i, j) {
if (d.data.Group === "Domestic") {
if (d.key === "A") { return "none"}
else if (d.key === "B") { return "lightblue"}
else if (d.key === "C") { return "blue"}
else if (d.key === "D") { return "darkblue"}
else { return "forestgreen"}
}
else if (d.data.Group === "Pest") {
if (d.key === "A") { return "yellow"}
else if (d.key === "B") { return "lightorange"}
else if (d.key === "C") { return "orange"}
else if (d.key === "D") { return "darkorange"}
else { return "Brown"} //"yellow", "lightorange", "orange", ""
}
else if (d.data.Group === "Africa") {
if (Object.keys(root.data) === 1) { return "grey"}
else if (d.key === "B") { return "lightred"}
else if (d.key === "C") { return "red"}
else if (d.key === "D") { return "darkred"}
else { return "pink"}
}
else if (d.data.Group == "Marine") {
if (stackKeys == "A") { return "lightgrey"}
else if (stackKeys[d] == "B") { return "lightblue"}
else if (stackKeys[i] == "C") { return "blue"}
else if (stackKeys[3] == "D") { return "darkblue"}
else { return "steelblue"}
}
else { return "black" }
;})
Viz Hub中的代码
【问题讨论】:
-
所以您试图根据堆栈是 a、b、c 还是 d 来填充?
-
其实你有可能开始一个jsfiddle吗?
-
虽然您在制定和研究问题方面付出了多少努力,但我不清楚该去哪里寻找。在您分享的 4 个代码示例中,我假设 bl.ocks.org 是开始工作的基础。但是,仅供参考 - 虽然您的 cmets 可能对您有意义,但它们会使您的代码更加复杂,外人更难理解。请确认我内联的代码(来自 bl.ocks.org 示例,我删除了一些非必要的东西)是您开始的基础?
-
@RubenHelsloot 你内联的代码是我开始的基础。感谢您的坚持,尽管我发表了评论。
-
而您正在寻找的是让所有片段都具有不同的颜色?那么一张由 4 叠 3 条组成的图表,每条不是 3 种颜色,而是 12 种颜色?
标签: javascript d3.js colors stack key