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

Commit

Permalink
add dataZoom for graph (#1736)
Browse files Browse the repository at this point in the history
* add dataZoom for graph

* fix comments- datazoom Y

* fix bug of val bold

* update yarn.lock
  • Loading branch information
lvybriage authored and liuzhe-lz committed Nov 25, 2019
1 parent d07f728 commit a03570a
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 986 deletions.
2 changes: 1 addition & 1 deletion src/webui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
109 changes: 69 additions & 40 deletions src/webui/src/components/trial-detail/DefaultMetricPoint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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) => {
Expand All @@ -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>
Expand All @@ -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>
Expand All @@ -64,14 +72,66 @@ 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;
}

private generateGraphConfig(maxSequenceId: number) {
const { startY, endY } = this.state;
return {
grid: {
left: '8%',
},
tooltip: {
trigger: 'item',
enterable: true,
position: (point: Array<number>, data: TooltipForAccuracy) => (
[(data.data[0] < maxSequenceId ? point[0] : (point[0] - 300)), 80]
),
formatter: (data: TooltipForAccuracy) => (
'<div class="tooldetailAccuracy">' +
'<div>Trial No.: ' + data.data[0] + '</div>' +
'<div>Default metric: ' + data.data[1] + '</div>' +
'<div>Parameters: <pre>' + JSON.stringify(data.data[2], null, 4) + '</pre></div>' +
'</div>'
),
},
dataZoom: [
{
id: 'dataZoomY',
type: 'inside',
yAxisIndex: [0],
filterMode: 'empty',
start: startY,
end: endY
}
],
xAxis: {
name: 'Trial',
type: 'category',
},
yAxis: {
name: 'Default metric',
type: 'value',
scale: true,
},
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 = {
Expand All @@ -85,41 +145,10 @@ const EmptyGraph = {
yAxis: {
name: 'Default metric',
type: 'value',
scale: true,
}
};

function generateGraphConfig(maxSequenceId: number) {
return {
grid: {
left: '8%',
},
tooltip: {
trigger: 'item',
enterable: true,
position: (point: Array<number>, data: TooltipForAccuracy) => (
[ (data.data[0] < maxSequenceId ? point[0] : (point[0] - 300)), 80 ]
),
formatter: (data: TooltipForAccuracy) => (
'<div class="tooldetailAccuracy">' +
'<div>Trial No.: ' + data.data[0] + '</div>' +
'<div>Default metric: ' + data.data[1] + '</div>' +
'<div>Parameters: <pre>' + JSON.stringify(data.data[2], null, 4) + '</pre></div>' +
'</div>'
),
},
xAxis: {
name: 'Trial',
type: 'category',
},
yAxis: {
name: 'Default metric',
type: 'value',
scale: true,
},
series: undefined,
};
}

function generateScatterSeries(trials: Trial[]) {
const data = trials.map(trial => [
trial.sequenceId,
Expand All @@ -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]);
}
}

Expand Down
117 changes: 32 additions & 85 deletions 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 } 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');
Expand All @@ -17,7 +17,8 @@ interface DurationProps {
}

interface DurationState {
durationSource: {};
startDuration: number; // for record data zoom
endDuration: number;
}

class Duration extends React.Component<DurationProps, DurationState> {
Expand All @@ -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',
Expand All @@ -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',
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Loading

0 comments on commit a03570a

Please sign in to comment.