Files
bio-performx/app/services/__pycache__/graph_generator.cpython-312.pyc
T

594 lines
68 KiB
Plaintext
Raw Normal View History

Ë
2025-11-28 16:19:32 +01:00
þ†)iFãó dZddlZddlZddlmZddlZej d«ddlmZ ddl
2025-11-24 19:37:28 +01:00
m Z ddl
ZddlZddlZddlmZGdd«Zy)
Graph Generator Service
This service generates all the charts and visualizations required for the medical report.
2025-11-28 12:11:00 +01:00
Based on the analysis notebooks in services_dfdf/.
éN)ÚPathÚAgg©ÚFancyBboxPatchcóeZdZdZd,defdZdedefdZ d-dejde
defd „Z d-dejde
2025-11-28 12:11:00 +01:00
defd
Z d-dejde
defd Z
d-dejde
defd Z d-dejde
defd
Z d-dejde
defdZ d-dejde
2025-11-28 12:11:00 +01:00
defdZ d-dedede
defdZ d-dededede
def
dZ d-dejde
defdZ d.dededededede
2025-11-21 12:34:53 +01:00
defd „Z d-dede
2025-11-28 12:11:00 +01:00
defd!„Z d/d"eed#eed$ed%ed&eeede
defd'„Z d0d"eed#eed&eeede
def
d(„Z d/d"eed#eed)ed%ed&eeede
defd*„Z d-dejde
defd+„Zy)1ÚGraphGeneratorz'Generate all charts for medical reportsÚ
charts_dircó\t|«|_|jjd¬«y)z{
Initialize the graph generator.
2025-11-24 19:37:28 +01:00
Args:
charts_dir: Directory to save generated charts
T)Úexist_okN)rr Úmkdir)Úselfr s úU/home/oluwasanmi/Documents/Work/MKD/report_generation/app/services/graph_generator.pyÚ__init__zGraphGenerator.__init__s%ô˜zÓŒØ ×Ñ tÐÕÚ
image_pathÚreturncóÊ t|d«5}tj|j««j d«cddd«S#1swYyxYw#t
$rYywxYw)
Convert image file to base64 string.
Args:
image_path: Path to image file
2025-11-21 12:15:42 +01:00
2025-11-24 19:37:28 +01:00
Returns:
2025-11-21 09:23:13 +01:00
Base64 encoded string
Úrbúutf-8NÚ)ÚopenÚbase64Ú b64encodeÚreadÚdecodeÚFileNotFoundError)r
rÚ
image_files rÚ_image_to_base64zGraphGenerator._image_to_base64$sWð Üj '¨:Ü×
¯©Ó(9Ó:×AÀ'Ó
Kñ
K×'ûä ò Ùð ús. AŽ2A
Á AÁ
AÁAÁAÁ A"Á!A"ÚdfÚsave_as_base64c
óš|jd¬«}|dj«}tjd¬«tj«}t j |ddd¬«|jd «|jd«|jd
d ¬ «|jd
td|dj«««|j«}|jtj d
|dj«dzd««t j |ddd|ddd¬«|jd«|jd
td|dj««dz«|j#«j%«|j#«j%«|j'«\}}|j'«\} }
|j)|| z||
zd¬«t+|«dk\rw|j-d
|ddd¬«|j-|d|ddd¬«|j-|d|ddd¬«|j-|d|dj«dd ¬«|j.d!z } tj0| d"d#¬$«tj2«|r|j5| «St7| «S)%a
2025-11-21 12:15:42 +01:00
Generate respiratory chart (VT and Speed over time).
Args:
df: Processed DataFrame with smoothed columns
save_as_base64: If True, return base64 string, else return file path
2025-11-21 12:15:42 +01:00
Returns:
2025-11-24 19:37:28 +01:00
Base64 string or file path
ÚPHASE©ÚsubsetúT(sec)©éé©ÚfigsizezVT(l)_smoothedzVT (L)©ÚdataÚlabelú
Time (sec)Tçš™™™™™¹?©ÚalpharééÈÚSpeedÚgreenú
steps-posté©r,r-r.ÚcolorÚaxÚ drawstyleÚ linewidthr/ééú
upper left©Úlocéçš™™™™™É?Ú lightblue©r3r;ÚpurpleéÚ
lightgreenÚbluezrespiratory.pngé,Útight©ÚdpiÚ bbox_inches)Údrop_duplicatesÚtolistÚpltÚfigureÚsubplotÚsnsÚlineplotÚ
set_xlabelÚ
set_ylabelÚgridÚset_ylimÚminÚmaxÚtwinxÚ
set_xticksÚnpÚarangeÚ
get_legendÚremoveÚget_legend_handles_labelsÚlegendÚlenÚaxvspanr ÚsavefigÚcloserÚstr© r
rr Úfirst_unique_phaseÚ phase_timesÚax1Úax2Úlines1Úlabels1Úlines2Úlabels2Ú
chart_paths rÚgenerate_respiratory_chartz)GraphGenerator.generate_respiratory_chart4sað ×/°wÐØÑ ä
˜7Õk‰kmˆô ˜" Ð,<ÀHÕ   Ø ˜SˆÔ ˜A˜rÐ"2Ñ3×i‰i‹kˆØ ”r—yy  B x¡L×$4Ñ$4Ó$6¸Ñ$<¸ ØØØØØØØõ
ð Ø ˜B  7¡ §¡Ó 1Ó2°QÑ Ó×ÑÔ Ó×ÑÔ×9‰ˆØ×9‰ˆØ
6˜F? G¨gÑ$5¸<ˆ
Ô ˆ{Ó ˜qÒ Ø K‰K˜˜; q™>°¸Kˆ K‰K˜  A™¨ °A©¸cȈKÔ K‰K˜  A™¨ °A©¸cȈKÔ K‰K˜  A™¨¨8© ×(8Ñ(8Ó(:À#ÈVˆ —__Ð'8Ñ8ˆ
Ü J C°WÕ ‰ Œ á4Bˆ$ ZÓÈJËÐWrc ó |jd«jd¬«jd«}|jdd}||jdk\|jdkz}t j d¬ «t
jjd
«tdt|«dz«Dcgc]}d |Œ }}tjt|««}|d |d
zdz }|d |dzdz } t j«}
|
j||dddd¬«|
j|| |dddd¬«|
jdd¬«|
j!dd¬«|
j#dd«t%t'|| |d ««D]r\}\} } }
| dkDr|
j)|| dz | d d!d!d"d#d$¬%«| dkDr!|
j)|| | dz z| d d!d!d"d#d$¬%«|
j)||
d&z|
d d'd!d(d)d#d*¬%«Œtt%|j«D]?\}}|
j)|d+|d d,d!d-d"¬.«|
j)|d/|d0zd d1d!d-d2d3¬4«ŒA|
2025-11-24 19:37:28 +01:00
j+«}|j-||d5d6d7d2d8d9¬:«|j!d;dd8¬<«|j/d=d8¬>«|j#dd?«t%|d5«D]-\}}|j)||d)zt1|«d@d!d(d)d#d8¬%«Œ/|
2025-11-21 14:15:29 +01:00
j3|«|
2025-11-24 19:37:28 +01:00
j5|dA¬«|
2025-11-21 12:15:42 +01:00
j7«\}}|j7«\}}|
2025-11-21 14:15:29 +01:00
j9||z||zdBddd¬C«|
2025-11-24 19:37:28 +01:00
j;dddDd&¬E«|
j=d«t j>«t j@dFdG¬H«|jBdIz }t jD|dJ¬K«t jF«|r|jI|«StK|«Scc}w)La
Generate fuel utilization chart (CHO vs FAT by stage).
2025-11-21 09:23:13 +01:00
Args:
2025-11-21 09:23:13 +01:00
df: Processed DataFrame with smoothed columns
save_as_base64: If True, return base64 string, else return file path
Returns:
Base64 string or file path
r6T)Ú numeric_onlyr@éÿÿÿÿç @g@)ér4r)ÚdefaultzStage z EE(kcal/min)zFAT(%)édzCARBS(%)z#1f77b4çš™™™™™é?ç333333ã?ÚFat)r;r3Úwidthr/z#ff7f0eÚCarbs)Úbottomr;r3r€r/ré ©ÚfontsizezFuel (kcal/min)réç333333Ó?r9ú.1fÚcenteré ÚboldÚwhite)ÚhaÚvar…Ú
fontweightr;çà?z kcalré
Úblackgø¿z mphÚtop©rr…gffffffÀgX9´Èv¾ù?z min/kmr4Úgray©rr…r;zHR(bpm)ÚorIÚredú
Heart Rate)Úmarkerr>Ú
markersizer;r/úHeart Rate (bpm))r…r;r.©ÚaxisÚ
labelcoloréÜÚbpmé rA)rCÚframeonÚfancyboxÚshadowÚ-)r3Ú linestyler>r1çÍÌÌÌÌÌì?)rr“zfuel_utilization_chart.pngrL)rO)&ÚgroupbyÚmeanÚroundÚilocÚindexrSrTÚstyleÚuseÚrangerfr`raÚgcaÚbarrXrYr[Ú enumerateÚzipÚtextr^ÚplotÚ tick_paramsÚintr_Úset_xticklabelsrdrerZÚ
set_axisbelowÚ tight_layoutÚsubplots_adjustr rhrirrj)r
rr Ú speed_groupsÚ
filtered_dataÚ stage_labelsÚ x_positionsÚfat_eeÚcarbs_eernÚfat_valÚcarb_valÚ total_valÚspeedroÚhrrprqrrrsrts rÚgenerate_fuel_utilization_chartz.GraphGenerator.generate_fuel_utilization_chartrsð—zz *×/¸Ó ب2Ð ð
×
Ñ
 
&¨<×+=Ñ+=ÀÑ+DÑ 
ˆ
ô
2025-11-24 19:37:28 +01:00
˜
 ä.3°A´s¸=Ó7IÈAÑ7MÔ.NÓOÑ.N¨˜&  š Ð.Nˆ Зi‘i¤ MÓ 2Ó ð˜~ѸxÑ1HÑHÈ3ÑØ  Ñ0°=ÀÑ3LÑLÈsÑäg‰g‹iˆð Ø Ø ØØØØð
ô
ð Ø Ø ØØØØØð ô
ð r BˆÔ Ð(°2ˆÔ Ôô2;Ü ˜ Ñ"?Ó 2
Ñ -ˆAÑ-˜ 9ð˜Š}ØØØ˜a‘KؘsØØØô ð˜#Š~ØØØ˜h¨™lÑ ØØØô ð
H‰HØØ˜CؘSÐØØØð
õ
ð32
ôJ" -×"5Ñ"5Ö6‰HˆAˆ H‰HQ˜  s  ¨4Ð0°XÀ%ÐRSˆHÔ H‰HØØØ˜5‘= Ð% WÐØØØð
õ
ði‰i‹kˆØ Ø Ø ˜)Ñ ØØØØð ô
ð Ð)°B¸eˆÔ ˜S¨UˆÔ Ôô˜}¨YÑ8‰EˆAˆrØ H‰HØØR‘Ür“7)˜3ØØØØð
õ
ð  ×јL°2ÐÔ×9‰ˆØ×9‰ˆØ
Ø V‰OØ  ØØØØð
ô
ð ˜S¨C¸3ˆÔ ×ј$Ôä ×ÑÔÜ ×Ñ 3¨CÕ—__Ð'CÑCˆ
Ü J CÕ ‰ Œ á4Bˆt×$ ZÓÈJËÐWùòQPsÂ1 P c
ó˜|jd¬«}|dj«}tjd¬«tj«}t j |dddd¬ «|jd
«|jd«|jd |dj««|jd d
¬«|j«}t j |ddd|dd¬«|jdd¬«|jdd¬«|jd |dj«dz«|j«}|jdjd«t j |ddd|ddd¬«|jdd¬«|jdd¬«|jd |dj«dz«|j!t#j$d |dj«dzd««|j'«r|j'«j)«|j'«r|j'«j)«|j'«r|j'«j)«|j+«\}} |j+«\}
} |j+«\} }
|j-||
z| z| | z|
2025-11-24 19:37:28 +01:00
zd¬ «t/|«d!k\rw|j1d |dd"d#¬$«|j1|d|dd"d%¬$«|j1|d|d&d"d'¬$«|j1|d&|dj«d"d¬$«|j2d(z }tj4|d)d*¬+«tj6«|r|j9|«St;|«S),a
Generate VO2 Pulse chart with HR and Speed.
Args:
df: Processed DataFrame with smoothed columns
save_as_base64: If True, return base64 string, else return file path
Returns:
Base64 string or file path
r"r#r%r&r)zVO2 Pulse_smoothedúVO2 Pulse (mL/beat)rK©r,r-r.r/r;r0rTr1r2úHR(bpm)_smoothedr˜r9©r,r-r.r;r<r>r/©r;r.rr@Úright©Úoutwardé<r6r7r8r:r5rArBrDrErFrGrHrIrJzvo2_pulse_chart.pngrMrL©rPrO)rQrRrSrTrUrVrWrXrYr[r]rZr^ÚspinesÚ set_positionr_r`rarbrcrdrerfrgr rhrirrj©r
rr rlrmrnroÚax3rprqrrrsÚlines3Úlabels3rts rÚgenerate_vo2_pulse_chartz'GraphGenerator.generate_vo2_pulse_chartsOð ×/°wÐØÑ ä
˜7Õk‰k‹mˆô ØØØõ 
ð  Ð Ð ˜SˆÔi‰i‹kˆÜ ØØØ ØØØØ
ð ÐˆÔ ˜S¨UˆÔ Ð4°qÑi‰i‹kˆØ
×Ô ØØØØØØØõ
ð w gˆÔ ˜S¨WˆÔ ˜7™ ŸÓ)¨AÑ ”r—yy  B x¡L×$4Ñ$4Ó$6¸Ñ$<¸ >‰>Ô Ø N‰NÓ × >‰>Ô Ø N‰NÓ × >‰>Ô Ø N‰NÓ × ×9‰ˆØ×9‰ˆØ×9‰ˆØ
Ø V‰O˜ $ Ñ&7¸'Ñ&AÀ|ð ô
2025-11-24 19:37:28 +01:00
ô
ˆ{Ó ˜qÒ Ø K‰K˜˜; q™>°¸Kˆ K‰K˜  A™¨ °A©¸cȈKÔ K‰K˜  A™¨ °A©¸cȈKÔ K‰K˜  A™¨¨8© ×(8Ñ(8Ó(:À#ÈVˆ —__Ð'<Ñ<ˆ
Ü J¨G¸Õ ‰ Œ á4Bˆt×$ ZÓÈJËÐWrc
óx|jd¬«}|dj«}tjd¬«tj«}t j |ddd¬«|jd «|jd«|jd
|dj«d z«|jd d
¬«|j«}|jtjd
|dj«dzd««t j |ddd|ddd¬«|jd
|dj«d z«|jd«|j!«j#«|j!«j#«|j%«\}}|j%«\} }
|j'|| z||
zd¬«t)|«dk\rw|j+d
|d dd¬«|j+|d |ddd¬«|j+|d|ddd¬«|j+|d|dj«dd¬«|j,dz } tj.| d d!¬"«tj0«|r|j3| «St5| «S)#a
Generate VO2 per Breath chart.
Args:
df: Processed DataFrame with smoothed columns
save_as_base64: If True, return base64 string, else return file path
Returns:
Base64 string or file path
2025-11-24 19:37:28 +01:00
r"r#r%r&r)zVO2 Breath_smoothedzVO2 per Breath (mL/breath)r+r0rr@Tr1r2r5r6r7r8r9r:rArBrDrErFrGrHrIrJrKzvo2_breath_chart.pngrMrL)rQrRrSrTrUrVrWrXrYr[r]rZr^r_r`rarbrcrdrerfrgr rhrirrjrks rÚgenerate_vo2_breath_chartz(GraphGenerator.generate_vo2_breath_chartss^ð ×/°wÐØÑ ä
˜7Õk‰k‹mˆä ØØØ
ð  Ð Ð1×7¸ ˜SˆÔi‰i‹kˆØ ”r—yy  B x¡L×$4Ñ$4Ó$6¸Ñ$<¸ ØØØØØØØõ
ð ˜7™ ŸÓ)¨AÑ ð Ó×ÑÔ Ó×ÑÔ×9‰ˆØ×9‰ˆØ
6˜F? G¨gÑ$5¸<ˆ
Ô ˆ{Ó ˜qÒ Ø K‰K˜˜; q™>°¸Kˆ K‰K˜  A™¨ °A©¸cȈKÔ K‰K˜  A™¨ °A©¸cȈKÔ K‰K˜  A™¨¨8© ×(8Ñ(8Ó(:À#ÈVˆ —__Ð'=Ñ=ˆ
Ü J¨G¸Õ ‰ Œ á4Bˆt×$ ZÓÈJËÐWrcó|jd¬«}|dj«}tjd¬«tj«}t j |ddd¬«|jd «|jd
«|jd d ¬
«|j«}|jtjd|dj«dzd««t j |ddd|d¬«|jd«|jdd«|j!«j#«|j!«j#«|j%«\}}|j%«\} }
|j'|| z||
zd¬«t)|«dk\rw|j+d|ddd¬«|j+|d|ddd¬«|j+|d|ddd¬«|j+|d|dj«dd ¬«|j,d!z } tj.| d"d#¬$«tj0«|r|j3| «St5| «S)%a
Generate fat metabolism chart (CHO vs FAT over time).
Args:
df: Processed DataFrame with smoothed columns
save_as_base64: If True, return base64 string, else return file path
Returns:
Base64 string or file path
r"r#r%r&r)Ú CHO_smoothedzCHO (kcal/min)r+r0z CHO (g/min)Tr1r2rr5Ú FAT_smoothedr7zFAT (kcal/min))r,r-r.r;r<r/rzrArBrDr@rErFrGr9rHrIrJrKzfat_metabolism_chart.pngrMrL)rQrRrSrTrUrVrWrXrYrZr^r_r`rar]r[rbrcrdrerfrgr rhrirrjrks rÚgenerate_fat_metabolism_chartz,GraphGenerator.generate_fat_metabolism_chartµs!ð ×/°wÐØÑ ä
˜7Õk‰kmˆô ˜" ¨NÐBRÕ   ˜SˆÔi‰i‹kˆØ ”r—yy  B x¡L×$4Ñ$4Ó$6¸Ñ$<¸ ØØØØØØ

ð Ð Ôð Ó×ÑÔ Ó×ÑÔ×9‰ˆØ×9‰ˆØ
6˜F? G¨gÑ$5¸<ˆ
2025-11-24 19:37:28 +01:00
Ô ˆ{Ó ˜qÒ Ø K‰K˜˜; q™>°¸Kˆ K‰K˜  A™¨ °A©¸cȈKÔ K‰K˜  A™¨ °A©¸cȈKÔ K‰K˜  A™¨¨8© ×(8Ñ(8Ó(:À#ÈVˆ —__Ð'AÑAˆ
2025-11-28 12:11:00 +01:00
Ü J¨G¸Õ ‰ Œ á4Bˆt×$ ZÓÈJËÐWrc ó¸|jd¬«}|dj«}tjd¬«tj«}t j |dddd¬ «|jd
«|jd «|jd |d
j««|jdd¬«|j«}t j |ddd|dd¬«|jdd¬«|j|dj«|dj«dz«|jdd¬«|j«}|jdj!d«t j |ddd|dd¬«|jdd¬«|jdd¬«|jd |dj«dz«|j#t%j&d |dj«dzd««|j)«r|j)«j+«|j)«r|j)«j+«|j)«r|j)«j+«|j-«\}} |j-«\}
} |j-«\} }
2025-11-24 19:37:28 +01:00
|j/||
z| z| | z|
zd ¬!«t1|«d"k\rw|j3d |dd#d$¬%«|j3|d|dd#d&¬%«|j3|d|d'd#d(¬%«|j3|d'|dj«d#d¬%«|j4d)z }tj6|d*d+¬,«tj8«|r|j;|«St=|«S)-a
Generate recovery chart (VCO2, HR, and BF).
2025-11-21 09:23:13 +01:00
Args:
df: Processed DataFrame with smoothed columns
save_as_base64: If True, return base64 string, else return file path
2025-11-21 09:23:13 +01:00
Returns:
Base64 string or file path
r"r#r%r&r)zVCO2(ml/min)_smoothedz
VCO2 (ml/min)rKr0rz VCO2(ml/min)Tr1r2r˜r9r@r.rzBF(bpm)_smoothedr7zBF (bpm)r5rArBrDrErFrGrHrIrJzrecovery_chart.pngrMrL)rQrRrSrTrUrVrWrXrYr[r]rZr^r\r_r`rarbrcrdrerfrgr rhrirrjr×s rÚgenerate_recovery_chartz&GraphGenerator.generate_recovery_chartðs_ð ×/°wÐØÑ ä
˜7Õk‰k‹mˆô ØØØõ 
2025-11-21 12:15:42 +01:00
ð  Ð ˜>Ñ ˜SˆÔi‰i‹kˆÜ ØØØ ØØØØ
ð ÐˆÔ +×1°2Ð6HÑ3I×3MÑ3MÓ3OÐRSÑ3SÔ ˜S¨UˆÔi‰i‹kˆØ
×Ô ØØØ ØØØØõ
ð ˆÔ ˜S¨WˆÔ Ð4°qÑ ”r—yy  B x¡L×$4Ñ$4Ó$6¸Ñ$<¸ >‰>Ô Ø N‰NÓ × >‰>Ô Ø N‰NÓ × >‰>Ô Ø N‰NÓ × ×9‰ˆØ×9‰ˆØ×9‰ˆØ
Ø V‰O˜ $ Ñ&7¸'Ñ&AÀ|ð ô
2025-11-21 12:15:42 +01:00
ô
ˆ{Ó ˜qÒ Ø K‰K˜˜; q™>°¸Kˆ K‰K˜  A™¨ °A©¸cȈKÔ K‰K˜  A™¨ °A©¸cȈKÔ K‰K˜  A™¨¨8© ×(8Ñ(8Ó(:À#ÈVˆ —__Ð';Ñ;ˆ
Ü J¨G¸Õ ‰ Œ á4Bˆt×$ ZÓÈJËÐWrÚoxygenation_dfc ódddlm}tjd¬«tj|d|dddd ¬
«tj|d|d d d
d ¬
2025-11-24 19:37:28 +01:00
«|dj «}ddddddd|fg}|D]X\}}|d|k\|d|kz}||dj
«z} | j«dkDrv|j| df}
2025-11-21 12:15:42 +01:00
|j| df} |j|
2025-11-24 19:37:28 +01:00
| d«j«j} | d| d|
zz}
2025-11-28 12:11:00 +01:00
tj|
2025-11-24 19:37:28 +01:00
|
ddd d¬«||d j
«z}|j«dkDsŒã|j|df}|j|d f}|j||d«j«j}|d|d|zz}tj||ddd d¬«Œ[tjd«tjd«tjd«tjdd¬«tj d ¬!«tj"«|j$d"z }tj&|d#d$¬%«tj(«|r|j+|«St-|«S)&a@
Generate TSI (Tissue Saturation Index) chart with trend lines per stage.
2025-11-21 12:15:42 +01:00
Args:
2025-11-28 12:11:00 +01:00
oxygenation_df: DataFrame with Time, TSI, and TSI-second columns
save_as_base64: If True, return base64 string, else return file path
Returns:
Base64 string or file path
r)Ú
Polynomial)g@r)ÚTimeÚTSIzTSI (Left Leg)Ú steelbluer9©r/r;r>z
TSI-secondzTSI2 (Right Leg)Úorange)réú)éô)éî)éè)éâ)éÜr@rú--r})r;r>r3zTime (s)zTSI (%)z<TSI (Left) and TSI2 (Right) with Black Slope Lines per Stagerz upper right)r…rCçÐ?r2z
tsi_chart.pngrMé )Únumpy.polynomial.polynomialrærSrTr]ÚisnaÚsumrCÚfitÚconvertÚcoefÚxlabelÚylabelÚtitlererZr rhrirrj)r
r Úmax_timeÚ intervalsÚ
start_timeÚend_timeÚ
mask_intervalÚ mask_leftÚx_leftÚy_leftÚ
coefs_leftÚ
trend_leftÚ
mask_rightÚx_rightÚy_rightÚ coefs_rightÚ trend_rightrts rÚgenerate_tsi_chartz!GraphGenerator.generate_tsi_chartLõ
˜9Õ Ø ˜ ˜ Øõ 
ô Ø ˜ ˜ Øõ 
ð" )×à Ø Ø Ø Ø Ø Ø
 ð
ˆ ô%.Ñ ˆJ˜à+¨FÑ3°zјvÑ&¨(ш
¸Ñ)>×)CÑ)CÓ)EÐ(EÑEˆ}‰} Ò'×+¨I°vÐ,=Ñ>Ø'×+¨I°uÐ,<Ñ=Ø'Ÿ^™^¨F°F¸>×H×M
Ø™]¨Z¸©]¸VÑ-CÑC
ÜØØØØõ
ð'¨.¸Ñ*F×*KÑ*KÓ*MÐ)MÑMˆ~‰~Ó ,¨Z¸Ð-?Ñ@Ø,¨Z¸Ð-EÑFØ(Ÿn™n¨W°g¸A×P Ø)¨!™n¨{¸1©~ÀÑ/GÑG ÜØØØØ÷
ð;%.ôL
Ü
Ü ‰ Ð
2025-11-24 19:37:28 +01:00
2025-11-28 12:11:00 +01:00
˜B MÕ Ü ×ÑÔà—_‘_ Ñ
Ü J¨G¸Õ ‰ Œ á4Bˆt×$ ZÓÈJËÐWrÚ fat_mass_lbsÚ
lean_mass_lbscó\||z}||z dz}||z dz}||g}ddg}tjd¬«tj|ddtdd ¬
«|ddg¬ «tjd d
d|dd|ddddddtddd¬«¬«tjd
d d|dd|ddddddtddd¬«¬«tj
d«|j dz } tj| dd¬«tj«|r|j| «St| «S) a-
2025-11-21 09:23:13 +01:00
Generate body composition donut chart.
Args:
fat_mass_lbs: Fat mass in pounds
2025-11-21 09:23:13 +01:00
lean_mass_lbs: Lean mass in pounds
save_as_base64: If True, return base64 string, else return file path
Returns:
Base64 string or file path
r|z#fde3acz#ff9966)r4r4r)réZrÚw)r€Ú edgecolor)ÚautopctÚ
startangleÚ
wedgepropsÚcolorsÚlabelsrxr@z
Fat Mass (rˆzlbs)
úr‹r‰ú
round,pad=0.3rŒr}©ÚboxstyleÚ facecolorr3)r…rrÚbboxz Lean Mass (Úequalzbody_composition_chart.pngrMiX) rSrTÚpieÚdictrµr rhrirrj)
r
rrr Ú total_weightÚfat_percentageÚlean_percentageÚsizesrrts
rÚgenerate_body_composition_chartz.GraphGenerator.generate_body_composition_chart¯sQð$ 3ˆ ØÑ5¸Ñ<ˆØ(¨<Ñ7¸>ˆà Ð1ˆØ˜'ˆä
˜ Ø ØØÜ #°Ôؘ

ô Ø Ø
ؘ *¨&°ÀÐ0DÀAÐ ØØØÜ˜¸'ÈÔ
ô Ø
Ø Ø˜-¨Ð,¨F°?À3Ð2GÀqÐ ØØØÜ˜¸'ÈÔ
ô Ôà—__Ð'CÑCˆ
Ü J¨G¸Õ ‰ Œ á4Bˆt×$ ZÓÈJËÐWrr$ÚageÚgenderc
óvd|cxkrdkrnnd}n$d|cxkrdkrnnd}nd|cxkrdkrnnd }nd}|j«d
k(rd nd }|d
2025-11-28 12:11:00 +01:00
|d}|j«dk(r|dk(rgd¢}ngd¢}n|dk(rgd¢}n|dk(rgd¢}ngd¢}tjd¬«\} }
|D]\} } }
2025-11-28 12:11:00 +01:00
|
jd|
2025-11-24 19:37:28 +01:00
| d| dd¬«Œ |
j |ddddd|
j «¬ «|
j
dd!«|
jtdd"d#««|
2025-11-28 12:11:00 +01:00
jg«|
jd$d||
2025-11-24 19:37:28 +01:00
j«d%d&d'¬(«tdd"d#«}|
j|«|Dcgc]}|d)Œ }}|
2025-11-28 12:11:00 +01:00
j|«|
jd&jd«|
2025-11-28 12:11:00 +01:00
jd*jd«|
2025-11-21 09:23:13 +01:00
jd+jd«|
jd,jd-«tdd"d#«D]*}|
j ||gd$d.gd|
j «d¬/«Œ,tj«|j d0z }tj"|d1d2¬3«tj$«|r|j'|«St)|«Scc}w)4aS
2025-11-21 09:23:13 +01:00
Generate body fat percentage chart.
Args:
fat_percentage: Body fat percentage
age: Patient age
2025-11-28 12:11:00 +01:00
gender: Patient gender ('male' or 'female')
save_as_base64: If True, return base64 string, else return file path
Returns:
Base64 string or file path
r†é'z20-39é(é;z40-59rÓéOz60-79ÚmaleÚFz
female))ú#F8A8A8rrz)ú#FFEECCrzr()ú#D0F0C0r†rz©r5é#r(©r4r,r))r4rr†©r5r†r()r6érr7r9)©r4rr(©r5r(r(©r6rrr:)r4r;r;)r<r=r>)r5r†r©r4r?r†)r<r=)r6rrz)r5r;r(r?)rr9r)rr@rr)r.r€ÚleftÚheightr;rr>gÍÌÌÌÌÌð?ÚvrF)r;rÚclip_onÚ transformé2é3r(çš™™™™™©¿r‰)rDrr…rr“r@rTg{®Gáz„¿)r;rDrCzbody_fat_percent_chart.pngrMrL)ÚlowerrSÚsubplotsÚbarhr¶Úget_xaxis_transformÚset_xlimr_Ú
set_yticksrµÚget_yaxis_transformr¹Ú set_visibler»r rhrirrj)r
r$r(r)r Ú age_groupÚ
gender_abbrevÚ demographicÚsegmentsÚfigr<r;ÚstartÚlengthÚticksÚtrr-rts rÚgenerate_body_fat_percent_chartz.GraphGenerator.generate_body_fat_percent_chartðð( Œ?˜‰IØ
3Œ_˜"‰IØ
3Œ_˜"‰Iàˆ%Ÿ|™|›~°Ò7™¸Sˆ
Ø"˜  3 } o°QÐ7ˆ ð <‰<>˜ ˜òð˜GÒð˜gÒòô—,‘, wÔ/‰ˆˆ%-Ñ ˆE5˜ G‰GØØØØØØð
õ
ð%-ð Ø Ø ØØØØØ× ô
ð AØ
2025-11-28 12:11:00 +01:00
”e˜A˜r 1“oÔ
2025-11-28 12:11:00 +01:00
Ø
Ø Ø
Ø Ø×ØØð ô
ôa˜˜Q“ˆØ
Ù#(Ó)¡5˜aQCq' 5ˆÐ
×ј ×& 
×$ 
2025-11-28 12:11:00 +01:00
×% 
×Ôq˜"˜aˆ G‰GØAØ˜ØØ×ð
õ
ð ×ÑÔà—__Ð'CÑCˆ
Ü J¨G¸Õ ‰ Œ á4Bˆt×$ ZÓÈJËÐWùò3*sÅ8 J6Ú
spirometry_dfcó, ‡)—gd¢ddggd¢gd¢gd¢dœ}i}|j«D]>\}}|D]4}||jvsŒ|||<tj||d¬ «||<Œ>Œ@|j«D]"\}}||jvsŒ||k7sŒ||||<Œ$d
d d d
œ} g}
| j«D]\} } |j|dj
j
«| k(}
|
jrS|j|dj
j
«j
j«| j«k(}
|
jrCd| vr?| jdd«}|j|dj
j
2025-11-28 12:11:00 +01:00
«|k(}
|
jr0td| d«td|dj««Œ|
2025-11-28 12:11:00 +01:00
jd}
|
jd|
jdtj««}|
jd|
jd|
jd|
2025-11-28 12:11:00 +01:00
jdtj««««}|
jd|
jd|
jdtj«««}|
j| | |||dœ«Œt!|
«dk7r+t#d t!|
«d!|
Dcgc]}|d"Œ c}«t%j&dd#d$d%d&d'i¬(«\}}d)\}}gd*¢}t)j*||d#zd#«}|Dcgc]
2025-11-28 12:11:00 +01:00
}t |«Œ}}t-||
«D]\}}|D] \}}}|j/d||z
|d+|d,¬-«Œ"|j1dd.d#¬/«tj2|d0«rNt5j6|j8|j:«} |j=t?|d0«d1d2d3d4| d5¬6«|jA|d7d8d9d:d;¬<«|jC||«|jEg«|jG|«|jI|d=¬>«|jKd«Œ|djMd?d@ddAdBdC¬D«|djMdd@dEdAdBdC¬D«|jOdF¬G«|jQgdH¢«}!|!jSdI«dJ„}"|!jCdd#«|!jUdd#«g}#|
D]J}|d"d
k(rd
n |d"d k(rd ndK}$|d"dLvrdMnd}%|ddN|%}&|dOdPd}'|#j|$|&|'f«ŒLgdQ¢}(|(D)‡)cgc]Š)tWˆ)fdR„|#D««Œ}*})gdS¢}+t-|*|+«D]\\}$}&}'},|$dT|&dU|'}-|"|!dV|,f|-«Œ!|jXdWz }.t%jZ|.dXdY¬Z«t%j\«|r|j_|.«St |.«Scc}wcc}wcc})w)[a
Generate spirometry chart with Z-scores.
Args:
spirometry_df: Spirometry DataFrame with parameters
save_as_base64: If True, return base64 string, else return file path
Returns:
Base64 string or file path
)ÚBestÚbestÚBESTÚLLNÚlln)úPred.ÚPredÚpredÚ PredictedÚ predicted)ú%Pred.ú%Predz%predz% Pred.z% PredúPred %úPred%)ÚZScoreúZ-Scorezz-scoreÚZscoreÚzscorezZ Score)r\r_rarfrjÚcoerce©ÚerrorsÚFVCÚFEV1z FEV1/FVC%)z Lung Volumez
Lung Powerz Power/VolumeÚ
Parametersrrz#Warning: Could not find parameter 'z' in spirometry datazAvailable parameters: rr\r]rfrgrhrirjrkrl)r/Úparamr]ÚpctÚzrIzCExpected 3 spirometry parameters (FVC, FEV1, FEV1/FVC%), but found z . Found: rtr@)ç'@gÍÌÌÌÌÌ @TÚhspaceçÍÌÌÌÌÌä?)ÚnrowsÚncolsr*ÚsharexÚ gridspec_kw)éûÿÿÿrI))r~éüÿÿÿz#f4a7a7)réýÿÿÿz#f7c49a)r€ç333333û¿z#f6e3a3)rrIz#c9f0ccr~Únone)r€r@rAr;rr©r;Úlwrvg333333ó?rBÚdimgrayF)rr;rDrCr/r@rr9)rCr…rÚpadr4r„rgÍÌÌÌÌÌÜ?r‰r‚r”rdgö(\Âõè?))gÃõ(\Âé?g¸…ëQ¸®?ç
2025-11-28 12:11:00 +01:00
×£p=
2025-11-21 12:49:36 +01:00
Ç?r¨Úoffc óÐ|\}}t|dz
|dz
2025-11-24 19:37:28 +01:00
fdddddd¬ «}|j|«|j||d
2025-11-21 12:49:36 +01:00
z|d d d d
¬«|j||dz
dd d dd¬«y)N縅ëQ¸Þ?g
2025-11-21 12:34:53 +01:00
×£p=
·?g¸…ëQ¸î?r‡z!round,pad=0.02,rounding_size=0.08z#ddddddz#f3f3f3çð?)rÚecÚfcr>gš™™™™™™?r‰r‹)rr…rg)\Âõ(¬?z of predictedrŠz#555555r)rÚ add_patchrµ)r<Úxyrµr-r.rs rÚpillz6GraphGenerator.generate_spirometry_chart.<locals>.pill&s؉DˆAˆqÜT‘˜1˜t™8ÐØØØØôˆDð
L‰L˜Ô Ø G‰GØØE‘ ØØØØØ
ô
2025-11-21 12:49:36 +01:00
ð
G‰GØØE‘ ØØØØØð
2025-11-21 12:34:53 +01:00
õ
rúFEV1/FVC)rqrrÚLz.2frurˆ)rqrrrc3ó4K|]}|dk(sŒ |Œy­w)r)Ú.0ÚitemÚks €rú <genexpr>z;GraphGenerator.generate_spirometry_chart.<locals>.<genexpr>Xsøèø€Ð>¡+˜$°°a±¸A³¡+ùsƒ
)g=
×£p=ê?rŠç333333Ã?Ú
u → rzspirometry_chart.pngrLrMrN)0ÚitemsÚcolumnsÚpdÚ
2025-11-28 12:11:00 +01:00
to_numericrCrjÚstripÚemptyÚupperÚreplaceÚprintrRÚgetÚNAÚappendrfÚ
ValueErrorrSrIr`rar´rJÚaxvlineÚnotnaÚ mtransformsÚblended_transform_factoryÚ transDataÚ transAxesr¶ÚfloatÚ set_titlerLrMr_rXÚadd_axesržr[Únextr rhrir)/r
rZr Úcolumn_aliasesÚcolumn_mappingÚ
target_colÚpossible_namesÚcol_nameÚ
2025-11-21 12:49:36 +01:00
source_colÚrows_mapÚrecordsr/rtÚrowÚ param_no_pctÚbest_valÚpct_valÚz_valÚrrTÚaxesÚx_minÚx_maxrSrWr¿rr<ÚrecÚbr;ÚtransÚbox_axrÚ right_itemsÚnameÚunitÚ value_fmtÚpct_fmtÚorderr—Úright_items_sortedÚysr.Ú main_linerts/ ` rÚgenerate_spirometry_chartz(GraphGenerator.generate_spirometry_chart€saø€ò ˜5òVñ
2025-11-28 12:11:00 +01:00
ˆð"ˆØ*8×*>Ñ*>Ö*@Ñ &ˆJ˜Û*ؘ}×4Ø19N .ä.0¯m©mØ% /¸ô/M ñ+Að'5×&:Ñ&:Ö&<Ñ "ˆJ˜
2025-11-21 12:49:36 +01:00
Ø ×!6Ñ!6Ò6¸Ó;SØ,9¸*Ñ,E
˜'=ð  Ø
ˆð ˆØ$ŸN™N×,‰LˆE×# M°,Ñ$?×$CÑ$C×$IÑ$IÓ$KÈuÑ$TÑUˆyŠyà#×! /×3×?×GÈ5Ï;É;Ë=ÑðyŠyà˜%<Ø#(§=¡=°°bÓ#9'×% 3×7×?À<ÑyŠyÜÐ;¸E¸7ÐBVÐÐ.¨}¸\Ñ/J×/QÑ/QÓ/SÐ.TÐØ—(‘(˜1‘+ˆCà—w‘w˜v s§w¡w¨v´r·u±uÓ'=Ó>ˆ—g˜#Ÿ'™' '¨3¯7©7°8¸S¿W¹WÀWÌbÏeÉeÓ=TÓ+UÓˆGð—G‘G˜H c§g¡g¨i¸¿¹ÀÌ2Ï5É5Ó9QÓ&RÓSˆ N‰Nàñ ö
2025-11-24 19:37:28 +01:00
ð7-ôL ˆw‹<˜1Ò ÜðÜ  ›\˜N¨)ÉÓ4QÉÀA°Q°w³ZÈÑ4QÐ3RðTóð
2025-11-21 14:15:29 +01:00
ô —L‘LØØØØØ! 4Ð 
2025-11-24 19:37:28 +01:00
‰ ˆˆT𠈈uò
2025-11-21 12:34:53 +01:00
ˆô— ‘ ˜% ¨¡¨AÓ.ˆÙ"'Ó(¡%˜Q”#a•& %ˆÐ˜4 ×)‰GˆBã' 1ؘQ ™U¨°3¸eÈvðõð
J‰Jq ¨AˆJÔ x‰x˜˜C™Ô#×—LL "§,¡,óðܘ#˜c™(“OØØØôð
L‰LØG  &°2À&Èað
ô
ð
2025-11-21 14:15:29 +01:00
K‰K˜˜ M‰M˜ Ø M‰M˜%Ô Ø × Ñ ˜v°Ð Ô M‰M˜ ðC*ðH
2025-11-21 12:34:53 +01:00
ˆQ‰ T˜4 ¨8¸È1ˆ Ô ˆQ‰ ˜k¨h¸8Èaˆ Ô ×Ñ $ÐÔÒØ ò ð> ˜˜1ÔØ˜˜1Ôðˆ ÛˆCðw< 5Òà #  °Ò 6‘f¸Jð
ð
˜g™,¨/Ñ9‘3¸sˆDؘv™; sÐ+¨D¨6Ð2ˆIؘU™ CÐÐ*ˆGØ × Ñ   i°Ð òáHMô
ÙHMÀ1ŒDÓ>¡+Ó ð ð
2025-11-28 12:11:00 +01:00
ò ˆÜ-0Ð1CÀRÖ-HÑ &ˆT9˜Ø˜&  9 +¨U°7°)Ð<ˆ ˜#˜q˜  .Ið—__Ð'=Ñ=ˆ
2025-11-21 14:15:29 +01:00
Ü J C°WÕ ‰ Œ á4Bˆ$ ZÓÈJËÐWùòG5Rùò,)ùò@
sË XÌ:X ÕXrmr_kcalÚ weight_kgÚ height_cmÚ age_yearsÚsexcóˆddlm}tjd¬«\}} d}
2025-11-24 19:37:28 +01:00
t ||||g«r^|j «dk(rd|zd|zzd |zz
2025-11-21 13:23:38 +01:00
d z} n*|j «d
k(rd|zd|zzd |zz
2025-11-24 19:37:28 +01:00
d z
2025-11-21 13:23:38 +01:00
} nd} | r
| dkDr|| z }
gd ¢} gd
2025-11-21 12:15:42 +01:00
¢}
| dd}| d}| d}d}d}d}d}d}|
t
t|
2025-11-21 13:23:38 +01:00
|«|«}n0d}d}||z
||z
2025-11-21 12:34:53 +01:00
z }||||z
2025-11-21 12:15:42 +01:00
zz}t
t||«|«}| j|||f||z
|d|d¬««||kDr"| j|||f||z
|d|d¬««| j|dz||dz ztt|««ddd|ddtd ddd!¬"«¬#« | j|g||zd$zgd%d&|d'¬(«d)}|dz
2025-11-28 12:11:00 +01:00
}|}|D]}| j||g||g||d*d'd¬+«Œ |d$z
}t|
2025-11-21 13:23:38 +01:00
|«D]\}} | j| ||dd,d-d|¬.«Œ | j|||zd/zd0dd1d&d¬2«| j||«| j!dd«| j#d3«tj$«|j&d4z }!tj(|!d5d6¬7«tj*«|r|j-|!«St/|!«S)8a•
2025-11-24 19:37:28 +01:00
Generate metabolism chart (Slow vs Fast Metabolism).
Matches the notebook implementation with ratio-based scale (0.3 to 1.9).
Args:
rmr_kcal: Resting metabolic rate in kcal/day (measured RMR)
weight_kg: Weight in kg (optional, for calculating ratio)
height_cm: Height in cm (optional, for calculating ratio)
age_years: Age in years (optional, for calculating ratio)
sex: Sex ("male" or "female", optional, for calculating ratio)
save_as_base64: If True, return base64 string, else return file path
Returns:
Base64 string or file path
r)Ú Rectangle©rwg@r)Nr/rg@r(r3é¡)r‡çffffffæ?r¨gš™™™™™ñ?gÍÌÌÌÌÌô?çø?gffffffþ?)z Very SlowÚSlowÚAverageÚFastz Very Fastr@rxç
×£p=
×?rŠz#B2FFC8z#ECEDF2ú#606060rïi¸ r)rr„gìQ¸…ë±?r9ÚkCalsr@r‰rzround,pad=0.14r)rrr3)rr;r…Úweightrg{®Gáz´?rBrF)rr;rCgffffffbutt)r;r„Úsolid_capstylerCÚzorderr“©rr…r;rzSlow vs Fast Metabolismr)rr…rˆzmetabolism_chart.pngrMrL)Úmatplotlib.patchesrØrSrIÚallrHr\r]r¸r"r´rLr[r rhrirrj)"r
2025-11-28 12:11:00 +01:00
r rTr<ÚratioÚ mifflin_rmrÚ scale_edgesÚ scale_labelsÚ
2025-11-24 19:37:28 +01:00
tick_edgesÚx_startÚx_endÚ
bar_heightÚy_barÚ color_beforeÚ color_afterÚ
2025-11-28 12:11:00 +01:00
gray_colorÚ
2025-11-24 19:37:28 +01:00
highlight_endÚmin_rmrÚmax_rmrÚ
2025-11-28 12:11:00 +01:00
normalizedÚ
tick_widthÚ tick_bottomÚtick_topÚedgeÚlabel_yr/Útickrts" rÚgenerate_metabolism_chartz(GraphGenerator.generate_metabolism_chartfsˆõ0—,‘, {Ô3‰ˆˆRðˆÜ  ˜9 i°Ð y‰y{˜  9™n¨t°iÑ/?Ñ?À!ÀiÁ-ÑOÐRSÑS‘ Ø Ò  9™n¨t°iÑ/?Ñ?À!ÀiÁ-ÑOÐRUÑU à" á˜{¨Q𨠠;Ñ.ò:ˆ ÚLˆ Ø   &ˆ
à˜a‘.ˆØ˜B‘ˆàˆ
2025-11-24 19:37:28 +01:00
Øˆà ˆ ؈ ؈
2025-11-28 12:11:00 +01:00
ð Рܤ E¨7Ó 3°UÓ;‰Mðˆˆ" ¸7Ñ1BÑCˆ# j°E¸G±OÑ&DÑDˆ¤ M°7Ó ;¸UÓCˆMð ٠ؘ%Ð Ø˜ØØØØô

2025-11-24 19:37:28 +01:00
ô
ð ˜ L‰LÙØ˜eÐ! GÑØØô
ô
ð Ø d‰NØ J  ”5˜“?Ó$ EÐ ØØØØÜÐ/°F¸yÐPSÔ ô
ð Ø
ˆ

 
ØØØð
ô
ðˆ
ؘd‘lˆ ؈ۈDØ G‰GØt ؘhÐ ØØØð
õ
ðð Ñܘ|¨ZÖ8‰KˆE G‰GØØØØØØØØ ð
õ
ð Ø Ø   Ñ ØØØð ô
ð G˜
AØ
Œä ×ÑÔà—_‘_Ð'=Ñ=ˆ
Ü J¨G¸Õ ‰ Œ á4Bˆt×$ ZÓÈJËÐWrc óddlm}tjd¬«\}}d|z
}d}|d|dd d
d ¬ «}|j |«||d
f|dd d
d¬ «} |j | «t ddd¬«}
|j |dz dd|ddfdddœ|
¤Ž|j ||dz zddd|z
ddfdddœ|
¤Ž|j
|ddddddd¬«|j||gdd gdd!¬"«|j|d#d$d%dd&¬'«gd(¢} d} | D}
|
dk(r@|j
|
dzd)t|
«ddddd¬*«|j|
|
gd+d,g| d-d.¬/«ŒH|
dk(r@|j
2025-11-28 12:11:00 +01:00
|
dz
d)t|
2025-11-28 12:11:00 +01:00
«ddddd¬*«|j|
|
gd+d,g| d-d.¬/«Œ|j
2025-11-21 12:49:36 +01:00
|
2025-11-21 14:15:29 +01:00
d)t|
«ddddd¬*«|j|
|
2025-11-21 13:23:38 +01:00
gd+d,g| d0d.¬/«ŒÊ|jd1d-dd2d3¬4«|jdd«|jdd5«|jd6«tj«|jd7z }tj|d8d9¬:«tj «|r|j#|«St|«S);aO
2025-11-28 12:11:00 +01:00
Generate fuel source chart (Fats vs Carbs).
2025-11-24 19:37:28 +01:00
Matches the notebook implementation with proper tick styling.
2025-11-28 12:11:00 +01:00
Args: