-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
186 additions
and
118 deletions.
There are no files selected for viewing
61 changes: 61 additions & 0 deletions
61
app/javascript/optim_viewer/components/MonoObjOptimPlotter.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* eslint-disable max-classes-per-file */ | ||
import React from 'react'; | ||
import Plot from 'react-plotly.js'; | ||
import PropTypes from 'prop-types'; | ||
|
||
class MonoObjOptimPlotter extends React.PureComponent { | ||
static makeTrace(y, name) { | ||
const trace = { | ||
x: Array.from({ length: y.length }, (_, i) => i + 1), | ||
y, | ||
type: 'scatter', | ||
mode: 'markers+lines', | ||
}; | ||
trace.name = name; | ||
return trace; | ||
} | ||
|
||
render() { | ||
const { | ||
data, | ||
} = this.props; | ||
|
||
let plot_data = []; | ||
if (data.length === 1) { | ||
for (let i = 0; i < data[0].inputs.x[0].length; i += 1) { | ||
const trace = MonoObjOptimPlotter.makeTrace(data[0].inputs.x.map((z) => z[i]), `x${i + 1}`); | ||
plot_data.push(trace); | ||
} | ||
for (let i = 0; i < data[0].inputs.y[0].length; i += 1) { | ||
let label = `cstr${i + 2 - data[0].config.cstr_specs.length}`; | ||
if (i < data[0].config.n_obj) { | ||
label = `obj${i + 1}`; | ||
} | ||
const trace = MonoObjOptimPlotter.makeTrace(data[0].inputs.y.map((z) => z[i]), label); | ||
plot_data.push(trace); | ||
} | ||
} else { | ||
for (let d = 0; d < data.length; d += 1) { | ||
for (let i = 0; i < data[d].config.n_obj; i += 1) { | ||
const trace = MonoObjOptimPlotter.makeTrace(data[d].inputs.y.map((z) => z[i]), `serie#${d + 1} obj`); | ||
plot_data.push(trace); | ||
} | ||
} | ||
} | ||
|
||
const layout = { | ||
width: 800, | ||
height: 500, | ||
title: 'Data Points', | ||
xaxis: { title: '# Evaluations' }, | ||
yaxis: { title: 'Values' }, | ||
}; | ||
|
||
return (<Plot data={plot_data} layout={layout} />); | ||
} | ||
} | ||
|
||
MonoObjOptimPlotter.propTypes = { | ||
data: PropTypes.array.isRequired, | ||
}; | ||
export default MonoObjOptimPlotter; |
113 changes: 113 additions & 0 deletions
113
app/javascript/optim_viewer/components/MultiObjOptimPlotter.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* eslint-disable max-classes-per-file */ | ||
import React from 'react'; | ||
import Plot from 'react-plotly.js'; | ||
import PropTypes from 'prop-types'; | ||
|
||
const COLORMAP = ['#ff7f0e', '#1f77b4', '#2ca02c', '#d62728']; | ||
const SYMBOLS = ['circle', 'triangle-up', 'diamond', 'x']; | ||
|
||
class MultiObjOptimViewer extends React.PureComponent { | ||
render() { | ||
const { data } = this.props; | ||
const plot_data = []; | ||
const layout = {}; | ||
|
||
const { n_obj } = data[0].config; | ||
|
||
const pdh = 1.0 / n_obj; | ||
const pdv = 1.0 / n_obj; | ||
|
||
for (let d = 0; d < data.length; d += 1) { | ||
for (let i = 0; i < n_obj; i += 1) { | ||
for (let j = 0; j < n_obj; j += 1) { | ||
const xlabel = `obj${j + 1}`; | ||
const ylabel = `obj${i + 1}`; | ||
|
||
let x = []; | ||
let y = []; | ||
const n_val = data[d].inputs.y.length; | ||
|
||
if (i === j) { | ||
x = Array.from({ length: n_val }, (_, n) => n + 1); | ||
y = data[d].inputs.y.map((yrow) => yrow[i]); | ||
} else { | ||
for (let k = 0; k < n_val; k += 1) { | ||
x.push(data[d].inputs.y[k][j]); | ||
y.push(data[d].inputs.y[k][i]); | ||
} | ||
} | ||
const trace = { | ||
x, | ||
y, | ||
type: 'scatter', | ||
mode: i === j ? 'marker+lines' : 'markers', | ||
}; | ||
const n = n_obj * i + j + 1; | ||
const xname = `x${n}`; | ||
const yname = `y${n}`; | ||
trace.xaxis = xname; | ||
trace.yaxis = yname; | ||
if (i === j) { | ||
trace.name = `${ylabel} values`; | ||
} else { | ||
trace.name = `${ylabel} vs ${xlabel}`; | ||
} | ||
if (data.length > 1) { | ||
trace.name = `serie#${d + 1} ${trace.name}`; | ||
} | ||
trace.marker = { | ||
color: data.length > 1 ? COLORMAP[d] : COLORMAP[1], | ||
symbol: SYMBOLS[0], | ||
}; | ||
|
||
layout[`xaxis${n}`] = { domain: [(j + 0.1) * pdh, (j + 0.9) * pdh], anchor: yname }; | ||
layout[`yaxis${n}`] = { domain: [(i + 0.1) * pdv, (i + 0.9) * pdv], anchor: xname }; | ||
if (j === 0) { | ||
layout[`yaxis${n}`].title = ylabel; | ||
} | ||
if (i === 0) { | ||
layout[`xaxis${n}`].title = xlabel; | ||
} | ||
plot_data.push(trace); | ||
|
||
if (i !== j && data[d].outputs.y_best) { | ||
const n_val_pareto = data[d].outputs.y_best.length; | ||
const xp = []; | ||
const yp = []; | ||
for (let k = 0; k < n_val_pareto; k += 1) { | ||
xp.push(data[d].outputs.y_best[k][j]); | ||
yp.push(data[d].outputs.y_best[k][i]); | ||
} | ||
const trace2 = { | ||
x: xp, | ||
y: yp, | ||
type: 'scatter', | ||
mode: 'markers', | ||
}; | ||
trace2.xaxis = xname; | ||
trace2.yaxis = yname; | ||
trace2.name = `Pareto ${ylabel} vs ${xlabel}`; | ||
if (data.length > 1) { | ||
trace2.name = `serie#${d + 1} ${trace2.name}` | ||
} | ||
trace2.marker = { | ||
color: COLORMAP[d], | ||
symbol: SYMBOLS[1], | ||
}; | ||
plot_data.push(trace2); | ||
} | ||
} | ||
} | ||
} | ||
layout.width = n_obj * 250 + 500; | ||
layout.height = n_obj * 250 + 100; | ||
layout.title = 'Optim history and Pareto fronts'; | ||
|
||
return (<Plot data={plot_data} layout={layout} />); | ||
} | ||
} | ||
|
||
MultiObjOptimViewer.propTypes = { | ||
data: PropTypes.array.isRequired, | ||
}; | ||
export default MultiObjOptimViewer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,140 +1,34 @@ | ||
/* eslint-disable max-classes-per-file */ | ||
import React from 'react'; | ||
import Plot from 'react-plotly.js'; | ||
import PropTypes from 'prop-types'; | ||
|
||
// const COLORS = [ | ||
// '#1f77b4', // muted blue | ||
// '#ff7f0e', // safety orange | ||
// '#2ca02c', // cooked asparagus green | ||
// '#d62728', // brick red | ||
// '#9467bd', // muted purple | ||
// '#8c564b', // chestnut brown | ||
// '#e377c2', // raspberry yogurt pink | ||
// '#7f7f7f', // middle gray | ||
// '#bcbd22', // curry yellow - green | ||
// '#17becf' // blue - teal | ||
// ]; | ||
import MonoObjOptimPlotter from 'optim_viewer/components/MonoObjOptimPlotter'; | ||
import MultiObjOptimPlotter from 'optim_viewer/components/MultiObjOptimPlotter'; | ||
|
||
class OptimViewer extends React.PureComponent { | ||
constructor(props) { | ||
super(props); | ||
const { | ||
data, | ||
type, | ||
} = this.props; | ||
this.input_list = []; | ||
|
||
if (data[0].inputs.y) { | ||
if (data[0].config.n_obj === 1) { | ||
if (type === 'single') { | ||
if (data[0].inputs.x) { | ||
for (let i = 0; i < data[0].inputs.x[0].length; i += 1) { | ||
this.addInputPlot(data[0].inputs.x, i, `input ${i + 1}`); | ||
} | ||
for (let i = 0; i < data[0].inputs.y[0].length; i += 1) { | ||
this.addInputPlot(data[0].inputs.y, i, `output ${i + 1}`); | ||
} | ||
} | ||
} else { | ||
for (let i = 0; i < data.length; i += 1) { | ||
if (data[i].inputs.x) { | ||
this.addInputPlot(data[i].inputs.y, 0, `output of #${data[i].id}`); | ||
} | ||
} | ||
} | ||
} else if (type === 'single') { | ||
if (data[0].inputs.y) { | ||
this.addParetoPlot(data[0].inputs.y, 'History'); | ||
} | ||
if (data[0].outputs.y_best) { | ||
this.addParetoPlot(data[0].outputs.y_best, 'Approx Pareto front'); | ||
} | ||
} else { | ||
for (let i = 0; i < data.length; i += 1) { | ||
if (data[i].inputs.y) { | ||
this.addParetoPlot(data[i].inputs.y, `#${data[i].id}`); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
addInputPlot(x, n, name) { | ||
this.input_list.push({ | ||
x: Array.from({ length: x.length }, (_, i) => i + 1), | ||
y: x.map((z) => z[n]), | ||
type: 'scatter', | ||
mode: 'markers lines', | ||
name, | ||
}); | ||
} | ||
|
||
addParetoPlot(y, name) { | ||
this.input_list.push({ | ||
x: y.map((z) => z[0]), | ||
y: y.map((z) => z[1]), | ||
type: 'scatter', | ||
mode: 'markers', | ||
name, | ||
}); | ||
} | ||
|
||
render() { | ||
const { | ||
data, | ||
} = this.props; | ||
if (this.input_list.length === 0) { | ||
const { data } = this.props; | ||
if (data.length === 0) { | ||
return ( | ||
<div className="alert alert-primary mt-5 mb-5" role="alert"> | ||
No data! Optimization not run yet? | ||
</div> | ||
); | ||
} | ||
|
||
let viewer = <MultiObjOptimPlotter data={data} />; | ||
if (data[0].config.n_obj === 1) { | ||
return ( | ||
<div className="container"> | ||
<div className="row"> | ||
<div className="col-sm"> | ||
<Plot | ||
data={this.input_list} | ||
layout={{ | ||
width: 800, | ||
height: 500, | ||
title: 'Data Points', | ||
xaxis: { title: '# Evaluations' }, | ||
yaxis: { title: 'Values' }, | ||
}} | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
viewer = <MonoObjOptimPlotter data={data} />; | ||
} | ||
|
||
return ( | ||
<div className="container"> | ||
<div className="row"> | ||
<div className="col-sm"> | ||
<Plot | ||
data={this.input_list} | ||
layout={{ | ||
width: 800, | ||
height: 500, | ||
title: 'Pareto front', | ||
xaxis: { title: 'y1' }, | ||
yaxis: { title: 'y2' }, | ||
}} | ||
/> | ||
</div> | ||
</div> | ||
<div> | ||
{ viewer } | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
OptimViewer.propTypes = { | ||
data: PropTypes.array.isRequired, | ||
type: PropTypes.string.isRequired, | ||
}; | ||
export default OptimViewer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters