meta-edc 1.0.6__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meta_ae/action_items.py +10 -2
- meta_ae/baker_recipes.py +1 -2
- meta_ae/tests/tests/test_actions.py +1 -2
- meta_analytics/dataframes/__init__.py +3 -0
- meta_analytics/dataframes/constants.py +1 -1
- meta_analytics/dataframes/get_eos_df.py +15 -2
- meta_analytics/dataframes/get_glucose_df.py +149 -0
- meta_analytics/dataframes/get_glucose_fbg_df.py +27 -0
- meta_analytics/dataframes/get_glucose_fbg_ogtt_df.py +22 -0
- meta_analytics/dataframes/glucose_endpoints/endpoint_by_date.py +106 -120
- meta_analytics/dataframes/glucose_endpoints/glucose_endpoints_by_date.py +36 -227
- meta_analytics/dataframes/utils.py +18 -4
- meta_analytics/notebooks/anu.ipynb +95 -0
- meta_analytics/notebooks/appointment_planning.ipynb +329 -0
- meta_analytics/notebooks/arvs.ipynb +103 -0
- meta_analytics/notebooks/cleaning/consent_v1_ext.ipynb +227 -0
- meta_analytics/notebooks/cleaning/offschedule_eos.ipynb +353 -0
- meta_analytics/notebooks/dsmc/renal_dysfunction.ipynb +435 -0
- meta_analytics/notebooks/endpoints/meta_endpoints_by_date.ipynb +664 -0
- meta_analytics/notebooks/followup_examination.ipynb +141 -0
- meta_analytics/notebooks/hba1c.ipynb +136 -0
- meta_analytics/notebooks/hiv_regimens.ipynb +429 -0
- meta_analytics/notebooks/incidence.ipynb +232 -0
- meta_analytics/notebooks/liver.ipynb +389 -0
- meta_analytics/notebooks/magreth.ipynb +645 -0
- meta_analytics/notebooks/monitoring_report.ipynb +1751 -0
- meta_analytics/notebooks/pharmacy.ipynb +1070 -0
- meta_analytics/notebooks/pharmacy_stock_202410.ipynb +306 -0
- meta_analytics/notebooks/steering.ipynb +61 -0
- meta_analytics/notebooks/undiagnosed/meta3_screening_consort_chart.ipynb +1176 -0
- meta_analytics/notebooks/undiagnosed/meta3_screening_undiagnosed.ipynb +519 -0
- meta_analytics/notebooks/undiagnosed/meta_screening_table2.ipynb +964 -0
- meta_analytics/notebooks/undiagnosed/screen_undiagnosed_or.ipynb +296 -0
- meta_analytics/notebooks/undiagnosed/screening.ipynb +273 -0
- meta_analytics/notebooks/undiagnosed/screening2.ipynb +958 -0
- meta_analytics/notebooks/undiagnosed/screening_undiagnosed_20241002.ipynb +958 -0
- meta_analytics/notebooks/ven.ipynb +191 -0
- meta_analytics/notebooks/vitals.ipynb +263 -0
- meta_analytics/utils.py +81 -0
- meta_edc/settings/debug.py +3 -2
- meta_edc/urls.py +1 -0
- {meta_edc-1.0.6.dist-info → meta_edc-1.1.0.dist-info}/METADATA +6 -5
- {meta_edc-1.0.6.dist-info → meta_edc-1.1.0.dist-info}/RECORD +77 -36
- {meta_edc-1.0.6.dist-info → meta_edc-1.1.0.dist-info}/WHEEL +1 -1
- meta_edc-1.1.0.dist-info/licenses/AUTHORS.rst +8 -0
- meta_labs/reportables.py +14 -11
- meta_labs/tests/test_reportables.py +33 -12
- meta_pharmacy/notebooks/pharmacy.ipynb +41 -0
- meta_prn/migrations/0063_historicaloffstudymedication_singleton_field_and_more.py +37 -0
- meta_prn/migrations/0064_auto_20250602_2143.py +18 -0
- meta_prn/models/end_of_study.py +2 -0
- meta_prn/models/off_study_medication.py +2 -0
- meta_reports/migrations/0054_auto_20250422_2003.py +81 -0
- meta_reports/migrations/0055_alter_glucosesummary_table.py +17 -0
- meta_reports/migrations/0056_auto_20250422_2214.py +54 -0
- meta_reports/migrations/0057_auto_20250422_2224.py +54 -0
- meta_reports/migrations/0058_auto_20250422_2232.py +54 -0
- meta_reports/models/dbviews/glucose_summary/unmanaged_model.py +13 -1
- meta_reports/models/dbviews/glucose_summary/view_definition.py +8 -5
- meta_screening/eligibility/eligibility_part_three/base_eligibility_part_three.py +59 -47
- meta_screening/form_validators/screening_part_three.py +6 -1
- meta_screening/tests/meta_test_case_mixin.py +3 -0
- meta_screening/tests/tests/test_forms.py +9 -2
- meta_screening/tests/tests/test_screening_part_three.py +11 -14
- meta_subject/action_items.py +1 -2
- meta_subject/choices.py +2 -1
- meta_subject/form_validators/glucose_form_validator.py +16 -1
- meta_subject/forms/blood_results/blood_results_rft_form.py +60 -3
- meta_subject/forms/study_medication_form.py +5 -3
- meta_subject/migrations/0221_auto_20250402_1913.py +42 -0
- meta_subject/migrations/0222_alter_historicalstudymedication_stock_codes_and_more.py +46 -0
- meta_subject/migrations/0223_bloodresultsfbc_errors_bloodresultsgludummy_errors_and_more.py +83 -0
- meta_subject/migrations/0224_bloodresultsfbc_abnormal_summary_and_more.py +153 -0
- meta_subject/tests/tests/test_egfr.py +5 -5
- meta_analytics/dataframes/enrolled/__init__.py +0 -1
- meta_analytics/dataframes/enrolled/get_glucose_df.py +0 -122
- /meta_edc-1.0.6.dist-info/AUTHORS → /meta_analytics/dataframes/glucose_endpoints/utils.py +0 -0
- {meta_edc-1.0.6.dist-info → meta_edc-1.1.0.dist-info/licenses}/LICENSE +0 -0
- {meta_edc-1.0.6.dist-info → meta_edc-1.1.0.dist-info}/top_level.txt +0 -0
@@ -3,21 +3,78 @@ from django.utils.safestring import mark_safe
|
|
3
3
|
from edc_action_item.forms import ActionItemCrfFormMixin
|
4
4
|
from edc_crf.crf_form_validator import CrfFormValidator
|
5
5
|
from edc_crf.modelform_mixins import CrfModelFormMixin
|
6
|
+
from edc_egfr.form_validator_mixins import EgfrCkdEpiFormValidatorMixin
|
6
7
|
from edc_lab_panel.panels import rft_panel
|
7
8
|
from edc_lab_results.form_validator_mixins import BloodResultsFormValidatorMixin
|
8
|
-
from
|
9
|
+
from edc_registration.models import RegisteredSubject
|
10
|
+
from edc_utils import age
|
11
|
+
from edc_visit_schedule.utils import is_baseline
|
12
|
+
from edc_vitals.form_validators import BmiFormValidatorMixin
|
9
13
|
|
10
|
-
from
|
14
|
+
from meta_visit_schedule.constants import DAY1
|
15
|
+
|
16
|
+
from ...models import BloodResultsRft, FollowupVitals, PhysicalExam, SubjectVisit
|
11
17
|
|
12
18
|
|
13
19
|
class BloodResultsRftFormValidator(
|
14
|
-
BloodResultsFormValidatorMixin,
|
20
|
+
BloodResultsFormValidatorMixin,
|
21
|
+
EgfrCkdEpiFormValidatorMixin,
|
22
|
+
BmiFormValidatorMixin,
|
23
|
+
CrfFormValidator,
|
15
24
|
):
|
16
25
|
panel = rft_panel
|
17
26
|
|
18
27
|
def clean(self):
|
19
28
|
super().clean()
|
20
29
|
self.validate_bmi()
|
30
|
+
if self.cleaned_data.get("creatinine_value") and self.cleaned_data.get(
|
31
|
+
"creatinine_units"
|
32
|
+
):
|
33
|
+
|
34
|
+
if is_baseline(self.related_visit):
|
35
|
+
baseline_egfr_value = None
|
36
|
+
else:
|
37
|
+
baseline_visit = SubjectVisit.objects.get(
|
38
|
+
subject_identifier=self.related_visit.subject_identifier,
|
39
|
+
visit_code=DAY1,
|
40
|
+
visit_code_sequence=0,
|
41
|
+
)
|
42
|
+
baseline_egfr_value = BloodResultsRft.objects.get(
|
43
|
+
subject_visit=baseline_visit
|
44
|
+
).egfr_value
|
45
|
+
rs = RegisteredSubject.objects.get(
|
46
|
+
subject_identifier=self.related_visit.subject_identifier
|
47
|
+
)
|
48
|
+
age_in_years = age(rs.dob, self.report_datetime).years
|
49
|
+
|
50
|
+
self.validate_egfr(
|
51
|
+
gender=rs.gender,
|
52
|
+
age_in_years=age_in_years,
|
53
|
+
ethnicity=rs.ethnicity,
|
54
|
+
weight_in_kgs=self.get_weight_in_kgs(),
|
55
|
+
baseline_egfr_value=baseline_egfr_value,
|
56
|
+
)
|
57
|
+
|
58
|
+
def get_weight_in_kgs(self) -> float | None:
|
59
|
+
if is_baseline(self.related_visit):
|
60
|
+
obj = (
|
61
|
+
PhysicalExam.objects.filter(
|
62
|
+
subject_visit=self.related_visit, weight__isnull=False
|
63
|
+
)
|
64
|
+
.order_by("report_datetime")
|
65
|
+
.last()
|
66
|
+
)
|
67
|
+
else:
|
68
|
+
obj = (
|
69
|
+
FollowupVitals.objects.filter(
|
70
|
+
subject_visit=self.related_visit, weight__isnull=False
|
71
|
+
)
|
72
|
+
.order_by("report_datetime")
|
73
|
+
.last()
|
74
|
+
)
|
75
|
+
if obj:
|
76
|
+
return obj.weight
|
77
|
+
return None
|
21
78
|
|
22
79
|
|
23
80
|
class BloodResultsRftForm(ActionItemCrfFormMixin, CrfModelFormMixin, forms.ModelForm):
|
@@ -38,16 +38,18 @@ class StudyMedicationFormValidator(BaseStudyMedicationFormValidator):
|
|
38
38
|
|
39
39
|
def validate_stock_codes_are_dispensed(self):
|
40
40
|
if self.cleaned_data.get("stock_codes"):
|
41
|
-
pattern = re.compile("^([A-Z0-9]{6})(,[A-Z0-9]{6})*$")
|
41
|
+
# pattern = re.compile("^([A-Z0-9]{6})(,[A-Z0-9]{6})*$")
|
42
|
+
pattern = re.compile("^([A-Z0-9]{6})(\r\n[A-Z0-9]{6})*$")
|
42
43
|
if not pattern.match(self.cleaned_data.get("stock_codes")):
|
43
44
|
raise forms.ValidationError(
|
44
45
|
{
|
45
46
|
"stock_codes": (
|
46
|
-
"Invalid format. Enter one or more valid codes
|
47
|
+
"Invalid format. Enter one or more valid codes. "
|
48
|
+
"One code per line only. No commas, spaces, etc"
|
47
49
|
)
|
48
50
|
}
|
49
51
|
)
|
50
|
-
for stock_code in self.cleaned_data.get("stock_codes").split("
|
52
|
+
for stock_code in self.cleaned_data.get("stock_codes").split("\r\n"):
|
51
53
|
try:
|
52
54
|
Stock.objects.get(
|
53
55
|
code=stock_code,
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Generated by Django 6.0 on 2025-04-02 16:13
|
2
|
+
from django.apps import apps as django_apps
|
3
|
+
from django.db import migrations
|
4
|
+
from django.db.migrations import RunPython
|
5
|
+
from edc_appointment.constants import MISSED_APPT
|
6
|
+
from edc_pdutils.dataframes import get_crf
|
7
|
+
from edc_utils import get_utcnow
|
8
|
+
from tqdm import tqdm
|
9
|
+
|
10
|
+
|
11
|
+
def update(apps, schema_editor):
|
12
|
+
"""Correct missed appointments incorrectly set to
|
13
|
+
appt_timing=ONTIME_APPT.
|
14
|
+
"""
|
15
|
+
appointment_model_cls = django_apps.get_model("edc_appointment.appointment")
|
16
|
+
df_missedvisit = get_crf(
|
17
|
+
"meta_subject.subjectvisitmissed",
|
18
|
+
subject_visit_model="meta_subject.subjectvisit",
|
19
|
+
)
|
20
|
+
df_subjects = df_missedvisit[df_missedvisit.appt_timing != MISSED_APPT][
|
21
|
+
["subject_identifier", "visit_code_str", "visit_code_sequence"]
|
22
|
+
].copy()
|
23
|
+
for tpl in tqdm(df_subjects.itertuples(), total=len(df_subjects)):
|
24
|
+
obj = appointment_model_cls.objects.get(
|
25
|
+
subject_identifier=tpl.subject_identifier,
|
26
|
+
visit_code=tpl.visit_code_str,
|
27
|
+
visit_code_sequence=tpl.visit_code_sequence,
|
28
|
+
)
|
29
|
+
obj.appt_timing = MISSED_APPT
|
30
|
+
obj.modified = get_utcnow()
|
31
|
+
obj.user_modified = "erikvw"
|
32
|
+
|
33
|
+
obj.save(update_fields=["appt_timing", "user_modified", "modified"])
|
34
|
+
|
35
|
+
|
36
|
+
class Migration(migrations.Migration):
|
37
|
+
|
38
|
+
dependencies = [
|
39
|
+
("meta_subject", "0220_historicalbloodresultsgludummy_bloodresultsgludummy"),
|
40
|
+
]
|
41
|
+
|
42
|
+
operations = [RunPython(update)]
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Generated by Django 6.0 on 2025-04-15 22:06
|
2
|
+
|
3
|
+
import django.core.validators
|
4
|
+
from django.db import migrations, models
|
5
|
+
|
6
|
+
|
7
|
+
class Migration(migrations.Migration):
|
8
|
+
|
9
|
+
dependencies = [
|
10
|
+
("meta_subject", "0221_auto_20250402_1913"),
|
11
|
+
]
|
12
|
+
|
13
|
+
operations = [
|
14
|
+
migrations.AlterField(
|
15
|
+
model_name="historicalstudymedication",
|
16
|
+
name="stock_codes",
|
17
|
+
field=models.TextField(
|
18
|
+
blank=True,
|
19
|
+
help_text="Enter the medication bottle barcode or barcodes. Type one code per line",
|
20
|
+
max_length=30,
|
21
|
+
null=True,
|
22
|
+
validators=[
|
23
|
+
django.core.validators.RegexValidator(
|
24
|
+
message="Enter one or more valid codes, one code per line",
|
25
|
+
regex="^([A-Z0-9]{6})(\r\n[A-Z0-9]{6})*$",
|
26
|
+
)
|
27
|
+
],
|
28
|
+
),
|
29
|
+
),
|
30
|
+
migrations.AlterField(
|
31
|
+
model_name="studymedication",
|
32
|
+
name="stock_codes",
|
33
|
+
field=models.TextField(
|
34
|
+
blank=True,
|
35
|
+
help_text="Enter the medication bottle barcode or barcodes. Type one code per line",
|
36
|
+
max_length=30,
|
37
|
+
null=True,
|
38
|
+
validators=[
|
39
|
+
django.core.validators.RegexValidator(
|
40
|
+
message="Enter one or more valid codes, one code per line",
|
41
|
+
regex="^([A-Z0-9]{6})(\r\n[A-Z0-9]{6})*$",
|
42
|
+
)
|
43
|
+
],
|
44
|
+
),
|
45
|
+
),
|
46
|
+
]
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# Generated by Django 5.2.3 on 2025-06-25 20:55
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
("meta_subject", "0222_alter_historicalstudymedication_stock_codes_and_more"),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AddField(
|
14
|
+
model_name="bloodresultsfbc",
|
15
|
+
name="errors",
|
16
|
+
field=models.TextField(blank=True, null=True),
|
17
|
+
),
|
18
|
+
migrations.AddField(
|
19
|
+
model_name="bloodresultsgludummy",
|
20
|
+
name="errors",
|
21
|
+
field=models.TextField(blank=True, null=True),
|
22
|
+
),
|
23
|
+
migrations.AddField(
|
24
|
+
model_name="bloodresultshba1c",
|
25
|
+
name="errors",
|
26
|
+
field=models.TextField(blank=True, null=True),
|
27
|
+
),
|
28
|
+
migrations.AddField(
|
29
|
+
model_name="bloodresultsins",
|
30
|
+
name="errors",
|
31
|
+
field=models.TextField(blank=True, null=True),
|
32
|
+
),
|
33
|
+
migrations.AddField(
|
34
|
+
model_name="bloodresultslft",
|
35
|
+
name="errors",
|
36
|
+
field=models.TextField(blank=True, null=True),
|
37
|
+
),
|
38
|
+
migrations.AddField(
|
39
|
+
model_name="bloodresultslipids",
|
40
|
+
name="errors",
|
41
|
+
field=models.TextField(blank=True, null=True),
|
42
|
+
),
|
43
|
+
migrations.AddField(
|
44
|
+
model_name="bloodresultsrft",
|
45
|
+
name="errors",
|
46
|
+
field=models.TextField(blank=True, null=True),
|
47
|
+
),
|
48
|
+
migrations.AddField(
|
49
|
+
model_name="historicalbloodresultsfbc",
|
50
|
+
name="errors",
|
51
|
+
field=models.TextField(blank=True, null=True),
|
52
|
+
),
|
53
|
+
migrations.AddField(
|
54
|
+
model_name="historicalbloodresultsgludummy",
|
55
|
+
name="errors",
|
56
|
+
field=models.TextField(blank=True, null=True),
|
57
|
+
),
|
58
|
+
migrations.AddField(
|
59
|
+
model_name="historicalbloodresultshba1c",
|
60
|
+
name="errors",
|
61
|
+
field=models.TextField(blank=True, null=True),
|
62
|
+
),
|
63
|
+
migrations.AddField(
|
64
|
+
model_name="historicalbloodresultsins",
|
65
|
+
name="errors",
|
66
|
+
field=models.TextField(blank=True, null=True),
|
67
|
+
),
|
68
|
+
migrations.AddField(
|
69
|
+
model_name="historicalbloodresultslft",
|
70
|
+
name="errors",
|
71
|
+
field=models.TextField(blank=True, null=True),
|
72
|
+
),
|
73
|
+
migrations.AddField(
|
74
|
+
model_name="historicalbloodresultslipids",
|
75
|
+
name="errors",
|
76
|
+
field=models.TextField(blank=True, null=True),
|
77
|
+
),
|
78
|
+
migrations.AddField(
|
79
|
+
model_name="historicalbloodresultsrft",
|
80
|
+
name="errors",
|
81
|
+
field=models.TextField(blank=True, null=True),
|
82
|
+
),
|
83
|
+
]
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# Generated by Django 5.2.3 on 2025-06-25 23:57
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
("meta_subject", "0223_bloodresultsfbc_errors_bloodresultsgludummy_errors_and_more"),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AddField(
|
14
|
+
model_name="bloodresultsfbc",
|
15
|
+
name="abnormal_summary",
|
16
|
+
field=models.TextField(blank=True, null=True),
|
17
|
+
),
|
18
|
+
migrations.AddField(
|
19
|
+
model_name="bloodresultsfbc",
|
20
|
+
name="reportable_summary",
|
21
|
+
field=models.TextField(blank=True, null=True),
|
22
|
+
),
|
23
|
+
migrations.AddField(
|
24
|
+
model_name="bloodresultsgludummy",
|
25
|
+
name="abnormal_summary",
|
26
|
+
field=models.TextField(blank=True, null=True),
|
27
|
+
),
|
28
|
+
migrations.AddField(
|
29
|
+
model_name="bloodresultsgludummy",
|
30
|
+
name="reportable_summary",
|
31
|
+
field=models.TextField(blank=True, null=True),
|
32
|
+
),
|
33
|
+
migrations.AddField(
|
34
|
+
model_name="bloodresultshba1c",
|
35
|
+
name="abnormal_summary",
|
36
|
+
field=models.TextField(blank=True, null=True),
|
37
|
+
),
|
38
|
+
migrations.AddField(
|
39
|
+
model_name="bloodresultshba1c",
|
40
|
+
name="reportable_summary",
|
41
|
+
field=models.TextField(blank=True, null=True),
|
42
|
+
),
|
43
|
+
migrations.AddField(
|
44
|
+
model_name="bloodresultsins",
|
45
|
+
name="abnormal_summary",
|
46
|
+
field=models.TextField(blank=True, null=True),
|
47
|
+
),
|
48
|
+
migrations.AddField(
|
49
|
+
model_name="bloodresultsins",
|
50
|
+
name="reportable_summary",
|
51
|
+
field=models.TextField(blank=True, null=True),
|
52
|
+
),
|
53
|
+
migrations.AddField(
|
54
|
+
model_name="bloodresultslft",
|
55
|
+
name="abnormal_summary",
|
56
|
+
field=models.TextField(blank=True, null=True),
|
57
|
+
),
|
58
|
+
migrations.AddField(
|
59
|
+
model_name="bloodresultslft",
|
60
|
+
name="reportable_summary",
|
61
|
+
field=models.TextField(blank=True, null=True),
|
62
|
+
),
|
63
|
+
migrations.AddField(
|
64
|
+
model_name="bloodresultslipids",
|
65
|
+
name="abnormal_summary",
|
66
|
+
field=models.TextField(blank=True, null=True),
|
67
|
+
),
|
68
|
+
migrations.AddField(
|
69
|
+
model_name="bloodresultslipids",
|
70
|
+
name="reportable_summary",
|
71
|
+
field=models.TextField(blank=True, null=True),
|
72
|
+
),
|
73
|
+
migrations.AddField(
|
74
|
+
model_name="bloodresultsrft",
|
75
|
+
name="abnormal_summary",
|
76
|
+
field=models.TextField(blank=True, null=True),
|
77
|
+
),
|
78
|
+
migrations.AddField(
|
79
|
+
model_name="bloodresultsrft",
|
80
|
+
name="reportable_summary",
|
81
|
+
field=models.TextField(blank=True, null=True),
|
82
|
+
),
|
83
|
+
migrations.AddField(
|
84
|
+
model_name="historicalbloodresultsfbc",
|
85
|
+
name="abnormal_summary",
|
86
|
+
field=models.TextField(blank=True, null=True),
|
87
|
+
),
|
88
|
+
migrations.AddField(
|
89
|
+
model_name="historicalbloodresultsfbc",
|
90
|
+
name="reportable_summary",
|
91
|
+
field=models.TextField(blank=True, null=True),
|
92
|
+
),
|
93
|
+
migrations.AddField(
|
94
|
+
model_name="historicalbloodresultsgludummy",
|
95
|
+
name="abnormal_summary",
|
96
|
+
field=models.TextField(blank=True, null=True),
|
97
|
+
),
|
98
|
+
migrations.AddField(
|
99
|
+
model_name="historicalbloodresultsgludummy",
|
100
|
+
name="reportable_summary",
|
101
|
+
field=models.TextField(blank=True, null=True),
|
102
|
+
),
|
103
|
+
migrations.AddField(
|
104
|
+
model_name="historicalbloodresultshba1c",
|
105
|
+
name="abnormal_summary",
|
106
|
+
field=models.TextField(blank=True, null=True),
|
107
|
+
),
|
108
|
+
migrations.AddField(
|
109
|
+
model_name="historicalbloodresultshba1c",
|
110
|
+
name="reportable_summary",
|
111
|
+
field=models.TextField(blank=True, null=True),
|
112
|
+
),
|
113
|
+
migrations.AddField(
|
114
|
+
model_name="historicalbloodresultsins",
|
115
|
+
name="abnormal_summary",
|
116
|
+
field=models.TextField(blank=True, null=True),
|
117
|
+
),
|
118
|
+
migrations.AddField(
|
119
|
+
model_name="historicalbloodresultsins",
|
120
|
+
name="reportable_summary",
|
121
|
+
field=models.TextField(blank=True, null=True),
|
122
|
+
),
|
123
|
+
migrations.AddField(
|
124
|
+
model_name="historicalbloodresultslft",
|
125
|
+
name="abnormal_summary",
|
126
|
+
field=models.TextField(blank=True, null=True),
|
127
|
+
),
|
128
|
+
migrations.AddField(
|
129
|
+
model_name="historicalbloodresultslft",
|
130
|
+
name="reportable_summary",
|
131
|
+
field=models.TextField(blank=True, null=True),
|
132
|
+
),
|
133
|
+
migrations.AddField(
|
134
|
+
model_name="historicalbloodresultslipids",
|
135
|
+
name="abnormal_summary",
|
136
|
+
field=models.TextField(blank=True, null=True),
|
137
|
+
),
|
138
|
+
migrations.AddField(
|
139
|
+
model_name="historicalbloodresultslipids",
|
140
|
+
name="reportable_summary",
|
141
|
+
field=models.TextField(blank=True, null=True),
|
142
|
+
),
|
143
|
+
migrations.AddField(
|
144
|
+
model_name="historicalbloodresultsrft",
|
145
|
+
name="abnormal_summary",
|
146
|
+
field=models.TextField(blank=True, null=True),
|
147
|
+
),
|
148
|
+
migrations.AddField(
|
149
|
+
model_name="historicalbloodresultsrft",
|
150
|
+
name="reportable_summary",
|
151
|
+
field=models.TextField(blank=True, null=True),
|
152
|
+
),
|
153
|
+
]
|
@@ -205,8 +205,8 @@ class TestEgfr(MetaTestCaseMixin, TestCase):
|
|
205
205
|
data.update(creatinine_value=152.0, creatinine_units=MICROMOLES_PER_LITER)
|
206
206
|
obj_1000 = BloodResultsRft.objects.create(**data)
|
207
207
|
obj_1000.refresh_from_db()
|
208
|
-
self.assertEqual(round_half_away_from_zero(obj_1000.egfr_value, 3), Decimal("49.
|
209
|
-
self.assertEqual(round_half_away_from_zero(obj_1000.egfr_value, 2), Decimal("49.
|
208
|
+
self.assertEqual(round_half_away_from_zero(obj_1000.egfr_value, 3), Decimal("49.019"))
|
209
|
+
self.assertEqual(round_half_away_from_zero(obj_1000.egfr_value, 2), Decimal("49.02"))
|
210
210
|
self.assertEqual(round_half_away_from_zero(obj_1000.egfr_value, 1), Decimal("49.0"))
|
211
211
|
self.assertEqual(round_half_away_from_zero(obj_1000.egfr_value), Decimal("49"))
|
212
212
|
|
@@ -228,7 +228,7 @@ class TestEgfr(MetaTestCaseMixin, TestCase):
|
|
228
228
|
data.update(creatinine_value=150.8, creatinine_units=MICROMOLES_PER_LITER)
|
229
229
|
obj_2000 = BloodResultsRft.objects.create(**data)
|
230
230
|
obj_2000.refresh_from_db()
|
231
|
-
self.assertEqual(round_half_away_from_zero(obj_2000.egfr_value, 3), Decimal("49.
|
232
|
-
self.assertEqual(round_half_away_from_zero(obj_2000.egfr_value, 2), Decimal("49.
|
231
|
+
self.assertEqual(round_half_away_from_zero(obj_2000.egfr_value, 3), Decimal("49.492"))
|
232
|
+
self.assertEqual(round_half_away_from_zero(obj_2000.egfr_value, 2), Decimal("49.49"))
|
233
233
|
self.assertEqual(round_half_away_from_zero(obj_2000.egfr_value, 1), Decimal("49.5"))
|
234
|
-
self.assertEqual(round_half_away_from_zero(obj_2000.egfr_value), Decimal("
|
234
|
+
self.assertEqual(round_half_away_from_zero(obj_2000.egfr_value), Decimal("49"))
|
@@ -1 +0,0 @@
|
|
1
|
-
from .get_glucose_df import get_glucose_df
|
@@ -1,122 +0,0 @@
|
|
1
|
-
import numpy as np
|
2
|
-
import pandas as pd
|
3
|
-
from django_pandas.io import read_frame
|
4
|
-
from edc_pdutils.dataframes import get_eos, get_subject_consent, get_subject_visit
|
5
|
-
|
6
|
-
from meta_subject.models import Glucose, GlucoseFbg
|
7
|
-
|
8
|
-
|
9
|
-
def get_glucose_df() -> pd.DataFrame:
|
10
|
-
qs_glucose_fbg = GlucoseFbg.objects.all()
|
11
|
-
df_glucose_fbg = read_frame(qs_glucose_fbg)
|
12
|
-
df_glucose_fbg.rename(
|
13
|
-
columns={"fbg_fasting": "fasting", "subject_visit": "subject_visit_id"},
|
14
|
-
inplace=True,
|
15
|
-
)
|
16
|
-
|
17
|
-
df_glucose_fbg.loc[(df_glucose_fbg["fasting"] == "fasting"), "fasting"] = "Yes"
|
18
|
-
df_glucose_fbg.loc[(df_glucose_fbg["fasting"] == "non_fasting"), "fasting"] = "No"
|
19
|
-
df_glucose_fbg["fasting_hrs"] = np.nan
|
20
|
-
df_glucose_fbg["fasting_hrs"] = df_glucose_fbg["fasting_duration_delta"].apply(
|
21
|
-
lambda x: x.total_seconds() / 3600
|
22
|
-
)
|
23
|
-
df_glucose_fbg["fasting_hrs"] = df_glucose_fbg["fasting_hrs"].apply(
|
24
|
-
lambda x: 8.05 if not x else x
|
25
|
-
)
|
26
|
-
# df_glucose_fbg = df_glucose_fbg.loc[df_glucose_fbg["fasting_hrs"] >= 8.0]
|
27
|
-
# df_glucose_fbg.reset_index(drop=True, inplace=True)
|
28
|
-
df_glucose_fbg.loc[
|
29
|
-
:,
|
30
|
-
["ogtt_value", "ogtt_units", "ogtt_datetime"],
|
31
|
-
] = [np.nan, None, pd.NaT]
|
32
|
-
df_glucose_fbg["source"] = "meta_subject.glucosefbg"
|
33
|
-
|
34
|
-
qs_glucose = Glucose.objects.all()
|
35
|
-
df_glucose = read_frame(qs_glucose)
|
36
|
-
df_glucose.rename(columns={"subject_visit": "subject_visit_id"}, inplace=True)
|
37
|
-
df_glucose.loc[(df_glucose["fasting"] == "fasting"), "fasting"] = "Yes"
|
38
|
-
df_glucose.loc[(df_glucose["fasting"] == "non_fasting"), "fasting"] = "No"
|
39
|
-
df_glucose["fasting_hrs"] = np.nan
|
40
|
-
df_glucose["fasting_hrs"] = df_glucose[df_glucose["fasting"] == "Yes"][
|
41
|
-
"fasting_duration_delta"
|
42
|
-
].apply(lambda x: x.total_seconds() / 3600)
|
43
|
-
df_glucose["fasting_hrs"] = df_glucose["fasting_hrs"].apply(lambda x: 8.05 if not x else x)
|
44
|
-
# df_glucose = df_glucose.loc[df_glucose["fasting_hrs"] >= 8.0]
|
45
|
-
# df_glucose.reset_index(drop=True, inplace=True)
|
46
|
-
df_glucose["source"] = "meta_subject.glucose"
|
47
|
-
|
48
|
-
keep_cols = [
|
49
|
-
"subject_visit_id",
|
50
|
-
"fasting",
|
51
|
-
"fasting_hrs",
|
52
|
-
"fbg_value",
|
53
|
-
"fbg_units",
|
54
|
-
"fbg_datetime",
|
55
|
-
"ogtt_value",
|
56
|
-
"ogtt_units",
|
57
|
-
"ogtt_datetime",
|
58
|
-
"source",
|
59
|
-
"revision",
|
60
|
-
"report_datetime",
|
61
|
-
]
|
62
|
-
df_glucose = df_glucose[keep_cols]
|
63
|
-
df_glucose_fbg = df_glucose_fbg[keep_cols]
|
64
|
-
# df = pd.concat([df_glucose_fbg, df_glucose])
|
65
|
-
df = pd.merge(
|
66
|
-
df_glucose,
|
67
|
-
df_glucose_fbg,
|
68
|
-
on="subject_visit_id",
|
69
|
-
how="outer",
|
70
|
-
indicator=True,
|
71
|
-
suffixes=("", "_2"),
|
72
|
-
)
|
73
|
-
|
74
|
-
for suffix in ["", "_2"]:
|
75
|
-
cols = [f"fasting_hrs{suffix}", f"fbg_value{suffix}", f"ogtt_value{suffix}"]
|
76
|
-
df[cols] = df[cols].apply(pd.to_numeric)
|
77
|
-
cols = [f"fbg_datetime{suffix}", f"ogtt_datetime{suffix}"]
|
78
|
-
df[cols] = df[cols].apply(pd.to_datetime)
|
79
|
-
df.loc[
|
80
|
-
(df[f"fbg_units{suffix}"] != "mmol/L (millimoles/L)")
|
81
|
-
& (df[f"fbg_value{suffix}"] >= 0),
|
82
|
-
f"fbg_units{suffix}",
|
83
|
-
] = "mmol/L (millimoles/L)"
|
84
|
-
df.loc[
|
85
|
-
(df[f"ogtt_units{suffix}"] != "mmol/L (millimoles/L)")
|
86
|
-
& (df[f"ogtt_value{suffix}"] >= 0),
|
87
|
-
f"ogtt_units{suffix}",
|
88
|
-
] = "mmol/L (millimoles/L)"
|
89
|
-
# remove values if not fasted
|
90
|
-
# df.loc[(df[f"fasting{suffix}"] != YES), f"fbg_value{suffix}"] = np.nan
|
91
|
-
# df.loc[(df[f"fasting{suffix}"] != YES), f"ogtt_value{suffix}"] = np.nan
|
92
|
-
|
93
|
-
# reconcile all to single column
|
94
|
-
df.loc[(df["fbg_value"].isna()) & (df["fbg_value_2"].notna()), "fbg_value"] = df[
|
95
|
-
"fbg_value_2"
|
96
|
-
]
|
97
|
-
df.loc[(df["ogtt_value"].isna()) & (df["ogtt_value_2"].notna()), "ogtt_value"] = df[
|
98
|
-
"ogtt_value_2"
|
99
|
-
]
|
100
|
-
cols = [col for col in list(df.columns) if col.endswith("_2")]
|
101
|
-
df.drop(columns=cols, inplace=True)
|
102
|
-
cols = [col for col in list(df.columns) if col.endswith("_3")]
|
103
|
-
df.drop(columns=cols, inplace=True)
|
104
|
-
|
105
|
-
df_subject_visit = get_subject_visit("meta_subject.subjectvisit")
|
106
|
-
df_consent = get_subject_consent("meta_consent.subjectconsent")
|
107
|
-
df_eos = get_eos("meta_prn.endofstudy")
|
108
|
-
|
109
|
-
df = pd.merge(df_subject_visit, df, on="subject_visit_id", how="left")
|
110
|
-
df = pd.merge(df, df_consent, on="subject_identifier", how="left")
|
111
|
-
df = pd.merge(df, df_eos, on="subject_identifier", how="left")
|
112
|
-
|
113
|
-
df["visit_days"] = df["baseline_datetime"].rsub(df["visit_datetime"]).dt.days
|
114
|
-
df["fgb_days"] = df["baseline_datetime"].rsub(df["fbg_datetime"]).dt.days
|
115
|
-
df["ogtt_days"] = df["baseline_datetime"].rsub(df["ogtt_datetime"]).dt.days
|
116
|
-
df["visit_days"] = pd.to_numeric(df["visit_days"], downcast="integer")
|
117
|
-
df["fgb_days"] = pd.to_numeric(df["fgb_days"], downcast="integer")
|
118
|
-
df["ogtt_days"] = pd.to_numeric(df["ogtt_days"], downcast="integer")
|
119
|
-
|
120
|
-
df = df.sort_values(by=["subject_identifier", "visit_code"])
|
121
|
-
df.reset_index(drop=True, inplace=True)
|
122
|
-
return df
|
File without changes
|
File without changes
|
File without changes
|