Skip to content
This repository has been archived by the owner on Sep 18, 2024. It is now read-only.

Support nested experiment more friendly #2554

Merged
merged 5 commits into from
Jun 22, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/webui/src/components/Modals/Compare.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import IntermediateVal from '../public-child/IntermediateVal';
import { TRIALS } from '../../static/datamodel';
import { contentStyles, iconButtonStyles } from '../Buttons/ModalTheme';
import '../../static/style/compare.scss';
import { TableRecord, Intermedia, TooltipForIntermediate } from '../../static/interface'; // eslint-disable-line no-unused-vars
import { TableRecord, Intermedia, TooltipForIntermediate } from '../../static/interface';

// the modal of trial compare
interface CompareProps {
Expand Down
2 changes: 1 addition & 1 deletion src/webui/src/components/trial-detail/Duration.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import ReactEcharts from 'echarts-for-react';
import { TableObj, EventMap } from '../../static/interface'; // eslint-disable-line no-unused-vars
import { TableObj, EventMap } from '../../static/interface';
import { filterDuration, convertDuration } from '../../static/function';
import 'echarts/lib/chart/bar';
import 'echarts/lib/component/tooltip';
Expand Down
170 changes: 105 additions & 65 deletions src/webui/src/components/trial-detail/Para.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import * as React from 'react';
import ReactEcharts from 'echarts-for-react';
import { filterByStatus } from '../../static/function';
import { EXPERIMENT } from '../../static/datamodel';
import { Stack, PrimaryButton, Dropdown, IDropdownOption, } from 'office-ui-fabric-react'; // eslint-disable-line no-unused-vars
import { ParaObj, Dimobj, TableObj } from '../../static/interface'; // eslint-disable-line no-unused-vars
import { Stack, PrimaryButton, Dropdown, IDropdownOption } from 'office-ui-fabric-react';
import { ParaObj, Dimobj, TableObj } from '../../static/interface';
import 'echarts/lib/chart/parallel';
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/title';
Expand All @@ -28,6 +28,8 @@ interface ParaState {
// office-fabric-ui
selectedItem?: { key: string | number | undefined }; // percent Selector
swapyAxis?: string[]; // yAxis Selector
paraYdataNested: number[][];
isNested: false;
}

interface ParaProps {
Expand Down Expand Up @@ -68,7 +70,9 @@ class Para extends React.Component<ParaProps, ParaState> {
succeedRenderCount: 10000000,
clickCounts: 1,
isLoadConfirm: false,
swapyAxis: []
swapyAxis: [],
paraYdataNested: [],
isNested: false
};
}

Expand All @@ -79,23 +83,30 @@ class Para extends React.Component<ParaProps, ParaState> {
lengthofTrials: number
): void => {
// get data for every lines. if dim is choice type, number -> toString()
const paraYdata: number[][] = [];
Object.keys(eachTrialParams).map(item => {
const temp: number[] = [];
for (let i = 0; i < dimName.length; i++) {
if ('type' in parallelAxis[i]) {
temp.push(eachTrialParams[item][dimName[i]].toString());
} else {
// default metric
temp.push(eachTrialParams[item][dimName[i]]);
let paraYdata: number[][] = [];
const { isNested } = this.state;
if (isNested === false) {
Object.keys(eachTrialParams).map(item => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for ... of loop should be prefered if the return value is not used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. foreach(item => ... is also better

const temp: number[] = [];
for (let i = 0; i < dimName.length; i++) {
// if ('type' in parallelAxis[i]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unused comments here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok,

if (parallelAxis[i].type === 'category') {
temp.push(eachTrialParams[item][dimName[i]].toString());
} else {
// default metric
temp.push(eachTrialParams[item][dimName[i]]);
}
}
}
paraYdata.push(temp);
});
paraYdata.push(temp);
});
} else {
paraYdata = this.state.paraYdataNested;
}
// add acc
Object.keys(paraYdata).map(item => {
paraYdata[item].push(accPara[item]);
});

// according acc to sort ydata // sort to find top percent dataset
if (paraYdata.length !== 0) {
const len = paraYdata[0].length - 1;
Expand Down Expand Up @@ -133,7 +144,7 @@ class Para extends React.Component<ParaProps, ParaState> {
const lenOfDataSource: number = dataSource.length;
const accPara: number[] = [];
// specific value array
const eachTrialParams: string[] = [];
const eachTrialParams: Array<any> = [];
// experiment interface search space obj
const searchRange = searchSpace !== undefined ? JSON.parse(searchSpace) : '';
// nest search space
Expand All @@ -144,13 +155,15 @@ class Para extends React.Component<ParaProps, ParaState> {
return;
}
});
const dimName = Object.keys(searchRange);
this.setState({ dimName: dimName });

let dimName: string[] = [];
const parallelAxis: Array<Dimobj> = [];
// search space range and specific value [only number]
let i = 0;
const yAxisOrderList = new Map();
this.setState({ isNested: isNested });
if (isNested === false) {
dimName = Object.keys(searchRange);
this.setState({ dimName: dimName });
for (i; i < dimName.length; i++) {
const data: string[] = [];
const searchKey = searchRange[dimName[i]];
Expand Down Expand Up @@ -223,37 +236,25 @@ class Para extends React.Component<ParaProps, ParaState> {
}
}
} else {
for (i; i < dimName.length; i++) {
const searchKey = searchRange[dimName[i]];
const data: string[] = [];
let j = 0;
switch (searchKey._type) {
case 'choice':
for (j; j < searchKey._value.length; j++) {
const item = searchKey._value[j];
Object.keys(item).map(key => {
if (key !== '_name' && key !== '_type') {
Object.keys(item[key]).map(index => {
if (index !== '_type') {
const realChoice = item[key][index];
Object.keys(realChoice).map(m => {
data.push(`${item._name}_${realChoice[m]}`);
});
}
});
}
});
for (const parallelAxisName in searchRange) {
const data: any[] = [];
dimName.push(parallelAxisName);

for (const choiceItem in searchRange[parallelAxisName]) {
if (choiceItem === '_value') {
for (const item in searchRange[parallelAxisName][choiceItem]) {
data.push(searchRange[parallelAxisName][choiceItem][item]._name);
}
data.push('null');
yAxisOrderList.set(parallelAxisName, JSON.parse(JSON.stringify(data)));
parallelAxis.push({
dim: i,
name: dimName[i],
type: 'category',
data: data,
name: parallelAxisName,
type: 'category',
boundaryGap: true,
axisLine: {
lineStyle: {
type: 'dotted', // axis type,solid dashed dotted
type: 'dotted', // axis type,soliddasheddotted
width: 1
}
},
Expand All @@ -266,16 +267,44 @@ class Para extends React.Component<ParaProps, ParaState> {
show: true,
interval: 0,
// rotate: 30
},
});
break;
default:
parallelAxis.push({
dim: i,
name: dimName[i]
}
});
i++;
for (const item in searchRange[parallelAxisName][choiceItem]) {
for (const key in searchRange[parallelAxisName][choiceItem][item]) {
if (key !== '_name') {
dimName.push(key);
parallelAxis.push({
dim: i,
data: searchRange[parallelAxisName][choiceItem][item][key]._value.concat('null'),
name: `${searchRange[parallelAxisName][choiceItem][item]._name}_${key}`,
type: 'category',
boundaryGap: true,
axisLine: {
lineStyle: {
type: 'dotted', // axis type,solid,dashed,dotted
width: 1
}
},
axisTick: {
show: true,
interval: 0,
alignWithLabel: true,
},
axisLabel: {
show: true,
interval: 0,
// rotate: 30
}
});
i++;
}
}
}
}
}
}
this.setState({ dimName: dimName });
}
parallelAxis.push({
dim: i,
Expand All @@ -291,6 +320,7 @@ class Para extends React.Component<ParaProps, ParaState> {
tooltip: {
trigger: 'item'
},

parallel: {
parallelAxisDefault: {
tooltip: {
Expand Down Expand Up @@ -332,7 +362,7 @@ class Para extends React.Component<ParaProps, ParaState> {
} else {
Object.keys(dataSource).map(item => {
const trial = dataSource[item];
eachTrialParams.push(trial.description.parameters || '');
eachTrialParams.push(trial.description.parameters);
// may be a succeed trial hasn't final result
// all detail page may be break down if havn't if
if (trial.acc !== undefined) {
Expand All @@ -341,22 +371,32 @@ class Para extends React.Component<ParaProps, ParaState> {
}
}
});
// nested search space, deal data
// nested search space, fill all yAxis data
if (isNested !== false) {
eachTrialParams.forEach(element => {
Object.keys(element).forEach(key => {
const item = element[key];
if (typeof item === 'object') {
Object.keys(item).forEach(index => {
if (index !== '_name') {
element[key] = `${item._name}_${item[index]}`;
} else {
element[key] = 'null';
const renderDataSource: Array<any> = [];
for (const i in eachTrialParams) {
const eachTrialData: Array<any> = [];
for (const m in eachTrialParams[i]) {
for (const n in yAxisOrderList.get(m)) {
if (yAxisOrderList.get(m)[n] === eachTrialParams[i][m]._name) {
for (const index in eachTrialParams[i][m]) {
if (index !== '_name') {
eachTrialData.push(eachTrialParams[i][m][index].toString());
}
if (eachTrialParams[i][m][index] === 'Empty') {
eachTrialData.push('Empty');
}
}
});
} else if (yAxisOrderList.get(m)[n] === 'Empty') {
eachTrialData.push(eachTrialParams[i][m]._name.toString());
} else {
eachTrialData.push('null');
}
}
});
});
}
renderDataSource.push(eachTrialData);
}
this.setState({ paraYdataNested: renderDataSource });
}
// if not return final result
const maxVal = accPara.length === 0 ? 1 : Math.max(...accPara);
Expand Down Expand Up @@ -592,7 +632,7 @@ class Para extends React.Component<ParaProps, ParaState> {
}

componentDidUpdate(prevProps: ParaProps): void {
if(this.props.dataSource !== prevProps.dataSource) {
if (this.props.dataSource !== prevProps.dataSource) {
const { dataSource, expSearchSpace, whichGraph } = this.props;
if (whichGraph === 'Hyper-parameter') {
this.hyperParaPic(dataSource, expSearchSpace);
Expand Down