Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

show RNAseq type in sample hover #4171

Merged
merged 16 commits into from
Jul 1, 2024
22 changes: 14 additions & 8 deletions seqr/views/apis/family_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from seqr.views.utils.project_context_utils import add_families_context, families_discovery_tags, add_project_tag_types, \
MME_TAG_NAME
from seqr.models import Family, FamilyAnalysedBy, Individual, FamilyNote, Sample, VariantTag, AnalysisGroup, RnaSeqTpm, \
PhenotypePrioritization, Project
PhenotypePrioritization, Project, RnaSeqOutlier, RnaSeqSpliceOutlier
from seqr.views.utils.permissions_utils import check_project_permissions, get_project_and_check_pm_permissions, \
login_and_policies_required, user_is_analyst, has_case_review_permissions
from seqr.views.utils.variant_utils import get_phenotype_prioritization, get_omim_intervals_query, DISCOVERY_CATEGORY
Expand All @@ -43,10 +43,21 @@ def family_page_data(request, family_guid):
has_case_review_perm = has_case_review_permissions(project, request.user)

sample_models = Sample.objects.filter(individual__family=family)
samples = get_json_for_samples(sample_models, project_guid=project.guid, family_guid=family_guid, skip_nested=True, is_analyst=is_analyst)
samples = get_json_for_samples(
sample_models, project_guid=project.guid, family_guid=family_guid, skip_nested=True, is_analyst=is_analyst
)
response = {
'samplesByGuid': {s['sampleGuid']: s for s in samples},
'samplesByGuid': {s['sampleGuid']: s for s in samples}
}
rna_type_samples = {
'TPM': set(RnaSeqTpm.objects.filter(sample__in=sample_models).values_list('sample__guid', flat=True)),
'Expression Outlier': set(RnaSeqOutlier.objects.filter(sample__in=sample_models).values_list('sample__guid', flat=True)),
'Splice Outlier': set(RnaSeqSpliceOutlier.objects.filter(sample__in=sample_models).values_list('sample__guid', flat=True)),
}
for sample in response['samplesByGuid'].values():
sample['rnaSeqTypes'] = [
rnaseq_type for rnaseq_type, sample_ids in rna_type_samples.items() if sample['sampleGuid'] in sample_ids
]

add_families_context(response, families, project.guid, request.user, is_analyst, has_case_review_perm)
family_response = response['familiesByGuid'][family_guid]
Expand Down Expand Up @@ -77,11 +88,6 @@ def family_page_data(request, family_guid):
'postDiscoveryOmimOptions': omim_map,
})

outlier_individual_guids = sample_models.filter(sample_type=Sample.SAMPLE_TYPE_RNA, is_active=True)\
.exclude(rnaseqoutlier__isnull=True, rnaseqspliceoutlier__isnull=True).values_list('individual__guid', flat=True)
for individual_guid in outlier_individual_guids:
response['individualsByGuid'][individual_guid]['hasRnaOutlierData'] = True

tools_by_indiv = {}
tools_agg = PhenotypePrioritization.objects.filter(individual__family=family).values('individual__guid').annotate(
phenotypePrioritizationTools=ArrayAgg(
Expand Down
17 changes: 10 additions & 7 deletions seqr/views/apis/family_api_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@

INDIVIDUAL_GUIDS = [INDIVIDUAL_GUID, INDIVIDUAL2_GUID, INDIVIDUAL3_GUID]

FAMILY_API_SAMPLE_FIELDS = {*SAMPLE_FIELDS, 'rnaSeqTypes'}
SAMPLE_GUIDS = ['S000129_na19675', 'S000130_na19678', 'S000131_na19679', 'S000151_na19675_1', 'S000152_na19675_d2', 'S000153_na19679']


class FamilyAPITest(AuthenticationTestCase):
fixtures = ['users', '1kg_project', 'reference_data']

Expand Down Expand Up @@ -69,8 +73,7 @@ def test_family_page_data(self):

self.assertEqual(len(response_json['individualsByGuid']), 3)
individual = response_json['individualsByGuid'][INDIVIDUAL_GUID]
individual_fields = {'sampleGuids', 'igvSampleGuids', 'mmeSubmissionGuid', 'hasRnaOutlierData',
'phenotypePrioritizationTools'}
individual_fields = {'sampleGuids', 'igvSampleGuids', 'mmeSubmissionGuid', 'phenotypePrioritizationTools'}
individual_fields.update(INDIVIDUAL_FIELDS)
self.assertSetEqual(set(individual.keys()), individual_fields)
self.assertListEqual([
Expand All @@ -83,19 +86,19 @@ def test_family_page_data(self):
],
[response_json['individualsByGuid'][guid].get('phenotypePrioritizationTools') for guid in INDIVIDUAL_GUIDS]
)
self.assertListEqual(
[True, False, True],
[response_json['individualsByGuid'][guid].get('hasRnaOutlierData', False) for guid in INDIVIDUAL_GUIDS]
)
self.assertSetEqual({PROJECT_GUID}, {i['projectGuid'] for i in response_json['individualsByGuid'].values()})
self.assertSetEqual({FAMILY_GUID}, {i['familyGuid'] for i in response_json['individualsByGuid'].values()})

self.assertEqual(len(response_json['samplesByGuid']), 6)
self.assertSetEqual(set(next(iter(response_json['samplesByGuid'].values())).keys()), SAMPLE_FIELDS)
self.assertSetEqual(set(next(iter(response_json['samplesByGuid'].values())).keys()), FAMILY_API_SAMPLE_FIELDS)
self.assertSetEqual({PROJECT_GUID}, {s['projectGuid'] for s in response_json['samplesByGuid'].values()})
self.assertSetEqual({FAMILY_GUID}, {s['familyGuid'] for s in response_json['samplesByGuid'].values()})
self.assertEqual(len(individual['sampleGuids']), 3)
self.assertTrue(set(individual['sampleGuids']).issubset(set(response_json['samplesByGuid'].keys())))
self.assertListEqual(
[[], [], [], ['TPM', 'Splice Outlier'], ['TPM', 'Expression Outlier', 'Splice Outlier'], ['Splice Outlier']],
[response_json['samplesByGuid'][guid].get('rnaSeqTypes', {}) for guid in SAMPLE_GUIDS]
)

self.assertEqual(len(response_json['igvSamplesByGuid']), 1)
self.assertSetEqual(set(next(iter(response_json['igvSamplesByGuid'].values())).keys()), IGV_SAMPLE_FIELDS)
Expand Down
2 changes: 1 addition & 1 deletion ui/pages/Project/components/FamilyTable/IndividualRow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ const DataDetails = React.memo(({ loadedSamples, individual, mmeSubmission }) =>
/>
) : <MmeStatusLabel title="Submitted to MME" dateField="lastModifiedDate" color="violet" individual={individual} mmeSubmission={mmeSubmission} />
)}
{individual.hasRnaOutlierData && (
{loadedSamples.some(sample => sample.isActive && (sample.rnaSeqTypes.includes('Expression Outlier') || sample.rnaSeqTypes.includes('Splice Outlier'))) && (
<div>
<Link
target="_blank"
Expand Down
17 changes: 12 additions & 5 deletions ui/shared/components/panel/sample.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import PropTypes from 'prop-types'
import styled from 'styled-components'
import { Popup, Icon } from 'semantic-ui-react'

import { HorizontalSpacer } from '../Spacers'
import { DATASET_TYPE_SNV_INDEL_CALLS } from '../../utils/constants'
import { HorizontalSpacer, VerticalSpacer } from '../Spacers'
import { DATASET_TYPE_SNV_INDEL_CALLS, SAMPLE_TYPE_RNA } from '../../utils/constants'

const Detail = styled.span`
font-size: 11px;
Expand Down Expand Up @@ -33,9 +33,16 @@ const Sample = React.memo(({ loadedSample, isOutdated, hoverDetails }) => (
}
</span>
}
content={loadedSample ?
`data was${isOutdated ? ' previously ' : ''} ${hoverDetails ? `${hoverDetails} on ${new Date(loadedSample.loadedDate).toLocaleDateString()}` : 'loaded'}` :
'no data available'}
content={
<div>
{loadedSample ?
`data was${isOutdated ? ' previously ' : ''} ${hoverDetails ? `${hoverDetails} on ${new Date(loadedSample.loadedDate).toLocaleDateString()}` : 'loaded'}` :
'no data available'}
<VerticalSpacer height={5} />
{loadedSample.sampleType && loadedSample.sampleType === SAMPLE_TYPE_RNA &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rnaSeqTypes will only have values for RNA samples so you can remove this part of the condition check

Copy link
Contributor Author

@jklugherz jklugherz Jun 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this part of the check some old(?) rna samples which do not have any matches in the 3 rnaseqtype tables will display like this:
image

There are 76 of these samples all created on 2016-12-05

WITH sample_rnaseq as (
    select s.guid, s.id, s.created_date,
           seqr_rnaseqtpm.id as tpm_id, seqr_rnaseqoutlier.id as outlier_id, sr.id as splice_outlier_id
    from seqr_sample s
    left join seqr_rnaseqtpm on s.id = seqr_rnaseqtpm.sample_id
    left join seqr_rnaseqoutlier on s.id = seqr_rnaseqoutlier.sample_id
    left join public.seqr_rnaseqspliceoutlier sr on s.id = sr.sample_id
    where s.sample_type in ('RNA')
)
SELECT * FROM sample_rnaseq
WHERE tpm_id is null
and outlier_id is null
and splice_outlier_id is null

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they're all probably from the R0246_rna_seq_bc project, I've been using that for testing since I was certain it would have rna samples given the name

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh we should only be showing this for active samples, not inactive sample

loadedSample.isActive && `RNAseq methods: ${loadedSample.rnaSeqTypes.join(', ')}`}
</div>
}
position="left center"
/>
))
Expand Down
Loading