Skip to content

Commit 1b482ae

Browse files
authored
Merge pull request #5090 from broadinstitute/codon-search
Codon search
2 parents e800145 + 37097f3 commit 1b482ae

File tree

4 files changed

+42
-13
lines changed

4 files changed

+42
-13
lines changed

seqr/utils/search/search_utils_tests.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,6 @@ def _get_expected_search_call(self, results_cache, search_fields=None, has_gene_
284284
dataset_type=None, secondary_dataset_type=None, exclude_keys=None, exclude_key_pairs=None,
285285
exclude_locations=False, exclude=None, annotations=None, annotations_secondary=None, single_gene_search=False, **kwargs):
286286
genes = intervals = None
287-
has_included_gene_search = has_gene_search and not exclude_locations
288287
if has_gene_search:
289288
genes = {'ENSG00000186092': mock.ANY, 'ENSG00000227232': mock.ANY}
290289
intervals = [{'chrom': '2', 'start': 1234, 'end': 5678, 'offset': None}, {'chrom': '7', 'start': 100, 'end': 10100, 'offset': 0.1}]
@@ -296,7 +295,7 @@ def _get_expected_search_call(self, results_cache, search_fields=None, has_gene_
296295
'inheritance_mode': inheritance_mode,
297296
'inheritance_filter': {},
298297
'skipped_samples': mock.ANY,
299-
'dataset_type': None if has_included_gene_search else dataset_type,
298+
'dataset_type': dataset_type,
300299
'secondary_dataset_type': secondary_dataset_type,
301300
'exclude_locations': exclude_locations,
302301
'genes': genes,
@@ -490,6 +489,22 @@ def _mock_get_variants(families, search, user, previous_search_results, genome_v
490489
inheritance_mode='any_affected', exclude={'clinvar': ['benign']}, search_fields=['exclude'],
491490
)
492491

492+
del self.search_model.search['exclude']
493+
self.search_model.search['exclude_svs'] = True
494+
query_variants(self.results_model, user=self.user)
495+
self._test_expected_search_call(
496+
mock_get_variants, results_cache, sort='xpos', page=1, num_results=100, skip_genotype_filter=False,
497+
inheritance_mode='any_affected', omitted_sample_guids=SV_SAMPLES, dataset_type='SNV_INDEL',
498+
)
499+
500+
self.search_model.search['locus'] = {'rawItems': 'WASH7P'}
501+
query_variants(self.results_model, user=self.user)
502+
self._test_expected_search_call(
503+
mock_get_variants, results_cache, sort='xpos', page=1, num_results=100, skip_genotype_filter=False,
504+
inheritance_mode='any_affected', has_gene_search=True, single_gene_search=True,
505+
omitted_sample_guids=NON_SNP_INDEL_SAMPLES, dataset_type='SNV_INDEL_only',
506+
)
507+
493508
def _test_exclude_previous_search(self, mock_get_variants, *args, num_searches=1, **kwargs):
494509
self._test_expected_search_call(mock_get_variants, *args, **kwargs)
495510
self.assertEqual(mock_get_variants.call_count, num_searches)

seqr/utils/search/utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ def _search_dataset_type(search, genome_version):
464464
chroms = [gene[f'chromGrch{genome_version}'] for gene in (search.get('genes') or {}).values()] + [
465465
interval['chrom'] for interval in (search.get('intervals') or [])
466466
] if not search.get('exclude_locations') else None
467-
dataset_type = _annotation_dataset_type(search.get('annotations'), chroms, pathogenicity=search.get('pathogenicity'))
467+
dataset_type = _annotation_dataset_type(search.get('annotations'), chroms, pathogenicity=search.get('pathogenicity'), exclude_svs=search.pop('exclude_svs', False))
468468
secondary_dataset_type = _annotation_dataset_type(search['annotations_secondary'], chroms) if search.get('annotations_secondary') else None
469469

470470
return dataset_type, secondary_dataset_type, None
@@ -486,15 +486,15 @@ def _chromosome_filter_dataset_type(chroms, any_sv):
486486
return ALL_DATA_TYPES if any_sv else Sample.DATASET_TYPE_VARIANT_CALLS
487487

488488

489-
def _annotation_dataset_type(annotations, chroms, pathogenicity=None):
489+
def _annotation_dataset_type(annotations, chroms, pathogenicity=None, exclude_svs=False):
490490
if not (annotations or chroms):
491-
return Sample.DATASET_TYPE_VARIANT_CALLS if pathogenicity else None
491+
return Sample.DATASET_TYPE_VARIANT_CALLS if (pathogenicity or exclude_svs) else None
492492

493493
annotation_types = set((annotations or {}).keys())
494494
if annotations and annotation_types.issubset(SV_ANNOTATION_TYPES) and not pathogenicity:
495495
return Sample.DATASET_TYPE_SV_CALLS
496496

497-
no_svs = (annotations and annotation_types.isdisjoint(SV_ANNOTATION_TYPES))
497+
no_svs = exclude_svs or (annotations and annotation_types.isdisjoint(SV_ANNOTATION_TYPES))
498498
if chroms:
499499
return _chromosome_filter_dataset_type(chroms, any_sv=not no_svs)
500500
elif no_svs:

ui/shared/components/buttons/SearchResultsLink.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ const mapDispatchToProps = (dispatch, ownProps) => ({
3434
if (ownProps.svType) {
3535
search.annotations = { [VEP_GROUP_SV]: [ownProps.svType, `gCNV_${ownProps.svType}`] }
3636
}
37+
if (ownProps.excludeSvs) {
38+
search.exclude_svs = ownProps.excludeSvs
39+
}
3740
const familyGuids = ownProps.familyGuid ? [ownProps.familyGuid] : ownProps.familyGuids
3841
const projectFamilies = familyGuids && [{ familyGuids }]
3942
dispatch(navigateSavedHashedSearch(

ui/shared/components/panel/variants/Annotations.jsx

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
} from 'redux/selectors'
1818
import { HorizontalSpacer, VerticalSpacer } from '../../Spacers'
1919
import CopyToClipboardButton from '../../buttons/CopyToClipboardButton'
20-
import SearchResultsLink from '../../buttons/SearchResultsLink'
20+
import SearchResultsLink, { PermissiveGeneSearchLink } from '../../buttons/SearchResultsLink'
2121
import Modal from '../../modal/Modal'
2222
import { ButtonLink, HelpIcon } from '../../StyledComponents'
2323
import RnaSeqJunctionOutliersTable from '../../table/RnaSeqJunctionOutliersTable'
@@ -112,6 +112,9 @@ const DividedLink = styled.a.attrs({ target: '_blank', rel: 'noreferrer' })`
112112

113113
const DividedButtonLink = DividedLink.withComponent(ButtonLink)
114114

115+
const BaseDividedGeneSearchLink = DividedLink.withComponent(PermissiveGeneSearchLink)
116+
const DividedGeneSearchLink = props => <BaseDividedGeneSearchLink {...props} />
117+
115118
const UcscBrowserLink = ({ genomeVersion, chrom, pos, refLength, endOffset, copyPosition }) => {
116119
const posInt = parseInt(pos, 10)
117120
const ucscGenomeVersion = genomeVersion === GENOME_VERSION_37 ? '19' : genomeVersion
@@ -366,13 +369,21 @@ const variantSearchLinks = (variant, mainTranscript, genesById, user, elasticsea
366369
</NavLink>
367370
)
368371

372+
const seqrLinks = [{
373+
key: 'seqr-search',
374+
trigger: seqrSearchLink,
375+
content: `Search for this variant across all your seqr projects${svType ? '. Any structural variant with ≥20% reciprocal overlap will be returned.' : ''}`,
376+
}]
377+
if (!svType) {
378+
seqrLinks.push({
379+
key: 'codon-search',
380+
trigger: <DividedGeneSearchLink buttonText="seqr codon" genomeVersion={genomeVersion} location={`${chrom}:${pos - 2}-${pos + 2}`} excludeSvs />,
381+
content: 'Search for variants within 2bp of this variant across all your seqr projects in any affected individual and with AF < 3%',
382+
})
383+
}
384+
369385
return [
370-
<Popup
371-
key="seqr-search"
372-
trigger={seqrSearchLink}
373-
content={`Search for this variant across all your seqr projects${svType ? '. Any structural variant with ≥20% reciprocal overlap will be returned.' : ''}`}
374-
size="tiny"
375-
/>,
386+
...seqrLinks.map(props => <Popup size="tiny" {...props} />),
376387
...VARIANT_LINKS.filter(({ shouldShow }) => shouldShow(linkVariant, user)).map(
377388
({ name, getHref }) => <DividedLink key={name} href={getHref(linkVariant)}>{name}</DividedLink>,
378389
),

0 commit comments

Comments
 (0)