meta-edc 0.3.36__py3-none-any.whl → 0.3.38__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.
Files changed (37) hide show
  1. meta_analytics/__init__.py +1 -1
  2. meta_analytics/dataframes/__init__.py +1 -0
  3. meta_analytics/dataframes/constants.py +1 -1
  4. meta_analytics/dataframes/get_eos_df.py +26 -0
  5. meta_analytics/dataframes/glucose_endpoints/glucose_endpoints_by_date.py +102 -79
  6. meta_analytics/dataframes/screening/get_screening_df.py +42 -6
  7. meta_analytics/get_tables.py +4 -28
  8. meta_edc/settings/debug.py +2 -2
  9. meta_edc-0.3.38.dist-info/METADATA +766 -0
  10. {meta_edc-0.3.36.dist-info → meta_edc-0.3.38.dist-info}/RECORD +36 -20
  11. {meta_edc-0.3.36.dist-info → meta_edc-0.3.38.dist-info}/WHEEL +1 -1
  12. meta_pharmacy/admin/__init__.py +3 -0
  13. meta_pharmacy/admin/label_admin.py +0 -0
  14. meta_pharmacy/admin/lot_number_admin.py +43 -0
  15. meta_pharmacy/admin/rx_admin.py +75 -0
  16. meta_pharmacy/{admin.py → admin/substitutions_admin.py} +3 -71
  17. meta_pharmacy/labels/__init__.py +2 -0
  18. meta_pharmacy/labels/get_label_data.py +30 -0
  19. meta_pharmacy/labels/print_sheets.py +86 -0
  20. meta_pharmacy/migrations/0006_lotnumber_label.py +289 -0
  21. meta_pharmacy/migrations/0007_lotnumber_medication.py +24 -0
  22. meta_pharmacy/models/__init__.py +4 -0
  23. meta_pharmacy/models/label.py +50 -0
  24. meta_pharmacy/models/lot_number.py +25 -0
  25. meta_pharmacy/models/rx.py +18 -0
  26. meta_pharmacy/{models.py → models/substitutions.py} +2 -16
  27. meta_reports/admin/endpoints_admin.py +1 -1
  28. meta_reports/admin/modeladmin_mixins.py +5 -5
  29. meta_reports/migrations/0050_alter_endpoints_created.py +19 -0
  30. meta_reports/migrations/0051_remove_endpoints_baseline_datetime_and_more.py +40 -0
  31. meta_reports/models/dbviews/imp_substitutions/unmanaged_model.py +3 -1
  32. meta_reports/models/endpoints.py +3 -3
  33. meta_visit_schedule/visit_schedules/phase_three/crfs.py +1 -0
  34. meta_edc-0.3.36.dist-info/METADATA +0 -94
  35. {meta_edc-0.3.36.dist-info → meta_edc-0.3.38.dist-info}/AUTHORS +0 -0
  36. {meta_edc-0.3.36.dist-info → meta_edc-0.3.38.dist-info}/LICENSE +0 -0
  37. {meta_edc-0.3.36.dist-info → meta_edc-0.3.38.dist-info}/top_level.txt +0 -0
@@ -1,2 +1,2 @@
1
- from .dataframes import get_glucose_tested_only_df, get_screening_df
1
+ from .dataframes import get_eos_df, get_glucose_tested_only_df, get_screening_df
2
2
  from .get_tables import get_tables
@@ -7,6 +7,7 @@ from .constants import (
7
7
  endpoint_cases,
8
8
  endpoint_columns,
9
9
  )
10
+ from .get_eos_df import get_eos_df
10
11
  from .glucose_endpoints import EndpointByDate, GlucoseEndpointsByDate
11
12
  from .screening import get_glucose_tested_only_df, get_screening_df
12
13
  from .utils import (
@@ -8,7 +8,7 @@ OGTT_THRESHOLD_MET = "OGTT >= 11.1"
8
8
 
9
9
  endpoint_columns = [
10
10
  "subject_identifier",
11
- "site",
11
+ "site_id",
12
12
  "baseline_datetime",
13
13
  "visit_datetime",
14
14
  "interval_in_days",
@@ -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
@@ -28,26 +28,34 @@ from ..utils import (
28
28
  from .endpoint_by_date import EndpointByDate
29
29
 
30
30
 
31
- def normalize_date_columns(df: pd.DataFrame, cols: list[str] = None) -> pd.DataFrame:
32
- """Normalize date columns by flooring"""
33
- for col in cols:
34
- if not df[col].empty:
35
- df[col] = df[col].dt.floor("d")
36
- else:
37
- df[col] = pd.NaT
38
- return df
39
-
40
-
41
31
  def calculate_fasting_hrs(df: pd.DataFrame):
42
32
  df.loc[(df["fasting"] == NO), "fasting_duration_delta"] = pd.NaT
43
33
  if df.empty:
44
34
  df["fasting_hrs"] = np.nan
45
35
  else:
46
- df["fasting_hrs"] = df["fasting_duration_delta"].dt.total_seconds() / 3600
36
+ df["fasting_hrs"] = df["fasting_duration_delta"].apply(
37
+ lambda s: np.nan if pd.isna(s) else s.total_seconds() / 3600
38
+ )
47
39
  return df
48
40
 
49
41
 
50
42
  class GlucoseEndpointsByDate:
43
+ """
44
+ Usage:
45
+ cls = GlucoseEndpointsByDate()
46
+ cls.run()
47
+
48
+ # subjects who reached endpoint
49
+ cls.endpoint_only_df.endpoint_type.value_counts()
50
+ cls.endpoint_only_df.endpoint_label.value_counts()
51
+
52
+ # subjects who reached endpoint with total
53
+ result_df = cls.endpoint_only_df.endpoint_label.value_counts().to_frame().reset_index()
54
+ result_df.columns = ["endpoint_label", "total"]
55
+ result_df.loc[-1] = ["total", result_df.total.sum()]
56
+ result_df = result_df.reset_index(drop=True)
57
+ result_df
58
+ """
51
59
 
52
60
  fbg_threshhold = 7.0
53
61
  ogtt_threshhold = 11.1
@@ -67,7 +75,7 @@ class GlucoseEndpointsByDate:
67
75
  "subject_identifier",
68
76
  "visit_code",
69
77
  "visit_datetime",
70
- "site",
78
+ "site_id",
71
79
  "baseline_datetime",
72
80
  ]
73
81
 
@@ -88,40 +96,75 @@ class GlucoseEndpointsByDate:
88
96
  self.endpoint_cases = {k: v for k, v in endpoint_cases.items() if k in self.case_list}
89
97
 
90
98
  # merge two model DFs
91
- self.df = self.glucose_fbg_ogtt_df.merge(
92
- self.glucose_fbg_df,
93
- on=["subject_visit_id"],
94
- how="outer",
95
- indicator=True,
96
- suffixes=("", "_y"),
99
+ if self.glucose_fbg_ogtt_df.empty:
100
+ self.df = self.glucose_fbg_df.copy()
101
+ self.df[["ogtt_value", "ogtt_units"]] = np.nan
102
+ self.df[["ogtt_datetime"]] = pd.NaT
103
+ elif self.glucose_fbg_df.empty:
104
+ self.df = self.glucose_fbg_ogtt_df.copy()
105
+ else:
106
+ self.df = self.glucose_fbg_ogtt_df.merge(
107
+ self.glucose_fbg_df,
108
+ on=["subject_visit_id"],
109
+ how="outer",
110
+ indicator=True,
111
+ suffixes=("", "_y"),
112
+ )
113
+ # cast as ...
114
+ for col in ["fasting_hrs", "fbg_value"]:
115
+ self.df[col] = self.df[col].astype("float64")
116
+ if f"{col}_y" in self.df.columns:
117
+ self.df[f"{col}_y"] = self.df[f"{col}_y"].astype("float64")
118
+ for col in ["fasting", "fbg_units", "source"]:
119
+ self.df[col] = self.df[col].astype("object")
120
+ if f"{col}_y" in self.df.columns:
121
+ self.df[f"{col}_y"] = self.df[f"{col}_y"].astype("object")
122
+ self.df = self.df.drop(
123
+ columns=[col for col in self.df.columns if col.endswith("_y") or col == "_merge"]
124
+ )
125
+ self.df = self.df.reset_index(drop=True)
126
+
127
+ # merge w/ subject_visit
128
+ subject_visit_df = get_subject_visit(
129
+ "meta_subject.subjectvisit", subject_identifiers=self.subject_identifiers
130
+ )
131
+ self.df = subject_visit_df.merge(
132
+ self.df, on=["subject_visit_id"], how="left", suffixes=("", "_y")
97
133
  )
134
+ self.df = self.df[[col for col in self.keep_cols]]
98
135
  self.df = self.df.reset_index(drop=True)
99
136
 
100
137
  # pivot right_only cols
101
- cols = {
102
- "fasting": None,
103
- "fasting_hrs": np.nan,
104
- "fbg_value": None,
105
- "fbg_units": None,
106
- "fbg_datetime": None,
107
- "source": None,
108
- "report_datetime": pd.NaT,
109
- }
110
- for col, null_value in cols.items():
111
- self.df.loc[
112
- (self.df["_merge"].isin(["both", "right_only"])) & (self.df[col].isna()), col
113
- ] = self.df[f"{col}_y"]
114
- # if fbg_datetime still null, use visit datetime to sort order
115
- self.df.loc[(self.df["fbg_datetime"].isna()), "fbg_datetime"] = self.df[
116
- "visit_datetime"
138
+ cols = [
139
+ "fasting",
140
+ "fasting_hrs",
141
+ "fbg_value",
142
+ "fbg_units",
143
+ "fbg_datetime",
144
+ "source",
145
+ "report_datetime",
117
146
  ]
118
- cols = [col for col in self.df.columns if col.endswith("_y")]
119
- cols.append("_merge")
120
- self.df = self.df.drop(columns=cols)
147
+ for col in cols:
148
+ if f"{col}_y" in self.df.columns and not self.df[f"{col}_y"].isnull().all():
149
+ self.df.loc[
150
+ (self.df["_merge"].isin(["both", "right_only"])) & (self.df[col].isna()),
151
+ col,
152
+ ] = self.df[f"{col}_y"]
153
+ # if fbg_datetime still null, use visit datetime
154
+ if self.df["fbg_datetime"].isnull().all():
155
+ self["fbg_datetime"] = self.df["visit_datetime"]
156
+ else:
157
+ self.df.loc[(self.df["fbg_datetime"].isna()), "fbg_datetime"] = self.df[
158
+ "visit_datetime"
159
+ ]
160
+ self.df = self.df.drop(
161
+ columns=[col for col in self.df.columns if col.endswith("_y") or col == "_merge"]
162
+ )
121
163
  self.df = self.df.reset_index(drop=True)
122
164
 
123
165
  self.merge_with_consent()
124
166
  self.merge_with_eos()
167
+
125
168
  self.add_calculated_days_from_baseline_to_event_columns()
126
169
 
127
170
  # label rows by type of glu tests (ones with value)
@@ -173,23 +216,15 @@ class GlucoseEndpointsByDate:
173
216
  df = get_crf(
174
217
  model="meta_subject.glucosefbg",
175
218
  subject_identifiers=self.subject_identifiers,
176
- subject_visit_model="meta_subject.subjectvisit",
177
- )
178
- # merge w/ subject_visit
179
- subject_visit_df = get_subject_visit("meta_subject.subjectvisit")
180
- df = subject_visit_df.merge(
181
- df, on=["subject_visit_id"], how="left", suffixes=("", "_y")
219
+ # subject_visit_model="meta_subject.subjectvisit",
182
220
  )
183
221
  df["source"] = "meta_subject.glucosefbg"
184
222
  df.rename(columns={"fbg_fasting": "fasting"}, inplace=True)
185
223
  df.loc[(df["fasting"] == "fasting"), "fasting"] = YES
186
224
  df.loc[(df["fasting"] == "non_fasting"), "fasting"] = NO
187
225
  df = calculate_fasting_hrs(df)
188
- df = df[[col for col in self.keep_cols if not col.startswith("ogtt")]]
226
+ # df = df[[col for col in self.keep_cols if not col.startswith("ogtt")]]
189
227
  df = df.reset_index(drop=True)
190
- df = normalize_date_columns(
191
- df, cols=["fbg_datetime", "report_datetime", "visit_datetime"]
192
- )
193
228
  self._glucose_fbg_df = df
194
229
  return self._glucose_fbg_df
195
230
 
@@ -203,27 +238,23 @@ class GlucoseEndpointsByDate:
203
238
  df = get_crf(
204
239
  model="meta_subject.glucose",
205
240
  subject_identifiers=self.subject_identifiers,
206
- subject_visit_model="meta_subject.subjectvisit",
241
+ # subject_visit_model="meta_subject.subjectvisit",
207
242
  )
208
243
  df["source"] = "meta_subject.glucose"
209
- # merge w/ subject_visit
210
- subject_visit_df = get_subject_visit("meta_subject.subjectvisit")
211
- df = subject_visit_df.merge(
212
- df, on=["subject_visit_id"], how="left", suffixes=("", "_y")
213
- )
214
244
  df = calculate_fasting_hrs(df)
215
- df = df[self.keep_cols]
245
+ # df = df[self.keep_cols]
216
246
  df = df.reset_index(drop=True)
217
- df = normalize_date_columns(
218
- df, cols=["fbg_datetime", "ogtt_datetime", "report_datetime", "visit_datetime"]
219
- )
220
247
  self._glucose_fbg_ogtt_df = df
221
248
  return self._glucose_fbg_ogtt_df
222
249
 
223
250
  def merge_with_consent(self):
224
251
  """Merge in consent DF."""
225
- df_consent = get_subject_consent("meta_consent.subjectconsent")
226
- self.df = pd.merge(self.df, df_consent, on="subject_identifier", how="left")
252
+ df_consent = get_subject_consent(
253
+ "meta_consent.subjectconsent", subject_identifiers=self.subject_identifiers
254
+ )
255
+ self.df = pd.merge(
256
+ self.df, df_consent, on="subject_identifier", how="left", suffixes=("", "_y")
257
+ )
227
258
  self.df = self.df.sort_values(by=["subject_identifier", "fbg_datetime"])
228
259
  self.df = self.df.reset_index(drop=True)
229
260
 
@@ -232,7 +263,7 @@ class GlucoseEndpointsByDate:
232
263
 
233
264
  Drops patients who were taken off study by late exclusion.
234
265
  """
235
- df_eos = get_eos("meta_prn.endofstudy")
266
+ df_eos = get_eos("meta_prn.endofstudy", subject_identifiers=self.subject_identifiers)
236
267
  df_eos = df_eos[
237
268
  df_eos["offstudy_reason"]
238
269
  != (
@@ -240,7 +271,9 @@ class GlucoseEndpointsByDate:
240
271
  "values or raised blood pressure at enrolment"
241
272
  )
242
273
  ]
243
- self.df = pd.merge(self.df, df_eos, on="subject_identifier", how="left")
274
+ self.df = pd.merge(
275
+ self.df, df_eos, on="subject_identifier", how="left", suffixes=("", "_y")
276
+ )
244
277
  self.df = self.df.sort_values(by=["subject_identifier", "fbg_datetime"])
245
278
  self.df = self.df.reset_index(drop=True)
246
279
 
@@ -255,11 +288,11 @@ class GlucoseEndpointsByDate:
255
288
  self.df["visit_days"] = (
256
289
  self.df["visit_datetime"] - self.df["baseline_datetime"]
257
290
  ).dt.days
258
- if not self.df["fbg_datetime"].empty:
291
+ if not self.df["fbg_datetime"].isnull().all():
259
292
  self.df["fbg_days"] = (
260
293
  self.df["fbg_datetime"] - self.df["baseline_datetime"]
261
294
  ).dt.days
262
- if not self.df["ogtt_datetime"].empty:
295
+ if not self.df["ogtt_datetime"].isnull().all():
263
296
  self.df["ogtt_days"] = (
264
297
  self.df["ogtt_datetime"] - self.df["baseline_datetime"]
265
298
  ).dt.days
@@ -375,16 +408,6 @@ class GlucoseEndpointsByDate:
375
408
  subject_df = subject_df[endpoint_columns]
376
409
  subject_df = subject_df.sort_values(["subject_identifier", "fbg_datetime"])
377
410
  subject_df = subject_df.reset_index(drop=True)
378
- # subject_df = subject_df.merge(
379
- # self.visit_codes_df,
380
- # on="visit_code",
381
- # how="outer",
382
- # indicator=False,
383
- # suffixes=["", "2"],
384
- # )
385
- # subject_df["subject_identifier"] = subject_identifier
386
- # subject_df = subject_df.drop(columns=["count"])
387
- # subject_df = subject_df.reset_index(drop=True)
388
411
  return subject_df
389
412
 
390
413
  def check_endpoint_by_fbg_for_subject(
@@ -476,24 +499,24 @@ class GlucoseEndpointsByDate:
476
499
  model_cls.objects.all().delete()
477
500
  created = 0
478
501
  if not df.empty:
502
+ df["fbg_datetime"] = df["fbg_datetime"].dt.tz_localize("UTC")
503
+ df["baseline_datetime"] = df["baseline_datetime"].dt.tz_localize("UTC")
479
504
  data = [
480
505
  model_cls(
481
506
  subject_identifier=row["subject_identifier"],
482
- site_id=row["site"],
483
- baseline_datetime=(
507
+ site_id=row["site_id"],
508
+ baseline_date=(
484
509
  None if pd.isna(row["baseline_datetime"]) else row["baseline_datetime"]
485
510
  ),
486
511
  visit_code=None if pd.isna(row["visit_code"]) else row["visit_code"],
487
512
  fbg_value=(None if pd.isna(row["fbg_value"]) else row["fbg_value"]),
488
513
  ogtt_value=None if pd.isna(row["ogtt_value"]) else row["ogtt_value"],
489
- fbg_datetime=(
490
- None if pd.isna(row["fbg_datetime"]) else row["fbg_datetime"]
491
- ),
514
+ fbg_date=(None if pd.isna(row["fbg_datetime"]) else row["fbg_datetime"]),
492
515
  fasting=(None if pd.isna(row["fasting"]) else row["fasting"]),
493
516
  endpoint_label=(
494
517
  None if pd.isna(row["endpoint_label"]) else row["endpoint_label"]
495
518
  ),
496
- offstudy_datetime=(
519
+ offstudy_date=(
497
520
  None if pd.isna(row["offstudy_datetime"]) else row["offstudy_datetime"]
498
521
  ),
499
522
  offstudy_reason=(
@@ -9,13 +9,33 @@ from meta_subject.models import PhysicalExam, SubjectVisit
9
9
  def get_screening_df(df: pd.DataFrame | None = None) -> pd.DataFrame:
10
10
  df = pd.DataFrame() if not hasattr(df, "empty") else df
11
11
  if df.empty:
12
- qs_screening = SubjectScreening.objects.all()
13
- df = read_frame(qs_screening)
14
- df = df.drop(df[df["hiv_pos"] == "No"].index)
15
- # df = df.drop(df[df["meta_phase_two"] == "Yes"].index)
12
+ cols = [
13
+ f.name
14
+ for f in SubjectScreening._meta.get_fields()
15
+ if f.name
16
+ not in [
17
+ "contact_number",
18
+ "initials",
19
+ "hospital_identifier",
20
+ "modified",
21
+ "user_created",
22
+ "user_modified",
23
+ "hostname_created",
24
+ "hostname_modified",
25
+ "device_created",
26
+ "device_modified",
27
+ "locale_created",
28
+ "locale_modified",
29
+ "slug",
30
+ ]
31
+ ]
32
+ qs_screening = SubjectScreening.objects.values(*cols).all()
33
+ df = read_frame(qs_screening, verbose=False)
34
+ df = df.drop(df[df["hiv_pos"] == "No"].index) # removes 2 rows
35
+ df = df.reset_index(drop=True)
16
36
 
17
37
  # convert all to float
18
- cols = [
38
+ num_cols = [
19
39
  "age_in_years",
20
40
  "calculated_bmi_value",
21
41
  "converted_fbg2_value",
@@ -31,7 +51,23 @@ def get_screening_df(df: pd.DataFrame | None = None) -> pd.DataFrame:
31
51
  "sys_blood_pressure_avg",
32
52
  "waist_circumference",
33
53
  ]
34
- df[cols] = df[cols].apply(pd.to_numeric)
54
+ df[num_cols] = df[num_cols].apply(pd.to_numeric)
55
+
56
+ df["reasons_ineligible_part_one"] = df["reasons_ineligible_part_one"].apply(
57
+ lambda x: None if x == "" else x
58
+ )
59
+ df["reasons_ineligible_part_two"] = df["reasons_ineligible_part_two"].apply(
60
+ lambda x: None if x == "" else x
61
+ )
62
+ df["reasons_ineligible_part_two"] = df["reasons_ineligible_part_two"].str.replace(
63
+ "Has Dm", "Diabetes"
64
+ )
65
+ df["reasons_ineligible_part_two"] = df["reasons_ineligible_part_two"].str.replace(
66
+ "On Dm Medication", "taking anti-diabetic medications"
67
+ )
68
+ df["reasons_ineligible_part_three"] = df["reasons_ineligible_part_three"].apply(
69
+ lambda x: None if x == "" else x
70
+ )
35
71
 
36
72
  # condition to include any glucose test
37
73
 
@@ -1,6 +1,3 @@
1
- from datetime import datetime
2
- from pathlib import Path
3
-
4
1
  import pandas as pd
5
2
  from edc_analytics.custom_tables import (
6
3
  AgeTable,
@@ -15,31 +12,10 @@ from edc_analytics.custom_tables import (
15
12
  OgttTable,
16
13
  WaistCircumferenceTable,
17
14
  )
15
+ from edc_analytics.data import Data
18
16
 
19
- from meta_analytics.dataframes import get_glucose_tested_only_df, get_screening_df
20
- from meta_analytics.tables import EligibleP12Table, HasDmTable
21
-
22
-
23
- class Data:
24
- def __init__(self, label: str, table_df: pd.DataFrame, data_df: pd.DataFrame):
25
- self.label = label
26
- self.table_df = table_df
27
- self.data_df = data_df
28
-
29
- def __repr__(self):
30
- return f"{self.label} obs={len(self.data_df)}"
31
-
32
- def to_csv(
33
- self, folder: str | None = None, filename: str | None = None, cols: int | None = None
34
- ):
35
- folder = folder or "/Users/erikvw/Documents/ucl/protocols/meta3/reports/"
36
- cols = cols or 5
37
- datestamp = datetime.now().strftime("%Y%m%d%H%M")
38
- filename = filename or f"meta3_table_{self.label}_{datestamp}.csv"
39
- path = Path(folder) / filename
40
- self.table_df.iloc[:, :cols].to_csv(
41
- path_or_buf=path, encoding="utf-8", index=0, sep="|"
42
- )
17
+ from .dataframes import get_glucose_tested_only_df, get_screening_df
18
+ from .tables import EligibleP12Table, HasDmTable
43
19
 
44
20
 
45
21
  def get_tables() -> dict[str, Data]:
@@ -101,5 +77,5 @@ def get_tables() -> dict[str, Data]:
101
77
  ]:
102
78
  tbl = tbl_cls(main_df=df)
103
79
  dfs.append(tbl.table_df)
104
- results.update({key: Data(key, pd.concat(list(dfs)), df)})
80
+ results.update({key: Data(key, pd.concat(list(dfs)), df, "meta3")})
105
81
  return results
@@ -7,8 +7,8 @@ from .defaults import * # noqa
7
7
  print(f"Settings file {__file__}")
8
8
 
9
9
  # TZ Sites:
10
- # SITE_ID = SiteID(default=20) # Amana
11
- SITE_ID = SiteID(default=10) # Hindu Mandal
10
+ SITE_ID = SiteID(default=20) # Amana
11
+ # SITE_ID = SiteID(default=10) # Hindu Mandal
12
12
  # SITE_ID = SiteID(default=40) # Mwananyamala
13
13
  # SITE_ID = SiteID(default=50) # Mbagala
14
14
  # SITE_ID = SiteID(default=60) # Mnazi-Moja