Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
vig
Sublinear Algorithms for VA
pseudo
Commits
e3815982
Commit
e3815982
authored
Oct 29, 2020
by
Kruyff,D.L.W. (Dylan)
Browse files
Major changes
parent
69108089
Changes
19
Hide whitespace changes
Inline
Side-by-side
AngularApp/prototype/src/app/api.service.ts
View file @
e3815982
...
@@ -85,20 +85,8 @@ export class ApiService {
...
@@ -85,20 +85,8 @@ export class ApiService {
return
await
response
.
json
();
return
await
response
.
json
();
}
}
async
getAverageProgressWindows
(
windows
):
Promise
<
number
[][]
>
{
async
getAverageWindows
(
windows
):
Promise
<
any
>
{
const
response
=
await
fetch
(
'
http://127.0.0.1:5000/average-progress
'
,
{
const
response
=
await
fetch
(
'
http://127.0.0.1:5000/average
'
,
{
method
:
'
POST
'
,
headers
:
{
'
Accept
'
:
'
application/json
'
,
'
Content-Type
'
:
'
application/json
'
},
body
:
JSON
.
stringify
({
windows
})
});
return
await
response
.
json
();
}
async
getAverageTableWindows
(
windows
):
Promise
<
number
[][]
>
{
const
response
=
await
fetch
(
'
http://127.0.0.1:5000/average-table
'
,
{
method
:
'
POST
'
,
method
:
'
POST
'
,
headers
:
{
headers
:
{
'
Accept
'
:
'
application/json
'
,
'
Accept
'
:
'
application/json
'
,
...
...
AngularApp/prototype/src/app/app.module.ts
View file @
e3815982
...
@@ -18,6 +18,7 @@ import {ZingchartAngularModule} from 'zingchart-angular';
...
@@ -18,6 +18,7 @@ import {ZingchartAngularModule} from 'zingchart-angular';
import
{
ProgressViewComponent
}
from
'
./progress-view/progress-view.component
'
;
import
{
ProgressViewComponent
}
from
'
./progress-view/progress-view.component
'
;
import
{
MainComponent
}
from
'
./main/main.component
'
;
import
{
MainComponent
}
from
'
./main/main.component
'
;
import
{
MatProgressBarModule
}
from
'
@angular/material/progress-bar
'
;
import
{
MatProgressBarModule
}
from
'
@angular/material/progress-bar
'
;
import
{
MatSliderModule
}
from
'
@angular/material/slider
'
;
PlotlyModule
.
plotlyjs
=
PlotlyJS
;
PlotlyModule
.
plotlyjs
=
PlotlyJS
;
...
@@ -40,7 +41,8 @@ PlotlyModule.plotlyjs = PlotlyJS;
...
@@ -40,7 +41,8 @@ PlotlyModule.plotlyjs = PlotlyJS;
BrowserAnimationsModule
,
BrowserAnimationsModule
,
MatTabsModule
,
MatTabsModule
,
MatProgressBarModule
,
MatProgressBarModule
,
ZingchartAngularModule
ZingchartAngularModule
,
MatSliderModule
],
],
providers
:
[],
providers
:
[],
bootstrap
:
[
AppComponent
]
bootstrap
:
[
AppComponent
]
...
...
AngularApp/prototype/src/app/cache.service.ts
View file @
e3815982
...
@@ -25,7 +25,7 @@ export class CacheService {
...
@@ -25,7 +25,7 @@ export class CacheService {
public
stepSize
=
200
;
public
stepSize
=
200
;
public
querySelectionMode
=
true
;
public
querySelectionMode
=
true
;
public
distances
=
[];
public
distances
=
[];
public
dtwdistances
:
number
[]
=
[];
public
_
dtwdistances
:
number
[]
=
[];
public
onNewData
:
EventEmitter
<
void
>
=
new
EventEmitter
<
void
>
();
public
onNewData
:
EventEmitter
<
void
>
=
new
EventEmitter
<
void
>
();
public
onNewSimilarity
:
EventEmitter
<
void
>
=
new
EventEmitter
<
void
>
();
public
onNewSimilarity
:
EventEmitter
<
void
>
=
new
EventEmitter
<
void
>
();
...
@@ -71,7 +71,7 @@ export class CacheService {
...
@@ -71,7 +71,7 @@ export class CacheService {
const
output
=
await
this
.
api
.
initialize
(
this
.
_queryWindow
);
const
output
=
await
this
.
api
.
initialize
(
this
.
_queryWindow
);
this
.
dtwdistances
=
output
.
distances
;
this
.
dtwdistances
=
output
.
distances
;
this
.
candidates
=
output
.
candidates
;
this
.
candidates
=
output
.
candidates
;
this
.
tables
=
output
.
hash_functions
;
this
.
createTable
()
;
this
.
_parameters
=
output
.
parameters
;
this
.
_parameters
=
output
.
parameters
;
console
.
log
(
output
);
console
.
log
(
output
);
}
}
...
@@ -81,16 +81,12 @@ export class CacheService {
...
@@ -81,16 +81,12 @@ export class CacheService {
const
output
=
await
this
.
api
.
update
(
this
.
_queryWindow
,
this
.
distances
,
this
.
_parameters
);
const
output
=
await
this
.
api
.
update
(
this
.
_queryWindow
,
this
.
distances
,
this
.
_parameters
);
this
.
dtwdistances
=
output
.
distances
;
this
.
dtwdistances
=
output
.
distances
;
this
.
candidates
=
output
.
candidates
;
this
.
candidates
=
output
.
candidates
;
this
.
tables
=
output
.
hash_functions
;
this
.
createTable
()
;
console
.
log
(
output
);
console
.
log
(
output
);
}
}
async
getAverageProgressWindows
(
windows
):
Promise
<
number
[][]
>
{
async
getAverageWindows
(
windows
):
Promise
<
any
>
{
return
await
this
.
api
.
getAverageProgressWindows
(
windows
);
return
await
this
.
api
.
getAverageWindows
(
windows
);
}
async
getAverageTableWindows
(
windows
):
Promise
<
number
[][]
>
{
return
await
this
.
api
.
getAverageTableWindows
(
windows
);
}
}
async
getQueryWindow
(
window
):
Promise
<
number
[]
>
{
async
getQueryWindow
(
window
):
Promise
<
number
[]
>
{
...
@@ -104,6 +100,27 @@ export class CacheService {
...
@@ -104,6 +100,27 @@ export class CacheService {
return
await
this
.
api
.
getWindow
(
indices
);
return
await
this
.
api
.
getWindow
(
indices
);
}
}
public
createTable
()
{
const
indices
=
this
.
dtwdistances
.
map
((
x
)
=>
x
>
500
?
100
:
Math
.
floor
(
x
/
5
));
const
table
=
{};
this
.
candidates
.
forEach
((
candidate
,
index
)
=>
{
if
(
table
[
indices
[
index
]]
===
undefined
)
{
table
[
indices
[
index
]]
=
[];
}
table
[
indices
[
index
]].
push
(
candidate
);
});
this
.
tables
=
table
;
}
public
set
dtwdistances
(
v
)
{
this
.
_dtwdistances
=
v
;
}
public
get
dtwdistances
():
number
[]
{
return
this
.
_dtwdistances
;
}
public
set
query
(
v
)
{
public
set
query
(
v
)
{
this
.
_query
=
v
;
this
.
_query
=
v
;
}
}
...
...
AngularApp/prototype/src/app/labeling-window/labeling-window.component.html
View file @
e3815982
...
@@ -9,8 +9,10 @@
...
@@ -9,8 +9,10 @@
</div>
</div>
</div>
</div>
</div>
</div>
<button
*ngIf=
"candidates"
(click)=
"updateQuery()"
class=
"train-button"
>
Update query
</button>
<div
class=
"button-holder"
>
<button
*ngIf=
"candidates"
(click)=
"train()"
class=
"train-button"
>
Train
</button>
<button
*ngIf=
"candidates"
(click)=
"updateQuery()"
class=
"train-button"
>
Query
</button>
<button
*ngIf=
"candidates"
(click)=
"train()"
class=
"train-button"
>
Train
</button>
</div>
</div>
</div>
AngularApp/prototype/src/app/labeling-window/labeling-window.component.ts
View file @
e3815982
...
@@ -43,7 +43,7 @@ export class LabelingWindowComponent implements OnInit {
...
@@ -43,7 +43,7 @@ export class LabelingWindowComponent implements OnInit {
}
}
async
getTopKSimilar
()
{
async
getTopKSimilar
()
{
this
.
topk
=
this
.
service
.
candidates
.
slice
(
0
,
2
0
);
this
.
topk
=
this
.
service
.
candidates
.
slice
(
0
,
1
2
);
await
this
.
createPlots
();
await
this
.
createPlots
();
}
}
...
...
AngularApp/prototype/src/app/main/main.component.css
View file @
e3815982
...
@@ -31,11 +31,11 @@
...
@@ -31,11 +31,11 @@
}
}
.left
{
.left
{
width
:
8
0%
;
width
:
7
0%
;
}
}
.right
{
.right
{
width
:
2
0%
;
width
:
3
0%
;
border-left
:
groove
;
border-left
:
groove
;
}
}
...
...
AngularApp/prototype/src/app/overview-window/overview-window.component.ts
View file @
e3815982
...
@@ -32,6 +32,7 @@ export class OverviewWindowComponent implements OnInit {
...
@@ -32,6 +32,7 @@ export class OverviewWindowComponent implements OnInit {
}
}
async
initializePlot
()
{
async
initializePlot
()
{
this
.
debugClicked
();
this
.
service
.
queryWindow
=
undefined
;
this
.
service
.
queryWindow
=
undefined
;
this
.
data
=
[];
this
.
data
=
[];
for
(
let
i
=
0
;
i
<
this
.
service
.
rawValues
.
length
;
i
++
)
{
for
(
let
i
=
0
;
i
<
this
.
service
.
rawValues
.
length
;
i
++
)
{
...
@@ -169,7 +170,7 @@ export class OverviewWindowComponent implements OnInit {
...
@@ -169,7 +170,7 @@ export class OverviewWindowComponent implements OnInit {
x
:
clickData
.
x
,
x
:
clickData
.
x
,
y
:
clickData
.
y
y
:
clickData
.
y
});
});
const
index
=
80503
;
//
Math.floor(xyInformation[0].scalenumvalue / (12000 / 6));
const
index
=
Math
.
floor
(
xyInformation
[
0
].
scalenumvalue
/
(
12000
/
6
));
await
this
.
service
.
getQueryWindow
(
index
);
await
this
.
service
.
getQueryWindow
(
index
);
await
this
.
service
.
initial
();
await
this
.
service
.
initial
();
// const temp = {};
// const temp = {};
...
@@ -177,6 +178,12 @@ export class OverviewWindowComponent implements OnInit {
...
@@ -177,6 +178,12 @@ export class OverviewWindowComponent implements OnInit {
// this.service.labels = temp;
// this.service.labels = temp;
}
}
async
debugClicked
()
{
const
index
=
80503
;
// Math.floor(xyInformation[0].scalenumvalue / (12000 / 6));
await
this
.
service
.
getQueryWindow
(
index
);
await
this
.
service
.
initial
();
}
zoom
(
p
)
{
zoom
(
p
)
{
if
(
!
p
.
ev
)
{
if
(
!
p
.
ev
)
{
return
;
return
;
...
...
AngularApp/prototype/src/app/progress-view/progress-view.component.css
View file @
e3815982
...
@@ -17,3 +17,15 @@
...
@@ -17,3 +17,15 @@
display
:
flex
;
display
:
flex
;
justify-content
:
center
;
justify-content
:
center
;
}
}
.hide
{
display
:
none
;
}
.container
{
display
:
flex
;
justify-content
:
center
;
}
line
{
stroke
:
#5e4646
;
}
circle
{
stroke
:
#fff
;
stroke-width
:
1.5px
;
}
AngularApp/prototype/src/app/progress-view/progress-view.component.html
View file @
e3815982
<
div
class=
"container"
*ngIf=
"data"
>
<
svg
id=
"visual"
width=
'500'
height=
'300'
></svg
>
<span
class=
"title"
><b>
Training Progress
</b></span
>
<div
*ngIf=
"data"
class=
"container"
>
<div
class=
"window"
>
<div
class=
"window"
>
<div
class=
"plots"
>
<div
class=
"plots"
>
<plotly-plot
[data]=
"data
"
[la
yout]=
"layout"
(sliderChange)=
"setSliderValue($event)
"
></plotly-plot>
<plotly-plot
*ngFor=
"let data of this.data; index as i;
"
[
c
la
ss.hide]=
"i != sliderValue"
[data]=
"data"
[layout]=
"layout
"
></plotly-plot>
</div>
</div>
</div>
</div>
<div
class=
"button-holder"
>
<mat-slider
vertical
min=
"0"
[max]=
"maxLength"
step=
"1"
[(value)]=
"sliderValue"
thumbLabel
tickInterval=
"5"
></mat-slider>
<button
class=
"show-candidates-button"
(click)=
"showCandidates()"
>
Show all {{ amountOfCandidates }} candidates
</button>
</div>
</div>
</div>
<style>
line
{
stroke
:
#999
;
}
circle
{
stroke
:
#fff
;
stroke-width
:
1.5px
;
}
</style>
<svg
width=
'960'
height=
'500'
></svg>
<script
src=
'https://d3js.org/d3.v4.min.js'
></script>
<script
src=
'https://d3js.org/d3.v4.min.js'
></script>
<script>
</script>
AngularApp/prototype/src/app/progress-view/progress-view.component.ts
View file @
e3815982
...
@@ -12,14 +12,15 @@ export class ProgressViewComponent implements OnInit {
...
@@ -12,14 +12,15 @@ export class ProgressViewComponent implements OnInit {
public
data
;
public
data
;
public
layout
;
public
layout
;
public
amountOfCandidates
;
public
amountOfCandidates
;
public
hover
=
0
;
private
_sliderValue
;
private
_sliderValue
=
0
;
constructor
(
private
cache
:
CacheService
)
{
}
constructor
(
private
cache
:
CacheService
)
{
}
ngOnInit
():
void
{
ngOnInit
():
void
{
this
.
showgraph
();
// this.cache.onNewSimilarity.subscribe(() => {
this.showgraph();
});
this
.
cache
.
onNew
Similarity
.
subscribe
(()
=>
{
this
.
initializeInfo
();
});
this
.
cache
.
onNew
Tables
.
subscribe
(()
=>
{
this
.
showgraph
();
});
}
}
averagePlot
(
averages
)
{
averagePlot
(
averages
)
{
...
@@ -121,47 +122,113 @@ export class ProgressViewComponent implements OnInit {
...
@@ -121,47 +122,113 @@ export class ProgressViewComponent implements OnInit {
};
};
}
}
async
initializeInfo
():
Promise
<
void
>
{
hoverPlot
(
averages
)
{
console
.
log
(
'
Updating progress view
'
);
this
.
data
=
averages
.
map
((
average
,
i
)
=>
{
console
.
log
(
this
.
similarity
);
return
[
const
allWindows
=
[];
{
const
keys
=
Object
.
keys
(
this
.
similarity
);
x
:
[...
Array
(
average
.
average
.
length
).
keys
()],
for
(
let
i
=
this
.
cache
.
nrOfTables
;
i
>=
1
;
i
--
)
{
y
:
average
.
average
,
if
(
keys
.
indexOf
(
i
.
toString
())
===
-
1
)
{
type
:
'
line
'
,
allWindows
.
push
([]);
line
:
{
}
else
{
color
:
'
red
'
,
allWindows
.
push
(
this
.
similarity
[
i
.
toString
()]);
width
:
3
}
}
}
},
const
averages
=
await
this
.
cache
.
getAverageProgressWindows
(
allWindows
);
{
this
.
plot
=
this
.
averagePlot
(
averages
);
x
:
[...
Array
(
average
.
average
.
length
).
keys
()],
let
candidates
=
[];
y
:
average
.
max
,
for
(
let
i
=
this
.
_sliderValue
;
i
<
this
.
cache
.
nrOfTables
;
i
++
)
{
type
:
'
scatter
'
,
candidates
=
candidates
.
concat
(
this
.
cache
.
windowSimilarity
[
i
.
toString
()]);
fill
:
null
,
}
mode
:
'
lines
'
,
this
.
amountOfCandidates
=
candidates
.
length
;
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
get
similarity
()
{
public
set
sliderValue
(
v
:
number
)
{
return
this
.
cache
.
windowSimilarity
;
this
.
_sliderValue
=
v
;
d3
.
selectAll
(
'
circle
'
).
transition
().
style
(
'
stroke
'
,
undefined
);
d3
.
select
(
'
#node-
'
+
v
).
transition
().
style
(
'
stroke
'
,
'
black
'
).
style
(
'
stroke-width
'
,
20
);
}
}
public
setSliderValue
(
v
)
{
public
get
sliderValue
():
number
{
this
.
_sliderValue
=
v
.
slider
.
active
;
return
this
.
_sliderValue
;
let
candidates
=
[];
for
(
let
i
=
this
.
_sliderValue
;
i
<
this
.
cache
.
nrOfTables
;
i
++
)
{
candidates
=
candidates
.
concat
(
this
.
cache
.
windowSimilarity
[
i
.
toString
()]);
}
this
.
amountOfCandidates
=
candidates
.
length
;
}
}
public
showCandidates
()
{
public
get
maxLength
():
number
{
this
.
cache
.
sliderValue
=
this
.
_sliderValue
;
return
Object
.
keys
(
this
.
similarity
).
length
;
}
public
get
similarity
()
{
return
this
.
cache
.
tables
;
}
}
public
showgraph
()
{
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
'
);
console
.
log
(
'
building
'
);
const
svg
=
d3
.
select
(
'
svg
'
);
const
svg
=
d3
.
select
(
'
#visual
'
);
const
width
=
+
svg
.
attr
(
'
width
'
);
const
width
=
+
svg
.
attr
(
'
width
'
);
const
height
=
+
svg
.
attr
(
'
height
'
);
const
height
=
+
svg
.
attr
(
'
height
'
);
...
@@ -171,52 +238,46 @@ export class ProgressViewComponent implements OnInit {
...
@@ -171,52 +238,46 @@ export class ProgressViewComponent implements OnInit {
.
force
(
'
link
'
,
d3
.
forceLink
().
id
((
d
:
any
)
=>
d
.
id
))
.
force
(
'
link
'
,
d3
.
forceLink
().
id
((
d
:
any
)
=>
d
.
id
))
.
force
(
'
charge
'
,
d3
.
forceManyBody
().
strength
(
100
))
// Gravity force
.
force
(
'
charge
'
,
d3
.
forceManyBody
().
strength
(
100
))
// Gravity force
.
force
(
'
collide
'
,
d3
.
forceCollide
().
radius
(
25
).
iterations
(
3
))
// Repulsion force
.
force
(
'
collide
'
,
d3
.
forceCollide
().
radius
(
25
).
iterations
(
3
))
// Repulsion force
.
force
(
'
center
'
,
d3
.
forceCenter
(
width
/
2
,
height
/
2
));
// Position force
.
force
(
'
center
'
,
d3
.
forceCenter
(
width
/
2
,
height
/
2
));
// Position force
d3
.
json
(
'
assets/miserables.json
'
)
.
catch
((
error
)
=>
{
throw
error
;
})
.
then
((
graph
)
=>
{
const
link
=
svg
.
append
(
'
g
'
)
.
selectAll
(
'
line
'
)
.
data
(
graph
.
links
)
.
enter
().
append
(
'
line
'
)
.
attr
(
'
stroke
'
,
'
blue
'
)
.
attr
(
'
fill
'
,
'
purple
'
)
.
attr
(
'
stroke-width
'
,
(
d
:
any
)
=>
d
.
value
*
.
08
);
const
node
=
svg
.
append
(
'
g
'
)
.
selectAll
(
'
circle
'
)
.
data
(
graph
.
nodes
)
.
enter
().
append
(
'
circle
'
)
.
attr
(
'
r
'
,
5
)
.
attr
(
'
fill
'
,
(
d
:
any
)
=>
color
(
d
.
group
))
.
call
(
d3
.
drag
()
.
on
(
'
start
'
,
dragstarted
)
.
on
(
'
drag
'
,
dragged
)
.
on
(
'
end
'
,
dragended
));
simulation
.
nodes
(
graph
.
nodes
)
.
on
(
'
tick
'
,
ticked
);
simulation
.
force
<
any
>
(
'
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
);
}
});
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
<
any
>
(
'
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
);