从 D3.js 中完全相同的数据数组向多个路径添加颜色
Add color to multiple paths from an array of exact same data in D3.js
这个问题可能有误导性,但我不知道如何说得更准确。
基本上,我的数据如下:
{
"pitcher": 547943,
"pitch_type": "CH",
"velo": 80.15329032258065,
"hmov": 0,
"vmov": 0,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CH",
"velo": 80.15329032258065,
"hmov": 12.729861677419354,
"vmov": 5.4084,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CU",
"velo": 72.77105263157895,
"hmov": 0,
"vmov": 0,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CU",
"velo": 72.77105263157895,
"hmov": -13.357961403508773,
"vmov": -13.062238596491229,
"name": "hyun-jin-ryu"
}
我想为每个 pitch_type 获取路径,从 (hmov[0],vmov[0]) 或 0,0 开始,然后到 (hmov[1], vmov[1]) .我还创建了一个与 "velo" 关联的色标,但找不到将其分配给我的路径笔划的方法。我怀疑这与有 2 个 velo 值有关,但不能确定这是否是问题所在。
//Loop through each pitch
dataNest.forEach(function(d) {
svg.append("path")
.data([data])
.attr("d", pitchLine(d.values))
.attr("stroke", function(d) { return veloScale(d); }) //Problematic part
.attr("stroke-witdh", 2);
});
完整代码:
const margin = {top: 25, bottom: 25, right: 25, left: 25};
const height = 300 - margin.top - margin.bottom;
const width = 300 - margin.left - margin.right;
//Set Ranges
let x = d3.scaleLinear().range([0, width]);
let y = d3.scaleLinear().range([height, 0]);
let veloScale = d3.scaleSequential(d3.interpolateViridis);
//Set line generator
let pitchLine = d3.line()
.x(function(d) { return x(d.hmov); })
.y(function(d) { return y(d.vmov); });
//Add SVG canvas
let 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 + ")");
///////////////////////////////
//Get the Data
d3.json("ryu.json").then(function(data) {
data.forEach(function(d) {
d.hmov = +d.hmov;
d.vmov = +d.vmov;
d.velo = +d.velo;
});
//Scales
x.domain(d3.extent(data, function(d) { return d.hmov; }));
y.domain(d3.extent(data, function(d) { return d.vmov; }));
veloScale.domain(d3.extent(data, function(d) { return d.velo; }))
//Nesting data
let dataNest = d3.nest()
.key(function(d) { return d.pitch_type; })
.entries(data);
//Loop through each pitch
dataNest.forEach(function(d) {
svg.append("path")
.data([data])
.attr("d", pitchLine(d.values))
.attr("stroke", function(d) { return veloScale(d); })
.attr("stroke-witdh", 2);
});
应该更新循环遍历 dataNest 数组的代码部分,以便
a) 数据在正确的级别连接,即创建每个路径的 dataNest 数组,以及路径基准的 d.values。
b) 描边颜色函数传入要映射到颜色的数组中的值。由于 d.values 数组中的每个元素可能有不同的速度值,因此您需要决定使用哪一个。下面的示例使用数组中第一个元素的速度值。
//Create a separate g element to contain the path, based on the nested array
let pitch = svg.selectAll(".pitch-type")
.data(dataNest)
.enter()
.append("g")
//for each g element, add a path and assign the d.values for that path
pitch.append("path")
.datum(d => d.values)
.attr("d", d => pitchLine(d))
//pass in the velo value to get a colour
.attr("stroke", d => veloScale(d[0].velo))
.attr("stroke-witdh", 2);
let data = [{
"pitcher": 547943,
"pitch_type": "CH",
"velo": 80.15329032258065,
"hmov": 0,
"vmov": 0,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CH",
"velo": 80.15329032258065,
"hmov": 12.729861677419354,
"vmov": 5.4084,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CU",
"velo": 72.77105263157895,
"hmov": 0,
"vmov": 0,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CU",
"velo": 72.77105263157895,
"hmov": -13.357961403508773,
"vmov": -13.062238596491229,
"name": "hyun-jin-ryu"
}]
const margin = {top: 25, bottom: 25, right: 25, left: 25};
const height = 300 - margin.top - margin.bottom;
const width = 300 - margin.left - margin.right;
//Set Ranges
let x = d3.scaleLinear().range([0, width]);
let y = d3.scaleLinear().range([height, 0]);
let veloScale = d3.scaleSequential(d3.interpolateViridis);
//Set line generator
let pitchLine = d3.line()
.x(function(d) { return x(d.hmov); })
.y(function(d) { return y(d.vmov); });
//Add SVG canvas
let 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 + ")");
data.forEach(function(d) {
d.hmov = +d.hmov;
d.vmov = +d.vmov;
d.velo = +d.velo;
});
//Scales
x.domain(d3.extent(data, function(d) { return d.hmov; }));
y.domain(d3.extent(data, function(d) { return d.vmov; }));
veloScale.domain(d3.extent(data, function(d) { return d.velo; }))
//Nesting data
let dataNest = d3.nest()
.key(function(d) { return d.pitch_type; })
.entries(data);
let pitch = svg.selectAll(".pitch-type")
.data(dataNest)
.enter()
.append("g")
pitch.append("path")
.datum(d => d.values)
.attr("d", d => pitchLine(d))
.attr("stroke", d => veloScale(d[0].velo))
.attr("stroke-witdh", 2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
这个问题可能有误导性,但我不知道如何说得更准确。 基本上,我的数据如下:
{
"pitcher": 547943,
"pitch_type": "CH",
"velo": 80.15329032258065,
"hmov": 0,
"vmov": 0,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CH",
"velo": 80.15329032258065,
"hmov": 12.729861677419354,
"vmov": 5.4084,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CU",
"velo": 72.77105263157895,
"hmov": 0,
"vmov": 0,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CU",
"velo": 72.77105263157895,
"hmov": -13.357961403508773,
"vmov": -13.062238596491229,
"name": "hyun-jin-ryu"
}
我想为每个 pitch_type 获取路径,从 (hmov[0],vmov[0]) 或 0,0 开始,然后到 (hmov[1], vmov[1]) .我还创建了一个与 "velo" 关联的色标,但找不到将其分配给我的路径笔划的方法。我怀疑这与有 2 个 velo 值有关,但不能确定这是否是问题所在。
//Loop through each pitch
dataNest.forEach(function(d) {
svg.append("path")
.data([data])
.attr("d", pitchLine(d.values))
.attr("stroke", function(d) { return veloScale(d); }) //Problematic part
.attr("stroke-witdh", 2);
});
完整代码:
const margin = {top: 25, bottom: 25, right: 25, left: 25};
const height = 300 - margin.top - margin.bottom;
const width = 300 - margin.left - margin.right;
//Set Ranges
let x = d3.scaleLinear().range([0, width]);
let y = d3.scaleLinear().range([height, 0]);
let veloScale = d3.scaleSequential(d3.interpolateViridis);
//Set line generator
let pitchLine = d3.line()
.x(function(d) { return x(d.hmov); })
.y(function(d) { return y(d.vmov); });
//Add SVG canvas
let 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 + ")");
///////////////////////////////
//Get the Data
d3.json("ryu.json").then(function(data) {
data.forEach(function(d) {
d.hmov = +d.hmov;
d.vmov = +d.vmov;
d.velo = +d.velo;
});
//Scales
x.domain(d3.extent(data, function(d) { return d.hmov; }));
y.domain(d3.extent(data, function(d) { return d.vmov; }));
veloScale.domain(d3.extent(data, function(d) { return d.velo; }))
//Nesting data
let dataNest = d3.nest()
.key(function(d) { return d.pitch_type; })
.entries(data);
//Loop through each pitch
dataNest.forEach(function(d) {
svg.append("path")
.data([data])
.attr("d", pitchLine(d.values))
.attr("stroke", function(d) { return veloScale(d); })
.attr("stroke-witdh", 2);
});
应该更新循环遍历 dataNest 数组的代码部分,以便
a) 数据在正确的级别连接,即创建每个路径的 dataNest 数组,以及路径基准的 d.values。
b) 描边颜色函数传入要映射到颜色的数组中的值。由于 d.values 数组中的每个元素可能有不同的速度值,因此您需要决定使用哪一个。下面的示例使用数组中第一个元素的速度值。
//Create a separate g element to contain the path, based on the nested array
let pitch = svg.selectAll(".pitch-type")
.data(dataNest)
.enter()
.append("g")
//for each g element, add a path and assign the d.values for that path
pitch.append("path")
.datum(d => d.values)
.attr("d", d => pitchLine(d))
//pass in the velo value to get a colour
.attr("stroke", d => veloScale(d[0].velo))
.attr("stroke-witdh", 2);
let data = [{
"pitcher": 547943,
"pitch_type": "CH",
"velo": 80.15329032258065,
"hmov": 0,
"vmov": 0,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CH",
"velo": 80.15329032258065,
"hmov": 12.729861677419354,
"vmov": 5.4084,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CU",
"velo": 72.77105263157895,
"hmov": 0,
"vmov": 0,
"name": "hyun-jin-ryu"
},
{
"pitcher": 547943,
"pitch_type": "CU",
"velo": 72.77105263157895,
"hmov": -13.357961403508773,
"vmov": -13.062238596491229,
"name": "hyun-jin-ryu"
}]
const margin = {top: 25, bottom: 25, right: 25, left: 25};
const height = 300 - margin.top - margin.bottom;
const width = 300 - margin.left - margin.right;
//Set Ranges
let x = d3.scaleLinear().range([0, width]);
let y = d3.scaleLinear().range([height, 0]);
let veloScale = d3.scaleSequential(d3.interpolateViridis);
//Set line generator
let pitchLine = d3.line()
.x(function(d) { return x(d.hmov); })
.y(function(d) { return y(d.vmov); });
//Add SVG canvas
let 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 + ")");
data.forEach(function(d) {
d.hmov = +d.hmov;
d.vmov = +d.vmov;
d.velo = +d.velo;
});
//Scales
x.domain(d3.extent(data, function(d) { return d.hmov; }));
y.domain(d3.extent(data, function(d) { return d.vmov; }));
veloScale.domain(d3.extent(data, function(d) { return d.velo; }))
//Nesting data
let dataNest = d3.nest()
.key(function(d) { return d.pitch_type; })
.entries(data);
let pitch = svg.selectAll(".pitch-type")
.data(dataNest)
.enter()
.append("g")
pitch.append("path")
.datum(d => d.values)
.attr("d", d => pitchLine(d))
.attr("stroke", d => veloScale(d[0].velo))
.attr("stroke-witdh", 2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>