问题描述
当未手动列出组时,我很难理解d3.layout.stack().在下面的示例中,类似于我在其他问题中发现的内容,组在[]中列为"Apple",依此类推,但据我所知,必须手动输入.我正在寻找一种无需手动输入苹果",蓝莓"等的方法.
I am having a really hard time understanding d3.layout.stack() when groups are not listed manually. In the below example, similar to what I've found in other questions, groups are listed in [] as "Apple", etc., but as far as I understand this has to be inputted manually. I am seeking a way to not have to manually input "Apple", "Blueberry", etc.
var dataset = d3.layout.stack()(["Apple", "Blueberry", "Lettuce", "Orange"].map(function(fruit) {
return data.map(function(d) {
return {x: d.orchard, y: +d[fruit]};
});
}));
我尝试在数据对象中插入如下一行,称为名称":
I've tried inserting a line in my data object as below, called 'names':
[{names='Apple','Blueberry','Lettuce','Orange'}, {Apple=1.0, Orange=2.0, Lettuce=1.0, orchard=小明, Blueberry=1.0}, {Apple=1.0, Orange=1.0, Lettuce=1.0, orchard=小陈, Blueberry=1.0}, {Apple=1.0, Orange=1.0, Lettuce=1.0, orchard=小虎, Blueberry=1.0}, {Orange=1.0, Lettuce=1.0, orchard=小桃, Blueberry=1.0, Apple=1.0}]
有没有办法编写类似于下面的代码?
Is there a way to code something similar to below?
var dataset = d3.layout.stack()([d3.keys(names)].map(function(fruit) {
我应该集中精力在数据对象中插入唯一的名称列表,还是通过在d3代码本身中解析数据以累积唯一组名称的列表来做到这一点?
Should I be focused more on inserting a unique list of names into my data object, or do so by parsing my data in my d3 code itself to accumulate a list of unique group names?
我想知道d3.keys逻辑是否有意义,是否也可以将其应用于以下上下文,而不是列举每种情况:
I am wondering, if the d3.keys logic makes sense, if it can be applied to the below context too, instead of enumerating each case:
legend.append("text")
.attr("x", width + 5)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d, i) {
for(var j =0; j<4; j++){
switch (i) {
case j: return d3.keys[j]
// switch (i) {
//
// case 0: return "orange"
// case 1: return "apple"
// case 2: return "blueberry"
// case 3: return "lettuce"
}
}
});
推荐答案
我最终只是将整个图形转换为d3 v5.以下是一些注释,这些注释基于我与自己的作品混合使用的许多资料来源:
I ended up just converting the entire graph to d3 v5. Below is some notes based off a lot of sources I looked at mixed with my own work:
堆积条的更好做法是使用
Better practice for stacked bar is to use
.data(d3.stack().keys(keys)(data))
其中
var keys = d3.keys(data[0]).filter(function(d){
return d != "orchard";
});
或换句话说:
var keys = d3.keys(data[0]).filter(d => d != "orchard")
这对于用javascript预解析的数据很有用.假设您在csv中只有几列:
This is useful for data that is pre-parsed in javascript. Say you have just columns in a csv:
var keys = csv.columns.slice(0);
很有用,但适用于堆叠的相同原理.
is useful, but same philosophy for stacking applies.
一个小问题:如果您稍后在数据中产生新的类别,即数据[1]而不是数据[0]的一部分是新的水果菠萝,则密钥将无法识别菠萝.它仅响应第一个条目的数据对象.
Slight issue: if you have new categories arising later on in the data, i.e. a new fruit pineapple is part of data[1] but not data[0], key will not identify pineapple. It only responds to the data object of the first entry.
在保持相同过滤器的情况下,不依赖data[1], data[0], etc.,
和data[0], data[1], etc.
的累积"键:
To not rely on data[1], data[0], etc.,
and "accumulate" keys for data[0], data[1], etc.
while maintaining the same filter:
var key = [];
for(var i =0; i < d3.keys(data).length; i++){
var joinin = d3.keys(data[i]).filter(d => d != "orchard")
var key = key.concat(joinin)
// console.log(key)
}
最有可能编写该代码的一种更好的方法,但解释是:
There's most likely a better way of writing that code, but the explanation is:
如果您编写了这样的内容,您将只获得一组数据的密钥:
If you wrote something like this you'd get keys for only one set of data:
var key = d3.keys(data[2]).filter(function(d){
return d != "orchard";
});
如果您编写了此代码,则将获得每次数据迭代的密钥:
If you wrote this you get the keys for each iteration of data:
var key = [];
for(var i =0; i < d3.keys(data).length; i++){
var key = d3.keys(data[i]).filter(d => d != "orchard")
console.log(key)
key.push(key);
}
因此,诀窍是使用for循环获取数据的每次迭代,但将其合并到一个没有重复的单数列表中.
So the trick is to use a for loop to get each iteration of data but concat that into one singular list, which has no repeats.
如果您想要为每个键提供值该怎么办?同样,这是针对这样的数据结构的,这有点不符合常规:
What if you wanted the value given to each key? Again, this is for a data structure like this, which is a little unconventional:
data = [
{0:
{"Apple": 1}
{"orchard": xx}
}
{1:
{"Apple": 2}
{"orchard": xx}
}
]
您可以使用以下内容,其中key
将返回["Apple"]
,而key_values
将返回[1, 2]
.基本上,过滤器d> 0可防止任何字符串,例如果园名称"xx".与过滤果园相同.
You can use the below, where key
will return ["Apple"]
, and key_values
will return [1, 2]
. Basically the filter d > 0 prevents any strings, so like names of orchards "xx". Does the same as filtering out orchards.
var key = [];
var key_values = [];
for(var i =0; i < d3.keys(data).length; i++){
var key_value = d3.entries(data[i]).map(d => d.value).filter(d => d > 0)
var key_values = key_values.concat(key_value)
var joinin = d3.keys(data[i]).filter(d => d != "orchard")
var key = key.concat(joinin)
}
(EDIT2)关于图例.
(EDIT2) About the legend..
我只是将代码替换为,我知道d3v5可以简化以下(?),
I just replaced my code with, and I know d3v5 can simplify the below(?),
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter()
.append("g")
.attr("class","legend")
.attr("transform",function(d,i) {
return "translate(1300," + i * 15 + ")";
});
在我的情况下,输入变量是离散的,例如"Apple"等,而不是整数,因此我们使用scaleOrdinal并仅对域使用"keys".不过,您实际上并不需要编写该代码,我认为它默认为离散变量的输入列表?不知道为什么会这样.
In my case input variables are discrete, like "Apple" etc., not integers, so we use scaleOrdinal and just use "keys" for the domain. You don't really need to write that though, I think it defaults to the input list of discrete variables? Not sure why it works.
var color = d3.scaleOrdinal()
.domain(keys)
// .range (whatever you want)
这篇关于避免在d3.layout.stack()["group 1","group 2"]中枚举组名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!