Skip to content

Commit

Permalink
Merge pull request #961 from notoraptor/db-flatten-params
Browse files Browse the repository at this point in the history
[dashboard/db page] DIsplay parameters in separated flattened columns after ID column
  • Loading branch information
bouthilx authored Jul 6, 2022
2 parents 20994af + dda3256 commit 11eb0b7
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 37 deletions.
44 changes: 44 additions & 0 deletions dashboard/src/src/__tests__/flattenObject.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { flattenObject } from '../utils/flattenObject';

test('test flatten object', () => {
const input = {
a: 1,
b: {
ba: 'world',
bb: 1.5,
bc: {
bd: {
'a key': 333,
'another key': {
x: -1,
y: true,
},
},
},
bd: {
bff: 'abcdefgh',
orion: 'benchmarks',
},
be: 100,
bf: 'bf',
},
c: [10, '2a'],
d: 'hello',
};
const output = flattenObject(input);
console.log(output);
const keys = Object.keys(output);
expect(keys.length).toBe(12);
expect(output.hasOwnProperty('a')).toBeTruthy();
expect(output.hasOwnProperty('b.ba')).toBeTruthy();
expect(output.hasOwnProperty('b.bb')).toBeTruthy();
expect(output.hasOwnProperty('b.bc.bd.a key')).toBeTruthy();
expect(output.hasOwnProperty('b.bc.bd.another key.x')).toBeTruthy();
expect(output.hasOwnProperty('b.bc.bd.another key.y')).toBeTruthy();
expect(output.hasOwnProperty('b.bd.bff')).toBeTruthy();
expect(output.hasOwnProperty('b.bd.orion')).toBeTruthy();
expect(output.hasOwnProperty('b.be')).toBeTruthy();
expect(output.hasOwnProperty('b.bf')).toBeTruthy();
expect(output.hasOwnProperty('c')).toBeTruthy();
expect(output.hasOwnProperty('d')).toBeTruthy();
});
97 changes: 60 additions & 37 deletions dashboard/src/src/experiments/content/DatabasePage/DatabasePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Backend, DEFAULT_BACKEND } from '../../../utils/queryServer';
import TrialTable from './TrialTable';
import { BackendContext } from '../../BackendContext';
import { Grid, Row, Column } from 'carbon-components-react';
import { flattenObject } from '../../../utils/flattenObject';

/**
* Component to pretty display an object (JSON dictionary) into data table.
Expand Down Expand Up @@ -52,15 +53,68 @@ class TrialsProvider {
trialIndices.sort();
const trials = [];
for (let trialID of trialIndices) {
const trial = await this.backend.query(
const rawTrial = await this.backend.query(
`trials/${experiment}/${trialID}`
);
// Save parameters and statistics as already rendered components.
trial.parameters = <ObjectToGrid object={trial.parameters} />;
// Flatten parameters
const flattenedParameters = flattenObject(
rawTrial.parameters,
// Add prefix `params`
// to prevent collision with existing keys in trial object
'params'
);
// Prepare rendering for array parameters
for (let key of Object.keys(flattenedParameters)) {
if (Array.isArray(flattenedParameters[key])) {
flattenedParameters[key] = flattenedParameters[
key
].map((value, i) => <div key={i}>{value.toString()}</div>);
}
}
// Save flattened keys in specific property `paramKeys` for later
rawTrial.paramKeys = Object.keys(flattenedParameters);
const trial = { ...rawTrial, ...flattenedParameters };
// Save statistics as already rendered components.
trial.statistics = <ObjectToGrid object={trial.statistics} />;
trials.push(trial);
}
this.trials[experiment] = trials;
// Prepare headers for this experiment using `paramKeys` from first trial
// We assume paramKeys is the same for all trials
const paramKeys = trials[0].paramKeys.slice();
paramKeys.sort();
const paramHeaders = paramKeys.map(paramKey => ({
key: paramKey,
// Ignore prefix `params.`
header: `Parameter ${paramKey.substr(7)}`,
}));
const trialHeaders = [
{
key: 'id',
header: 'ID',
},
...paramHeaders,
{
key: 'submitTime',
header: 'Submit time',
},
{
key: 'startTime',
header: 'Start time',
},
{
key: 'endTime',
header: 'End time',
},
{
key: 'objective',
header: 'Objective',
},
{
key: 'statistics',
header: 'Statistics',
},
];
this.trials[experiment] = { headers: trialHeaders, trials: trials };
}
return this.trials[experiment];
}
Expand All @@ -72,37 +126,6 @@ class TrialsProvider {
*/
const TRIALS_PROVIDER = new TrialsProvider(DEFAULT_BACKEND);

const headers = [
{
key: 'id',
header: 'ID',
},
{
key: 'submitTime',
header: 'Submit time',
},
{
key: 'startTime',
header: 'Start time',
},
{
key: 'endTime',
header: 'End time',
},
{
key: 'parameters',
header: 'Parameters',
},
{
key: 'objective',
header: 'Objective',
},
{
key: 'statistics',
header: 'Statistics',
},
];

class DatabasePage extends React.Component {
// Control variable to avoid setting state if component was unmounted before an asynchronous API call finished.
_isMounted = false;
Expand All @@ -123,8 +146,8 @@ class DatabasePage extends React.Component {
<div className="bx--row database-page__r1">
<div className="bx--col-lg-16">
<TrialTable
headers={headers}
rows={this.state.trials}
headers={this.state.trials.headers}
rows={this.state.trials.trials}
experiment={this.state.experiment}
/>
</div>
Expand Down
19 changes: 19 additions & 0 deletions dashboard/src/src/utils/flattenObject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
function _flattenObject(inObj, outObj, prefix = '') {
if (prefix.length) {
prefix += '.';
}
for (let key of Object.keys(inObj)) {
const value = inObj[key];
if (value.constructor === Object) {
_flattenObject(value, outObj, prefix + key);
} else {
outObj[prefix + key] = value;
}
}
}

export function flattenObject(obj, prefix = '') {
const output = {};
_flattenObject(obj, output, prefix);
return output;
}

0 comments on commit 11eb0b7

Please sign in to comment.