clinicedc 2.0.12__py3-none-any.whl → 2.0.13__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.

Potentially problematic release.


This version of clinicedc might be problematic. Click here for more details.

Files changed (101) hide show
  1. {clinicedc-2.0.12.dist-info → clinicedc-2.0.13.dist-info}/METADATA +2 -1
  2. {clinicedc-2.0.12.dist-info → clinicedc-2.0.13.dist-info}/RECORD +101 -24
  3. edc_action_item/migrations/0017_auto_20190305_0123.py +1 -1
  4. edc_action_item/migrations/0030_edcpermissions.py +1 -1
  5. edc_adverse_event/migrations/0001_initial.py +1 -1
  6. edc_adverse_event/migrations/0002_auto_20190802_0059.py +1 -1
  7. edc_adverse_event/migrations/0008_auto_20220825_0451.py +1 -1
  8. edc_adverse_event/migrations/0009_auto_20220907_0157.py +1 -1
  9. edc_adverse_event/model_mixins/hospitaization/hospitalization_model_mixin.py +1 -3
  10. edc_analytics/__init__.py +3 -0
  11. edc_analytics/apps.py +8 -0
  12. edc_analytics/constants.py +26 -0
  13. edc_analytics/custom_tables/__init__.py +11 -0
  14. edc_analytics/custom_tables/age.py +72 -0
  15. edc_analytics/custom_tables/art.py +88 -0
  16. edc_analytics/custom_tables/bmi.py +125 -0
  17. edc_analytics/custom_tables/bp.py +103 -0
  18. edc_analytics/custom_tables/fasting.py +126 -0
  19. edc_analytics/custom_tables/fbg.py +98 -0
  20. edc_analytics/custom_tables/fbg_ogtt.py +384 -0
  21. edc_analytics/custom_tables/gender.py +12 -0
  22. edc_analytics/custom_tables/hba1c.py +87 -0
  23. edc_analytics/custom_tables/ogtt.py +95 -0
  24. edc_analytics/custom_tables/waist.py +105 -0
  25. edc_analytics/data.py +36 -0
  26. edc_analytics/row/__init__.py +4 -0
  27. edc_analytics/row/row_definition.py +43 -0
  28. edc_analytics/row/row_definitions.py +32 -0
  29. edc_analytics/row/row_statistics.py +88 -0
  30. edc_analytics/row/row_statistics_with_gender.py +115 -0
  31. edc_analytics/stata/__init__.py +1 -0
  32. edc_analytics/stata/get_stata_labels_from_model.py +44 -0
  33. edc_analytics/styler.py +93 -0
  34. edc_analytics/table.py +108 -0
  35. edc_analytics/urls.py +6 -0
  36. edc_appointment/migrations/0018_auto_20190305_0123.py +1 -1
  37. edc_auth/migrations/0001_squashed_0033_alter_userprofile_is_multisite_viewer.py +1 -1
  38. edc_auth/migrations/0012_auto_20191026_0034.py +1 -1
  39. edc_auth/migrations/0013_auto_20191026_0055.py +1 -1
  40. edc_auth/migrations/0025_permissions.py +1 -1
  41. edc_consent/migrations/0001_initial.py +1 -1
  42. edc_dashboard/migrations/0001_initial.py +1 -1
  43. edc_data_manager/migrations/0001_initial.py +1 -1
  44. edc_data_manager/migrations/0025_edcpermissions.py +1 -1
  45. edc_dx/__init__.py +6 -0
  46. edc_dx/apps.py +5 -0
  47. edc_dx/diagnoses.py +250 -0
  48. edc_dx/form_validators/__init__.py +2 -0
  49. edc_dx/form_validators/diagnosis_form_validator_mixin.py +54 -0
  50. edc_dx/form_validators/result_form_validator_mixin.py +65 -0
  51. edc_dx/utils.py +42 -0
  52. edc_dx_review/__init__.py +0 -0
  53. edc_dx_review/apps.py +5 -0
  54. edc_dx_review/auth_objects.py +13 -0
  55. edc_dx_review/auths.py +12 -0
  56. edc_dx_review/choices.py +24 -0
  57. edc_dx_review/constants.py +7 -0
  58. edc_dx_review/fieldsets.py +47 -0
  59. edc_dx_review/form_mixins/__init__.py +3 -0
  60. edc_dx_review/form_mixins/clinical_review_baseline_required_form_mixin.py +25 -0
  61. edc_dx_review/form_validator_mixins/__init__.py +6 -0
  62. edc_dx_review/form_validator_mixins/clinical_review_baseline_form_validator_mixin.py +7 -0
  63. edc_dx_review/form_validator_mixins/clinical_review_followup_form_validator_mixin.py +25 -0
  64. edc_dx_review/list_data.py +19 -0
  65. edc_dx_review/medical_date.py +195 -0
  66. edc_dx_review/migrations/0001_initial.py +307 -0
  67. edc_dx_review/migrations/0002_diagnosislocations_extra_value_and_more.py +32 -0
  68. edc_dx_review/migrations/0003_alter_diagnosislocations_options_and_more.py +148 -0
  69. edc_dx_review/migrations/0004_remove_diagnosislocations_edc_dx_revi_name_a39b40_idx_and_more.py +20 -0
  70. edc_dx_review/migrations/__init__.py +0 -0
  71. edc_dx_review/model_mixins/__init__.py +20 -0
  72. edc_dx_review/model_mixins/clinical_review_baseline_model_mixin.py +25 -0
  73. edc_dx_review/model_mixins/clinical_review_followup/__init__.py +5 -0
  74. edc_dx_review/model_mixins/clinical_review_followup/clinical_review_followup_chol_model_mixin.py +54 -0
  75. edc_dx_review/model_mixins/clinical_review_followup/clinical_review_followup_dm_model_mixin.py +54 -0
  76. edc_dx_review/model_mixins/clinical_review_followup/clinical_review_followup_hiv_model_mixin.py +54 -0
  77. edc_dx_review/model_mixins/clinical_review_followup/clinical_review_followup_htn_model_mixin.py +56 -0
  78. edc_dx_review/model_mixins/clinical_review_followup/clinical_review_followup_model_mixin.py +25 -0
  79. edc_dx_review/model_mixins/dx_location_model_mixin.py +17 -0
  80. edc_dx_review/model_mixins/factory/__init__.py +4 -0
  81. edc_dx_review/model_mixins/factory/baseline_review_model_mixin_factory.py +55 -0
  82. edc_dx_review/model_mixins/factory/calculate_date.py +43 -0
  83. edc_dx_review/model_mixins/factory/dx_initial_review_model_mixin_factory.py +97 -0
  84. edc_dx_review/model_mixins/factory/followup_review_model_mixin_factory.py +39 -0
  85. edc_dx_review/model_mixins/factory/rx_initial_review_model_mixin_factory.py +69 -0
  86. edc_dx_review/model_mixins/followup_review/__init__.py +2 -0
  87. edc_dx_review/model_mixins/followup_review/followup_review_model_mixin.py +22 -0
  88. edc_dx_review/model_mixins/followup_review/hiv_followup_review_model_mixin.py +32 -0
  89. edc_dx_review/model_mixins/initial_review/__init__.py +6 -0
  90. edc_dx_review/model_mixins/initial_review/chol_initial_review_model_mixin.py +34 -0
  91. edc_dx_review/model_mixins/initial_review/hiv_initial_model_mixins.py +119 -0
  92. edc_dx_review/model_mixins/initial_review/ncd_initial_review_model_mixin.py +42 -0
  93. edc_dx_review/models.py +20 -0
  94. edc_dx_review/radio_fields.py +30 -0
  95. edc_dx_review/utils.py +220 -0
  96. edc_export/migrations/0004_auto_20190305_0123.py +1 -1
  97. edc_export/migrations/0013_edcpermissions.py +1 -1
  98. edc_facility/migrations/0005_healthfacility_healthfacilitytypes_and_more.py +1 -1
  99. edc_vitals/model_mixins/blood_pressure_model_mixin.py +1 -0
  100. {clinicedc-2.0.12.dist-info → clinicedc-2.0.13.dist-info}/WHEEL +0 -0
  101. {clinicedc-2.0.12.dist-info → clinicedc-2.0.13.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,125 @@
1
+ import pandas as pd
2
+ from edc_constants.constants import FEMALE, MALE
3
+
4
+ from ..constants import (
5
+ MEDIAN_IQR,
6
+ MEDIAN_RANGE,
7
+ N_ONLY,
8
+ N_WITH_COL_PROP,
9
+ N_WITH_ROW_PROP,
10
+ )
11
+ from ..row import RowDefinition, RowDefinitions
12
+ from ..table import Table
13
+
14
+
15
+ class BmiTable(Table):
16
+
17
+ colname = "calculated_bmi_value"
18
+
19
+ def __init__(self, main_df: pd.DataFrame = None):
20
+ super().__init__(
21
+ colname="calculated_bmi_value",
22
+ main_df=main_df,
23
+ title="BMI categories (kg/m2)",
24
+ )
25
+
26
+ @property
27
+ def row_definitions(self) -> RowDefinitions:
28
+ df_tmp = self.main_df.copy()
29
+ row_defs = RowDefinitions(reverse_rows=False)
30
+ row0 = RowDefinition(
31
+ title=self.title,
32
+ label=self.default_sublabel,
33
+ condition=(df_tmp["gender"].notna()),
34
+ columns={FEMALE: (N_ONLY, 2), MALE: (N_ONLY, 2), "All": (N_ONLY, 2)},
35
+ drop=False,
36
+ )
37
+ row_defs.add(row0)
38
+ columns = {
39
+ FEMALE: (N_WITH_COL_PROP, 2),
40
+ MALE: (N_WITH_COL_PROP, 2),
41
+ "All": (N_WITH_ROW_PROP, 2),
42
+ }
43
+ row_defs.add(
44
+ RowDefinition(
45
+ colname="calculated_bmi_value",
46
+ label="Less than 18.5",
47
+ condition=(df_tmp[self.colname] < 18.5),
48
+ columns=columns,
49
+ drop=False,
50
+ )
51
+ )
52
+ row_defs.add(
53
+ RowDefinition(
54
+ colname="calculated_bmi_value",
55
+ label="18.5-24.9",
56
+ condition=(df_tmp[self.colname] >= 18.5) & (df_tmp[self.colname] < 25.0),
57
+ columns=columns,
58
+ drop=False,
59
+ )
60
+ )
61
+ row_defs.add(
62
+ RowDefinition(
63
+ colname="calculated_bmi_value",
64
+ label="25.0-29.9",
65
+ condition=(df_tmp[self.colname] >= 25.0) & (df_tmp[self.colname] < 30.0),
66
+ columns=columns,
67
+ drop=False,
68
+ )
69
+ )
70
+ row_defs.add(
71
+ RowDefinition(
72
+ colname="calculated_bmi_value",
73
+ label="30.0-39.9",
74
+ condition=(df_tmp[self.colname] >= 30.0) & (df_tmp[self.colname] < 40.0),
75
+ columns=columns,
76
+ drop=False,
77
+ )
78
+ )
79
+ row_defs.add(
80
+ RowDefinition(
81
+ colname="calculated_bmi_value",
82
+ label="40 or above",
83
+ condition=(df_tmp[self.colname] >= 40.0),
84
+ columns=columns,
85
+ drop=False,
86
+ )
87
+ )
88
+ cond = df_tmp[self.colname].isna()
89
+ if len(df_tmp[cond]) > 0:
90
+ row_defs.add(
91
+ RowDefinition(
92
+ colname="calculated_bmi_value",
93
+ label="not measured",
94
+ condition=cond,
95
+ columns=columns,
96
+ drop=False,
97
+ )
98
+ )
99
+ row_defs.add(
100
+ RowDefinition(
101
+ colname="calculated_bmi_value",
102
+ label="Median (IQR)",
103
+ condition=(df_tmp["gender"].notna()),
104
+ columns={
105
+ FEMALE: (MEDIAN_IQR, 2),
106
+ MALE: (MEDIAN_IQR, 2),
107
+ "All": (MEDIAN_IQR, 2),
108
+ },
109
+ drop=False,
110
+ )
111
+ )
112
+ row_defs.add(
113
+ RowDefinition(
114
+ colname="calculated_bmi_value",
115
+ label="Median (range)",
116
+ condition=(df_tmp["gender"].notna()),
117
+ columns={
118
+ FEMALE: (MEDIAN_RANGE, 2),
119
+ MALE: (MEDIAN_RANGE, 2),
120
+ "All": (MEDIAN_RANGE, 2),
121
+ },
122
+ drop=False,
123
+ )
124
+ )
125
+ return row_defs
@@ -0,0 +1,103 @@
1
+ import pandas as pd
2
+ from edc_constants.constants import FEMALE, MALE
3
+
4
+ from ..constants import N_ONLY, N_WITH_COL_PROP, N_WITH_ROW_PROP
5
+ from ..row import RowDefinition, RowDefinitions
6
+ from ..table import Table
7
+
8
+
9
+ class BpTable(Table):
10
+
11
+ sys_col_name = "sys_blood_pressure_avg"
12
+ dia_col_name = "dia_blood_pressure_avg"
13
+
14
+ def __init__(self, main_df: pd.DataFrame = None):
15
+ super().__init__(
16
+ colname="",
17
+ main_df=main_df,
18
+ title="Blood pressure at baseline (mmHg)",
19
+ )
20
+ self.table_df = self.table_df.reindex(index=self.table_df.index[::-1])
21
+
22
+ @property
23
+ def row_definitions(self) -> RowDefinitions:
24
+ df_tmp = self.main_df.copy()
25
+ row_defs = RowDefinitions(reverse_rows=True)
26
+ row0 = RowDefinition(
27
+ title=self.title,
28
+ label=self.default_sublabel,
29
+ condition=(df_tmp["gender"].notna()),
30
+ columns={
31
+ FEMALE: (N_ONLY, 2),
32
+ MALE: (N_ONLY, 2),
33
+ "All": (N_ONLY, 2),
34
+ },
35
+ drop=False,
36
+ )
37
+ row_defs.add(row0)
38
+ columns = {
39
+ FEMALE: (N_WITH_COL_PROP, 2),
40
+ MALE: (N_WITH_COL_PROP, 2),
41
+ "All": (N_WITH_ROW_PROP, 2),
42
+ }
43
+ row_defs.add(
44
+ RowDefinition(
45
+ label="Severe hypertension (>=180/110)",
46
+ condition=(
47
+ (df_tmp[self.sys_col_name] >= 180) | (df_tmp[self.dia_col_name] >= 110)
48
+ ),
49
+ columns=columns,
50
+ drop=True,
51
+ )
52
+ )
53
+ row_defs.add(
54
+ RowDefinition(
55
+ label="Hypertension (>=140/90)",
56
+ condition=(
57
+ (df_tmp[self.sys_col_name] >= 140) | (df_tmp[self.dia_col_name] >= 90)
58
+ ),
59
+ columns=columns,
60
+ drop=True,
61
+ )
62
+ )
63
+ row_defs.add(
64
+ RowDefinition(
65
+ label="Pre-hypertension (<140/90)",
66
+ condition=(
67
+ (df_tmp[self.sys_col_name] >= 120) | (df_tmp[self.dia_col_name] >= 80)
68
+ ),
69
+ columns=columns,
70
+ drop=True,
71
+ )
72
+ )
73
+ row_defs.add(
74
+ RowDefinition(
75
+ label="Normal (<120/80)",
76
+ condition=(
77
+ (df_tmp[self.sys_col_name] >= 90) | (df_tmp[self.dia_col_name] >= 60)
78
+ ),
79
+ columns=columns,
80
+ drop=True,
81
+ )
82
+ )
83
+ row_defs.add(
84
+ RowDefinition(
85
+ label="Low (<90/60)",
86
+ condition=(
87
+ (df_tmp[self.sys_col_name] >= 0) | (df_tmp[self.dia_col_name] >= 0)
88
+ ),
89
+ columns=columns,
90
+ drop=True,
91
+ )
92
+ )
93
+ row_defs.add(
94
+ RowDefinition(
95
+ label="not measured",
96
+ condition=(
97
+ (df_tmp[self.sys_col_name].isna()) & (df_tmp[self.dia_col_name].isna())
98
+ ),
99
+ columns=columns,
100
+ drop=True,
101
+ )
102
+ )
103
+ return row_defs
@@ -0,0 +1,126 @@
1
+ import pandas as pd
2
+ from edc_constants.constants import FEMALE, MALE
3
+
4
+ from ..constants import MEDIAN_IQR, N_ONLY, N_WITH_COL_PROP, N_WITH_ROW_PROP
5
+ from ..row import RowDefinition, RowDefinitions
6
+ from ..table import Table
7
+
8
+
9
+ class FastingFbgTable(Table):
10
+ def __init__(
11
+ self,
12
+ main_df: pd.DataFrame = None,
13
+ colname: str | None = None,
14
+ title: str | None = None,
15
+ ):
16
+ colname = colname or "fasting_fbg_hrs"
17
+ title = title or "Fasting duration (hrs)"
18
+ super().__init__(colname=colname, main_df=main_df, title=title)
19
+
20
+ @property
21
+ def row_definitions(self) -> RowDefinitions:
22
+ df_tmp = self.main_df.copy()
23
+ row_defs = RowDefinitions(reverse_rows=False)
24
+ row0 = RowDefinition(
25
+ title=self.title,
26
+ label=self.default_sublabel,
27
+ condition=(df_tmp["gender"].notna()),
28
+ columns={FEMALE: (N_ONLY, 2), MALE: (N_ONLY, 2), "All": (N_ONLY, 2)},
29
+ drop=False,
30
+ )
31
+ row_defs.add(row0)
32
+ columns = {
33
+ FEMALE: (MEDIAN_IQR, 2),
34
+ MALE: (MEDIAN_IQR, 2),
35
+ "All": (MEDIAN_IQR, 2),
36
+ }
37
+ row_defs.add(
38
+ RowDefinition(
39
+ colname=self.colname,
40
+ label="FBG fasted (hours), median (IQR)",
41
+ condition=(self.main_df[self.colname].notna()),
42
+ columns=columns,
43
+ drop=False,
44
+ )
45
+ )
46
+ columns = {
47
+ FEMALE: (N_WITH_COL_PROP, 2),
48
+ MALE: (N_WITH_COL_PROP, 2),
49
+ "All": (N_WITH_ROW_PROP, 2),
50
+ }
51
+ row_defs.add(
52
+ RowDefinition(
53
+ colname=self.colname,
54
+ label="FBG Fasted <8.0 hrs",
55
+ condition=(self.main_df[self.colname] < 8.0),
56
+ columns=columns,
57
+ drop=False,
58
+ )
59
+ )
60
+ row_defs.add(
61
+ RowDefinition(
62
+ colname=self.colname,
63
+ label="not measured",
64
+ condition=(self.main_df[self.colname].isna()),
65
+ columns=columns,
66
+ drop=False,
67
+ )
68
+ )
69
+ return row_defs
70
+
71
+
72
+ class FastingOgttTable(Table):
73
+ def __init__(self, main_df: pd.DataFrame = None):
74
+ super().__init__(colname="fasting_ogtt_hrs", main_df=main_df, title="")
75
+
76
+ @property
77
+ def row_definitions(self) -> RowDefinitions:
78
+ row_defs = RowDefinitions(reverse_rows=False)
79
+ columns = {
80
+ FEMALE: (MEDIAN_IQR, 2),
81
+ MALE: (MEDIAN_IQR, 2),
82
+ "All": (MEDIAN_IQR, 2),
83
+ }
84
+ row_defs.add(
85
+ RowDefinition(
86
+ colname=self.colname,
87
+ label="OGTT fasted (hours), median (IQR)",
88
+ condition=(self.main_df[self.colname].notna()),
89
+ columns=columns,
90
+ drop=False,
91
+ )
92
+ )
93
+ columns = {
94
+ FEMALE: (N_WITH_COL_PROP, 2),
95
+ MALE: (N_WITH_COL_PROP, 2),
96
+ "All": (N_WITH_ROW_PROP, 2),
97
+ }
98
+ row_defs.add(
99
+ RowDefinition(
100
+ colname=self.colname,
101
+ label="OGTT Fasted <8.0 hrs",
102
+ condition=(self.main_df[self.colname] < 8.0),
103
+ columns=columns,
104
+ drop=False,
105
+ )
106
+ )
107
+ row_defs.add(
108
+ RowDefinition(
109
+ colname=self.colname,
110
+ label="not measured",
111
+ condition=(self.main_df[self.colname].isna()),
112
+ columns=columns,
113
+ drop=False,
114
+ )
115
+ )
116
+ return row_defs
117
+
118
+
119
+ class FastingTable(Table):
120
+ def __init__(self, main_df: pd.DataFrame = None):
121
+ super().__init__(main_df=main_df, title="Fasting duration (hrs)")
122
+
123
+ def build_table_df(self) -> None:
124
+ df1 = FastingFbgTable(main_df=self.main_df).table_df
125
+ df2 = FastingOgttTable(main_df=self.main_df).table_df
126
+ self.table_df = pd.concat([df1, df2])
@@ -0,0 +1,98 @@
1
+ import pandas as pd
2
+ from edc_constants.constants import FEMALE, MALE
3
+
4
+ from ..constants import MEAN_95CI, N_ONLY, N_WITH_COL_PROP, N_WITH_ROW_PROP
5
+ from ..row import RowDefinition, RowDefinitions
6
+ from ..table import Table
7
+
8
+
9
+ class FbgTable(Table):
10
+ def __init__(self, main_df: pd.DataFrame = None):
11
+ super().__init__(colname="fbg", main_df=main_df, title="FBG (mmol/L) categories")
12
+
13
+ @property
14
+ def row_definitions(self) -> RowDefinitions:
15
+ df_tmp = self.main_df.copy()
16
+ row_defs = RowDefinitions(reverse_rows=False)
17
+ row0 = RowDefinition(
18
+ title=self.title,
19
+ label=self.default_sublabel,
20
+ condition=(df_tmp["gender"].notna()),
21
+ columns={FEMALE: (N_ONLY, 2), MALE: (N_ONLY, 2), "All": (N_ONLY, 2)},
22
+ drop=False,
23
+ )
24
+ row_defs.add(row0)
25
+
26
+ columns = {
27
+ FEMALE: (N_WITH_COL_PROP, 2),
28
+ MALE: (N_WITH_COL_PROP, 2),
29
+ "All": (N_WITH_ROW_PROP, 2),
30
+ }
31
+ row_defs.add(
32
+ RowDefinition(
33
+ colname=self.colname,
34
+ label="Not fasted",
35
+ condition=(self.main_df["fasting_fbg_hrs"] < 8.0),
36
+ columns=columns,
37
+ drop=True,
38
+ )
39
+ )
40
+
41
+ columns = {
42
+ FEMALE: (MEAN_95CI, 2),
43
+ MALE: (MEAN_95CI, 2),
44
+ "All": (MEAN_95CI, 2),
45
+ }
46
+ row_mean = RowDefinition(
47
+ colname=self.colname,
48
+ label="Mean (95% CI)",
49
+ condition=(self.main_df[self.colname].notna()),
50
+ columns=columns,
51
+ drop=False,
52
+ )
53
+ columns = {
54
+ FEMALE: (N_WITH_COL_PROP, 2),
55
+ MALE: (N_WITH_COL_PROP, 2),
56
+ "All": (N_WITH_ROW_PROP, 2),
57
+ }
58
+
59
+ row_defs.add(
60
+ RowDefinition(
61
+ colname=self.colname,
62
+ label="<6.1",
63
+ condition=(self.main_df[self.colname] < 6.1),
64
+ columns=columns,
65
+ drop=True,
66
+ )
67
+ )
68
+ row_defs.add(
69
+ RowDefinition(
70
+ colname=self.colname,
71
+ label="6.1-6.9",
72
+ condition=(self.main_df[self.colname] >= 6.1)
73
+ & (self.main_df[self.colname] < 7.0),
74
+ columns=columns,
75
+ drop=True,
76
+ )
77
+ )
78
+ row_defs.add(
79
+ RowDefinition(
80
+ colname=self.colname,
81
+ label="7.0 and above",
82
+ condition=(self.main_df[self.colname] >= 7.0),
83
+ columns=columns,
84
+ drop=True,
85
+ )
86
+ )
87
+ row_defs.add(
88
+ RowDefinition(
89
+ colname=self.colname,
90
+ label="not measured",
91
+ condition=(self.main_df[self.colname].isna()),
92
+ columns=columns,
93
+ drop=True,
94
+ )
95
+ )
96
+
97
+ row_defs.add(row_mean)
98
+ return row_defs