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

425 lines
45 KiB
Plaintext
Raw Normal View History

Ë
i•¦ãó˜dZddlZddlmZddlZej
d«ddlmZddl m
Z ddl Z
ddlZddlZddlmZGdd«Zy)
Graph Generator Service
This service generates all the charts and visualizations required for the medical report.
Based on the analysis notebooks in services_dfdf/.
éN)ÚPathÚAgg©ÚFancyBboxPatchc óúeZdZdZddefdZdedefdZ ddejde
defd „Z ddejde
defd
Z ddejde
defd Z
ddejde
defd Z ddejde
defd
Z ddejde
defdZ ddejde
defdZ ddedede
defdZ ddededede
def
dZ ddejde
defdZ ddede
defdZ ddede
defdZy) ÚGraphGeneratorz'Generate all charts for medical reportsÚ
charts_dircó\t|«|_|jjd¬«y)z{
Initialize the graph generator.
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
Returns:
Base64 encoded string
Úrbzutf-8NÚ)ÚopenÚbase64Ú b64encodeÚreadÚdecodeÚFileNotFoundError)r
rÚ
image_files rÚ_image_to_base64zGraphGenerator._image_to_base64#s]ð Üj 
K¨:Ü×
¯©Ó(9Ó:×AÀ'Ó
K÷
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
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
Returns:
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©r2r:Ú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_chart3sað ×/°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|
j+«}|j-||d5d6d7d2d8d9¬:«|j!d;dd8¬<«|j/d=d8¬>«|j#dd?«t%|d5«D]-\}}|j)||d)zt1|«d@d!d(d)d#d8¬%«Œ/|
j3|«|
j5|dA¬«|
j7«\}}|j7«\}}|
j9||z||zdBddd¬C«|
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).
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
r5T)Ú numeric_onlyr?éÿÿÿÿg @g@)ér3r(ÚdefaultzStage z EE(kcal/min)zFAT(%)édzCARBS(%)z#1f77b4çš™™™™™é?ç333333ã?ÚFat)r:r2Úwidthr.z#ff7f0eÚCarbs)Úbottomr:r2r~r.ré ©ÚfontsizezFuel (kcal/min)rég333333Ó?r8ú.1fÚcenteré ÚboldÚwhite)ÚhaÚvarƒÚ
fontweightr:çà?z kcalr€é
Úblackgø¿z mphÚtop©rgffffffÀgX9´Èv¾ù?z min/kmr3Úgray©rr:zHR(bpm)ÚorHÚredz
Heart Rate)Úmarkerr=Ú
markersizer:r.úHeart Rate (bpm))r:r-©ÚaxisÚ
labelcoloréÜÚbpmé r@)rBÚframeonÚfancyboxÚshadowú-)r2Ú linestyler=r0çÍÌÌÌÌÌì?)r€rzfuel_utilization_chart.pngrK)rN)&ÚgroupbyÚmeanÚroundÚilocÚindexrRrSÚstyleÚuseÚrangerer_r`ÚgcaÚbarrWrXrZÚ enumerateÚzipÚtextr]ÚplotÚ tick_paramsÚintr^Úset_xticklabelsrcrdrYÚ
set_axisbelowÚ tight_layoutÚsubplots_adjustr rgrhrri)r
rrÚ speed_groupsÚ
filtered_dataÚ stage_labelsÚ x_positionsÚfat_eeÚcarbs_eermÚfat_valÚcarb_valÚ total_valÚspeedrnÚhrrorprqrrrss rÚgenerate_fuel_utilization_chartz.GraphGenerator.generate_fuel_utilization_chartqs—ð—zz *×/¸Ó ب2Ð ð
×
Ñ
 
&¨<×+=Ñ+=ÀÑ+DÑ 
ˆ
ô
˜
 ä.3°A´s¸=Ó7IÈAÑ7MÓ.NÖ˜&  š РЗi‘i¤ MÓ 2Ó ð˜~ѸxÑ1HÑHÈ3ÑØ  Ñ0°=ÀÑ3LÑLÈsÑäg‰g‹iˆð Ø Ø ØØØØð
ô
ð Ø Ø ØØØØØð ô
ð r BˆÔ Ð(°2ˆÔ Ôô2;Ü ˜ Ñ"?Ó 2
ò" Ñ -ˆ-˜ 9ð˜Š}ØØØ˜a‘KؘsØØØô ð˜#Š~ØØØ˜h¨™lÑ ØØØô ð
H‰HØØ˜CؘSÐØØØð
õ
ð3" ôJ" -×"5Ñ"5Ó
‰HˆAˆ H‰HQ˜  s  ¨4Ð0°XÀ%ÐRSˆHÔ H‰HØØØ˜5‘= Ð% WÐØØØð
õ
ð
ði‰i‹kˆØ Ø Ø ˜)Ñ ØØØØð ô
ð Ð)°B¸eˆÔ ˜S¨UˆÔ Ôô˜}¨YÑ
‰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|
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)rJ©r+r,r-r.r:r/rTr0r1úHR(bpm)_smoothedr•r8r˜©r+r,r-r:r;r=r.©r:r-r™r?Úright©Úoutwardé<r5r6r7r9r4r@rArCrDrErFrGrHrIzvo2_pulse_chart.pngrLrK©rOrN)rPrQrRrSrTrUrVrWrXrZr\rYr]ÚspinesÚ set_positionr^r_r`rarbrcrdrerfr rgrhrri©r
rrrkrlrmrnÚax3rorprqrrÚlines3Úlabels3rss 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À|ð ô
ô
ˆ{Ó ˜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
r!r"r$r%r(zVO2 Breath_smoothedzVO2 per Breath (mL/breath)r*r/rr?Tr0r1r4r5r6r7r8r9r@rArCrDrErFrGrHrIrJzvo2_breath_chart.pngrLrK)rPrQrRrSrTrUrVrWrXrZr\rYr]r^r_r`rarbrcrdrerfr rgrhrrirjs rÚgenerate_vo2_breath_chartz(GraphGenerator.generate_vo2_breath_chartrs^ð ×/°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*r/z CHO (g/min)Tr0r1rr4Ú FAT_smoothedr6zFAT (kcal/min))r+r,r-r:r;r.rxr@rArCr?rDrErFr8rGrHrIrJzfat_metabolism_chart.pngrLrK)rPrQrRrSrTrUrVrWrXrYr]r^r_r`r\rZrarbrcrdrerfr rgrhrrirjs 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¸<ˆ
Ô ˆ{Ó ˜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ˆ
Ü 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-«\} }
|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).
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(zVCO2(ml/min)_smoothedz
VCO2 (ml/min)rJr/rz VCO2(ml/min)Tr0r1r•r8r˜r?r-r™zBF(bpm)_smoothedr6zBF (bpm)r4r@rArCrDrErFrGrHrIzrecovery_chart.pngrLrK)rPrQrRrSrTrUrVrWrXrZr\rYr]r[r^r_r`rarbrcrdrerfr rgrhrris rÚgenerate_recovery_chartz&GraphGenerator.generate_recovery_chartïs_ð ×/°wÐØÑ ä
˜7Õk‰k‹mˆô ØØØõ 
ð  Ð ˜>Ñ ˜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À|ð ô
ô
ˆ{Ó ˜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 ¬
«|dj «}ddddddd|fg}|D]X\}}|d|k\|d|kz}||dj
«z} | j«dkDrv|j| df}
|j| df} |j|
| d«j«j} | d| d|
zz}
tj|
|
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.
Args:
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)rg@r(ÚTimeÚTSIzTSI (Left Leg)Ú steelbluer8)r.r:r=z
TSI-secondzTSI2 (Right Leg)Úorange)réú)éô)éî)éè)éâ)éÜr?rz--r{)r:r=r2zTime (s)zTSI (%)z<TSI (Left) and TSI2 (Right) with Black Slope Lines per StagerŽz upper right)rBgÐ?r1z
tsi_chart.pngrLé )Únumpy.polynomial.polynomialrârRrSr\ÚisnaÚsumrBÚfitÚconvertÚcoefÚxlabelÚylabelÚtitlerdrYr rgrhrri)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_rightrss rÚgenerate_tsi_chartz!GraphGenerator.generate_tsi_chartKõ
˜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
Ü
Ü ‰ Ð
˜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-
Generate body composition donut chart.
Args:
fat_mass_lbs: Fat mass in pounds
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
rzz#fde3acz#ff9966)r3r3r(réZrÚw)r~Ú edgecolor)ÚautopctÚ
startangleÚ
wedgepropsÚcolorsÚlabelsrwr?z
Fat Mass (r…zlbs)
úrˆr†z
round,pad=0.3r‰r{)ÚboxstyleÚ facecolorr2)rÚbboxz Lean Mass (Úequalzbody_composition_chart.pngrLiX) rRrSÚpieÚdictr±r rgrhrri)
r
rrrÚ total_weightÚfat_percentageÚlean_percentageÚsizesrrss
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
|d}|j«dk(r|dk(rgd¢}ngd¢}n|dk(rgd¢}n|dk(rgd¢}ngd¢}tjd¬«\} }
|D]\} } }
|
jd|
| d| dd¬«Œ |
j |ddddd|
j «¬ «|
j
dd!«|
jtdd"d#««|
jg«|
jd$d||
j«d%d&d'¬(«tdd"d#«}|
j|«|Dcgc]}|d)Œ }}|
j|«|
jd&jd«|
jd*jd«|
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
Generate body fat percentage chart.
Args:
fat_percentage: Body fat percentage
age: Patient age
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))ú#F8A8A8rrx)ú#FFEECCrxr')ú#D0F0C0r„rx©r,é#r'©r+r#))r+rr„©r,r„r')r-ér.r0)©r+rr'©r,r'r'©r-r1)r+r2r2)r3r4r5)r,r„©r+r>r„)r3r4)r-rx)r,r2r'r6)r8r(rr?rr)r-r~ÚleftÚheightr:r r=gÍÌÌÌÌÌð?ÚvrŽF)rr:r—Úclip_onÚ transformé2é3r'gš™™™™™©¿r†r)r;rrrr7r€Tg{®Gáz„¿)r:r;r:zbody_fat_percent_chart.pngrLrK)ÚlowerrRÚsubplotsÚbarhr²Úget_xaxis_transformÚset_xlimr^Ú
set_yticksr±Úget_yaxis_transformrµÚ set_visibler·r rgrhrri)r
rrr rÚ age_groupÚ
gender_abbrevÚ demographicÚsegmentsÚfigr;r:ÚstartÚlengthÚticksÚtrr,rss 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Ô/‰ˆˆRð%-ò Ñ ˆE5˜ G‰GØØØØØØð
õ
ð ð Ø Ø ØØØØØ× ô
ð AØ
”e˜A˜r 1“oÔ
Ø
Ø Ø
Ø Ø×ØØð ô
ôa˜˜Q“ˆØ
Ø#(Ö)˜aQCq)ˆÐ
×ј ×& 
×$ 
×% 
×Ô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
«|k(}
|
jr0td| d«td|dj««Œ|
jd}
|
jd|
jdtj««}|
jd|
jd|