Skip to content

Commit 1edcc2a

Browse files
committed
Merge branch 'explanation-page' of https://github.com/Musacca/predict-react into explanation-page
2 parents 15fffa2 + 679ed26 commit 1edcc2a

File tree

4 files changed

+154
-83
lines changed

4 files changed

+154
-83
lines changed

src/components/prediction/ResultTable.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, {PureComponent} from 'react';
22
import {DataTable, TableBody, TableColumn, TableHeader, TablePagination, TableRow} from 'react-md/lib/DataTables/index';
33
import PropTypes from 'prop-types';
4-
import {jobRunPropType} from '../../propTypes';
4+
import {jobPropType} from '../../propTypes';
55
import JsonHolder from '../validation/JsonHolder';
66

77
/* eslint-disable camelcase */
@@ -77,7 +77,7 @@ class ResultTable extends PureComponent {
7777
}
7878

7979
ResultTable.propTypes = {
80-
jobs: PropTypes.arrayOf(jobRunPropType).isRequired,
80+
jobs: PropTypes.arrayOf(jobPropType).isRequired,
8181
onRequestJobs: PropTypes.func.isRequired,
8282
};
8383

Lines changed: 145 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,165 @@
11
import React, {PureComponent} from 'react';
22
import {DataTable, TableBody, TableColumn, TableHeader, TablePagination, TableRow} from 'react-md/lib/DataTables/index';
33
import PropTypes from 'prop-types';
4-
import {tracePropType} from '../../propTypes';
4+
import {jobPropType} from '../../propTypes';
5+
import JsonHolder from '../validation/JsonHolder';
56

67
/* eslint-disable camelcase */
7-
8-
/* eslint-disable max-len */
98
class RuntimeTable extends PureComponent {
10-
constructor(props) {
11-
super(props);
12-
this.state = {slicedData: []};
13-
}
9+
constructor(props) {
10+
super(props);
11+
this.state = {slicedData: this.props.jobs.slice(0, 10)};
12+
}
1413

15-
handlePagination(start, rowsPerPage) {
16-
this.setState({slicedData: this.props.traces.slice(start, start + rowsPerPage)});
14+
handlePagination(start, rowsPerPage) {
15+
this.setState({slicedData: this.props.jobs.slice(start, start + rowsPerPage)});
16+
}
17+
18+
componentDidUpdate(prevProps) {
19+
if (prevProps.jobs.length !== this.props.jobs.length) {
20+
let traces_list = this.createTableData();
21+
if (traces_list !== {}) {
22+
this.setState({slicedData: traces_list.slice(0, 10)});
23+
}
1724
}
25+
}
1826

19-
compareTraces(prevtraces, traces) {
20-
if (prevtraces.length !== traces.length) return true;
21-
for (let i = 0; i < prevtraces.length; i = i + 1) {
22-
if ((prevtraces[i].last_event !== traces[i].last_event) || (prevtraces[i].completed !== traces[i].completed) ||
23-
(prevtraces[i].n_events !== traces[i].n_events)) {
24-
return true;
27+
getGraphicTraceData(case_id) {
28+
const higher_id = this.props.jobs[0].config.parent_job;
29+
let filtered_replay_job = this.props.jobs.filter((job) => case_id in job.case_id
30+
&& job.config.parent_job === higher_id);
31+
let gold_value = 0;
32+
let list_values = [];
33+
filtered_replay_job.sort(function (a, b) {
34+
if (a.id < b.id) {
35+
return -1;
36+
} else {
37+
return 1;
38+
}
39+
});
40+
filtered_replay_job.map((job) => {
41+
if (case_id in job.results) {
42+
list_values.push(...job.results[case_id]);
2543
}
26-
}
27-
return false;
28-
}
44+
if (case_id in job.gold_value) {
45+
gold_value = job.gold_value[case_id];
46+
}
47+
});
48+
return [list_values, gold_value];
49+
}
2950

30-
componentDidUpdate(prevProps) {
31-
if (this.compareTraces(prevProps.traces, this.props.traces)) {
32-
this.setState({slicedData: this.props.traces.slice(0, 10)});
33-
}
34-
}
51+
createTableData() {
52+
try {
53+
const higher_id = this.props.jobs[0].config.parent_job;
54+
let filtered_jobs = this.props.jobs.filter((job) => (job.config.parent_job === higher_id));
55+
let trace_set = new Set();
56+
filtered_jobs.map((job) => {
57+
job.case_id.map((trace) => {
58+
trace_set.add(trace);
59+
});
60+
});
61+
let trace_dict = {};
62+
trace_set.forEach((key) => (trace_dict[key] = {
63+
trace_id: key,
64+
events: 0,
65+
config: {},
66+
results: -1,
67+
gold_value: {},
68+
last_job: -1,
69+
}));
70+
filtered_jobs.map((job) => {
71+
job.case_id.map((trace_id) => {
72+
if (job.event_number[trace_id] >= trace_dict[trace_id].events
73+
|| job.id > trace_dict[trace_id].last_job) {
74+
if (trace_id in job.event_number) {
75+
trace_dict[trace_id].events = job.event_number[trace_id];
76+
}
77+
if (trace_id in job.results) {
78+
trace_dict[trace_id].results = job.results[trace_id];
79+
}
80+
if (trace_id in job.config) {
81+
trace_dict[trace_id].config = job.config[trace_id];
82+
}
83+
if (trace_id in job.gold_value) {
84+
trace_dict[trace_id].gold_value = job.gold_value[trace_id];
85+
}
86+
}
87+
});
88+
});
89+
return Object.values(trace_dict);
90+
} catch (err) {
91+
return 0;
92+
}
93+
}
3594

36-
getHeaderColumns() {
37-
const headers =
38-
['Trace Name', 'Completed', 'Events Elapsed', 'Start Time', 'Latest event time',
39-
'Regression Prediction', 'Classification Prediction', 'Time Series Prediction Prediction'];
95+
/* showGraph(case_id) { Function to call in onClick on Tablerow
96+
let values = this.getGraphicTraceData(case_id);
97+
values[0] are the values given during the reproduction of the trace
98+
vales[1] gold_value
99+
Use this values as input of graph as in validation/ResultWrapper
100+
A possible way to implement charts can be that this function will create charts and put them as a props of this
101+
class and in render create a variable if the prop contains graphs and show them
102+
}
103+
}*/
40104

41-
return headers.map((header) => {
42-
return <TableColumn key={header}> {header}</TableColumn>;
43-
}
44-
);
45-
}
105+
componentDidMount() {
106+
const intervalId = setInterval(() => {
107+
this.props.onRequestJobs();
108+
const traces_list = this.createTableData();
109+
if (traces_list !== 0) {
110+
this.setState({slicedData: traces_list.slice(0, 10)});
111+
}
112+
}, 20000);
113+
this.setState({intervalId: intervalId});
114+
}
46115

47-
render() {
48-
return (<DataTable baseId="simple-pagination" plain>
49-
<TableHeader>
50-
<TableRow selectable={false}>
51-
{this.getHeaderColumns()}
52-
</TableRow>
53-
</TableHeader>
54-
<TableBody>
55-
{this.state.slicedData.map( // TODO: update to use timeSeriesPrediction
56-
({id, name, completed, n_events, first_event, last_event, reg_results, class_results, class_actual, duration, inter_result}) => (
57-
<TableRow key={id} selectable={false}>
58-
<TableColumn>{name}</TableColumn>
59-
<TableColumn>{completed ? 'True' : 'False'}</TableColumn>
60-
<TableColumn>{n_events}</TableColumn>
61-
<TableColumn>{new Date(first_event).toLocaleString()}</TableColumn>
62-
<TableColumn>{new Date(last_event).toLocaleString()}</TableColumn>
63-
<TableColumn>{JSON.stringify(reg_results)}</TableColumn>
64-
<TableColumn>{JSON.stringify(class_results)}</TableColumn>
65-
</TableRow>
66-
))}
67-
</TableBody>
68-
<TablePagination rows={this.props.traces.length} rowsPerPageLabel={'Rows per page'}
69-
onPagination={this.handlePagination.bind(this)}/>
70-
</DataTable>);
71-
}
116+
117+
componentWillUnmount() {
118+
clearInterval(this.state.intervalId);
119+
}
120+
121+
getHeaderColumns() {
122+
const headers =
123+
['Trace_id', 'Events', 'Configuration', 'Prediction', 'Actual value'];
124+
125+
return headers.map((header) => {
126+
let grow = false;
127+
if (header === 'Configuration') {
128+
grow = true;
129+
}
130+
return <TableColumn key={header} grow={grow}> {header}</TableColumn>;
131+
}
132+
);
133+
}
134+
135+
render() {
136+
return (<DataTable baseId="simple-pagination" plain>
137+
<TableHeader>
138+
<TableRow selectable={false}>
139+
{this.getHeaderColumns()}
140+
</TableRow>
141+
</TableHeader>
142+
<TableBody>
143+
{this.state.slicedData.map(
144+
({trace_id, events, config, results, gold_value}) => (
145+
<TableRow key={trace_id} selectable={false}>
146+
<TableColumn>{trace_id}</TableColumn>
147+
<TableColumn>{events}</TableColumn>
148+
<TableColumn grow><JsonHolder data={config}/></TableColumn>
149+
<TableColumn>{JSON.stringify(results)}</TableColumn>
150+
<TableColumn>{JSON.stringify(gold_value)}</TableColumn>
151+
</TableRow>
152+
))}
153+
</TableBody>
154+
<TablePagination rows={this.props.jobs.length} rowsPerPageLabel={'Rows per page'}
155+
onPagination={this.handlePagination.bind(this)}/>
156+
</DataTable>);
157+
}
72158
}
73159

74160
RuntimeTable.propTypes = {
75-
traces: PropTypes.arrayOf(tracePropType).isRequired,
76-
onRequestTraces: PropTypes.func.isRequired,
161+
jobs: PropTypes.arrayOf(jobPropType).isRequired,
162+
onRequestJobs: PropTypes.func.isRequired,
77163
};
78164

79165
export default RuntimeTable;

src/propTypes.js

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,16 @@ export const jobPropType = PropTypes.shape({
9090
hyperopt: PropTypes.shape(hyperOptShape),
9191
labelling: PropTypes.shape(labelPropType).isRequired,
9292
predictive_model: PropTypes.string,
93-
results: PropTypes.string,
93+
results: PropTypes.objectOf(PropTypes.any),
9494
clustering: PropTypes.string,
95+
parent_job: PropTypes.string.isRequired,
9596
encoding: PropTypes.shape(encodingPropType).isRequired,
9697
kmeans: PropTypes.objectOf(PropTypes.any),
9798
}).isRequired,
9899
created_date: PropTypes.string.isRequired,
100+
case_id: PropTypes.arrayOf(PropTypes.number),
101+
event_number: PropTypes.objectOf(PropTypes.any),
102+
gold_values: PropTypes.objectOf(PropTypes.any),
99103
modified_date: PropTypes.string.isRequired,
100104
result: PropTypes.shape({
101105
mae: PropTypes.number,
@@ -115,25 +119,6 @@ export const jobPropType = PropTypes.shape({
115119
})
116120
}).isRequired;
117121

118-
export const jobRunPropType = PropTypes.shape({
119-
id: PropTypes.number.isRequired,
120-
status: PropTypes.string.isRequired,
121-
split: PropTypes.objectOf(splitPropType).isRequired,
122-
splitName: PropTypes.string,
123-
type: PropTypes.oneOf([CLASSIFICATION, REGRESSION, TIME_SERIES_PREDICTION]).isRequired,
124-
config: PropTypes.shape({
125-
hyperopt: PropTypes.shape(hyperOptShape),
126-
labelling: PropTypes.shape(labelPropType).isRequired,
127-
method: PropTypes.string,
128-
clustering: PropTypes.string,
129-
encoding: PropTypes.shape(encodingPropType).isRequired,
130-
kmeans: PropTypes.objectOf(PropTypes.any),
131-
}).isRequired,
132-
created_date: PropTypes.string.isRequired,
133-
modified_date: PropTypes.string.isRequired,
134-
result: PropTypes.any.isRequired,
135-
}).isRequired;
136-
137122
export const jobFlatPropType = PropTypes.shape({
138123
id: PropTypes.number.isRequired,
139124
prefix_length: PropTypes.number.isRequired,

src/views/Runtime/Runtime.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import ModelSelector from '../../components/prediction/ModelSelector';
99
import ReactGA from 'react-ga';
1010
import {REPLAY_JOB_CHANGED, jobsRequested, REPLAY_SPLIT_CHANGED} from '../../actions/JobActions';
1111
import {splitsRequested} from '../../actions/SplitActions';
12-
import ResultTable from '../../components/prediction/ResultTable';
12+
import RuntimeTable from '../../components/runtime/RuntimeTable';
1313

1414
const compare = (a, b) => {
1515
if (a.id < b.id) {
@@ -93,7 +93,7 @@ class Runtime extends Component {
9393
onReset={this.onReset} jobs={jobs}/>
9494
</div>
9595
<div className="md-cell md-cell--12">
96-
<ResultTable jobs={filteredJobsRun.sort(compare)} onRequestJobs={this.requestJobsRun.bind(this)}/>
96+
<RuntimeTable jobs={filteredJobsRun.sort(compare)} onRequestJobs={this.requestJobsRun.bind(this)}/>
9797
</div>
9898
</div>
9999
);

0 commit comments

Comments
 (0)