Skip to content
GitLab
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
4f8966d6
Commit
4f8966d6
authored
Nov 17, 2020
by
Kruyff,D.L.W. (Dylan)
Browse files
Better visualisations + multivariate data
parent
6e893f4b
Changes
31
Expand all
Hide whitespace changes
Inline
Side-by-side
AngularApp/prototype/src/app/api.service.ts
View file @
4f8966d6
...
...
@@ -6,17 +6,19 @@ export interface RawData {
}
export
interface
LshData
{
candidates
:
number
[];
distances
:
number
[];
hash_functions
:
number
[];
// number[][][][];
candidates
:
number
[][][];
average_candidates
:
number
[];
average_distances
:
number
[];
distances
:
number
[][][];
hash_functions
:
number
[][][][];
parameters
?:
number
[];
}
export
interface
TableInfoData
{
prototypes
:
{
average
:
number
[];
min
:
number
[];
max
:
number
[];
average
:
number
[]
[]
;
min
:
number
[]
[]
;
max
:
number
[]
[]
;
}[];
distances
:
number
[][];
}
...
...
AngularApp/prototype/src/app/labeling-window/labeling-window.component.css
View file @
4f8966d6
...
...
@@ -2,11 +2,12 @@
margin-right
:
20px
;
display
:
flex
;
justify-content
:
center
;
border-right
:
1px
solid
;
border-bottom
:
1px
solid
;
}
.subplot-container
{
display
:
flex
;
flex-wrap
:
wrap
;
overflow-x
:
scroll
;
width
:
95%
;
}
...
...
AngularApp/prototype/src/app/labeling-window/labeling-window.component.ts
View file @
4f8966d6
...
...
@@ -44,13 +44,13 @@ export class LabelingWindowComponent implements OnInit {
}
async
showSamples
()
{
this
.
topk
=
this
.
state
.
lshData
.
candidates
this
.
topk
=
this
.
state
.
lshData
.
average_
candidates
.
filter
((
candidate
)
=>
this
.
state
.
labels
[
candidate
]
!==
true
)
.
slice
(
0
,
this
.
k
);
this
.
subplots
=
[];
const
values
:
number
[][][]
=
await
this
.
state
.
getWindow
(
this
.
topk
);
for
(
const
idx
in
this
.
topk
)
{
const
window
=
values
[
idx
]
.
slice
(
0
,
1
)
;
const
window
=
values
[
idx
];
const
data
=
[];
window
.
forEach
((
channel
:
number
[],
index
:
number
)
=>
{
data
.
push
({
...
...
@@ -70,7 +70,7 @@ export class LabelingWindowComponent implements OnInit {
data
:
data
,
layout
:
{
grid
:
{
rows
:
1
,
//
this.state.queryWindow.length,
rows
:
this
.
state
.
queryWindow
.
length
,
columns
:
1
,
subplots
:
subplots
,
},
...
...
@@ -85,7 +85,7 @@ export class LabelingWindowComponent implements OnInit {
b
:
0
,
pad
:
4
},
height
:
100
,
height
:
100
*
values
[
0
].
length
,
width
:
300
,
titlefont
:
{
size
:
9
...
...
AngularApp/prototype/src/app/labels/labels.component.ts
View file @
4f8966d6
...
...
@@ -20,7 +20,7 @@ export class LabelsComponent implements OnInit {
async
createSubplots
()
{
this
.
goodLabels
=
[];
this
.
badLabels
=
[];
const
labelWindows
:
number
[][]
=
await
this
.
state
.
getWindow
(
Object
.
keys
(
this
.
state
.
labels
).
map
(
Number
));
const
labelWindows
:
number
[][]
[]
=
await
this
.
state
.
getWindow
(
Object
.
keys
(
this
.
state
.
labels
).
map
(
Number
));
Object
.
keys
(
this
.
state
.
labels
).
forEach
((
key
,
i
)
=>
{
const
index
=
Number
(
key
);
const
plot
=
...
...
AngularApp/prototype/src/app/main/main.component.html
View file @
4f8966d6
...
...
@@ -3,8 +3,8 @@
<app-overview-window
style=
"z-index: 10"
></app-overview-window>
<mat-tab-group
animationDuration=
"0ms"
(selectedTabChange)=
"changeTab($event)"
>
<mat-tab
label=
"Training"
>
<app-labeling-window></app-labeling-window>
<app-table-overview></app-table-overview>
<app-labeling-window></app-labeling-window>
</mat-tab>
<mat-tab
label=
"Labeled data"
>
<app-labels></app-labels>
...
...
AngularApp/prototype/src/app/overview-window/overview-window.component.html
View file @
4f8966d6
<zingchart-angular
#chart
[id]=
"id"
[config]=
"config"
(mousewheel)=
"zoom($event)"
(click)=
"clicked($event)"
[height]=
"
15
0"
></zingchart-angular>
<zingchart-angular
#chart
[id]=
"id"
[config]=
"config"
(mousewheel)=
"zoom($event)"
(click)=
"clicked($event)"
[height]=
"
30
0"
></zingchart-angular>
AngularApp/prototype/src/app/overview-window/overview-window.component.ts
View file @
4f8966d6
...
...
@@ -16,6 +16,7 @@ export class OverviewWindowComponent implements OnInit {
public
series
=
[];
public
goodLabels
=
[];
public
badLabels
=
[];
public
candidateLabels
=
[];
public
data
;
public
layout
;
...
...
@@ -93,9 +94,6 @@ export class OverviewWindowComponent implements OnInit {
});
// Initialize channels
this
.
state
.
rawData
.
forEach
((
channel
,
index
)
=>
{
if
(
index
!==
0
)
{
return
;
}
const
data
=
[];
for
(
let
i
=
0
;
i
<
channel
.
values
.
length
;
i
++
)
{
data
.
push
([
i
,
channel
.
values
[
i
]]);
...
...
@@ -150,37 +148,59 @@ export class OverviewWindowComponent implements OnInit {
};
console
.
log
(
this
.
config
);
console
.
log
(
"
showing plot
"
);
await
this
.
debugClicked
();
}
async
updatePlot
()
{
console
.
log
(
'
updating plot
'
);
if
(
!
this
.
state
.
queryWindow
)
{
return
;
}
this
.
goodLabels
=
[];
this
.
badLabels
=
[];
this
.
markers
=
[];
for
(
const
index
in
this
.
state
.
labels
)
{
if
(
this
.
state
.
labels
[
index
])
{
this
.
goodLabels
.
push
([
Number
(
index
)
*
(
12000
/
6
)
,
0
]);
this
.
goodLabels
.
push
([
Number
(
index
),
0
]);
this
.
markers
.
push
({
type
:
'
area
'
,
// BUG: For some reason the range values are multiplied by 10
range
:
[
Number
(
index
)
*
(
12000
/
6
)
/
10
,
(
Number
(
index
)
*
(
12000
/
6
)
+
this
.
state
.
windowSize
)
/
10
],
backgroundColor
:
'
#4caf50
'
,
range
:
[
Number
(
index
)
/
10
,
(
Number
(
index
)
+
this
.
state
.
windowSize
)
/
10
],
backgroundColor
:
"
#4caf50
"
,
});
}
else
{
this
.
badLabels
.
push
([
Number
(
index
)
*
(
12000
/
6
),
0
]);
this
.
badLabels
.
push
([
Number
(
index
)
,
-
1
]);
this
.
markers
.
push
({
type
:
'
area
'
,
// BUG: For some reason the range values are multiplied by 10
range
:
[
Number
(
index
)
*
(
12000
/
6
)
/
10
,
(
Number
(
index
)
*
(
12000
/
6
)
+
this
.
state
.
windowSize
)
/
10
],
backgroundColor
:
'
#f44336
'
,
range
:
[
Number
(
index
)
/
10
,
(
Number
(
index
)
+
this
.
state
.
windowSize
)
/
10
],
backgroundColor
:
"
#f44336
"
,
});
}
}
this
.
series
[
1
].
values
=
this
.
goodLabels
;
this
.
series
[
2
].
values
=
this
.
badLabels
;
this
.
config
.
scaleX
.
markers
=
this
.
markers
;
zingchart
.
exec
(
'
zingchart-ng-1
'
,
'
setdata
'
,
{
// for (const index of this.state.lshData.average_candidates) {
// this.candidateLabels.push([Number(index), 1]);
// this.markers.push({
// type: 'area',
// // BUG: For some reason the range values are multiplied by 10
// range: [Number(index) / 10, (Number(index) + this.state.windowSize) / 10],
// backgroundColor: '#b1a343',
// });
// }
console
.
log
(
this
.
markers
);
for
(
const
channel
of
this
.
config
.
graphset
)
{
if
(
channel
.
type
===
'
line
'
)
{
channel
.
scaleX
.
markers
=
this
.
markers
;
}
else
{
channel
.
series
[
0
].
values
=
this
.
goodLabels
;
channel
.
series
[
1
].
values
=
this
.
badLabels
;
channel
.
series
[
2
].
values
=
this
.
candidateLabels
;
}
}
this
.
chart
.
setdata
({
data
:
this
.
config
});
}
async
updateCandidates
(
sliderIndex
)
{
...
...
AngularApp/prototype/src/app/progress-view/progress-view.component.css
View file @
4f8966d6
...
...
@@ -27,5 +27,11 @@
justify-content
:
center
;
}
mat-slider
{
display
:
flex
;
justify-content
:
center
;
width
:
400px
;
}
line
{
stroke
:
#5e4646
;
}
circle
{
stroke
:
#fff
;
stroke-width
:
1.5px
;
}
AngularApp/prototype/src/app/progress-view/progress-view.component.html
View file @
4f8966d6
<svg
id=
"visual"
width=
'500'
height=
'300'
></svg>
<!--<svg id="visual" width='500' height='300'></svg>-->
<div
*ngIf=
"data"
class=
"histogram"
>
<div
class=
"container"
>
<plotly-plot
(hover)=
"onHover($event)"
[data]=
"hist.data"
[layout]=
"hist.layout"
></plotly-plot>
</div>
<div
class=
"slider"
>
<mat-slider
[min]=
"0"
[max]=
"maxLength"
step=
"1"
[value]=
"sliderValue"
(input)=
"setSliderValue($event)"
thumbLabel
tickInterval=
"5"
></mat-slider>
</div>
</div>
<div
*ngIf=
"data"
class=
"container"
>
<div
class=
"window"
>
<div
class=
"plots"
>
<plotly-plot
*ngFor=
"let data of this.data; index as i;"
[class.hide]=
"i != sliderValue"
[data]=
"data"
[layout]=
"layout"
></plotly-plot>
</div>
</div>
<mat-slider
vertical
min=
"0"
[max]=
"maxLength"
step=
"1"
[(value)]=
"sliderValue"
thumbLabel
tickInterval=
"5"
></mat-slider>
</div>
<script
src=
'https://d3js.org/d3.v4.min.js'
></script>
AngularApp/prototype/src/app/progress-view/progress-view.component.ts
View file @
4f8966d6
import
{
Component
,
OnInit
}
from
'
@angular/core
'
;
import
{
Component
,
OnInit
,
ViewChild
}
from
'
@angular/core
'
;
import
{
StateService
}
from
'
../state.service
'
;
import
*
as
d3
from
'
d3
'
;
...
...
@@ -8,9 +8,11 @@ import * as d3 from 'd3';
styleUrls
:
[
'
./progress-view.component.css
'
]
})
export
class
ProgressViewComponent
implements
OnInit
{
@
ViewChild
(
'
chart
'
)
chart
;
public
plot
;
public
data
;
public
layout
;
public
hist
;
public
amountOfCandidates
;
public
hover
=
0
;
...
...
@@ -20,23 +22,60 @@ export class ProgressViewComponent implements OnInit {
ngOnInit
():
void
{
this
.
state
.
onNewTableInfo
.
subscribe
(()
=>
{
this
.
showgraph
();
});
this
.
state
.
onNewTableInfo
.
subscribe
(()
=>
{
this
.
showHistogram
();
});
}
showHistogram
()
{
const
table
=
this
.
state
.
_averageTable
;
this
.
hist
=
{
data
:
[{
x
:
Object
.
keys
(
table
),
y
:
Object
.
values
(
table
).
map
((
values
:
number
[])
=>
values
.
length
),
// / (this.service.rawValues.length - this.service.windowSize)),
type
:
'
bar
'
,
opacity
:
0.5
,
marker
:
{
color
:
Object
.
keys
(
table
).
map
((
key
)
=>
{
return
this
.
getColor
(
Number
(
key
)
/
Number
(
Object
.
keys
(
table
)[
Object
.
keys
(
table
).
length
-
1
]));
})
}
}],
layout
:
{
hovermode
:
'
closest
'
,
autosize
:
true
,
margin
:
{
l
:
10
,
r
:
10
,
t
:
10
,
b
:
10
,
pad
:
4
},
xaxis
:
{
showticklabels
:
false
},
yaxis
:
{
showticklabels
:
false
},
height
:
200
,
width
:
400
,
}
};
}
onHover
(
data
)
{
console
.
log
(
data
);
this
.
setSliderValue
({
value
:
data
.
points
[
0
].
x
});
}
hoverPlot
(
averages
)
{
const
subplots
=
[];
this
.
data
=
averages
.
map
((
prototype
)
=>
{
return
[
{
x
:
[...
Array
(
prototype
.
average
.
length
).
keys
()],
y
:
prototype
.
average
,
type
:
'
line
'
,
line
:
{
color
:
'
red
'
,
width
:
3
}
},
{
x
:
[...
Array
(
prototype
.
average
.
length
).
keys
()],
y
:
prototype
.
max
,
const
channelData
=
[];
prototype
.
max
.
forEach
((
channel
,
index
)
=>
{
channelData
.
push
({
x
:
[...
Array
(
channel
.
length
).
keys
()],
y
:
channel
,
xaxis
:
'
x
'
,
yaxis
:
`y
${
index
+
2
}
`
,
type
:
'
scatter
'
,
fill
:
null
,
mode
:
'
lines
'
,
...
...
@@ -44,10 +83,14 @@ export class ProgressViewComponent implements OnInit {
color
:
'
rgb(55, 128, 191)
'
,
width
:
3
}
},
{
x
:
[...
Array
(
prototype
.
average
.
length
).
keys
()],
y
:
prototype
.
min
,
});
});
prototype
.
min
.
forEach
((
channel
,
index
)
=>
{
channelData
.
push
({
x
:
[...
Array
(
channel
.
length
).
keys
()],
y
:
channel
,
xaxis
:
'
x
'
,
yaxis
:
`y
${
index
+
2
}
`
,
type
:
'
scatter
'
,
fill
:
'
tonexty
'
,
mode
:
'
lines
'
,
...
...
@@ -55,10 +98,32 @@ export class ProgressViewComponent implements OnInit {
color
:
'
rgb(55, 128, 191)
'
,
width
:
3
}
},
];
});
});
prototype
.
average
.
forEach
((
channel
,
index
)
=>
{
channelData
.
push
({
x
:
[...
Array
(
channel
.
length
).
keys
()],
y
:
channel
,
xaxis
:
'
x
'
,
yaxis
:
`y
${
index
+
2
}
`
,
type
:
'
line
'
,
line
:
{
color
:
'
red
'
,
width
:
3
}
});
});
return
channelData
;
});
for
(
let
index
=
0
;
index
<
this
.
state
.
queryWindow
.
length
;
index
++
)
{
subplots
.
push
([
`xy
${
index
+
2
}
`
]);
}
this
.
layout
=
{
grid
:
{
rows
:
this
.
state
.
queryWindow
.
length
,
columns
:
1
,
subplots
:
subplots
,
},
showlegend
:
false
,
hovermode
:
'
closest
'
,
autosize
:
true
,
...
...
@@ -77,15 +142,21 @@ export class ProgressViewComponent implements OnInit {
zeroline
:
false
,
showticklabels
:
false
,
},
height
:
3
00
,
width
:
3
00
,
height
:
4
00
,
width
:
4
00
,
};
this
.
state
.
queryWindow
.
forEach
((
channel
:
number
[],
index
:
number
)
=>
{
this
.
layout
[
`yaxis
${
index
+
2
}
`
]
=
{
zeroline
:
false
,
showticklabels
:
false
,
};
});
}
public
set
s
liderValue
(
v
:
number
)
{
this
.
_sliderValue
=
v
;
public
set
S
liderValue
(
v
)
{
this
.
_sliderValue
=
v
.
value
;
d3
.
selectAll
(
'
circle
'
).
transition
().
style
(
'
stroke
'
,
undefined
);
d3
.
select
(
'
#node-
'
+
v
).
transition
().
style
(
'
stroke
'
,
'
black
'
).
style
(
'
stroke-width
'
,
20
);
d3
.
select
(
'
#node-
'
+
v
.
value
).
transition
().
style
(
'
stroke
'
,
'
black
'
).
style
(
'
stroke-width
'
,
20
);
}
public
get
sliderValue
():
number
{
...
...
@@ -93,11 +164,11 @@ export class ProgressViewComponent implements OnInit {
}
public
get
maxLength
():
number
{
return
Object
.
keys
(
this
.
table
).
length
;
return
Object
.
keys
(
this
.
table
).
length
-
1
;
}
public
get
table
()
{
return
this
.
state
.
t
able
;
return
this
.
state
.
_averageT
able
;
}
async
showgraph
()
{
...
...
@@ -107,91 +178,91 @@ export class ProgressViewComponent implements OnInit {
this
.
hoverPlot
(
this
.
state
.
tableInfo
.
prototypes
);
const
distances
=
this
.
state
.
tableInfo
.
distances
;
for
(
const
key
in
this
.
table
)
{
const
size
=
this
.
table
[
key
].
length
;
nodes
.
push
({
id
:
key
,
group
:
Number
(
key
),
size
:
size
});
}
for
(
const
key
in
this
.
table
)
{
for
(
const
key2
in
this
.
table
)
{
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
};
const
svg
=
d3
.
select
(
'
#visual
'
);
const
width
=
+
svg
.
attr
(
'
width
'
);
const
height
=
+
svg
.
attr
(
'
height
'
);
svg
.
selectAll
(
'
*
'
).
remove
();
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
<
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
);
}
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
;
}
//
for (const key in this.table) {
//
const size = this.table[key].length;
//
nodes.push({id: key, group: Number(key), size: size});
//
}
//
for (const key in this.table) {
//
for (const key2 in this.table) {
//
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};
//
//
const svg = d3.select('#visual');
//
const width = +svg.attr('width');
//
const height = +svg.attr('height');
//
//
svg.selectAll('*').remove();
//
//
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<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);
//
}
//
//
function dragstarted(d) {
//
if (!d3.event.active) {
//
simulation.alphaTarget(0.1).restart();
//
}
//
d.fx = d.x;
//
d.fy = d.y;