Skip to content

Commit

Permalink
feat(sunburst): kids-first#2641 review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
adipaul1981 committed Nov 10, 2020
1 parent d25122b commit 47866ae
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 139 deletions.
32 changes: 31 additions & 1 deletion src/components/OntologyBrowser/Model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { PhenotypeSource } from './store';
import { PhenotypeSource, splitHPOTerm } from './store';
import React from 'react';
import { hpoTreeTitleFormat } from '../UI/Charts/Sunburst/Sunburst';

export type TreeNode = {
title: React.ReactElement | string;
Expand All @@ -17,6 +19,34 @@ export type TreeNode = {
name?: string;
};

export const lightTreeNodeConstructorOld = (
key: string,
title: React.ReactElement | string,
children: TreeNode[] = [],
): TreeNode => ({
title: title,
text: '',
key: key,
children,
valueText: 0,
});

export const lightTreeNodeConstructor = (
phenotype: string,
selectedPhenotypeInfoTitle: string,
children: TreeNode[] = [],
): TreeNode => {
const splitPheno = splitHPOTerm(phenotype);

return {
title: hpoTreeTitleFormat(splitPheno, selectedPhenotypeInfoTitle),
text: '',
key: phenotype,
children,
valueText: 0,
};
};

export default class OntologyTree {
phenotypes: PhenotypeSource[] = [];
tree: TreeNode[] = [];
Expand Down
46 changes: 45 additions & 1 deletion src/components/OntologyBrowser/Test/store.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { PhenotypeSource, PhenotypeStore, removeSameTerms, selectSameTerms } from '../store';
import {
generateNavTreeFormKey,
PhenotypeSource,
PhenotypeStore,
removeSameTerms,
selectSameTerms,
} from '../store';
import { TreeNode } from '../Model';
import { flatMockData, treeData } from './mockData';
import { hpoTreeTitleFormat } from 'components/UI/Charts/Sunburst/Sunburst';

describe('Phenotype Store', () => {
let newStore: PhenotypeStore;
Expand Down Expand Up @@ -198,4 +205,41 @@ describe('Phenotype Store', () => {
expect(firstLevel.value).toEqual(66);
});
});

describe('Sunburst generateInfoTree method', () => {
it('should render tree data', () => {
const inputPhenotype = 'Aaa (HP:0001)-Bbb (HP:0002)-Ccc (HP:0003)';
const phenotypes = inputPhenotype.match(new RegExp(/([A-Z].+?\(HP:\d+\))/, 'g'));

const result = generateNavTreeFormKey((phenotypes || []).reverse(), 'Ccc (HP:0003)');

const expectedResult = [
{
key: 'Aaa (HP:0001)',
text: '',
valueText: 0,
title: hpoTreeTitleFormat({ name: 'Aaa', code: 'HP:0001' }, 'Ccc (HP:0003)'),
children: [
{
key: 'Bbb (HP:0002)',
title: hpoTreeTitleFormat({ name: 'Bbb', code: 'HP:0002' }, 'Ccc (HP:0003)'),
text: '',
valueText: 0,
children: [
{
key: 'Ccc (HP:0003)',
title: hpoTreeTitleFormat({ name: 'Ccc', code: 'HP:0003' }, 'Ccc (HP:0003)'),
text: '',
valueText: 0,
children: [],
},
],
},
],
},
];

expect(result).toEqual(expectedResult);
});
});
});
44 changes: 43 additions & 1 deletion src/components/OntologyBrowser/store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { graphql } from '../../services/arranger';
import OntologyTree, { TreeNode } from './Model';
import OntologyTree, { lightTreeNodeConstructor, TreeNode } from './Model';

export type PhenotypeSource = {
key: string;
Expand All @@ -10,6 +10,9 @@ export type PhenotypeSource = {
filter_by_term: any;
};

const RegexHPOCode = /^.+(\(HP:\d+\)$)/;
export const RegexExtractPhenotype = new RegExp(/([A-Z].+?\(HP:\d+\))/, 'g');

const dotToUnderscore = (str: string) => str.replace('.', '__');

const termRegex = new RegExp('[^-]+$');
Expand Down Expand Up @@ -61,6 +64,45 @@ const findAllSameTerms = (
return sameTermKeys;
};

export const generateNavTreeFormKey = (
phenotypes: string[],
selectedPhenotypeInfoTitle: string,
): TreeNode[] => {
if (!phenotypes.length) {
return [];
}

if (phenotypes.length === 1) {
const leafPheno = phenotypes.pop();

if (!leafPheno) {
return [];
}

return [lightTreeNodeConstructor(leafPheno, selectedPhenotypeInfoTitle)];
}

const rootPheno = phenotypes.pop();

return rootPheno
? [
lightTreeNodeConstructor(
rootPheno,
selectedPhenotypeInfoTitle,
generateNavTreeFormKey(phenotypes, selectedPhenotypeInfoTitle),
),
]
: [];
};

export const splitHPOTerm = (term: string) => {
const match = RegexHPOCode.exec(term);
return {
name: term.replace(match ? match[1] : '', '').trim(),
code: match ? match[1].replace('(', '').replace(')', '') : '',
};
};

export class PhenotypeStore {
// Flat representation of phenotype from graphql source
phenotypes: PhenotypeSource[] = [];
Expand Down
14 changes: 9 additions & 5 deletions src/components/UI/Charts/Sunburst/InfoPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
/* eslint-disable react/prop-types */
import React, { FunctionComponent } from 'react';
import './sunburst.css';
import { Phenotype } from 'store/sunburstTypes';
import { RootState } from 'store/rootState';
import { connect, ConnectedProps } from 'react-redux';
import { addTermToActiveIndex } from 'store/actionCreators/virtualStudies';
import { ThunkDispatch } from 'redux-thunk';
import { AddTermToActiveIndex, Term } from 'store/virtualStudiesTypes';
import { Button } from 'antd';
import InfoPanelNavTree from './InfoPanelNavTree';
import { TreeNode } from '../../../OntologyBrowser/Model';
import { Button, Tree } from 'antd';
import { TreeNode } from 'components/OntologyBrowser/Model';
import './sunburst.css';

type OwnProps = {
data: Pick<Phenotype, 'title' | 'key' | 'results' | 'exactTagCount'>;
Expand Down Expand Up @@ -65,7 +64,12 @@ const InfoPanel: FunctionComponent<Props> = ({ data, onClickAddTermToActiveIndex
</div>
<div className={'tree-grid'}>
<div className={'tree-title'}>Current Path</div>
<InfoPanelNavTree treeData={treeData} expandedKeys={key.split('-')} />
<Tree
treeData={treeData}
expandedKeys={key.split('-')}
switcherIcon={<div />}
className={'sunburst-phenotypes-tree'}
/>
</div>
</div>
);
Expand Down
22 changes: 0 additions & 22 deletions src/components/UI/Charts/Sunburst/InfoPanelNavTree.tsx

This file was deleted.

80 changes: 17 additions & 63 deletions src/components/UI/Charts/Sunburst/Sunburst.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@ import sunburstD3 from './sunburst-d3';
import InfoPanel from './InfoPanel';
import { Phenotype } from 'store/sunburstTypes';
import './sunburst.css';

const RegexHPO = /^.+(\(HP:\d+\)$)/;
const RegexExtractPhenotype = new RegExp(/([A-Z].+?\(HP:\d+\))/, 'g');

type TreeNode = {
key: string;
title: React.ReactElement | string;
children: TreeNode[];
};
import {
generateNavTreeFormKey,
RegexExtractPhenotype,
splitHPOTerm,
} from 'components/OntologyBrowser/store';
import { lightTreeNodeConstructor, TreeNode } from 'components/OntologyBrowser/Model';

type PhenotypeSplit = {
name: string;
Expand Down Expand Up @@ -42,53 +39,14 @@ const pickPhenotypeInfo = (p: Phenotype) => ({
exactTagCount: p.exactTagCount,
});

export const hpoTreeTitleFormat = (splitPheno: PhenotypeSplit) => (
<div style={{ color: '#515885', fontSize: 14, fontWeight: 400 }}>
{splitPheno.name}
<span style={{ color: '#7D84A6', fontSize: 12, fontWeight: 400 }}>{splitPheno.code}</span>
</div>
);

const splitHPOTerm = (term: string | undefined) => {
let match;
if (term) {
match = RegexHPO.exec(term);
return {
name: term.replace(match ? match[1] : '', ' '),
code: match ? match[1] : '',
};
} else {
return { name: '', code: '' };
}
};

export const generateInfoTree = (phenotypes: string[]): TreeNode[] => {
if (!phenotypes.length) {
return [];
}

if (phenotypes.length == 1) {
const leafPheno = phenotypes.pop();
const splitPheno = splitHPOTerm(leafPheno);

return [
{
key: leafPheno,
title: hpoTreeTitleFormat(splitPheno),
children: [],
} as TreeNode,
];
}
const rootPheno = phenotypes.pop();
const splitPheno = splitHPOTerm(rootPheno);

return [
{
key: rootPheno,
title: hpoTreeTitleFormat(splitPheno),
children: generateInfoTree(phenotypes),
} as TreeNode,
];
export const hpoTreeTitleFormat = (splitPheno: PhenotypeSplit, currentTerm: string) => {
const currentPhenoCode = splitHPOTerm(currentTerm).code;
return (
<div className={`hpo-tree-name ${currentPhenoCode === splitPheno.code ? 'hpo-tree-bold' : ''}`}>
{splitPheno.name}
<span className={'hpo-tree-code'}>{` ${splitPheno.code}`}</span>
</div>
);
};

class Sunburst extends Component<SunburstProps, State> {
Expand All @@ -112,7 +70,7 @@ class Sunburst extends Component<SunburstProps, State> {
getSelectedPhenotype = (phenotype: Phenotype) => {
const phenotypes = phenotype.key.match(RegexExtractPhenotype);
const phenoReversed = (phenotypes || []).reverse();
const treeData: TreeNode[] = generateInfoTree(phenoReversed);
const treeData: TreeNode[] = generateNavTreeFormKey(phenoReversed, phenotype.title);
this.setState({
selectedPhenotypeInfo: pickPhenotypeInfo(phenotype),
phenotypeTree: treeData,
Expand All @@ -130,12 +88,8 @@ class Sunburst extends Component<SunburstProps, State> {
tooltipFormatter,
centerTextFormatter,
});
const splitPheno = splitHPOTerm(data.key);
const rootTreeNode: TreeNode = {
key: data.key,
title: hpoTreeTitleFormat(splitPheno),
children: [],
};
const rootTreeNode: TreeNode = lightTreeNodeConstructor(data.key, data.key);

this.setState({ phenotypeTree: [rootTreeNode] });
}

Expand Down
44 changes: 0 additions & 44 deletions src/components/UI/Charts/Sunburst/Test/Sunburst.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { treeData } from 'components/OntologyBrowser/Test/mockData';
import thunk from 'redux-thunk';
import configureStore from 'redux-mock-store';
import { Provider } from 'react-redux';
import { generateInfoTree } from '../Sunburst';
import { expect } from 'chai';

configure({ adapter: new Adapter() });

Expand Down Expand Up @@ -51,45 +49,3 @@ describe('Sunburst', () => {
expect(wrapper.find('svg').prop('viewBox')).toEqual('0 0 400 450');
});
});

describe('Sunburst generateInfoTree method', () => {
it('should render tree data', () => {
const inputPhenotype = 'Aaa (HP:0001)-Bbb (HP:0002)-Ccc (HP:0003)';
const phenotypes = inputPhenotype.split('-').reverse();
const result = generateInfoTree(phenotypes);

const expectedResult = [
{
key: 'Aaa',
title: (
<div>
Aaa<span style={{ color: 'red' }}>HP:0001</span>
</div>
),
children: [
{
key: 'Bbb',
title: (
<div>
Bbb<span style={{ color: 'red' }}>HP:0002</span>
</div>
),
children: [
{
key: 'Ccc',
title: (
<div>
Ccc<span style={{ color: 'red' }}>HP:0003</span>
</div>
),
children: [],
},
],
},
],
},
];

expect(result).to.be.deep.equal(expectedResult);
});
});
Loading

0 comments on commit 47866ae

Please sign in to comment.