import { Component, OnInit } from '@angular/core'; import {CacheService} from '../cache.service'; import * as d3 from 'd3'; @Component({ selector: 'app-progress-view', templateUrl: './progress-view.component.html', styleUrls: ['./progress-view.component.css'] }) export class ProgressViewComponent implements OnInit { public plot; public data; public layout; public amountOfCandidates; public hover = 0; private _sliderValue = 0; constructor(private cache: CacheService) { } ngOnInit(): void { // this.cache.onNewSimilarity.subscribe(() => { this.showgraph(); }); this.cache.onNewTables.subscribe(() => { this.showgraph(); }); } averagePlot(averages) { console.log(averages); let highest = 0; averages.map((average, i) => { if (average.average.length !== 0 && i > highest) { highest = i; } }); let data = averages.map((average, i) => { return [ { x: [...Array(average.average.length).keys()], y: average.average, type: 'line', visible: i === highest, line: { color: 'red', width: 3 } }, { x: [...Array(average.average.length).keys()], y: average.max, type: 'scatter', visible: i === highest, fill: null, mode: 'lines', line: { color: 'rgb(55, 128, 191)', width: 3 } }, { x: [...Array(average.average.length).keys()], y: average.min, type: 'scatter', visible: i === highest, fill: 'tonexty', mode: 'lines', line: { color: 'rgb(55, 128, 191)', width: 3 } }, ]; }); data = [].concat(...data); const visibility = Array(averages.length * 3).fill(false); const steps = []; for (let i = 0; i < this.cache.nrOfTables; i++) { const v = visibility.slice(); v[i * 3 + 2] = true; v[i * 3 + 1] = true; v[i * 3] = true; steps.push({ label: (100 * (i + 1) / this.cache.nrOfTables).toString() + '%', method: 'restyle', args: ['visible', v] }); } this._sliderValue = highest; this.data = data; this.layout = { showlegend: false, hovermode: 'closest', autosize: true, margin: { l: 50, r: 30, t: 30, pad: 4 }, xaxis: { showgrid: false, zeroline: false, showticklabels: false, }, yaxis: { zeroline: false, showticklabels: false, }, height: 300, width: 300, sliders: [{ active: highest, pad: {t: 30}, currentvalue: { xanchor: 'right', prefix: 'Similarity: ', font: { color: '#888', size: 10 } }, steps }] }; } hoverPlot(averages) { this.data = averages.map((average, i) => { return [ { x: [...Array(average.average.length).keys()], y: average.average, type: 'line', line: { color: 'red', width: 3 } }, { x: [...Array(average.average.length).keys()], y: average.max, type: 'scatter', fill: null, mode: 'lines', line: { color: 'rgb(55, 128, 191)', width: 3 } }, { x: [...Array(average.average.length).keys()], y: average.min, type: 'scatter', fill: 'tonexty', mode: 'lines', line: { color: 'rgb(55, 128, 191)', width: 3 } }, ]; }); this.layout = { showlegend: false, hovermode: 'closest', autosize: true, margin: { l: 50, r: 30, t: 30, pad: 4 }, xaxis: { showgrid: false, zeroline: false, showticklabels: false, }, yaxis: { zeroline: false, showticklabels: false, }, height: 300, width: 300, }; } public set sliderValue(v: number) { this._sliderValue = v; d3.selectAll('circle').transition().style('stroke', undefined); d3.select('#node-' + v).transition().style('stroke', 'black').style('stroke-width', 20); } public get sliderValue(): number { return this._sliderValue; } public get maxLength(): number { return Object.keys(this.similarity).length; } public get similarity() { return this.cache.tables; } async showgraph() { const nodes = []; const links = []; const temp = (await this.cache.getAverageWindows(Object.values(this.similarity))); const keys = Object.keys(this.similarity); console.log(temp); this.hoverPlot(temp.averages); const distances = temp.distances; console.log(this.similarity); for (const key in this.similarity) { const size = this.similarity[key].length; nodes.push({id: key, group: Number(key), size: size}); } for (const key in this.similarity) { for (const key2 in this.similarity) { if (key === key2) { continue; } links.push({source: key, target: key2, value: 0.001 * (100 - 5 * distances[keys.indexOf(key)][keys.indexOf(key2)])}); } } const graph = {nodes, links}; console.log(graph); console.log('building'); const svg = d3.select('#visual'); const width = +svg.attr('width'); const height = +svg.attr('height'); const color = d3.scaleOrdinal(d3.schemeCategory10); const simulation = d3.forceSimulation() .force('link', d3.forceLink().id((d: any) => d.id)) .force('charge', d3.forceManyBody().strength(100)) // Gravity force .force('collide', d3.forceCollide().radius(25).iterations(3)) // Repulsion force .force('center', d3.forceCenter(width / 2, height / 2)); // Position force const link = svg.append('g') .selectAll('line') .data(graph.links) .enter().append('line') .attr('stroke', 'grey') .attr('stroke-width', (d: any) => d.value); const node = svg.append('g') .selectAll('circle') .data(graph.nodes) .enter().append('circle') .attr('r', (d: any) => 5 * Math.log(d.size) / Math.log(10)) .attr('fill', (d: any) => this.getColor(d.group / graph.nodes.length)) .attr('id', (d: any) => 'node-' + d.group) .on('mouseover', (d: any) => {this.sliderValue = d.group; }) .call(d3.drag() .on('start', dragstarted) .on('drag', dragged) .on('end', dragended)); simulation .nodes(graph.nodes as any) .on('tick', ticked); simulation.force('link') .links(graph.links); function ticked() { link .attr('x1', (d: any) => d.source.x) .attr('y1', (d: any) => d.source.y) .attr('x2', (d: any) => d.target.x) .attr('y2', (d: any) => d.target.y); node .attr('cx', (d: any) => d.x) .attr('cy', (d: any) => d.y); } function dragstarted(d) { if (!d3.event.active) { simulation.alphaTarget(0.1).restart(); } d.fx = d.x; d.fy = d.y; } function dragged(d) { d.fx = d3.event.x; d.fy = d3.event.y; } function dragended(d) { if (!d3.event.active) { simulation.alphaTarget(0); } d.fx = null; d.fy = null; } } getColor(value) { const hue=((1-value)*120).toString(10); return ["hsl(",hue,",100%,50%)"].join(""); } }