【发布时间】:2021-06-27 01:05:42
【问题描述】:
我正在开发一个应用程序,我在 Angular 和 D3.JS 的客户端解析 CSV 文件以创建图形节点
如何组合两个 .csv 文件数组来创建一个数据集?加载 CSV 文件后,将数组返回到 this.files。
我使用的 CSV Parser 库是 NgxCsvParser。
client-parser.component
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { NgxCsvParser } from 'ngx-csv-parser';
import { NgxCSVParserError } from 'ngx-csv-parser';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
files: File[] = [];
connections: any[] = [];
header = true;
nodes: any[] = [];
links: any[] = [];
constructor(
public router: Router,
private ngxCsvParser: NgxCsvParser
) {}
ngOnInit(): void {}
onSelect(event: {
addedFiles: any;
}) {
this.files.push(...event.addedFiles);
this.ngxCsvParser.parse(this.files[0], {
header: this.header,
delimiter: ','
})
.pipe().subscribe((result: Array < any > ) => {
this.connections = result;
this.nodes.push({
"firstName": "You",
"lastName": "",
"name": "You",
"company": ""
});
for (const source of this.connections) {
const sourceName = source["First Name"] + " " + source["Last Name"];
this.links.push({
"source": "You",
"target": sourceName
});
this.nodes.push({
"firstName": source["First Name"],
"lastName": source["Last Name"],
"name": sourceName,
"company": source["Company"]
});
for (const target of this.connections) {
const targetName = target["First Name"] + " " + target["Last Name"];
if (sourceName != targetName && source["Company"] == target["Company"]) {
this.links.push({
"source": sourceName,
"target": targetName
});
}
}
const graph = {
"nodes": this.nodes,
"links": this.links
}
console.log(graph);
localStorage.setItem('graph', JSON.stringify(graph));
}
}, (error: NgxCSVParserError) => {
console.log('Error', error);
});
// this.router.navigateByUrl('/graph');
}
onRemove(event: File) {
console.log(event);
this.files.splice(this.files.indexOf(event), 1);
}
}
d3.component
import { Component, OnInit } from '@angular/core';
import * as d3 from 'd3';
import {Node} from '../d3/models/node';
import {Link} from '../d3/models/link';
@Component({
selector: 'app-graph',
templateUrl: './graph.component.html',
styleUrls: ['./graph.component.scss']
})
export class GraphComponent implements OnInit {
constructor() { }
ngOnInit() {
const retrievedObject = localStorage.getItem('graph');
const graph = JSON.parse(retrievedObject);
this.loadForceDirectedGraph(graph.nodes, graph.links);
}
loadForceDirectedGraph(nodes: Node[], links: Link[]) {
const svg = d3.select('svg');
const width = +svg.attr('width');
const height = +svg.attr('height');
const color = d3.scaleOrdinal(d3.schemeBlues[9]);
const simulation = d3.forceSimulation()
.force('link', d3.forceLink().id((d: Node) => d.name))// the id of the node
.force("charge", d3.forceManyBody().strength(-5).distanceMax(0.5 * Math.min(width, height)))
.force('center', d3.forceCenter(width / 2, height / 2));
console.log(nodes, links);
const link = svg.append('g')
.attr('class', 'links')
.selectAll('line')
.data(links)
.enter()
.append('line')
.attr('stroke-width', d => Math.sqrt(d.index))
.attr('stroke', 'black');
const node = svg.append('g')
.attr('class', 'nodes')
.selectAll('circle')
.data(nodes)
.enter()
.append('circle')
.attr('r', 8)
.attr("fill", function(d) { return color(d.company); })
.call(d3.drag()
.on('start', dragStarted)
.on('drag', dragged)
.on('end', dragEnded)
);
node.append('text')
.text((d) => d.company)
.attr('x', 6)
.attr('y', 3);
node.append('title').text((d) => d.name);
simulation
.nodes(nodes)
.on('tick', ticked);
simulation.force<d3.ForceLink<any, any>>('link')
.links(links);
function ticked() {
node
.attr('cx', d => d.x)
.attr('cy', d => d.y);
link
.attr('x1', d => d.source.x)
.attr('y1', d => d.source.y)
.attr('x2', d => d.target.x)
.attr('y2', d => d.target.y);
}
function dragStarted(event) {
if (!event.active) { simulation.alphaTarget(0.3).restart(); }
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
}
function dragged(event) {
event.subject.fx = event.x;
event.subject.fy = event.y;
}
function dragEnded(event) {
if (!event.active) { simulation.alphaTarget(0); }
event.subject.fx = null;
event.subject.fy = null;
}
}
}
【问题讨论】:
-
限制节点数和链接数是什么意思?你只是想在某个数字后停下来吗?您想将相似的节点/链接组合在一起吗?如果您只显示部分数据,该图表可能不准确。
-
基本上如何将两个 .csv 文件(例如 this.files[i] )组合在一起以创建一个图形
-
您读取一个 CSV 并创建一个数组以传递给 D3,对吗?为什么不能将数据从第二个 CSV 推送到同一个数组?我错过了什么?
-
@adamdport 很好,一旦数组数据被传递,它会自动定向到另一个将显示图表的组件。如何确保仅在添加第二个 CSV 后才显示图表。
-
@kjamp 在这种情况下,@Maxie 已经发布的答案似乎是可用的。他们的
onResultHandler只会在两个 CSV 都被解析后触发,并且您将可以访问两者的数据来构建您的数组。
标签: javascript node.js angular typescript d3.js