Skip to content

Commit

Permalink
Add SMART LabPanel
Browse files Browse the repository at this point in the history
- fixes chb#44
  • Loading branch information
Travers Franckle committed Dec 31, 2012
1 parent 0288bba commit 1e6b8eb
Show file tree
Hide file tree
Showing 20 changed files with 1,225 additions and 55 deletions.
41 changes: 41 additions & 0 deletions indivo/data_models/core/lab_panel/example.sdmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<Models xmlns="http://indivo.org/vocab/xml/documents#">
<Model name="LabPanel">
<Field name="lab_results">
<Models>
<Model name="LabResult">
<Field name="date">2009-05-16T12:00:00Z</Field>

<Field name="abnormal_interpretation_code_title">Normal</Field>
<Field name="abnormal_interpretation_code_system">http://smartplatforms.org/terms/codes/LabResultInterpretation#</Field>
<Field name="abnormal_interpretation_code_identifier">normal</Field>

<Field name="accession_number">AC09205823577</Field>

<Field name="name_title">Serum Sodium</Field>
<Field name="name_code_title">Serum Sodium</Field>
<Field name="name_code_system">http://purl.bioontology.org/ontology/LNC/</Field>
<Field name="name_code_identifier">2951-2</Field>

<Field name="status_code_title">Final results: complete and verified</Field>
<Field name="status_code_system">http://smartplatforms.org/terms/codes/LabStatus#</Field>
<Field name="status_code_identifier">final</Field>

<Field name="notes">Blood sample appears to have hemolyzed</Field>

<Field name="quantitative_result_non_critical_range_max_value">155</Field>
<Field name="quantitative_result_non_critical_range_max_unit">mEq/L</Field>
<Field name="quantitative_result_non_critical_range_min_value">120</Field>
<Field name="quantitative_result_non_critical_range_min_unit">mEq/L</Field>

<Field name="quantitative_result_normal_range_max_value">145</Field>
<Field name="quantitative_result_normal_range_max_unit">mEq/L</Field>
<Field name="quantitative_result_normal_range_min_value">135</Field>
<Field name="quantitative_result_normal_range_min_unit">mEq/L</Field>

<Field name="quantitative_result_value_value">140</Field>
<Field name="quantitative_result_value_unit">mEq/L</Field>
</Model>
</Models>
</Field>
</Model>
</Models>
19 changes: 19 additions & 0 deletions indivo/data_models/core/lab_panel/extra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from indivo.serializers import DataModelSerializers
from indivo.validators import ValueInSetValidator, ExactValueValidator, NonNullValidator
from indivo.data_models.options import DataModelOptions
from indivo.lib.rdf import PatientGraph

LOINC_URI="http://purl.bioontology.org/ontology/LNC/"

class LabPanelSerializers(DataModelSerializers):
def to_rdf(query, record=None, carenet=None):
if not record:
record = carenet.record
graph = PatientGraph(record)
resultOrder = graph.addLabPanelList(query.results.iterator(), True if query.limit else False)
graph.addResponseSummary(query, resultOrder)
return graph.toRDF()

class LabPanelOptions(DataModelOptions):
model_class_name = 'LabPanel'
serializers = LabPanelSerializers
7 changes: 7 additions & 0 deletions indivo/data_models/core/lab_panel/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from indivo.models import Fact
from django.db import models
from indivo.fields import CodedValueField

class LabPanel(Fact):
name = CodedValueField()

File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@
'final',
]

class LabSerializers(DataModelSerializers):
class LabResultSerializers(DataModelSerializers):
def to_rdf(query, record=None, carenet=None):
if not record:
record = carenet.record
graph = PatientGraph(record)
resultOrder = graph.addLabList(query.results.iterator(), True if query.limit else False)
resultOrder = graph.addLabResultList(query.results.iterator(), True if query.limit else False)
graph.addResponseSummary(query, resultOrder)
return graph.toRDF()

class LabOptions(DataModelOptions):
class LabResultOptions(DataModelOptions):
model_class_name = 'LabResult'
serializers = LabSerializers
serializers = LabResultSerializers
field_validators = {
'abnormal_interpretation_code_system': [ExactValueValidator(LAB_INTERP_URI, nullable=True)],
'abnormal_interpretation_code_identifier': [ValueInSetValidator(VALID_INTERPS, nullable=True)],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ class LabResult(Fact):
status = CodedValueField()
narrative_result = models.CharField(max_length=255, null=True)
notes = models.CharField(max_length=600, null=True)
quantitative_result = QuantitativeResultField()
quantitative_result = QuantitativeResultField()
lab_panel = models.ForeignKey('LabPanel', null=True, related_name='lab_results')
File renamed without changes.
104 changes: 70 additions & 34 deletions indivo/lib/rdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,35 @@ def addImmunizationList(self, immunizations, order_results=False):

return immunization_list_node

def addLabList(self, labs, order_results=False):
def addLabPanelList(self, lab_panels, order_results=False):
"""Adds Lab Panels to the patient's graph"""

g = self.g
panel_list_node = None

if order_results:
# build an ordered list if requested
panel_list_node = BNode()
panel_collection = Collection(g, panel_list_node, [])

for panel in lab_panels:
panel_node = URIRef(panel.uri('lab_panels'))
g.add((panel_node, RDF.type, SP['LabPanel']))
if order_results:
panel_collection.append(panel_node)

lab_name = self._getCodedValueFromField(panel, 'name', [SPCODE['LOINC']])
if lab_name:
g.add((panel_node , SP['labName'], self.newCodedValue(lab_name)))

for lab_result in panel.lab_results.all().iterator():
result_node = self.lab_result(lab_result)
g.add((panel_node, SP['labResult'], result_node))
self.addStatement(result_node)

return panel_list_node

def addLabResultList(self, labs, order_results=False):
"""Adds Lab Results to the patient's graph"""
g = self.g
lab_list_node = None
Expand All @@ -393,42 +421,11 @@ def addLabList(self, labs, order_results=False):
lab_collection = Collection(g, lab_list_node, [])

for lab in labs:
lNode = URIRef(lab.uri('lab_results'))
g.add((lNode, RDF.type, SP['LabResult']))
lNode = self.lab_result(lab)
self.addStatement(lNode)
if order_results:
lab_collection.append(lNode)

lab_name = self._getCodedValueFromField(lab, 'name', [SPCODE['LOINC']])
g.add((lNode , SP['labName'], self.newCodedValue(lab_name)))

g.add((lNode, DCTERMS['date'], Literal(lab.date)))

abnormal_interpretation = self._getCodedValueFromField(lab, 'abnormal_interpretation', [SPCODE['LabResultInterpretation']])
if abnormal_interpretation:
g.add((lNode, SP['abnormalInterpretation'], self.newCodedValue(abnormal_interpretation)))

if lab.accession_number:
g.add((lNode, SP['accessionNumber'], Literal(lab.accession_number)))

lab_status = self._getCodedValueFromField(lab, 'status', [SPCODE['LabResultStatus']])
if lab_status:
g.add((lNode, SP['labStatus'], self.newCodedValue(lab_status)))

if lab.narrative_result:
nrNode = BNode()
g.add((nrNode, RDF.type, SP['NarrativeResult']))
g.add((nrNode, SP['value'], Literal(lab.narrative_result)))
g.add((lNode, SP['narrativeResult'], nrNode))

if lab.notes:
g.add((lNode, SP['notes'], Literal(lab.notes)))

qrNode = self.quantitativeResult(lab, 'quantitative_result')
if qrNode:
g.add((lNode, SP['quantitativeResult'], qrNode))

self.addStatement(lNode)

return lab_list_node

def addCombinedAllergyList(self, combinedAllergies, order_results=False):
Expand Down Expand Up @@ -644,6 +641,45 @@ def encounter(self, encounter):
g.add((eNode, SP['encounterType'], self.newCodedValue(encounter_type)))
return eNode

def lab_result(self, lab):
""" Build a Medication, but don't add fills and don't link it to the patient. Returns the med node. """
g = self.g
if not lab: return

lNode = URIRef(lab.uri('lab_results'))
g.add((lNode, RDF.type, SP['LabResult']))

lab_name = self._getCodedValueFromField(lab, 'name', [SPCODE['LOINC']])
g.add((lNode , SP['labName'], self.newCodedValue(lab_name)))

g.add((lNode, DCTERMS['date'], Literal(lab.date)))

abnormal_interpretation = self._getCodedValueFromField(lab, 'abnormal_interpretation', [SPCODE['LabResultInterpretation']])
if abnormal_interpretation:
g.add((lNode, SP['abnormalInterpretation'], self.newCodedValue(abnormal_interpretation)))

if lab.accession_number:
g.add((lNode, SP['accessionNumber'], Literal(lab.accession_number)))

lab_status = self._getCodedValueFromField(lab, 'status', [SPCODE['LabResultStatus']])
if lab_status:
g.add((lNode, SP['labStatus'], self.newCodedValue(lab_status)))

if lab.narrative_result:
nrNode = BNode()
g.add((nrNode, RDF.type, SP['NarrativeResult']))
g.add((nrNode, SP['value'], Literal(lab.narrative_result)))
g.add((lNode, SP['narrativeResult'], nrNode))

if lab.notes:
g.add((lNode, SP['notes'], Literal(lab.notes)))

qrNode = self.quantitativeResult(lab, 'quantitative_result')
if qrNode:
g.add((lNode, SP['quantitativeResult'], qrNode))

return lNode

def medication(self, m):
""" Build a Medication, but don't add fills and don't link it to the patient. Returns the med node. """
g = self.g
Expand Down
7 changes: 5 additions & 2 deletions indivo/lib/view_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ def parse_date_group(value):
field, time_incr = value.split('*')
return {'field':field, 'time_incr':time_incr}

def parse_date(value):
return iso8601.parse_utc_date(value)

check_safety()

parse_map = {
Expand All @@ -69,8 +72,8 @@ def parse_date_group(value):
'aggregate_by': parse_aggregate_by,
'date_range': parse_date_range,
'date_group': parse_date_group,
'date_from': parse_string, # SMART v0.5, transformed to date_range in smart views
'date_to': parse_string, # SMART v0.5, transformed to date_range in smart views
'date_from': parse_date, # SMART v0.5, transformed to date_range in smart views
'date_to': parse_date, # SMART v0.5, transformed to date_range in smart views
}

ignore_map = {
Expand Down
Loading

0 comments on commit 1e6b8eb

Please sign in to comment.