Unverified Commit 12410686 authored by chicm-ms's avatar chicm-ms Committed by GitHub
Browse files

Merge pull request #20 from microsoft/master

pull code
parents 611a45fc 61fec446
...@@ -67,7 +67,7 @@ def get_next_parameter(): ...@@ -67,7 +67,7 @@ def get_next_parameter():
params_file_name = 'parameter.cfg' params_file_name = 'parameter.cfg'
else: else:
raise AssertionError('_param_index value ({}) should >=0'.format(_param_index)) raise AssertionError('_param_index value ({}) should >=0'.format(_param_index))
params_filepath = os.path.join(_sysdir, params_file_name) params_filepath = os.path.join(_sysdir, params_file_name)
if not os.path.isfile(params_filepath): if not os.path.isfile(params_filepath):
request_next_parameter() request_next_parameter()
...@@ -81,11 +81,11 @@ def get_next_parameter(): ...@@ -81,11 +81,11 @@ def get_next_parameter():
def send_metric(string): def send_metric(string):
if _nni_platform != 'local': if _nni_platform != 'local':
data = (string).encode('utf8') data = (string).encode('utf8')
assert len(data) < 1000000, 'Metric too long' assert len(data) < 1000000, 'Metric too long'
print('NNISDK_ME%s' % (data), flush=True) print('NNISDK_ME%s' % (data), flush=True)
else: else:
data = (string + '\n').encode('utf8') data = (string + '\n').encode('utf8')
assert len(data) < 1000000, 'Metric too long' assert len(data) < 1000000, 'Metric too long'
_metric_file.write(b'ME%06d%b' % (len(data), data)) _metric_file.write(b'ME%06d%b' % (len(data), data))
_metric_file.flush() _metric_file.flush()
if sys.platform == "win32": if sys.platform == "win32":
......
...@@ -24,12 +24,12 @@ import numpy as np ...@@ -24,12 +24,12 @@ import numpy as np
def get_json_content(file_path): def get_json_content(file_path):
"""Load json file content """Load json file content
Parameters Parameters
---------- ----------
file_path: file_path:
path to the file path to the file
Raises Raises
------ ------
TypeError TypeError
...@@ -43,9 +43,9 @@ def get_json_content(file_path): ...@@ -43,9 +43,9 @@ def get_json_content(file_path):
return None return None
def generate_pcs(nni_search_space_content): def generate_pcs(nni_search_space_content):
"""Generate the Parameter Configuration Space (PCS) which defines the """Generate the Parameter Configuration Space (PCS) which defines the
legal ranges of the parameters to be optimized and their default values. legal ranges of the parameters to be optimized and their default values.
Generally, the format is: Generally, the format is:
# parameter_name categorical {value_1, ..., value_N} [default value] # parameter_name categorical {value_1, ..., value_N} [default value]
# parameter_name ordinal {value_1, ..., value_N} [default value] # parameter_name ordinal {value_1, ..., value_N} [default value]
...@@ -53,14 +53,14 @@ def generate_pcs(nni_search_space_content): ...@@ -53,14 +53,14 @@ def generate_pcs(nni_search_space_content):
# parameter_name integer [min_value, max_value] [default value] log # parameter_name integer [min_value, max_value] [default value] log
# parameter_name real [min_value, max_value] [default value] # parameter_name real [min_value, max_value] [default value]
# parameter_name real [min_value, max_value] [default value] log # parameter_name real [min_value, max_value] [default value] log
Reference: https://automl.github.io/SMAC3/stable/options.html Reference: https://automl.github.io/SMAC3/stable/options.html
Parameters Parameters
---------- ----------
nni_search_space_content: search_space nni_search_space_content: search_space
The search space in this experiment in nni The search space in this experiment in nni
Returns Returns
------- -------
Parameter Configuration Space (PCS) Parameter Configuration Space (PCS)
...@@ -81,8 +81,8 @@ def generate_pcs(nni_search_space_content): ...@@ -81,8 +81,8 @@ def generate_pcs(nni_search_space_content):
if search_space[key]['_type'] == 'choice': if search_space[key]['_type'] == 'choice':
choice_len = len(search_space[key]['_value']) choice_len = len(search_space[key]['_value'])
pcs_fd.write('%s categorical {%s} [%s]\n' % ( pcs_fd.write('%s categorical {%s} [%s]\n' % (
key, key,
json.dumps(list(range(choice_len)))[1:-1], json.dumps(list(range(choice_len)))[1:-1],
json.dumps(0))) json.dumps(0)))
if key in categorical_dict: if key in categorical_dict:
raise RuntimeError('%s has already existed, please make sure search space has no duplicate key.' % key) raise RuntimeError('%s has already existed, please make sure search space has no duplicate key.' % key)
...@@ -90,19 +90,19 @@ def generate_pcs(nni_search_space_content): ...@@ -90,19 +90,19 @@ def generate_pcs(nni_search_space_content):
elif search_space[key]['_type'] == 'randint': elif search_space[key]['_type'] == 'randint':
# TODO: support lower bound in randint # TODO: support lower bound in randint
pcs_fd.write('%s integer [0, %d] [%d]\n' % ( pcs_fd.write('%s integer [0, %d] [%d]\n' % (
key, key,
search_space[key]['_value'][0], search_space[key]['_value'][0],
search_space[key]['_value'][0])) search_space[key]['_value'][0]))
elif search_space[key]['_type'] == 'uniform': elif search_space[key]['_type'] == 'uniform':
pcs_fd.write('%s real %s [%s]\n' % ( pcs_fd.write('%s real %s [%s]\n' % (
key, key,
json.dumps(search_space[key]['_value']), json.dumps(search_space[key]['_value']),
json.dumps(search_space[key]['_value'][0]))) json.dumps(search_space[key]['_value'][0])))
elif search_space[key]['_type'] == 'loguniform': elif search_space[key]['_type'] == 'loguniform':
# use np.round here to ensure that the rounded defaut value is in the range, which will be rounded in configure_space package # use np.round here to ensure that the rounded defaut value is in the range, which will be rounded in configure_space package
search_space[key]['_value'] = list(np.round(np.log(search_space[key]['_value']), 10)) search_space[key]['_value'] = list(np.round(np.log(search_space[key]['_value']), 10))
pcs_fd.write('%s real %s [%s]\n' % ( pcs_fd.write('%s real %s [%s]\n' % (
key, key,
json.dumps(search_space[key]['_value']), json.dumps(search_space[key]['_value']),
json.dumps(search_space[key]['_value'][0]))) json.dumps(search_space[key]['_value'][0])))
elif search_space[key]['_type'] == 'quniform' \ elif search_space[key]['_type'] == 'quniform' \
...@@ -122,9 +122,9 @@ def generate_pcs(nni_search_space_content): ...@@ -122,9 +122,9 @@ def generate_pcs(nni_search_space_content):
return None return None
def generate_scenario(ss_content): def generate_scenario(ss_content):
"""Generate the scenario. The scenario-object (smac.scenario.scenario.Scenario) is used to configure SMAC and """Generate the scenario. The scenario-object (smac.scenario.scenario.Scenario) is used to configure SMAC and
can be constructed either by providing an actual scenario-object, or by specifing the options in a scenario file. can be constructed either by providing an actual scenario-object, or by specifing the options in a scenario file.
Reference: https://automl.github.io/SMAC3/stable/options.html Reference: https://automl.github.io/SMAC3/stable/options.html
The format of the scenario file is one option per line: The format of the scenario file is one option per line:
...@@ -135,7 +135,7 @@ def generate_scenario(ss_content): ...@@ -135,7 +135,7 @@ def generate_scenario(ss_content):
Parameters Parameters
---------- ----------
abort_on_first_run_crash: bool abort_on_first_run_crash: bool
If true, SMAC will abort if the first run of the target algorithm crashes. Default: True, If true, SMAC will abort if the first run of the target algorithm crashes. Default: True,
because trials reported to nni tuner would always in success state because trials reported to nni tuner would always in success state
algo: function algo: function
Specifies the target algorithm call that SMAC will optimize. Interpreted as a bash-command. Specifies the target algorithm call that SMAC will optimize. Interpreted as a bash-command.
......
...@@ -64,7 +64,7 @@ class SMACTuner(Tuner): ...@@ -64,7 +64,7 @@ class SMACTuner(Tuner):
def _main_cli(self): def _main_cli(self):
"""Main function of SMAC for CLI interface """Main function of SMAC for CLI interface
Returns Returns
------- -------
instance instance
...@@ -153,7 +153,7 @@ class SMACTuner(Tuner): ...@@ -153,7 +153,7 @@ class SMACTuner(Tuner):
def receive_trial_result(self, parameter_id, parameters, value): def receive_trial_result(self, parameter_id, parameters, value):
"""receive_trial_result """receive_trial_result
Parameters Parameters
---------- ----------
parameter_id: int parameter_id: int
...@@ -162,7 +162,7 @@ class SMACTuner(Tuner): ...@@ -162,7 +162,7 @@ class SMACTuner(Tuner):
parameters parameters
value: value:
value value
Raises Raises
------ ------
RuntimeError RuntimeError
...@@ -185,7 +185,7 @@ class SMACTuner(Tuner): ...@@ -185,7 +185,7 @@ class SMACTuner(Tuner):
Also, we convert categorical: Also, we convert categorical:
categorical values in search space are changed to list of numbers before, categorical values in search space are changed to list of numbers before,
those original values will be changed back in this function those original values will be changed back in this function
Parameters Parameters
---------- ----------
challenger_dict: dict challenger_dict: dict
...@@ -211,12 +211,12 @@ class SMACTuner(Tuner): ...@@ -211,12 +211,12 @@ class SMACTuner(Tuner):
def generate_parameters(self, parameter_id): def generate_parameters(self, parameter_id):
"""generate one instance of hyperparameters """generate one instance of hyperparameters
Parameters Parameters
---------- ----------
parameter_id: int parameter_id: int
parameter id parameter id
Returns Returns
------- -------
list list
...@@ -234,12 +234,12 @@ class SMACTuner(Tuner): ...@@ -234,12 +234,12 @@ class SMACTuner(Tuner):
def generate_multiple_parameters(self, parameter_id_list): def generate_multiple_parameters(self, parameter_id_list):
"""generate mutiple instances of hyperparameters """generate mutiple instances of hyperparameters
Parameters Parameters
---------- ----------
parameter_id_list: list parameter_id_list: list
list of parameter id list of parameter id
Returns Returns
------- -------
list list
......
...@@ -124,7 +124,7 @@ else: ...@@ -124,7 +124,7 @@ else:
funcs_args, funcs_args,
fixed_inputs, fixed_inputs,
optional_inputs, optional_inputs,
optional_input_size=0): optional_input_size):
'''execute the chosen function and inputs. '''execute the chosen function and inputs.
Below is an example of chosen function and inputs: Below is an example of chosen function and inputs:
{ {
...@@ -149,7 +149,7 @@ else: ...@@ -149,7 +149,7 @@ else:
chosen_layer = mutable_block[mutable_layer_id]["chosen_layer"] chosen_layer = mutable_block[mutable_layer_id]["chosen_layer"]
chosen_inputs = mutable_block[mutable_layer_id]["chosen_inputs"] chosen_inputs = mutable_block[mutable_layer_id]["chosen_inputs"]
real_chosen_inputs = [optional_inputs[input_name] for input_name in chosen_inputs] real_chosen_inputs = [optional_inputs[input_name] for input_name in chosen_inputs]
layer_out = funcs[chosen_layer]([fixed_inputs, real_chosen_inputs], *funcs_args[chosen_layer]) layer_out = funcs[chosen_layer]([fixed_inputs, real_chosen_inputs], **funcs_args[chosen_layer])
return layer_out return layer_out
......
...@@ -32,7 +32,7 @@ from nni.multi_phase.multi_phase_dispatcher import MultiPhaseMsgDispatcher ...@@ -32,7 +32,7 @@ from nni.multi_phase.multi_phase_dispatcher import MultiPhaseMsgDispatcher
from unittest import TestCase, main from unittest import TestCase, main
class NaiveMultiPhaseTuner(MultiPhaseTuner): class NaiveMultiPhaseTuner(MultiPhaseTuner):
''' '''
supports only choices supports only choices
''' '''
def __init__(self): def __init__(self):
......
...@@ -40,7 +40,7 @@ class TrialTestCase(TestCase): ...@@ -40,7 +40,7 @@ class TrialTestCase(TestCase):
def test_get_sequence_id(self): def test_get_sequence_id(self):
self.assertEqual(nni.get_sequence_id(), 0) self.assertEqual(nni.get_sequence_id(), 0)
def test_report_intermediate_result(self): def test_report_intermediate_result(self):
nni.report_intermediate_result(123) nni.report_intermediate_result(123)
self.assertEqual(test_platform.get_last_metric(), { self.assertEqual(test_platform.get_last_metric(), {
......
...@@ -9,11 +9,12 @@ ...@@ -9,11 +9,12 @@
"copy-to-clipboard": "^3.0.8", "copy-to-clipboard": "^3.0.8",
"echarts": "^4.1.0", "echarts": "^4.1.0",
"echarts-for-react": "^2.0.14", "echarts-for-react": "^2.0.14",
"react": "^16.4.2", "react": "^16.7.0-alpha.2",
"react-dom": "^16.4.2", "react-dom": "^16.7.0-alpha.2",
"react-json-tree": "^0.11.0", "react-json-tree": "^0.11.0",
"react-monaco-editor": "^0.22.0", "react-monaco-editor": "^0.22.0",
"react-router": "3.2.1", "react-router": "3.2.1",
"react-responsive": "^7.0.0",
"react-scripts-ts-antd": "2.17.0" "react-scripts-ts-antd": "2.17.0"
}, },
"scripts": { "scripts": {
...@@ -28,7 +29,8 @@ ...@@ -28,7 +29,8 @@
"@types/react": "^16.4.17", "@types/react": "^16.4.17",
"@types/react-dom": "^16.0.7", "@types/react-dom": "^16.0.7",
"@types/react-json-tree": "^0.6.8", "@types/react-json-tree": "^0.6.8",
"@types/react-responsive": "^3.0.3",
"@types/react-router": "3.0.15", "@types/react-router": "3.0.15",
"typescript": "^3.0.1" "typescript": "^3.0.1"
} }
} }
\ No newline at end of file
...@@ -10,14 +10,12 @@ ...@@ -10,14 +10,12 @@
left: 0; left: 0;
top: 0; top: 0;
width: 100%; width: 100%;
height: 56px; height: 56px;
background: #0071BC; background: #0071BC;
border-right: 1px solid #ccc; border-right: 1px solid #ccc;
z-index: 1000; z-index: 1000;
} }
.headerCon{
min-width: 1024px;
}
.contentBox{ .contentBox{
width: 100%; width: 100%;
} }
...@@ -29,5 +27,3 @@ ...@@ -29,5 +27,3 @@
margin-bottom: 30px; margin-bottom: 30px;
background: #fff; background: #fff;
} }
...@@ -3,20 +3,59 @@ import { Row, Col } from 'antd'; ...@@ -3,20 +3,59 @@ import { Row, Col } from 'antd';
import './App.css'; import './App.css';
import SlideBar from './components/SlideBar'; import SlideBar from './components/SlideBar';
class App extends React.Component<{}, {}> { interface AppState {
interval: number;
whichPageToFresh: string;
}
class App extends React.Component<{}, AppState> {
public _isMounted: boolean;
constructor(props: {}) {
super(props);
this.state = {
interval: 10, // sendons
whichPageToFresh: ''
};
}
changeInterval = (interval: number) => {
if (this._isMounted === true) {
this.setState(() => ({ interval: interval }));
}
}
changeFresh = (fresh: string) => {
// interval * 1000
if (this._isMounted === true) {
this.setState(() => ({ whichPageToFresh: fresh }));
}
}
componentDidMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
}
render() { render() {
const { interval, whichPageToFresh } = this.state;
const reactPropsChildren = React.Children.map(this.props.children, child =>
// tslint:disable-next-line:no-any
React.cloneElement(child as React.ReactElement<any>, { interval, whichPageToFresh })
);
return ( return (
<Row className="nni" style={{minHeight: window.innerHeight}}> <Row className="nni" style={{ minHeight: window.innerHeight }}>
<Row className="header"> <Row className="header">
<Col span={1} /> <Col span={1} />
<Col className="headerCon" span={22}> <Col className="headerCon" span={22}>
<SlideBar /> <SlideBar changeInterval={this.changeInterval} changeFresh={this.changeFresh}/>
</Col> </Col>
<Col span={1} /> <Col span={1} />
</Row> </Row>
<Row className="contentBox"> <Row className="contentBox">
<Row className="content"> <Row className="content">
{this.props.children} {reactPropsChildren}
</Row> </Row>
</Row> </Row>
</Row> </Row>
......
...@@ -39,13 +39,18 @@ interface OverviewState { ...@@ -39,13 +39,18 @@ interface OverviewState {
isMultiPhase: boolean; isMultiPhase: boolean;
} }
class Overview extends React.Component<{}, OverviewState> { interface OverviewProps {
interval: number; // user select
whichPageToFresh: string;
}
class Overview extends React.Component<OverviewProps, OverviewState> {
public _isMounted = false; public _isMounted = false;
public intervalID = 0; public intervalID = 0;
public intervalProfile = 1; public intervalProfile = 1;
constructor(props: {}) { constructor(props: OverviewProps) {
super(props); super(props);
this.state = { this.state = {
searchSpace: {}, searchSpace: {},
...@@ -377,17 +382,19 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -377,17 +382,19 @@ class Overview extends React.Component<{}, OverviewState> {
data: accarr data: accarr
}] }]
}; };
this.setState({ accuracyData: accOption }, () => { if (this._isMounted) {
if (accarr.length === 0) { this.setState({ accuracyData: accOption }, () => {
this.setState({ if (accarr.length === 0) {
accNodata: 'No data' this.setState({
}); accNodata: 'No data'
} else { });
this.setState({ } else {
accNodata: '' this.setState({
}); accNodata: ''
} });
}); }
});
}
} }
clickMaxTop = (event: React.SyntheticEvent<EventTarget>) => { clickMaxTop = (event: React.SyntheticEvent<EventTarget>) => {
...@@ -405,23 +412,39 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -405,23 +412,39 @@ class Overview extends React.Component<{}, OverviewState> {
isOffInterval = () => { isOffInterval = () => {
const { status } = this.state; const { status } = this.state;
switch (status) { const { interval } = this.props;
case 'DONE': if (status === 'DONE' || status === 'ERROR' || status === 'STOPPED' ||
case 'ERROR': interval === 0
case 'STOPPED': ) {
window.clearInterval(this.intervalID); window.clearInterval(this.intervalID);
window.clearInterval(this.intervalProfile); window.clearInterval(this.intervalProfile);
break; return;
default: }
}
componentWillReceiveProps(nextProps: OverviewProps) {
const { interval, whichPageToFresh } = nextProps;
window.clearInterval(this.intervalID);
window.clearInterval(this.intervalProfile);
if (whichPageToFresh.includes('/oview')) {
this.showTrials();
this.showSessionPro();
}
if (interval !== 0) {
this.intervalID = window.setInterval(this.showTrials, interval * 1000);
this.intervalProfile = window.setInterval(this.showSessionPro, interval * 1000);
} }
} }
componentDidMount() { componentDidMount() {
this._isMounted = true; this._isMounted = true;
this.showSessionPro(); const { interval } = this.props;
this.showTrials(); this.showTrials();
this.intervalID = window.setInterval(this.showTrials, 10000); this.showSessionPro();
this.intervalProfile = window.setInterval(this.showSessionPro, 60000); if (interval !== 0) {
this.intervalID = window.setInterval(this.showTrials, interval * 1000);
this.intervalProfile = window.setInterval(this.showSessionPro, interval * 1000);
}
} }
componentWillUnmount() { componentWillUnmount() {
...@@ -447,7 +470,7 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -447,7 +470,7 @@ class Overview extends React.Component<{}, OverviewState> {
</Row> </Row>
<Row className="overMessage"> <Row className="overMessage">
{/* status graph */} {/* status graph */}
<Col span={9} className="prograph overviewBoder"> <Col span={9} className="prograph overviewBoder cc">
<Title1 text="Status" icon="5.png" /> <Title1 text="Status" icon="5.png" />
<Progressed <Progressed
trialNumber={trialNumber} trialNumber={trialNumber}
...@@ -459,13 +482,13 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -459,13 +482,13 @@ class Overview extends React.Component<{}, OverviewState> {
/> />
</Col> </Col>
{/* experiment parameters search space tuner assessor... */} {/* experiment parameters search space tuner assessor... */}
<Col span={7} className="overviewBoder"> <Col span={7} className="overviewBoder cc">
<Title1 text="Search space" icon="10.png" /> <Title1 text="Search space" icon="10.png" />
<Row className="experiment"> <Row className="experiment">
<SearchSpace searchSpace={searchSpace} /> <SearchSpace searchSpace={searchSpace} />
</Row> </Row>
</Col> </Col>
<Col span={8} className="overviewBoder"> <Col span={8} className="overviewBoder cc">
<Title1 text="Profile" icon="4.png" /> <Title1 text="Profile" icon="4.png" />
<Row className="experiment"> <Row className="experiment">
{/* the scroll bar all the trial profile in the searchSpace div*/} {/* the scroll bar all the trial profile in the searchSpace div*/}
......
import * as React from 'react'; import * as React from 'react';
import { Link } from 'react-router'; import { Link } from 'react-router';
import axios from 'axios'; import axios from 'axios';
import { DOWNLOAD_IP } from '../static/const';
import { Row, Col, Menu, Dropdown, Icon } from 'antd';
import { MANAGER_IP } from '../static/const'; import { MANAGER_IP } from '../static/const';
import MediaQuery from 'react-responsive';
import { DOWNLOAD_IP } from '../static/const';
import { Row, Col, Menu, Dropdown, Icon, Select } from 'antd';
const { SubMenu } = Menu;
const { Option } = Select;
import '../static/style/slideBar.scss'; import '../static/style/slideBar.scss';
import '../static/style/button.scss'; import '../static/style/button.scss';
interface SliderState { interface SliderState {
version: string; version: string;
menuVisible: boolean; menuVisible: boolean;
navBarVisible: boolean;
}
interface SliderProps {
changeInterval: (value: number) => void;
changeFresh: (value: string) => void;
} }
interface EventPer { interface EventPer {
key: string; key: string;
} }
class SlideBar extends React.Component<{}, SliderState> { class SlideBar extends React.Component<SliderProps, SliderState> {
public _isMounted = false; public _isMounted = false;
public divMenu: HTMLDivElement | null;
constructor(props: {}) { public countOfMenu: number = 0;
super(props); public selectHTML: Select | null;
this.state = {
version: '', constructor(props: SliderProps) {
menuVisible: false super(props);
}; this.state = {
} version: '',
menuVisible: false,
downExperimentContent = () => { navBarVisible: false,
axios };
.all([ }
axios.get(`${MANAGER_IP}/experiment`),
axios.get(`${MANAGER_IP}/trial-jobs`), downExperimentContent = () => {
axios.get(`${MANAGER_IP}/metric-data`) axios
]) .all([
.then(axios.spread((res, res1, res2) => { axios.get(`${MANAGER_IP}/experiment`),
if (res.status === 200 && res1.status === 200 && res2.status === 200) { axios.get(`${MANAGER_IP}/trial-jobs`),
if (res.data.params.searchSpace) { axios.get(`${MANAGER_IP}/metric-data`)
res.data.params.searchSpace = JSON.parse(res.data.params.searchSpace); ])
} .then(axios.spread((res, res1, res2) => {
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false; if (res.status === 200 && res1.status === 200 && res2.status === 200) {
let trialMessagesArr = res1.data; if (res.data.params.searchSpace) {
const interResultList = res2.data; res.data.params.searchSpace = JSON.parse(res.data.params.searchSpace);
Object.keys(trialMessagesArr).map(item => { }
// transform hyperparameters as object to show elegantly const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
trialMessagesArr[item].hyperParameters = JSON.parse(trialMessagesArr[item].hyperParameters); let trialMessagesArr = res1.data;
const trialId = trialMessagesArr[item].id; const interResultList = res2.data;
// add intermediate result message Object.keys(trialMessagesArr).map(item => {
trialMessagesArr[item].intermediate = []; // transform hyperparameters as object to show elegantly
Object.keys(interResultList).map(key => { trialMessagesArr[item].hyperParameters = JSON.parse(trialMessagesArr[item].hyperParameters);
const interId = interResultList[key].trialJobId; const trialId = trialMessagesArr[item].id;
if (trialId === interId) { // add intermediate result message
trialMessagesArr[item].intermediate.push(interResultList[key]); trialMessagesArr[item].intermediate = [];
} Object.keys(interResultList).map(key => {
const interId = interResultList[key].trialJobId;
if (trialId === interId) {
trialMessagesArr[item].intermediate.push(interResultList[key]);
}
});
});
const result = {
experimentParameters: res.data,
trialMessage: trialMessagesArr
};
const aTag = document.createElement('a');
const file = new Blob([JSON.stringify(result, null, 4)], { type: 'application/json' });
aTag.download = 'experiment.json';
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'experiment.json';
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
}
}));
}
downnnimanagerLog = () => {
axios(`${DOWNLOAD_IP}/nnimanager.log`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
const nniLogfile = res.data;
const aTag = document.createElement('a');
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
const file = new Blob([nniLogfile], { type: 'application/json' });
aTag.download = 'nnimanagerLog.log';
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'nnimanagerLog.log';
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
}
}); });
}); }
const result = {
experimentParameters: res.data, downDispatcherlog = () => {
trialMessage: trialMessagesArr axios(`${DOWNLOAD_IP}/dispatcher.log`, {
}; method: 'GET'
const aTag = document.createElement('a'); })
const file = new Blob([JSON.stringify(result, null, 4)], { type: 'application/json' }); .then(res => {
aTag.download = 'experiment.json'; if (res.status === 200) {
aTag.href = URL.createObjectURL(file); const dispatchLogfile = res.data;
aTag.click(); const aTag = document.createElement('a');
if (!isEdge) { const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
URL.revokeObjectURL(aTag.href); const file = new Blob([dispatchLogfile], { type: 'application/json' });
} aTag.download = 'dispatcherLog.log';
if (navigator.userAgent.indexOf('Firefox') > -1) { aTag.href = URL.createObjectURL(file);
const downTag = document.createElement('a'); aTag.click();
downTag.addEventListener('click', function () { if (!isEdge) {
downTag.download = 'experiment.json'; URL.revokeObjectURL(aTag.href);
downTag.href = URL.createObjectURL(file); }
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'dispatcherLog.log';
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
}
}); });
let eventMouse = document.createEvent('MouseEvents'); }
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse); getNNIversion = () => {
} axios(`${MANAGER_IP}/version`, {
} method: 'GET'
})); })
} .then(res => {
if (res.status === 200 && this._isMounted) {
downnnimanagerLog = () => { this.setState({ version: res.data });
axios(`${DOWNLOAD_IP}/nnimanager.log`, { }
method: 'GET'
})
.then(res => {
if (res.status === 200) {
const nniLogfile = res.data;
const aTag = document.createElement('a');
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
const file = new Blob([nniLogfile], { type: 'application/json' });
aTag.download = 'nnimanagerLog.json';
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'nnimanagerLog.json';
downTag.href = URL.createObjectURL(file);
}); });
let eventMouse = document.createEvent('MouseEvents'); }
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse); handleMenuClick = (e: EventPer) => {
} if (this._isMounted) { this.setState({ menuVisible: false }); }
switch (e.key) {
// download experiment related content
case '1':
this.downExperimentContent();
break;
// download nnimanager log file
case '2':
this.downnnimanagerLog();
break;
// download dispatcher log file
case '3':
this.downDispatcherlog();
break;
case 'close':
case '10':
case '20':
case '30':
case '60':
this.getInterval(e.key);
break;
default:
} }
}); }
}
handleVisibleChange = (flag: boolean) => {
downDispatcherlog = () => { if (this._isMounted === true) {
axios(`${DOWNLOAD_IP}/dispatcher.log`, { this.setState({ menuVisible: flag });
method: 'GET'
})
.then(res => {
if (res.status === 200) {
const dispatchLogfile = res.data;
const aTag = document.createElement('a');
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
const file = new Blob([dispatchLogfile], { type: 'application/json' });
aTag.download = 'dispatcherLog.json';
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'dispatcherLog.json';
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
} }
}); }
}
getInterval = (value: string) => {
getNNIversion = () => {
axios(`${MANAGER_IP}/version`, { if (value === 'close') {
method: 'GET' this.props.changeInterval(0);
}) } else {
.then(res => { this.props.changeInterval(parseInt(value, 10));
if (res.status === 200 && this._isMounted) { }
this.setState({ version: res.data }); }
menu = () => {
this.countOfMenu = 0;
return (
<Menu onClick={this.handleMenuClick}>
<Menu.Item key="1">Experiment Parameters</Menu.Item>
<Menu.Item key="2">NNImanager Logfile</Menu.Item>
<Menu.Item key="3">Dispatcher Logfile</Menu.Item>
</Menu>
);
}
// nav bar
navigationBar = () => {
const { version } = this.state;
const feedBackLink = `https://github.com/Microsoft/nni/issues/new?labels=${version}`;
return (
<Menu onClick={this.handleMenuClick} mode="inline">
<Menu.Item key="overview"><Link to={'/oview'}>Overview</Link></Menu.Item>
<Menu.Item key="detail"><Link to={'/detail'}>Trials detail</Link></Menu.Item>
<Menu.Item key="fresh">
<span className="fresh" onClick={this.fresh}><span>Fresh</span></span>
</Menu.Item>
<Menu.Item key="feedback">
<a href={feedBackLink} target="_blank">Feedback</a>
</Menu.Item>
<Menu.Item key="version">Version: {version}</Menu.Item>
<SubMenu
key="download"
onChange={this.handleVisibleChange}
title={
<span>
<span>Download</span>
</span>
}
>
<Menu.Item key="1">Experiment Parameters</Menu.Item>
<Menu.Item key="2">NNImanager Logfile</Menu.Item>
<Menu.Item key="3">Dispatcher Logfile</Menu.Item>
</SubMenu>
</Menu>
);
}
// nav bar <1299
showMenu = () => {
if (this.divMenu !== null) {
this.countOfMenu = this.countOfMenu + 1;
if (this.countOfMenu % 2 === 0) {
this.divMenu.setAttribute('class', 'hide');
} else {
this.divMenu.setAttribute('class', 'show');
}
} }
}); }
}
select = () => {
handleMenuClick = (e: EventPer) => { return (
if (this._isMounted) { this.setState({ menuVisible: false }); } <Select
// download experiment related content onSelect={this.getInterval}
switch (e.key) { defaultValue="Refresh every 10s"
case '1': className="interval"
this.downExperimentContent(); >
break; <Option value="close">Disable Auto Refresh</Option>
case '2': <Option value="10">Refresh every 10s</Option>
this.downnnimanagerLog(); <Option value="20">Refresh every 20s</Option>
break; <Option value="30">Refresh every 30s</Option>
case '3': <Option value="60">Refresh every 1min</Option>
this.downDispatcherlog(); </Select>
break; );
default: }
}
} fresh = (event: React.SyntheticEvent<EventTarget>) => {
event.preventDefault();
handleVisibleChange = (flag: boolean) => { const whichPage = window.location.pathname;
this.setState({ menuVisible: flag }); this.props.changeFresh(whichPage);
} }
componentDidMount() { componentDidMount() {
this._isMounted = true; this._isMounted = true;
this.getNNIversion(); this.getNNIversion();
} }
componentWillUnmount() { componentWillUnmount() {
this._isMounted = false; this._isMounted = false;
} }
render() { render() {
const { version, menuVisible } = this.state; const { version, menuVisible } = this.state;
const feed = `https://github.com/Microsoft/nni/issues/new?labels=${version}`; const feed = `https://github.com/Microsoft/nni/issues/new?labels=${version}`;
const menu = ( return (
<Menu onClick={this.handleMenuClick}> <Row>
<Menu.Item key="1">Experiment Parameters</Menu.Item> <MediaQuery query="(min-width: 1299px)">
<Menu.Item key="2">NNImanager Logfile</Menu.Item> <Row className="nav">
<Menu.Item key="3">Dispatcher Logfile</Menu.Item> <ul className="link">
</Menu> <li className="logo">
); <Link to={'/oview'}>
return ( <img
<Row className="nav"> src={require('../static/img/logo2.png')}
<Col span={8}> style={{ width: 88 }}
<ul className="link"> alt="NNI logo"
<li className="logo"> />
<Link to={'/oview'}> </Link>
<img src={require('../static/img/logo2.png')} style={{ width: 88 }} alt="NNI logo" /> </li>
</Link> <li className="tab firstTab">
</li> <Link to={'/oview'} activeClassName="high">
<li className="tab firstTab"> Overview
<Link to={'/oview'} activeClassName="high"> </Link>
Overview </li>
</Link> <li className="tab">
</li> <Link to={'/detail'} activeClassName="high">
<li className="tab"> Trials detail
<Link to={'/detail'} activeClassName="high"> </Link>
Trials detail </li>
</Link> <li className="feedback">
</li> <span className="fresh" onClick={this.fresh}>
</ul> <Icon type="sync"/><span>Fresh</span>
</Col> </span>
<Col span={16} className="feedback"> <Dropdown
<Dropdown className="dropdown"
className="dropdown" overlay={this.menu()}
overlay={menu} onVisibleChange={this.handleVisibleChange}
onVisibleChange={this.handleVisibleChange} visible={menuVisible}
visible={menuVisible} trigger={['click']}
> >
<a className="ant-dropdown-link" href="#"> <a className="ant-dropdown-link" href="#">
Download <Icon type="down" /> Download <Icon type="down" />
</a> </a>
</Dropdown> </Dropdown>
<a href={feed} target="_blank"> <a href={feed} target="_blank">
<img <img
src={require('../static/img/icon/issue.png')} src={require('../static/img/icon/issue.png')}
alt="NNI github issue" alt="NNI github issue"
/> />
Feedback Feedback
</a> </a>
<span className="version">Version: {version}</span> <span className="version">Version: {version}</span>
</Col> </li>
</Row> </ul>
); </Row>
} </MediaQuery>
<MediaQuery query="(max-width: 1299px)">
<Row className="little">
<Col span={6} className="menu">
<Icon type="unordered-list" className="more" onClick={this.showMenu} />
<div ref={div => this.divMenu = div} className="hide">{this.navigationBar()}</div>
</Col>
<Col span={10} className="logo">
<Link to={'/oview'}>
<img
src={require('../static/img/logo2.png')}
style={{ width: 88 }}
alt="NNI logo"
/>
</Link>
</Col>
</Row>
</MediaQuery>
{this.select()}
</Row>
);
}
} }
export default SlideBar; export default SlideBar;
\ No newline at end of file
...@@ -27,14 +27,18 @@ interface TrialDetailState { ...@@ -27,14 +27,18 @@ interface TrialDetailState {
entriesInSelect: string; entriesInSelect: string;
searchSpace: string; searchSpace: string;
isMultiPhase: boolean; isMultiPhase: boolean;
isTableLoading: boolean;
whichGraph: string; whichGraph: string;
hyperCounts: number; // user click the hyper-parameter counts hyperCounts: number; // user click the hyper-parameter counts
durationCounts: number; durationCounts: number;
intermediateCounts: number; intermediateCounts: number;
} }
class TrialsDetail extends React.Component<{}, TrialDetailState> { interface TrialsDetailProps {
interval: number;
whichPageToFresh: string;
}
class TrialsDetail extends React.Component<TrialsDetailProps, TrialDetailState> {
public _isMounted = false; public _isMounted = false;
public interAccuracy = 0; public interAccuracy = 0;
...@@ -62,7 +66,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -62,7 +66,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
</div> </div>
); );
constructor(props: {}) { constructor(props: TrialsDetailProps) {
super(props); super(props);
this.state = { this.state = {
...@@ -79,7 +83,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -79,7 +83,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
whichGraph: '1', whichGraph: '1',
isHasSearch: false, isHasSearch: false,
isMultiPhase: false, isMultiPhase: false,
isTableLoading: false,
hyperCounts: 0, hyperCounts: 0,
durationCounts: 0, durationCounts: 0,
intermediateCounts: 0 intermediateCounts: 0
...@@ -95,9 +98,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -95,9 +98,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
]) ])
.then(axios.spread((res, res1) => { .then(axios.spread((res, res1) => {
if (res.status === 200 && res1.status === 200) { if (res.status === 200 && res1.status === 200) {
if (this._isMounted === true) {
this.setState(() => ({ isTableLoading: true }));
}
const trialJobs = res.data; const trialJobs = res.data;
const metricSource = res1.data; const metricSource = res1.data;
const trialTable: Array<TableObj> = []; const trialTable: Array<TableObj> = [];
...@@ -144,7 +144,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -144,7 +144,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
const items = metricSource[key]; const items = metricSource[key];
if (items.trialJobId === id) { if (items.trialJobId === id) {
// succeed trial, last intermediate result is final result // succeed trial, last intermediate result is final result
// final result format may be object // final result format may be object
if (typeof JSON.parse(items.data) === 'object') { if (typeof JSON.parse(items.data) === 'object') {
mediate.push(JSON.parse(items.data).default); mediate.push(JSON.parse(items.data).default);
} else { } else {
...@@ -187,10 +187,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -187,10 +187,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
} }
} }
if (this._isMounted) { if (this._isMounted) {
this.setState(() => ({ this.setState(() => ({ tableListSource: trialTable }));
isTableLoading: false,
tableListSource: trialTable
}));
} }
if (entriesInSelect === 'all' && this._isMounted) { if (entriesInSelect === 'all' && this._isMounted) {
this.setState(() => ({ this.setState(() => ({
...@@ -235,21 +232,24 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -235,21 +232,24 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
// close timer // close timer
isOffIntervals = () => { isOffIntervals = () => {
axios(`${MANAGER_IP}/check-status`, { const { interval } = this.props;
method: 'GET' if (interval === 0) {
}) window.clearInterval(this.interTableList);
.then(res => { return;
if (res.status === 200 && this._isMounted) { } else {
switch (res.data.status) { axios(`${MANAGER_IP}/check-status`, {
case 'DONE': method: 'GET'
case 'ERROR': })
case 'STOPPED': .then(res => {
if (res.status === 200 && this._isMounted) {
const expStatus = res.data.status;
if (expStatus === 'DONE' || expStatus === 'ERROR' || expStatus === 'STOPPED') {
window.clearInterval(this.interTableList); window.clearInterval(this.interTableList);
break; return;
default: }
} }
} });
}); }
} }
handleEntriesSelect = (value: string) => { handleEntriesSelect = (value: string) => {
...@@ -312,11 +312,23 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -312,11 +312,23 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
}); });
} }
componentWillReceiveProps(nextProps: TrialsDetailProps) {
const { interval, whichPageToFresh } = nextProps;
window.clearInterval(this.interTableList);
if (interval !== 0) {
this.interTableList = window.setInterval(this.getDetailSource, interval * 1000);
}
if (whichPageToFresh.includes('/detail')) {
this.getDetailSource();
}
}
componentDidMount() { componentDidMount() {
this._isMounted = true; this._isMounted = true;
const { interval } = this.props;
this.getDetailSource(); this.getDetailSource();
this.interTableList = window.setInterval(this.getDetailSource, 10000); this.interTableList = window.setInterval(this.getDetailSource, interval * 1000);
this.checkExperimentPlatform(); this.checkExperimentPlatform();
} }
...@@ -330,14 +342,13 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -330,14 +342,13 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
const { const {
tableListSource, searchResultSource, isHasSearch, isMultiPhase, tableListSource, searchResultSource, isHasSearch, isMultiPhase,
entriesTable, experimentPlatform, searchSpace, experimentLogCollection, entriesTable, experimentPlatform, searchSpace, experimentLogCollection,
whichGraph, isTableLoading whichGraph
} = this.state; } = this.state;
const source = isHasSearch ? searchResultSource : tableListSource; const source = isHasSearch ? searchResultSource : tableListSource;
return ( return (
<div> <div>
<div className="trial" id="tabsty"> <div className="trial" id="tabsty">
<Tabs type="card" onChange={this.handleWhichTabs}> <Tabs type="card" onChange={this.handleWhichTabs}>
{/* <TabPane tab={this.titleOfacc} key="1" destroyInactiveTabPane={true}> */}
<TabPane tab={this.titleOfacc} key="1"> <TabPane tab={this.titleOfacc} key="1">
<Row className="graph"> <Row className="graph">
<DefaultPoint <DefaultPoint
...@@ -358,7 +369,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -358,7 +369,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
</TabPane> </TabPane>
<TabPane tab={this.titleOfDuration} key="3"> <TabPane tab={this.titleOfDuration} key="3">
<Duration source={source} whichGraph={whichGraph} /> <Duration source={source} whichGraph={whichGraph} />
{/* <Duration source={source} whichGraph={whichGraph} clickCounts={durationCounts} /> */}
</TabPane> </TabPane>
<TabPane tab={this.titleOfIntermediate} key="4"> <TabPane tab={this.titleOfIntermediate} key="4">
<Intermediate source={source} whichGraph={whichGraph} /> <Intermediate source={source} whichGraph={whichGraph} />
...@@ -407,7 +417,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -407,7 +417,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
<TableList <TableList
entries={entriesTable} entries={entriesTable}
tableSource={source} tableSource={source}
isTableLoading={isTableLoading}
isMultiPhase={isMultiPhase} isMultiPhase={isMultiPhase}
platform={experimentPlatform} platform={experimentPlatform}
updateList={this.getDetailSource} updateList={this.getDetailSource}
......
...@@ -78,7 +78,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -78,7 +78,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
}).then(res => { }).then(res => {
if (res.status === 200) { if (res.status === 200) {
message.destroy(); message.destroy();
message.success(`Update ${CONTROLTYPE[1].toLocaleLowerCase()} message.success(`Update ${CONTROLTYPE[1].toLocaleLowerCase()}
successfully`); successfully`);
// rerender trial profile message // rerender trial profile message
const { updateFile } = this.props; const { updateFile } = this.props;
......
...@@ -123,7 +123,7 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> { ...@@ -123,7 +123,7 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
<Button <Button
onClick={this.showFormatModal.bind(this, record)} onClick={this.showFormatModal.bind(this, record)}
> >
Copy as python Copy as json
</Button> </Button>
</Row> </Row>
</Row> </Row>
......
...@@ -15,7 +15,7 @@ class TrialLog extends React.Component<TrialLogProps, {}> { ...@@ -15,7 +15,7 @@ class TrialLog extends React.Component<TrialLogProps, {}> {
render() { render() {
const { logStr } = this.props; const { logStr } = this.props;
return ( return (
<div> <div>
<LogPathChild <LogPathChild
......
...@@ -115,13 +115,13 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState> ...@@ -115,13 +115,13 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
}, },
xAxis: { xAxis: {
type: 'category', type: 'category',
name: 'Scape', name: 'Step',
boundaryGap: false, boundaryGap: false,
data: xAxis data: xAxis
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
name: 'Intermediate' name: 'metric'
}, },
series: trialIntermediate series: trialIntermediate
}; };
......
...@@ -22,6 +22,7 @@ interface ParaState { ...@@ -22,6 +22,7 @@ interface ParaState {
max: number; // graph color bar limit max: number; // graph color bar limit
min: number; min: number;
sutrialCount: number; // succeed trial numbers for SUC sutrialCount: number; // succeed trial numbers for SUC
succeedRenderCount: number; // all succeed trials number
clickCounts: number; clickCounts: number;
isLoadConfirm: boolean; isLoadConfirm: boolean;
} }
...@@ -68,6 +69,7 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -68,6 +69,7 @@ class Para extends React.Component<ParaProps, ParaState> {
min: 0, min: 0,
max: 1, max: 1,
sutrialCount: 10000000, sutrialCount: 10000000,
succeedRenderCount: 10000000,
clickCounts: 1, clickCounts: 1,
isLoadConfirm: false isLoadConfirm: false
}; };
...@@ -76,7 +78,8 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -76,7 +78,8 @@ class Para extends React.Component<ParaProps, ParaState> {
getParallelAxis = getParallelAxis =
( (
dimName: Array<string>, parallelAxis: Array<Dimobj>, dimName: Array<string>, parallelAxis: Array<Dimobj>,
accPara: Array<number>, eachTrialParams: Array<string> accPara: Array<number>, eachTrialParams: Array<string>,
lengthofTrials: number
) => { ) => {
// get data for every lines. if dim is choice type, number -> toString() // get data for every lines. if dim is choice type, number -> toString()
const paraYdata: number[][] = []; const paraYdata: number[][] = [];
...@@ -120,7 +123,7 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -120,7 +123,7 @@ class Para extends React.Component<ParaProps, ParaState> {
if (swapAxisArr.length >= 2) { if (swapAxisArr.length >= 2) {
this.swapGraph(paraData, swapAxisArr); this.swapGraph(paraData, swapAxisArr);
} }
this.getOption(paraData); this.getOption(paraData, lengthofTrials);
if (this._isMounted === true) { if (this._isMounted === true) {
this.setState(() => ({ paraBack: paraData })); this.setState(() => ({ paraBack: paraData }));
} }
...@@ -159,8 +162,8 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -159,8 +162,8 @@ class Para extends React.Component<ParaProps, ParaState> {
parallelAxis.push({ parallelAxis.push({
dim: i, dim: i,
name: dimName[i], name: dimName[i],
max: searchKey._value[0] - 1, min: searchKey._value[0],
min: 0 max: searchKey._value[1],
}); });
break; break;
...@@ -248,7 +251,8 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -248,7 +251,8 @@ class Para extends React.Component<ParaProps, ParaState> {
this.setState({ this.setState({
paraNodata: 'No data', paraNodata: 'No data',
option: optionOfNull, option: optionOfNull,
sutrialCount: 0 sutrialCount: 0,
succeedRenderCount: 0
}); });
} }
} else { } else {
...@@ -265,7 +269,7 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -265,7 +269,7 @@ class Para extends React.Component<ParaProps, ParaState> {
}); });
if (this._isMounted) { if (this._isMounted) {
this.setState({ max: Math.max(...accPara), min: Math.min(...accPara) }, () => { this.setState({ max: Math.max(...accPara), min: Math.min(...accPara) }, () => {
this.getParallelAxis(dimName, parallelAxis, accPara, eachTrialParams); this.getParallelAxis(dimName, parallelAxis, accPara, eachTrialParams, lenOfDataSource);
}); });
} }
} }
...@@ -283,7 +287,7 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -283,7 +287,7 @@ class Para extends React.Component<ParaProps, ParaState> {
} }
// deal with response data into pic data // deal with response data into pic data
getOption = (dataObj: ParaObj) => { getOption = (dataObj: ParaObj, lengthofTrials: number) => {
// dataObj [[y1], [y2]... [default metric]] // dataObj [[y1], [y2]... [default metric]]
const { max, min } = this.state; const { max, min } = this.state;
const parallelAxis = dataObj.parallelAxis; const parallelAxis = dataObj.parallelAxis;
...@@ -348,6 +352,7 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -348,6 +352,7 @@ class Para extends React.Component<ParaProps, ParaState> {
this.setState(() => ({ this.setState(() => ({
option: optionown, option: optionown,
paraNodata: '', paraNodata: '',
succeedRenderCount: lengthofTrials,
sutrialCount: paralleData.length sutrialCount: paralleData.length
})); }));
} }
...@@ -367,7 +372,7 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -367,7 +372,7 @@ class Para extends React.Component<ParaProps, ParaState> {
} }
swapReInit = () => { swapReInit = () => {
const { clickCounts } = this.state; const { clickCounts, succeedRenderCount } = this.state;
const val = clickCounts + 1; const val = clickCounts + 1;
if (this._isMounted) { if (this._isMounted) {
this.setState({ isLoadConfirm: true, clickCounts: val, }); this.setState({ isLoadConfirm: true, clickCounts: val, });
...@@ -419,7 +424,7 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -419,7 +424,7 @@ class Para extends React.Component<ParaProps, ParaState> {
paraData[paraItem][dim1] = paraData[paraItem][dim2]; paraData[paraItem][dim1] = paraData[paraItem][dim2];
paraData[paraItem][dim2] = temp; paraData[paraItem][dim2] = temp;
}); });
this.getOption(paraBack); this.getOption(paraBack, succeedRenderCount);
// please wait the data // please wait the data
if (this._isMounted) { if (this._isMounted) {
this.setState(() => ({ this.setState(() => ({
...@@ -503,12 +508,16 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -503,12 +508,16 @@ class Para extends React.Component<ParaProps, ParaState> {
return true; return true;
} }
const { sutrialCount, clickCounts } = nextState; const { sutrialCount, clickCounts, succeedRenderCount } = nextState;
const beforeCount = this.state.sutrialCount; const beforeCount = this.state.sutrialCount;
const beforeClickCount = this.state.clickCounts; const beforeClickCount = this.state.clickCounts;
const beforeRealRenderCount = this.state.succeedRenderCount;
if (sutrialCount !== beforeCount) { if (sutrialCount !== beforeCount) {
return true; return true;
} }
if (succeedRenderCount !== beforeRealRenderCount) {
return true;
}
if (clickCounts !== beforeClickCount) { if (clickCounts !== beforeClickCount) {
return true; return true;
......
...@@ -30,7 +30,6 @@ interface TableListProps { ...@@ -30,7 +30,6 @@ interface TableListProps {
platform: string; platform: string;
logCollection: boolean; logCollection: boolean;
isMultiPhase: boolean; isMultiPhase: boolean;
isTableLoading: boolean;
} }
interface TableListState { interface TableListState {
...@@ -195,7 +194,7 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -195,7 +194,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
render() { render() {
const { entries, tableSource, updateList, isTableLoading } = this.props; const { entries, tableSource, updateList } = this.props;
const { intermediateOption, modalVisible, isShowColumn, columnSelected } = this.state; const { intermediateOption, modalVisible, isShowColumn, columnSelected } = this.state;
let showTitle = COLUMN; let showTitle = COLUMN;
let bgColor = ''; let bgColor = '';
...@@ -264,8 +263,12 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -264,8 +263,12 @@ class TableList extends React.Component<TableListProps, TableListState> {
sorter: (a: TableObj, b: TableObj) => (a.duration as number) - (b.duration as number), sorter: (a: TableObj, b: TableObj) => (a.duration as number) - (b.duration as number),
render: (text: string, record: TableObj) => { render: (text: string, record: TableObj) => {
let duration; let duration;
if (record.duration !== undefined && record.duration > 0) { if (record.duration !== undefined) {
duration = convertDuration(record.duration); if (record.duration > 0 && record.duration < 1) {
duration = `${record.duration}s`;
} else {
duration = convertDuration(record.duration);
}
} else { } else {
duration = 0; duration = 0;
} }
...@@ -418,7 +421,6 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -418,7 +421,6 @@ class TableList extends React.Component<TableListProps, TableListState> {
dataSource={tableSource} dataSource={tableSource}
className="commonTableStyle" className="commonTableStyle"
pagination={{ pageSize: entries }} pagination={{ pageSize: entries }}
loading={isTableLoading}
/> />
{/* Intermediate Result Modal */} {/* Intermediate Result Modal */}
<Modal <Modal
......
...@@ -49,8 +49,8 @@ table { ...@@ -49,8 +49,8 @@ table {
border-collapse: collapse; border-collapse: collapse;
border-spacing: 0; border-spacing: 0;
} }
@font-face { @font-face {
font-family: 'Segoe'; font-family: 'Segoe';
src: url('./static/font/SegoePro-Regular.ttf'); src: url('./static/font/SegoePro-Regular.ttf');
} }
...@@ -50,7 +50,7 @@ const getFinalResult = (final: Array<FinalResult>) => { ...@@ -50,7 +50,7 @@ const getFinalResult = (final: Array<FinalResult>) => {
} }
}; };
// get final result value // acc obj // get final result value // acc obj
const getFinal = (final: Array<FinalResult>) => { const getFinal = (final: Array<FinalResult>) => {
let showDefault: FinalType; let showDefault: FinalType;
if (final) { if (final) {
......
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