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> ...@@ -378,7 +378,7 @@ class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState>
{/* trial table list */} {/* trial table list */}
<Title1 text="Trial jobs" icon="6.png" /> <Title1 text="Trial jobs" icon="6.png" />
<Row className="allList"> <Row className="allList">
<Col span={12}> <Col span={10}>
<span>Show</span> <span>Show</span>
<Select <Select
className="entry" className="entry"
...@@ -392,26 +392,28 @@ class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState> ...@@ -392,26 +392,28 @@ class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState>
</Select> </Select>
<span>entries</span> <span>entries</span>
</Col> </Col>
<Col span={12} className="right"> <Col span={14} className="right">
<Row> <Button
<Col span={12}> type="primary"
<Button className="tableButton editStyle"
type="primary" onClick={this.tableList ? this.tableList.addColumn : this.test}
className="tableButton editStyle" >
onClick={this.tableList ? this.tableList.addColumn : this.test} Add column
> </Button>
Add column <Button
</Button> type="primary"
</Col> className="tableButton editStyle mediateBtn"
<Col span={12}> // use child-component tableList's function, the function is in child-component.
<Input onClick={this.tableList ? this.tableList.compareBtn : this.test}
type="text" >
placeholder="Search by id, trial No. or status" Compare
onChange={this.searchTrial} </Button>
style={{ width: 230, marginLeft: 6 }} <Input
/> type="text"
</Col> placeholder="Search by id, trial No. or status"
</Row> onChange={this.searchTrial}
style={{ width: 230, marginLeft: 6 }}
/>
</Col> </Col>
</Row> </Row>
<TableList <TableList
......
import * as React from 'react'; import * as React from 'react';
import { Row, Col, Button, Switch } from 'antd'; 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'; import ReactEcharts from 'echarts-for-react';
require('echarts/lib/component/tooltip'); require('echarts/lib/component/tooltip');
require('echarts/lib/component/title'); 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 { interface IntermediateState {
detailSource: Array<TableObj>; detailSource: Array<TableObj>;
interSource: object; interSource: object;
......
...@@ -7,6 +7,7 @@ import { MANAGER_IP, trialJobStatus, COLUMN, COLUMN_INDEX } from '../../static/c ...@@ -7,6 +7,7 @@ import { MANAGER_IP, trialJobStatus, COLUMN, COLUMN_INDEX } from '../../static/c
import { convertDuration, intermediateGraphOption, killJob } from '../../static/function'; import { convertDuration, intermediateGraphOption, killJob } from '../../static/function';
import { TableObj, TrialJob } from '../../static/interface'; import { TableObj, TrialJob } from '../../static/interface';
import OpenRow from '../public-child/OpenRow'; import OpenRow from '../public-child/OpenRow';
import Compare from '../Modal/Compare';
import IntermediateVal from '../public-child/IntermediateVal'; // table default metric column import IntermediateVal from '../public-child/IntermediateVal'; // table default metric column
import '../../static/style/search.scss'; import '../../static/style/search.scss';
require('../../static/style/tableStatus.css'); require('../../static/style/tableStatus.css');
...@@ -38,6 +39,9 @@ interface TableListState { ...@@ -38,6 +39,9 @@ interface TableListState {
isObjFinal: boolean; isObjFinal: boolean;
isShowColumn: boolean; isShowColumn: boolean;
columnSelected: Array<string>; // user select columnKeys columnSelected: Array<string>; // user select columnKeys
selectRows: Array<TableObj>;
isShowCompareModal: boolean;
selectedRowKeys: string[] | number[];
} }
interface ColumnIndex { interface ColumnIndex {
...@@ -50,6 +54,7 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -50,6 +54,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
public _isMounted = false; public _isMounted = false;
public intervalTrialLog = 10; public intervalTrialLog = 10;
public _trialId: string; public _trialId: string;
public tables: Table<TableObj> | null;
constructor(props: TableListProps) { constructor(props: TableListProps) {
super(props); super(props);
...@@ -59,7 +64,10 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -59,7 +64,10 @@ class TableList extends React.Component<TableListProps, TableListState> {
modalVisible: false, modalVisible: false,
isObjFinal: false, isObjFinal: false,
isShowColumn: 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> { ...@@ -71,7 +79,8 @@ class TableList extends React.Component<TableListProps, TableListState> {
.then(res => { .then(res => {
if (res.status === 200) { if (res.status === 200) {
const intermediateArr: number[] = []; 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 => { Object.keys(res.data).map(item => {
const temp = JSON.parse(res.data[item].data); const temp = JSON.parse(res.data[item].data);
if (typeof temp === 'object') { if (typeof temp === 'object') {
...@@ -184,6 +193,31 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -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() { componentDidMount() {
this._isMounted = true; this._isMounted = true;
} }
...@@ -195,7 +229,14 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -195,7 +229,14 @@ class TableList extends React.Component<TableListProps, TableListState> {
render() { render() {
const { entries, tableSource, updateList } = this.props; 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 showTitle = COLUMN;
let bgColor = ''; let bgColor = '';
const trialJob: Array<TrialJob> = []; const trialJob: Array<TrialJob> = [];
...@@ -417,7 +458,9 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -417,7 +458,9 @@ class TableList extends React.Component<TableListProps, TableListState> {
<Row className="tableList"> <Row className="tableList">
<div id="tableList"> <div id="tableList">
<Table <Table
ref={(table: Table<TableObj> | null) => this.tables = table}
columns={showColumn} columns={showColumn}
rowSelection={rowSelection}
expandedRowRender={this.openRow} expandedRowRender={this.openRow}
dataSource={tableSource} dataSource={tableSource}
className="commonTableStyle" className="commonTableStyle"
...@@ -458,6 +501,7 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -458,6 +501,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
className="titleColumn" className="titleColumn"
/> />
</Modal> </Modal>
<Compare compareRows={selectRows} visible={isShowCompareModal} cancelFunc={this.hideCompareModal} />
</Row> </Row>
); );
} }
......
...@@ -108,10 +108,15 @@ interface FinalResult { ...@@ -108,10 +108,15 @@ interface FinalResult {
data: string; data: string;
} }
interface Intermedia {
name: string; // id
type: string;
data: Array<number | object>; // intermediate data
hyperPara: object; // each trial hyperpara value
}
export { export {
TableObj, Parameters, Experiment, TableObj, Parameters, Experiment, AccurPoint, TrialNumber, TrialJob,
AccurPoint, TrialNumber, TrialJob, DetailAccurPoint, TooltipForAccuracy, ParaObj, Dimobj, FinalResult, FinalType,
DetailAccurPoint, TooltipForAccuracy, TooltipForIntermediate, SearchSpace, Intermedia
ParaObj, Dimobj, FinalResult, FinalType,
TooltipForIntermediate, SearchSpace
}; };
.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{ .allList{
width: 96%; width: 96%;
margin: 0 auto; margin: 0 auto;
...@@ -31,4 +31,7 @@ ...@@ -31,4 +31,7 @@
} }
} }
Button.mediateBtn{
margin: 0 32px;
}
...@@ -102,3 +102,8 @@ ...@@ -102,3 +102,8 @@
.ant-modal-title{ .ant-modal-title{
font-size: 20px; 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