【发布时间】:2019-12-14 14:32:52
【问题描述】:
我的目标是绘制平行四边形,将一家公司在一个业务季度的排名与其在下一业务季度的新排名联系起来。我使用 rects 代表每个公司或manager。 (每列是一个营业季度)。我的步骤/进度:
- 使用
.each()来存储平行四边形顶点,方法是检索x、y和height的每个矩形的.attr()。 - 由于每列的公司顺序不同,我不得不将这些 x 和 y 坐标存储到两个数组中。
- 然后我不得不合并它们,条件是 xs 和 ys 属于同一个经理。 (例如,
Fidelity在第一列之后从 #1 变为 #2)。
这就是麻烦开始的地方,基本上,我的y1s 和y0s 都卡在相同的值上,我不知道为什么。
var margins = {top:20, bottom:300, left:30, right:100};
var height = 600;
var width = 900;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var outerRadius = (400 / 2);
var innerRadius = 15;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append('g')
.attr('transform', "translate("+margins.left+","+margins.top+ ")");
var heightScale = d3.scaleLinear()
.domain([.01,.09])
.range([7,50]);
/*
var tsvData = d3.tsv('market-share-change.tsv');
tsvData.then(function(rawData) {
var data = rawData.map(function(d) {
return { manager:d.manager, t1:+d.t1, t2:+d.t2, t3:+d.t3}
});
})
*/
var data = [[{'manager': 'Mirae Asset', 'share': 0.016},
{'manager': 'Manulife', 'share': 0.015},
{'manager': 'ChinaAMC', 'share': 0.012},
{'manager': 'Principal', 'share': 0.015},
{'manager': 'Aberdeen Standard', 'share': 0.013},
{'manager': 'CSOP', 'share': 0.015},
{'manager': 'BOCI-Prudential', 'share': 0.019},
{'manager': 'Allianz', 'share': 0.016},
{'manager': 'HSBC', 'share': 0.027},
{'manager': 'Deutsche Bank', 'share': 0.014},
{'manager': 'Invesco', 'share': 0.025},
{'manager': 'First State', 'share': 0.033},
{'manager': 'JP Morgan', 'share': 0.041},
{'manager': 'Value Partners', 'share': 0.04},
{'manager': 'Schroders', 'share': 0.051},
{'manager': 'Hang Seng', 'share': 0.063},
{'manager': 'UBS', 'share': 0.056},
{'manager': 'SSgA', 'share': 0.066},
{'manager': 'Fidelity', 'share': 0.088},
{'manager': 'BlackRock', 'share': 0.084}],
[{'manager': 'Mirae Asset', 'share': 0.013},
{'manager': 'Manulife', 'share': 0.014},
{'manager': 'ChinaAMC', 'share': 0.013},
{'manager': 'Principal', 'share': 0.018},
{'manager': 'Aberdeen Standard', 'share': 0.014},
{'manager': 'CSOP', 'share': 0.019},
{'manager': 'BOCI-Prudential', 'share': 0.02},
{'manager': 'Allianz', 'share': 0.015},
{'manager': 'HSBC', 'share': 0.023},
{'manager': 'Deutsche Bank', 'share': 0.02},
{'manager': 'Invesco', 'share': 0.02},
{'manager': 'First State', 'share': 0.029},
{'manager': 'JP Morgan', 'share': 0.04},
{'manager': 'Value Partners', 'share': 0.039},
{'manager': 'Schroders', 'share': 0.051},
{'manager': 'Hang Seng', 'share': 0.063},
{'manager': 'UBS', 'share': 0.055},
{'manager': 'SSgA', 'share': 0.065},
{'manager': 'Fidelity', 'share': 0.088},
{'manager': 'BlackRock', 'share': 0.101}],
[{'manager': 'Mirae Asset', 'share': 0.012},
{'manager': 'Manulife', 'share': 0.014},
{'manager': 'ChinaAMC', 'share': 0.014},
{'manager': 'Principal', 'share': 0.017},
{'manager': 'Aberdeen Standard', 'share': 0.017},
{'manager': 'CSOP', 'share': 0.018},
{'manager': 'BOCI-Prudential', 'share': 0.018},
{'manager': 'Allianz', 'share': 0.018},
{'manager': 'HSBC', 'share': 0.023},
{'manager': 'Deutsche Bank', 'share': 0.023},
{'manager': 'Invesco', 'share': 0.023},
{'manager': 'First State', 'share': 0.029},
{'manager': 'JP Morgan', 'share': 0.041},
{'manager': 'Value Partners', 'share': 0.044},
{'manager': 'Schroders', 'share': 0.048},
{'manager': 'Hang Seng', 'share': 0.056},
{'manager': 'UBS', 'share': 0.061},
{'manager': 'SSgA', 'share': 0.062},
{'manager': 'Fidelity', 'share': 0.087},
{'manager': 'BlackRock', 'share': 0.096}]];
var poly = [
{'x':0,'y':0},
{'x':0,'y':0}
];
var multiPoly1 = d3.range(20).map(()=>JSON.parse(JSON.stringify(poly)));
var multiPoly2 = d3.range(20).map(()=>JSON.parse(JSON.stringify(poly)));
/*
for (var k=0; k <(data[0].length); k++) {
polyMaster[0][k].push({'manager':data[0][k].manager})
};
*/
var colorMap = {
'Fidelity':"#003366",
'BlackRock':"#366092",
'SSgA':"#4f81b9",
'Hang Seng':"#95b3d7",
'UBS':"#b8cce4",
'Schroders':"#e7eef8",
'JP Morgan':"#a6a6a6",
'Value Partners':"#d9d9d9",
'Yuanta':"#ffffcc",
'First State':"#ffffcc",
'HSBC':'#f6d18b',
'Invesco':'#e4a733',
'BOCI-Prudential':"#b29866",
'Allianz':'#a6a6a6',
'Mirae Asset':'#d9d9d9',
'Manulife':'#e7eef8',
'CSOP':'#b8cce4',
'Principal':'#95b3d7',
'Deutsche Bank':'#4f81b9',
'Aberdeen Standard':'#366092',
'ChinaAMC':'#003366'
};
for (var j=0; j <(data.length); j++) {
var className = "column"+String(j);
let counterRect = 0,
counterText = 0;
var spacing = 170;
var sortedData = data[j].sort(function(a,b) {
return b.share - a.share;
});
var column = graphGroup.selectAll(className)
.data(sortedData)
.attr('class', className)
.enter().append("g");
column.append("rect")
.attr('class','rect'+String(j))
.attr("width", 120)
.attr("height", function(d) {
return heightScale(d.share)
})
.attr('x', function(d) {return j*spacing})
.attr('y', function(d, i) {
let previous = counterRect;
return (counterRect += heightScale(d.share)+2, previous)
})
.each(function(d,i) {
if (j==0) {
multiPoly1[i][0].x = 120;
}
})
.each(function(d,i) {
if (j==0) {
multiPoly1[i][0].y = parseFloat(d3.select(this).attr('y'));
}
})
.each(function(d,i) {
if (j==0) {
multiPoly1[i][1].x = 120;
}
})
.each(function(d,i) {
if (j==0) {
multiPoly1[i][1].y = parseFloat(d3.select(this).attr('y'))+parseFloat(d3.select(this).attr('height'));
}
})
.each(function(d,i) {
if (j==1) {
multiPoly2[i][1].x = parseFloat(d3.select(this).attr('x'));
}
})
.each(function(d,i) {
if (j==1) {
multiPoly2[i][1].y = parseFloat(d3.select(this).attr('y'));
}
})
.each(function(d,i) {
if (j==1) {
multiPoly2[i][0].x = parseFloat(d3.select(this).attr('x'));
}
})
.each(function(d,i) {
if (j==1) {
multiPoly2[i][0].y = parseFloat(d3.select(this).attr('y'))+parseFloat(d3.select(this).attr('height'));
}
})
.style('fill',function(d,i) {return colorMap[d.manager]});
column.append("text")
.attr('x', function(d) {return j*spacing+60})
.attr('y', function(d, i) {
let previous = counterText;
return (counterText += heightScale(d.share)+2, previous + (heightScale(d.share)/2))
})
.attr("dominant-baseline", "central")
.attr('text-anchor', 'middle')
.text(function(d) {
return d.manager;
});
var managerList = [];
for (var k = 0; k < sortedData.length; k++)
managerList.push({'manager':sortedData[k].manager});
var tempList1 = [];
for (var k = 0; k < managerList.length; k++)
tempList1.push({'manager': managerList[k], 'x1': multiPoly1[k][0].x, 'y1':multiPoly1[k][0].y, 'x2':multiPoly1[k][1].x, 'y2':multiPoly1[k][1].y });
var tempList2 = [];
for (var k = 0; k < managerList.length; k++)
tempList2.push({'manager': managerList[k], 'x3': multiPoly2[k][1].x, 'y3':multiPoly2[k][1].y, 'x4':multiPoly2[k][0].x, 'y4':multiPoly2[k][0].y });
var combinedList = [];
const list1ByManager = tempList1.reduce((a, item) => {
a[item.manager] = item;
return a;
}, {});
var combinedList = tempList2.map((item2) => ({
...list1ByManager[item2.manager],
...item2
}));
console.log(combinedList)
var polyMaster = [];
for (var k = 0; k < managerList.length; k++) {
var tempItem = [
{'x':combinedList[k].x1, 'y':combinedList[k].y1},
{'x':combinedList[k].x2, 'y':combinedList[k].y2},
{'x':combinedList[k].x3, 'y':combinedList[k].y3},
{'x':combinedList[k].x4, 'y':combinedList[k].y4},
];
polyMaster.push(tempItem);
}
console.log(polyMaster)
};
graphGroup.selectAll("polygon")
.data(polyMaster)
.enter().append("polygon")
.attr("points",function(d) {
return d.map(function(d) { return [d.x,d.y].join(","); }).join(" ");})
.attr("stroke","black")
.attr("stroke-width",2);
<script src="https://d3js.org/d3.v5.min.js"></script>
在控制台日志中检查 tempList1 和 tempList2 确认我确实正确存储了所有值,但是由于某种原因,当我尝试将这两个数组合并到 combinedList 时,ys 没有正确合并.相关代码:
var combinedList = [];
const list1ByManager = tempList1.reduce((a, item) => {
a[item.manager] = item;
return a;
}, {});
var combinedList = tempList2.map((item2) => ({
...list1ByManager[item2.manager],
...item2
}));
问题
我是否错误地合并了tempList1 和tempList2?为什么ys 没有像 sn-p 所示的那样保留?
(换句话说,平行四边形(黑色)不应该全部画在第一列的底部,它们应该完美地连接到相应的公司——如果你愿意,可以形成一座桥梁,让眼睛更容易看到通过追踪该公司在第一列中的位置到其在第二列中的新位置来查看任何一家公司的排名变化)
注意:我现在只关心第一列和第二列之间的平行四边形。在弄清楚这么多之前,我不会尝试使用第三列。
【问题讨论】:
-
@GerardoFurtado 从文档来看,链接生成器似乎只产生线条,还是有平行四边形链接方法?
-
@GerardoFurtado 关键是我需要它有刚性线和二维(平行四边形),而不是曲线。
-
那么,您必须创建自己的路径(或倾斜的矩形)。现在这个问题更加广泛了。
-
@ArashHowaida 您能否添加一个有代表性的示例数据和一个草图,显示您希望最终结果的样子?
标签: javascript d3.js