meta-edc 0.3.15__py3-none-any.whl → 0.3.50__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- meta_ae/action_items.py +2 -2
- meta_ae/migrations/0017_auto_20221130_2257.py +12 -7
- meta_ae/tests/holidays.csv +1 -1
- meta_analytics/README.rst +17 -0
- meta_analytics/dataframes/__init__.py +19 -0
- meta_analytics/dataframes/constants.py +33 -0
- meta_analytics/dataframes/enrolled/__init__.py +1 -0
- meta_analytics/dataframes/enrolled/get_glucose_df.py +122 -0
- meta_analytics/dataframes/get_eos_df.py +26 -0
- meta_analytics/dataframes/get_last_imp_visits_df.py +101 -0
- meta_analytics/dataframes/glucose_endpoints/__init__.py +2 -0
- meta_analytics/dataframes/glucose_endpoints/endpoint_by_date.py +183 -0
- meta_analytics/dataframes/glucose_endpoints/glucose_endpoints_by_date.py +531 -0
- meta_analytics/dataframes/screening/__init__.py +2 -0
- meta_analytics/dataframes/screening/get_glucose_tested_only_df.py +20 -0
- meta_analytics/dataframes/screening/get_screening_df.py +163 -0
- meta_analytics/dataframes/utils.py +65 -0
- meta_analytics/get_tables.py +81 -0
- meta_analytics/tables/__init__.py +2 -0
- meta_analytics/tables/eligible.py +106 -0
- meta_analytics/tables/enrolled/__init__.py +0 -0
- meta_analytics/tables/enrolled/glucose.py +28 -0
- meta_analytics/tables/has_dm.py +61 -0
- meta_analytics/tests/__init__.py +0 -0
- meta_analytics/tests/test_endpoints_by_date.py +94 -0
- meta_auth/auth_objects.py +22 -0
- meta_auth/auths.py +18 -3
- meta_consent/action_items.py +18 -1
- meta_consent/admin/__init__.py +1 -0
- meta_consent/admin/subject_consent_v1_ext_admin.py +45 -0
- meta_consent/baker_recipes.py +1 -0
- meta_consent/consents.py +20 -1
- meta_consent/constants.py +1 -0
- meta_consent/forms/__init__.py +1 -0
- meta_consent/forms/subject_consent_v1_ext_form.py +16 -0
- meta_consent/locale/lg/LC_MESSAGES/django.po +69 -0
- meta_consent/locale/sw/LC_MESSAGES/django.po +12 -12
- meta_consent/migrations/0026_historicalsubjectconsentv1ext_subjectconsentv1ext.py +544 -0
- meta_consent/migrations/0027_auto_20250111_0344.py +30 -0
- meta_consent/models/__init__.py +1 -0
- meta_consent/models/signals.py +18 -0
- meta_consent/models/subject_consent_v1_ext.py +29 -0
- meta_consent/tests/holidays.csv +1 -1
- meta_dashboard/locale/lg/LC_MESSAGES/django.po +30 -0
- meta_dashboard/locale/sw/LC_MESSAGES/django.po +11 -2
- meta_dashboard/navbars.py +3 -1
- meta_dashboard/templates/meta_dashboard/bootstrap3/buttons/eligibility_button.html +1 -1
- meta_dashboard/templates/meta_dashboard/bootstrap3/buttons/screening_button.html +1 -1
- meta_dashboard/templates/meta_dashboard/bootstrap3/subject/dashboard/sidebar.html +24 -0
- meta_dashboard/templates/meta_dashboard/bootstrap3/subject/dashboard.html +3 -0
- meta_dashboard/templatetags/meta_dashboard_extras.py +1 -1
- meta_dashboard/tests/holidays.csv +1 -1
- meta_dashboard/tests/urls.py +0 -1
- meta_dashboard/view_utils/__init__.py +6 -0
- meta_dashboard/view_utils/subject_screening_button.py +2 -2
- meta_dashboard/views/subject/dashboard/dashboard_view.py +38 -0
- meta_edc/__init__.py +7 -0
- meta_edc/celery.py +4 -13
- meta_edc/celery_live.py +18 -0
- meta_edc/celery_uat.py +24 -0
- meta_edc/management/commands/update_forms_reference.py +6 -2
- meta_edc/migrations/__init__.py +0 -0
- meta_edc/navbars.py +2 -1
- meta_edc/settings/debug.py +10 -2
- meta_edc/settings/defaults.py +58 -43
- meta_edc/templates/meta_edc/bootstrap3/home.html +5 -2
- meta_edc/tests/tests/test_endpoints.py +2 -0
- meta_edc/urls.py +4 -1
- meta_edc/wsgi.py +1 -1
- meta_edc/wsgi_live.py +1 -1
- meta_edc/wsgi_uat.py +1 -1
- meta_edc-0.3.50.dist-info/AUTHORS +0 -0
- meta_edc-0.3.50.dist-info/METADATA +766 -0
- {meta_edc-0.3.15.dist-info → meta_edc-0.3.50.dist-info}/RECORD +316 -127
- {meta_edc-0.3.15.dist-info → meta_edc-0.3.50.dist-info}/WHEEL +1 -1
- {meta_edc-0.3.15.dist-info → meta_edc-0.3.50.dist-info}/top_level.txt +1 -0
- meta_pharmacy/admin/__init__.py +2 -0
- meta_pharmacy/admin/rx_admin.py +75 -0
- meta_pharmacy/admin/substitutions_admin.py +67 -0
- meta_pharmacy/admin_site.py +9 -0
- meta_pharmacy/apps.py +5 -0
- meta_pharmacy/constants.py +10 -0
- meta_pharmacy/forms/__init__.py +2 -0
- meta_pharmacy/forms/rx_form.py +16 -0
- meta_pharmacy/forms/substitutions_form.py +54 -0
- meta_pharmacy/label_configs.py +30 -0
- meta_pharmacy/labels/__init__.py +5 -0
- meta_pharmacy/labels/draw_label_for_subject_with_barcode.py +62 -0
- meta_pharmacy/labels/draw_label_for_subject_with_code128.py +14 -0
- meta_pharmacy/labels/draw_label_with_test_data.py +26 -0
- meta_pharmacy/labels/label_data.py +14 -0
- meta_pharmacy/labels/print_sheets.py +97 -0
- meta_pharmacy/list_data.py +8 -0
- meta_pharmacy/management/__init__.py +0 -0
- meta_pharmacy/management/commands/__init__.py +0 -0
- meta_pharmacy/management/commands/update_initial_pharmacy_data.py +10 -0
- meta_pharmacy/migrations/0002_initial.py +695 -0
- meta_pharmacy/migrations/0003_auto_20240909_2335.py +64 -0
- meta_pharmacy/migrations/0004_alter_historicalsubstitutions_report_datetime_and_more.py +23 -0
- meta_pharmacy/migrations/0005_auto_20240911_0352.py +17 -0
- meta_pharmacy/migrations/0006_lotnumber_label.py +289 -0
- meta_pharmacy/migrations/0007_lotnumber_medication.py +24 -0
- meta_pharmacy/migrations/0008_remove_lotnumber_medication_and_more.py +390 -0
- meta_pharmacy/migrations/0009_remove_historicalrx_slug.py +17 -0
- meta_pharmacy/models/__init__.py +3 -0
- meta_pharmacy/models/label_data.py +38 -0
- meta_pharmacy/models/rx.py +18 -0
- meta_pharmacy/models/rx_label.py +39 -0
- meta_pharmacy/models/substitutions.py +88 -0
- meta_pharmacy/urls.py +8 -0
- meta_pharmacy/utils/__init__.py +1 -0
- meta_pharmacy/utils/update_initial_pharmacy_data.py +146 -0
- meta_prn/action_items.py +9 -1
- meta_prn/admin/pregnancy_notification_admin.py +6 -2
- meta_prn/migrations/0034_auto_20220630_1110.py +3 -3
- meta_prn/migrations/0035_auto_20220630_1140.py +59 -56
- meta_prn/tests/tests/test_dm_referral.py +3 -6
- meta_reports/__init__.py +1 -0
- meta_reports/admin/__init__.py +15 -0
- meta_reports/admin/dbviews/__init__.py +14 -0
- meta_reports/admin/dbviews/glucose_summary_admin.py +116 -0
- meta_reports/admin/dbviews/imp_substitutions_admin.py +101 -0
- meta_reports/admin/dbviews/missing_screening_ogtt_admin/__init__.py +2 -0
- meta_reports/admin/dbviews/missing_screening_ogtt_admin/note_model_admin.py +53 -0
- meta_reports/admin/dbviews/missing_screening_ogtt_admin/unmanaged_model_admin.py +84 -0
- meta_reports/admin/dbviews/on_study_missing_lab_values_admin/__init__.py +1 -0
- meta_reports/admin/dbviews/on_study_missing_lab_values_admin/unmanaged_model_admin.py +13 -0
- meta_reports/admin/dbviews/on_study_missing_values_admin/__init__.py +1 -0
- meta_reports/admin/dbviews/on_study_missing_values_admin/unmanaged_model_admin.py +13 -0
- meta_reports/admin/dbviews/patient_history_missing_baseline_cd4_admin.py +58 -0
- meta_reports/admin/dbviews/unattended_three_in_row2_admin.py +47 -0
- meta_reports/admin/dbviews/unattended_three_in_row_admin.py +35 -0
- meta_reports/admin/dbviews/unattended_two_in_row_admin.py +34 -0
- meta_reports/admin/endpoints_admin.py +14 -0
- meta_reports/admin/endpoints_all_admin.py +13 -0
- meta_reports/admin/last_imp_refill_admin.py +181 -0
- meta_reports/admin/list_filters.py +30 -0
- meta_reports/admin/modeladmin_mixins.py +112 -0
- meta_reports/admin_site.py +5 -0
- meta_reports/apps.py +1 -16
- meta_reports/forms/__init__.py +1 -0
- meta_reports/forms/missing_ogtt_note_form.py +33 -0
- meta_reports/management/__init__.py +0 -0
- meta_reports/management/commands/__init__.py +0 -0
- meta_reports/management/commands/generate_endpoints.py +13 -0
- meta_reports/migrations/0001_initial.py +87 -0
- meta_reports/migrations/0002_patienthistorymissingbaselinecd4_and_more.py +64 -0
- meta_reports/migrations/0003_auto_20240618_0505.py +12 -0
- meta_reports/migrations/0004_alter_patienthistorymissingbaselinecd4_table.py +17 -0
- meta_reports/migrations/0005_endpoints.py +47 -0
- meta_reports/migrations/0006_endpoints_baseline_datetime.py +18 -0
- meta_reports/migrations/0007_alter_endpoints_endpoint_label_and_more.py +43 -0
- meta_reports/migrations/0008_alter_endpoints_endpoint_label.py +18 -0
- meta_reports/migrations/0009_alter_endpoints_options.py +21 -0
- meta_reports/migrations/0010_alter_patienthistorymissingbaselinecd4_options_and_more.py +49 -0
- meta_reports/migrations/0011_auto_20240813_0156.py +54 -0
- meta_reports/migrations/0012_auto_20240813_1516.py +48 -0
- meta_reports/migrations/0013_auto_20240813_1516.py +48 -0
- meta_reports/migrations/0014_auto_20240813_1517.py +48 -0
- meta_reports/migrations/0015_alter_endpoints_site.py +22 -0
- meta_reports/migrations/0016_missingscreeningogtt.py +47 -0
- meta_reports/migrations/0017_auto_20240819_1711.py +166 -0
- meta_reports/migrations/0018_auto_20240819_1713.py +54 -0
- meta_reports/migrations/0019_auto_20240819_1721.py +54 -0
- meta_reports/migrations/0020_auto_20240819_1811.py +54 -0
- meta_reports/migrations/0021_auto_20240819_1817.py +54 -0
- meta_reports/migrations/0022_auto_20240819_1832.py +54 -0
- meta_reports/migrations/0023_endpoints_meta_report_subject_a56b22_idx.py +20 -0
- meta_reports/migrations/0024_glucosesummary.py +38 -0
- meta_reports/migrations/0025_auto_20240822_0115.py +87 -0
- meta_reports/migrations/0026_auto_20240822_0120.py +54 -0
- meta_reports/migrations/0027_auto_20240822_0140.py +54 -0
- meta_reports/migrations/0028_alter_glucosesummary_options.py +22 -0
- meta_reports/migrations/0029_auto_20240822_0149.py +54 -0
- meta_reports/migrations/0030_auto_20240822_1637.py +54 -0
- meta_reports/migrations/0031_endpointsproxy.py +25 -0
- meta_reports/migrations/0032_alter_endpointsproxy_options.py +21 -0
- meta_reports/migrations/0033_auto_20240823_0012.py +54 -0
- meta_reports/migrations/0034_auto_20240823_1642.py +54 -0
- meta_reports/migrations/0035_historicalmissingogttnote_missingogttnote.py +457 -0
- meta_reports/migrations/0036_historicalmissingogttnote_fasting_and_more.py +86 -0
- meta_reports/migrations/0037_historicalmissingogttnote_result_status_and_more.py +51 -0
- meta_reports/migrations/0038_alter_historicalmissingogttnote_fasting_and_more.py +33 -0
- meta_reports/migrations/0039_onstudymissingvalues.py +44 -0
- meta_reports/migrations/0040_auto_20240824_0412.py +282 -0
- meta_reports/migrations/0041_auto_20240828_2229.py +14 -0
- meta_reports/migrations/0042_onstudymissinglabvalues.py +43 -0
- meta_reports/migrations/0043_auto_20240828_2309.py +88 -0
- meta_reports/migrations/0044_auto_20240828_2323.py +93 -0
- meta_reports/migrations/0045_auto_20240829_0248.py +54 -0
- meta_reports/migrations/0046_auto_20240829_0250.py +54 -0
- meta_reports/migrations/0047_impsubstitutions.py +56 -0
- meta_reports/migrations/0048_auto_20240909_2338.py +48 -0
- meta_reports/migrations/0049_auto_20240911_0327.py +54 -0
- meta_reports/migrations/0050_alter_endpoints_created.py +19 -0
- meta_reports/migrations/0051_remove_endpoints_baseline_datetime_and_more.py +40 -0
- meta_reports/migrations/0052_lastimpvisit.py +57 -0
- meta_reports/migrations/0053_rename_lastimpvisit_lastimprefill_and_more.py +31 -0
- meta_reports/models/__init__.py +16 -0
- meta_reports/models/dbviews/README +14 -0
- meta_reports/models/dbviews/__init__.py +9 -0
- meta_reports/models/dbviews/glucose_summary/__init__.py +2 -0
- meta_reports/models/dbviews/glucose_summary/unmanaged_model.py +35 -0
- meta_reports/models/dbviews/glucose_summary/view_definition.py +28 -0
- meta_reports/models/dbviews/imp_substitutions/__init__.py +1 -0
- meta_reports/models/dbviews/imp_substitutions/unmanaged_model.py +41 -0
- meta_reports/models/dbviews/imp_substitutions/view_definition.py +21 -0
- meta_reports/models/dbviews/missing_screening_ogtt/__init__.py +2 -0
- meta_reports/models/dbviews/missing_screening_ogtt/note_model.py +57 -0
- meta_reports/models/dbviews/missing_screening_ogtt/unmanaged_model.py +41 -0
- meta_reports/models/dbviews/missing_screening_ogtt/view_definition.py +20 -0
- meta_reports/models/dbviews/on_study_missing_lab_values/__init__.py +1 -0
- meta_reports/models/dbviews/on_study_missing_lab_values/qa_cases.py +53 -0
- meta_reports/models/dbviews/on_study_missing_lab_values/unmanged_model.py +20 -0
- meta_reports/models/dbviews/on_study_missing_lab_values/view_definition.py +17 -0
- meta_reports/models/dbviews/on_study_missing_values/__init__.py +1 -0
- meta_reports/models/dbviews/on_study_missing_values/qa_cases.py +54 -0
- meta_reports/models/dbviews/on_study_missing_values/unmanged_model.py +20 -0
- meta_reports/models/dbviews/on_study_missing_values/view_definition.py +17 -0
- meta_reports/models/dbviews/patient_history_missing_baseline_cd4/__init__.py +1 -0
- meta_reports/models/dbviews/patient_history_missing_baseline_cd4/unmanaged_model.py +31 -0
- meta_reports/models/dbviews/patient_history_missing_baseline_cd4/view_definition.py +21 -0
- meta_reports/models/dbviews/unattended_three_in_row/__init__.py +1 -0
- meta_reports/models/dbviews/unattended_three_in_row/unmanaged_model.py +29 -0
- meta_reports/models/dbviews/unattended_three_in_row/view_definition.py +31 -0
- meta_reports/models/dbviews/unattended_three_in_row2/__init__.py +1 -0
- meta_reports/models/dbviews/unattended_three_in_row2/unmanaged_model.py +29 -0
- meta_reports/models/dbviews/unattended_three_in_row2/view_definition.py +50 -0
- meta_reports/models/dbviews/unattended_two_in_row/__init__.py +1 -0
- meta_reports/models/dbviews/unattended_two_in_row/unmanaged_model.py +27 -0
- meta_reports/models/dbviews/unattended_two_in_row/view_definition.py +30 -0
- meta_reports/models/endpoints.py +31 -0
- meta_reports/models/endpoints_proxy.py +11 -0
- meta_reports/models/last_imp_refill.py +34 -0
- meta_reports/tasks.py +12 -0
- meta_reports/templates/meta_reports/columns/subject_identifier_column.html +1 -0
- meta_reports/templates/meta_reports/endpoints_all_change_list_note.html +12 -0
- meta_reports/templates/meta_reports/endpoints_change_list_note.html +12 -0
- meta_reports/tests/test_sql_gen.py +5 -0
- meta_reports/urls.py +8 -0
- meta_reports/utils.py +0 -0
- meta_screening/admin/subject_screening_admin.py +1 -0
- meta_screening/migrations/0067_alter_historicalscreeningpartone_report_datetime_and_more.py +84 -0
- meta_screening/tests/holidays.csv +1 -1
- meta_screening/tests/meta_test_case_mixin.py +15 -0
- meta_sites/tests/test_sites.py +1 -1
- meta_subject/action_items.py +2 -2
- meta_subject/admin/__init__.py +2 -1
- meta_subject/admin/birth_outcome_admin.py +2 -0
- meta_subject/admin/blood_results/__init__.py +1 -1
- meta_subject/admin/blood_results/{blood_results_lipid_admin.py → blood_results_lipids_admin.py} +7 -7
- meta_subject/admin/diabetes/__init__.py +1 -1
- meta_subject/admin/diabetes/dm_endpoint_admin.py +35 -0
- meta_subject/admin/glucose_fbg_admin.py +4 -0
- meta_subject/admin/other_arv_regimens_admin.py +2 -0
- meta_subject/admin/study_medication_admin.py +10 -0
- meta_subject/form_validators/__init__.py +1 -1
- meta_subject/form_validators/dm_endpoint_form_validator.py +35 -0
- meta_subject/forms/__init__.py +2 -2
- meta_subject/forms/blood_results/__init__.py +1 -1
- meta_subject/forms/blood_results/{blood_results_lipid_form.py → blood_results_lipids_form.py} +5 -5
- meta_subject/forms/diabetes/__init__.py +1 -2
- meta_subject/forms/diabetes/dm_endpoint_form.py +13 -0
- meta_subject/forms/study_medication_form.py +35 -0
- meta_subject/locale/lg/LC_MESSAGES/django.po +470 -0
- meta_subject/locale/sw/LC_MESSAGES/django.po +191 -89
- meta_subject/metadata_rules/metadata_rules.py +7 -0
- meta_subject/metadata_rules/predicates.py +45 -8
- meta_subject/migrations/0107_auto_20220415_0043.py +28 -22
- meta_subject/migrations/0126_auto_20220719_2142.py +4 -4
- meta_subject/migrations/0131_auto_20220722_0411.py +28 -23
- meta_subject/migrations/0132_auto_20220722_1825.py +10 -6
- meta_subject/migrations/0135_auto_20220722_2212.py +39 -35
- meta_subject/migrations/0150_auto_20220914_0039.py +15 -11
- meta_subject/migrations/0207_alter_historicalphysicalexam_waist_circumference_and_more.py +46 -0
- meta_subject/migrations/0208_birthoutcomes_crf_status_and_more.py +62 -0
- meta_subject/migrations/0209_remove_historicaldmdxresult_dm_diagnosis_and_more.py +37 -0
- meta_subject/migrations/0210_remove_dmdxresult_dm_diagnosis_and_more.py +123 -0
- meta_subject/migrations/0211_dmendpoint_endpoint_reached_and_more.py +45 -0
- meta_subject/migrations/0212_auto_20240827_2222.py +23 -0
- meta_subject/migrations/0213_rename_bloodresultslipid_bloodresultslipids_and_more.py +35 -0
- meta_subject/migrations/0214_historicalstudymedication_stock_codes_and_more.py +44 -0
- meta_subject/migrations/0215_alter_historicalstudymedication_stock_codes_and_more.py +46 -0
- meta_subject/model_mixins/arv_history_model_mixin.py +3 -3
- meta_subject/models/__init__.py +3 -2
- meta_subject/models/birth_outcomes.py +6 -1
- meta_subject/models/blood_results/__init__.py +1 -1
- meta_subject/models/blood_results/{blood_results_lipid.py → blood_results_lipids.py} +3 -3
- meta_subject/models/diabetes/__init__.py +1 -2
- meta_subject/models/diabetes/dm_endpoint.py +61 -0
- meta_subject/models/glucose.py +4 -1
- meta_subject/models/physical_exam.py +1 -0
- meta_subject/models/signals.py +19 -0
- meta_subject/models/todo.txt +1 -1
- meta_subject/static/meta_subject/slider.css +1 -1
- meta_subject/templates/meta_subject/endpoint_review_instructions.html +1 -1
- meta_subject/templates/meta_subject/widgets/slider.html +0 -1
- meta_subject/tests/holidays.csv +1 -1
- meta_subject/tests/tests/test_medication_adherence.py +5 -1
- meta_subject/tests/tests/test_metadata_rules.py +2 -2
- meta_subject/tests/tests/test_mnsi.py +212 -121
- meta_subject/tests/tests/test_sf12.py +0 -12
- meta_visit_schedule/constants.py +4 -0
- meta_visit_schedule/tests/tests/test_schedule.py +4 -0
- meta_visit_schedule/visit_schedules/phase_three/crfs.py +75 -13
- meta_visit_schedule/visit_schedules/phase_three/requisitions.py +12 -0
- meta_visit_schedule/visit_schedules/phase_three/schedule.py +65 -2
- meta_visit_schedule/visit_schedules/phase_three/schedule_dm_referral.py +1 -1
- tests/etc/randomization_list.csv +1 -1
- {meta_edc/tests → tests}/etc/randomization_list_phase_three.csv +4 -4
- tests/holidays.csv +1 -1
- {meta_edc/tests → tests}/test_settings.py +16 -6
- meta_edc/tests/etc/user-aes-local.key +0 -1
- meta_edc/tests/etc/user-aes-restricted.key +0 -0
- meta_edc/tests/etc/user-rsa-local-private.pem +0 -27
- meta_edc/tests/etc/user-rsa-local-public.pem +0 -9
- meta_edc/tests/etc/user-rsa-restricted-private.pem +0 -27
- meta_edc/tests/etc/user-rsa-restricted-public.pem +0 -9
- meta_edc/tests/etc/user-salt-local.key +0 -0
- meta_edc/tests/etc/user-salt-restricted.key +0 -0
- meta_edc-0.3.15.dist-info/METADATA +0 -88
- meta_reports/tests/holidays.csv +0 -15
- meta_subject/admin/diabetes/dm_diagnosis_admin.py +0 -89
- meta_subject/form_validators/dm_diagnosis_form_validator.py +0 -38
- meta_subject/form_validators/dm_dx_result_form_validator.py +0 -7
- meta_subject/forms/diabetes/dm_diagnosis_form.py +0 -13
- meta_subject/forms/diabetes/dm_dx_result_form.py +0 -11
- meta_subject/models/diabetes/dm_diagnosis.py +0 -50
- meta_subject/models/diabetes/dm_dx_result.py +0 -70
- /meta_edc-0.3.15.dist-info/AUTHORS → /meta_analytics/__init__.py +0 -0
- /meta_pharmacy/models.py → /meta_analytics/constants.py +0 -0
- /meta_reports/models.py → /meta_analytics/notebooks/cleaning/__init__.py +0 -0
- {meta_edc-0.3.15.dist-info → meta_edc-0.3.50.dist-info}/LICENSE +0 -0
meta_ae/action_items.py
CHANGED
@@ -11,11 +11,11 @@ from edc_adverse_event.constants import (
|
|
11
11
|
DEATH_REPORT_TMG_ACTION,
|
12
12
|
)
|
13
13
|
from edc_constants.constants import CLOSED, DEAD, HIGH_PRIORITY, NO, YES
|
14
|
-
from edc_lab_results import BLOOD_RESULTS_LIPID_ACTION
|
15
14
|
from edc_lab_results.constants import (
|
16
15
|
BLOOD_RESULTS_FBC_ACTION,
|
17
16
|
BLOOD_RESULTS_GLU_ACTION,
|
18
17
|
BLOOD_RESULTS_LFT_ACTION,
|
18
|
+
BLOOD_RESULTS_LIPIDS_ACTION,
|
19
19
|
BLOOD_RESULTS_RFT_ACTION,
|
20
20
|
)
|
21
21
|
from edc_ltfu.constants import LOST_TO_FOLLOWUP
|
@@ -85,7 +85,7 @@ class AeInitialAction(ActionWithNotification):
|
|
85
85
|
display_name = "Submit AE Initial Report"
|
86
86
|
notification_display_name = "AE Initial Report"
|
87
87
|
parent_action_names = [
|
88
|
-
|
88
|
+
BLOOD_RESULTS_LIPIDS_ACTION,
|
89
89
|
BLOOD_RESULTS_GLU_ACTION,
|
90
90
|
BLOOD_RESULTS_LFT_ACTION,
|
91
91
|
BLOOD_RESULTS_RFT_ACTION,
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# Generated by Django 4.1.2 on 2022-11-30 19:57
|
2
|
+
from django.core.exceptions import ObjectDoesNotExist
|
2
3
|
from django.db import migrations
|
3
4
|
from edc_constants.constants import NOT_APPLICABLE
|
4
5
|
from tqdm import tqdm
|
@@ -7,13 +8,17 @@ from tqdm import tqdm
|
|
7
8
|
def update_investigator_ae_classification(apps, schema_editor):
|
8
9
|
ae_tmg_cls = apps.get_model("meta_ae", "aetmg")
|
9
10
|
ae_classification_cls = apps.get_model("edc_adverse_event", "aeclassification")
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
obj
|
11
|
+
try:
|
12
|
+
ae_classification = ae_classification_cls.objects.get(name=NOT_APPLICABLE)
|
13
|
+
except ObjectDoesNotExist:
|
14
|
+
pass
|
15
|
+
else:
|
16
|
+
total = ae_tmg_cls.objects.filter(investigator_ae_classification__isnull=True).count()
|
17
|
+
for obj in tqdm(
|
18
|
+
ae_tmg_cls.objects.filter(investigator_ae_classification__isnull=True), total=total
|
19
|
+
):
|
20
|
+
obj.investigator_ae_classification = ae_classification
|
21
|
+
obj.save_base(update_fields=["investigator_ae_classification"])
|
17
22
|
|
18
23
|
|
19
24
|
class Migration(migrations.Migration):
|
meta_ae/tests/holidays.csv
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
import pandas as pd
|
5
|
+
import numpy as np
|
6
|
+
import matplotlib.pyplot as plt
|
7
|
+
import seaborn as sns
|
8
|
+
from django_pandas.io import read_frame
|
9
|
+
from dj_notebook import activate
|
10
|
+
|
11
|
+
from meta_screening.models import SubjectScreening
|
12
|
+
|
13
|
+
plus = activate(dotenv_file="/Users/erikvw/source/edc_source/meta-edc/.env")
|
14
|
+
|
15
|
+
qs = SubjectScreening.objects.all()
|
16
|
+
|
17
|
+
df = read_frame(qs)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
from .constants import (
|
2
|
+
CASE_EOS,
|
3
|
+
CASE_FBG_ONLY,
|
4
|
+
CASE_FBGS_WITH_FIRST_OGTT,
|
5
|
+
CASE_FBGS_WITH_SECOND_OGTT,
|
6
|
+
CASE_OGTT,
|
7
|
+
endpoint_cases,
|
8
|
+
endpoint_columns,
|
9
|
+
)
|
10
|
+
from .get_eos_df import get_eos_df
|
11
|
+
from .get_last_imp_visits_df import get_last_imp_visits_df
|
12
|
+
from .glucose_endpoints import EndpointByDate, GlucoseEndpointsByDate
|
13
|
+
from .screening import get_glucose_tested_only_df, get_screening_df
|
14
|
+
from .utils import (
|
15
|
+
get_empty_endpoint_df,
|
16
|
+
get_test_string,
|
17
|
+
get_unique_subject_identifiers,
|
18
|
+
get_unique_visit_codes,
|
19
|
+
)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
CASE_EOS = 7
|
2
|
+
CASE_FBGS_WITH_FIRST_OGTT = 2
|
3
|
+
CASE_FBGS_WITH_SECOND_OGTT = 3
|
4
|
+
CASE_FBG_ONLY = 4
|
5
|
+
CASE_OGTT = 1
|
6
|
+
EOS_DM_MET = "EOS - Patient developed diabetes"
|
7
|
+
OGTT_THRESHOLD_MET = "OGTT >= 11.1"
|
8
|
+
|
9
|
+
endpoint_columns = [
|
10
|
+
"subject_identifier",
|
11
|
+
"site_id",
|
12
|
+
"baseline_datetime",
|
13
|
+
"visit_datetime",
|
14
|
+
"interval_in_days",
|
15
|
+
"visit_code",
|
16
|
+
"fbg_value",
|
17
|
+
"ogtt_value",
|
18
|
+
"fbg_datetime",
|
19
|
+
"fasting",
|
20
|
+
"endpoint_label",
|
21
|
+
"endpoint_type",
|
22
|
+
"endpoint",
|
23
|
+
"offstudy_datetime",
|
24
|
+
"offstudy_reason",
|
25
|
+
]
|
26
|
+
|
27
|
+
endpoint_cases = {
|
28
|
+
CASE_OGTT: OGTT_THRESHOLD_MET,
|
29
|
+
CASE_FBGS_WITH_FIRST_OGTT: "FBG >= 7 x 2, first OGTT<=11.1",
|
30
|
+
CASE_FBGS_WITH_SECOND_OGTT: "FBG >= 7 x 2, second OGTT<=11.1",
|
31
|
+
CASE_FBG_ONLY: "FBG >= 7 x 2, OGTT not considered",
|
32
|
+
CASE_EOS: EOS_DM_MET,
|
33
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
from .get_glucose_df import get_glucose_df
|
@@ -0,0 +1,122 @@
|
|
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
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import pandas as pd
|
2
|
+
from edc_pdutils.dataframes import get_eos, get_subject_visit
|
3
|
+
|
4
|
+
|
5
|
+
def get_eos_df() -> pd.DataFrame:
|
6
|
+
"""
|
7
|
+
df = get_eos_df()
|
8
|
+
|
9
|
+
# look at transfers and last attended visit
|
10
|
+
df[(df.transfer_reason.notna())]
|
11
|
+
|
12
|
+
"""
|
13
|
+
df_eos = get_eos("meta_prn.endofstudy")
|
14
|
+
df_visit = get_subject_visit("meta_subject.subjectvisit")
|
15
|
+
df_last_visit = (
|
16
|
+
df_visit.groupby(["subject_identifier", "site"])
|
17
|
+
.agg({"last_visit_code": "max", "last_visit_datetime": "max"})
|
18
|
+
.reset_index()
|
19
|
+
)
|
20
|
+
df_last_visit = df_last_visit.rename(columns={"site": "site_id"})
|
21
|
+
|
22
|
+
df_eos = df_eos.merge(
|
23
|
+
df_last_visit, on="subject_identifier", how="left", suffixes=("", "_y")
|
24
|
+
)
|
25
|
+
df_eos = df_eos.drop(columns=["site_id_y"])
|
26
|
+
return df_eos
|
@@ -0,0 +1,101 @@
|
|
1
|
+
import pandas as pd
|
2
|
+
from django.apps import apps as django_apps
|
3
|
+
from django.core.exceptions import ObjectDoesNotExist
|
4
|
+
from django_pandas.io import read_frame
|
5
|
+
from edc_pdutils.dataframes import get_appointments, get_crf
|
6
|
+
|
7
|
+
|
8
|
+
class InvalidLotNumber(Exception):
|
9
|
+
pass
|
10
|
+
|
11
|
+
|
12
|
+
def site_cond(df, site_id):
|
13
|
+
return (0 == 0) if not site_id else df.site_id == site_id
|
14
|
+
|
15
|
+
|
16
|
+
def get_last_imp_visits_df(
|
17
|
+
lot_no: str | None = None,
|
18
|
+
site_id: int | None = None,
|
19
|
+
) -> pd.DataFrame:
|
20
|
+
"""Returns a dataframe of the last IMP visits based on the last
|
21
|
+
StudyMedication refill report.
|
22
|
+
|
23
|
+
`assignment` col defaults to "*****" unless a valid `lot_no` is
|
24
|
+
provided.
|
25
|
+
"""
|
26
|
+
lot_obj = None
|
27
|
+
if lot_no:
|
28
|
+
lot_number_model_cls = django_apps.get_model("meta_pharmacy.lotnumber")
|
29
|
+
try:
|
30
|
+
lot_obj = lot_number_model_cls.objects.get(lot_no=lot_no)
|
31
|
+
except ObjectDoesNotExist:
|
32
|
+
raise ObjectDoesNotExist("The lot number given is invalid")
|
33
|
+
|
34
|
+
df_meds = get_crf(
|
35
|
+
"meta_subject.studymedication", subject_visit_model="meta_subject.subjectvisit"
|
36
|
+
)
|
37
|
+
df_meds = (
|
38
|
+
df_meds[(df_meds.refill == "Yes") & (site_cond(df_meds, site_id))]
|
39
|
+
.groupby(by=["subject_identifier", "site_id"])
|
40
|
+
.agg({"last_visit_code": "max", "last_visit_datetime": "max"})
|
41
|
+
.reset_index()
|
42
|
+
)
|
43
|
+
df_meds = df_meds.rename(
|
44
|
+
columns={"last_visit_code": "imp_visit_code", "last_visit_datetime": "imp_visit_date"}
|
45
|
+
)
|
46
|
+
df_meds.reset_index()
|
47
|
+
|
48
|
+
# merge with OffSchedule
|
49
|
+
opts = {} if not site_id else dict(site_id=site_id)
|
50
|
+
offschedule_model_cls = django_apps.get_model("meta_prn.offschedule")
|
51
|
+
df_off = read_frame(
|
52
|
+
offschedule_model_cls.objects.values(
|
53
|
+
"subject_identifier", "offschedule_datetime"
|
54
|
+
).filter(**opts),
|
55
|
+
verbose=False,
|
56
|
+
)
|
57
|
+
df_off["offschedule_datetime"] = df_off["offschedule_datetime"].dt.tz_localize(None)
|
58
|
+
df_off["offschedule_datetime"] = df_off["offschedule_datetime"].dt.normalize()
|
59
|
+
df_off = df_off.set_index("subject_identifier")
|
60
|
+
|
61
|
+
df_meds = df_meds.set_index("subject_identifier")
|
62
|
+
df_final = pd.merge(
|
63
|
+
df_meds, df_off, left_index=True, right_index=True, how="outer"
|
64
|
+
).reset_index()
|
65
|
+
|
66
|
+
# merge with RandomizationList if lot_obj
|
67
|
+
# note: slow to decrypt assignment
|
68
|
+
if lot_obj:
|
69
|
+
rando_model_cls = django_apps.get_model("meta_rando.randomizationlist")
|
70
|
+
qs = rando_model_cls.objects.values("subject_identifier", "assignment").filter(
|
71
|
+
assignment=lot_obj.assignment
|
72
|
+
)
|
73
|
+
df_rando = read_frame(qs, verbose=False)
|
74
|
+
df_final = df_final.merge(df_rando, on="subject_identifier", how="left")
|
75
|
+
else:
|
76
|
+
df_final["assignment"] = "*****"
|
77
|
+
|
78
|
+
# merge in appts
|
79
|
+
df_appt = (
|
80
|
+
get_appointments()
|
81
|
+
.groupby(by=["subject_identifier"])
|
82
|
+
.agg({"next_visit_code": "max", "next_appt_datetime": "max"})
|
83
|
+
.reset_index()
|
84
|
+
)
|
85
|
+
df_final = df_final.merge(
|
86
|
+
df_appt[["subject_identifier", "next_visit_code", "next_appt_datetime"]],
|
87
|
+
on="subject_identifier",
|
88
|
+
how="left",
|
89
|
+
)
|
90
|
+
df_final = df_final[(df_final.offschedule_datetime.isna()) & (df_final.assignment.notna())]
|
91
|
+
|
92
|
+
# Filter out subjects off_schedule.
|
93
|
+
# If lot_obj, filter out those with alternative assignment.
|
94
|
+
df_final = df_final[(df_final.offschedule_datetime.isna()) & (df_final.assignment.notna())]
|
95
|
+
df_final = df_final.drop(columns=["offschedule_datetime"])
|
96
|
+
|
97
|
+
# calculate days since the IMP visit
|
98
|
+
df_final["days_since"] = pd.to_datetime("today").normalize() - df_final.imp_visit_date
|
99
|
+
df_final["days_until"] = df_final.next_appt_datetime - pd.to_datetime("today").normalize()
|
100
|
+
df_final = df_final.reset_index()
|
101
|
+
return df_final
|
@@ -0,0 +1,183 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import pandas as pd
|
3
|
+
from edc_constants.constants import YES
|
4
|
+
|
5
|
+
from ..constants import endpoint_cases
|
6
|
+
|
7
|
+
|
8
|
+
class EndpointTdeltaError(Exception):
|
9
|
+
pass
|
10
|
+
|
11
|
+
|
12
|
+
class InvalidCaseList(Exception):
|
13
|
+
pass
|
14
|
+
|
15
|
+
|
16
|
+
class EndpointByDate:
|
17
|
+
"""Given all timepoints for a subject, flag the first timepoint
|
18
|
+
where the protocol endpoint is reached.
|
19
|
+
|
20
|
+
IMPORTANT: Remove case one before passing to this class
|
21
|
+
* case 1. any OGTT >= 11.1
|
22
|
+
|
23
|
+
Evaluation is done in order
|
24
|
+
|
25
|
+
Order of protocol endpoint evaluation:
|
26
|
+
* case 2. FBG >= 7 x 2, first OGTT<11.1
|
27
|
+
* case 3. FBG >= 7 x 2, second OGTT<11.1
|
28
|
+
|
29
|
+
Additional criteria considered:
|
30
|
+
1. any threshhold FBG must be taken while fasted (fasting=YES)
|
31
|
+
2. threshhold FBG readings must be consecutive (no
|
32
|
+
readings below threshold in the sequence regardless
|
33
|
+
of fasting)
|
34
|
+
3. at least 7 days between threshhold FBG readings.
|
35
|
+
4. at least one of the two threshold FBG readings must be taken
|
36
|
+
with an OGTT at the same timepoint.
|
37
|
+
|
38
|
+
Note:
|
39
|
+
case 4 is not a protocol endpoint. It considers only FBG and fasting.
|
40
|
+
It looks for two consecutive fasted threshold FBG readings.
|
41
|
+
"""
|
42
|
+
|
43
|
+
valid_case_list = [2, 3, 4]
|
44
|
+
|
45
|
+
def __init__(
|
46
|
+
self,
|
47
|
+
subject_df: pd.DataFrame = None,
|
48
|
+
fbg_threshhold: float = None,
|
49
|
+
ogtt_threshhold: float = None,
|
50
|
+
case_list: list[int] | None = None,
|
51
|
+
):
|
52
|
+
self.row = None
|
53
|
+
self.index = None
|
54
|
+
self.subject_df = subject_df[subject_df["fbg_value"].notna()]
|
55
|
+
self.subject_df = self.subject_df.reset_index(drop=True)
|
56
|
+
self.fbg_threshhold = fbg_threshhold
|
57
|
+
self.ogtt_threshhold = ogtt_threshhold
|
58
|
+
self.case_list = case_list or [2, 3]
|
59
|
+
if [x for x in self.case_list if x not in self.valid_case_list]:
|
60
|
+
raise InvalidCaseList(f"Expected any of {self.valid_case_list}. Got {case_list}.")
|
61
|
+
self.endpoint_cases = {k: v for k, v in endpoint_cases.items() if k in self.case_list}
|
62
|
+
self.evaluate()
|
63
|
+
|
64
|
+
def evaluate(self):
|
65
|
+
for index, _ in self.subject_df.iterrows():
|
66
|
+
if 2 in self.case_list and self.case_two(index):
|
67
|
+
break
|
68
|
+
elif 3 in self.case_list and self.case_three(index):
|
69
|
+
break
|
70
|
+
elif 4 in self.case_list and self.case_four(index):
|
71
|
+
break
|
72
|
+
|
73
|
+
def endpoint_reached(self, index: int, case: int, next_is_endpoint: bool | None = None):
|
74
|
+
"""Update the subject_df"""
|
75
|
+
fbg_datetime = (
|
76
|
+
self.get_next("fbg_datetime", index)
|
77
|
+
if next_is_endpoint
|
78
|
+
else self.get("fbg_datetime", index)
|
79
|
+
)
|
80
|
+
self.subject_df.loc[self.subject_df["fbg_datetime"] == fbg_datetime, "endpoint"] = 1
|
81
|
+
self.subject_df["interval_in_days"] = np.nan
|
82
|
+
try:
|
83
|
+
self.subject_df.loc[
|
84
|
+
self.subject_df["fbg_datetime"] == fbg_datetime, "interval_in_days"
|
85
|
+
] = self.sequential_assessments_in_days(index)
|
86
|
+
except EndpointTdeltaError:
|
87
|
+
pass
|
88
|
+
self.subject_df["interval_in_days"] = pd.to_numeric(
|
89
|
+
self.subject_df["interval_in_days"]
|
90
|
+
)
|
91
|
+
self.subject_df.loc[
|
92
|
+
self.subject_df["fbg_datetime"] == fbg_datetime, "endpoint_type"
|
93
|
+
] = case
|
94
|
+
self.subject_df.loc[
|
95
|
+
self.subject_df["fbg_datetime"] == fbg_datetime, "endpoint_label"
|
96
|
+
] = self.endpoint_cases[case]
|
97
|
+
|
98
|
+
def case_two(self, index: int):
|
99
|
+
"""FBG >= 7 x 2, first OGTT<11.1.
|
100
|
+
|
101
|
+
First FBG must be done with corresponding OGTT.
|
102
|
+
"""
|
103
|
+
reached = (
|
104
|
+
self.get_next("fbg_datetime", index)
|
105
|
+
and self.get("fbg_value", index)
|
106
|
+
and self.get("ogtt_value", index)
|
107
|
+
and self.get("fasting", index)
|
108
|
+
and self.get_next("fbg_value", index)
|
109
|
+
and self.get_next("fasting", index)
|
110
|
+
and self.get("fbg_value", index) >= self.fbg_threshhold
|
111
|
+
and self.get("ogtt_value", index) < self.ogtt_threshhold
|
112
|
+
and self.get("fasting", index) == YES
|
113
|
+
and self.get_next("fbg_value", index) >= self.fbg_threshhold
|
114
|
+
and self.get_next("fasting", index) == YES
|
115
|
+
and (self.get_next("fbg_datetime", index) - self.get("fbg_datetime", index)).days
|
116
|
+
>= 7
|
117
|
+
)
|
118
|
+
if reached:
|
119
|
+
self.endpoint_reached(index, case=2, next_is_endpoint=True)
|
120
|
+
return reached
|
121
|
+
|
122
|
+
def case_three(self, index: int):
|
123
|
+
"""FBG >= 7 x 2, second OGTT<11.1.
|
124
|
+
|
125
|
+
Second FBG must be done with corresponding OGTT.
|
126
|
+
"""
|
127
|
+
reached = (
|
128
|
+
self.get_next("fbg_datetime", index)
|
129
|
+
and self.get("fbg_value", index)
|
130
|
+
and self.get("fasting", index)
|
131
|
+
and self.get_next("fbg_value", index)
|
132
|
+
and self.get_next("ogtt_value", index)
|
133
|
+
and self.get_next("fasting", index)
|
134
|
+
and self.get("fbg_value", index) >= self.fbg_threshhold
|
135
|
+
and self.get("fasting", index) == YES
|
136
|
+
and self.get_next("fbg_value", index) >= self.fbg_threshhold
|
137
|
+
and self.get_next("ogtt_value", index) < self.ogtt_threshhold
|
138
|
+
and self.get_next("fasting", index) == YES
|
139
|
+
and (self.get_next("fbg_datetime", index) - self.get("fbg_datetime", index)).days
|
140
|
+
>= 7
|
141
|
+
)
|
142
|
+
if reached:
|
143
|
+
self.endpoint_reached(index, case=3, next_is_endpoint=True)
|
144
|
+
return reached
|
145
|
+
|
146
|
+
def case_four(self, index: int):
|
147
|
+
"""FBG >= 7 x 2, OGTT not considered
|
148
|
+
|
149
|
+
This is not a protocol endpoint.
|
150
|
+
"""
|
151
|
+
reached = (
|
152
|
+
self.get("fbg_value", index)
|
153
|
+
and self.get("fbg_datetime", index)
|
154
|
+
and self.get("fasting", index)
|
155
|
+
and self.get_next("fbg_value", index)
|
156
|
+
and self.get_next("ogtt_value", index)
|
157
|
+
and self.get_next("fbg_datetime", index)
|
158
|
+
and self.get_next("fasting", index)
|
159
|
+
and self.get("fbg_value", index) >= self.fbg_threshhold
|
160
|
+
and self.get("fasting", index) == YES
|
161
|
+
and self.get_next("fbg_value", index) >= self.fbg_threshhold
|
162
|
+
and self.get_next("fasting", index) == YES
|
163
|
+
and (self.get_next("fbg_datetime", index) - self.get("fbg_datetime", index)).days
|
164
|
+
>= 7
|
165
|
+
)
|
166
|
+
if reached:
|
167
|
+
self.endpoint_reached(index, case=4, next_is_endpoint=True)
|
168
|
+
return reached
|
169
|
+
|
170
|
+
def sequential_assessments_in_days(self, index) -> int:
|
171
|
+
if not self.get_next("fbg_value", index):
|
172
|
+
raise EndpointTdeltaError
|
173
|
+
return (self.get_next("fbg_datetime", index) - self.get("visit_datetime", index)).days
|
174
|
+
|
175
|
+
def get(self, col: str, index: int) -> float | None:
|
176
|
+
try:
|
177
|
+
next_value = self.subject_df.iloc[index : index + 1][col].item()
|
178
|
+
except ValueError:
|
179
|
+
next_value = None
|
180
|
+
return next_value
|
181
|
+
|
182
|
+
def get_next(self, col: str, index: int) -> float | None:
|
183
|
+
return self.get(col, index + 1)
|