Commit f9fc3d01 authored by Lijiao's avatar Lijiao Committed by Yan Ni
Browse files

Trial compare (#1190)

* Trial compare

* delete chinese notes
parent 150ee83a
import * as React from 'react';
import { Row, Modal } from 'antd';
import ReactEcharts from 'echarts-for-react';
import IntermediateVal from '../public-child/IntermediateVal';
import '../../static/style/compare.scss';
import { TableObj, Intermedia, TooltipForIntermediate } from 'src/static/interface';
// the modal of trial compare
interface CompareProps {
compareRows: Array<TableObj>;
visible: boolean;
cancelFunc: () => void;
}
class Compare extends React.Component<CompareProps, {}> {
public _isCompareMount: boolean;
constructor(props: CompareProps) {
super(props);
}
intermediate = () => {
const { compareRows } = this.props;
const trialIntermediate: Array<Intermedia> = [];
const idsList: Array<string> = [];
Object.keys(compareRows).map(item => {
const temp = compareRows[item];
trialIntermediate.push({
name: temp.id,
data: temp.description.intermediate,
type: 'line',
hyperPara: temp.description.parameters
});
idsList.push(temp.id);
});
// find max intermediate number
trialIntermediate.sort((a, b) => { return (b.data.length - a.data.length); });
const legend: Array<string> = [];
// max length
const length = trialIntermediate[0] !== undefined ? trialIntermediate[0].data.length : 0;
const xAxis: Array<number> = [];
Object.keys(trialIntermediate).map(item => {
const temp = trialIntermediate[item];
legend.push(temp.name);
});
for (let i = 1; i <= length; i++) {
xAxis.push(i);
}
const option = {
tooltip: {
trigger: 'item',
enterable: true,
position: function (point: Array<number>, data: TooltipForIntermediate) {
if (data.dataIndex < length / 2) {
return [point[0], 80];
} else {
return [point[0] - 300, 80];
}
},
formatter: function (data: TooltipForIntermediate) {
const trialId = data.seriesName;
let obj = {};
const temp = trialIntermediate.find(key => key.name === trialId);
if (temp !== undefined) {
obj = temp.hyperPara;
}
return '<div class="tooldetailAccuracy">' +
'<div>Trial ID: ' + trialId + '</div>' +
'<div>Intermediate: ' + data.data + '</div>' +
'<div>Parameters: ' +
'<pre>' + JSON.stringify(obj, null, 4) + '</pre>' +
'</div>' +
'</div>';
}
},
grid: {
left: '5%',
top: 40,
containLabel: true
},
legend: {
data: idsList
},
xAxis: {
type: 'category',
name: 'Step',
boundaryGap: false,
data: xAxis
},
yAxis: {
type: 'value',
name: 'metric'
},
series: trialIntermediate
};
return (
<ReactEcharts
option={option}
style={{ width: '100%', height: 418, margin: '0 auto' }}
notMerge={true} // update now
/>
);
}
// render table column ---
initColumn = () => {
const { compareRows } = this.props;
const idList: Array<string> = [];
const durationList: Array<number> = [];
const parameterList: Array<object> = [];
let parameterKeys: Array<string> = [];
if (compareRows.length !== 0) {
parameterKeys = Object.keys(compareRows[0].description.parameters);
}
Object.keys(compareRows).map(item => {
const temp = compareRows[item];
idList.push(temp.id);
durationList.push(temp.duration);
parameterList.push(temp.description.parameters);
});
return (
<table className="compare">
<tbody>
<tr>
<td />
{Object.keys(idList).map(key => {
return (
<td className="value" key={key}>{idList[key]}</td>
);
})}
</tr>
<tr>
<td className="column">Default metric</td>
{Object.keys(compareRows).map(index => {
const temp = compareRows[index];
return (
<td className="value" key={index}>
<IntermediateVal record={temp}/>
</td>
);
})}
</tr>
<tr>
<td className="column">duration</td>
{Object.keys(durationList).map(index => {
return (
<td className="value" key={index}>{durationList[index]}</td>
);
})}
</tr>
{
Object.keys(parameterKeys).map(index => {
return (
<tr key={index}>
<td className="column" key={index}>{parameterKeys[index]}</td>
{
Object.keys(parameterList).map(key => {
return (
<td key={key} className="value">
{parameterList[key][parameterKeys[index]]}
</td>
);
})
}
</tr>
);
})
}
</tbody>
</table>
);
}
componentDidMount() {
this._isCompareMount = true;
}
componentWillUnmount() {
this._isCompareMount = false;
}
render() {
const { visible, cancelFunc } = this.props;
return (
<Modal
title="Compare trials"
visible={visible}
onCancel={cancelFunc}
footer={null}
destroyOnClose={true}
maskClosable={false}
width="90%"
>
<Row>{this.intermediate()}</Row>
<Row>{this.initColumn()}</Row>
</Modal>
);
}
}
export default Compare;
......@@ -378,7 +378,7 @@ class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState>
{/* trial table list */}
<Title1 text="Trial jobs" icon="6.png" />
<Row className="allList">
<Col span={12}>
<Col span={10}>
<span>Show</span>
<Select
className="entry"
......@@ -392,9 +392,7 @@ class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState>
</Select>
<span>entries</span>
</Col>
<Col span={12} className="right">
<Row>
<Col span={12}>
<Col span={14} className="right">
<Button
type="primary"
className="tableButton editStyle"
......@@ -402,8 +400,14 @@ class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState>
>
Add column
</Button>
</Col>
<Col span={12}>
<Button
type="primary"
className="tableButton editStyle mediateBtn"
// use child-component tableList's function, the function is in child-component.
onClick={this.tableList ? this.tableList.compareBtn : this.test}
>
Compare
</Button>
<Input
type="text"
placeholder="Search by id, trial No. or status"
......@@ -412,8 +416,6 @@ class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState>
/>
</Col>
</Row>
</Col>
</Row>
<TableList
entries={entriesTable}
tableSource={source}
......
import * as React from 'react';
import { Row, Col, Button, Switch } from 'antd';
import { TooltipForIntermediate, TableObj } from '../../static/interface';
import { TooltipForIntermediate, TableObj, Intermedia } from '../../static/interface';
import ReactEcharts from 'echarts-for-react';
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
interface Intermedia {
name: string; // id
type: string;
data: Array<number | object>; // intermediate data
hyperPara: object; // each trial hyperpara value
}
interface IntermediateState {
detailSource: Array<TableObj>;
interSource: object;
......
......@@ -7,6 +7,7 @@ import { MANAGER_IP, trialJobStatus, COLUMN, COLUMN_INDEX } from '../../static/c
import { convertDuration, intermediateGraphOption, killJob } from '../../static/function';
import { TableObj, TrialJob } from '../../static/interface';
import OpenRow from '../public-child/OpenRow';
import Compare from '../Modal/Compare';
import IntermediateVal from '../public-child/IntermediateVal'; // table default metric column
import '../../static/style/search.scss';
require('../../static/style/tableStatus.css');
......@@ -38,6 +39,9 @@ interface TableListState {
isObjFinal: boolean;
isShowColumn: boolean;
columnSelected: Array<string>; // user select columnKeys
selectRows: Array<TableObj>;
isShowCompareModal: boolean;
selectedRowKeys: string[] | number[];
}
interface ColumnIndex {
......@@ -50,6 +54,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
public _isMounted = false;
public intervalTrialLog = 10;
public _trialId: string;
public tables: Table<TableObj> | null;
constructor(props: TableListProps) {
super(props);
......@@ -59,7 +64,10 @@ class TableList extends React.Component<TableListProps, TableListState> {
modalVisible: false,
isObjFinal: false,
isShowColumn: false,
columnSelected: COLUMN
isShowCompareModal: false,
columnSelected: COLUMN,
selectRows: [],
selectedRowKeys: [] // after modal closed 清掉选择的痕迹
};
}
......@@ -71,7 +79,8 @@ class TableList extends React.Component<TableListProps, TableListState> {
.then(res => {
if (res.status === 200) {
const intermediateArr: number[] = [];
// support intermediate result is dict
// support intermediate result is dict because the last intermediate result is
// final result in a succeed trial, it may be a dict.
Object.keys(res.data).map(item => {
const temp = JSON.parse(res.data[item].data);
if (typeof temp === 'object') {
......@@ -184,6 +193,31 @@ class TableList extends React.Component<TableListProps, TableListState> {
);
}
fillSelectedRowsTostate = (selected: number[] | string[], selectedRows: Array<TableObj>) => {
if (this._isMounted === true) {
this.setState(() => ({ selectRows: selectedRows, selectedRowKeys: selected }));
}
}
// open Compare-modal
compareBtn = () => {
const { selectRows } = this.state;
if (selectRows.length === 0) {
alert('Please select datas you want to compare!');
} else {
if (this._isMounted === true) {
this.setState({ isShowCompareModal: true });
}
}
}
// close Compare-modal
hideCompareModal = () => {
// close modal. clear select rows data, clear selected track
if (this._isMounted) {
this.setState({ isShowCompareModal: false, selectedRowKeys: [], selectRows: [] });
}
}
componentDidMount() {
this._isMounted = true;
}
......@@ -195,7 +229,14 @@ class TableList extends React.Component<TableListProps, TableListState> {
render() {
const { entries, tableSource, updateList } = this.props;
const { intermediateOption, modalVisible, isShowColumn, columnSelected } = this.state;
const { intermediateOption, modalVisible, isShowColumn, columnSelected,
selectRows, isShowCompareModal, selectedRowKeys } = this.state;
const rowSelection = {
selectedRowKeys: selectedRowKeys,
onChange: (selected: string[] | number[], selectedRows: Array<TableObj>) => {
this.fillSelectedRowsTostate(selected, selectedRows);
}
};
let showTitle = COLUMN;
let bgColor = '';
const trialJob: Array<TrialJob> = [];
......@@ -417,7 +458,9 @@ class TableList extends React.Component<TableListProps, TableListState> {
<Row className="tableList">
<div id="tableList">
<Table
ref={(table: Table<TableObj> | null) => this.tables = table}
columns={showColumn}
rowSelection={rowSelection}
expandedRowRender={this.openRow}
dataSource={tableSource}
className="commonTableStyle"
......@@ -458,6 +501,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
className="titleColumn"
/>
</Modal>
<Compare compareRows={selectRows} visible={isShowCompareModal} cancelFunc={this.hideCompareModal} />
</Row>
);
}
......
......@@ -108,10 +108,15 @@ interface FinalResult {
data: string;
}
interface Intermedia {
name: string; // id
type: string;
data: Array<number | object>; // intermediate data
hyperPara: object; // each trial hyperpara value
}
export {
TableObj, Parameters, Experiment,
AccurPoint, TrialNumber, TrialJob,
DetailAccurPoint, TooltipForAccuracy,
ParaObj, Dimobj, FinalResult, FinalType,
TooltipForIntermediate, SearchSpace
TableObj, Parameters, Experiment, AccurPoint, TrialNumber, TrialJob,
DetailAccurPoint, TooltipForAccuracy, ParaObj, Dimobj, FinalResult, FinalType,
TooltipForIntermediate, SearchSpace, Intermedia
};
.compare{
width: 92%;
margin: 0 auto;
color: #333;
tr{
line-height: 30px;
border-bottom: 1px solid #ccc;
}
.column{
width: 124px;
padding-left: 18px;
font-weight: 700;
}
.value{
width: 152px;
padding-right: 18px;
text-align: right;
}
}
/* some buttons about trial-detail table */
/* some buttons in trial-detail table */
.allList{
width: 96%;
margin: 0 auto;
......@@ -31,4 +31,7 @@
}
}
Button.mediateBtn{
margin: 0 32px;
}
......@@ -102,3 +102,8 @@
.ant-modal-title{
font-size: 20px;
}
/*disable select all checkbox in detail page*/
.ant-table-selection{
display: none;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment