-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TopFeat/results view top loci (#1337)
* feat(no-access): add no access message (#1301) * feat(resultsViewTopLoci): Initial commit * feat(resultsViewTopLoci): Fixed title for AF * feat(resultsViewTopLoci): Got search to work on first column * feat(resultsViewTopLoci): Got search to work on remaining columns * feat(resultsViewTopLoci): Formatted code * feat(resultsViewTopLoci): Seperated out logic for filtering into seperate file * feat(resultsViewTopLoci): Ran linter * feat(resultsViewTopLoci): Moved files into seperate folder * feat(resultsViewTopLoci): Wrote unit tests * feat(resultsViewTopLoci): Ran formatter * feat(resultsViewTopLoci): Ran formatter and npm test * feat(resultsViewTopLoci): Added comments back for ESLINT ignores * feat(resultsViewTopLoci): Reverted unintentially changed file * feat(resultsViewTopLoci): Updated search function to remove commas and added additional pageSizeOptions * feat(resultsViewTopLoci): Wrote custom sorting function for variant * feat(resultsViewTopLoci): Updated sort functions for AF and PVAL to parse Number before sort * feat(resultsViewTopLoci): Simplified sort method for variant --------- Co-authored-by: Thanh Dang Nguyen <thanhnd@uchicago.edu>
- Loading branch information
1 parent
f8ddb3e
commit 6308e59
Showing
11 changed files
with
448 additions
and
39 deletions.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
src/Analysis/GWASResults/TestData/ResultsViewData/TopLociTableData.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const TopLociTableData = [ | ||
{ | ||
chrom: '1', | ||
pos: 1000, | ||
ref: 'A', | ||
alt: 'T', | ||
rsids: 'rs123', | ||
nearest_genes: 'GeneA', | ||
af: 0.1, | ||
pval: 0.05, | ||
}, | ||
{ | ||
chrom: '1', | ||
pos: 1001, | ||
ref: 'A', | ||
alt: 'T', | ||
rsids: 'rs456', | ||
nearest_genes: 'GeneB', | ||
af: 0.1, | ||
pval: 0.05, | ||
}, | ||
]; | ||
|
||
export default TopLociTableData; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
195 changes: 195 additions & 0 deletions
195
src/Analysis/GWASResults/Views/Results/ResultsPheWeb/TopLociTable/TopLociTable.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
import React, { useMemo, useState, useEffect } from 'react'; | ||
import { Table, Input, Button } from 'antd'; | ||
import PropTypes from 'prop-types'; | ||
import { SearchOutlined } from '@ant-design/icons'; | ||
import downloadTSVFromJson from './downloadTSVFromJSON'; | ||
import filterLociTableData from './filterLociTableData'; | ||
|
||
const TopLociTable = ({ data }) => { | ||
// Adds a variant key value pair with the desired formatting | ||
const tableData = useMemo( | ||
() => data.map((obj) => ({ | ||
...obj, | ||
variant: `${obj?.chrom}:${obj?.pos.toLocaleString('en-US')} ${obj?.ref}/ | ||
${obj?.alt} (${obj?.rsids})`, | ||
})), | ||
[data], | ||
); | ||
|
||
const [filteredData, setFilteredData] = useState(data); | ||
const [lociTableState, setLociTableState] = useState({ | ||
variantSearchTerm: '', | ||
nearestGenesSearchTerm: '', | ||
pvalSearchTerm: '', | ||
afSearchTerm: '', | ||
currentPage: 1, | ||
}); | ||
|
||
useEffect(() => { | ||
setFilteredData(filterLociTableData(tableData, lociTableState)); | ||
}, [lociTableState, tableData]); | ||
|
||
const handleSearchTermChange = (event, searchTermKey) => { | ||
if (searchTermKey === 'variant') { | ||
setLociTableState({ | ||
...lociTableState, | ||
currentPage: 1, | ||
variantSearchTerm: event.target.value, | ||
}); | ||
} | ||
if (searchTermKey === 'nearest_genes') { | ||
setLociTableState({ | ||
...lociTableState, | ||
currentPage: 1, | ||
nearestGenesSearchTerm: event.target.value, | ||
}); | ||
} | ||
if (searchTermKey === 'pval') { | ||
setLociTableState({ | ||
...lociTableState, | ||
currentPage: 1, | ||
pvalSearchTerm: event.target.value, | ||
}); | ||
} | ||
if (searchTermKey === 'af') { | ||
setLociTableState({ | ||
...lociTableState, | ||
currentPage: 1, | ||
afSearchTerm: event.target.value, | ||
}); | ||
} | ||
return null; | ||
}; | ||
|
||
const handleTableChange = (pagination) => { | ||
if (pagination.current !== lociTableState.currentPage) { | ||
// User changes page selection, set page to current pagination selection | ||
return setLociTableState({ | ||
...lociTableState, | ||
currentPage: pagination.current, | ||
}); | ||
} | ||
// When the user updates sorting set page to first page | ||
return setLociTableState({ | ||
...lociTableState, | ||
currentPage: 1, | ||
}); | ||
}; | ||
|
||
const columns = [ | ||
{ | ||
title: 'Variant', | ||
dataIndex: 'variant', | ||
key: 'variant', | ||
sorter: (a, b) => { | ||
const chromA = Number(a.chrom); | ||
const chromB = Number(b.chrom); | ||
if (chromA === chromB) { | ||
return Number(a.pos) - Number(b.pos); | ||
} | ||
return chromA - chromB; | ||
}, | ||
|
||
children: [ | ||
{ | ||
title: ( | ||
<Input | ||
placeholder='Search by Variant' | ||
value={lociTableState.variantSearchTerm} | ||
onChange={(event) => handleSearchTermChange(event, 'variant')} | ||
suffix={<SearchOutlined />} | ||
/> | ||
), | ||
dataIndex: 'variant', | ||
}, | ||
], | ||
}, | ||
{ | ||
title: 'Nearest Gene(s)', | ||
dataIndex: 'nearest_genes', | ||
key: 'nearest_genes', | ||
sorter: (a, b) => a.nearest_genes.localeCompare(b.nearest_genes), | ||
children: [ | ||
{ | ||
title: ( | ||
<Input | ||
placeholder='Search by Nearest gene(s)' | ||
suffix={<SearchOutlined />} | ||
value={lociTableState.nearestGenesSearchTerm} | ||
onChange={(event) => handleSearchTermChange(event, 'nearest_genes')} | ||
/> | ||
), | ||
dataIndex: 'nearest_genes', | ||
}, | ||
], | ||
}, | ||
{ | ||
title: 'AF', | ||
dataIndex: 'af', | ||
key: 'af', | ||
sorter: (a, b) => Number(a.af) - Number(b.af), | ||
|
||
children: [ | ||
{ | ||
title: ( | ||
<Input | ||
placeholder='Search by Af' | ||
suffix={<SearchOutlined />} | ||
value={lociTableState.afSearchTerm} | ||
onChange={(event) => handleSearchTermChange(event, 'af')} | ||
/> | ||
), | ||
dataIndex: 'af', | ||
}, | ||
], | ||
}, | ||
{ | ||
title: 'P-value', | ||
dataIndex: 'pval', | ||
key: 'pval', | ||
sorter: (a, b) => Number(a.pval) - Number(b.pval), | ||
children: [ | ||
{ | ||
title: ( | ||
<Input | ||
placeholder='Search by P-value' | ||
suffix={<SearchOutlined />} | ||
value={lociTableState.pvalSearchTerm} | ||
onChange={(event) => handleSearchTermChange(event, 'pval')} | ||
/> | ||
), | ||
dataIndex: 'pval', | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
return ( | ||
<section className='top-loci'> | ||
<h2>Top Loci</h2> | ||
<div className='table-header'> | ||
<Button onClick={() => downloadTSVFromJson('topLociTSV.tsv', data)}> | ||
Download All Results | ||
</Button> | ||
</div> | ||
<Table | ||
dataSource={filteredData} | ||
columns={columns} | ||
rowKey={(record) => record.pos} | ||
onChange={handleTableChange} | ||
pagination={{ | ||
current: lociTableState.currentPage, | ||
defaultPageSize: 10, | ||
showSizeChanger: true, | ||
pageSizeOptions: ['10', '50', '100', '500', '1000'], | ||
}} | ||
/> | ||
</section> | ||
); | ||
}; | ||
|
||
TopLociTable.propTypes = { | ||
data: PropTypes.array.isRequired, | ||
}; | ||
|
||
export default TopLociTable; |
Oops, something went wrong.