Skip to content

Commit

Permalink
Merge pull request #167 from macarthur-lab/hotfix-phenotips_pdf_view-…
Browse files Browse the repository at this point in the history
…0.01

Hotfix phenotips pdf view 0.01
  • Loading branch information
bw2 committed Mar 11, 2016
2 parents af381bc + 984240d commit 9d91606
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 4 deletions.
1 change: 1 addition & 0 deletions xbrowse_server/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@

#phenotips related
url(r'^phenotips/proxy/edit/(?P<eid>[\w|-]+)$', 'xbrowse_server.phenotips.views.fetch_phenotips_edit_page', name='fetch_phenotips_edit_page'),
url(r'^phenotips/proxy/view/(?P<eid>[\w|-]+)$', 'xbrowse_server.phenotips.views.fetch_phenotips_pdf_page', name='fetch_phenotips_pdf_page'),
)
26 changes: 26 additions & 0 deletions xbrowse_server/base/views/project_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,17 @@
from xbrowse_server.mall import get_reference
from xbrowse_server import mall
from xbrowse_server.gene_lists.views import download_response as gene_list_download_response
from xbrowse_server.phenotips.reporting_utilities import get_phenotype_entry_metrics_for_project
from xbrowse_server.phenotips.reporting_utilities import categorize_phenotype_counts
from xbrowse_server.phenotips.reporting_utilities import aggregate_phenotype_counts_into_bins
from xbrowse_server.decorators import log_request
import logging

logger = logging.getLogger(__name__)


@login_required
@log_request('project_views')
def project_home(request, project_id):

project = get_object_or_404(Project, project_id=project_id)
Expand All @@ -58,7 +66,25 @@ def project_home(request, project_id):
else:
raise Exception("Authx - how did we get here?!?")

phenotips_supported=False
if project_id in settings.PHENOTIPS_SUPPORTED_PROJECTS:
phenotips_supported=True

indiv_phenotype_counts=[]
binned_counts={}
categorized_phenotype_counts={}
if phenotips_supported:
try:
indiv_phenotype_counts= get_phenotype_entry_metrics_for_project(project_id)
binned_counts=aggregate_phenotype_counts_into_bins(indiv_phenotype_counts)
categorized_phenotype_counts=categorize_phenotype_counts(binned_counts)
except Exception as e:
print 'error looking for project information in PhenoTips:logging & moving,there might not be any data'
logger.error('project_views:'+str(e))

return render(request, 'project.html', {
'categorized_phenotype_counts':categorized_phenotype_counts,
'phenotips_supported':phenotips_supported,
'project': project,
'auth_level': auth_level,
'can_edit': project.can_edit(request.user),
Expand Down
193 changes: 193 additions & 0 deletions xbrowse_server/phenotips/reporting_utilities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
from xbrowse_server.base.models import Project
from xbrowse_server.phenotips.utilities import get_uname_pwd_for_project
import os
from django.conf import settings
import requests
from requests.auth import HTTPBasicAuth

def get_phenotype_entry_metrics_for_project(project_id):
'''
Processes the given project
Inputs:
project: a project ID
'''
try:
project = Project.objects.get(project_id=project_id)
individuals=[]
for individual in project.get_individuals():
individuals.append(individual.indiv_id)
return get_phenotype_entry_details_for_individuals(individuals,project_id)
except Exception as e:
print '\nsorry, we encountered an error finding project:',e,'\n'
raise

def aggregate_phenotype_counts_into_bins(phenotype_counts):
'''
Given a list of individual phenotype counts, aggregates these into
bins of counts
Input:
A list of dicts that have indiv ID and how many phenotypes entered
[{}, ....]
Ex:
[{'eid': u'NA19675', 'num_phenotypes_entered': 1},....]
Output:
A dict that resembles (the "count" here is derived from "num_phenotypes_entered":
{count: [indiv1, indiv2, indiv3 ..indivs with this many phenotypes entered],
count2: [indivX,...]}
'''
aggregated={}
for count in phenotype_counts:
if aggregated.has_key(count['num_phenotypes_entered']):
aggregated[count['num_phenotypes_entered']].append(count['eid'])
else:
aggregated[count['num_phenotypes_entered']] = [count['eid']]
return aggregated



def get_phenotype_entry_details_for_individuals(individuals,project_id):
'''
Process this list of individuals
Inputs:
individuals: a list of individuals
'''
all_patients=[]
try:
for individual in individuals:
phenotype_count_for_indiv=phenotype_entry_metric_for_individual(individual,project_id)
all_patients.append({'eid':individual,'num_phenotypes_entered':phenotype_count_for_indiv})
return all_patients
except Exception as e:
raise




def print_details_to_stdout(proj_dets,summarize):
'''
Print details to STDOUT
Inputs:
proj_dets: a project details structure
summarize: True/False whether to summarize view
'''
category_names=self.get_phenotype_count_categorie_names()
if summarize:
print '{:20s} {:20s} {:20s} {:20s} {:20s} {:20s}'.format('Project',*category_names)
try:
for proj_id,dets in proj_dets.iteritems():
phenotype_counts={}
for patient_det in dets:
if not summarize:
print patient_det['eid'],patient_det['num_phenotypes_entered']
if summarize:
if phenotype_counts.has_key(patient_det['num_phenotypes_entered']):
phenotype_counts[patient_det['num_phenotypes_entered']].append(patient_det['eid'])
else:
phenotype_counts[patient_det['num_phenotypes_entered']]=[patient_det['eid']]
if summarize:
data=categorize_phenotype_counts(phenotype_counts)
print '{:20s}'.format(proj_id),
for category_name in category_names:
print '{:20s}'.format(str(len(data[category_name]))),
print
except Exception as e:
raise


def categorize_phenotype_counts(phenotype_counts):
'''
Bin counts in categories for easy reporting in columns
Categories are:
0
0-10
10-20
>30
Notes:
If you add any new categories, remember to update method
get_phenotype_count_categorie_names.
Inputs:
A dict of number of patients to number of phenotypes
entered for each patient
Outputs:
-A dict with keys of above categories and values being count
of each.
-A tuple with category names
'''
category_names=get_phenotype_count_categorie_names()
data={}
for c in category_names:
data[c]=[]
for phenotype_count,patients in phenotype_counts.iteritems():
if phenotype_count ==0:
data['0'].extend(patients)
if phenotype_count>0 and phenotype_count<11:
data['1to10'].extend(patients)
if phenotype_count>=11 and phenotype_count<=20:
data['11to20'].extend(patients)
if phenotype_count>=21 and phenotype_count<=30:
data['21to30'].extend(patients)
if phenotype_count>=31:
data['larger_than_31'].extend(patients)
return data


def get_phenotype_count_categorie_names():
'''
Return a tuple of category names used
categorize_phenotype_counts.
Notes:
Any updates to this function must coincide with method
'''
return ('0','1to10','11to20','21to30','larger_than_31')





def get_phenotypes_entered_for_individual(indiv_id,project_id):
'''
Get phenotype data enterred for this individual.
Inputs:
indiv_id: an individual ID (ex: PIE-OGI855-001726)
'''
try:
uname,pwd = get_uname_pwd_for_project(project_id,read_only=True)
url = os.path.join(settings.PHENOPTIPS_HOST_NAME,'rest/patients/eid/' + indiv_id)
response = requests.get(url, auth=HTTPBasicAuth(uname,pwd))
return response.json()
except Exception as e:
print 'patient phenotype export error:',e
raise





def phenotype_entry_metric_for_individual(indiv_id, project_id):
'''
Determine a metric that describes the level of phenotype entry for this
individual.
Notes:
1. Phenotype terms appear in both features (where HPO terms exist)
and in nonstandard_features where phenotypes were defined in
regular text where HPO might not have existed.
Inputs:
indiv_id: an individual ID (ex: PIE-OGI855-001726)
'''
entered_phenotypes=get_phenotypes_entered_for_individual(indiv_id,project_id)
count=0
for k,v in entered_phenotypes.iteritems():
if k=='features' or k=='nonstandard_features':
count = count + len(v)
return count
38 changes: 38 additions & 0 deletions xbrowse_server/phenotips/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,44 @@ def fetch_phenotips_edit_page(request,eid):



@log_request('phenotips_proxy_pdf_page')
@login_required
@csrf_exempt
def fetch_phenotips_pdf_page(request,eid):
'''
A proxy for phenotips view and edit patient pages
Notes:
- Exempting csrf here since phenotips doesn't have this support
- Each call to this endpoint is atomic, no session information is kept
between calls. Each call to this is from within a new Frame, hence no
notion of session is kept. Each is a new login into PhenoTips.
'''
try:
current_user = request.user
project_id=request.GET['project']
uname,pwd = get_uname_pwd_for_project(project_id,read_only=True)
ext_id=convert_internal_id_to_external_id(eid,uname,pwd)
auth_level=get_auth_level(project_id,request.user)
if auth_level == 'unauthorized':
return HttpResponse('unauthorized')
url= settings.PHENOPTIPS_HOST_NAME + '/bin/export/data/' + ext_id + '?format=pdf&pdfcover=0&pdftoc=0&pdftemplate=PhenoTips.PatientSheetCode'
response,curr_session = do_authenticated_call_to_phenotips(url,uname,pwd)
http_response=HttpResponse(response.content)
for header in response.headers.keys():
if header != 'connection' and header != 'transfer-encoding': #these hop-by-hop headers are not allowed by Django
http_response[header]=response.headers[header]
return http_response
except Exception as e:
print e
raise Http404








@log_request('proxy_get')
@login_required
@csrf_exempt
Expand Down
27 changes: 23 additions & 4 deletions xbrowse_server/templates/family/family_home.html
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ <h4 class="section-header">Individuals</h4>
<th>Mother</th>
<th>Father</th>
{% if phenotips_supported %}
<th>Phenotips</th>
<th>PhenoTips</th>
{% endif %}
</tr>
</thead>
Expand All @@ -145,7 +145,12 @@ <h4 class="section-header">Individuals</h4>
<td>{% if indiv.maternal_id %}{{ indiv.maternal_id }}{% else %}-{% endif %}</td>
<td>{% if indiv.paternal_id %}{{ indiv.paternal_id }}{% else %}-{% endif %}</td>
{% if phenotips_supported %}
<td><button id={{ indiv }} type="button" class="btn btn-info btn-sm phenotipsEditModalBtn">Edit in Phenotips</button></td>
<td>
{% if user_is_admin %}
<button id={{ indiv }} type="button" class="btn btn-info btn-sm phenotipsEditModalBtn">Edit</button>
{% endif %}
<button id={{ indiv }} type="button" class="btn btn-info btn-sm phenotipsViewModalBtn">View</button>
</td>
{% endif %}
</tr>
{% endfor %}
Expand All @@ -161,7 +166,7 @@ <h4 class="section-header">Individuals</h4>
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Phenotips</h4>
<h4 class="modal-title">PhenoTips</h4>
</div>
<div class="modal-body"">
<iframe name="phenotipsEditPatientFrame" id="phenotipsEditPatientFrame" src="" width=1000 height=800 frameborder="0"></iframe>
Expand All @@ -170,18 +175,27 @@ <h4 class="modal-title">Phenotips</h4>
</div>
</div>
<script>
<!-- Edit page -->
$('.phenotipsEditModalBtn').on('click',function(event) {
var patientId=this.id;
var project_name="{{ project.project_id }}";
showEditPageForThisPatient(patientId,project_name);
});

//to capture modal close event relating to editing/viewing a phenotips patient page
$("#phenotipsModal").on("hidden.bs.modal",function() {
//clear up the existing frame so frame is black before next page loads
$('#phenotipsEditPatientFrame').attr('src', "about:blank");
});
</script>

<script>
<!-- View ONLY PDF page -->
$('.phenotipsViewModalBtn').on('click',function(event) {
var patientId=this.id;
var project_name="{{ project.project_id }}";
showViewPageForThisPatient(patientId,project_name);
});
</script>



Expand All @@ -202,6 +216,11 @@ <h4 class="modal-title">Phenotips</h4>
$('#phenotipsEditPatientFrame').attr('src', uri);
$('#phenotipsModal').modal('show');
}
function showViewPageForThisPatient(patientId,project) {
var uri = '/api/phenotips/proxy/view/' + patientId + '?' + 'project=' + project;
$('#phenotipsEditPatientFrame').attr('src', uri);
$('#phenotipsModal').modal('show');
}
</script>

<style>
Expand Down
28 changes: 28 additions & 0 deletions xbrowse_server/templates/project.html
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,34 @@ <h4 class="section-header">Results</h4>
<h5><a href="{% url 'add_tag' project.project_id %}">Create tag</a></h5>
</div>
</div>


{% if phenotips_supported and auth_level == 'admin'%}
<h4 class="section-header">Phenotype entry metrics</h4>
<div class="row">
<table class="table table-hover">
<tr>
<td><p>Count of HPO terms<p></td>
<td><p>0<p></td>
<td><p>1 to 10</p></td>
<td><p>11 to 20</p></td>
<td><p>21 to 30</p></td>
<td><p>More than 30</p></td>
</tr>
<tr>
<td><p>Individuals</p></td>
<td><p>{{ categorized_phenotype_counts.0|length }}</p></td>
<td><p>{{ categorized_phenotype_counts.1to10|length }}</p></td>
<td><p>{{ categorized_phenotype_counts.11to20|length }}</p></td>
<td><p>{{ categorized_phenotype_counts.21to30|length }}</p></td>
<td><p>{{ categorized_phenotype_counts.larger_than_31|length }}</p></td>
</tr>
</table>
</div>
{% endif %}



</div>
<div class="col-sm-4">
<h4 class="section-header">Project Settings</h4>
Expand Down

0 comments on commit 9d91606

Please sign in to comment.