Commit a03570a0 authored by Lijiao's avatar Lijiao Committed by liuzhe-lz
Browse files

add dataZoom for graph (#1736)

* add dataZoom for graph

* fix comments- datazoom Y

* fix bug of val bold

* update yarn.lock
parent d07f7280
......@@ -12,7 +12,7 @@
"copy-to-clipboard": "^3.0.8",
"css-loader": "0.28.7",
"dotenv": "^8.0.0",
"echarts": "^4.1.0",
"echarts": "^4.5.0",
"echarts-for-react": "^2.0.14",
"file-loader": "^4.1.0",
"fork-ts-checker-webpack-plugin": "^1.5.0",
......
......@@ -3,7 +3,7 @@ import { Switch } from 'antd';
import ReactEcharts from 'echarts-for-react';
import { EXPERIMENT, TRIALS } from '../../static/datamodel';
import { Trial } from '../../static/model/trial';
import { TooltipForAccuracy } from '../../static/interface';
import { TooltipForAccuracy, EventMap } from '../../static/interface';
require('echarts/lib/chart/scatter');
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
......@@ -16,12 +16,18 @@ interface DefaultPointProps {
interface DefaultPointState {
bestCurveEnabled: boolean;
startY: number; // dataZoomY
endY: number;
}
class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState> {
constructor(props: DefaultPointProps) {
super(props);
this.state = { bestCurveEnabled: false };
this.state = {
bestCurveEnabled: false,
startY: 0, // dataZoomY
endY: 100,
};
}
loadDefault = (checked: boolean) => {
......@@ -35,6 +41,7 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
render() {
const graph = this.generateGraph();
const accNodata = (graph === EmptyGraph ? 'No data' : '');
const onEvents = { 'dataZoom': this.metricDataZoom };
return (
<div>
......@@ -53,6 +60,7 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
}}
theme="my_theme"
notMerge={true} // update now
onEvents={onEvents}
/>
<div className="showMess">{accNodata}</div>
</div>
......@@ -64,31 +72,17 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
if (trials.length === 0) {
return EmptyGraph;
}
const graph = generateGraphConfig(trials[trials.length - 1].sequenceId);
const graph = this.generateGraphConfig(trials[trials.length - 1].sequenceId);
if (this.state.bestCurveEnabled) {
(graph as any).series = [ generateBestCurveSeries(trials), generateScatterSeries(trials) ];
(graph as any).series = [generateBestCurveSeries(trials), generateScatterSeries(trials)];
} else {
(graph as any).series = [ generateScatterSeries(trials) ];
(graph as any).series = [generateScatterSeries(trials)];
}
return graph;
}
}
const EmptyGraph = {
grid: {
left: '8%'
},
xAxis: {
name: 'Trial',
type: 'category',
},
yAxis: {
name: 'Default metric',
type: 'value',
}
};
function generateGraphConfig(maxSequenceId: number) {
private generateGraphConfig(maxSequenceId: number) {
const { startY, endY } = this.state;
return {
grid: {
left: '8%',
......@@ -97,7 +91,7 @@ function generateGraphConfig(maxSequenceId: number) {
trigger: 'item',
enterable: true,
position: (point: Array<number>, data: TooltipForAccuracy) => (
[ (data.data[0] < maxSequenceId ? point[0] : (point[0] - 300)), 80 ]
[(data.data[0] < maxSequenceId ? point[0] : (point[0] - 300)), 80]
),
formatter: (data: TooltipForAccuracy) => (
'<div class="tooldetailAccuracy">' +
......@@ -107,6 +101,16 @@ function generateGraphConfig(maxSequenceId: number) {
'</div>'
),
},
dataZoom: [
{
id: 'dataZoomY',
type: 'inside',
yAxisIndex: [0],
filterMode: 'empty',
start: startY,
end: endY
}
],
xAxis: {
name: 'Trial',
type: 'category',
......@@ -118,8 +122,33 @@ function generateGraphConfig(maxSequenceId: number) {
},
series: undefined,
};
}
private metricDataZoom = (e: EventMap) => {
if (e.batch !== undefined) {
this.setState(() => ({
startY: (e.batch[0].start !== null ? e.batch[0].start : 0),
endY: (e.batch[0].end !== null ? e.batch[0].end : 100)
}));
}
}
}
const EmptyGraph = {
grid: {
left: '8%'
},
xAxis: {
name: 'Trial',
type: 'category',
},
yAxis: {
name: 'Default metric',
type: 'value',
scale: true,
}
};
function generateScatterSeries(trials: Trial[]) {
const data = trials.map(trial => [
trial.sequenceId,
......@@ -135,17 +164,17 @@ function generateScatterSeries(trials: Trial[]) {
function generateBestCurveSeries(trials: Trial[]) {
let best = trials[0];
const data = [[ best.sequenceId, best.accuracy, best.description.parameters ]];
const data = [[best.sequenceId, best.accuracy, best.description.parameters]];
for (let i = 1; i < trials.length; i++) {
const trial = trials[i];
const delta = trial.accuracy! - best.accuracy!;
const better = (EXPERIMENT.optimizeMode === 'minimize') ? (delta < 0) : (delta > 0);
if (better) {
data.push([ trial.sequenceId, trial.accuracy, trial.description.parameters ]);
data.push([trial.sequenceId, trial.accuracy, trial.description.parameters]);
best = trial;
} else {
data.push([ trial.sequenceId, best.accuracy, trial.description.parameters ]);
data.push([trial.sequenceId, best.accuracy, trial.description.parameters]);
}
}
......
import * as React from 'react';
import ReactEcharts from 'echarts-for-react';
import { TableObj } from 'src/static/interface';
import { TableObj, EventMap } from 'src/static/interface';
import { filterDuration } from 'src/static/function';
require('echarts/lib/chart/bar');
require('echarts/lib/component/tooltip');
......@@ -17,7 +17,8 @@ interface DurationProps {
}
interface DurationState {
durationSource: {};
startDuration: number; // for record data zoom
endDuration: number;
}
class Duration extends React.Component<DurationProps, DurationState> {
......@@ -26,63 +27,13 @@ class Duration extends React.Component<DurationProps, DurationState> {
super(props);
this.state = {
durationSource: this.initDuration(this.props.source),
};
}
initDuration = (source: Array<TableObj>) => {
const trialId: Array<string> = [];
const trialTime: Array<number> = [];
const trialJobs = source.filter(filterDuration);
Object.keys(trialJobs).map(item => {
const temp = trialJobs[item];
trialId.push(temp.sequenceId);
trialTime.push(temp.duration);
});
return {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
bottom: '3%',
containLabel: true,
left: '1%',
right: '4%'
},
dataZoom: [{
type: 'slider',
name: 'trial',
filterMode: 'filter',
yAxisIndex: 0,
orient: 'vertical'
}, {
type: 'slider',
name: 'trial',
filterMode: 'filter',
xAxisIndex: 0
}],
xAxis: {
name: 'Time',
type: 'value',
},
yAxis: {
name: 'Trial',
type: 'category',
data: trialId
},
series: [{
type: 'bar',
data: trialTime
}]
startDuration: 0, // for record data zoom
endDuration: 100,
};
}
getOption = (dataObj: Runtrial) => {
const { startDuration, endDuration } = this.state;
return {
tooltip: {
trigger: 'axis',
......@@ -96,19 +47,16 @@ class Duration extends React.Component<DurationProps, DurationState> {
left: '1%',
right: '4%'
},
dataZoom: [{
type: 'slider',
name: 'trial',
filterMode: 'filter',
yAxisIndex: 0,
orient: 'vertical'
}, {
type: 'slider',
name: 'trial',
filterMode: 'filter',
xAxisIndex: 0
}],
dataZoom: [
{
id: 'dataZoomY',
type: 'inside',
yAxisIndex: [0],
filterMode: 'empty',
start: startDuration,
end: endDuration
},
],
xAxis: {
name: 'Time',
type: 'value',
......@@ -140,21 +88,7 @@ class Duration extends React.Component<DurationProps, DurationState> {
trialId: trialId,
trialTime: trialTime
});
this.setState({
durationSource: this.getOption(trialRun[0])
});
}
componentDidMount() {
const { source } = this.props;
this.drawDurationGraph(source);
}
componentWillReceiveProps(nextProps: DurationProps) {
const { whichGraph, source } = nextProps;
if (whichGraph === '3') {
this.drawDurationGraph(source);
}
return this.getOption(trialRun[0]);
}
shouldComponentUpdate(nextProps: DurationProps, nextState: DurationState) {
......@@ -183,18 +117,31 @@ class Duration extends React.Component<DurationProps, DurationState> {
}
render() {
const { durationSource } = this.state;
const { source } = this.props;
const graph = this.drawDurationGraph(source);
const onEvents = { 'dataZoom': this.durationDataZoom };
return (
<div>
<ReactEcharts
option={durationSource}
option={graph}
style={{ width: '95%', height: 412, margin: '0 auto' }}
theme="my_theme"
notMerge={true} // update now
onEvents={onEvents}
/>
</div>
);
}
private durationDataZoom = (e: EventMap) => {
if (e.batch !== undefined) {
this.setState(() => ({
startDuration: (e.batch[0].start !== null ? e.batch[0].start : 0),
endDuration: (e.batch[0].end !== null ? e.batch[0].end : 100)
}));
}
}
}
export default Duration;
import * as React from 'react';
import { Row, Button, Switch } from 'antd';
import { TooltipForIntermediate, TableObj, Intermedia } from '../../static/interface';
import { TooltipForIntermediate, TableObj, Intermedia, EventMap } from '../../static/interface';
import ReactEcharts from 'echarts-for-react';
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
......@@ -14,6 +14,8 @@ interface IntermediateState {
isFilter: boolean;
length: number;
clickCounts: number; // user filter intermediate click confirm btn's counts
startMediaY: number;
endMediaY: number;
}
interface IntermediateProps {
......@@ -38,7 +40,9 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
isLoadconfirmBtn: false,
isFilter: false,
length: 100000,
clickCounts: 0
clickCounts: 0,
startMediaY: 0,
endMediaY: 100
};
}
......@@ -48,6 +52,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
length: source.length,
detailSource: source
});
const { startMediaY, endMediaY } = this.state;
const trialIntermediate: Array<Intermedia> = [];
Object.keys(source).map(item => {
const temp = source[item];
......@@ -113,6 +118,16 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
type: 'value',
name: 'Metric'
},
dataZoom: [
{
id: 'dataZoomY',
type: 'inside',
yAxisIndex: [0],
filterMode: 'empty',
start: startMediaY,
end: endMediaY
}
],
series: trialIntermediate
};
this.setState({
......@@ -258,6 +273,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
render() {
const { interSource, isLoadconfirmBtn, isFilter } = this.state;
const IntermediateEvents = { 'dataZoom': this.intermediateDataZoom };
return (
<div>
{/* style in para.scss */}
......@@ -265,7 +281,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
{
isFilter
?
<span style={{marginRight: 15}}>
<span style={{ marginRight: 15 }}>
<span className="filter-x"># Intermediate result</span>
<input
// placeholder="point"
......@@ -306,12 +322,22 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
option={interSource}
style={{ width: '100%', height: 418, margin: '0 auto' }}
notMerge={true} // update now
onEvents={IntermediateEvents}
/>
<div className="yAxis"># Intermediate result</div>
</Row>
</div>
);
}
private intermediateDataZoom = (e: EventMap) => {
if (e.batch !== undefined) {
this.setState(() => ({
startMediaY: (e.batch[0].start !== null ? e.batch[0].start : 0),
endMediaY: (e.batch[0].end !== null ? e.batch[0].end : 100)
}));
}
}
}
export default Intermediate;
......@@ -275,6 +275,7 @@ class Para extends React.Component<ParaProps, ParaState> {
parallelAxis.push({
dim: i,
name: 'default metric',
scale: true,
nameTextStyle: {
fontWeight: 700
}
......
......@@ -81,6 +81,7 @@ interface Dimobj {
axisLabel?: object;
axisLine?: object;
nameTextStyle?: object;
scale?: boolean;
}
interface ParaObj {
......@@ -179,9 +180,13 @@ interface NNIManagerStatus {
errors: string[];
}
interface EventMap {
[key: string]: () => void;
}
export {
TableObj, TableRecord, Parameters, ExperimentProfile, AccurPoint,
DetailAccurPoint, TooltipForAccuracy, ParaObj, Dimobj, FinalType,
TooltipForIntermediate, SearchSpace, Intermedia, MetricDataRecord, TrialJobInfo,
NNIManagerStatus,
NNIManagerStatus, EventMap
};
This diff is collapsed.
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