我正在研究D3图,我试图将散点图分组到我使用路径变量创建的区域/区域。我正在寻找一些简单,计算的方法来做到这一点。以下是我正在使用的示例:
const shallowRightPath = 'M0 25 L0 55 L28 50 L23 25 L0 25';
const shallowLeftPath = 'M85 25 L85 55 L57 50 L62 25 L85 25';
const shallowCenterPath = 'M28 50 L23 25 L62 25 L57 50 L28 50';
const slotPath = 'M27 89 L32 71 L53 71 L58 89 L27 89';
const deepSlotPath = 'M32 71 L28 50 L57 50 L53 71 L32 71';
const attackingRightPath = 'M0 55 L0 72 A28 28 1 0 0 5.7 89 L27 89 L32 71 L28 50 L0 55';
const attackingLeftPath = 'M85 55 L85 72 A28 28 0 0 1 79.3 89 L58 89 L53 71 L57 50 L85 55';
const zoneInfo = [
{"num": 1, "name": "Shallow Right", "path": shallowRightPath, "color":"blue"},
{"num": 2, "name": "Shallow Left", "path": shallowLeftPath, "color":"yellow"},
{"num": 3, "name": "Shallow Center Right", "path": shallowCenterPath, "color":"green"},
{"num": 4, "name": "Slot", "path": slotPath, "color":"green"},
{"num": 5, "name": "Deep Slot", "path": deepSlotPath, "color":"red"},
{"num": 6, "name": "Attacking Right", "path": attackingRightPath, "color":"yellow"},
{"num": 7, "name": "Attacking Left", "path": attackingLeftPath, "color":"blue"}
];
// append shaded paths
const shades = d3.select('svg').append('g')
for(var i = 0; i < zoneInfo.length; i++) {
shades.append("path")
.attr("d", zoneInfo[i].path)
.attr("fill", zoneInfo[i].color)
.attr("stroke", "black")
.attr("stroke-width", '0.3')
.attr("opacity", 0.85);
}
const points = [
{x: 15, y: 35, zonenum: ""},
{x: 29, y: 35, zonenum: ""},
{x: 59, y: 55, zonenum: ""},
{x: 45, y: 75, zonenum: ""},
{x: 57, y: 49, zonenum: ""}
]
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg></svg>
这些路径中的大多数是梯形和其他奇数四边形,并且基于梯形线的函数通过一系列不等式计算每个点的区域需要相当长的时间(除非我有一个函数来做到这一点)以及)。
是否有更简单的方法来确定我的点列表属于哪个区域?谢谢!
答案 0 :(得分:1)
如果可以使用坐标将路径转换为数组数组,例如......
[[85, 25], [85, 55], [57, 50], [62, 25], [85, 25]]
...您可以使用d3.polygonContains(),其中......
当且仅当指定的点位于指定的多边形内时才返回true。
例如,过滤您的zoneInfo
数组并将num
值分配给相应的点:
points.forEach(function(d) {
d.zonenum = zoneInfo.filter(function(e) {
return d3.polygonContains(e.polygon, [d.x, d.y])
})[0].num
});
这是一个包含一些路径和点的演示:
const zoneInfo = [{
"num": 1,
"name": "Shallow Right",
"color": "blue",
"polygon": [
[0, 25],
[0, 55],
[28, 50],
[23, 25],
[0, 25]
]
},
{
"num": 2,
"name": "Shallow Left",
"color": "yellow",
"polygon": [
[85, 25],
[85, 55],
[57, 50],
[62, 25],
[85, 25]
]
},
{
"num": 3,
"name": "Shallow Center Right",
"color": "green",
"polygon": [
[28, 50],
[23, 25],
[62, 25],
[57, 50],
[28, 50]
]
},
{
"num": 4,
"name": "Slot",
"color": "green",
"polygon": [
[27, 89],
[32, 71],
[53, 71],
[58, 89],
[27, 89]
]
},
{
"num": 5,
"name": "Deep Slot",
"color": "red",
"polygon": [
[32, 71],
[28, 50],
[57, 50],
[53, 71],
[32, 71]
]
}
];
const points = [{
x: 15,
y: 35,
zonenum: ""
},
{
x: 29,
y: 35,
zonenum: ""
},
{
x: 45,
y: 75,
zonenum: ""
},
{
x: 57,
y: 49,
zonenum: ""
}
];
points.forEach(function(d) {
d.zonenum = zoneInfo.filter(function(e) {
return d3.polygonContains(e.polygon, [d.x, d.y])
})[0].num
});
console.log(points)
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg></svg>
&#13;
答案 1 :(得分:0)
R中的这个解决方案为我做了诀窍
createZones <- function(xvals, yvals) {
getM <- function(x1, y1, x2, y2) {
return((y2 - y1) / (x2 - x1))
}
getB <- function(x1, y1, x2, y2) {
slopeM <- (y2 - y1) / (x2 - x1)
return(y1 - slopeM*x1)
}
# based on xScale inverted due to d3 coordinates
zonenumbers = rep(0, length(xvals))
zonenames = rep("", length(xvals))
zonenumbers[which(yvals <= 25)] <- 1
zonenames[which(yvals <= 25)] <- 'Neutral Zone'
zonenumbers[which(yvals > 25 &
yvals > getM(23, 25, 28, 50) * xvals + getB(23, 25, 28, 50) &
yvals < getM(0, 55, 28, 50) * xvals + getB(0, 55, 28, 50))] <- 2
zonenames[which(yvals > 25 &
yvals > getM(23, 25, 28, 50) * xvals + getB(23, 25, 28, 50) &
yvals < getM(0, 55, 28, 50) * xvals + getB(0, 55, 28, 50))] <- 'Shallow Right'
zonenumbers[which(yvals > 25 &
yvals < getM(57, 50, 85, 55) * xvals + getB(57, 50, 85, 55) &
yvals > getM(57, 50, 62, 25) * xvals + getB(57, 50, 62, 25))] <- 3
zonenames[which(yvals > 25 &
yvals < getM(57, 50, 85, 55) * xvals + getB(57, 50, 85, 55) &
yvals > getM(57, 50, 62, 25) * xvals + getB(57, 50, 62, 25))] <- 'Shallow Left'
zonenumbers[which(yvals > 25 & yvals <= 50 &
yvals < getM(23, 25, 28, 50) * xvals + getB(23, 25, 28, 50) &
yvals < getM(57, 50, 62, 25) * xvals + getB(57, 50, 62, 25))] <- 4
zonenames[which(yvals > 25 & yvals <= 50 &
yvals < getM(23, 25, 28, 50) * xvals + getB(23, 25, 28, 50) &
yvals < getM(57, 50, 62, 25) * xvals + getB(57, 50, 62, 25))] <- 'Shallow Center'
zonenumbers[which(yvals > 71 & yvals <= 89 &
yvals > getM(27, 89, 32, 71) * xvals + getB(27, 89, 32, 71) &
yvals > getM(53, 71, 58, 89) * xvals + getB(53, 71, 58, 89))] <- 5
zonenames[which(yvals > 71 & yvals <= 89 &
yvals > getM(27, 89, 32, 71) * xvals + getB(27, 89, 32, 71) &
yvals > getM(53, 71, 58, 89) * xvals + getB(53, 71, 58, 89))] <- 'Slot'
zonenumbers[which(yvals > 50 & yvals <= 71 &
yvals < getM(32, 71, 28, 50) * xvals + getB(32, 71, 28, 50) &
yvals < getM(57, 50, 53, 71) * xvals + getB(57, 50, 53, 71))] <- 6
zonenames[which(yvals > 50 & yvals <= 71 &
yvals < getM(27, 89, 32, 71) * xvals + getB(27, 89, 32, 71) &
yvals < getM(53, 71, 58, 89) * xvals + getB(53, 71, 58, 89))] <- 'Deep Slot'
zonenumbers[which(yvals <= 89 &
yvals < getM(27, 89, 32, 71) * xvals + getB(27, 89, 32, 71) &
yvals > getM(32, 71, 28, 50) * xvals + getB(32, 71, 28, 50) &
yvals > getM(28, 50, 0, 55) * xvals + getB(28, 50, 0, 55))] <- 7
zonenames[which(yvals <= 89 &
yvals < getM(27, 89, 32, 71) * xvals + getB(27, 89, 32, 71) &
yvals > getM(32, 71, 28, 50) * xvals + getB(32, 71, 28, 50) &
yvals > getM(28, 50, 0, 55) * xvals + getB(28, 50, 0, 55))] <- 'Attacking Right'
zonenumbers[which(yvals <= 89 &
yvals < getM(58, 89, 53, 71) * xvals + getB(58, 89, 53, 71) &
yvals > getM(53, 71, 57, 50) * xvals + getB(53, 71, 57, 50) &
yvals > getM(57, 50, 85, 55) * xvals + getB(57, 50, 85, 55))] <- 8
zonenames[which(yvals <= 89 &
yvals < getM(58, 89, 53, 71) * xvals + getB(58, 89, 53, 71) &
yvals > getM(53, 71, 57, 50) * xvals + getB(53, 71, 57, 50) &
yvals > getM(57, 50, 85, 55) * xvals + getB(57, 50, 85, 55))] <- 'Attacking Left'
zonenumbers[which(yvals > 89)] <- 9
zonenames[which(yvals > 89)] <- 'Behind The Net'
return(data.frame(zonenumber = zonenumbers, zonename = zonenames, stringsAsFactors = FALSE))
}