Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

trisomy-21-bmi-rendering-issue-fix #96

Merged
merged 5 commits into from
Aug 12, 2024
Merged
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 package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rcpch/digital-growth-charts-react-component-library",
"version": "7.0.7",
"version": "7.0.8",
"description": "A React component library for the RCPCH digital growth charts using Rollup, TypeScript and Styled-Components",
"main": "build/index.js",
"module": "build/esm.index.js",
Expand Down
19 changes: 19 additions & 0 deletions src/CentileChart/CentileChart.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { termToOverFourYearsGirlHeight } from '../testParameters/measurements/te
import { turnerHeightOneYearToEleven } from '../testParameters/measurements/turnerHeightOneYearToEleven';
import { beforeDueDateError } from '../testParameters/measurements/beforeDueDateError';
import { termBabyGirlWeight } from '../testParameters/measurements/termBabyGirlWeight';
import { trisomy21HighBMI } from '../testParameters/measurements/trisomy21HighBMI';

export default {
title: 'CentileChart',
Expand Down Expand Up @@ -463,6 +464,24 @@ export const WithTermBabyGirlWeight = () => (
/>
);

export const WithTrisomy21HighBMI = () => (
<CentileChart
chartsVersion="7.0.0"
reference="trisomy-21"
title="Trisomy 21 Child"
subtitle="High BMI Boy"
measurementMethod="bmi"
sex="male"
childMeasurements={trisomy21HighBMI}
midParentalHeightData={midParentalHeights}
enableZoom={true}
styles={Tanner3Styles}
enableExport={true}
exportChartCallback={() => null}
clinicianFocus={true}
/>
);

// props

const midParentalHeights = {};
2 changes: 1 addition & 1 deletion src/chartdata/reference-data.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export { ukwhoBMIFemaleCentileData }
export { ukwhoBMIMaleSDSData }
export { ukwhoBMIFemaleSDSData }

export { ukwhoCustomData }
// export { ukwhoCustomData }

export { trisomy21HeightMaleCentileData }
export { trisomy21HeightFemaleCentileData }
Expand Down
9 changes: 8 additions & 1 deletion src/functions/getDomainsAndData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { trisomy21WeightFemaleCentileData } from '../chartdata/trisomy21_weight_
import { trisomy21OFCMaleCentileData } from '../chartdata/trisomy21_ofc_male_centile_data';
import { trisomy21OFCFemaleCentileData } from '../chartdata/trisomy21_ofc_female_centile_data';
import { turnerHeightFemaleCentileData } from '../chartdata/turner_height_female_centile_data';
import { LineSegment } from 'victory';

type CentileLabelValues = {
0.4: { value: number; workingX: number };
Expand Down Expand Up @@ -302,7 +303,7 @@ function childMeasurementRanges(
console.warn('Measurements considered invalid by the API given to the chart. The chart will ignore them.');
}
}

return { lowestChildX, highestChildX, lowestChildY, highestChildY };
}

Expand Down Expand Up @@ -351,6 +352,7 @@ function updateCoordsOfExtremeValues(
d: IPlottedCentileMeasurement,
native = false,
): void {

// transition points can lead to inaccurate coords for centile labels, therefore don't include 2 or 4 years old
if (!native || (d.x !== 4 && d.x !== 2)) {
if (extremeValues.lowestY > d.y) {
Expand All @@ -360,6 +362,11 @@ function updateCoordsOfExtremeValues(
if (extremeValues.highestY < d.y) {
extremeValues.highestY = d.y;
}
// this is necessary because in the BMI dataset (esp Trisomy-21), the values for Y ramp up to infinitity towards the end of the dataset
// this is a hack to prevent the chart from scaling to infinity - see discussion in #93 about the nature of SDS calculation when L is 0 or negative
if (extremeValues.highestY > 500){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a bit confused how this works so added some logging and I think it relies on d.y being null after the run of increasing values? So ultimately it resets highestY to then pick up a more reasonable value when processing the next points?

My first thought was why not clamp with a max here but I guess this way the plot ends up scaled to fit the actual data.

I'm wondering would this break if we lost the nulls in a future chart-coordinates update though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The presence of nulls allows us to plot values against x even when there is no reference data - this for example was a request from the neonatologists who wanted the facility to plot weights on preterm infants from 22 weeks gestation where there is no reference data. There I added extra null values to the reference data to allow this. I am afraid I forget now why extra nulls were added here, but not all datasets end at the same age - for example girls head circumference ends at 17y, while the boys ends at 18y and weight and height in UK90 go all the way up to 23 y.
I didn't actually write this code - @chvanlennep is the brain behind it - but I think the idea is to plot a measurement, even if it is higher than the visibile centile data. The extra lines I added were to filter out anything over 500 as this is pretty much impossible anyway and matches the thresholds (domains, as they are known in VictoryChart speak) already set by default.
If you are happy with this I will merge into live and push a patch - let me know and I will go ahead. I am happy to raise an issue in the internal dev chat about chart domains if you wish on the forum? I am not wedded to this methodology and am happy to change it if you feel there is a better approach.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool thanks for the explanation. Happy to merge this, I think we can go with a "three strikes" approach to this code - once we've added the third hack or special case we can look at how to make it more resilient based on the reports we get from users

extremeValues.highestY = d.y;
}

if (native) {
if (extremeValues.highestYForX[centileString].workingX < d.x) {
Expand Down
5 changes: 5 additions & 0 deletions src/functions/tooltips.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export function tooltipText(
chronological_percentage_median_bmi
} = datum;

if (datum.y === null) {
return
}


// flag passed in from user - if clinician, show clinician age advice strings, else show child/family advice
const comment = clinicianFocus ? clinician_comment : lay_comment;

Expand Down
148 changes: 148 additions & 0 deletions src/testParameters/measurements/trisomy21HighBMI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import type { Measurement } from "../../interfaces/RCPCHMeasurementObject";

export const trisomy21HighBMI: Measurement[] = [
{
"birth_data": {
"birth_date": "2006-05-08",
"gestation_weeks": 40,
"gestation_days": 0,
"estimated_date_delivery": "2006-05-08",
"estimated_date_delivery_string": "Mon 08 May, 2006",
"sex": "male"
},
"measurement_dates": {
"observation_date": "2022-11-01",
"chronological_decimal_age": 16.484599589322382,
"corrected_decimal_age": 16.484599589322382,
"chronological_calendar_age": "16 years, 5 months, 3 weeks and 3 days",
"corrected_calendar_age": "16 years, 5 months, 3 weeks and 3 days",
"corrected_gestational_age": {
"corrected_gestation_weeks": null,
"corrected_gestation_days": null
},
"comments": {
"clinician_corrected_decimal_age_comment": "Born at term. No correction has been made for gestation.",
"lay_corrected_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.",
"lay_chronological_decimal_age_comment": "Your child was born on their due date."
},
"corrected_decimal_age_error": null,
"chronological_decimal_age_error": null
},
"child_observation_value": {
"measurement_method": "bmi",
"observation_value": 36.3,
"observation_value_error": null
},
"measurement_calculated_values": {
"corrected_sds": 1.9929195642473767,
"corrected_centile": 97.7,
"corrected_centile_band": "This body mass index measurement is on or near the 98th centile.",
"chronological_sds": 1.9929195642473767,
"chronological_centile": 97.7,
"chronological_centile_band": "This body mass index measurement is on or near the 98th centile.",
"corrected_measurement_error": null,
"chronological_measurement_error": null,
"corrected_percentage_median_bmi": 163.3208998549931,
"chronological_percentage_median_bmi": 163.3208998549931
},
"plottable_data": {
"centile_data": {
"chronological_decimal_age_data": {
"x": 16.484599589322382,
"y": 36.3,
"b": null,
"centile": 97.7,
"sds": 1.9929195642473767,
"bone_age_label": null,
"events_text": null,
"bone_age_type": null,
"bone_age_sds": null,
"bone_age_centile": null,
"observation_error": null,
"age_type": "chronological_age",
"calendar_age": "16 years, 5 months, 3 weeks and 3 days",
"lay_comment": "Your child was born on their due date.",
"clinician_comment": "Born Term. No correction has been made for gestation.",
"age_error": null,
"centile_band": "This body mass index measurement is on or near the 98th centile.",
"observation_value_error": null
},
"corrected_decimal_age_data": {
"x": 16.484599589322382,
"y": 36.3,
"b": null,
"centile": 97.7,
"sds": 1.9929195642473767,
"bone_age_label": null,
"events_text": null,
"bone_age_type": null,
"bone_age_sds": null,
"bone_age_centile": null,
"observation_error": null,
"age_type": "corrected_age",
"calendar_age": "16 years, 5 months, 3 weeks and 3 days",
"corrected_gestational_age": "",
"lay_comment": "Your child was born on their due date.",
"clinician_comment": "Born at term. No correction has been made for gestation.",
"age_error": null,
"centile_band": "This body mass index measurement is on or near the 98th centile.",
"observation_value_error": null
}
},
"sds_data": {
"chronological_decimal_age_data": {
"x": 16.484599589322382,
"y": 1.9929195642473767,
"b": null,
"centile": 97.7,
"sds": null,
"bone_age_label": null,
"events_text": null,
"bone_age_type": null,
"bone_age_sds": null,
"bone_age_centile": null,
"observation_error": null,
"age_type": "chronological_age",
"calendar_age": "16 years, 5 months, 3 weeks and 3 days",
"lay_comment": "Your child was born on their due date.",
"clinician_comment": "Born Term. No correction has been made for gestation.",
"age_error": null,
"centile_band": "This body mass index measurement is on or near the 98th centile.",
"observation_value_error": null
},
"corrected_decimal_age_data": {
"x": 16.484599589322382,
"y": 1.9929195642473767,
"b": null,
"centile": 97.7,
"sds": null,
"bone_age_label": null,
"events_text": null,
"bone_age_type": null,
"bone_age_sds": null,
"bone_age_centile": null,
"observation_error": null,
"age_type": "corrected_age",
"calendar_age": "16 years, 5 months, 3 weeks and 3 days",
"corrected_gestational_age": "",
"lay_comment": "Your child was born on their due date.",
"clinician_comment": "Born at term. No correction has been made for gestation.",
"age_error": null,
"centile_band": "This body mass index measurement is on or near the 98th centile.",
"observation_value_error": null
}
}
},
"bone_age": {
"bone_age": null,
"bone_age_type": null,
"bone_age_sds": null,
"bone_age_centile": null,
"bone_age_text": null
},
"events_data": {
"events_text": null
}
}
]