猿问

D3 堆叠条形图,每个堆叠由不同组设置不同的颜色,

问题

我试图在 D3 (v5) 中获得一个堆叠条形图,为不同的组提供单独的彩色条形(我可以做到,图 1),每个堆叠具有不同的颜色(取决于图 2)。

https://img1.mukewang.com/64e7297a0001e58e06470316.jpg

我找不到一种方法来获得堆栈着色(即我希望组颜色的不同色调随不同的堆栈高度而变化)图 3 中的示例(除非我希望不同的组具有不同的颜色,即不重复)因为他们在这里)。

https://img1.mukewang.com/64e729870001d0d706530405.jpg

在我提供的代码示例中,有两组数据。一个简单的设置,可以帮助处理数据:


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

我实际上正在尝试使用一个更大的集合。这是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;

    }


  )

JSFiddle: https://jsfiddle.net/yq7bkvdL/

我尝试过的

我觉得我只是错过了一些简单的东西,但我是一个编码菜鸟,我的编码非常初级,所以我无法解决它。

我想我要么把填充attr放在错误的地方。或者是我不明白如何在 的嵌套/分层数据中选择键d3.stack

我尝试了各种方法,但都没有成功:

1.颜色数组 我尝试编写一个函数来创建颜色数组,通过迭代(使用forEach)“键”和“组”值/名称并将它们连接起来创建一个可以与d3 缩放(顺序)以选择正确的颜色。例如,对于第一个数据集,它将创建一个数组ColoursID [DomesticA, DomesticB, DomesticC, DomesticD,PestA, PestB...],然后与中的颜色相匹配ColourS ["grey", "lightgreen", "green", "darkgreen", "yellow", ...]

下面是这样做的尝试,以及注释掉的各种其他探索。


森林海
浏览 172回答 1
1回答

HUX布斯

如果您想在条形长度较小的情况下稍微改变条形颜色,您可以使用fill-opacity并保持fill相同!这样,如果值较浅,则颜色会不太明显且较浅。opacity只需创建一个带有 range 的新比例即可[0.3, 1]。我选择 0.3 是因为 0 不透明度意味着条形图不可见,而您通常不希望这样。我添加了一个单独的值d.height来表示条形的整个可见高度,该高度与 start 分开(但相当于d.Min + d.All + d.Max)。现在,只需将该属性应用于每个条形即可完成。您可以选择将范围设置为[0, 1]而不用于d3.extent域 - 这可能会导致类似的结果,尽管您可以通过思想实验发现一些差异。现在该fill-opacity属性已在每个柱上设置。因此同一堆栈中的条具有相同的fill-opacity值。但请注意,这完全是可选的,您也可以应用不同的值。// set the dimensions and margins of the graphconst margin = {&nbsp; &nbsp; top: 90,&nbsp; &nbsp; right: 20,&nbsp; &nbsp; bottom: 30,&nbsp; &nbsp; left: 40&nbsp; },&nbsp; width = 960 - margin.left - margin.right,&nbsp; height = 960 - margin.top - margin.bottom;const svg = d3.select("#my_dataviz")&nbsp; .append("svg")&nbsp; .attr("width", width + margin.left + margin.right)&nbsp; .attr("height", height + margin.top + margin.bottom)&nbsp; .append("g")&nbsp; .attr("transform",&nbsp; &nbsp; "translate(" + margin.left + "," + margin.top + ")");const y = d3.scaleBand()&nbsp; .range([0, height])&nbsp; .padding(0.1);const x = d3.scaleLinear()&nbsp; .range([0, width]);const z = d3.scaleOrdinal()&nbsp; .range(["none", "lightsteelblue", "steelblue", "darksteelblue"]);const opacity = d3.scaleLinear()&nbsp; .range([0.3, 1]);d3.csv("https://gist.githubusercontent.com/JimMaltby/844ca313589e488b249b86ead0d621a9/raw/f328ad6291ffd3c9767a2dbdba5ce8ade59a5dfa/TimeBarDummyFormat.csv", d3.autoType, (d, i, columns) => {&nbsp; &nbsp; &nbsp; var i = 3;&nbsp; &nbsp; &nbsp; var t = 0;&nbsp; &nbsp; &nbsp; for (; i < columns.length; ++i)&nbsp; &nbsp; &nbsp; &nbsp; t += d[columns[i]] = +d[columns[i]];&nbsp; &nbsp; &nbsp; d.total = t;&nbsp; &nbsp; &nbsp; d.height = d.total - d.Start;&nbsp; &nbsp; &nbsp; return d;&nbsp; &nbsp; }&nbsp; ).then(function(data) {&nbsp; &nbsp; const keys = data.columns.slice(3); // takes the column names, ignoring the first 3 items = ["EarlyMin","EarlyAll", "LateAll", "LateMax"]&nbsp; &nbsp; // List of groups = species here = value of the first column called group -> I show them on the X axis&nbsp; &nbsp; const Groups = d3.map(data, d => d.Group);&nbsp; &nbsp; y.domain(data.map(d => d.Ser));&nbsp; &nbsp; x.domain([2000, d3.max(data, d => d.total)]).nice();&nbsp; &nbsp; z.domain(keys);&nbsp; &nbsp; opacity.domain(d3.extent(data, d => d.height));&nbsp; &nbsp; console.log(opacity.domain());&nbsp; &nbsp; svg.append("g")&nbsp; &nbsp; &nbsp; .selectAll("g")&nbsp; &nbsp; &nbsp; .data(d3.stack().keys(keys)(data))&nbsp; &nbsp; &nbsp; .enter().append("g")&nbsp; &nbsp; &nbsp; .attr("fill", d => z(d.key))&nbsp; &nbsp; &nbsp; .selectAll("rect")&nbsp; &nbsp; &nbsp; .data(d => d)&nbsp; &nbsp; &nbsp; .enter()&nbsp; &nbsp; &nbsp; .append("rect")&nbsp; &nbsp; &nbsp; .attr("y", d => y(d.data.Ser))&nbsp; &nbsp; &nbsp; .attr("x", d => x(d[0]))&nbsp; &nbsp; &nbsp; .attr("height", y.bandwidth())&nbsp; &nbsp; &nbsp; .attr("width", d => x(d[1]) - x(d[0]))&nbsp; &nbsp; &nbsp; .attr("fill-opacity", d => opacity(d.data.height));&nbsp; &nbsp; svg.append("g")&nbsp; &nbsp; &nbsp; .attr("transform", "translate(0,0)")&nbsp; &nbsp; &nbsp; .call(d3.axisTop(x));&nbsp; &nbsp; svg.append("g")&nbsp; &nbsp; &nbsp; .call(d3.axisLeft(y));&nbsp; });.bar {&nbsp; fill: rgb(70, 131, 180);}<script src="https://d3js.org/d3.v5.min.js"></script><div id="my_dataviz"></div>编辑:知道您想按组对条形进行着色,我将使用相同的逻辑,但进行一些调整:首先,我转而z处理fill-opacity(我仍然用它来强调不同的群体),并使用新的group颜色序数比例。这个规模的关键就是预先存在的领域d.Group。// set the dimensions and margins of the graphconst margin = {&nbsp; &nbsp; top: 90,&nbsp; &nbsp; right: 20,&nbsp; &nbsp; bottom: 30,&nbsp; &nbsp; left: 40&nbsp; },&nbsp; width = 960 - margin.left - margin.right,&nbsp; height = 960 - margin.top - margin.bottom;const svg = d3.select("#my_dataviz")&nbsp; .append("svg")&nbsp; .attr("width", width + margin.left + margin.right)&nbsp; .attr("height", height + margin.top + margin.bottom)&nbsp; .append("g")&nbsp; .attr("transform",&nbsp; &nbsp; "translate(" + margin.left + "," + margin.top + ")");const y = d3.scaleBand()&nbsp; .range([0, height])&nbsp; .padding(0.1);const x = d3.scaleLinear()&nbsp; .range([0, width]);const z = d3.scaleOrdinal()&nbsp; .range([0.25, 0.5, 0.75, 1]);const group = d3.scaleOrdinal()&nbsp; .range(["darkgreen", "darkred", "steelblue", "purple"]);d3.csv("https://gist.githubusercontent.com/JimMaltby/844ca313589e488b249b86ead0d621a9/raw/f328ad6291ffd3c9767a2dbdba5ce8ade59a5dfa/TimeBarDummyFormat.csv", d3.autoType, (d, i, columns) => {&nbsp; &nbsp; &nbsp; var i = 3;&nbsp; &nbsp; &nbsp; var t = 0;&nbsp; &nbsp; &nbsp; for (; i < columns.length; ++i)&nbsp; &nbsp; &nbsp; &nbsp; t += d[columns[i]] = +d[columns[i]];&nbsp; &nbsp; &nbsp; d.total = t;&nbsp; &nbsp; &nbsp; return d;&nbsp; &nbsp; }&nbsp; ).then(function(data) {&nbsp; &nbsp; const keys = data.columns.slice(3); // takes the column names, ignoring the first 3 items = ["EarlyMin","EarlyAll", "LateAll", "LateMax"]&nbsp; &nbsp; y.domain(data.map(d => d.Ser));&nbsp; &nbsp; x.domain([2000, d3.max(data, d => d.total)]).nice();&nbsp; &nbsp; z.domain(keys);&nbsp; &nbsp; group.domain(data.map(d => d.Group));&nbsp; &nbsp; svg.append("g")&nbsp; &nbsp; &nbsp; .selectAll("g")&nbsp; &nbsp; &nbsp; .data(d3.stack().keys(keys)(data))&nbsp; &nbsp; &nbsp; .enter().append("g")&nbsp; &nbsp; &nbsp; .attr("fill-opacity", d => z(d.key))&nbsp; &nbsp; &nbsp; .selectAll("rect")&nbsp; &nbsp; &nbsp; .data(d => d)&nbsp; &nbsp; &nbsp; .enter()&nbsp; &nbsp; &nbsp; .append("rect")&nbsp; &nbsp; &nbsp; .attr("y", d => y(d.data.Ser))&nbsp; &nbsp; &nbsp; .attr("x", d => x(d[0]))&nbsp; &nbsp; &nbsp; .attr("height", y.bandwidth())&nbsp; &nbsp; &nbsp; .attr("width", d => x(d[1]) - x(d[0]))&nbsp; &nbsp; &nbsp; .attr("fill", d => group(d.data.Group));&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; svg.append("g")&nbsp; &nbsp; &nbsp; .attr("transform", "translate(0,0)")&nbsp; &nbsp; &nbsp; .call(d3.axisTop(x));&nbsp; &nbsp; svg.append("g")&nbsp; &nbsp; &nbsp; .call(d3.axisLeft(y));&nbsp; });.bar {&nbsp; fill: rgb(70, 131, 180);}<script src="https://d3js.org/d3.v5.min.js"></script><div id="my_dataviz"></div>编辑2:如果你想自己指定颜色,我会使用颜色键映射:// set the dimensions and margins of the graphconst margin = {&nbsp; &nbsp; top: 90,&nbsp; &nbsp; right: 20,&nbsp; &nbsp; bottom: 30,&nbsp; &nbsp; left: 40&nbsp; },&nbsp; width = 960 - margin.left - margin.right,&nbsp; height = 960 - margin.top - margin.bottom;const svg = d3.select("#my_dataviz")&nbsp; .append("svg")&nbsp; .attr("width", width + margin.left + margin.right)&nbsp; .attr("height", height + margin.top + margin.bottom)&nbsp; .append("g")&nbsp; .attr("transform",&nbsp; &nbsp; "translate(" + margin.left + "," + margin.top + ")");const y = d3.scaleBand()&nbsp; .range([0, height])&nbsp; .padding(0.1);const x = d3.scaleLinear()&nbsp; .range([0, width]);const z = d3.scaleOrdinal()&nbsp; .range([0.25, 0.5, 0.75, 1]);const group = d3.scaleOrdinal()&nbsp; .range([&nbsp; &nbsp; { Start: "none", Min: "lightgreen", All: "green", Max: "darkgreen" },&nbsp; &nbsp; { Start: "none", Min: "indianred", All: "red", Max: "darkred" },&nbsp; &nbsp; { Start: "none", Min: "lightsteelblue", All: "steelblue", Max: "darksteelblue" }&nbsp; ]);d3.csv("https://gist.githubusercontent.com/JimMaltby/844ca313589e488b249b86ead0d621a9/raw/f328ad6291ffd3c9767a2dbdba5ce8ade59a5dfa/TimeBarDummyFormat.csv", d3.autoType, (d, i, columns) => {&nbsp; &nbsp; &nbsp; var i = 3;&nbsp; &nbsp; &nbsp; var t = 0;&nbsp; &nbsp; &nbsp; for (; i < columns.length; ++i)&nbsp; &nbsp; &nbsp; &nbsp; t += d[columns[i]] = +d[columns[i]];&nbsp; &nbsp; &nbsp; d.total = t;&nbsp; &nbsp; &nbsp; return d;&nbsp; &nbsp; }&nbsp; ).then(function(data) {&nbsp; &nbsp; const keys = data.columns.slice(3); // takes the column names, ignoring the first 3 items = ["EarlyMin","EarlyAll", "LateAll", "LateMax"]&nbsp; &nbsp; y.domain(data.map(d => d.Ser));&nbsp; &nbsp; x.domain([2000, d3.max(data, d => d.total)]).nice();&nbsp; &nbsp; z.domain(keys);&nbsp; &nbsp; group.domain(data.map(d => d.Group));&nbsp; &nbsp; svg.append("g")&nbsp; &nbsp; &nbsp; .selectAll("g")&nbsp; &nbsp; &nbsp; .data(d3.stack().keys(keys)(data))&nbsp; &nbsp; &nbsp; .enter().append("g")&nbsp; &nbsp; &nbsp; .each(function(e) {&nbsp; &nbsp; &nbsp; &nbsp; d3.select(this)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .selectAll("rect")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .data(d => d)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .enter()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .append("rect")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .attr("y", d => y(d.data.Ser))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .attr("x", d => x(d[0]))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .attr("height", y.bandwidth())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .attr("width", d => x(d[1]) - x(d[0]))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .attr("fill", d => group(d.data.Group)[e.key]);&nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; svg.append("g")&nbsp; &nbsp; &nbsp; .attr("transform", "translate(0,0)")&nbsp; &nbsp; &nbsp; .call(d3.axisTop(x));&nbsp; &nbsp; svg.append("g")&nbsp; &nbsp; &nbsp; .call(d3.axisLeft(y));&nbsp; });.bar {&nbsp; fill: rgb(70, 131, 180);}<script src="https://d3js.org/d3.v5.min.js"></script><div id="my_dataviz"></div>
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答