Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Fractalis
fractal.js
Commits
b8d67217
Commit
b8d67217
authored
Oct 03, 2018
by
Sascha Herzinger
Browse files
Implementation of new parameter API
parent
45a60f2c
Pipeline
#6671
passed with stages
in 5 minutes and 55 seconds
Changes
10
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/main.js
View file @
b8d67217
...
...
@@ -67,14 +67,25 @@ class FractalJS {
store
.
dispatch
(
'
setSubsets
'
,
[])
}
// FIXME: temporarily disabled. Focus on stabilizing core functionality for now.
// // noinspection JSMethodCanBeStatic
// chart2id (vm, callback) {
// return store.getters.stateManager.chart2id(vm, callback)
// }
//
// // noinspection JSMethodCanBeStatic
// id2chart (selector, stateID) {
// return store.getters.stateManager.id2chart(selector, stateID)
// }
// noinspection JSMethodCanBeStatic
chart2id
(
vm
,
callback
)
{
return
store
.
getters
.
state
Manager
.
chart2id
(
vm
,
callback
)
getChartParameterDescription
(
vm
)
{
return
store
.
getters
.
chart
Manager
.
getChartParamDescr
(
vm
)
}
// noinspection JSMethodCanBeStatic
id2chart
(
selector
,
stateID
)
{
return
store
.
getters
.
state
Manager
.
id2chart
(
selector
,
stateID
)
setChartParameter
(
vm
,
parameter
)
{
store
.
getters
.
chart
Manager
.
setChartParams
(
vm
,
parameter
)
}
}
...
...
src/services/chart-manager.js
View file @
b8d67217
import
Vue
from
'
vue
'
import
_
from
'
lodash
'
export
default
class
{
constructor
()
{
...
...
@@ -46,4 +47,20 @@ export default class {
getAvailableCharts
()
{
return
Object
.
keys
(
this
.
availableCharts
)
}
getChartParamDescr
(
vm
)
{
if
(
typeof
vm
.
params
===
'
undefined
'
)
{
throw
new
Error
(
'
This chart does not expose any parameters. This is a bug that you should report.
'
)
}
return
_
.
cloneDeep
(
vm
.
params
)
}
setChartParameter
(
vm
,
params
)
{
Object
.
keys
(
params
).
forEach
(
key
=>
{
if
(
typeof
vm
.
params
[
key
]
===
'
undefined
'
)
{
throw
new
Error
(
`Parameter "
${
key
}
" does not exist for this chart.`
)
}
vm
.
params
[
key
].
value
=
params
[
key
]
})
}
}
src/vue/charts/Boxplot.vue
View file @
b8d67217
...
...
@@ -2,52 +2,55 @@
<chart
v-on:resize=
"resize"
>
<control-panel
name=
"Boxplot Panel"
>
<data-box
header=
"
Numerical Variables
"
<data-box
:
header=
"
params.numVars.label
"
:dataTypes=
"['numerical', 'numerical_array']"
:validRange=
"[1, Infinity]"
v-on:update=
"update_numData"
>
:validRange=
"[params.numVars.minLength, params.numVars.maxLength]"
v-on:select=
"updateNumVarsSelection"
v-on:update=
"updateNumVars"
>
</data-box>
<data-box
header=
"
Categorical Variables
"
<data-box
:
header=
"
params.catVars.label
"
:dataTypes=
"['categorical']"
v-on:update=
"update_catData"
>
:validRange=
"[params.catVars.minLength, params.catVars.maxLength]"
v-on:select=
"updateCatVarsSelection"
v-on:update=
"updateCatVars"
>
</data-box>
<hr
class=
"fjs-seperator"
/>
<div
class=
"fjs-parameter-container"
>
<div>
<label>
Data transformation:
<select
class=
"fjs-transformation-select"
v-model=
"params.transformation"
>
<option
v-for=
"t in transformations"
>
{{
t
}}
</option>
<select
class=
"fjs-transformation-select"
v-model=
"params.transformation
.value
"
>
<option
v-for=
"t in
params.
transformation
.validValue
s"
>
{{
t
}}
</option>
</select>
</label>
</div>
<div>
<label>
<input
type=
"checkbox"
v-model=
"params.showOutliers"
/>
<input
type=
"checkbox"
v-model=
"params.showOutliers
.value
"
/>
Show Outliers
</label>
</div>
<div>
<label>
<input
type=
"checkbox"
v-model=
"params.showData"
/>
<input
type=
"checkbox"
v-model=
"params.showData
.value
"
/>
Show Points
</label>
</div>
<div>
<label>
<input
type=
"checkbox"
v-model=
"params.jitter"
/>
<input
type=
"checkbox"
v-model=
"params.jitter
.value
"
/>
Jitter Data
</label>
</div>
<div>
<label>
<input
type=
"checkbox"
v-model=
"params.showKDE"
/>
<input
type=
"checkbox"
v-model=
"params.showKDE
.value
"
/>
Show Density Est.
</label>
</div>
<div>
<label>
<input
type=
"checkbox"
v-model=
"params.ignoreSubsets"
/>
<input
type=
"checkbox"
v-model=
"params.ignoreSubsets
.value
"
/>
Ignore Subsets
</label>
</div>
...
...
@@ -153,7 +156,7 @@
</image>
<polyline
class=
"fjs-kde"
:points=
"kdePolyPoints[label]"
v-if=
"params.showKDE"
>
v-if=
"params.showKDE
.value
"
>
</polyline>
</g>
</g>
...
...
@@ -177,16 +180,50 @@
name
:
'
boxplot
'
,
data
()
{
return
{
numData
:
[],
catData
:
[],
transformations
:
[
'
identity
'
,
'
log2(x)
'
,
'
log10(x)
'
,
'
2^x
'
,
'
10^x
'
],
params
:
{
showOutliers
:
true
,
showData
:
false
,
jitter
:
false
,
showKDE
:
false
,
ignoreSubsets
:
false
,
transformation
:
'
identity
'
numVars
:
{
type
:
Array
,
elementType
:
String
,
label
:
'
Numerical Variables
'
,
validValues
:
[],
minLength
:
1
,
maxLength
:
Infinity
,
value
:
[]
},
catVars
:
{
type
:
Array
,
elementType
:
String
,
label
:
'
Categorical Variables
'
,
validValues
:
[],
minLength
:
0
,
maxLength
:
Infinity
,
value
:
[]
},
showOutliers
:
{
type
:
Boolean
,
value
:
true
},
showData
:
{
type
:
Boolean
,
value
:
false
},
jitter
:
{
type
:
Boolean
,
value
:
false
},
showKDE
:
{
type
:
Boolean
,
value
:
false
},
ignoreSubsets
:
{
type
:
Boolean
,
value
:
false
},
transformation
:
{
type
:
String
,
value
:
'
identity
'
,
validValues
:
[
'
identity
'
,
'
log2(x)
'
,
'
log10(x)
'
,
'
2^x
'
,
'
10^x
'
]
}
},
width
:
0
,
height
:
0
,
...
...
@@ -212,8 +249,8 @@
features
:
this
.
numData
,
categories
:
this
.
catData
,
id_filter
:
this
.
idFilter
.
value
,
transformation
:
this
.
params
.
transformation
,
subsets
:
this
.
params
.
ignoreSubsets
?
[]
:
store
.
getters
.
subsets
transformation
:
this
.
params
.
transformation
.
value
,
subsets
:
this
.
params
.
ignoreSubsets
.
value
?
[]
:
store
.
getters
.
subsets
}
},
pointSize
()
{
...
...
@@ -253,13 +290,13 @@
.
filter
(
d
=>
d
.
subset
===
subset
&&
d
.
feature
===
feature
&&
d
.
category
===
category
&&
(
this
.
params
.
showOutliers
?
true
:
!
d
.
outlier
)
&&
(
this
.
params
.
showOutliers
.
value
?
true
:
!
d
.
outlier
)
&&
typeof
d
.
value
===
'
number
'
)
.
map
(
d
=>
{
return
{
id
:
d
.
id
,
value
:
d
.
value
,
jitter
:
Math
.
max
(
this
.
pointSize
/
2
,
(
this
.
params
.
jitter
?
Math
.
random
()
*
this
.
boxplotWidth
/
2
:
this
.
boxplotWidth
/
2
)
-
this
.
pointSize
/
2
),
jitter
:
Math
.
max
(
this
.
pointSize
/
2
,
(
this
.
params
.
jitter
.
value
?
Math
.
random
()
*
this
.
boxplotWidth
/
2
:
this
.
boxplotWidth
/
2
)
-
this
.
pointSize
/
2
),
subset
:
d
.
subset
,
category
:
d
.
category
,
outlier
:
d
.
outlier
...
...
@@ -294,7 +331,7 @@
},
scales
()
{
const
values
=
this
.
results
.
data
.
filter
(
d
=>
this
.
params
.
showOutliers
?
true
:
!
d
.
outlier
)
.
filter
(
d
=>
this
.
params
.
showOutliers
.
value
?
true
:
!
d
.
outlier
)
.
map
(
d
=>
d
.
value
)
const
flattened
=
[].
concat
.
apply
([],
values
)
const
extent
=
d3
.
extent
(
flattened
)
...
...
@@ -359,10 +396,10 @@
})
}
},
'
params.showData
'
:
{
'
params.showData
.value
'
:
{
handler
:
function
()
{
this
.
$nextTick
(()
=>
this
.
drawPoints
())
}
},
'
params.jitter
'
:
{
'
params.jitter
.value
'
:
{
handler
:
function
()
{
this
.
$nextTick
(()
=>
this
.
drawPoints
())
}
},
'
points
'
:
{
...
...
@@ -391,12 +428,6 @@
hideTooltip
(
label
)
{
this
.
getTippyInstances
(
label
).
forEach
(
d
=>
d
.
hide
())
},
update_numData
(
ids
)
{
this
.
numData
=
ids
},
update_catData
(
ids
)
{
this
.
catData
=
ids
},
setIDFilter
(
label
)
{
if
(
label
===
this
.
selectedLabel
)
{
store
.
dispatch
(
'
setFilter
'
,
{
source
:
this
.
_uid
,
filter
:
'
ids
'
,
value
:
[]})
...
...
@@ -413,7 +444,7 @@
const
canvas
=
this
.
canvas
[
label
]
const
ctx
=
canvas
.
getContext
(
'
2d
'
)
ctx
.
clearRect
(
0
,
0
,
canvas
.
width
,
canvas
.
height
)
if
(
this
.
params
.
showData
)
{
if
(
this
.
params
.
showData
.
value
)
{
this
.
points
[
label
].
forEach
(
point
=>
{
ctx
.
beginPath
()
ctx
.
fillStyle
=
point
.
outlier
?
'
#f00
'
:
'
#000
'
...
...
@@ -442,6 +473,18 @@
this
.
results
=
results
})
.
catch
(
error
=>
console
.
error
(
error
))
},
updateNumVars
(
ids
)
{
this
.
params
.
numVars
.
validValues
=
ids
},
updateCatVars
(
ids
)
{
this
.
params
.
catVars
.
validValues
=
ids
},
updateNumVarsSelection
(
ids
)
{
this
.
params
.
numVars
.
value
=
ids
},
updateCatVarsSelection
(
ids
)
{
this
.
params
.
catVars
.
value
=
ids
}
},
components
:
{
...
...
@@ -455,11 +498,6 @@
],
directives
:
{
tooltip
},
mounted
()
{
this
.
registerDataToSave
([
'
catData
'
,
'
numData
'
,
'
params
'
])
}
}
</
script
>
...
...
src/vue/charts/Heatmap.vue
View file @
b8d67217
<
template
>
<chart
v-on:resize=
"resize"
>
<control-panel
name=
"Heatmap Panel"
>
<data-box
header=
"
Numerical Variables
"
<data-box
:
header=
"
params.numVars.label
"
:dataTypes=
"['numerical_array']"
:validRange=
"[1, Infinity]"
v-on:update=
"update_numericArrayData"
>
:validRange=
"[params.numVars.minLength, params.numVars.maxLength]"
v-on:select=
"updateNumVarsSelection"
v-on:update=
"updateNumVars"
>
</data-box>
<hr
class=
"fjs-seperator"
/>
...
...
@@ -12,67 +13,12 @@
<span
class=
"fjs-param-header"
>
Ranking Criteria
</span>
<fieldset
class=
"fjs-expression-ranking fjs-fieldset"
>
<legend>
Expression Level
</legend>
<!--FIXME: Make this dynamic similar to volcanoplot-->
<div>
<div
v-for=
"method in params.rankingMethod.validValues"
>
<label>
<input
type=
"radio"
value=
"me
an
"
v-model=
"rankingMethod"
>
<input
type=
"radio"
:
value=
"me
thod
"
v-model=
"
params.
rankingMethod
.value
"
>
Mean
</label>
</div>
<div>
<label>
<input
type=
"radio"
value=
"median"
v-model=
"rankingMethod"
>
Median
</label>
</div>
</fieldset>
<fieldset
class=
"fjs-fieldset"
>
<legend>
Expression Variability
</legend>
<div>
<label>
<input
type=
"radio"
value=
"variance"
v-model=
"rankingMethod"
>
Variance
</label>
</div>
</fieldset>
<fieldset
class=
"fjs-fieldset"
>
<legend>
Differential Expression
</legend>
<div>
<label>
<input
type=
"radio"
value=
"logFC"
v-model=
"rankingMethod"
>
logFC
</label>
</div>
<div>
<label>
<input
type=
"radio"
value=
"t"
v-model=
"rankingMethod"
>
t
</label>
</div>
<div>
<label>
<input
type=
"radio"
value=
"F"
v-model=
"rankingMethod"
>
F
</label>
</div>
<div>
<label>
<input
type=
"radio"
value=
"B"
v-model=
"rankingMethod"
>
B
</label>
</div>
<div>
<label>
<input
type=
"radio"
value=
"P.Val"
v-model=
"rankingMethod"
>
P.Value
</label>
</div>
<div>
<label>
<input
type=
"radio"
value=
"adj.P.Val"
v-model=
"rankingMethod"
>
adj.P.Value
</label>
</div>
</fieldset>
</div>
...
...
@@ -80,36 +26,30 @@
<span
class=
"fjs-param-header"
>
Heatmap Clustering
</span>
<fieldset
class=
"fjs-fieldset"
>
<legend>
Algorithm
</legend>
<div>
<div
v-for=
"algorithm in params.clusterAlgorithm.validValues"
>
<label>
<input
type=
"radio"
value=
"hclust"
v-model=
"cluster.algorithm"
/>
Hierarch.
</label>
</div>
<div>
<label>
<input
type=
"radio"
value=
"kmeans"
v-model=
"cluster.algorithm"
/>
KMeans
<input
type=
"radio"
:value=
"algorithm"
v-model=
"params.clusterAlgorithm.value"
/>
{{
algorithm
}}
</label>
</div>
</fieldset>
<fieldset
class=
"fjs-cluster-option-fieldset fjs-fieldset"
v-if=
"cluster
.a
lgorithm === 'hclust'"
>
<fieldset
class=
"fjs-cluster-option-fieldset fjs-fieldset"
v-if=
"
params.
cluster
A
lgorithm
.value
=== 'hclust'"
>
<legend>
Options
</legend>
<div
class=
"fjs-hclust-selects"
>
<select
v-model=
"
cluster.options.method
"
>
<select
v-model=
"
params.clusterMethod.value
"
>
<option
value=
""
selected
disabled
>
-- Method --
</option>
<option
:value=
"value"
v-for=
"value in
['single', 'complete', 'average', 'weighted', 'centroid', 'median', 'ward']
"
v-model=
"
cluster.options.method
"
>
v-for=
"value in
params.clusterMethod.validValues
"
v-model=
"
params.clusterMethod.value
"
>
{{
value
}}
</option>
</select>
<select
v-model=
"
cluster.options.metric
"
>
<select
v-model=
"
params.clusterMetric.value
"
>
<option
value=
""
selected
disabled
>
-- Metric --
</option>
<option
:value=
"value"
v-for=
"value in
['euclidean', 'sqeuclidean', 'cityblock', 'correlation', 'cosine']
"
v-model=
"
cluster.options.metric
"
>
v-for=
"value in
params.clusterMetric.validValues
"
v-model=
"
params.clusterMetric.value
"
>
{{
value
}}
</option>
</select>
...
...
@@ -117,17 +57,17 @@
<div
class=
"fjs-cluster-ranges"
>
<label>
<input
type=
"range"
min=
"
1
"
max=
"
20
"
v-model=
"
cluster.options.n_row_c
lusters"
/>
{{
cluster
.
options
.
n_row_c
lusters
}}
Row Clusters
:
min=
"
params.nRowClusters.min
"
:
max=
"
params.nRowClusters.max
"
v-model=
"
params.nRowC
lusters
.value
"
/>
{{
params
.
nRowC
lusters
.
value
}}
Row Clusters
</label>
</div>
<div
class=
"fjs-cluster-ranges"
>
<label>
<input
type=
"range"
min=
"
1
"
max=
"
20
"
v-model=
"
cluster.options.n_col_c
lusters"
/>
{{
cluster
.
options
.
n_col_c
lusters
}}
Col Clusters
:
min=
"
params.nColClusters.min
"
:
max=
"
params.nColClusters.max
"
v-model=
"
params.nColC
lusters
.value
"
/>
{{
params
.
nColC
lusters
.
value
}}
Col Clusters
</label>
</div>
</fieldset>
...
...
@@ -137,17 +77,17 @@
<div
class=
"fjs-cluster-ranges"
>
<label>
<input
type=
"range"
min=
"
1
"
max=
"
20
"
v-model=
"
cluster.options.n_row_c
entroids"
/>
{{
cluster
.
options
.
n_row_c
entroids
}}
Row Centroids
:
min=
"
params.nRowCentroids.min
"
:
max=
"
params.nRowCentroids.max
"
v-model=
"
params.nRowC
entroids
.value
"
/>
{{
params
.
nRowC
entroids
.
value
}}
Row Centroids
</label>
</div>
<div
class=
"fjs-cluster-ranges"
>
<label>
<input
type=
"range"
min=
"
1
"
max=
"
20
"
v-model=
"
cluster.options.n_col_c
entroids"
/>
{{
cluster
.
options
.
n_col_c
entroids
}}
Col Centroids
:
min=
"
params.nColCentroids.min
"
:
max=
"
params.nColCentroids.max
"
v-model=
"
params.nColC
entroids
.value
"
/>
{{
params
.
nColC
entroids
.
value
}}
Col Centroids
</label>
</div>
</fieldset>
...
...
@@ -183,6 +123,7 @@
import
deepFreeze
from
'
deep-freeze-strict
'
import
getHDPICanvas
from
'
../../utils/high-dpi-canvas
'
import
StateSaver
from
'
../mixins/state-saver
'
import
_
from
'
lodash
'
export
default
{
name
:
'
heatmap
'
,
data
()
{
...
...
@@ -191,18 +132,62 @@
height
:
0
,
colorScale
:
d3
.
interpolateCool
,
subsetColors
:
d3
.
schemeCategory10
,
numericArrayDataIds
:
[],
rankingMethod
:
'
mean
'
,
cluster
:
{
algorithm
:
'
hclust
'
,
options
:
{
method
:
''
,
metric
:
''
,
n_row_clusters
:
5
,
n_col_clusters
:
5
,
n_row_centroids
:
5
,
n_col_centroids
:
5
params
:
{
numVars
:
{
type
:
Array
,
elementType
:
String
,
label
:
'
Numerical Variables
'
,
validValues
:
[],
minLength
:
1
,
maxLength
:
Infinity
,
value
:
[]
},
rankingMethod
:
{
type
:
String
,
validValues
:
[],
value
:
'
mean
'
},
clusterAlgorithm
:
{
type
:
String
,
validValues
:
[
'
hclust
'
,
'
kmeans
'
],
value
:
'
hclust
'
},
clusterMethod
:
{
type
:
String
,
validValues
:
[
'
single
'
,
'
complete
'
,
'
average
'
,
'
weighted
'
,
'
centroid
'
,
'
median
'
,
'
ward
'
],
value
:
''
},
clusterMetric
:
{
type
:
String
,
validValues
:
[
'
euclidean
'
,
'
sqeuclidean
'
,
'
cityblock
'
,
'
correlation
'
,
'
cosine
'
],
value
:
''
},
nRowClusters
:
{
type
:
Number
,
min
:
1
,
max
:
20
,
value
:
5
},
nColClusters
:
{
type
:
Number
,
min
:
1
,
max
:
20
,
value
:
5
},
nRowCentroids
:
{
type
:
Number
,
min
:
1
,
max
:
20
,
value
:
5
},
nColCentroids
:
{
type
:
Number
,
min
:
1
,
max
:
20
,
value
:
5
}
},
cluster
:
{
colColors
:
d3
.
schemeCategory10
,
rowColors
:
d3
.
schemeCategory10
.
slice
().
reverse
(),
results
:
{
...
...
@@ -220,13 +205,13 @@
computed
:
{
mainArgs
()
{
return
{
numerical_arrays
:
this
.
numericArrayDataIds
,
numerical_arrays
:
this
.
params
.
numVars
.
value
,
numericals
:
[],
categoricals
:
[],
ranking_method
:
this
.
rankingMethod
,
ranking_method
:
this
.
params
.
rankingMethod
.
value
,
params
:
{},
id_filter
:
this
.
idFilter
.
value
,
max_rows
:
100
,
max_rows
:
100
,
// FIXME: make this configurable
subsets
:
store
.
getters
.
subsets
}
},
...
...
@@ -240,14 +225,14 @@
})
return
{
df
:
df
,
cluster_algo
:
this
.
cluster
.
a
lgorithm
,
cluster_algo
:
this
.
params
.
cluster
A
lgorithm
.
value
,
options
:
{
method
:
this
.
cluster
.
options
.
method
,
metric
:
this
.
cluster
.
options
.
metric
,
n_row_clusters
:
parseInt
(
this
.
cluster
.
options
.
n_row_c
lusters
),
n_col_clusters
:
parseInt
(
this
.
cluster
.
options
.
n_col_c
lusters
),
n_row_centroids
:
parseInt
(
this
.
cluster
.
options
.
n_row_c
entroids
),
n_col_centroids
:
parseInt
(
this
.
cluster
.
options
.
n_col_c
entroids
)
method
:
this
.
params
.
clusterMethod
.
value
,
metric
:
this
.
params
.
clusterMetric
.
value
,
n_row_clusters
:
parseInt
(
this
.
params
.
nRowC
lusters
.
value
),
n_col_clusters
:
parseInt
(
this
.
params
.
nColC
lusters
.
value
),
n_row_centroids
:
parseInt
(
this
.
params
.
nRowC
entroids
.
value
),
n_col_centroids
:
parseInt
(
this
.
params
.
nColC
entroids
.
value
)
}
}
},
...
...
@@ -271,6 +256,15 @@
canvas
()
{
return
getHDPICanvas
(
this
.
padded
.
width
,
this
.
padded
.
height
)
},
statistics
()
{
if
((
this
.
params
.
rankingMethod
.
value
===
'
limma
'
)
&&
(
store
.
getters
.
subsets
.
length
===
2
))
{
return
[
'
logFC
'
,
'
P.Value
'
,
'
feature
'
,
'
AveExpr
'
,
'
t
'
,
'
adj.P.Val
'
,
'
B
'
]
}
else
if
((
this
.
params
.
rankingMethod
.
value
===
'
limma
'
)
&&
(
store
.
getters
.
subsets
.
length
>
2
))
{
return
[
'
F
'
,
'
P.Value
'
,
'
feature
'
,
'
AveExpr
'
,
'
adj.P.Val
'
]
}
else
{
throw
new
Error
(
`Unknown ranking method:
${
this
.
params
.
rankingMethod
.
value
}
`
)
}
},
cols
()
{
let
cols
=
[]
if
(
this
.
cluster
.
results
.
cols
.
length
)
{
...
...
@@ -415,13 +409,13 @@
sigBars
()
{
return
this
.
results
.
stats
.
feature
.
map
((
d
,
i
)
=>
{
return
{
x
:
-
this
.
sigScales
.
x
(
this
.
results
.
stats
[
this
.
rankingMethod
][
i
]),
x
:
-
this
.
sigScales
.
x
(
this
.
results
.
stats
[
this
.
params
.
rankingMethod
.
value
][
i
]),
y
:
this
.
sigScales
.
y
(
d
),
width
:
this
.
sigScales
.
x
(
this
.
results
.
stats
[
this
.
rankingMethod
][
i
]),
width
:
this
.
sigScales
.
x
(
this
.
results
.
stats
[
this
.
params
.
rankingMethod
.
value
][
i
]),