Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
openmole
Visu Playground
Commits
0124c972
Commit
0124c972
authored
Sep 23, 2021
by
Mathieu Leclaire
Browse files
Add Matthias vizualization work
parent
3f216f85
Changes
21
Expand all
Hide whitespace changes
Inline
Side-by-side
build.sbt
View file @
0124c972
...
...
@@ -11,7 +11,7 @@ val laminarVersion = "0.12.2"
val
scaladgetVersion
=
"1.9.0"
val
scalajsDomVersion
=
"1.1.0"
val
scalatagsVersion
=
"0.9.4"
val
plotlyVersion
=
"1.5.
6
"
val
plotlyVersion
=
"1.5.
8-SNAPSHOT
"
val
openmoleVersion
=
"14.0-SNAPSHOT"
lazy
val
shared
=
project
.
in
(
file
(
"shared"
))
settings
(
...
...
client/src/main/scala/
fr/iscpif/
client/Client.scala
→
client/src/main/scala/client/Client.scala
View file @
0124c972
...
...
@@ -22,21 +22,27 @@ object App {
val
method
=
Var
(
""
)
val
experiment
=
Var
(
""
)
val
convergencePlot
=
Var
(
div
())
val
paretoPlot
=
Var
(
div
())
lazy
val
d
=
div
(
h3
(
child
.
text
<--
experiment
.
signal
),
h4
(
child
.
text
<--
method
.
signal
.
map
{
m
=>
s
"with the method $m"
}),
child
<--
convergencePlot
.
signal
div
(
child
<--
convergencePlot
.
signal
),
div
(
child
<--
paretoPlot
.
signal
)
)
Post
[
shared.Api
].
convergence
().
call
().
foreach
{
c
=>
convergencePlot
.
set
(
NSGA2
.
convergence
(
c
))
convergencePlot
.
set
(
Plot
.
convergence
(
c
))
}
Post
[
shared.Api
].
metadata
().
call
().
foreach
{
m
=>
setMetadata
(
m
.
OMRData
)
}
Post
[
shared.Api
].
lastGeneration
().
call
().
foreach
{
lg
=>
lg
.
map
{
gen
=>
paretoPlot
.
set
(
Plot
.
pareto
(
gen
))}.
getOrElse
(
div
(
"Nothing to be ploted"
))
}
def
setMetadata
(
omrData
:
OMROutputFormat.OMRData
)
=
{
method
.
set
(
omrData
.
method
)
experiment
.
set
(
s
"${omrData.fileName} - ${omrData.version}"
)
...
...
client/src/main/scala/
fr/iscpif/
client/
NSGA2
.scala
→
client/src/main/scala/client/
Plot
.scala
View file @
0124c972
...
...
@@ -4,12 +4,16 @@ import org.openmole.plotlyjs._
import
org.openmole.plotlyjs.all._
import
scala.scalajs.js.JSConverters.
{
iterableOnceConvertible2JSRichIterableOnce
,
_
}
import
org.openmole.plugin.method.evolution.data.AnalysisData
import
org.openmole.plotlyjs.PlotlyImplicits._
import
com.raquo.laminar.api.L._
import
plotlyjs.demo.homemade.api.Data.
{
Input
,
Outcome
,
Output
}
import
plotlyjs.demo.homemade.api.Pareto.
{
Minimization
,
ParetoDisplay
,
ParetoObjective
}
import
plotlyjs.demo.homemade.pareto.Pareto
import
scala.scalajs._
object
NSGA2
{
object
Plot
{
def
convergence
(
convergence
:
org.openmole.plugin.method.evolution.data.AnalysisData.Convergence
)
=
{
val
plotDiv
=
div
()
...
...
@@ -23,8 +27,8 @@ object NSGA2 {
val
data
=
linechart
.
lines
val
(
generations
,
hypervolume
)
=
convergence
match
{
case
st
:
org.openmole.plugin.method.evolution.data.
AnalysisData.StochasticNSGA2.Convergence
=>
st
.
generations
.
map
{
gs
=>
(
gs
.
generation
.
toString
,
gs
.
hypervolume
.
getOrElse
(
0.0
))}.
unzip
case
n
:
org.openmole.plugin.method.evolution.data.
AnalysisData.NSGA2.Convergence
=>
n
.
generations
.
map
{
gs
=>
(
gs
.
generation
.
toString
,
gs
.
hypervolume
.
getOrElse
(
0.0
))}.
unzip
case
st
:
AnalysisData.StochasticNSGA2.Convergence
=>
st
.
generations
.
map
{
gs
=>
(
gs
.
generation
.
toString
,
gs
.
hypervolume
.
getOrElse
(
0.0
))}.
unzip
case
n
:
AnalysisData.NSGA2.Convergence
=>
n
.
generations
.
map
{
gs
=>
(
gs
.
generation
.
toString
,
gs
.
hypervolume
.
getOrElse
(
0.0
))}.
unzip
}
val
dataRef
=
data
...
...
@@ -41,4 +45,32 @@ object NSGA2 {
plotDiv
}
def
pareto
(
paretoGeneration
:
AnalysisData.Generation
)
=
{
val
(
objective
,
generation
,
genome
)
=
paretoGeneration
match
{
case
st
:
AnalysisData.StochasticNSGA2.Generation
=>
(
st
.
objective
,
st
.
generation
,
st
.
genome
)
case
n
:
AnalysisData.NSGA2.Generation
=>
(
n
.
objective
,
n
.
generation
,
n
.
genome
)
}
println
(
"OBJ"
)
objective
.
foreach
{
println
}
// println("GENOME")
// genome.foreach{println}
// println("PARETO " + objective.head)
objective
match
{
case
sto
:
Vector
[
AnalysisData.StochasticNSGA2.Objective
]
=>
val
outcomes
=
genome
.
transpose
.
zip
(
sto
.
map
{
_
.
objectives
})
println
(
"STOCHASTIC ... "
+
sto
)
Pareto
.
plot
(
Seq
(
"o1"
,
"o2"
,
"o3"
).
map
{
o
=>
ParetoObjective
(
o
,
Minimization
)},
outcomes
.
map
{
case
(
i
,
o
)
=>
println
(
"I size "
+
i
.
size
+
" // "
+
i
)
println
(
"O size "
+
o
.
size
+
" // "
+
o
)
Outcome
(
i
.
map
{
ii
=>
Input
(
"??"
,
ii
.
toDouble
)},
o
.
map
{
oo
=>
Output
(
"???"
,
oo
.
toDouble
)})},
ParetoDisplay
(
800
,
showPath
=
true
)
)
case
n
:
AnalysisData.NSGA2.Objective
=>
div
(
"stochastic"
)
}
}
}
\ No newline at end of file
client/src/main/scala/
fr/iscpif/
client/Utils.scala
→
client/src/main/scala/client/Utils.scala
View file @
0124c972
File moved
client/src/main/scala/homemade/api/Data.scala
0 → 100644
View file @
0124c972
package
plotlyjs.demo.homemade.api
object
Data
{
case
class
Input
(
name
:
String
,
value
:
Double
)
case
class
Output
(
name
:
String
,
value
:
Double
)
case
class
Outcome
(
inputs
:
Seq
[
Input
],
outputs
:
Seq
[
Output
],
samples
:
Option
[
Int
]
=
None
)
}
client/src/main/scala/homemade/api/PSE.scala
0 → 100644
View file @
0124c972
package
plotlyjs.demo.homemade.api
import
com.raquo.laminar.nodes.ReactiveHtmlElement
import
org.scalajs.dom.html.Div
import
plotlyjs.demo.homemade.api.Data.Outcome
import
plotlyjs.demo.homemade.pse.PSE.plotAPI
object
PSE
{
case
class
PSEDimension
(
name
:
String
,
bounds
:
Seq
[
Double
])
case
class
PSEDisplay
(
size
:
Int
)
def
pse
(
dimensions
:
Seq
[
PSEDimension
],
outcomes
:
Seq
[
Outcome
],
pseDisplay
:
PSEDisplay
)
:
ReactiveHtmlElement
[
Div
]
=
plotAPI
(
dimensions
,
outcomes
,
pseDisplay
)
}
client/src/main/scala/homemade/api/Pareto.scala
0 → 100644
View file @
0124c972
package
plotlyjs.demo.homemade.api
import
com.raquo.laminar.nodes.ReactiveHtmlElement
import
org.scalajs.dom.html.Div
import
plotlyjs.demo.homemade.api.Data.Outcome
import
plotlyjs.demo.homemade.pareto.Pareto.plotAPI
object
Pareto
{
trait
OptimizationType
object
Maximization
extends
OptimizationType
object
Minimization
extends
OptimizationType
case
class
ParetoObjective
(
name
:
String
,
optimizationType
:
OptimizationType
)
case
class
ParetoDisplay
(
size
:
Int
,
showPath
:
Boolean
=
false
)
def
pareto
(
objectives
:
Seq
[
ParetoObjective
],
outcomes
:
Seq
[
Outcome
],
paretoDisplay
:
ParetoDisplay
)
:
ReactiveHtmlElement
[
Div
]
=
plotAPI
(
objectives
,
outcomes
,
paretoDisplay
)
}
client/src/main/scala/homemade/pareto/Pareto.scala
0 → 100644
View file @
0124c972
This diff is collapsed.
Click to expand it.
client/src/main/scala/homemade/pareto/PointPlotter.scala
0 → 100644
View file @
0124c972
package
plotlyjs.demo.homemade.pareto
import
plotlyjs.demo.homemade.api.Pareto.
{
Maximization
,
Minimization
,
OptimizationType
}
import
plotlyjs.demo.homemade.pareto.PointPlotter._
import
plotlyjs.demo.homemade.utils.Vectors._
case
class
PointPlotter
(
optimizationTypes
:
Seq
[
OptimizationType
],
outputs
:
Seq
[
Vector
],
betterPlot
:
BetterPlot
)
{
val
plotOutputs
:
Seq
[
Vector
]
=
{
val
orientations
=
optimizationTypes
.
map
((
_
,
betterPlot
)).
map
{
case
(
Minimization
,
BetterPlot
.
IsLower
)
|
(
Maximization
,
BetterPlot
.
IsHigher
)
=>
1.0
case
(
Minimization
,
BetterPlot
.
IsHigher
)
|
(
Maximization
,
BetterPlot
.
IsLower
)
=>
-
1.0
}
val
orientedOutputs
=
outputs
.
map
(
_
.
mul
(
orientations
))
val
min
=
orientedOutputs
.
transpose
.
map
(
_
.
min
)
val
max
=
orientedOutputs
.
transpose
.
map
(
_
.
max
)
orientedOutputs
.
map
(
_
.
zipWithIndex
.
map
{
case
(
c
,
i
)
=>
(
c
-
min
(
i
))/(
max
(
i
)
-
min
(
i
))
})
}
}
object
PointPlotter
{
class
BetterPlot
object
BetterPlot
{
object
IsLower
extends
BetterPlot
//TODO delete
object
IsHigher
extends
BetterPlot
}
}
client/src/main/scala/homemade/pareto/SnowflakeBasis.scala
0 → 100644
View file @
0124c972
package
plotlyjs.demo.homemade.pareto
import
plotlyjs.demo.homemade.pareto.SnowflakeBasis.cartesianFromPolar
import
plotlyjs.demo.homemade.utils.Basis
import
plotlyjs.demo.homemade.utils.Vectors._
import
scala.math.
{
atan2
,
cos
,
sin
}
class
SnowflakeBasis
(
dimension
:
Int
)
extends
Basis
{
override
val
size
:
Int
=
dimension
override
def
basisVector
(
i
:
Int
)
:
Vector
=
{
if
(
dimension
==
2
)
{
i
match
{
case
0
=>
cartesianFromPolar
(
Seq
(
1
,
0
))
case
1
=>
cartesianFromPolar
(
Seq
(
1
,
90
))
}
}
else
{
cartesianFromPolar
(
Seq
(
1
,
360
*
i
/
dimension
))
}
}
}
object
SnowflakeBasis
{
class
PolarVector
(
vector
:
Vector
)
extends
Vector
{
override
def
apply
(
i
:
Int
)
:
Double
=
vector
.
apply
(
i
)
override
def
length
:
Int
=
vector
.
length
override
def
iterator
:
Iterator
[
Double
]
=
vector
.
iterator
val
radius
:
Double
=
vector
(
0
)
val
angle
:
Double
=
vector
(
1
)
}
def
polarFromCartesian
(
vector
:
Vector
)
:
PolarVector
=
{
val
radius
=
vector
.
norm
val
x
=
vector
(
0
)
val
y
=
vector
(
1
)
val
angle
=
atan2
(
y
,
x
).
toDegrees
new
PolarVector
(
Seq
(
radius
,
angle
))
}
class
CartesianVector
(
vector
:
Vector
)
extends
Vector
{
override
def
apply
(
i
:
Int
)
:
Double
=
vector
.
apply
(
i
)
override
def
length
:
Int
=
vector
.
length
override
def
iterator
:
Iterator
[
Double
]
=
vector
.
iterator
val
x
:
Double
=
vector
(
0
)
val
y
:
Double
=
vector
(
1
)
}
def
cartesianFromPolar
(
vector
:
Vector
)
:
CartesianVector
=
{
val
radius
=
vector
(
0
)
val
theta
=
vector
(
1
).
toRadians
val
x
=
radius
*
cos
(
theta
)
val
y
=
radius
*
sin
(
theta
)
new
CartesianVector
(
Seq
(
x
,
y
))
}
}
client/src/main/scala/homemade/pse/MultiScaleBasis.scala
0 → 100644
View file @
0124c972
package
plotlyjs.demo.homemade.pse
import
plotlyjs.demo.homemade.utils.Basis
import
plotlyjs.demo.homemade.utils.Vectors._
case
class
MultiScaleBasis
(
sourceDimension
:
Int
,
subdivisions
:
Seq
[
Int
],
destinationDimension
:
Int
,
allowStretch
:
Boolean
=
false
)
extends
Basis
{
val
remainder
:
Int
=
sourceDimension
%
destinationDimension
val
stretchable
:
Boolean
=
remainder
!=
0
val
stretched
:
Boolean
=
allowStretch
&&
stretchable
def
axisIndex
(
i
:
Int
)
:
Int
=
{
i
%
destinationDimension
}
def
scaleIndex
(
i
:
Int
)
:
Int
=
{
i
/
destinationDimension
}
def
axis
(
i
:
Int
)
:
Int
=
{
axisIndex
(
i
)
}
def
scale
(
i
:
Int
)
:
Double
=
{
var
iSubScale
=
i
var
scaleFactor
=
1
var
valid
=
true
while
(
valid
)
{
iSubScale
-=
destinationDimension
if
(
iSubScale
>=
0
)
{
scaleFactor
*=
(
subdivisions
(
iSubScale
)
+
1
)
}
else
{
valid
=
false
}
}
scaleFactor
}
val
maxScaleIndex
:
Int
=
scaleIndex
(
sourceDimension
-
1
)
override
val
size
:
Int
=
sourceDimension
override
def
basisVector
(
i
:
Int
)
:
Vector
=
{
(
0.0
at
destinationDimension
).
replace
(
axis
(
i
),
1.0
)
*
scale
(
i
)
}
override
def
transform
(
vector
:
Vector
)
:
Vector
=
{
if
((
destinationDimension
until
sourceDimension
).
map
(
vector
(
_
).
isWhole
).
reduceOption
(
_
&&
_
).
getOrElse
(
true
))
{
super
.
transform
(
vector
)
}
else
{
throw
new
IllegalArgumentException
(
s
"Coordinates from index $destinationDimension until $sourceDimension must be whole."
)
}
}
def
totalSize
(
i
:
Int
)
:
Double
=
{
val
maxParallel
=
sourceDimension
-
1
-
((
sourceDimension
-
1
-
i
)
%
destinationDimension
)
(
basisVector
(
maxParallel
)
*
subdivisions
(
i
)).
norm
}
def
size
(
destinationAxis
:
Int
)
:
Double
=
{
for
(
i
<-
0
until
sourceDimension
)
{
if
(
axis
(
i
)
==
destinationAxis
)
{
return
totalSize
(
i
)
}
}
-
1
}
}
client/src/main/scala/homemade/pse/PSE.scala
0 → 100644
View file @
0124c972
This diff is collapsed.
Click to expand it.
client/src/main/scala/homemade/utils/Basis.scala
0 → 100644
View file @
0124c972
package
plotlyjs.demo.homemade.utils
import
plotlyjs.demo.homemade.utils.Vectors._
trait
Basis
{
val
size
:
Int
def
basisVector
(
i
:
Int
)
:
Vector
def
component
(
vector
:
Vector
,
i
:
Int
)
:
Vector
=
{
vector
(
i
)
*
basisVector
(
i
)
}
def
transform
(
vector
:
Vector
)
:
Vector
=
{
(
0
until
size
).
map
(
component
(
vector
,
_
)).
reduce
(
_
+
_
)
}
}
client/src/main/scala/homemade/utils/IntVectors.scala
0 → 100644
View file @
0124c972
package
plotlyjs.demo.homemade.utils
import
plotlyjs.demo.homemade.utils.Vectors._
import
scala.language.implicitConversions
import
scala.math._
object
IntVectors
{
type
IntVector
=
Seq
[
Int
]
implicit
class
ImplicitIntVector
(
intVector
:
IntVector
)
{
def
vector
:
Vector
=
intVector
.
map
(
_
.
toDouble
)
def
intVectorToString
:
String
=
"("
+
intVector
.
mkString
(
", "
)
+
")"
}
implicit
def
implicitToVector
(
i
:
IntVector
)
:
Vector
=
i
.
map
(
_
.
toDouble
)
implicit
def
toIntVector
(
v
:
Vector
)
:
IntVector
=
v
.
map
(
rint
(
_
).
toInt
)
def
vectorIndices
(
sizes
:
Seq
[
Int
])
:
Iterable
[
IntVector
]
=
{
if
(
sizes
.
isEmpty
)
{
new
Iterable
[
IntVector
]
{
override
def
iterator
:
Iterator
[
IntVector
]
=
new
Iterator
[
IntVector
]
{
override
def
hasNext
:
Boolean
=
false
override
def
next
()
:
IntVector
=
???
}
}
}
else
{
new
Iterable
[
IntVector
]
{
override
def
iterator
:
Iterator
[
IntVector
]
=
new
Iterator
[
IntVector
]
{
private
val
dimension
=
sizes
.
size
private
val
totalCount
=
sizes
.
product
private
val
pointGenerator
=
sizes
.
map
(
_
-
1
).
toArray
//Array.fill[Int](dimension)(_size - 1)
private
var
count
=
0
override
def
hasNext
:
Boolean
=
count
<
totalCount
override
def
next
()
:
IntVector
=
{
pointGenerator
(
0
)
+=
1
for
(
i
<-
0
until
dimension
if
pointGenerator
(
i
)
==
sizes
(
i
))
{
pointGenerator
(
i
)
=
0
if
(
i
+
1
<
dimension
)
pointGenerator
(
i
+
1
)
+=
1
}
count
=
count
+
1
pointGenerator
}
}
}.
view
}
}
def
positiveNCube
(
dimension
:
Int
,
p
:
Int
)
:
Iterable
[
IntVector
]
=
{
if
(
dimension
==
0
)
{
new
Iterable
[
IntVector
]
{
override
def
iterator
:
Iterator
[
IntVector
]
=
new
Iterator
[
IntVector
]
{
override
def
hasNext
:
Boolean
=
false
override
def
next
()
:
IntVector
=
???
}
}
}
else
{
new
Iterable
[
IntVector
]
{
override
def
iterator
:
Iterator
[
IntVector
]
=
new
Iterator
[
IntVector
]
{
private
val
pointGenerator
=
Array
.
fill
[
Int
](
dimension
)(
p
-
1
)
private
var
count
=
0
override
def
hasNext
:
Boolean
=
count
<
pow
(
p
,
dimension
)
override
def
next
()
:
IntVector
=
{
pointGenerator
(
0
)
+=
1
for
(
i
<-
0
until
dimension
if
pointGenerator
(
i
)
==
p
)
{
pointGenerator
(
i
)
=
0
if
(
i
+
1
<
dimension
)
pointGenerator
(
i
+
1
)
+=
1
}
count
=
count
+
1
pointGenerator
.
toSeq
}
}
}.
view
}
}
def
centeredNCube
(
dimension
:
Int
,
radius
:
Int
)
:
Iterable
[
IntVector
]
=
{
positiveNCube
(
dimension
,
2
*
radius
+
1
).
map
(
_
.
vector
.
sub
(
radius
.
toDouble
))
}
}
client/src/main/scala/homemade/utils/ParetoFrontGenerator.scala
0 → 100644
View file @
0124c972
package
plotlyjs.demo.homemade.utils
import
plotlyjs.demo.homemade.utils.Vectors._
object
ParetoFrontGenerator
{
def
random
(
dimension
:
Int
,
size
:
Int
)
:
Seq
[
Vector
]
=
{
var
front
=
Seq
[
Vector
]()
def
compareToFront
(
v
:
Vector
)
:
Double
=
ParetoFrontGenerator
.
compareToFront
(
front
,
v
)
def
stepTowardFront
(
s
:
Double
,
v
:
Vector
)
:
Vector
=
{
v
+
front
.
flatMap
(
_
.
zip
(
v
).
map
({
case
(
_c
,
c
)
=>
_c
-
c
})).
filter
(
math
.
signum
(
_
)
==
s
).
minBy
(
math
.
abs
)
}
def
frontBounds
(
v
:
Vector
)
:
(
Vector
,
Vector
)
=
{
val
comparison
=
compareToFront
(
v
)
if
(
comparison
==
0
)
{
(
stepTowardFront
(-
1
,
v
),
stepTowardFront
(+
1
,
v
))
}
else
{
val
direction
=
-
comparison
var
vPrevious
=
v
var
vNext
=
v
while
(
compareToFront
((
vPrevious
+
vNext
)
/
2
)
!=
0
)
{
vPrevious
=
vNext
vNext
=
stepTowardFront
(
direction
,
vPrevious
)
}
if
(
direction
>
0
)
(
vPrevious
,
vNext
)
else
(
vNext
,
vPrevious
)
}
}
front
=
front
++
(
0
until
dimension
).
map
((
0
at
dimension
).
replace
(
_
,
1
))
for
(
_
<-
1
to
size
)
{
val
(
v1
,
v2
)
=
frontBounds
((()
=>
math
.
random
())
at
dimension
)
val
epsilon
=
10
E
-
4
val
alpha
=
epsilon
+
math
.
random
()
*
(
1
-
epsilon
)
val
v
=
(
1
-
alpha
)
*
v1
+
alpha
*
v2
front
=
front
:+
v
}
front
=
front
.
drop
(
dimension
)
assert
(
front
.
map
(
compareToFront
(
_
)
==
0
).
reduce
(
_
&&
_
))
front
}
def
compare
(
v1
:
Vector
,
v2
:
Vector
)
:
Double
=
{
(
v1
-
v2
).
map
(
math
.
signum
).
filterNot
(
_
==
0
).
reduceOption
((
s1
,
s2
)
=>
if
(
s1
==
s2
)
s1
else
0
).
getOrElse
(
0
)
}
def
compareToFront
(
front
:
Seq
[
Vector
],
v
:
Vector
)
:
Double
=
{
front
.
map
(
compare
(
v
,
_
)).
filterNot
(
_
==
0
).
headOption
.
getOrElse
(
0
)
}
}
client/src/main/scala/homemade/utils/Utils.scala
0 → 100644
View file @
0124c972
package
plotlyjs.demo.homemade.utils
import
com.raquo.laminar.nodes.ReactiveHtmlElement
import
org.openmole.plotlyjs.
{
PlotData
,
Plotly
}
import
org.scalajs.dom.html
import
plotlyjs.demo.homemade.utils.Utils.ExtraTraceManager.ExtraTracesRef
import
plotlyjs.demo.homemade.utils.Vectors._
import
scala.math.
{
ceil
,
random
}
import
scala.scalajs.js.JSConverters._
object
Utils
{
def
printCode
[
T
](
sc
:
sourcecode.Text
[
T
])(
implicit
line
:
sourcecode.Line
,
file
:
sourcecode.File
)
:
T
=
{
println
(
file
.
value
+
":"
+
line
.
value
+
" "
+
sc
.
source
+
" = "
+
sc
.
value
)
sc
.
value
}
def
randomizeDimensions
(
seq
:
Seq
[
Vector
])
:
Seq
[
Vector
]
=
{
seq
.
headOption
.
map
(
head
=>
{
val
dimension
=
head
.
dimension
val
mulVector
=
(()
=>
ceil
(
10
*
random
))
at
dimension
val
addVector
=
(()
=>
10
*
random
-
5
)
at
dimension
seq
.
map
(
_
.
mul
(
mulVector
))
.
map
(
_
.
add
(
addVector
))
}).
getOrElse
(
Seq
[
Vector
]())
}
class
SkipOnBusy
{
private
var
busy
=
false
def
skipOnBusy
(
name
:
String
,
f
:
()
=>
Unit
)
:
Unit
=
{
if
(!
busy
)
{
busy
=
true
//println(name + "...")
f
()
//println(name + ".")
busy
=
false
}
else
{
//println(name + " skipped")
}
}
}
class
ExtraTraceManager
(
plotDiv
:
ReactiveHtmlElement
[
html.Div
],
initialTraceCount
:
Int
)
{
private
var
extraSize
=
0
private
var
refs
=
Seq
[
ExtraTracesRef
]()
def
addTraces
(
plotDataSeq
:
Seq
[
PlotData
])
:
ExtraTracesRef
=
{
refs
=
refs
:+
new
ExtraTracesRef
(
extraSize
,
extraSize
+
plotDataSeq
.
size
)
Plotly
.
addTraces
(
plotDiv
.
ref
,
plotDataSeq
.
map
(
Option
(
_
).
orUndefined
).
toJSArray
)
extraSize
=
refs
.
last
.
to
refs
.
last
}
def
deleteTraces
(
ref
:
ExtraTracesRef
)
:
Unit
=
{
val
size
=
ref
.
size
Plotly
.
deleteTraces
(
plotDiv
.
ref
,
(
ref
.
from
until
ref
.
to
)
.
map
(
_
+
initialTraceCount
)
.
map
(
_
.
toDouble
)
.
toJSArray
)
extraSize
-=
size
refs
=
refs
.
filterNot
(
_
==
ref
)
refs
.
filter
(
ref
.
to
<=
_
.
from
)
.
foreach
{
nextRef
=>
nextRef
.
from
-=
size
nextRef
.
to
-=
size
}
}
def
deleteAllTraces
()
:
Unit
=
{
Plotly
.
deleteTraces
(