Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions seqr/utils/search/search_utils_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ def _get_expected_search_call(self, results_cache, search_fields=None, has_gene_
dataset_type=None, secondary_dataset_type=None, exclude_keys=None, exclude_key_pairs=None,
exclude_locations=False, exclude=None, annotations=None, annotations_secondary=None, single_gene_search=False, **kwargs):
genes = intervals = None
has_included_gene_search = has_gene_search and not exclude_locations
if has_gene_search:
genes = {'ENSG00000186092': mock.ANY, 'ENSG00000227232': mock.ANY}
intervals = [{'chrom': '2', 'start': 1234, 'end': 5678, 'offset': None}, {'chrom': '7', 'start': 100, 'end': 10100, 'offset': 0.1}]
Expand All @@ -296,7 +295,7 @@ def _get_expected_search_call(self, results_cache, search_fields=None, has_gene_
'inheritance_mode': inheritance_mode,
'inheritance_filter': {},
'skipped_samples': mock.ANY,
'dataset_type': None if has_included_gene_search else dataset_type,
'dataset_type': dataset_type,
'secondary_dataset_type': secondary_dataset_type,
'exclude_locations': exclude_locations,
'genes': genes,
Expand Down Expand Up @@ -490,6 +489,22 @@ def _mock_get_variants(families, search, user, previous_search_results, genome_v
inheritance_mode='any_affected', exclude={'clinvar': ['benign']}, search_fields=['exclude'],
)

del self.search_model.search['exclude']
self.search_model.search['exclude_svs'] = True
query_variants(self.results_model, user=self.user)
self._test_expected_search_call(
mock_get_variants, results_cache, sort='xpos', page=1, num_results=100, skip_genotype_filter=False,
inheritance_mode='any_affected', omitted_sample_guids=SV_SAMPLES, dataset_type='SNV_INDEL',
)

self.search_model.search['locus'] = {'rawItems': 'WASH7P'}
query_variants(self.results_model, user=self.user)
self._test_expected_search_call(
mock_get_variants, results_cache, sort='xpos', page=1, num_results=100, skip_genotype_filter=False,
inheritance_mode='any_affected', has_gene_search=True, single_gene_search=True,
omitted_sample_guids=NON_SNP_INDEL_SAMPLES, dataset_type='SNV_INDEL_only',
)

def _test_exclude_previous_search(self, mock_get_variants, *args, num_searches=1, **kwargs):
self._test_expected_search_call(mock_get_variants, *args, **kwargs)
self.assertEqual(mock_get_variants.call_count, num_searches)
Expand Down
8 changes: 4 additions & 4 deletions seqr/utils/search/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ def _search_dataset_type(search, genome_version):
chroms = [gene[f'chromGrch{genome_version}'] for gene in (search.get('genes') or {}).values()] + [
interval['chrom'] for interval in (search.get('intervals') or [])
] if not search.get('exclude_locations') else None
dataset_type = _annotation_dataset_type(search.get('annotations'), chroms, pathogenicity=search.get('pathogenicity'))
dataset_type = _annotation_dataset_type(search.get('annotations'), chroms, pathogenicity=search.get('pathogenicity'), exclude_svs=search.pop('exclude_svs', False))
secondary_dataset_type = _annotation_dataset_type(search['annotations_secondary'], chroms) if search.get('annotations_secondary') else None

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


def _annotation_dataset_type(annotations, chroms, pathogenicity=None):
def _annotation_dataset_type(annotations, chroms, pathogenicity=None, exclude_svs=False):
if not (annotations or chroms):
return Sample.DATASET_TYPE_VARIANT_CALLS if pathogenicity else None
return Sample.DATASET_TYPE_VARIANT_CALLS if (pathogenicity or exclude_svs) else None

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

no_svs = (annotations and annotation_types.isdisjoint(SV_ANNOTATION_TYPES))
no_svs = exclude_svs or (annotations and annotation_types.isdisjoint(SV_ANNOTATION_TYPES))
if chroms:
return _chromosome_filter_dataset_type(chroms, any_sv=not no_svs)
elif no_svs:
Expand Down
3 changes: 3 additions & 0 deletions ui/shared/components/buttons/SearchResultsLink.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ const mapDispatchToProps = (dispatch, ownProps) => ({
if (ownProps.svType) {
search.annotations = { [VEP_GROUP_SV]: [ownProps.svType, `gCNV_${ownProps.svType}`] }
}
if (ownProps.excludeSvs) {
search.exclude_svs = ownProps.excludeSvs
}
const familyGuids = ownProps.familyGuid ? [ownProps.familyGuid] : ownProps.familyGuids
const projectFamilies = familyGuids && [{ familyGuids }]
dispatch(navigateSavedHashedSearch(
Expand Down
25 changes: 18 additions & 7 deletions ui/shared/components/panel/variants/Annotations.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from 'redux/selectors'
import { HorizontalSpacer, VerticalSpacer } from '../../Spacers'
import CopyToClipboardButton from '../../buttons/CopyToClipboardButton'
import SearchResultsLink from '../../buttons/SearchResultsLink'
import SearchResultsLink, { PermissiveGeneSearchLink } from '../../buttons/SearchResultsLink'
import Modal from '../../modal/Modal'
import { ButtonLink, HelpIcon } from '../../StyledComponents'
import RnaSeqJunctionOutliersTable from '../../table/RnaSeqJunctionOutliersTable'
Expand Down Expand Up @@ -112,6 +112,9 @@ const DividedLink = styled.a.attrs({ target: '_blank', rel: 'noreferrer' })`

const DividedButtonLink = DividedLink.withComponent(ButtonLink)

const BaseDividedGeneSearchLink = DividedLink.withComponent(PermissiveGeneSearchLink)
const DividedGeneSearchLink = props => <BaseDividedGeneSearchLink {...props} />

const UcscBrowserLink = ({ genomeVersion, chrom, pos, refLength, endOffset, copyPosition }) => {
const posInt = parseInt(pos, 10)
const ucscGenomeVersion = genomeVersion === GENOME_VERSION_37 ? '19' : genomeVersion
Expand Down Expand Up @@ -366,13 +369,21 @@ const variantSearchLinks = (variant, mainTranscript, genesById, user, elasticsea
</NavLink>
)

const seqrLinks = [{
key: 'seqr-search',
trigger: seqrSearchLink,
content: `Search for this variant across all your seqr projects${svType ? '. Any structural variant with ≥20% reciprocal overlap will be returned.' : ''}`,
}]
if (!svType) {
seqrLinks.push({
key: 'codon-search',
trigger: <DividedGeneSearchLink buttonText="seqr codon" genomeVersion={genomeVersion} location={`${chrom}:${pos - 2}-${pos + 2}`} excludeSvs />,
content: 'Search for variants within 2bp of this variant across all your seqr projects in any affected individual and with AF < 3%',
})
}

return [
<Popup
key="seqr-search"
trigger={seqrSearchLink}
content={`Search for this variant across all your seqr projects${svType ? '. Any structural variant with ≥20% reciprocal overlap will be returned.' : ''}`}
size="tiny"
/>,
...seqrLinks.map(props => <Popup size="tiny" {...props} />),
...VARIANT_LINKS.filter(({ shouldShow }) => shouldShow(linkVariant, user)).map(
({ name, getHref }) => <DividedLink key={name} href={getHref(linkVariant)}>{name}</DividedLink>,
),
Expand Down