|pypi| |actions| |codecov|
edc-reportable
--------------
Reportable clinic events, reference ranges, grading
.. code-block:: python
from dateutil.relativedelta import relativedelta
from edc_utils import get_utcnow
from edc_constants.constants import MALE, FEMALE
from edc_reportable import ValueReferenceGroup, NormalReference, GradeReference
from edc_reportable import site_reportables
from edc_reportable.tests.reportables import normal_data, grading_data
Create a group for each test:
.. code-block:: python
neutrophils = ValueReferenceGroup(name='neutrophils')
A normal reference is declared like this:
.. code-block:: python
ref = NormalReference(
name='neutrophils',
lower=2.5,
upper=7.5,
units='10e9/L',
age_lower=18,
age_upper=99,
age_units='years',
gender=[MALE, FEMALE])
>>> ref
NormalReference(neutrophils, 2.5<x<7.5 10e9/L MF, 18<AGE<99 years)
And added to a group like this:
.. code-block:: python
neutrophils.add_normal(ref)
Add as many normal references in a group as you like, just ensure the ``lower`` and ``upper`` boundaries don't overlap.
**Note**: If the lower and upper values of a normal reference overlap
with another normal reference in the same group, a ``BoundaryOverlap``
exception will be raised when the value is evaluated.
Catch this in your tests.
A grading reference is declared like this:
.. code-block:: python
g3 = GradeReference(
name='neutrophils',
grade=3,
lower=0.4,
lower_inclusive=True,
upper=0.59,
upper_inclusive=True,
units='10e9/L',
age_lower=18,
age_upper=99,
age_units='years',
gender=[MALE, FEMALE])
>>> g3
GradeReference(neutrophils, 0.4<=x<=0.59 in 10e9/L GRADE 3, MF, 18<AGE<99 in years) GRADE 3)
or using lower / upper limits of normal:
g3 = GradeReference(
name="amylase",
grade=1,
lower="3.0*ULN",
upper="5.0*ULN",
lower_inclusive=True,
upper_inclusive=False,
units=IU_LITER,
gender=MALE,
normal_references={MALE: [normal_reference]},
**adult_age_options)
>>> g3
GradeReference(amylase, 375.0<=x<625.0 IU/L GRADE 3) GRADE 3)
And added to the group like this:
.. code-block:: python
neutrophils.add_grading(g3)
Declare and add a ``GradeReference`` for each reportable grade of the test.
**Note**: If the lower and upper values of a grade reference overlap
with another grade reference in the same group, a ``BoundaryOverlap``
exception will be raised when the value is evaluated.
Catch this in your tests.
Declaring with ``parse``
========================
You may find using ``parse`` somewhat simplifies the declaration where ``lower``, ``lower_inclusive``, ``upper`` and ``upper_inclusive`` can be written as a phrase, like ``13.5<=x<=17.5``. For example:
.. code-block:: python
age_opts = dict(
age_lower=18,
age_upper=120,
age_units='years',
age_lower_inclusive=True,
age_upper_inclusive=True)
normal_data = {
'haemoglobin': [
p('13.5<=x<=17.5', units=GRAMS_PER_DECILITER,
gender=[MALE], **age_opts),
p('12.0<=x<=15.5', units=GRAMS_PER_DECILITER, gender=[FEMALE], **age_opts)],
...
}
Registering with ``site_reportables``
=====================================
Once you have declared all your references, register them
.. code-block:: python
site_reportables.register(
name='my_project',
normal_data=normal_data,
grading_data=grading_data)
**Important**:
Writing out references is prone to error. It is better to declare a
dictionary of normal references and grading references. Use the ``parse`` function
so that you can use a phrase like ``13.5<=x<=17.5`` instead of a listing attributes.
There are examples of complete ``normal_data`` and ``grading_data`` in the tests.
See``edc_reportable.tests.reportables``.
Attempting to grade a value without grading data
++++++++++++++++++++++++++++++++++++++++++++++++
If a value is pased to the evaluator and no grading data exists in the reference lists for
that test, an exception is raised.
Limiting what is "gradeable" for your project
+++++++++++++++++++++++++++++++++++++++++++++
The default tables have grading data for grades 1-4. The evaluator will grade any value
if there is grading data. You can prevent the evaluator from considering grades by passing
``reportable_grades`` when you register the normal and grading data.
For example:
.. code-block:: python
site_reportables.register(
name='my_project',
normal_data=normal_data,
grading_data=grading_data,
reportable_grades=[GRADE3, GRADE4],
)
In the above, by explicitly passing a list of grades, the evaluator will only raise an
exception for grades 3 and 4. If a value meets the criteria for grade 1 or 2, it will be ignored.
Declaring minor exceptions
++++++++++++++++++++++++++
Minor exceptions can be specified using the parameter ``reportable_grades_exceptions``.
For example, you wish to report grades 2,3,4 for Serum Amylase
but grades 3,4 for everything else. You would register as follows:
.. code-block:: python
site_reportables.register(
name='my_project',
normal_data=normal_data,
grading_data=grading_data,
reportable_grades=[GRADE3, GRADE4],
reportable_grades_exceptions={"amylase": [GRADE2, GRADE3, GRADE4]}
)
Exporting the reference tables
++++++++++++++++++++++++++++++
You can export your declared references to CSV for further inspection
.. code-block:: python
>>> site_reportables.to_csv(name='my_project', path='~/')
('/Users/erikvw/my_project_normal_ranges.csv',
'/Users/erikvw/my_project_grading.csv')
Using your reportables
======================
In your code, get the references by collection name:
.. code-block:: python
my_project_reportables = site_reportables.get('my_project')
neutrophil = my_project_reportables.get('neutrophil')
report_datetime = get_utcnow()
dob = (report_datetime - relativedelta(years=25)).date()
Check a normal value
====================
If a value is normal, ``get_normal`` returns the ``NormalReference`` instance that matched with the value.
.. code-block:: python
# evaluate a normal value
normal = neutrophil.get_normal(
value=3.5, units='10^9/L',
gender=MALE, dob=dob, report_datetime=report_datetime)
# returns a normal object with information about the range selected
>>> normal.description
'2.5<=3.5<=7.5 10^9/L MF, 18<=AGE years'
Check an abnormal value
=======================
If a value is abnormal, ``get_normal`` returns ``None``.
.. code-block:: python
# evaluate an abnormal value
opts = dict(
units='10^9/L',
gender=MALE, dob=dob,
report_datetime=report_datetime)
normal = neutrophil.get_normal(value=0.3, **opts)
# returns None
>>> if not normal:
print('abnormal')
'abnormal'
To show which ranges the value was evaluated against
.. code-block:: python
# use same options for units, gender, dob, report_datetime
>>> neutrophil.get_normal_description(**opts)
['2.5<=x<=7.5 10^9/L MF, 18<=AGE years']
Check if a value is "reportable"
================================
.. code-block:: python
grade = neutrophil.get_grade(
value=0.43, units='10^9/L',
gender=MALE, dob=dob, report_datetime=report_datetime)
>>> grade.grade
3
>>> grade.description
'0.4<=0.43<=0.59 10^9/L GRADE 3'
grade = neutrophil.get_grade(
value=0.3, units='10^9/L',
gender=MALE, dob=dob, report_datetime=report_datetime)
>>> grade.grade
4
>>> grade.description
'0.3<0.4 10^9/L GRADE 4'
If the value is not evaluated against any reportable ranges, a ``NotEvaluated`` exception is raised
.. code-block:: python
# call with the wrong units
>>> grade = neutrophil.get_grade(
value=0.3, units='mmol/L',
gender=MALE, dob=dob, report_datetime=report_datetime)
NotEvaluated: neutrophil value not graded. No reference range found ...
.. |pypi| image:: https://img.shields.io/pypi/v/edc-reportable.svg
:target: https://pypi.python.org/pypi/edc-reportable
.. |actions| image:: https://github.com/clinicedc/edc-reportable/actions/workflows/build.yml/badge.svg
:target: https://github.com/clinicedc/edc-reportable/actions/workflows/build.yml
.. |codecov| image:: https://codecov.io/gh/clinicedc/edc-reportable/branch/develop/graph/badge.svg
:target: https://codecov.io/gh/clinicedc/edc-reportable
Raw data
{
"_id": null,
"home_page": "https://github.com/clinicedc/edc-reportable",
"name": "edc-reportable",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.12",
"maintainer_email": null,
"keywords": "django, edc, DAIDS, reference ranges, normal ranges, clinicedc, clinical trials",
"author": "Erik van Widenfelt",
"author_email": "ew2789@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/98/47/85d00daaee8256f91927454310b50ca57e8e04917e8604beb3db29dab44f/edc_reportable-0.3.40.tar.gz",
"platform": null,
"description": "|pypi| |actions| |codecov|\n\nedc-reportable\n--------------\n\nReportable clinic events, reference ranges, grading\n\n.. code-block:: python\n\n from dateutil.relativedelta import relativedelta\n from edc_utils import get_utcnow\n from edc_constants.constants import MALE, FEMALE\n from edc_reportable import ValueReferenceGroup, NormalReference, GradeReference\n from edc_reportable import site_reportables\n from edc_reportable.tests.reportables import normal_data, grading_data\n\nCreate a group for each test:\n\n.. code-block:: python\n\n neutrophils = ValueReferenceGroup(name='neutrophils')\n\nA normal reference is declared like this:\n\n.. code-block:: python\n\n ref = NormalReference(\n name='neutrophils',\n lower=2.5,\n upper=7.5,\n units='10e9/L',\n age_lower=18,\n age_upper=99,\n age_units='years',\n gender=[MALE, FEMALE])\n\n >>> ref\n NormalReference(neutrophils, 2.5<x<7.5 10e9/L MF, 18<AGE<99 years)\n\nAnd added to a group like this:\n\n.. code-block:: python\n\n neutrophils.add_normal(ref)\n\nAdd as many normal references in a group as you like, just ensure the ``lower`` and ``upper`` boundaries don't overlap.\n\n **Note**: If the lower and upper values of a normal reference overlap\n with another normal reference in the same group, a ``BoundaryOverlap``\n exception will be raised when the value is evaluated.\n Catch this in your tests.\n\nA grading reference is declared like this:\n\n.. code-block:: python\n\n g3 = GradeReference(\n name='neutrophils',\n grade=3,\n lower=0.4,\n lower_inclusive=True,\n upper=0.59,\n upper_inclusive=True,\n units='10e9/L',\n age_lower=18,\n age_upper=99,\n age_units='years',\n gender=[MALE, FEMALE])\n\n >>> g3\n GradeReference(neutrophils, 0.4<=x<=0.59 in 10e9/L GRADE 3, MF, 18<AGE<99 in years) GRADE 3)\n\n or using lower / upper limits of normal:\n\n g3 = GradeReference(\n name=\"amylase\",\n grade=1,\n lower=\"3.0*ULN\",\n upper=\"5.0*ULN\",\n lower_inclusive=True,\n upper_inclusive=False,\n units=IU_LITER,\n gender=MALE,\n normal_references={MALE: [normal_reference]},\n **adult_age_options)\n\n >>> g3\n GradeReference(amylase, 375.0<=x<625.0 IU/L GRADE 3) GRADE 3)\n\nAnd added to the group like this:\n\n.. code-block:: python\n\n neutrophils.add_grading(g3)\n\nDeclare and add a ``GradeReference`` for each reportable grade of the test.\n\n **Note**: If the lower and upper values of a grade reference overlap\n with another grade reference in the same group, a ``BoundaryOverlap``\n exception will be raised when the value is evaluated.\n Catch this in your tests.\n\n\nDeclaring with ``parse``\n========================\n\nYou may find using ``parse`` somewhat simplifies the declaration where ``lower``, ``lower_inclusive``, ``upper`` and ``upper_inclusive`` can be written as a phrase, like ``13.5<=x<=17.5``. For example:\n\n.. code-block:: python\n\n age_opts = dict(\n age_lower=18,\n age_upper=120,\n age_units='years',\n age_lower_inclusive=True,\n age_upper_inclusive=True)\n\n normal_data = {\n 'haemoglobin': [\n p('13.5<=x<=17.5', units=GRAMS_PER_DECILITER,\n gender=[MALE], **age_opts),\n p('12.0<=x<=15.5', units=GRAMS_PER_DECILITER, gender=[FEMALE], **age_opts)],\n ...\n }\n\n\nRegistering with ``site_reportables``\n=====================================\n\nOnce you have declared all your references, register them\n\n.. code-block:: python\n\n site_reportables.register(\n name='my_project',\n normal_data=normal_data,\n grading_data=grading_data)\n\n\n\n**Important**:\n Writing out references is prone to error. It is better to declare a\n dictionary of normal references and grading references. Use the ``parse`` function\n so that you can use a phrase like ``13.5<=x<=17.5`` instead of a listing attributes.\n There are examples of complete ``normal_data`` and ``grading_data`` in the tests.\n See``edc_reportable.tests.reportables``.\n\nAttempting to grade a value without grading data\n++++++++++++++++++++++++++++++++++++++++++++++++\nIf a value is pased to the evaluator and no grading data exists in the reference lists for\nthat test, an exception is raised.\n\nLimiting what is \"gradeable\" for your project\n+++++++++++++++++++++++++++++++++++++++++++++\nThe default tables have grading data for grades 1-4. The evaluator will grade any value\nif there is grading data. You can prevent the evaluator from considering grades by passing\n``reportable_grades`` when you register the normal and grading data.\n\nFor example:\n\n.. code-block:: python\n\n site_reportables.register(\n name='my_project',\n normal_data=normal_data,\n grading_data=grading_data,\n reportable_grades=[GRADE3, GRADE4],\n )\n\nIn the above, by explicitly passing a list of grades, the evaluator will only raise an\nexception for grades 3 and 4. If a value meets the criteria for grade 1 or 2, it will be ignored.\n\nDeclaring minor exceptions\n++++++++++++++++++++++++++\n\nMinor exceptions can be specified using the parameter ``reportable_grades_exceptions``.\nFor example, you wish to report grades 2,3,4 for Serum Amylase\nbut grades 3,4 for everything else. You would register as follows:\n\n.. code-block:: python\n\n site_reportables.register(\n name='my_project',\n normal_data=normal_data,\n grading_data=grading_data,\n reportable_grades=[GRADE3, GRADE4],\n reportable_grades_exceptions={\"amylase\": [GRADE2, GRADE3, GRADE4]}\n )\n\n\n\nExporting the reference tables\n++++++++++++++++++++++++++++++\n\nYou can export your declared references to CSV for further inspection\n\n.. code-block:: python\n\n >>> site_reportables.to_csv(name='my_project', path='~/')\n\n ('/Users/erikvw/my_project_normal_ranges.csv',\n '/Users/erikvw/my_project_grading.csv')\n\nUsing your reportables\n======================\n\nIn your code, get the references by collection name:\n\n.. code-block:: python\n\n my_project_reportables = site_reportables.get('my_project')\n\n neutrophil = my_project_reportables.get('neutrophil')\n\n report_datetime = get_utcnow()\n dob = (report_datetime - relativedelta(years=25)).date()\n\nCheck a normal value\n====================\n\nIf a value is normal, ``get_normal`` returns the ``NormalReference`` instance that matched with the value.\n\n.. code-block:: python\n\n # evaluate a normal value\n normal = neutrophil.get_normal(\n value=3.5, units='10^9/L',\n gender=MALE, dob=dob, report_datetime=report_datetime)\n\n # returns a normal object with information about the range selected\n >>> normal.description\n '2.5<=3.5<=7.5 10^9/L MF, 18<=AGE years'\n\nCheck an abnormal value\n=======================\n\nIf a value is abnormal, ``get_normal`` returns ``None``.\n\n.. code-block:: python\n\n # evaluate an abnormal value\n opts = dict(\n units='10^9/L',\n gender=MALE, dob=dob,\n report_datetime=report_datetime)\n normal = neutrophil.get_normal(value=0.3, **opts)\n\n # returns None\n >>> if not normal:\n print('abnormal')\n 'abnormal'\n\nTo show which ranges the value was evaluated against\n\n.. code-block:: python\n\n # use same options for units, gender, dob, report_datetime\n >>> neutrophil.get_normal_description(**opts)\n ['2.5<=x<=7.5 10^9/L MF, 18<=AGE years']\n\nCheck if a value is \"reportable\"\n================================\n\n.. code-block:: python\n\n grade = neutrophil.get_grade(\n value=0.43, units='10^9/L',\n gender=MALE, dob=dob, report_datetime=report_datetime)\n\n >>> grade.grade\n 3\n\n >>> grade.description\n '0.4<=0.43<=0.59 10^9/L GRADE 3'\n\n grade = neutrophil.get_grade(\n value=0.3, units='10^9/L',\n gender=MALE, dob=dob, report_datetime=report_datetime)\n\n >>> grade.grade\n 4\n\n >>> grade.description\n '0.3<0.4 10^9/L GRADE 4'\n\nIf the value is not evaluated against any reportable ranges, a ``NotEvaluated`` exception is raised\n\n.. code-block:: python\n\n # call with the wrong units\n\n >>> grade = neutrophil.get_grade(\n value=0.3, units='mmol/L',\n gender=MALE, dob=dob, report_datetime=report_datetime)\n\n NotEvaluated: neutrophil value not graded. No reference range found ...\n\n.. |pypi| image:: https://img.shields.io/pypi/v/edc-reportable.svg\n :target: https://pypi.python.org/pypi/edc-reportable\n\n.. |actions| image:: https://github.com/clinicedc/edc-reportable/actions/workflows/build.yml/badge.svg\n :target: https://github.com/clinicedc/edc-reportable/actions/workflows/build.yml\n\n.. |codecov| image:: https://codecov.io/gh/clinicedc/edc-reportable/branch/develop/graph/badge.svg\n :target: https://codecov.io/gh/clinicedc/edc-reportable\n",
"bugtrack_url": null,
"license": "GPL license, see LICENSE",
"summary": "Reportable clinic events, reference ranges, grading for clinicedc/edc projects",
"version": "0.3.40",
"project_urls": {
"Homepage": "https://github.com/clinicedc/edc-reportable"
},
"split_keywords": [
"django",
" edc",
" daids",
" reference ranges",
" normal ranges",
" clinicedc",
" clinical trials"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "1c04b30a89c09aa78428c439996f37da6d600dadeb3af928a688a9e1ec3052ec",
"md5": "3d36a6fc853de80cadc16229cb95f0a9",
"sha256": "8fe4a2d6457b079d4032603913732148977b35cee709468e7bf408bba9b64cee"
},
"downloads": -1,
"filename": "edc_reportable-0.3.40-py3-none-any.whl",
"has_sig": false,
"md5_digest": "3d36a6fc853de80cadc16229cb95f0a9",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.12",
"size": 60359,
"upload_time": "2024-11-20T22:32:32",
"upload_time_iso_8601": "2024-11-20T22:32:32.307564Z",
"url": "https://files.pythonhosted.org/packages/1c/04/b30a89c09aa78428c439996f37da6d600dadeb3af928a688a9e1ec3052ec/edc_reportable-0.3.40-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "984785d00daaee8256f91927454310b50ca57e8e04917e8604beb3db29dab44f",
"md5": "3b5cca3e758e458369cb0037cfee72c2",
"sha256": "eb535717652f639c87b5987fd9aca0c5973d8300f56590067f22155f152233a9"
},
"downloads": -1,
"filename": "edc_reportable-0.3.40.tar.gz",
"has_sig": false,
"md5_digest": "3b5cca3e758e458369cb0037cfee72c2",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.12",
"size": 53638,
"upload_time": "2024-11-20T22:32:34",
"upload_time_iso_8601": "2024-11-20T22:32:34.171101Z",
"url": "https://files.pythonhosted.org/packages/98/47/85d00daaee8256f91927454310b50ca57e8e04917e8604beb3db29dab44f/edc_reportable-0.3.40.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-11-20 22:32:34",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "clinicedc",
"github_project": "edc-reportable",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"lcname": "edc-reportable"
}