Skip to content
Merged

who #54

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 4.2.8
current_version = 4.3.0
tag = False
commit = True

Expand Down
17 changes: 15 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
FROM python:3.12-bookworm
FROM python:3.12

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file into the container
COPY requirements.txt .

RUN pip install -r requirements.txt
# Create a virtual environment
RUN python -m venv /app/venv

# Upgrade pip and install the dependencies in the virtual environment
RUN /app/venv/bin/pip install --upgrade pip
RUN /app/venv/bin/pip install -r requirements.txt

# Copy the rest of the application code
COPY . .

# Set the entrypoint to use the virtual environment's Python interpreter
CMD ["python3"]
6 changes: 2 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# NOTE The below is the Docker Compose specification version NOT the Python version:
version: "3.8"
version: "3.12"

services:
rcpchgrowth-python:
Expand All @@ -9,5 +8,4 @@ services:
working_dir: /app
tty: true # Allocate a pseudo-TTY
stdin_open: true # Keep stdin open
command: |
pytest
container_name: rcpchgrowth-python
4 changes: 2 additions & 2 deletions rcpchgrowth/age_advice_strings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from rcpchgrowth.constants import CDC
from rcpchgrowth.constants import CDC, WHO

def comment_prematurity_correction(
chronological_decimal_age: float,
Expand All @@ -17,7 +17,7 @@ def comment_prematurity_correction(
lay_chronological_decimal_age_comment = "Your child was born on their due date."
clinician_chronological_decimal_age_comment = "Born Term. No correction has been made for gestation."
# These fields should only apply to CDC reference, since UK-WHO corrects for all gestations (and therefore corrected_decimal_age will never be equal to chronological_decimal_age if gestation_weeks is not 40)
if gestation_weeks < 42 and reference == CDC:
if gestation_weeks < 42 and (reference == CDC or reference == WHO):
if gestation_weeks < 37:
lay_chronological_decimal_age_comment = f"Your child was born at {gestation_weeks}+{gestation_days} weeks gestation. No correction is made for this beyond 2 years of age."
clinician_chronological_decimal_age_comment =f"Born preterm at {gestation_weeks}+{gestation_days} weeks gestation. No correction is made for this beyond 2 years of age."
Expand Down
196 changes: 193 additions & 3 deletions rcpchgrowth/chart_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .trisomy_21_aap import select_reference_data_for_trisomy_21_aap
from .turner import select_reference_data_for_turner
from .uk_who import select_reference_data_for_uk_who_chart
from .who import who_reference, select_reference_data_for_who_chart
from .constants.reference_constants import (
CDC_REFERENCES,
CDC,
Expand All @@ -25,6 +26,8 @@
TURNERS,
UK_WHO,
UK_WHO_REFERENCES,
WHO,
WHO_REFERENCES
)

"""
Expand Down Expand Up @@ -70,6 +73,12 @@ def create_chart(
sex=sex,
centile_format=centile_format,
is_sds=is_sds)
elif reference == WHO:
return create_who_chart(
measurement_method=measurement_method,
sex=sex,
centile_format=centile_format,
is_sds=is_sds)
else:
print("No reference data returned. Is there a spelling mistake in your reference?")

Expand Down Expand Up @@ -109,7 +118,7 @@ def generate_custom_sds_line(
centile=custom_centile
)
except:
print("Could not generate centile data.")
print("Could not generate centile data for UK-WHO.")
centile_data=[]
# all data can now be tagged by reference_name and added to reference_data
reference_data.append({reference: centile_data})
Expand All @@ -131,7 +140,30 @@ def generate_custom_sds_line(
centile=custom_centile
)
except:
print(f"Could not generate SDS centile data.")
print(f"Could not generate SDS centile data for {CDC}.")
centile_data=[]
# all data can now be tagged by reference_name and added to reference_data
reference_data.append({reference: centile_data})
elif reference == WHO:
for reference_index, reference in enumerate(WHO_REFERENCES):
# the centile reference data
lms_array_for_measurement=select_reference_data_for_who_chart(
who_reference_name=reference,
measurement_method=measurement_method,
sex=sex
)
centile_data=[]
try:
centile_data= build_centile_object(
reference=WHO,
measurement_method=measurement_method,
sex=sex,
lms_array_for_measurement=lms_array_for_measurement,
z=custom_sds,
centile=custom_centile
)
except:
print(f"Could not generate SDS centile data for WHO.")
centile_data=[]
# all data can now be tagged by reference_name and added to reference_data
reference_data.append({reference: centile_data})
Expand Down Expand Up @@ -219,6 +251,8 @@ def select_reference_lms_data(reference: str, measurement_method: str, sex: str)
lms_array_for_measurement=select_reference_data_for_trisomy_21(measurement_method=measurement_method, sex=sex)
elif reference == CDC:
lms_array_for_measurement=select_reference_data_for_cdc_chart(measurement_method=measurement_method, sex=sex)
elif reference == WHO:
lms_array_for_measurement=select_reference_data_for_who_chart(measurement_method=measurement_method, sex=sex)
else:
raise Exception("No data has been selected!")

Expand Down Expand Up @@ -907,7 +941,163 @@ def create_trisomy_21_aap_chart(measurement_method: str, sex: str, centile_forma
]
"""

# Private functions
def create_who_chart(
measurement_method: str,
sex: str,
centile_format: Union[str, list] = COLE_TWO_THIRDS_SDS_NINE_CENTILES,
is_sds = False
):

# user selects which centile collection they want, for sex and measurement_method
# If the Cole method is selected, conversion between centile and SDS
# is different as SDS is rounded to the nearest 2/3
# Cole method selection is stored in the cole_method flag.
# If no parameter is passed, default is the Cole method
# Alternatively it is possible to pass a custom list of values - if the is_sds flag is False (default) these are centiles

centile_sds_collection = []
cole_method = False

if (type(centile_format) is list):
# a custom list of centiles was provided
centile_sds_collection = centile_format
else:
# a standard centile collection was selected
centile_sds_collection = select_centile_format(centile_format)
is_sds=False

##
# iterate through the 3 references that make up CDC (Fenton, WHO, CDC itself)
# There will be a list for each one
##

# all data for a given reference are stored here: this is returned to the user
reference_data = []

for reference_index, reference_name in enumerate(WHO_REFERENCES):
sex_list: dict = {} # all the data for a given sex are stored here
# For each reference we have 2 sexes
# for sex_index, sex in enumerate(SEXES):
# For each sex we have 4 measurement_methods

measurements: dict = {} # all the data for a given measurement_method are stored here

# for measurement_index, measurement_method in enumerate(MEASUREMENT_METHODS):
# for every measurement method we have as many centiles
# as have been requested

centiles = [] # all generated centiles for a selected centile collection are stored here

default_youngest_reference = False
if reference_index == 1: # WHO children
default_youngest_reference = True

# the centile reference data
try:
lms_array_for_measurement=select_reference_data_for_who_chart(
who_reference_name=reference_name,
measurement_method=measurement_method,
sex=sex,
default_youngest_reference=default_youngest_reference)
except:
lms_array_for_measurement = []

for centile_index, centile_sds in enumerate(centile_sds_collection):
# we must create a z for each requested centile
# if the Cole 9 centiles were selected, these are rounded,
# so conversion to SDS is different
# Otherwise standard conversation of centile to z is used

z=0.0 #initialise
centile_value=0.0 #initialise

if cole_method:
z = rounded_sds_for_centile(centile_sds) # a centile was provided, so convert to z
centile_value=centile_sds # store the original centile value
else:
if (is_sds):
z=centile_sds # an sds was supplied
centile_value=centile(centile_sds) # convert the z to a centile and store
else:
z = sds_for_centile(centile_sds) # a centile was provided, so convert to z
centile_value=centile_sds # store the original centile value
centile_data = []

try:
# Generate a centile. there will be nine of these if Cole method selected.
# Some data does not exist at all ages, so any error reflects missing data.
# If this happens, an empty list is returned.
centile_data = generate_centile(
z=z,
centile=centile_value,
measurement_method=measurement_method,
sex=sex,
lms_array_for_measurement=lms_array_for_measurement,
reference=WHO,
is_sds=is_sds,
default_youngest_reference=default_youngest_reference
)
except LookupError as e:
print(f"Not possible to generate centile data for WHO {measurement_method} in {sex}s. {e}")
centile_data=None
# Store this centile for a given measurement

centiles.append({"sds": round(z * 100) / 100,
"centile": centile_value, "data": centile_data})

# this is the end of the centile_collection for loop
# All the centiles for this measurement, sex and reference are added to the measurements list
measurements.update({measurement_method: centiles})

# this is the end of the measurement_methods loop
# All data for all measurement_methods for this sex are added to the sex_list list

sex_list.update({sex: measurements})

# all data can now be tagged by reference_name and added to reference_data
reference_data.append({reference_name: sex_list})

# returns a list of 4 references, each containing 2 lists for each sex,
# each sex in turn containing 4 datasets for each measurement_method
return reference_data

"""
# return object structure
[ cdc_infant: {
male: {
height: [
{
sds: -2.667,
centile: 0.4
data: [{l: , x: , y: }, ....]
}
],
weight: [...],
bmi: [...],
ofc: [...]
},
female {...}
},
cdc_child: {
male: {
height: [
{
sds: -2.667,
centile: 0.4
data: [{l: , x: , y: }, ....]
}
],
weight: [...],
bmi: [...],
ofc: [...]
},
female {...}
}
]
"""



def select_centile_format(centile_format: str):
"""
Select the centile format
Expand Down
4 changes: 4 additions & 0 deletions rcpchgrowth/constants/age_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
FORTY_TWO_WEEKS_GESTATION = ((42 * 7) - (40 * 7)) / 365.25 # 42 weeks as decimal age
TWENTY_THREE_WEEKS_GESTATION = ((23 * 7) - (40 * 7)) / 365.25 # 23 weeks as decimal age
FIFTY_WEEKS_GESTATION = ((50 * 7) - (40 * 7)) / 365.25 # 50 weeks as decimal age
ZERO_YEARS = 0.0
TWO_YEARS = 2.0
THREE_YEARS = 3.0
FIVE_YEARS = 5.0
TEN_YEARS = 10.0
SEVENTEEN_YEARS = 17.0
EIGHTEEN_YEARS = 18.0
NINETEEN_YEARS = 19.0
TWENTY_YEARS = 20.0
TERM_WEEKS = 40
LOWER_THRESHOLD_PRETERM_REFERENCE_WEEKS = 23
14 changes: 13 additions & 1 deletion rcpchgrowth/constants/reference_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@
FENTON = "fenton" # Fenton is the reference name for preterm infants
CDC_REFERENCES = [FENTON, CDC_INFANT, CDC_CHILD] # CDC references

# WHO constants
WHO = "who" # WHO is the overarching reference
WHO_2006_INFANT = "who_2006_infant" # WHO 2006 infant is the reference name for children 0-2 years
WHO_2006_CHILD = "who_2006_child" # WHO 2006 child is the reference name for children 2-5 years
WHO_2007_CHILD = "who_2007_child" # WHO 2007 child is the reference name for children 5-19 years
WHO_REFERENCES = [WHO_2006_INFANT, WHO_2006_CHILD, WHO_2007_CHILD] # WHO references

WHO_2006_REFERENCE_LOWER_THRESHOLD = ((42 * 7) - (40 * 7)) / 365.25 # 42 weeks as decimal age # 2 weeks as decimal age
WHO_2006_REFERENCE_UPPER_THRESHOLD = 5.0 # 5 years as decimal age
WHO_2007_REFERENCE_LOWER_THRESHOLD = 5.0 # 5 years as decimal age
WHO_2007_REFERENCE_UPPER_THRESHOLD = 19.0 # 19 years as decimal age

# 23 weeks is the lowest decimal age available on the UK90 charts
UK90_REFERENCE_LOWER_THRESHOLD = (
(23 * 7) - (40 * 7)
Expand Down Expand Up @@ -64,7 +76,7 @@
WEIGHT = "weight"
HEAD_CIRCUMFERENCE = "ofc"
BMI = "bmi"
REFERENCES = [UK_WHO, TRISOMY_21, TURNERS]
REFERENCES = [UK_WHO, TRISOMY_21, TRISOMY_21_AAP, TURNERS, CDC, WHO]
SEXES = [MALE, FEMALE]
MEASUREMENT_METHODS = [HEIGHT, WEIGHT, HEAD_CIRCUMFERENCE, BMI]

Expand Down
Loading
Loading