From 847e8416b46f9db596ca5e77d40a57ecff04e7c4 Mon Sep 17 00:00:00 2001 From: Gael <Gael@WL20-0067.corp.pasteur.fr> Date: Mon, 21 Sep 2020 15:49:35 +0200 Subject: [PATCH] session package ordered --- README.md | 18 +- other/slitherine.doc | Bin 942080 -> 925184 bytes other/slitherine_config.doc | Bin 70656 -> 71680 bytes other/slitherine_script.doc | Bin 551936 -> 0 bytes todo.txt => other/todo.txt | 0 slitherine.R | 326 ++-- slitherine.config | 26 +- slitherine_script.R | 3125 ----------------------------------- 8 files changed, 173 insertions(+), 3322 deletions(-) delete mode 100644 other/slitherine_script.doc rename todo.txt => other/todo.txt (100%) delete mode 100644 slitherine_script.R diff --git a/README.md b/README.md index efa1252..e58846d 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,9 @@ Slitherine finds significant coverage differences when comparing two contact mat ## SLITHERINE CONTENT -**slitherine.R** file that can be sourced in R or RStudio, after opening slitherine.R and modifying the parameter section +**slitherine.R** file that can be executed using a CLI (command line interface) or sourced in R or RStudio -**slitherine.config** parameter settings for the slitherine_script.R file - -**slitherine_script.R** file that can be executed using a CLI (command line interface) +**slitherine.config** parameter settings for the slitherin.R file **dataset** folder containing the datasets used in the publication @@ -68,7 +66,7 @@ Slitherine finds significant coverage differences when comparing two contact mat |mouse_zygotene_chr2_region_27700_29160.txt | mouse meoisis zygotene stage (Fig6)| -**example_of_result** folder containing an example of result obtained with slitherine, using the slitherine_script file as well as the AT_Dndj1_D_T0.filt.2500.rebin_1162-1388.txt and AT200_Aurel_T6.filt.2500.rebin_1162-1388.txt matrices (Figure 3 of the publication) +**example_of_result** folder containing an example of result obtained with slitherine, using the slitherine_R file as well as the AT_Dndj1_D_T0.filt.2500.rebin_1162-1388.txt and AT200_Aurel_T6.filt.2500.rebin_1162-1388.txt matrices (Figure 3 of the publication) **other** folder containing gitlab web interface files as well as other non essential documents. Note that the slitherine_config.doc file can facilitate the reading of the parameter setting description @@ -77,7 +75,7 @@ Slitherine finds significant coverage differences when comparing two contact mat ### Using a R GUI (graphic user interface, i.e., R or RStudio windows) -1) Open the slitherine.R file and set the parameter in the "Parameters that need to be set by the user" section +1) Open the slitherine.config file and set the parameters. The file must be present in the same directory as slitherine.R 2) Open R or RStudio @@ -90,19 +88,19 @@ source("C:/Users/Gael/Desktop/slitherine.R") ### Using a R CLI (command line interface) -1) Open the slitherine.config file and set the variables +1) Open the slitherine.config file and set the parameters. The file must be present in the same directory as slitherine.R 2) Open a shell windows -3) run slitherine_script.R, for instance using the following instruction: +3) run slitherine.R, for instance using the following instruction: ``` -Rscript slitherine_script.R slitherine.config +Rscript slitherine.R slitherine.config ``` For cygwin, use something like: ``` -/cygdrive/c/Program\ Files/R/R-3.5.3/bin/Rscript slitherine_script.R slitherine.config +/cygdrive/c/Program\ Files/R/R-3.5.3/bin/Rscript slitherine.R slitherine.config ``` diff --git a/other/slitherine.doc b/other/slitherine.doc index 0b0fc8905c03bf20e566aae423d2c40052c505da..35d8db95061f4e91bc1adbfac41142be8dfc9d71 100644 GIT binary patch delta 151915 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	CgmQC{aM{o2+KLjHjQCN$0 zkQjGkFHYbzB<7pAh5LAj62vU?As51H<B(4b>B@^ycr%ikXj|y4W1DVM59Xt&b{AAy zsnrUygad2S_|40wTy2{7zlG48#9Co2CV&Fb9m5G+!8P1HyL<UeUL*XQ*-paqu(i_G zv&E+iv9uB#9J8zK3oCvy07cz0>b9cUI0`4HCtJ;7lM!2xO7}=YTHf50O&yzGsoGqp zNKSvE+wU}N2+p9pih-Db6DWCsy&^2fZd}4w6#j!n{YO?c?wL~95>P~0rSC3*N^%eJ z0x$6f`AE7vD!~tuT>w-_wyDTW-<!T_*2r0VXZ32{>nGdB-TtQTDW*hQ=O(<kGF{!@ z%#>YiTU=@K!)At3DBB{3B=s2zk>^A;)P*kwK<3ascMF-8IeZD3OKtSc_;r~R`>E}Z zIv22BO%~iyiBjLY(TH>@q4ZF%lwhsiP(rDs&MKx<ZIDC0R|8T)UNGYqNNKIZc1WpR zgp?d5rt5>ge^~05RF3O?<rm%v(tgPoc|Qini<A@0IEZ$a*dN4hoI%26Y9`#S&}+pi zY`$VU9&a7ZQcgl?PtDo7nQ<*&ERvIv)wo}N&K}47>aCxY?CP>I3ZrS4QD&I?lI1uo zgM_dVTak*xI0^~t94_G&?nA;XjK*jKANWB+AAms^hl!XBnVp%4#}Xuf*|V6-DpT~H z_8INY4EiGw!!Q!|nLomG8l({1DF8E;LkeWqWs7HdB~|aYiw_5J9a2gUAthB2e&`A* zwfRT@C8xWHOSpnNc#1dph^$xXxm~sRRaDmNd&(d8;1{8oj<ra~GdNzO+ko~MiAC6q zgLsVs*Es-$E~s&XdVm=8`IA=srhO-`vJ$HI?M`y`Y$R!WvY{knPdb6=L~Ou+vyrw@ z25#x;)zhm=sF$T{6{UmTeqq|J^3>>zs>)BbC8D2xh^imc!5EGa2**jB!V|p4+v}Fv z?#d~>$6G#pMSf<XEZkwAt#M38Vm2%|fWxqM9Ww%2Wz^J0d@Zl~zi0GC?Xbd@{z`jw zi@U<8GS%piXgfJ_<2hS!<#v7f_9>*{3K~#oUI>B|;4)mnJ2>8CuNf4ouIWun{hF+7 z-c9+?0siQR@rcAU%s~udaRe{%8aZxpnia*-2HkF1ylX3a^(`c2`yY4X9};m6p|?4^ zh)ehrmG7{~F$s&{dY6qjn%rZr;l6fVw!igcF&AgE^Jp7?);50gKWEUI)l*X1NJc#{ z4E7AaGM$%<B;$*aj4wknzmL~=gGyxn6C{`pcd}aA)K_-ty_nKXgoHN}3$PF>B-|x< z3l~C`&~w2DlOVIP?rv6#S3_mLz7kW~O!Z{OdSN?uV8DH10yC@2{(!S%53*V+HCF!6 zH(`n=0kKw~Ac|lFCSnHWV*!4}PFRqFRGcN1CLYQmy%$ru7MZl=c!($Xgs;f@kWMlh zqY0W~HIi^1w{YhnbKuDwcu9ovSMnD>{HyLBpY@M8o`NQb!8eqB%({X}ScAQfZ5IH9 zx;iygw+`WGCZpomPJ=RtaACD-bLD&!GSrfjWD;#jnfQ866h|qPfjxOidOdc4EG$jD zne7%#>Hflf<a)v(G?axGW?&`~uoBmB8z1lqrl)jhk^gB{ON*Au9(^ZC&7P8cQ@(Wu z@{I@l<wG=lMvcc~{Eht2`5gvgFrK|&5x!*a8hu|fo?+$e{tJI&P*H7|f)}k7SA7$5 z)D=Vtl*4bhhFiD~dtUiSzZ?c)JS5-vXUw|~^X|(O&zhl%;V6#d5+t&hkmzy{kqc^| zChDRdB;v-9s0V?_ExzrPZTdDc4?_`#@tA?xSd3q=3W->a0nF=StjB&_#Z%bIz|y8Y zE0^yNrJ-9%scb~h-z*C_y`qJJ5k*iN!HC5{_`H^05$FFhqccaz(H}Yf<EE&p>u{x> zTCS5a#om~2?j(EI4A!U)mkZplbW+N-p!|6jjWxHlA9Bl1%Jv*3H+xQ_$ZaQ%Bj+17 zYHz7c@3ak)r|sgV`%XOj^(*@Ww`OyGe@=JCA#c`2NogQ~_CNrJAQU6<W0H6Hd=IW9 zEy<6vW?^aIrySEalFWWbCfwd>8SCovz7{FS{+^&w9ko#pEzk*F)SoIU#V!8bl+}7y zBG$enf7k^JD=QxAsteg_TF3V0YMgQ^cfZgZa^o2vZatM-1=sRto3I<o2UZP~LOnHS zWhHlZ>+v@!f7!)wQv>{!gZ6Uw>BW$lTm2LV)wh?jO?9oJR5qOYNUrWm0ZYpOC0VaF ztjvIEhPv!JZO`Grxs73RVUQ~YNxMJ*LCURcg+9?-B1A3W&W?hix>Cf_u#a+7uNJA! zT_uK^ikqcwKjoxeb*rfqQ4O_~(#A1gsij!`m1cYZH7zewI^#DsXV`|Fu&4#=D>brI z)mvJJD7*EZRrLm)I~t-TTA?-CAQ%IYh$QSsDn?{A=<eVy@)|6jgXmthkVNE5^2>>i z23<7fAQl^O43ALP$)H<{b8vMw=*pr!`Xa{JAP;;gufAAL$5eaP)r%b2+o^8BG?-dH z)w=0(ai*FLRZ<$~H5haSQ3~ZS99wY!ckve<AS)T?!URZg5>Q<yOXFe6VSRmxsI4uk z-MsI`Nu=Q{?2$^8o#1bac8{~AekfgtPK2%7gGb1c&7i9cKX_)Re2fNN6~&<QKr?tl zMJ7B=lsAST7V&U(G3Xk*7}P0_j@rONHPwjmltt(lgEq*gHlA%Ej+oJB=Yr3oat~`s zwdyy9*$o&<?>!`%^Ml7nDfP_~&_1Nu0+WEcVIW3f3=9O=6cT7Nv_=<5(D~tkzP1@~ zCt#TgPsognfYzPlP%JNoo}gdpA%g;jCa{lYF^{JA-cJ515{Ho?-#}4jvkIERUIcxa z?uY4!LNsPWiX{$GH1kZBc45kPy~jL09K&&(z|0&5T?)?N7Ic)M3v6Yn>%g>j4ku<` zcu?k#2Zbzy$0-Z+Z76W<kACLe!_}ahf+r}K)4-_Y23<#N#Cc4~WzbE<R&2v|{EiG< z$Yra)@|XY%3ob(MDVa;UhmZz)+HXl;M|yhvH=hIi?hGWq8#yhW6IsDJ-r&P+JjW}% zhJj2KxFR=7pbW~x9e$92BOyUg!%SF%w{)DWY}VJd&&3h`LFR<H&>3@+FkFxa`Opv^ zXbPX)mf8{Y_Pfd-%O9GM1M&s=gL8NYLmm=CZv<f{{y=(ugYFVu7c}VJ!dS?lD~SMn zC}fb!(Q8>RM-Q#XMd)!p{LpTj;KFndy{8XJcS2`$!#IRv1y<o0&fqNUp=2dn2_-jr z=dpPHOsSgfaZTixiIDgj7cl6WK;n{^7T~=#E?vvQRE44jontW;DGnoNaf9w1Ol}69 zFZyE@ZX<6A3aunn0E0>ybemDA4D*S)WerB%#Igq6WXvyXnKfMr(+4y6S}qI7=?=0M zVKu=pavg*9ut(rY?vs&=+{<B?Eed-Cl6wFocgcAdnw8daSEm#+g{h%Vrgqjr-Z|M` zPL2D@<1O6Jah)>f**gVGkpIL-i4teua%5GWByk&ADo|h;P|=_pim8}}>&RQlplgRe zF{?652XD~kC)RYlLBlEr?KGwu7vbDfwU2Eq=g?^Sd>m{sB}6NM=J{l=C;L8-F#2Nx ze#Qc<$38s7M@X3VP+|xn7B}z)Z($;oe2~y?LPD!WNcQlK*g`B&l}5j+p@y!ZyFnL$ zuGI{>r5Ik_pxc4CS_YkSZ8k%7$rKgfgOc?u+h;57^uf%eq@aB{iUj1#^2J?vfX|4m zK|#T<ra|`tzP3bNNO%&?pk5tXJlHewv}JUS_h<ENjgPhv(^qpWoo1+zB|S#r`l^!k z2n*9N9WxM%$9Mwg`lO0VXpOd*fJtc9fHKDdti^FmYG}|c!g_4LCLBbsMpOli$4tz^ zoJIz-ZaWii8yj?A(7lO4*8?g}<19X)jE6y29koy!P0$t{P@pNZk8T)@83^|z6J+tC zm4XL)peI&i4L0JAR~9nUZpbYVuVe;ORN9Qmj68+|fxDp`CO~E`+8VfSDen?{8Xn*o zJeh}PI1Yc}o`g@xLY%&~c!^J*x#9V}N>h_<!*y%V0BEWv%u@n;%WP~%8Xn*oJej3t zXhi6ZA+sg3<d0qmfXv>nNP^7f159mZ(EWmB96;{o^dsgf{%ZPMg)Zh7LsL~dE3KWg z{4$80u;>NK7{5EVum8>a2Ykd=6eo#J@WT{H@_C!HVZi{5g^M@MSWBt}cHkIpqfjf0 z-$D+Ibs`4sOY+A${@DJ7Zmnq9TC=FJ25(TjjX^gWr%>95x`=3O#&f(x@wNuFgOj7L z$_RIIYYXFl%CP4a4rRLPdln+q8j#f2;2I>Ca;S`7unLKgTu<Q~B=@Z3S{P;U@cf>{ zJ<(yj0-#+9tgiS)2~=0iQH<(~B}&=<ZA|C;=A827Mre*+2!+hjc+ABTY{zlPY^Ea< zFW}7Vxj|;#KHIig*7a%2>V+KbSQRl4GjIk4+q2<E-S(`j?V0fIK=%w6@eQ2mlk??2 z{9LVlo;`ZDzlMLYBrj7KDM>rJHgkzmxpQesTIYcWwrnM<S8(=a&j7=40Ech{#~`_f zAsP?y0v<%*iDn%Pw!4*NWZ<po>~RHpIkM!I%aY??wYXdI?u##w*sFEqn`n-n*pJ`Q zp%WcM%tI<3;R&vGrg`W>cMKme*iTyrJXQBm_M4*qw;QGSok^X&$FYEVYo@|;PNJ2( zSt}0ZG4qSrjefLJ$!GpC7zx6e%p`~zkU;i90(k%l#vaJ8wqRnq(qF{uZd5lobT{a- zqZG=cKANB#q+k8xYj(nDXa8o}OQ#-6S87@wuTt{ptxwhn|3xVqQi%D~*|YeYY}%2< z5?GLmNRs^-(ULq&J@^~6hXt4L4n=x0JJ{?`_Y=8#v81sFfAnHgeb&KWW#njXFq7xQ zu!W`}W598a>9pgVwu3>f+R2%_%rc}DHz<Y71!abMp${aAi?|AV6anPg7sD_LGqDC6 zAd&rsv$zO}@*$q#EhOUHL|XvWP#aAk1(=yI8@VzQM*ELu!Y(sGcG}CU$*UBT`X))4 ztS)G1;`)hI>^<FBqm)!1tl|)zua~JZ<HC`YFFK<?24NJYVg{t3uHhzzQdpA^iJvha zi(xOw7z%J6P9P1};T*t%Kx25JGrD6W#s>UE=Zgt5<fO8813*UNW9|P~K4<K+-t5Is zKgL9zvq>4Lwq3`m+VpiwRrOpg=4$vJrJ7n~i&7z^1Pf2gQ<8g!;k{`jFb)^+4s`>m zhv<aPs1?M1U>~-rSb;mJ-j{hq-hM15ti^FWM6LezzT9=%We)CXM>meBn|@VFsp%UO zceCWa7MqZQLpTeG$c+ffpeE|U8xo~Nco@fFk5r=UXp3|h?;{b99r%JL*La<<{@kK& zQKzcI7@A(q(p0rf*{Dp`n+wWc>6t&7$7X1Q_UM8T422m#V+mGZ7xv;Xj^Px};{vY0 zK>0XB%B&#VAXPCsK`yb-USXNZ{GVxJgcJLjOqSig&78|jN#*>@^8n6ltlOgaeP4j? z=7N$=8FWWq1Y<BlF$s}ajxE@ULpX-pxQDm+gwJqf+2uh&R6|YFfj8Q~2Y%>>ftb?Q z-MYY|`49){B2UTUM7Q-v7?b;AxB}2V5fGzp-l_~!L-$x$uu|$1H`7mQY(uU~+p>*g z8M7O52AV0Z6FtD6EZ(e?Y*12C-h>q7p(+(cNhHBu&DJq}3{u@L;|3n~v((?tK^U{t zzc=^@r9V4mXbNxiKyL(NEGA+yVlWT$u>;KqQ1{UX!5EC0n1xvUfw#yKOh*KRQ6PjZ zc8I}ASAmJHA(rVomGSz)tO;6*XL!%Vb9nJh$w5-fGLS9CP-+qyg;IY<(@#JQ)?q6Q zV^~^fg#%;Ruuf!Y<LzXFuHsZWH1M8EcW546Ja*c6s#IwcM>WlIXj4AAZ)5j~HravO zgq&>;g|TqeQCA`j#wd)#d>p_zT)-oI#5d>(RDvyqil_>AG)HT6LoZB0JQiXR)?yR3 zf>nUK-??jxP6(GRTFl8D8ZyhjSnvlf;u0R<BlLp|Iw#~pL6kyWG=VqTqXYUQ0#S&? zLa11d6<CF>*o(`!i3j*L$k0>gGMHL|VknLZsDXAEiP4D1BBbF0{=_4^#A|$leh6Jv z1Y;P+4Y6F^tCZE7$ML}o70a;}Td)-=ID{iOh10l%>-ZCY;TfLeD~wc>oXCyZ*aN9R zCtw=JstmdIgz^3QS${lM<kpFdBwy{P8dNcRKHFusWn|r~C~Kd)ZBWkr%2sn>Ng@fI zhO@Sy9|m9*He(0Q;UltBXI)SRwNM`o5rF;}guxhxNtlC`*oNImhJ>5Jy$vy8sYzj} zCK?bK#q4oRMrwe!8sCtr?0be5Q5z%De2L4Awg%F@cyW}rF};?FTW-!MRn3JZrIR>= zbX>w4yu~{>jUZCwK_QeuWz<F!G(#J7fgc7T3==RFvk;BBn1_W}jm_9I!pxe(#0lKQ zbG*b?d_%U8EHP9-GkBvf`Xd_i@Cy>L78|e~$+&}JqqO#x%YEe)^TSU*%WsQnzq0=G ze}1xgQRC8-SSdw6a~(;l4633w+Mx@2V*r9N3ga*yQxJ(5%)<gK!!8`gNu0t{gwk3` z3nr~q9+ZSE-N!PNT0i+=>L&|3iAUGU&;N5}ydsrRk|>8tXbEWq+hHDdpnMoD2X5m& z^3Xt*hC6DZ114fN;;{x6q#za2px(lL&_1OnFrG<zSY~>FcV>Whm?_gcEYmw6Jxtq1 zt4$6lLF(jboHufBZYruCNM`NXvXM>M)?`*8ZJ2}SN0rLvLXz5JJb`W;oqXg*0W^dU zI-nE!A_Rjm5^;#fT&%(_q~I{l-~#@{D}01LoK^t}+|VH0gB>j<TB8FxqC0w^7Y1Vt z=3xm|VJ}W04OhY~smB#hz4;0suHqh^A=`L^?k7}*4>}<Vu~>{>u@PIa8!5Ptk`t); zsDb+Ei0<f%K^Tm&n25=khUpUw#dUL;P_Y;ZScmo4gX0q{%TFqO^ycGyNW)pY#Ar5+ zvWbku2|PmYNt6$p%K|8h;^>KB48aWSz!99ppLm8>c!T_`-$lV4g4+HwBe{iV2DJ(g zY8CGk-YP!4RZuH6;;8aMjs|=m-n*7b>wQ}XH#QfN@0Ua=xT6-jV<3hh6cLz)SZu;( zY{3DXKpK9>4cx;syu)W?jbICa94Lt@phhPq^WcJ*%v>@wB(GNg{FGK<wp!#EE$V?& zRAP?_+^|Rk%g`NXsKiAiff{H4Pk5m<+Mpf$F#sbl7G|hegLT*q3l8BlZsRk)qVN<7 z6kce9F6fCs^u?elbtn-gmf#|8-~pb&F_Jk&eiTD-RDvAY*!O*?NJSkH=2%$mRZMY` zarP#uW-k+?vS?cjMw=d3NxtHa>ZphM@J1W7MQ04fctju)zoI<-E$MfqA`Mq@6L%pM zBq=jJK0G}<y&uBUeZtkI3C`}apXvUe>QPbE2H*SF_LnDa%Ql%So*Y8*(5ur0Ap|Lq z9Q8jF(R3n@roWCIb6CmZ$r;(_(g8qq)WA~g$0huY4`@4&eOY|P#QAL7=5vx|Duc&J zr_qxByBs8zInj}i<mHIY7>2tjG>s+-%diqR@fa_l5LX?vfDig$B*r2fOOXg^Xc_R4 zt8=ygy?c)0|L9Tn9U(RRwUev*{JPXcFLoKy-^hOK8!oJrO})C}v>bpt&4pkq(v_0t z{F35Y?8jlG;}3j5wkTEzxWWx(&=&3Bi{2QCaF{U*@mPYT*a{0$aT34b2B>PbH7mC^ zGwI3U%u-ORAew|A#>LZmEmznm6rUt_T*xNFbp^L>{AWe`rkJ?in`Lb-BB{Q|H#p58 zYPcXD@}m&SqdMB7D|%xrqA(K+p<*RA;0PYzAslD2(x53?p%Z#z00z!%$lAt47!q(D zckvXjq0D0Yg`y~pGN=Yw<9;0C(%Ck|C1WmzITrjr#-+CIb&#!OEpui0UTxGx6L`P} z9nc9q&=>tM3K5u&8Q6d-RC=lW4KWLAP-HgSOZ>R{*;hbc`z_GcZFt)RXE$|uic<0a zZDqV>TN%yyB>ms;2d<(3D_&_-Ky!p50@JV*8?Y7IaRJwH8+Y&=uTda|g^Hh06;03# zLogJ>Fd5ThiqKJHA|A_-h)vjyeKD3LSCs*J^FBTtMjFoG7H;Dy{>De>W7&^GHe`nh zg;56XsEx+(!vKU}48jnBS@;FX*o#ZJf^V?~cb!ulJ15AGA}Efss0=^Mg&e}Nj=2z~ zZoAI);is-Ewe@ECr^QIbdK|`Y$iP)x!vj3QGrYlDWTDw}LN>Uf0&1fn8Y2kzU~eM- z-5vej8_hyzv_lVPw}1AGWWoQ?GD~N)ptP}Ww4r4n?X0x16EFqR*6zd}Nc%b%!!ZG~ zkc4A6ho|_AY_z{QkP|<_2jgLDmv!+>|AJLWnO~n0Vd66W!UN=3U~P&R13Ec6c@+OA z2S8r(F29slraF0}(m?%|&f&L|il$zw?|ycuLa%YurR`rzNB`1n1hmW~y=ZJlg@rVE z7@|@Su>i^<>NR{9v%X>}sxD!sa2rpcU&^|T;n=#=AXobNTJP`~`jiX<Wh}Y4I~)=W z{Qj}{UFEh}@-Bqps0VL!K_B#k#PuuIBNaz*5!dhtF2tG#61NvxAPkc*4Rf&&D<SiB z8Mp8k-YhiK)O}$hJ2ROBg`qWW@)QxR%O|%PGBqQUXHfBzI}Vvp*|gVI5A5V79_^;K zgwtGwrA<-HCbj4TWxKhQq}3Esh%+z;E0KgfNW~fajdzejE{lrjjzEN948rj<WFhRs z5uC(j+`?15#8;Ho7E&D&VIly-FbZt3tfv*YNQWsl#yw?Ⓢou|B-#hml0fX_OE%l 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 delta 162636 zcmd4acYGAp{`mjhB(o_b5L!U$l28&1X&@lIOHBi$2R6y3K#~pF6p*rDMZr+@h>C(B zNE5KITtNg2TtOuo1-)JnJBnVAYe)3=de7`8o1lI_pU3z6$B+2TwwW`hpEGA><B~(Y zmmIlyRl?+$K$Gz=++>R7xtUkL|MABk@@6Yuw?-SZMLV>I6&(<XD0D<8bVe6M!#y~> z;XLyizktp&j|2ypOqZLyRC64j1er{)rH7dsnlfi+&NekSHCMK)0Zp3(M3{O^4KroB zOu7dy1t{A{t?k+Zza&>es1blXR^DJd|GUR##wPl25~Qc-3D16i_IPJ2QqaR>`psf8 zc|ZSSpUHHNEQ#!EB1-(@$=^OU?q_^n|8WQb`SH;(9_8Qv<gp{$oqg71dWIcW?r&f+ zCG$oe0i>->^J^O7O?%^hyo_+wKVtpYvZL=m@9y45Z_2#e$m>hI_y_w%@c7Xf<CFT2 za-7p9Q}>!O@di{sV95gCe;<ueOMeaR+07f#>p!nOU<pr`j5nDkD07>zF|O$ojE}sB z@)mFSho<e_%%`Oe>;Js(f9WZecL}1Q_d_1zh>}#3Q#>Z{D8()RK4H7tcs#pbe`%8a ze`ZH{-Nt0Hm?Q#`5|^Q)7xT0SNAzxM>`_}qpP6VfEu3aDd6VgV^yZ`Yb>n_g)jLPl zzBWSgzV?=1-adUhKeA7@@8kWv{-ZZ7_1~|3y|zu@V@cj<*S=l%u-CsY$sX{R(UjKN z5ffTIJ2q&lpQSu8E+H;qZCXhDT1SJBwPB&d*Paj2o{ewtntz9~;%r-~-CCMww>tP$ zVs#ee%VU0#-I|kMV0W&yRW)6EKDzPRm5q+I9O@`6ww2~*7TB#7Y-UZjmiLV79+&uR zdiZVr=ESvcHobrCsb-B_)^WBX!gZ9)w>s^mrTIm<&akksD9=CZ2m-bi*$VAWE8AHM z99abFD3Wc8OB}Q9S*3CEskL7>Yh-PFBCS#SPF6>b5#O@X;<8d}j-w#kUJ@pe)%QxY z_H(h{;0ZH_6=ly(oH=afgoHRgEsaaMDIp=Q#GaX7G&3==XHvJs?!9}*mCh@zA8<~7 ziL=yNXe%wrpQmR+oON6o?_}C}Gn<UcvE~<*+H>tCu~z%MEPHXOHD8aCBQC$N*illN zYAv>vkbqM1Gv6s$U@di6C!|jtZjE-@?F3ZdsECQPjw;Hw+p}Z6p^+OUc58`!Zdrbb zJzI9kwHMh-C?8ck#jmBy8eQhpkDi_H%qk&tD^G}IW|^LQF|~P+q-WjW2}ubFGY6NI z*b8P(==s0P1E)R9LDBeT0;T%D%7y<?Cd66`?Y1H+2t{fmoASsn&p~-+D=4wsvZWH0 z6x&-CQIW{J{GuXzb{O?AFD}1G61sL=n;Tps%QCH=%HxbrN=Uppp=V;Eb$phiz*drP zP3+#iM`Aox(nev#kF)1H;-%DWnNCMR85t>|RoLcxtCmrxtYkr{E#DJ6JH;gRO#(5R zhBdmj(z*1ST=P09#)zPU9i$cy?GrzdL^$JbvDpjahuNKTN*%?28-;AUljQ2{!c)bK z9ID7KDDXy1Zw4iHXIVk1%V~|a&y&hW&5<a^_%^t75|}l|mg{M7StNNT?Yy+WJ~Mr0 zPFYcwUV-#f)oG0d`I&K&HIjzpiDSo-W#zO^M~P%qRvwi+OX@g9=OSb5IZ{5-mHhAW zwKjHf)=4G#6o-DS91bIa5w49C>SYvX9Ws2<;Pl~r>by%MbMZ#8o%U2zYIPLp`#I-3 zOYMbvxkz&@$+2bGt+b%*IO_<4&M$J7+KRI5vAiesFKd2oMSfAw9<n=6vK<vpYp+;6 zBs~kLj#7-NC5~L$w%&(1<J05QyLFGdDXx2ZJb6`OE14e|XHD@OU%IfYLh1}zWE?}1 zlWxr_usNOiS+)Yb;p_3LJ&w@{OiP@hSL@{Tc;eE{6Lvg@inLBkn(=orsfmbD1HGk7 zx2U(2&aS^G{rJClKQ3KbiqvdtwDi{X%QnW_XlgpHzX*s9%~6o)aLuEXW$>`eI8#L5 zNHZ&<RxtutZRNK70vqFtWC%H)W#hd9r$hQ)DY`z^$h^|hVrQTD_}u(bwxoJe%4H>S zIVJJAg|rPv>0c!zzQk4$Uw)G-j^XgHwjr^;?Pi=Y2GGftWtGy8@|nG`xO9G8mc5`L zPWoOd4*8lu4jDs$)ffS2gq~hZy7W9-L5}2LfpqpR=|o7m(Nby~ktek1$ZnA|_}cnO z{+3va$_g{7MbQb@e?<GYmy~nBbZdp9B-<LDJh<LQl5sMcNDQo{F6yA32<e|`EXH7J z#5T@4zIOQ6dm39=se{j?wie8%qza1*WZ;pCTrZ_{+V0<EhO5Xy`Xxv7SomglvXM%n zG$Btqe%gY!KCoG-{$5;BrcZA)${2^O&SHC3e$ISj9AR!z6Ogf!Pe5_5nl2=taocGv zcF-7QMnewe*~;w<HsuVu<di24#bkU|ahWyRTl4HiaTWP<@{8@+`L;MmNiI!vPJX-* z<(bivM-0eCxiO6JKG`W%S*8UpszE{iZ4`;qK?mV2g#1#cb+#kZ8l7L1RZx~KDbYtg zW6<N1n3_IBvPQCj2$OCCDl66tq@=8fIYo}%d&c@s<n)p(wawAX&GmP=W9?>5)WayE zF&32-6vWaOQfsI}p8Svl>!s_BMZf-k8=!O<b&8`!-GViyofY}cwX>?4tMD|xfF{>Z z9+`wT8<bKkT?7U5XH&}YGDFbwikc!B7bo)sPxI7gUQuf|&2HnWnO+UFj%Oz3EmAs@ zyt2$V$}WD6!+9GCw`IoH=6_i6{L(yf#50t8#(-fAv+;wAY%)`_b&of;iL=kMONZ&% zgI9Ei(xd5J=-NMKcWSCnT|8UUvrDL|{U`phF4^xd#@GLg;k7myR5pDUP^YQZ4zsS> zan{H}X#vhW=GPL%Ued|=gjM@t&1BcutB}#Q&W?5W<72%l83Ft5>!Q>c{YyMeJTa*^ zdzLy%^&<BcuT{1%rbV7=RTG3YS|2k!Z|n7zVZ&KWmuAhJ?^Azk_K21DnKkB;PG`QW z+)f{tZD($6)29TI3{O+bmulw|zfPTe!t2nV5g^*ze@Nfxl(E0g4$_Ml;l&u)<eXo~ z83I#S84t+c3F!qBhm&9#FpM|#J~@jyo3Uw0e%3(W-g4xqq0-l|J@4k_XUPjAAU&J{ zN3QhRan{=Hd@H{ye#(E6OK<DaJd6p5x6RaKkhRb=<@fdnVct!Mv7Ap4Vb8e`sbd0f zbj0~YTC%~rv6KGJJJR?L8#j?AHl@$AW){l{k+<_2nV)4HY9vnP05W8FW&osBz4)EE zm1~|p8qv0-SCD+MP8c~nB~hR6$+IM51eWk6OP%wnm39WQ+PC!x%V&~v%+j)@Hq@SP zdiq;qzF*=f)KipXbubV!+%~ESCyvp|?o^J0ei2ReLwUzrV?wM3Jsr>@oamQU*zLy5 zu(ZOV8ZR(6bw%gL+2dlZ#rgB>1)R*~<S;E@N@~rql~{A+kR^1VJmeI}{6kNvlWZDp z%gX!n)Xvi*;5|z%B4q_-g-%XWWe@#Dk(7gxQzb5YvCJN%+m!P!IiIxUN*7C>u~o{D z@rki|e*VesNmQo))80vvHDw%L!mb?zj7V{Wp57=?{`Cuwk=e*Uy;O|I721oO6t+s+ zW{z-CuyNL8M@7BBOJv?&lSCPP^vb|^$V^l31&B%<Tj_(bagOeDQqIXZ^~GAwNu%Cr zGgEhD<#P(I&!CDO6*OZ)FU@mNrSfx&@^ffp6j_}07WxXA=^KIPlWKYu{T)J-_!pPu zJDswvl@oSOvx-<i(3b~lr(AR)6jVMF5aPgaE=vRY3?V<OjPqFOoyzn%r+$38ltNGa zmrjffAxBbjth5&9&!Z^mOu8VM8hU#Y!ZW6O+4-KllnC^Qwf10PVs4qV1!E!@qsQ1- z2=P`5Yjhze!`?cQTo5DsdaGIwvaF!YPO2r#CApmBFlc!yl$B`_bN!N<H}tcHL}Mq~ zeUU0Y=+}G-rBp^mt*t70pmH3>SUFuQwb}~FIQ;<L_97<`)bb+dU)M;dUS)11hh!RQ z_pZ}OZ#iP{*zwZs)^wMn^d%fUKAhBh79bp%vJfCsEq!39?IZ?DpJjBQM$Qo#>67!F zOc#hZO@slqkUeF=OqK(DhEQ+!Nd5Dfu+&bunJVfFXfo5&;~8VbzGj(0KdFo4z=?5s zvh;BNCo5X@!ZFs12q&pdI6bag8oPd3$OuWF(oi|b(EmTI#*EZ!VNEu%8e_CdqSw97 zm}S&2&xBI1Rkd|bdJ<JQ#jj1g&%k7aQ)fc$Q(cXUC_A-vao!%Mk9#sw$~eiynVuu7 z+|yF5G9jmqcoqu^^7T2tcjbZFBaLY2t=4$!xZ#77t;L+#N<HwbvdDR{oTlV5dX-!C zl{1zO%ZlYJl`+gwO#k%fVMKd}bb5K|m<Y*Jb89;VVyrJu>N6pk`BRfUO)<w>VJp!m z)-2yTjU}bxV!N$`X^Krwz&J%u9h^Q`%?a>pH8dm1I>4G3Usx6ymQ@~ClIMu4X-Ph9 zFUw)ip&!lH7jJSn5}mKU91xvV9;0TBHAi$Y#`Pq+7pJv?lW%#XOJQl#*wQn+8pEn* z<Lg_mPiyr#tudDW;*1FT3=8CTfx~9>W-<#f7F0Z&5&ged)yq;tzc;tDQ{qwq^_p0J z%|tIqM@3Oh@LA=Iv{~hK(?@n0Dd9<yHM)X1UY;>Mlw~fN+!>kU`m6NTndj5<%QVWn zN+V;ZzVzbEXZf7|iO=g75v8toJ7Gpn$5BuIto+n0fB$CGch+=#hotNJ&cDrl>A#F# zEa@+bK(D3Jh3lP-@Ags_)Bk*l)rinc_Dz&uNi#D!1u83!OCLso)+}tvnDuvMB<t@H z%sBs#Y5ZU3xL$?pW^7Ha%TU8b4at1zSQ|x-8$4N}Y$vA~O4n}tp2Z9nha!_x<ZU@e zXA7C+c$Q4#q)=}iJXWUnHfvc?{@gO^V@YOysjO5QEjqSln&s(<$Orw9aRvE>oH*5< z3g}lY^!brK!KDF~*qeH1thAMyixuaO`Q6}>-b-(tR4wl;K%bb&2U2)kz>q4eKQ}6{ zyz4V-k7mh9KJ{(qPTzU7r*#;+)gD7{*)C2OvI-osY{8tWPLhoC406htmloRQ<rfkU z-`>RN>wKr|zEde9wo;pFdro8COy4A{B^-OLdrfoo`7ys{f143?QsAxMEVKS!B-}UM zBrVz{y@)JDF;5vbd??*a+Qh->6A~F!hDqfaH!9i42mO?lLe;Af^OV{ZYtJ;06*gIy zHD1YNu~dJ}+$NtfgrGRHzdk2jGA;BiwK}uXzsbs2s*jvamgdW8xiJK%c+O<>88`!+ zcYf<rc6Dk9L3Cq)__Hb~J%Zjh*OnuF%i5>cv~&4{X3X_HRnS??LXYQEsZPmx>z+(x zjT*~kCfPNa2-}Ldtn?=lB~Q2tsBd1ke!6_xoVPm3$;)*WSzmInl{@mYSv8_P%PECE z{nVEqtwk&il5$z!(Lb)R+vfPza%W6f-2+P}lMt8WqA#g!^?F;c$YZ8buRDs=JC;Z( z`1+sFAF=ew@|v_>-w$hp<?>cmNxr_K$2DJ;5a@HtnBEfwSE9WqQK&i7snY>iZP~L~ zlHlxxuE{v(;rv+wpojC!NUXAeE9*M7!4^0i#ZK$MusL?S?;45zQX(m97&1$jGd-8l zs;Lcn{m9JErTpZgw9`9TW1W4D)B}4_d47qbNRJGSK~FB%pnS$TJtj<_*qCnJ$&`(O z)~F*~ETh+<sn7I;Zj4EBRu?T*A9m&JuQpmfv63mCH>ldPAY*@h(qY7$gcZ>O3LSD( z=~HZa4bcll&wQ?4%j%?O{lt59-Zj4FyjG?QxqMu=QL%iXS2Io*Yfmj%fzg-cjA4VB zuYO@9iGtMM_DmmryHp9r)8`p0AgsnolW<v$nU1j^*(TGL+H>vFfz}bSG?FL{;>J-$ zIo4?UVJ;%egwQi3Hg>I@;3i4#*9#_=5RBc5NDh}da&q(nE^*0>(uglj#9mTD4VRWd zQuH;M1UWFP<g5bA^;WV+ntBeGshCJQocYpW$(okFv_obyXLnF{<P6p`)uNZJ=@H~J zdS`CXxXBY8*G-*bIhqkSeT_;lF`q*5-C3Uya$YH6dwVPWpp1TH*^~*(3~|O9D2YhA zNm4<A>IW&&(EHeVaV~uy$uZf;c;V@A^@Mm%E9P}$;562DI2XxuMoUeMo)@R@5W{JU z&!J<ixq7BZfW{dP1$rBcCX@6Ft@;b*A;#$jm$LQ##%F&Tg7KL%jH`Xcaa_uki_jz} zQ7@LiOwc^8)Ob$A;;p{B*2c$~m!CuZB3MuMQUCN<5j(xx^EqIDE8{2CMe13Bt=PAZ zVo5;820agb57ghvr2eLaP7-*%-4bQ7G28BGH$^NH*tjrcQ&p|~wYH?qxNK3oGBGT_ zTnd>?T-#w)Q<pw)#Y+=PwCb5Ji-)E8bSiqQniu0;?lM|~C(oo>v5-@mBt_(Xkr?CC zXX$5q^=hBI^wus<ME$vhrN@Jc;#nqS4aFK=+s8A@EOO>Jq?jZrF>IJ13$@;k=9Us$ zG3PYW3o`%aUY6nlZo#P8U%zEY@3-XK*BM5c=a<tz#}#Mic*CSNyDIcs2K3C5nk}Dt z!;)}~1s?e%z2<#mC5!9$#d$Pwhv&jlT&aDYal3|0r;T9s3$>DV@5Lv58#(~vG94p_ zOZr&31;glcjX=XH^0T==MJkd+wU>lvRCWCWeZ`v)ST~Ld%d_X_=9T{0w#FxQHl_vE zt||~}eo+(8NjeGiwjed*M{|o&K5uxMd+j2;G~}=XR<vpYONi?weS^25$*^80xD=l^ zt_w~=a*_~RX`!uH&&HZ?<r>ak20HQY0`&xEby7p9^^{GR{Hh5#Q3jX444O$?O#-fq zuk>7ch<eQ{;8rfm$v6Uc71-;hphw)_W{m6a4pb_^86lU*jS707<!RTRHwqoJX{nx+ ziN4As^Aw+^6G^K|k_tK8IPLSimNqQ+r<Lmy?Aj9#*;>XLdMM_-GW|3zG?%jC>y*AE zDSDpu#>5!kZEn=Z(rh~|Q9r}I&0gZrZ#$4<B_>2#qic?)FY>aLah4+=rzF${b^Xy2 z6aI&XtGTnsSi;d4shGRSinGjuSSxqxxm3G+8fP6#e?vh!idZJK6?2`>Gu`zxf8)GH zF6J?0RpiMPK!!-YAzLGh9Fg8h0rN=4ZT9snu~az9BDv<N_j$7JLmwp90cC<M^J`Dm zst!;28yBn_Uw38Nd()(TJ$vn@X31;sZJ+aOlC`1#v&m6E-rLx72avVDXX!X>ZTKq@ zYj?lU^4ayf&xHQ@$ItG5Aw4Lp&YsVPy;3>Q{hFWo#jc@@J<gbz1z|EAsF?}ot_>4e zt8sSptkyZz>Ns;}72eA{qp@sK=QDS5oH^JpK!Q+{63qRKXEi%Cm*Jw$4lz_ml@e!; zai=Dl|Hy7wCsxDNz7)R<ch!StO{@2bd-Z$fAoKnW=9B(^^2x7ewecbIF!!l5=I{LK zeXiK^2lf7k=B;Yg6thL$`EPTCs=8vfxUX$9f7htq*6zj!%pW(Y_hwDBs?2KTSLQ(X z=r_%Ae-;lthGx%3JKr(CQa>`1jQIL#(_`o+hTn$QJFvv&2|xFJm&`8>s{fImArEda zC%CsH`n_qX|1mk4Vs?Lev){vE^*{3N+0uPvq~BYAwr5t*pX}4s?6ytuv)7NkBq_k` z{&uF{{#Gt-#GYY_F@>4(O*y7$Q<lkLDl-+CN=;T%e}1ey%QKaj>?WHj+Z4wqnQXm) z?R~fGXX?h53B0?=qm(@gO~r&3XDT3UryioQorLdw&lSxF*KaBjiXuomn`Y~gC?Sw6 z(;WS|gWq!a5<OyBgiv6b&wJVWfr^Q0DWB)*+vX95m3In#66PSOR#Sz9;L?LEW}_0` z$|A;P9C|1Lmeq-~1X_Xue(dPOPa&`8@Tzue2}KfAKgVJTTk^G(1Lx}@NbXuWn#-mi z#!lu%^HO4-N0u2I%WjdTcu!hq>YsZfF_T~%rd+lyHO)gL#S+8zQGar%Qnr+XNgf(S zD|si$wS};&WL%l4#Qn!l{=b?V4=v!Fo9>i5wj7+`IZM}me4<N;%+w0vIQJ;tzu50` z6QkF-yvnba{><HFwcl^e>({^$+x%u-SNC4u<u~Wg>US%%dfMN=x%=*eehaVLsnb!v z!un0zO?!zqt3zM-9aD=>`*l-$lKk4Mg{S=z)a5t*8Ys8ty+9TJmR}1uAB?>&T!I*5 zR_ovJYw1ot>(}PGHl!cI%^}YHS(_VUb_ZSZiwUluZoRd-r~l%2;<^C!j}#w8sT05W zb#kxw_rLeLSQ*W8REU2>{i7-}VyOGIaQ|&R^?YBO_RTEy#x4HMjq>>T7XMh|S)zpj z;D@mRE!3Qm{*6?daRE)#;gSB`-H(m*AJL&+gw=P80^U(oc>#^w7iRl!uOA;}TN`kX z`>e~qo!LF5#6O{aq}=Qt<EN5u_y0wmpC1t9KE1$yM*Y6FCXm#?KRNnob#;k<n7i`+ zfKg^Q0R@@eA1?5J&g_0<bwILNonP!fzW!cB>LvHVO8<nodY`x(zUUuXKaPqwE8Qnw z@xP<H>rb1QgMQ6vnh9yc#XR$E@&At+o8H#6n#Q)!y!Oh82xa}yKhxdwSN|W=YRh!R z*no(dGPO2#IGGA_-MDsymjZTE!0jUICBJTAjy9{u?g_Z&&L{~e_|qa$l<Qu#WOG1( zI)7Kd94X*b&pwppf9mfeWxe{k%#{jK8<3lTp1N)ucC0Psz4hyun;@2StCy6&E=fg6 zj(0cvXTYk4?z5)@{^6%~pAG1)E?4_^R_8wm7^I$!F*i}?&j$2V&4SF$*2XpqcCR`Y zFxD)Y-GqCxxC6{l#Cnn=I!4X4m~U2B&Ifc=X`=%ZL;0#)6Fh>)RP#>)dd0jPVlrK< zKD>S1_I1_rv#>flrMvfgNBU#0=6MSnoi?c%Uj`&vq9gJiUi6&0T&{Idn?4D+Pfh$Z zV28Q!gP#SYwu%TdnOdMF`eOhFVq=)H9SxnKR+R>KQ5#PLPV@ZwETEM-d@?Xno&P+* zssg?U=xlj<P5IOTk$eZOrF+;H0prc;)RzJAs`AT#-hQT_{TBiP{8F0}qVJKq^13%} zMnA}r<*0)(44)o<=HbP5e#Z6bQYT%eP7!&%2PLSz-*WUF-*TM!KLvELBu3<Ykh)4; z_S0h3W7h(L{k^Xm#5I>sOc8m_lGNKzS=y_rZd$P4ujMN3)4)!lWYe$Z&G@vyc1|7b z8rDIrOtUnoeVY$!-yUlUmAFj+Ur{tYj*WN%C-Eje!ne4JYiPoE##$g7U!DHym7Obh zI;T2!-qPb0`R-Ob3#kdUPS#VS@w`tPwfdWY4u72-iJ6fcPXaqM2q?}gPS|L2jtmY^ z#Xkiks3qT80@axat(9_p8xZ9GP22<{w<doZ5bH8Elqhe4H`;ITT%s;f{tXiCmPEG_ zE3pbM;}yJ$@9_hE#7~f~#l<!<nYtkk8JLM#D8sY3;w?k<=!w9YKGmtXuVuW7zZTeB zoo}jXt~QcS3$Pe>LLwm%cmjK|56?p)B#}9d&+s|^3yGXWOd{2u1K$XVoJ4F8lJV8) zBVRqW!pV>4_q2h|fjl*t{tvl(-**8Ce_b?2=99_s%JywQlzQfyfY|Y-mU6@t%z$K# zH(TcMyb^1$7JIN4`{Bl6yn;_peER%`=kI#HaAM)}{iFMvqSey*mgZ{XWk%BWOG7Mb z&kq4z)Yws4n2P_-5~V)79574$^LzT9JuS4qX&BQ?jU@OJcmvh=3P0l-g84RZBZQ+d znxZ*cBL-b@BL;z<XzStChv|h5XQ%Mfi>{!#D*8U)e)Yi*0iD%P-v`{Ksy0{xlyzx{ zCK2wcTzrt#Sn7s1bP4S!{*ABk2h5H68YUjXdOVD`a0*pu(}eFOqaB7|D25>ixyWmx zI;_`vs*UGD2dllm1+`MEb~M<o4##L=YiIcd={3*)!Nr@@-2alDRKZs2{C@+qF)bxo zM<5ZB$o!6m955Ws&>Zt2kz0l}kVr}dFH{}acwm`xS(P(mRH9S5MOF1nK)iePj{!yI z?1r+*F1&z)coUK)NzW&^jK50P*g9z=3cRL*ocQz^Y*<#XY{Ie$8z#utft%NMe2aRj z4)MX!{=L(FQB}(<U8R;E?stq%@2PRiq<4#z0YaWv?O=eAYNKZT@^@9em#L{7`3~HP zjo5^<_z1tDLsJ?a(r~f*;O6DdX(Qs)+!LX#)soVnMh(($%OV2uyQivps6i*qcv^g{ zL8k_@MpyG$&;I@ROx_5tc|&a^hCVNsv<i+6y7??yFY1|TeArQc$#4B-kkMI^1xpiy zqy3srR7=gq7@&;_$s?W;@8^l*<9rKvd~@0X-o<-p#<!lEBLbhdFq!)D-SK|tk4cz} zDcIIZYS~a#e8|#8UEX2op$4oDZl$b_z%XTX2gNAINUgC^*V00tSGKQ0TKY{Ht=BpK z=Dof%p4@fYZ^jdEb@V3#^mkH78zYJ2<a4-!@6m)9_ref7h8_4GKO&0Qk3c#kRZ;?# z<(1X5sz>)4t&Zk}bdr%rGD*hK&>NfQ)n@Va?<|SeqW&KhSk)3s7tL?3#VGX-y&6jF zW}*VVd4G=A-$EnrgFR(%;hjTUR+LU37CT)A&q%4^Mzrtlqn4huw14oIfZ!nCcRGdE zY$Ex*>T-a$@<?s>c`2XD?8vkChrQLlUo4$!^F_*}ZobGn<V$NAW3}4D$lC-I<qDBX z(+-j7j4s%UJ=lvwh@w*6f)#iahwvGsvi*!-p*Nm#+w$^J^0T=*(L0oyYSMOU>LaF` zf|d>)-NckK+TWCh2P?D|!IAbSXc=dk%vXC0sF|+gfnB7f%NsuJ$otZh_SdJVr5!># z)n;xhKXvr22GO-2uWl0(tyXRc?(AwT5xfdhOZsYPu%Hpb(FSeN12-WVDVU2gEXD)a z0N>U%f>w2*s`lr=#^oEG%Qqg#7*UgYo~XqqLL1gbG%ZxwEP>H}q`*cLgKK*NNxpwg zmtfS8>(c4n&G?u+^{o*`4eOX1Au+qv)9z>USOf=3P|V+t*otj<3fu7vWPDsbKRadq z#XgY||C)mPwNP!Uv_$*24PuC(XY)@VRHT=c{*F%>Nw*=1@OxsMTD^rn&xmAN=mWL} zouo`91fL4*&5G~SREK@R(lE5Cp}x_2i)fuf6?XFn4W7mxoWc9}0KefHen*qGOaagg zi|{p`ZO4=Wos=y=Ypa;bC9A6Gp{-O^OS-^>J%L?R%7@Yq&TkN=j=aFw8hb6UrOJ4~ z(#rqC-cQx(_7W%kT4<)HmF#-c6R!_=Jd2O<87!^Y0I67lQ+N;O@DT<O&vDSFBbD=Q z{EY3P9GO8aq<u>G5qS?JEjKb)p6D5Dyw7i=k^HbRxT|M?k@sX1e==JwRKZ=<=?%d# zq1P3kpHYk*=Y-4AZ^cw(VHYHKC1;P|RY(p??tYCckX)7=wveNNxKMqe`ry|4=H545 z+!9|~;YkETIEknks&D><sb9}u0y@e`jYX!W-Vt5Kc%FMUmNDKOtrn@^Sf8}%t)eC$ zc;d+)(j3(<T;kFg-jeUg^Jv82Moh#)NNv~!<8*XkZpy-5@>e~&TZryQUH_{#K5FSI zZS+`1IN=}5P)p~8M*H#j-Pbjpiuc{m2dJg}gQC^;M;Ilj)t-J>b~jRPywP4Qu>^*g z^-fx^+pY!@1F4f;sgF`GU&C=+fYj07@dv`%lPYvXC-g>N48~YYM-CnW-OmB$Ey&>a z@=?n(dW<4c59ZA=^{m_5sv`xK7K*B)_pfiohZ<FjCnQ-0cD<$<FXdCcDPL=$zKaZv zRw-ec#qX}$RNASaXn)@v<GGPz<W$GhW)h`W@d<u_*-CQI5M6K!Mq(63BOT*00~xqj z&CkKDmE~KRmX1nPwkv@VK}NQEx(PL?FQ>+}eMYcKdBtM!zi;dsy>AH~cf+GZNM7pc zF<$c9NYA(%)V?u+?bV>WwBTULq=>v73vSmp4N9N<886c(t2BFHCn;IuX~&dCQV5a) z-<V5mXJQswbzoABNAM_K#cMc*VVzB;;b_bf!4y2vMdo3t>hcwt!G?vjQXBVhS~TlM z=KV~|2CKr6S{q{?_QJ64djG?UjD<P>PP(M;)8^E6Nogvu<>;|%==3Bq#VEl#T)+(+ zTq4#9F(}1)_(oLkg{oIC<b3F2FPX2z29*r>gIpkg_dU;a{3CxB+EPNh1an~CmY1mk zbn)Sf)X~!+<YQrj5cRL!mQG>P;}{!B9Q9@^PxL}C1_JN<p2F*x7AASM1yAA?_~x6| zi8Ceg&6|Hyc&?983v<(RjUmb;|2XUqy}lxDl3V)d(r|89UN)So-hL;j(}T~m&QSeM zP?QwtlX+@sgOF%H9`_w(rtPWFzO`E~__!FgueqjA%&zauI%hSIxa>qY<tgRb3B7PL z`eHH);lfhfflYV@zu|XGjW(I4Asf<&Hy*gK%=lGuVEO?yHz}}%Djumdl3~F};1hYF zYRO%eF2S|w^-lL{-_fVRH7`BqCPBs<b7R%g=3&u3`%8X#Ue1lZ!ziqpo#kazO4BEZ ztVHxzwC&1hi*~V`8e(5JM!6)WRNa|i;O-tK(>+**<M=0D$D=oq;GWdOUTXEbtk+d# zG6L`Yp2|OKC{=rJXlNH@%@2%IvxWzT`zLi-WK?qMqOvs&Z0ToNT-y-*GXgppAD1r( z(Vq-%HPuNYketj#9%kc7`~r!1a13XANJbiRV4QDcj7S_oKQoeL2x^Grv0h~*$cQ|C z>o4^h;xDiC9Ahg!lx_7+lIoO3b@Jr0=ana0YXUT~ReyQJ5^c^<wm3`2yap1H1z3&m z(S+QUT)xSZ(~WMVnxQ!&&<d>)i6{&~TS`JoBpNq?(fQzo&C55Jdw!O0&M;1DQ@2{e zf}4d8@T5%AqFxH6XTM{fvK0olQA@sLK|3`uEI_s2Zqdy88A~U1WQ!%(uY7?zx~xI8 zu{|%o`;7^<zH^I3Ds8zj!}F$A|3J?#sY7|qBvyUU4|8!J9>zZ)_2?zMiq~)gZ{cmc zgEM#^|HfH-hR?wYM%Biu1Ivo}nLJegQFEJEnzLpSB8}ac4SQnmwi)A?9^vRrbu`Ih z#J;9bjVS*(@k67)WkYWQj7;)B)OT_1XMUAoYTq4!9kZHAT>NPV7PLegv_}-Ou>^Z@ z4CnAOg5uZ??a&#L7JfD^E3TSWHMEK{rPWi<eXF1zqxlY-QRg1*tyb>}j8R8IHLY$M z{C@1L_T3ZgN%-?ERN8-oJ!!3zf_kaj6SQ3_ca$q!A~Xmo$Uq^AuntdP3tmGNKElWN z3g04vsbC94Vmu~cI<im#7gk^c4&p~#Jbn1|MY&9{ke|b$+YfI)oXbx-KWgr0!L6iS zuIh8UF{VU}J!&*iBX{m@z1etw!>EJC6M08(!L`|^4@Qk!ovF#WecJ;&x?0Pze+Ji( zO#$eJINXfUn1Vu-U=<GFCA^B0_!qv!_s}@wZHhLC!T_v=!g@S`WB4bk@J^ytZ>P+o zFC5%@uzIUJ;b-f?t&GMCw=T@ys^(fPt@R;56^{)H2-Issb$^xCI9MN~e4b8ARY!jf z(%&`eMRahz)Jy*P<cjBI)QI-)5SjA`q8D$01Pp)+(z8E+hY&#TF1>s>nn4O}>*>Rl z<r(En)6znMt-;33K{`oUKvB#02X|0|p4UPG!yMG(+%R?YN^o>=uKtSX8Er|QSY`yM zv`v=iAS2R7!s;i%&y!xM4g2TKkiDbQ!z3y#&<evb2IDXdIVge*Obf9Xe;}LzX%td$ z7Z?YsHy^A#xOu*fQ?ay&;8sETt=kgi{MKseB_msnr=AY4?)&rt(S95Is}A>D^aY7Y zZPVEIEtj$lVwsS3Y`ih4ty=0N{l+WFCB0g%Z#zzJcB8{3D!$|ADqgR~8XSX+r!tnF zLpkH=1um_v=2RxP7qe68FWOhk<G>{Y$ma&e4A+?0@J@$M>ACf+o@-G@TXAmVd90l` zUq8{&2Sjgi`jKc-s?UiEJND&3@`)6}hz1gyhasc<HpoanM<4C!^?R92AL3VBMMQ6A zrZC@Z48RAMA6#C(+%~F*48i&&?ID%}t}>eTHJ5M{UM=O7ACLP6vkJkxMnyJ0mZ^eX zuZ_feUm9sm>Z0bp6BHd(H)A%=4GQsVwoQ-wn6Ma6y!?odKLQYkcqE`7*5OMu>BIFu zJc8fg=*x)?#`R;3y`NhB8P`qszRaXXUt74=Fszkol*_V0$}h}z-n<gPUu8%S=2tTB z%@`fn$#YGK$-RG-<so(S2TObZ;DM)%$xY1@nFPtoe>#aH4w7-ckqzZ_7`j0sE|E?` zUr6LrVN{juu|1=Dj-{^fkA+n^fOr15-`SkJ_Pi707d%iU{?Wi^I-sv77&XNE*{W+y z6<oJlf@-$b-`R6HASn1x>XMAe-d$^E85R@oQnE4{2S1dSOdLEV7?m0-5tp2Q3SZy{ z{D_~>nB14r=zvH>VF09b#$p`g3diz|7g&;WPIHb(<Z?q(iA0q}?R%Tn@I$zkpy#$! zAC=OWS<rRy3zYaB9dyPxuP|2WuiHpJ^SQgv2~P$}a6#Ue^|Ddl)Emqxy#{7ClDMwH z!;qTwIJRIHcH;`JLTX%NYFiUD#dH)wYT-OAh6@ZM45ls~T(jl(#C3yITB{(d|N59S zDm9f0<#WT0$?oU2-}E>9eDb7=N^cO<RXW*h``h}b8g<ii9?{?xOJkC0yuk&L4ilQn z5#Pky_!!b2zQYgr8NXl%?c)}V#8^msnS^PW4yxw`V!ST5nxFLkGU)3oE3cVV+BhzR z$Qi$KHP^b<KYl0w8B@~hCc*WkrK|RK&ez7;eW&XqFRe(wn$y7*E(f2F+prWXumM}J z6VKvpTt!HKvL7vB#Q@}EHclXV0H-&&P{s1a{L1;+sGOgIK9xqBGk%k^@l$V;#Tm8# z49kuBmHunJRN5tmk<kHa-&rl%pOp!tTRUe?CBx;Vj25cXde$qKgit{A_fNODs;VNi z2$hf$+9H@&Y`J0X9yvje%4jBOlK6DRjY!9MOu!aAiLJPZZ}2UCNBBUR6=KmJV=)c6 zD8*8&Q)xX}OsyKiX<Jnf;>88a+tsYc>D*@B!}X+ue3}&3FGG!WjI!*m(t{=H>lia- z)y34pH){Pj>_|uyC3-n1MH%KpqAO87fMYn0uOU&tQ1#p+&)q#cjh}w{Zy870tEsnJ zy8h)=@OXb&fn>7V@$Xk7)y6=rdyvFeGFI*TJh)?OV{d-_!NDc324Ey4pT=PleDkY} z*NdR%8;{fvel}NbuDUH}VorZGxY81*s)MyyKa*808lzeLOr6!+!CGf|T>c$brjJ^* zY3jD%z^<z5lqFc5EF#0J0=4*C8m%L|9XNp3@h&dlDjE->Yea7hLn>yW6w9z4o3WSP zVRvYZD%>3!X8a17$@o<BYx+Tx&%Yf$&rNk+toQxofBHiGp3&fjwKM!0s+E^4ZT)|q zU1*Ggvd*LrhmDJl8BbW5HJ&`)@&^6Mh`@vrQt6uolJs_iYLk64&j(>R#zL|{k}V^{ zvSR&=@kWLPZjuhu;?)>dvE<^M`;H)Ota)mvH-omY$1d!}yLb;5@GY*vJeUC)VQ2y? zIw1i)pwE=Ku327b8^uo#8~00DnySqG!JXCEFfG_UCsfNe_iZfUzY00VH=b}CvwufV zIQ@A{!!*pn0<6WB!D@8~ONO(g04cUswMCioKP<aC1zG1soq}AUubCTd`dU!1Q6B#u zyv2B8PPof>!t~I1l4kkTc;YRyR9Sm4HI!VD)C|BlOh+yXPyuhs*71BJHe(B(hvcUG zZ0B0lSbfQ|qbhBvMaZ>8Ro$37tDbDkvsph|nyIRjmSFd`hFXAmd_&oPKVHLo_ym_> z8N&GtqLGAt7=W2b9ZH{sLTp2WVRVZlm}VhigxYj~DN=&n5~dtX>mEEx&hMQ})4AL- zBuxF5&E+M1y2rCt@~nrv7p7ug32CWzHPw3fzrOfuePXAMon??aXbuckZ~S0sHi4`q zPLf!OutfGW&f!yhgYWPQ{D`C^AQ0hbj*gJTB!Dv;PACtq-g;2YcsJNsPgDyTNM$1A zH%09m7-ZaPrWQ2}qEnIl+7wQHjSZLG6Cruh7ryzD#p^q<4Ikh#EaXpX^u)!}7msdV zyErFpalg*}a!hJs3vH^}-a+eHb1zU={RWN)ms?_0Rd8UuI%o~LQID8PZ?46-8cHa= zkOC=%iO9rkY{fJ9H_ju7QfY()jK@A4$0huLp2L}aU>P36Q+OJm;(PprCY0#K>KC`I zyts{@=G!h-Wb!zA+i1`43KOUDM~f^y{2#V#)UV0cB&CZA=YBRlDaB!7!D@S8U{iHu zB`v)54O%z#*!KZ}%GFGZ%xohEX^I;m)o3_Ukcu=c!6xiL)GZ_kCAbr7uof@iAPzx~ z@V1r44>#;hRklM7qGV<eU|p@>MDv#;V5|&n32Nhmj3+yrX;JELqdv1~0#TAEF2!M- zLlIFZ##~4=z0rD+=NIr5zJ_Zg%O|7AYgCP9LWOtGVhoch+%QHReVPj*T$&xMj(oyp zklIVLJnN#m{i8u+ePLKV(VC(C^C+#k+yK?SR}0AnIov6n#X0yMx)FztKs#JKwf|vP zZhD_iedzL=sh6|0UaEatZBf%6&GQ27?=i$54Zc<GP#DrxQ%fsDS~d6HuxR2krGL21 z*h0U1Q}UIqeeUG+yoy&JTnp$Rb2`lxB1i3nzUYT!q+%j&#bnIHVr;>)ID}((2frec zOp8Mgtn_4{WZox`Yh{P4FCM;lxO%(%aG&i$=Fe1B`KRW8#sKqJCUr1n22Ib^o&x`% zz1CSh{+UHnd)sR<>ZNo(NNLX|hudf|sVyYb|DYko5&<cq8!!#Uh~Vro3SH0}127Qd zFbOn#S(8}3J$vl-?A3bj++JO=YWGX)zf~>hpxr1p0S2p0nH+dqJ1uouBMH9`&UwNw zC7kUTGmg#|Td)-$LrbR9!P79M(ElL-8Z5XKlQ0>FQ`Ek7K|_rj>h!znHbyhu)}P6* z2c7hI?e_#RW&JRa>k!{^5l+AKfBq8v^{yzbqxxEE+Q}%b)!+z8oei1Df)f(cr*Hxv zA(t4=#R4n>r!`xvE6Z)=V|#HU?`W=WM0V1as!P)~i~67g1<|^LmaQJKGFM(Go#V?^ zEq-*U>?vvPOd9**6}*Wvcps8(e@J>G&;k=7X_s`%{BrB+s`*taxua%fF<f&Ob<}P$ z*FA1SwY!rR*|(AG;lL8y1BHV)j92g~j=_>jM~mJVj$2aQeL8E$%(G=f*+@1B$IYG% zj`BDqjiSQ~IEpLy8D{Ee6SPGI?!ZyJji~V~)?pR4;C;L}fh?GymM#lUl{>wAsLQPy zcz#t43eA%<jUl6N;egX|1h3#-bmw4`F%1QH65a?M;raLY2@)xP4&E4T(%qxGYWvNu zHoRz$R7{5hWhlq(xC;;C2)waB$Mete6)vMSv5!OodZ90dAO*KUQYxv`FMC%X<YDtg zmc!)7?TXcwnqBhgb2tdei-zPyG;Ty+j6yNWu?Y9$3A}(qF!GM|E1v%c;S;Gccor|f zaw{`e<f8)1umX=__pPRZrlUOh35_Q)DM1bjum~=!!!A6HJ$MO6a1<|3avzS<hM3de z<jC*B#1RK#JOO6Gj$Fvm<*0HnZy*xDEBF~-OlIu|KO=k!)o+SAI-Qf2S>5Ck;!2vX zei8l174G}DKF)iWd(zfFYQ?$esy;!<>hL(Nfm&&&->d3t30LzHwPmiCJ>ggLcpjhO zC&=;QIL=6n!35Z_0h_TG&tX4K;!}JM-#Fev94CUtxVdV1SykC)9{F#xJgu5R$8K`F zlB9fPs~pV6B2;1x9>Am6glDiHCs2iIbeYPjJ^ErGhF}f~a3}7@J$MKY;}LAYcF1~* zbWIlySGrw2h((&jS7IPXme6HSh4t|6Id(evfG1InPw_eYX0Td{^b7`znZyLiDy@hG zf+Od&9=^9X9Fn#>i}K)FZy2Y24OILqAq?g*4C|_wmhY0-?Z8<yoW>*0;b;7gP>vUd zG4RIcE}q|wd$0^oU<;1mC|<@ZIDwOR18<@V@8A<$!Ozo8O-<n>q$6TIiMnrwdrfbx z$UNdc-gpVua3d*=MH(d41t`MXkQ}h0r#B~foQIWIGt)hykM@E&eGM<ZN5Cu^AljfU z+MzqfU>uS$0~wf!S;$2xZo_?8frn?g)B9;pn=@nw*;qD|557bn8#N@8J_l*oi->Fn z7(~N{6gvli4fo>&e$JuG&t>5Yp=g*}bDMgZ+PG2ECu?2Qkx03FMV5YQ=V`kJY7>$l z=Gb4rpW}B!9BzihX9S9I5AK6ToEo7c`e6Vh&dHE?r)Ij72WiikU8%f~M3i6wp1@8> zq7LB;T*Dvem&I6xToj`M58yaX;wqYw_~wud=>o}+B=m!1Od%AW#@=ii?GS0SJTvtm zi^d`ul6|uv*|!N#;s}mGvhp<e3ahCFZa^IRVicyJ2oK;@{1a#K1Ac-OLxY+kp!>@; z`J1e{?%RiHi_IAg`J@qe*E9%&F$9z0z+x=NLwFMV@DCisA-st9@gw~6C<s^(h)sFQ z*4HvaC9G$LQk4`mSXDhusc)1oS8cqPo5g31<{MV}_hOFSqV*YVC5#S8L~lrZBreIA z1aF+=_;TDc@I7{b=eRfIxkry=1WvwzH#(s+rXdS?n2iNkgk`u7k6{zG;T^n($b2G$ z5tx_nP99ASn(f`Fnhnk(iVx#4AEyvKn+sStgbs7Kp#uF-h}%#Jg-zIn4FyaE3b|B= zu|<@vgX)WW9ma$up%bSyRsZ6v9r`aOp|lwprx=rlxaN6|ynsiAw;-{28z0~teus(J zbb-XKEBayzB&O4mi={XSiTPo?gDdz2l8U}?paS!-aE_^wX*o|;K$5g^j=M5hD>1t^ z@<P(L6HntPPU8byL?CGnK@@I80=lCw`Xd=>n2FgaL>cbI3OowQx5x1ej^k}q<5GdC zujvX;8jzt)(Gsl@g-+;+n{f-$F%dH`7o~;n7gDtm=BcH;xD!$`_drT#ACf7dER^E` z?7=g50WaZYoWMDJi>nBrG`qnlS@+a*ZL4{N6mbe}#ZoN8!`OtUQH^(T0Zof3G{hku zy)YiR#qJRk7!NY;t+#OkA0{IY_u>)k!%@7C4{-&*BYZ9gz)k3d9NdmmxP+^7Ih*Bs zAGH@ItDaz`YRL|6dNvm8Cuvo#Ttbqg%|;=XL5{o}l~@Udhwv~YMjNmZPh&46hR<R@ z4&w+U#;@QQj^i}Gc>5n4?!=rFdC-5kU6biohsdXAAZfe=N#lQU6~95!`v)45u14qq zNq0{eX?G8qsvS0`OD4?4e0VeCZJxh}bNB+1Iltm6tR*xp#GnU~aVsWc3T!3r^yv(+ zQ@tC%$D4nkvy*y*qj&|c;x&YpGEqT8^u=K0!-;M97FThwjEPh^Eoh#x2(l_Rq=#`r zs^5^lYAb{5k##}LqN15f>F1|wW@<&Z+BkL&a*>B6xChIy5*x4uPhuOM!gJV<cj1k{ zA8~DhD0FtZZ=I#>FyAVP8irZOL<!2U1h?Zp+>cFo61%Y%2k;^e!#7hTL*66sOakxu z9xqPg3p5}HB&Q^ox}Y24(HoL$gCIFKwA9@*TRUNP4dsPo;~Z>-WaT%wgkK?9`T|)h z+4`^ftP$dKT*5=QF`vbDG+aOn#k)9<PjCT0;CGl7G9klF7=;wvvC!1ObPrGN$I6B7 z`*O5$b4J2E8Uvxr(Y&Gkmk_*rrn2!;eFtK|;~u<#V>pcti<m!R33lS2_yS3bDTBqT z!!4|gty&hGY>dMCV6y6N)+_iLmuJRRwMh$CyYjUOx32UF_e-At2R9IwRl>u~7=bzP zJ?6{2K8E8sg^TzWiNqmkvHRB9QYj=t-7yHmF&(pD!#pg+GOWYX*n^{Z4PW8Y<Dc&Q zbmh*K6*DVtx$%}y$z%Daj?LA2tHTAX2|1lw2X&!9Yvev&p!GJ7Z#0a(<OseYZ{oFt zE}^~;3He*x>|)e~!jDK_LY>DB?8aNTyhL><W7SJv0!o-fdt&*gmD+tGaImouq~C_R zI3t7`GxXDvaaxFa)S+dMm!o{`Inos#zejJ5B1i3q{*a@4kGkD+<d=Coi8mmp_y?;W zzk{Em$<_Vz@3*PhPEvZKYV71YTB~kj%{VGv>%c`Qi&|Gqz8ov$*Biy!y(7XUh)cMP z?{EeEmr^s4i#*(pJMldBqxbC`_PvWQKDlbas;n^!;#aZqd4rn1gUqg|;EGq3{F+vx zeXjmBl?x|>oLbDxFgbt(-hlw*01~hS7EfTi5pxISkNdC!yKn&6ck($d;^bY7QTPNu z;%EGdt9Pl@Cjw`)Hq9ic_-H7#dLoxeRxRXY-RJC~Oq<}6xQ{{#oLGyE*aeBkejG;? zKE%iP20!3OG$KlE5DkfPEQVkV7GoLi1=j+(7JH#m9_5GUDEG6CQcDML4XJuQQPpoi z&=*TxjVvtQ&1dm$%p9$g@d3-L9aM3!rIFgRfQ`qFVJ*-5QVLUZ-5^KuW>_W9*WeLs zhGd`{l8JBPExd~l@CiP{SNIRU$4@Yk$rc162;R(ZMkcp|d^<<~Vg0ePx_PDkP+nb` zF`}|sZWVj6quHbeQ{HOC0!^vMN0XpS^R&CCw3fZQARTt(;@|iR-{U8Ei}N?0hu+OV zhaR{IJ<$uSF>q5OKimm1R<6{|T@xCi7P_=M)au)~p4}#wk?rw$WYvo$Tz{bMbv1HM z*3PFjzDm#%yl;>@?_rLCukc^|3d=GU>97)iV9~u~C>q~K)xnc6EvNV~3UilBAJEfH zl`A&8B%;HRhN+kiJ91Hs61cDmtMNECVFz~MFpl61-pALtf}ijU{E1-@8lyQ{p$$4B z<{th4QV*WojL}HJB+yM<<fnRbr92ov<p;|%4rcJ2C-Ot0q!@EMjZ$wdX8FGTo2)6j zmXe2a7i;HJJ4!gyF#~qY#sVzCa;(A{JdDkF3f}B}mgm$TZXrK-fiL3NDm`Dr@el3T zLnZIzXfJh@quoJWZ?}`%PiCbCH={Lc-PNTfTw`dzk7(3JsJ+DM<YFz>)kqJS&@bW_ z1W{m((GF6G9nclYn1o75!LG)`IE>@?9a7k43c4Y}(G~+S5(^;}!G-&=6T9vm%E-Z! zLpY6aYKGJjxrVa!a3!|R_xbI4CGXfOCA;;1>f)UY8{6+9N%QX_CyIjPhK$>_G<B#e zy{b1)0@eCEwMbV-3BM`YpdI>R7^G&VAq#d$E!~F0ID+QX)DDP45A?-gjKM@qM-Jv= zF_vQ$HsDF@!gI?xbveqD6L=f{!k73F*ATdZ1zog42XsLX^u-X2!mY5Q01L1TtML#v zVJGCaW%*H6cT@T==Y@3hmwHJ}=_t2TsQLG3cjxw=%Ml;JOZXg3*fR+ea5r}0Q~ZSA z5r03!4@O`dCL<fAcnKjCN;`}~4(`N?N_}{7GrT02r%Bu-)TglrNAL-}N4duHL_)d= zeIZ903pv^($PuT4wy?SS0xR+vEX$8rULMCRWBGmBe^m8y2F<d2v<&~ddoK2-SDW5g zc9Lk`g%xn)Fsg6{pCOp&`X*r(ud`uCAtX8XLTab+bCF7VSf#C?&#v6UwBXPR?YN3} z(RUvDH&t)X{aT#*<#sJ{T9Xy*_bB$^7|!5Z_^+fkq6ONc8!Dji2sUFMuA=oSwm}!% zj5WBl%CjC+M$6y$Zs=hCdSNS-P{uFg)~}V?#y%2hD*?nn4iJYV495uEf>9`k9DE)g zfLiJ9vx*B!W4*E2!kfDxF?t63@j6c6O-L+%!wtktV*BOEJtx;z@H1^-)IhmpTVj7# zEnKDDq^3L|9n#}kL-)QlT6421dQwXmVhWR;+Q6H{K0F_QTQLcfF$Gg0$#>(^<2zS6 z`I)q`?<D<y3$M!8u_Sit0VYyUuhZVs4<iS>X{0GscDRJ!5VD$>q5~q4kJ-2f%di&P zu>(hO4CnC4YWIi-Wr;un`Y*1cAs=`H>%{YJxCyC{fD2KEJ0S;H4(|b8<M}7>U&Cq& zhG5njweRQ9p{i<K1D5wTYI(+;eOz2=s}lavprJBOG1hAnM$4|UTOSO-WK73xSd2UH z1U6#}_TU6g;v&AmxA@N*_vnXN<I9-Ei`yYPY=d`)OFVD7mdXk%dSW<6Asv~R0|(|| z1=eE&w&EaOU#ph(3G&{PE%zz<ta@x<5@M`>Y@j;pvrm%QN`1YJ)2Z|8<wk=IT5H#T zh=;`GGMW&k#HktDq8Elj;xran$cMzK1ouNh;<OQma2#)<3TN;UzQPwL_MLcO{tWqf zK>uw#ce@^AVPy8}Y$1D{#s&NrKf$z)7@<9)5R2iMglWh|DHdTV?!zN^65H_%PU0*+ z#@Fjuv<%|Q73V_rHU8Vx;Z3YkN(8_29P(El&1@QiW@rmJbZ2x!Ka9XcNE9+qh6V6O z<4&GGip}swg{F0U<?-6zJCDnmV#RS1sa#KJEmZ~0R-Jj0!g@@ewcD(H>}n~A*o9~D zGTy+4ki>k3i})VDBk%#H90)-u8X*E*kcc4|is2Z64CJCVPAi?qo%$;trwt@xi=WaS zkTyS5wc9TJz!vTr;AJxv_@ov;-PH1H4tov31S5xRjsy&Y9AXq^V+AVlB0fOCgVb`I z#8^eyBl#iLEYM>;lg;&f8IO@*$!}zbeg%e_Jy^|JBz<wcU)!{egCrSwSPnVX{gC6y zu`a@&<H#}F!HP6osD82f$@}MJ%^TA_OKz&|tfrSR(4_68H$A>X`&hlRQ<E?3pJHyO zQtszm`Ii+;dO~GiiTk_w9REQR;-7?p7z0VuMC8DMwRi)P&eQl3m(h&$j)SCq67o=n z^>_!8AOFU;xQc5JC6Ev@C=lK8>0A3ByL;}Gx%>6UdcWVgd+yzH)#Uq_(lL?kXq>dA z?9=wD!U~dO-=W33Opy|d<avK2V>&WmM;^}LeSC~7xQh6P8AmV^#kd_?@eDq|C-^Ty z9$|z;AJ~wET-<~Eu_2OQGP#nIIUXwy@<p-AgO#4&+*@KR*S|QUUf#<+cKUSGwU0Vc zCq4R0rtNo<sI$AZ$lUf4Ux}Z@MUMLzUcetPKguwLZs>vWaN;(c#YY&rfpU3_?jM<0 zh49B2g)jl7Sn#;A#b~MAXTznBH>5xLj6VdSFTU(P%Ds;ImH6{3iBr`cEn(CKPc%01 z=*AKJ7uWDRyixP#@PP<NOGs4plg-uhZPlZC@I|7zJ%ih;m!Ba&s+KkgP@|vKo>y&m za_iAI2c(dH3Jg(~_iCN>GxLVBdlX_3kM59E_rgd>>g||=Vw6B~q7sk8jYBw%4<R{p z4w6gyy!aqrEi2z#c`#$M{!=-^IFm4b>wg?Z4RUktbi?!7eR7_Zpi*`QTGX6pj8Y6# zuM=1Gz%!gcMM$7Oz@O}IhDdZqZw$r|NYPA17P4VSF&5)4tigKh#sR#64{;u!;CuW4 zDPEcS9wZgZFKp&yFw8h7Jm}1D9=xzz?r7?vRz9aSHBJD>Zs3mKm+HR!z)jRIzAP(k zFLKH_%59{HJJL1;S!CnRuGVrKsX`T4f;(|P4&ekY<9A5a>Wxv5Dwcx+%!LyRuo4?_ z059SU{*80^2<O2<kLPD2-wz7oZ)R+qc0m8xxLm&(-+#`4amHEor8kIl%JcLGj$494 zB>K!FB_X7%gMO3Wq}Fm+30{KkyNNpV1TB3t^<WE!#J31|k~)T=7>(W7gXC>g;is7F zZKo&OK~IUx_-==BrG3?B4SKlwn>2&WE(!h;f;KXcpc%Sg9MZ8HFCl>_+>Abu=%nLT zWFrsxn1e;Q8xLV8Uc_m93=>Jvpx>0l0>tKn7n|@kz4DAv<$PI>@0H7MlltzEcEG5x z?O)Nl=%;!w9nfwqXe0aHfM|4sWJw0HQG(lWFDh{WFQO$`))kLn3!a2z<BK?oQ{ZMA z>LGPezSl0_ZojZu755B|lzZIN%ZIhkq=DC4j)-+NmtCvzE>24@_zwP*Oa!7a7-KO9 z#kdn|@em%y6WEEDAf+lL8i<zYi$TbM1NVTt)a7)o^6=Is{3^E{-def!@F@KqPU7x+ zRr^BEFMYiv<waV>l|$V2+(vd?fvwmHsU)xAG(LlAE3+0fLmv!8G77N)&tWK)YAoz1 z!JSx%t#}D1@D=_8KPq2i$ltI!P!-`>1Fbwz&Pr(cfvR%eyimp0#rS)8#Zj!+9a<ub zJTJ@Y4@Iutx;unF>a&k?AIDMd_R;^^BT4csi!cs#cD0q@BM^sy7zYOy;V!Jhdc1^J z(VDi9goAh$XYn<DLm+LV9eQC1Y{<cFxEGaJg@>>S&+q7HG%S|XxB=^6HS3_&tb&3? zG<h%MVn+35Wxhviu2-UZ>0=P>CduXRRUD=1lhQWQ*ELPE)@`kf`y9=0Cv^(Zh{25* zhpCtjJ91Hs5>TD_gIlZTZ_Q5WrBWk;I=J6Hrp1}-=4FUl|Ed-_KKwflAP13vyFvmF z+RdpT(l8B=;wf}|nry%|tk}bFwwK-?RT#66OH8mlqYutCx5M(MX!JkC@jG7+G@kvF zJ7Z5J_}->9?{#h20EzkSxEIT@9*<xrcH<BZ<8@Tw1JD|_A6|EO`@(Ex>lf5it@<@I zN@e^?mR>o*y}=)xWR$pei~;(sV_J8=H%6<s-{-G0Y&Tns)$>pZ<3n7)C75?n7Z8ND zXpdOLqX&9o2yQ_NCg4`gf*nPekEOU9tMMSVVHcjm3wRmFclBp_$CI<TfJ^e|{SH^< z=E^Erk7aSzSeUK(O=H#nsf%xD2i2}dmX7-098z;mXw!Q~NgzMLL~&`5q6|kDq+&c~ zARBTI;c_Q`rlgHY?W|^%=h9n@KKubAt~Z?3#^@c%4X3m(q~e6A4^C-K`7TV;F(I;V z5gvh5iyd&|A9xi}R1c{toe_`W7=e|L{%iHtg}GZ(R;TnlEi=qW_mL`XpjqX<MGW@5 z=NbR98_L#F+1B6@?87s77QaC%;c_aWRK!X=0EO06#u#)*PkefE|H(}&Do$pOUQw~4 zBC{gNlYcy@@7~dttGu^pjNSvY-t`_AMi*3Ti7KN?<62x}31k>XU=fyJ71rPs-oeNC z6joY5H;jg~h;f*Vf8ZrZ3ps&mya!o@+YTPrxvFQU^V4TtA38PuM(LOcz8IjczRR86 zW8c;$sQnR^u4>nN%rxb1OsOB<A=+;RSYlie64Di1h2<Fv9j(v?6EGRGkcs(NfM@X! z9K|bmAOAwgvvf3w!HpP%At=Ertj1O_hRdk~-vH{YKk&6w{??Q6o58~OpL``~NH_h@ zJE`_DmJVv8KbN#7o}r^ZeTH+*H-jueYWIh<Ro5BP#08vSNp=_Y&v&_Q*hW$$v6q-i ztRx06;$QH4js}WUlw&hq!RKi4Jf~JD#WJkK5xj*n_y}J=FAF&p#-C(P_<;LWByG>& zCA@|=@DBcsFYqmXLI_7_gf{4aIP^q+3`aVqAro^j5BH!F58+Ad#4|X6*YL)3CYPz2 zC;!5i_z~9-N>pz^Bw~<+evsr1#2}=>2}!Pge!xXx<HvaQ=f7nETIMj`e`;YmGo4if zELs4wRg-eO%Q^U{4>@_L{*Y(2MRoEt=M4$oyshM*FXI^AfaLF4oP*@^SNIy=z_OpR zK|72>Dl(Ceay)`Zu@^-8ASbC?D=#p#W{mRuRC{8pUe60@rgDCyzh|lXYxT`rM&r=? zug;TN$Ps_^95Kx&)DL<7Ga}r?0&y6CAs7ui?!Y}*i5>VS-oU$VW35{MQ;)`7;_|1~ z>OWh_v?XDDFy8=`+rrm;q!o>o^vIE~;79y~KOnJa4T(v6bOGl_)ti?)#`lf#7L4~X zzIk5g=zP`hyw)+WIM1{<)fBG=exk)#j2G(Md76-{NvrMW$(Q&k+@F4E0xhcj$J)mk z684RVM{o3lq<jo)$iY%b>hHuVY{maa*j)fbvGorh-&NT`1;xe$R8TQcY*0W@R8&xG zL<GCV7HjRouCc`yv1?51E(FDHy`t!~u6d33`x|zB{6BBqy&raF-JNsJ@0{tGGYL2i ziNZNZB%WW<R$dw3ZG5Bg9+tnV&tsd1b{RQj+4VAHxH`LqO|jqk-1gL_%<mD&w4J2{ z8D+Zo#HM7Ej86=?C57vFi+A{dfAA6c_tApjh(aigqVR)$HHh>xpYWu$xBdVDb><73 zXm#sjV({iE4TO;7P-7n3_^8@bPIqXJ`NKbWG&R^?vm_!Dmx-2uCuG8P(HO1K0iDnb zBQOcmFc-_Q4)Oakj->tfrRrYNTJ%2oyttb)XBqChcXr_-=NVm0O2+Z<i03w|{Upgc zkYocPNk&4F?E*<U1|u;6k_C<+ata|~R%>sHPA`<z)FEj$FVrh9<RpTWzrzd4uQ!gi zFKp;K%T9hZ8It+wuohq~!%~R#h{w%+n)^$eRAZQo?7%7gLl%p?KgV0-+Rx!mRD};Z zVKQPdA6sw==a7taWIn(a7m6LQoIZcW>GQCgOzjqA>JRW3e?d}uiQN3s1Cp92B*hx& zjERs`r$ADkiLE$+Q~R~BzirkVgC!fMaUK`&3P!Ra*~wzbQZ_wXEZuo`MOk>j6M<-e zFtk6Q1;6D2;Lu`>$QSBb{-F==W3d#Qk%*f}hs{A&(<p;RXo8VggcHbhh)Ox6$K*d< z%W8D(=wLLr=l4<Q0ZAhogD?t`-ULj63Q2nfR%0V1AKS1C2OxPmhEuo($=@A3KpI}) zC77+YT4?5fICJ1GpGryo#(QKY*I6JXD+)K1LeN3Y{S!^6LJ%WT)W-O;xSJS14k`9M zJb=R?t-=?ZWTTG*ama`TyYCF|z#*K*Ib6d(FdpV=5#&Gtlt!h)n$I_z<Hn$Ad_n$U z790}UBuAbj1P$LX^eAhkV+0P$alVIqCkP&H;vdvJ$qxBRy(=D#gX3e2{*{<oOAN+1 z%!H({2=Um7RD42aQp^cSy&&9CBT@7J$u*^(H5duU0!Y?YVmmY($3<MiEqsOP$R1DA zWn-X;tmlRlr3lKy8?{jv^)V1q%u$$$6^O$IY{KRvT3{yA0i)MuMo!})UgIkyHkpY{ zUX*|<%E1Gb5P<eaHLonD(?-AcjP%41NI=J64p!k5l5idOA;HcG*?*%~vc~k!Mn5Io z$f)%-ndTZR$iF$G4BDe7hGIOVl4f8960rT4R>9VkZ1mdB$Td8K)S?4iP#HB4j_#1! zU4(cf;_-3KD;p*7f6T~hNYxjE2Wr6=b<rIIA<berR^b@V;0A7<(ERO8iN<QuX71n} zzM(vAr#fmNqa86}hW!wRcIbLitCqub-Wcp{`Jfx`Q?Ul;@B}Xrc#1_24&WKWPO~Dw zV#Fcy8RkLM#rQKB>!9EFrdlphT+Z2??QOVSic>mtUERQ@pyk5EmL?9GyK<W<f4KHD zm#IZqSJITc^h69c;~+kx2<dyE9wbjK(F&31jTnr?B<zPZ&mQEn?P)D6w`sl6+?Ek3 zM0@mw6ebo6u?SMAjo6J-NWo*ggONg73!I<f5(t14z9l+h9L8f6^!=?wxv4qh+6Ov& z(9C&FV~r8=uUnCbBe;w^_#0Wy5>n(s75tR(bEJeIbjC1@KrCiL#UiZ2mUCJ}e$#4W zSILG<(BVAo8$Jj|1Y&RlACTt)%TD;C8G2$kw&4`6BOSIEnGxZSwit*x7cCc~TKWsS zCwIM<QZvqsl;ITg>4GM&z%69!25#au9^oba##?;C5B!9I92t=rcCbedIGxu53$g47 zc49<|Qyz3zW$=a+tv(t-ir5ZP%w8CbA&?@^#e6KmQY=5O1+&X%^k2?MJT@T#n<4Re z3yG1D@;g9cRRSd;F)IsC_+HTbi!nEb`7$DbY=~e;K--`jB(Osv!5xb!m<kE>UL1!6 zJQ))7$4G+&|MLYc%vl=nXGUy@ywrv>DnM$*7g95g&<avR(U4l2i8<JWEjWksxPUA8 zi5!<$c!8s*`nd)DkA8|lI+^jKV)Xyim1Rsm>ZnpCH}!}!7m*$*Zknvd72x_YrxNUJ z>jw+?hf=?XIL%PP<kq2pq%Ubpx__p5o-~VGW<`w$@VUawiBXt<=XinMNw~`F0_SAD zgJp1I|14*!T=~H*UOhNR!{Ud7f6{*w-8t!ZRnvcyej&6hZ}z&Hg3MCRT4;n8Xbs87 zd;Eee`EW#Wc%TLvzzoUb3w(n@zOtbp3ZV$fpd7qW3w02Rei)8LR}8fc@eF7<jq7*@ zDP+bG>^Kfri+xE`;&>(Lf1;BtFSY+ko5CFD&8j|hGo4f8%a|&v@zjUeRi^L_zhEL< z1yBrbsDf(nMIa=cLop3=a2+@C6o2C*ej*p)c7zK&P!V3JgAV8gsg@O2wb7+b<Ba|* z7)gZG(`nqq12|DvQg4+|1L2T5?2Exz3aQU4$(p}AbCUTABT4uKS1MU5x)y4qAzGsY zdSM<^Y{YKd$72+`MkOK?ZJ}ZX_Td7EF|AvA-klPl3(&`+Y3kg#&XU?+zI6o;@C51j z8y{i3&H@1C;DJi0i3VtoftYe#^RGa00;e!C6*I5^Yp?}3a0?Id0<ZA~AMqVO@C$}i z4nU=9ffZQ>nlmwy9d^ipVsJt!c%UX~Ar#%v1EXQaSS-R4tj7jyL_89(8FI!{KSj2N zP6q?p@mdob5Zf+e5kMGY+)WPJEKgIkv0DM2e5a>fo_9%8rX|zZi&MCaWZcDTe8#`X zdV?7UrBM!E=!!uYhKX2=1Z=yJaicuFw6TU+&GlW@bMGGNv#O@TW=U{6_Te}r;Y*Oj zuRt=8iu-s8$;c;sgJdQ%iDXAk<U@W)=A2LplEEsdg+^$C=4gReH(wRL$)B4?H_B`F zu-U_oirM;jWX44&W87Ip7Ocs<dZYq>oP1eWI(TqolA+dWWOY-BxtL6>6*{2{BpL%D z(J*5&7DA%33EOZOr*IY5@Dktf9a(SEI#3uT;fZRfjUec)KW@rC{S{{)O()d*c=153 z=r(GleRQ|Hz{gZD<Gi>-SyN?oe+5%D$uRk^%%3+>68>bIMDA5s@^b=`k8Dg|(k_Bh zr~pa73A$h;W?}`l<0S4N9mZR<Xw*j=^uu&)!f8Cbm9eWzp9tOmc)netx5>Y~luOd+ z2uY_m`XC09=6J+H(q0Nle;u|!@}c1vBtOJQo=Fjr6qppaCYE<g_v0IF3#bFDnaZmb zO4+)rM23eq)S(uC`t#fphnkEY@gy?Viq@|z$Yahele~bNkfNqRiu(mWA;q>wVMy_- zp)Mp0Eg_+ZLT^Y&rb5E90TP-MknlXfLp;JW$Z5mal>D4H9H{?q`J*4MU8DAo%r0va zMb%qqOg%DAVe}dfQw#c<B2{z0tZp5O$`oa43vW}wsBni|-6h5Q<m@qvVT^|76E;y1 zgQfTjzE9Z%Lyl)GFmVdTznIJ5h(dqK70*Mt#-_^eu9ND>Q*C&LoZLFdJ;ru_^m}o- zC8weEeTLHkCMR<N$yPjB+Kv=U_MY?pHzb>t;fsdogkczgSggYV9L5D)MKWH&Nb#~D zFDf7afoP5v=!3p@d$V3=U^aGQ7Y^bKO!wGl#(Hc)I^M&Mm^q;YWR;(>+E0t)U1a>t z7_$7EoWbTb<<EtQRMo9|Y>4Ho$%aixL+cXdh~FPWZsrP-N@Y}sFY4eFY#*?Zj1GuI zG=^Xd*5e?K;XIOY9seTRL)s~V5rr5`MJyI!DRy8F4n1^abCZGdxPXUvjP#U+F?I#i zoH2H$%&`Lxs?pA-B5G5avjXay4rLUnU_G`Yf1b~-s9QWt+=n2)dx4kugfIAoqK}wi z;0g~^Lml{|AzGsw24Og+U?H|65x4LZ&1t@WHs$GzGxKmlfKz7c3(ic5(NDc+oadOC z64ls{@t=CEfhj_bX=rMu`nhs&^+celdB$?!jZ{TaS$fkeTHjPWvWQG^9+qJTcH<yU z;ucKIER`TLkvAHk5yBudRWxL;5}XX<p-c5*Dq1ojZ>mcZQ(1Ldkm;iu-^kQTZFI@T zy|sh<Nan_o7=wwJk42C<bORD_92amKPmqH-wlIpL1WKbUyix0^)~d0I`(SG^BC~fr zgdz+b&=CVL5b-#PQ+S4VPqk{n9DVS5$H-6EvpkSxLm{}LG-NqZ9RUbL19Zh&tb3+; zHRT{m;5tTRVR8{S@i%0_Vvhp)f`v5@@6M=#7HEwQ=!M=G@Rt@C%0^X0Ax5lU>c{X* zY{ecpJ|}l5_JY$AxPnzL+0elSq~kqWrjr0xVk^$!5x%Bd`qh@_V(JG-^d6wNG^$ia z&ocUFksUZx!X>cQ3%TWN&ciNrpMRz$Pa9>4m#<NQ0pw;p;*fxIxQ#S?hKXF}x8$}e z@3jzwCTNTH=!@v*T2L#~USox5Mh0O5reFqUV=ii@F&CjBf-o*ktI&qSU)9DjG6}OV z7Yncs8xfD4*o8efgi|<|rd120+C$GVasgLy6Sr^&cX1!jk%pJBCD1ug1Z7YG6~VJ| z3^fpqK`*$i-L%!{HHeW>7=!VchlNlPhgDdO(~w%cjEtJpydr2%q1GzhMpYigJ*2@z z6&8RisvrQ(AywTQeJ}zeVa6=X#j<oQG?JVJE@NalRzTXu7HBwt(@4g3+{a72#wTQb zMZzeJvahtjjx^M;ulz$HKB$FO=!eC)gpbJenv)c0hY?tg3wREjzgZceB_?7rreX_@ z|NXl&&_ZfI>E1mqn@zkrGMJ7Q=na$}SsT!k9Q{vKQJ=Lm<<B%=wR)_JsibfIvLsp) zL1>N+=!o9viy=(hj0uoLC&8L<?BAMCSJQE$Uo0QaLPkz#G7O)_P5g!DNXI|;h)*&u z4-Xg|J~+J2;Bwp*>?j=ty8mChLd+RmF;0JWv*G{N@nJc&cTvth|NVuNnX?0xEb5pZ zCUZNx<0N$w)+||*|IBB_->`H<Ni;%ZbjAoQLE*Q&!|@$W0=eHa8{s*+eUQtSc<#45 z8?qG-+VLbmIao?he)j70E+$9y;ZV9%9rz(jJ~cvrc9#C9gpEzD{8D;JJ{w6CfFmR; zl8q{;iXd3Cly-5K%JZ?Rhg5e_`;TE;KH83pm(6`lWAYk)cO5Bxy8pksj^rD^yN<LD z|IdejtIN8ZJbGl8FtkG_NH~UJI3z487DK|5fW5el$9Rs{_<(<5Aao{37+>8wv32p* zu|39aZLzhM<)t<r!13gk{aE(~^)~IM15*#x*vHh+Y{)A=DT(r^in{25K^Th}m<g$! zHQ0>ZIF9Fdk6*}6t=U0p&;{=BgcqXF8!?!ONswAjE2=*bg-#@U$W;Y&UdvFklxCJ8 zbxE{|TjI}}g7l8lRdcLqj2e<z(R*%Io%)%|g%p#?EX7)E#sNISD}03w4afv(P=!$v z<xm6R=z+l)f^qM)-~k-xG)v1{j&;}u4aaa9H}MywWxmEgu>Zi~7scR-%J4%F8lx#X zqbs^$FkW0eq`zLQpSOOD_0@fSODa<{50Zl_@~x2=joFxwg;22`J8%?N@eqIGUwp?e zaBkjz7zb7SB}w^_;U5l;U;u8Q^+y&kc#HSw^NEE&PNCyxvW%Tb{rvm1Ijd!Pe3#yV z=JvC!rJbL1QPArlCVTbuUjB^Sz@;h=Co?~u$ZqMmRaGbRbnszAIUqXhLl%y84>c94 zF*&F&hl;Hk%1&nTq6pkj8jaBwUC<Sh=^6iMp2IoKW}d;w0<6Ra>_8&UA{A1)dw7Z; z_=y~pusBMfBD_!weyD>MXa$K%7g#RNIlN*1;jz|N-&ThM^a>g&6(ry4jlLLz377<l z=|Zf+b{s<z?js$q@CI)`YW}0CATMhL{L6<~2)-Tip%&_+1tJjzsibI3LEI<JYYb~- zzc@yu=1xLt?;M`t8|qMlk%)rSY9~m|rl%g;x^V2m-mU!?mS?R{NTVBlj-1Osb%Pn> zFbOlU0IRVETd)<<IIbfVpOF0v`GzYhpb0_{inbVxA&5a*a@ygv!yAz{?{L~^8R?PM zBTX|;AhcdG#X**DpOkN7(pO52EZ<m<qCLLjCszN<#?E&(tiS)yz9LyojAGZAE(i;$ z4=0(bsu91tF>{}6TCcar%m@0Ws>ia^kvI+4#+*ZPHwW{v2yxhe-PnUf9EIfTIV5kk z<f|y$P#wOALTB{CWJuoUU<p=3Ujl59rNG=nS4UYE2XnR2Q{(`#d|@+Ea3AUTj4zM? zC~$%VA{-KoQJ9M#`1wuqpGMoNCebkvovg@>LMV>vsDS_kA{f0e5TpOqs!eAb)NeE+ zt03V`z-}DEMSQ?dWGCzePy%j9OFppfz>HxtIt6#Crbex`DW~<GX_{}WCjV9zl~4^* zUG>lkVd#Y37=($Kj78tIYO~2m&>}__V>9;R4({SUUg0CYBGV5tgghvMVkn8y@POwJ zEod&=^YtY~>jdP7i}=TrNW+kytcfukUohYo3tXH>XM>T>{fvgm$YwOEk9=%OOV^kB z_6Uo^7<N^7!aB>zYg|h7P?m`gFU!yn&fw1I!F9Yz{p=jnx(iH)ygW&(5xQdl%!q{w z$<I>kLL!dfD30Oe56x>Kv%QyO_&Frgwq&#@+)xQk5Q=sf3TuJpGaUC*^IF6N%yEny z!WksvGo-{uN}3J1;fO-0gU09&iO68gz--LNGOUI~>Kr6mFQE{rVkn6KG(;B+G8i@U z5@vQYLx%B?n9jyxtipEe#4S8UR-+zsgFWxAs0@Duq6d0n8dl;6F5@-6!!eW5PzZ$~ zSMqUp$;>q=Bi3|T!y;!Hx$vbn^(o0z3h=FhmTw>7y=!Kp!8VK05Q{7}q>KjWjZgSu zqql^r>g-pXTVrX%y>C+gtP@MC#cF2fnnO9w>%P*I8X!3+iSnq50MtVxgrF7LVgP1g zG1g-z5<z~nfH>1(qqpSjEUw}fUg8zr;}d?sK+gTp1Z~j;lt%MjZ8~N2lXCULFpR-t zyurUvD65pYI4UCqVc-Cp^qey+vQgzm`hhmB>sr$iqlf%kJ9NPSjK(xb%+_Hu&LRcZ zvKTdw^`@)F`V1NFBQsHy$SQC~X?UO_B--^M5$^?w`gDB8SA4TEYV|jo_8Xg14>D%R zV=@|!<0R@RM#Dg)A>7tzc!XS8jfUYEiFfFdjp(6Jc3L7P!p6>M@Ub(hV}tCfN+*u? zmVTq!aN_iBQ@c_c5Aby`wzei$grr<i9#v2c_0a&q2t`|jV=(4o8IHl4)%y$=CYyeW zQER=~6mK*$q!*wr@9iN4nSr~=OhK}v5Q?J`s=x<L&<-8Z12LF_Mc9ljIDnHljq|vV zhmZihxccJi{;MxE^H!Nb<&!t~gfEcr4M7a7VVubDOf1AYY``-}c<l&nUX(ytc%eR8 zp)-160LEbsR$&ib-8k~<#)es%c{{miE}!hh30%Szq~JMTKq~MHe!)luN@bcc4%SMY z$*_u*NXTx~n(s7iF`5}NY{4}=z*k81+rk+Y;Dy?tNf@Hg5nVA3Dm0wHV`Q~wK?Qph zhBHc{Hhd5O*}OcOwn^SJ^KQx)AXAp9%CECSel5Q`f@A2AgZe@KoXir~iFD+2FdBAY zkAqQNH7={abQc$_FMl-FKh8#PNp3OLV<!?}o#=UnQ*Z}0nRp;V5djj^y!Wx3FiX-g zIDj)q!2?Kkp5Qz3krl~WNqC?M+F&{sV;y!tvb_hFAlc7B);&-c`>-F!aRGAM)WO+F zn)v_$@}__W4e|}2Tr9P)1jTYQTVV_;<YAcsPgKEWRLyHtqo(r&+qbP`-$gbE-yWhz zO!i&uwZuavf1`&amVz{7Vv_c7gexkcHYCY9Xq$_LS0W29Z-xwE7z)YEBrL=lY{nPZ zkf~fK3dyJoYUU=eM<uWf8EU}~4bTLkXpT0JVwoXDi^Coq#x>l+eLTQZWTvRLutyH$ zL3vn1Qi)-?*GC@ZIcH>IHwHEHaROUb{zU>-84|SG2t+X2q8o-_Xda_h_N3{$u{uMB zS(uFlP_Yynu?NR+2@?Jrc!)H9UH!D_oUuAXhEMo{@5r2&R*WJjjVhqh3_hrj5QOFB z*Jt^407HgwbVOJ5K{TdfJ+|X8&fz*z@fQEUAs=&OK31UTS%LaW8uG7=`SbyD<tJTS z!Buz^U}ixRN26f`R-$S_qoFzu75uYNvE9ceUt-1%vHgE<{OP;KMQdg+pho7j&!v{V zWV&9RTo~L?8NO%)$wx~>peqJrD3)L;wvqGdmx+NlLx%l0jbz-1l;APG;a_B<1UVq3 zssbrl%lx#wBwAi|h73Isg9%uSIIP2NBtc?u8&8mqxBR+#veY0$hWGe{AIM6S@}oE^ zKq6NIb<hwk(5e8xzQ(UxGh~RtaLmLatiui*hQ#~~l5i7G@C>%ZKP!r&6so`vjX@o0 zty5WNwwBszitgxvK^O+9!4;5NJc4U@fR`{)quEgi)gU$OhlXf|&IOtJO{VV6kfAGL zu@DDATQHo$Wu)RMvKC^U2N#q_%|b-}Hj%F{-}d5@gJ@Wo5~6bv)|8l3lyz4z)++dh zUQV=YTt*VEA{jrNEV~~1WBKGx7j64pQ&ScwOjITwfW~NnPMC%TSdFbX0Lj2fT*7rc zLQXPM0u@mU4Ir5eMLTptG*)0Ij^F}rfP!e|`z%m8NRb}lCEnv3zQdg&`k)b7qZ6d) zeJ}*0F&R^#;R0^rDc(Xt^sR_d>+sOD%IM9IAu|EXjv^=q4^%`Q_@f0{ArgHMgNa3{ zipNxiH$!^JXYsxWafn9(4&w^0;ttaA4-8ZbRit@8mDxxtD;x5lFx*iNK4^+igrf%r zV=Sm#t@>Xw8%s6EVm_8(HP+%BuHg}0<13^&WTxuvkk^Uy)1(9p849BwLJ@(UkcQJ2 z1277cFbl_V0heS7FQo(w{cp|dF`qrbchJ-fzmU_J#U~2D$(a(oq68h}Uw>M@!KVgi zxS%Q`u^78?1Ail*3sZn23ZgcA;ET2hLp$`uXcwdE^1v?SkM6AXCx66wncAs8<iTrw zTCwBZzK^}4M(?sS=}%NsH@`8pFiTb>8&x1#2}FH#fMjbJVz3C3#Z_31HHgO!?1E(d z7>*+qQjGg}fY*>B{lqWiCCgI0{4T~4|D%j$_|P3y@t^W)tKXU;jP<18A!v#=kRV6^ zI-@%*fiNU6d<TEy8}u$_H!j#{mWM*iepop*<ui|18~WaKE8{t9>pqy;g%CsiXGMyW z3<hB)vX`LUpg0<$5qctLNmff3ir4USWv2s~-1xp5^^x7i|M$}e?bT7)*_hHFMyL<z z&z01NUTtJki$D5T3K_Rb4vWi!A9=b!9(IL?e>C-Knnw!q9UkP!8@1sF$!QA=#87Cs zh*aEz<hCie?jU_lO6-uRl*TDhDOJ=u>$yIn!~1L|wd_|q*yaBH0&0jVR~MA$R;yE= zOuI9Jbmj|Z=i)z`+$!gk$uvVK!qFaG&<zrhLC8TMBrt{HT2k};!ZGMzS4JdKfskm8 z#bj*6X-M?G;1?7km=)z95v_;%2t_moxN5=QIP*|p03#CaQ5cPhn1pHAgaqtDGOoL7 z6~3Fe%i=mCUtpk)jF7srfg`9hgDc!n9u?pNKZLkxUOzbu<P*Y3Gjv2JbVgrH#0JD; zGq&I`5^)|EaM4Zk$)p@NHkXv-hw|kFSbvc5C6+jRW-LYSkQw1PhSyL^6Av^*H;l#X z(ndAXF<a^XJZo{}-fV>!tCR77MIN-x`G&nL1%mf5q@M{4HY&5c^Ijw+N$no)!$1mu zrktH|SCmI(v_(6Fm*Tz|g$pJmYi3CHuHzM~*~~@Oil8V;q7?j57xfT`254AX3p6QQ zg(_ugiLS7e%dmjqg;22;nafaPFu?)2;0RY#Ll7Dv3|%k?6EPpF!NGJnoW3#naPorW zaT~`a_Y12hFa2DFt-{VT(bQ9u6l6-fu@@Tl;Vs_bJ#xB}3*<sutil1<mStUvw{R|J z*#MEgwdos@XZ^U#&XwM=gno#mnoY)2e>fAKPkoq2abjVibg!IO^1BV&u?zp5le2tw z4sVc=E6vkRxoiyiKV`2r*$To$%tag|yKA9gKP2l%@Z##hb@L|h8W7nya-NqgkzCce zzDh}>o7$|7!ZUbFsAKCWCDgtiob+wphbu~Kb1GlV^4sHhjOX|VAMp+Lgu($8Q5F6O zKm$mq`r$R+;3t%Fdgu%jd7p~cch2m+bLNiaEpEo(xb|`FrP}`U-@FJOos^VM@la1V zC}ri2fo$qo2W7O;S#37a<gBn4(LJnM7uDHUaZ%^^Dy7vX3^g?5r;7A6rtv-<GcXg| zupK*a0T*!zPm#Gidjpt{%oS+)^ih(r>-?Vcd^~(hKcQkdtHMq+hr%k#`IUQgAfg}f z%s9l&!OqN~!|6$`FnQ{pM;VqmzQ8HVIhH(%P5oR_cFEWOFHev7&J!5OPbR#$acYao zxoz&k=00q0sZctouPe~WSO2`q9b*agU0!Sb9r0BPo66?v{-jDt)j5~q*3w`v6R;L; zi=}{e6fz&`pb2`SH|F9rQt$w2$%ob_&rTlIb5wF@EjP|&<m<k>cUgnFYPhuS{7OOf zPC=3`R+OeQv<OcHb&fF=P}`SM+|+HfE!C+2{d|4Ruk2Ru6;O(sbI3H)VesI%Cvu|- zs=*8O5rm#FV?B0Y7c^W(Djwq>e8yKeRwPI%hd0gNG<H+U;TM~FZR&NnrEkl_y$=7U zMRA6qK>?+zx~-^EPHkP3Y~OSui*NIj_id#Z9aD<d*1Dk5MhaE3aei8Xo|&plyay)Y zFF1R$nnpC{U}<HeVL38YVgC)TRhc`gv1~*nI##nRG-hApe4KuN{@b%OpG$IdHPV|l z#8cdQs{I=9ydlfO!l>Hrg%!1PZYfx4lt(3aq6)kbfNqeyO@QQY5@N9iJCK4WC|rqS zkf1_&tv{4Je_Zdj0s2dp2qo0fj)Y;4lhQCFAfpN>C1_avis)}4RI;6=?(=uwX2{G# z*_AR9#1N@_kFY#4?F#Th5P~rPgE0w{u?NXW!8N2J4gbK=64O_yiLVkCO&l<>!^Fmm z5~?Ls;~Z_C-<fk$`xR3TX4ISB=I)i`oI|j*zJqQG&k4*W_0kVgH~ldfF_?*2m<_43 z9XO41xQ=IdAySTRSu$bCmZQB}Z>dve3#~_WcT&RX1G176B|f^A3%K_<D=RbdFvf+H z+q)<stqeKk*Iu*&U(`cm^hH06fwYokke0FrMp}xr7$5kdG1$62y6I?o%F#{pM|Yne z>MJJ_-KAZ&Q#TY>Mr2e?C#j_3C6u<!9ppDX&<iuL3eo}};5Bm65{n}YV=)~w@d26t zXrWOVt(1#s)Yc^xSLrB98(C7RX;jO~?7h=fajR>{LpwICKpZyX94_D;T&vT*5Q0wV zjv-itcx=Y8>YBfsl4xus6Ou2=hb?Q6H5^Cjn(Q$ks}~bNus557Sb{IOP>V%2uHY&% z)wV3A_4^9-og}^YTm52<qs8PIiI$!X-kFb)Rw!wdV)~L!8B1E>ymvrn#9}#CVI4MO z8=k<0{CJ=~g3tt!ScD@ukBg{8KI>pGczSWdvPlDZMLJH3oYX)cl+l3<)3J`eC>>i~ z$(OO%yydP8HWpPYmEwch9yYcaYvjtMSgh)!!^<iY%|&Fw!(a`}QikKO52tY-kMI;9 zA%SxwSmjX>HBcLk(G<}bj1d@vMOcazSc&bBz+c3rTCB`3GaxnaD)ngUE6Z!+Jcj1I zny0@rwDHxbzTxVQa!NCW#l}U~E(Voyx-uI{arFn8AF-p4wYKGzQu2)=wY%xxXr_L5 zSKJyKTqJ=cNHyQaGZ<^@Rc^?}dl5LnADu7^>#+;F@fgK?IHKjF1yxY?8hvRi`VRtl zuf{(_U>rPs+4;c|oQC2@NH74qZ~{qnEDLbG2aT0AIN8m^H|;h04y$AgtIkwvp)Nwu z0`1TqW3d_<?&AkCkxC&{hBy2WhHywu24E~yUoFg2S#R`I8CeX;;zsPi5uCs&NVb!3 z74Kp4(>$xN>F8r3?^2%pa6v`XK~qGa7ka~5-oXq{!8A<w(|oG2gX1-wk#*P!3CKVA zh%fjTKajN!dj@buag;>0I+|Avb}P))81aG+0ucr?u7JoI((nm6{Mq(KUX(%yOu`(@ z!z*M7phU<9H~63q>Y_eqg^8&f=Z@^roYzQsHP_5u><KiJl-!v@0n0Z#@!kd9FdJKN z6=&<RctovwEW{9x+=1i@KIn+S_1X7To6S~=%CmauomigeT`><^iTZlI;wX6rsI1{5 zr9++v!&&S9S2uIDl_?!0zmkj2u;ye8!(%Z4(-4c9kQ^?;CP+?`ke6IK!w)Y~UL4!D zJXZc6*nVKWfgS_Ps_*<1p14zhZM3#^*dA?Kz=p26{1s0bEu{weDzjxnk!6tj&{rv@ z#+6iZsZZE^R2>T1*!D5xmg#mtBsxLGA}qyrq~a}XiBMkTATriS6=2u}B~bxh@CK__ z`G4b!jVT*vZ{%cpWYtKvD%E3pUghaPi~W@6YH$EsVoQBk^}Nl?8uoQHr9`A5uS`Iy zAPUFu2#=AO>M)@?YM}udqCEy-C}J=Y^RXP<zO{Pa>RI5G78BJlO1i13qBgBUdQ1J4 z@#^L}<Y82RGERNtr&Mf_+d37MU*E-jJitSI!e@Lz!v-`%)NaVX;SnC=JAU9NDh09N z39_7I*B>l!IFx%s4$H;V`VKxr>{&3Xy{)S_7^_K^lW+@n@ZTAD$7k>H5fm*gZrXtM z4Ju1V78TWTjg(R9lR!n&yU|Oj&(?30zf#ehO}_kR&NGqg%qW7gsE-C{juz;QXw1ez z9KmJ0L^?j<GaM+P6TDFi_0a%r5RT61+R%lZ(&zI`%WK&BPQQocv!=t=YgZa56^-hZ z*lgL<lm@H?>3uU#2dA$5d^>jGIPT*CB-j$@5BP$AAwidb=Oo}xs0ayuWdws0gS-+J zj_utdVPWrt770GGHC&9Vp=kzL8_@tm8!1~<GQvZT8Y*En^dL84u<9}^Yssd$slne9 z>d5dAEXGqTZA3f6XE-<Jdl-lJ_=>hoSV>?wPGMxQWfjA{9xOb1vWn3!G?n#?>NAJN z!KgmO3EX~M0?uW9dQVLS)QBd^>LyYcNq+(sU=buQYp@M_a1Ku(`LiKkB{3dc5}6u5 ze{`?;&F6c&&F88ybyYCix({0^cU8wu3cZ3xWzD8e3Q}Sk<dE+#fwg>V7~Y11IF8GB zijVjNDZhRpeoTC);F|FzExTiCvyWMLmPb=sW?VCNW|xO5W!X3&-4Yp{11t|#S_Rt4 zuWg7{cH}`3IKdjx+6?=k5t<_cT_Dw(9zWmQEz~Qto6H3sYVqdEJ+(<w4kaWtV^k7U zSA;6^{1%%id-+ixjKNq)Rn5UNB;XJ(-~paPs__H9K&mq{RhR{>A=g>ykA;$6SR;ls ztkjU5h@&l(Lm4S&jo~(|72&k6iOq?vxg|}DQIEjf^5Zs;wh;ztAA=DCX(tmf8B;JD z3$Y1lNk<aYNrNMUss~lq?<g*#`n6V$s57G2jcnUO>8*Z@P|9bdd7*{k*3@2pbrRC@ z{(?;~b0tQAmS`A_37Cv2n2lvvgY}RZSMGe{CbOu9F_qazE5IY(uC|jEjt9ME$Fw88 zFX2j<x+GYcrk)R0EL}xXt=ZI~t(D^8Ij!m3WO~LBRw3wwRNO=DrtC{00$nf~D)KZV zB1pthj0mMgVkx#FdvoiYq<1?~g$oe%`=|bM_XIlyrQ~J`{=8;p(+{D}ZL9PRk)mzD zHk?8#Zs0Gx!W+EBKllM_wu_NnC%j5Mwpksg_T)9LrC(`vM0;g|`Z-)_neh;{=IvO9 zJsiUUl9Vu|nd;n-HgHQmi;iK%$G?^^8*<8YO27@};DL&$g4*y!Ac7Hvj*zeoz$i?| za%{#?oWMz(MKZ2KLM(R)@=8gcN&ho3`fGh+=JknDYX6S5j%x7^N_*8lhVvG*&59Xy znbBz5(`YyRH0eFCb|`4At>;WK4Zq+`E!Be5pbw-L{Skl`Xo<G4)@*l%^%iw7ZNb<+ z;qt0mQD0D~g`#Bf6C!`g+nD6oUpsb=9HRI`<cei9@gq@+pV}uv+1)vpOsWU^pg#s< z6r}Nt#W+mDG%SQPsPQzS2{?qqkcM>x(zxE-d2{i=`a8TG&^t1YYFdlNp3lU=#}%$K z)W16_E}0C@>YI*=vw9^Y<2WUE&NSz!SF=vk@$5(r>=cPoN|W^?k>r|HSoXj?GU;b1 zMtgNaCDcPRgku<nL)!KzjD@su=_i+`-L07!(V%Jr{Yb9SRdwm2xT?-g=$c+%VFh+k z_N#;Y^O@e?N^D0Zyruo0GsqDpWNfa_D28y}+anrNaT;gv3x*ba4-L^BuToEJIiXJI z7uL_8mwP`osh2EB!<nNibyF^7WMN`w4o+Az<ECEitdwYGaA2PNoy;MIWwJfc3ujTN zCHtp{K_W`EVh0_5sDp3}!Ew}WZB+Z;w+UC10`<o;aU<F`+0<Ssmp1iK9-1YuGVzgE zgSFU$y-0*4cmWsj1z(YkM6;tHBs1eN0f%rHe`cyInec!$b7|L){Q0uGzG*J6wCn7A zw30e<p^hF+-~e^IUK}oCD<Z4J%U!+IoTHDwf(V};G>K+-VJU3@+CfU)0evwL)(AXd z_!S&mvyqJe5Ea7$EXRw~7e_bFJIdNmUOweB*168=*q*e~QGJwg`oZ&S+0UxmC$M8+ z?x{>(IFuEB)?P{(DoZBS2-`5Q4V%nZh!03?%k~yBhY=?<MTK^p1i&?<A{`aNS!$tC zxMg8XM|GBSCF~gK+cy8%n0aWHT*o0Eo3RCzNX`>JXo^rYM>q7x07&*?F%Q;kE@C(i z>u?6icn`_`M>vxGBIt%U_ut$<zjvME-gUgr-{<oE^X!sXUu*~&hceGr4B=+<H-ng` z<NLF+ZklduS)0X-XH*tU>f7E*kUF{#l^ouO2gZB#QCtFxN(#NO0*4{NyN*8tSd;*k zLQOP*1XRv()0_T?uFYyT>neu;>1{qgv-iK_losmBXyt|)*PjhzOYS1GnDVr=m)~_j zCyc}>Ov7x<!zOIU9_+^noWyxJP+{ez;$(AtNYufZQ8OF!s=|^kui9}8i~r)|S%K>( zla~%qCd()b<f$}dvP1-?vK;vF*4Dj|gG|QS9_lhY8dDL6)!2dENP)GzykuC~3{N=G zH=AbikP{xJ$(&PCjp(Q-YQI73XzR}>y)}_p=FLmnY}(R6N)=;J4*A_T{6u!zTOl~X z+Wvwv+MuBg?>#XFlfWi#`my+VV|uo%-O^R&5A{k6OYi8hN=~&*x@|Lc^E(25Z-|nt z#?PXNKi}Gx@wS&=ZpT$5<0bxqeS7vWP#>+(8g0-4LolYj<~58%AtB5T`VX!Dc%FZ} zh|BPZpcP<p2j&5sz*pReWN{2r6m1$8aT!mdxGbRz&wk^e6vv}#DOEI%G`JW8$1t&R zSd69Eg#9=RN$>(B(MynolW-T0keLkRK!pe`a3rU311m5hIje*kkQ}x`G*06wUg9IZ z;urFh>j|)yBB_HGIGTwCCGp{7*isxjxWWyUQ4_V$9BmPSj_8d(7>Iq?kJLylXbcDS zf>Rlh`22;Ru*NAL@d-f~`ePu*VIm}kyRjGhaRC`I)q=+<boXWnuHilZ@Clhaa$Exi zQ3w@K8CB2@oiGX$5sQS5n*Rh2bGM_0432ytKawv8Lw@i9N+$x1GAIjAOu`f_zymx& zSZAZbxeLn(n7R@=Wb0~Ks8;l~siQxj(E9jv&Q-2tS5fca%sLbooIrY#R%u8&UYLkj z%!Q=40he(P_aSLN#WQ?{t>goqoweX8M5&c0Bi;x=eYA#Twl@YN77OqWImvu6IKf(& zY7Bd!2|^Hso?Wz7)09odpq`8j#!#3s2IDaW^ROCgu^Gp46OZr_S%{Dg6g^s6&~zF~ z8wp!h5IRFqG(=zYLp1thAVy;>mSY9tz;bER!f}0C`j(Sd#>&+CSM{5zY|hTs;MKA= z^fTS3q`D);rii_qoX+?psc{K4Zmm*8zSF0qcgA;C-Q;?mu{n9l01KB^Epk|MCApED zm?5dJgyi4`ZsHblb)z*R56YtgJg^D{y0hHDr0)MYeO)EvAmrO?+(rKTh{C+~oLu+# z!MbhO9A!#9Nn;02S<-mPy93jcv?QJUaD_YmOfx<8M0#q%qOm<%jICE$-_%i$mSe53 zW?r^D3v(*j^#T3dg|Uo!bzU|{^&ZbYw|#4%V{SP?ois07LF-55et+bmcg)Sb)ohfw znK(^ypm{FYQgK&Dn^_ywoTm(EZZAdlL}Ro;9IPR5Ap|wh`aj_?>|%Ig4|dy7peO4^ z#Nz}0!N;Cj=zL|XF@)IZUz9KX&o401UM#2Jg?gBZGQCL%dHb+Mh;Q)h$4Lv^>Bpw( z`z&0^Cp~-UXMgqU_r|Pdw^Ki7wb^8EdBlBWJ%#=}_A54OA61#>{*mNOOujn)OxBz6 zTBr-jLQpTweUXxC^bBI8F~ZOZ6EF!=Ao-k+rC5eI9POofF5x6WwWEw2!xh}bSA2&P zg(`*8kU~~RD@b7{^wz2^Q|PT@0wez*52cm}<VP9!LZY!75|N92X{AJ@5+phuVa9wc z#8I5U?S5M53aTN(5<bI%XqHEKjHgJ$OT58Hd_uwgY$f6$9^nn%!eam%q2Sgn{Xx$> z0X-&dX7|<st);D&R=1Y3Evx3ylwz6Kg?lh0tF!hlPRU{Ho|}5p6PAg~1Z83}q3Rfp zOaob(pdI=Tq6D~!f`gf7u?pwlJ%l9*N(^P*MWJEr;vh>5Yu^}F-w*71Xi2Ntmg`}i zd`%`FU`b{q?~^Ra*;<nH=RFV&&=|pJjxb1eqRED2X&|I;FX`TEU~B}hhP)4~YEXM^ zP|9eB)+zx;HQyG+y+vO6>S&C^EX>0KNU0V<O7<9zlt@Zg0#eF2SW7A!(r?c1J-=#d z|5a1Nr>gxul>%z?T8^Y1x~yc?=B!t^qGnf;;@8(f0+WfLWQGK&H~L@{W?&g4XqRvm zDY$`KxR0C!G9QXV0(%n@Ty80n4isY24tC}hg6apWt1dfuf?LQcHk?0hRCdVYoD_A` z4O=%gK3*x;IiLLS38ZF9T54w-@4K)E`*9FQ@eZGnnc9;YEQQ9n2x`-C6|&);GKbel zbWRCL>FmQ+bV2t1n;gvQtkS-A%Cqlww2&{~!Cg2EXHg4B6hcX~Lwj_?P1GF0Ooc{h zjD2`>|Mb?yV|z5?|I@WjZ#|u{$=tU^Hg~yBA&WL`vy$IP(z!JD`|b_RT0GK0@+nDL zlapj*@-oTrk*xc0247Hf6!Rp!Mza*bG+e|NG&9rGa1b$LSX<%27^B*(5qAwHb+n_~ z=0Lk(c^qOP%h|DQN>YSm`ULLaE=;7Npf&;!g0^S}$xQ@$pbv&)G{!)3sqZAwdvbir zoKd~o@v5(%?ck!eRlC?p*mmF6R@IV}Ks9|Yd)<e2vicagLz&<&za0-LVJ1pf15(le z9EX(n6s|x@-UVGT84`ufqc#7XY~A^9X5<1SB$ts4YiRme!V|~)P8@)QY8YXXaE-vE zF`EBwCS;z($TX-}isg`aZp3{MS3{n$EMJiyE^vh>s-XsI!W-Lh0B`XQ|Dy0XX)5gK z?pZ!@`NaM*r`|u`whm)^ma`qBnfG#jw1cD~Dae$}kSWO&`ts{&T*6)4!+ku!OE`{a zrxwNu6cHaLQi@5;#%MK}Gv8P}g$>q0Ha#qT@LIZq?k;!i>1#h1b@P6ug^y&^1CrbT z48ay$gd{IXKExxW;RPfMUr=DY=5v74)#d`^Me<Y@9`J@Q>Ou1P2+tt-%?f+Cq6~r% zjKPqyoWxnY!$%aRY)+T~DQ70iXoBTgSv)_Td-e_yO|yJj0)A+O5VS;VbVOGS#R!bW z1kA>KSR*%>$i-kT7GfpVU>)L-fbG}|iSljyLiH)eJO=M6ESy2;4coC}iaIw@DVb?h zZ&^w>vs8F<(y~;Lr4q}?Bg&3$^6edXhcED+$_#<?C^C&E7fTVa7`G8Qo#J2`z9V7= zYiTT*$xIHfS<FnBIh$sUWZatlUyF%$vMI#Dp-h~9<qv(H9aAFBl8w_ik0*GJx3FgI z8^e;l+LkPyvt;uY@AvQt-;kMXE656a<V0Q+h7@Tf)}Ru_k>b6&Bd^o>w=UeeaCFzv z&3?aRxU1SOi>;UHbcKWCLry4DGs&@EiQ|@XJUsK=Nu`*%s7#~^d=Y@AXn|Jfivftm zEJz&J;1(pFPw_8)!I5|tfy6ip);Mbnzq)gt*Q@=!)=nR^c6!Duye@O|=#wn;)$R9f z6<PfGsb`KWCC!fVqk}kslaR`Cp`u(-9u?q&U`Qp-#9YkBA}qm5Bq0?~AQfGSO0J5< zkV;<*srYC34g-}RJ<FN%@C*#WaE!!Q?8H8toTaTet#mY+PckCSB@Om8m3nB18IUHl z4AP8tVlS@3(xeP`7%no0{Y)&zHyGw}oB{TT!34;>x;`mw!36o+ueEP$Ul~YRPuDGK zr?bjb%bX!KE1QHo+Eq>zZsL4a$Qk}5WzI&2u16HN-i|b6Jw-`PQYbo)(;S$B{rH9n z^QllYT)=VwGq4}I7ZN*+gqO;ZBE;c3zQJ!1n{n6)kHr}?j23rZi8Pv}5c9DJ%di}$ zaTY(3g=8I22t^>-a)LW5z#G1(1Icb%w8u)Ufn@yzzCwzSh3prG6UNUsy6a`yz=+(# zZFwEsFmD{M4Lw`(%6L##+QFXcu>(p4b^k@ewmnHHuCNPyK4+*wJ-k72kuxZas54J; z1iIg0TO0M-IRf2C{v@qpA2Q^G;%0V{bP^yj%tqXDzzwA!F%3fm`d~UFzOyh766fzQ z5MzmVMM%v3P!~}ch!K!_s7c)A5GV&h<<G$(>Gne+(jyKA>SKWi)hp*X6q=sQ!qTZa z&-T4_nC*=8%St7+@i{pjYRR>GMu}e?Qp%VM%QU5aYoR_Gp$)<j0jc*MSP7~BWTfC4 zq%GXQWBi2=_>8ZRHj<0Bkq@oW4$@vmU<ah#99mR~i7{{kl@?QB*G}x@b#3{?G&TgR zV}082VpKK`48N<4j()Ewt)<?2tI>yTv*^_mUYxe5PiiLb%drA0@fV&W4X#V5Bb34@ z+{P!AU&={lge_wW0ZGWUoP{BdF6UyHtu|FPc9Nrwev;eDsE)pv0ZG!D+%ty%OtK`C zm!`;x_c<|996XjMxTtYcOj*?7cd4Z@FJ<V4GSOt<0uG0&>W+Wut4lwmydarkQdv9& zHCZWVwv$QyS%UhE2cZ#~AQ)kgl1;!g%*7&X!)|Cu!ZqB2M1aiEeTck<bs5&QMpGS| zUmV{UUa%R*g`VeWZK$eFyT^&UTerw_nR`leHR&$r&|js}?(`xwy}>^exuJNN^T{+H z$#n5I-s2-A(m9B7J`{!%+)xfu1AeH7#t20#v_~gM?X1TR?7>&GrIw_|I%5f>=B_Mb zTUM&?HXNuvsm8+ahCdphF{VMP_b?K11XQ)*JPa$?2t#(HB_Byn+aQ1ErfryOc~6_m zi?I#*AN|wc9~tM$W{lhKDt68|+3B>3lQiRRaY|jk525@$WpucwBq#}uz$o0nP257E zm1G=6;0r(0K`S&{#rF}9FKdY6T2|x;S<kevVZFWwAFj@BBewv_rG7jWi$n3VITJ}Y zjqLfzCCGZm3*~+&j_TYyN?)@S*9~Rii5jSdb{G!Hp&8?`3Tv?r8?X_(kqRk=l%OCv z<vQa{hdF69ca-JTrKz{|2xZ1QtzK_mwyOCq3tVesvV`r;0mY=n-{meHzq~TNKciBf zaUcA5bUO3dRGfzNS1~6h>0ngDO7diS7yYS?T9^CEQlnY^{UR<S8P{+fpYa2~kU5Td z3{4S=R%nB^7=f`EkI9I|Qmn!nY{XU^z!99lDV)dUIAe9gRR+ExH`Q1W#Zdz82!T{{ z6#8KXmLh(Yw)deDWHd|NCtxe~;U3<g(rRiCp=g6J#9%l^U>xS-49+4IH}D2;@fknx z3&m(#PH=_`DxoHP))?y>nljK5t<V<Xh(bqnK@ZHuChWig9K>;)z!^MUqn&=Ncp1%4 z8TkvZ@d?tZv(looBL^H&9W_x4fshv83T@C4lW_@Gkc<@kgkc?_M02!4YmCDLOhtNX zx@LYV`$jUh7^|=z`*0YEIEoWEi*vYuEBFEj=D7lJh6_rg31oikfGBiA9}I`gqp_HQ zSy&9_S<U<xxoF3b;V6#b0{((w14{!G#}Ev|ZG1wWjVvWF07Eb>o*hzrLitV98ln<7 zK9QgwduL6S#+oeXzmvI0GSB`<t`L)!<lJFRavH<)uneoQ0ed!RK`%Lz5xR$wM4ZJr z+{7(NKJP;E`UR5Te2_dBgXDV<B=5s86SMGsqZay#Bd+H6j5tu3vhar#a5|P^B{pCi zG+cxf{t+YqU%+`ALv}c#6eK7fkib+%5Za;#WFve{Y|_A_f$fsk43wc*&HOjj5-R`N z3%$_?gE12Gun|Xa3%BtYUy+-z7e!^%LQ`~rR7a--E%YtL3+%**8PtzqEaoEtn{g0_ zkc_|Z1umPJ!_f}mXph*<THt$5WY)J%M1DM-e^`a$Tgcf~j!>Y_HkK!d##F39B2J;; zb{ZKfZfBE6I@!{1S^0g+PTT&ELWdTyOwl^!4Gbq>JI>(}ZsQ@I;sr93dM>y?a#9ry z(H<Sp9ldZ6hj19ONpg_q#miqVRGb-Td9ljS%%7-@Ao-Rj<*9*4+=P_z0~E?q7)9ZR zGU$cg=nHH4r!YKqn-=ti)@!x~<1imeFfQSbfEauUj34TvB|4%%24EltVJ_w&4%@H; zi8z5|T*D)z;j_H!dnx+XmuCJ(vFa0geG2l6hCA4{Lldk;_gyS`_fqeefekp0b115@ zq{iHR9E&_?IgBy8TsHmbbzGsloz=bm=f7?Y%{aGnoh^chAIfU8Wa=wSBxi@hC<+&p zMs?IgAc7!SYY#JKVJ=o<4R&Hb4&WrN;5!QMWWk7jn2$Y>gVWH=KM8_aKG};D+{R1T zQuqLbU;^f20pgH|qqvQau-#4Wkq1Rk6mBR3PgH?7{Lv7N&<gV4lzmBS_LyzSgnZBq z-O&#*7=tO8irJWh<yeWWIEZ5i+rt@SjKT~o#}=H#HPoiYq$c$}{<JwGle+28$p}r# zc+r2nK|SSWk_Vh*Q;Yvn+_lS@Y%3WXIm(a1AWfhTro-A4jxj7v;VP`np(IVBDyl)> zft(p5ug;c>Sh!H<m&vvaJz#Q4$u`Bdsk-h7dnfE)RZ+KGVT1ln7TZbY9P(=)gyA*5 z;5#zW*m9sc{1J%8XoCS5gpnA98JGiUpmA6QE_I1N7C%4ZPwL3jk;llG>;_E>_#qv7 z2L$Cdgapxhr;=B{LBOdX`?j1FbJ52_e6yO=t0vpAe`J4z!g;gQQMT@8nf^L##TDGf z9X!Ajyg)kM;WNJC2k5lWV2f<XjRJ5%8Mvb?nxh>e(Fxtq9X-G)c{+DbbefYmCvhYL zDV-VUEN`6?8z)k+>{Yc5E3P_da@?jc1)7+hr}6x2Ynz~MmZ2n9>cUb;n^r|-ntd<` zqc9qiF%9#u0L!o(@kqc<9Ks1)1anqOdVC^Ro%b}i^edZgSa8g?f;v8%ZL(_4O6Q58 z*=@(yagc9b$4%VA9X!SpyumwsL8b$2njt5ov`lt>PbSORr2I4}PU-N>hrxCpn%T~_ zm9eRve9r;7P!L5>6iz6Ga_~eI)P^4#qAx~5u9%Ncl`H0J^O`SLot0JlI&k;tqC&Pj z#yf^Rgc~_*%NRZ7+oLf9v+x1`pxr@cVT=L`N5dFQ!2E-nr-SWfV}<#Q?80vBK_YJA z7T)6n><@8t7WsJUZf@ITV{@63^#}4r`BD!33$z5@d*RYy)^SIvF-$=MPT?V*!}}Oz z#`fdX;wjd;;dbn_O=5A(2?*}bDx}zJZ}ZwZ82$4xwW5}(M)N)v<1ifw*o>pNi%0l@ z`lKF;RtP_=`RBLgfo|c9^uSy!$0}^VZd`<9`3~;lA)ev`zTz8x;@4p<(9!mQ(dQQ< zJe}8&4R*+jVsL^ps-iahPzV0#jlLM1sQDDKJ#LH`%*YUo$3#rWLM+F6Y{MQL!eN}p zMWo<19^ozC;XS^A?q&`4$a6%CC}O+XST7GFeG!doxQ<%XKvPH!MWG9NV-l=2M(gA0 zyK_2+@Tx9*_VnuGVp~ovd{7R)w#k}R+fdBb)~MckrnuFympYEcCP-bMgw*!~`~|7= zH;_8_M{~%wPVA61u~BOpSCIrtXIxTQww`UHjN?Ed#;oqz5ocO~*-n1Y0^t~j>@=MG zC<JGeLrX-WGkRhOW@9dvU?~!?4bt!uaRlrK{joewADJ%8<6{|n=^20JNg9RJLs>Y` zJl>xLM`PctmZ253SZcL&W%=dwNUpn-6^dSh=%=P^>X;I?A?Ey&#tB@+YkYz61e<Hf zikxsmX;eg2_@X`<pdtDr2BR?+6EO*s5sSH4ie*@bjo5)*C$!NeZO0iSb}@1Q2XO}H zkc8WKgqQe$uP~e>gRn<V<cBj#p*$+U1JzL*K_|5cH)(7^j5Ng-<T}NQ1TmO_S(pQ6 zcf$&-#tEDRO<}#hhK_0+Mc+vqxfo#9CypBx-oR1Z7#G`$>Z;PV_f@kivA2fUE!<uv zWt~Kh)64`Yc!sSqEWs{Z$Cb0py6Aq6O&DB85*{P^Jj+Fl!y1?_(5NnOa#Xt0PFk3) zd&X5kJj76c)DH)b<WZ$u=EpUCWo_fklKs=Tg>NvD2gyq-v_%ZeSdIV1*L?uSkpGYW z-(AAaikj$LaF;02dlx~1gecJxLVWZRqU1zdy$jJs7cE3D#~_60T?ipKq9<|=r=I$I zzGipte7@iB|9^XrWHxqZUhnt3XXZUK@ArE);VdpdV*LbH;wuP=yB6vr5S<|DpsJjZ z&cma|B06?pC!bFGgrjsW>|$cXq4MTqa<RLT>Q})$#ad9lHy=yk$cJ-GUxnnyU+^P8 z2I5y(u^$I<3}<l(m+?EELh`Q{`6YQc29qHJF!Qj}VKMSENDSkRHohVS&MF^Rfz6Q2 zb|Q1j*)v+@_ZoX<7q(@%VHCe3F$=Tt7v8{fk*yt5Fcr(O0(-z%Lo&qs$hqB`{nv}! z(X5rJ&Guzg>T{Jj%G_j5G8dV{BNV^H&IpTe70Gyo!IwE~;uwzOB)($K6~2qZIDu?Q z9Ac9=fX#5C-B49?WusLBlUaX9c4k!!vX~lZfOe2YE`%&L39{&Gkj1}*gy6#BYGV*2 zoN$bVgk^<(#x7^=|Gc7-)<=eF*6LD?mru;ZQAi?AKoao<l8_Pv-wd-MiCPXxSUe<g zr*H*MBv2A*Mm~&01d>3_nr?OabJqHGN{;f*v`HrWEqVc^N?X3ET5>icj@jD0nEq+j zRnwfy*tHN@r_b#mzvFR2-e0A3VFO}O>>5WX^uYwIz&gCgM+~}7VY*Gt79a69KHX*u zZf*8fE05&z@6fVNJf6^#F5vUWvLAO0@)9#x5^)RNSxjGyge-m%B!m;VfJ{gjR!9iT zu@(}>7JPt&@)cQ<C1WIO;`vEyuc+ks$mCuDwbUyO*paQOZSJh@lx~I`**I#{p(<Cb z7XM(|e(RXa^~*1_$PQN&Mitb@P>jVCOvhZ@!F@c&Q~ZgS_>T7EOh@#GoO95nG|tNZ ziPpYSt5m}uD=um~l`yt7GMCdhmQ^u^xyq*pLh^Mq#=wdhh{JE#hl4nR6F7wnxQb-l zL@Mqg4G*F3<YOaaBYQ>q^Qxu)R7-B<oGZ04d;GQvmGij9MDubG<K|s$XuchmU%vPl zf8aGfBg+kLfx-zDPy=<*0FB{|Ch$dTbV6r@q8A23PP{o`ku!vZs040Mg+|u$SKBr* zH?}=Lb!-kfGi+jRAl<|0YVr#wET6rIjizGUXOwt1HYQ&EOvbaZxs5fy%ytMO@GB-` zD&}AbRv{KUu@8rF1m|!8*Kik)kb&pO#2fsLY$>u9GZQnnWvY_~Oma+hV44SvsUz;v zw68}Ib6#z`huLJ5$AHq6)!ppTv5<Vz8T~N{mv99)a0hpBAIeRt`6!Rt=!Fp&1HHC3 zJh+MHaNCQqFnl@c4DqFvMR-&5tp9Ovw&sy9O~x@?#8dnQ<rWJ;Ei}PmY{Wf0NA6TE zSfT<d!V8Vj3c(nPa16sjECUxX{`(b^BWcF48N&_)(f-0y4fiz{RgbkWH&Xpt5N@2W z*@eb%=E5>nS<Ud_M+=!s^<}l{DJsmAPZ61QR`w=Na7BI;Kp_-I36w=8EW>iFKn6A2 zx$)~q_GneBmA&`x(B|fCbTp$-MgFsN_ZC!VhRTBZht6Jxobuh3ScTP)z1mv*h8wsG z*~>l0OMHNA*VNOgsjH#&N!R>O&Od7-TAJq=8_GY+4w0Rq!E}f123g^RpWuc%Xpdn0 z2RpGFC+=ts{W(eLE?<@}IX)c7w0zj{L6^IvAO7fot=NeZzmre*_&4;y04%@HUIT~l z1gFxB>h59Y2sP=Vb1;3n%t;+jFzbuBfjdaUpZEYHvo#?v@<A4zAF}u=kPuo!!srAE zWjl7>)jGB@Z!uaWuH86;v+yLw7U+dBkeE;5I&L8i>39Vv;+OOkfuyMlywDVF(F2ms zevq_Ek&H>=GJ3F-%qB_04-D6=?Km=r$iEK4WGuisY`{juVh8r&A|Bu)@{wCED2l4^ zLq`n4NX*1iEWfXX1X2@kCt1A`2jIx^OHAKI8XiMd!CSmTjx<&=svrmhu?UN?1gFxp zb{)+-jJ~Wh!)*jVAgV_kpAd`9h{G0~!0-5o?`Z#+m4X4dgs+eF8!~0|rv>Z1W!!d} z88^DKnak{s1*EZ%$H;(*g=K>a3Zpnmp*|##FigS{EX7)Ez+1e-dklQYegn&pm!R~@ zOJ=N8VWMIq?5~g(nl*@()J{Gj$tw>p1fnClqbD|CBQ`;jF3CO)N76qqElJN#a&5`y znV00B)sYX8{KIIB$2_dWR&2v|?7&4xe%(d}GVu}QpTYSF=NTx9QmBGz@PZFIpc8`8 z6X6*C#8}TTfr%-Y4iyJ+4i|A3zvB(w;v1BwTt-EQr`n+qvyZX8EPXQnFcmVBdsz33 z)AHvO7o5QZd_k5>qCgj1{Db27lFb<};qr=|Jet3<mj*h-@U#f~6?;0#jH9l`qfJWd zU1My6cLtc<)C)7s`PFTq=D?s1gf$a!xQv&`NhGfL1>P8knUDw*a2Z!{8z1oruIX&k z@P-dsrE5Vw&9TOyR=nwmPUwOEU=YGE5@RtLQ!yWFu?}(Ai$ge$6F83xxQSF2(2E81 zOXW>E-r+MAWl*%B;S6r#8NMMG`S~j(pBF*$dJ|5=k>{V8=B$jf0^2KHdXGl5sIJEN zn}gJ|VRVyCtFGi$FZAKE>(DA(&#*d~OWIm$1bnAv!&?ultIS4LU5+1CUkKAfFchP( z2&Gx2RZ$c5(H!9ziwT&91=xli*bfb7Z~;;zZsQK*o{-*BKS7<+&z#qoKxN(BPy5)< zoZV<GCZD)3pMvs&RfgjD8Se0eH=4p9Z4r$Bpci^$E*4`sR$(pHVLdis2Q(Z&B2MBG zuDsC3kC$sGS9p_xn|OpL_yh0p71{oz`hxr@hT<p-PgF&HG(iirgdf_Y3;O)2g$!cP z9oUCAgK!QN*i0&7G2$Sb&mkn>GG4&3Ielb0ADfeGR`%;D)M|NE_qTN$P6{_yQqP2$ z-Tx^9rKLn@s&$~8h;TVs9XOh`pGW3U9<p)zqBR202^+Bm@i>epc#2P$_?pTt=3@!g z<05Y24j$l7Wc!Q#BJ!gEihv?3|8q+)A3vo{R;2w$XjBXJ*b;M3m6E`ngJp7lFx0%i zS26Y*dRXiEEn&$lm%U}x;W(b)JBqyHP6kHeS3G~uTKt<ehHq&8iR6A}P2eD|qv#h- zC%)+CkO6Aa4yXO<&?i}G20fGUKr6RbJk+$AbRSC_ZZ2V!=zl^5R6`v!LR0vlH9DgU zf-nTXVl>8JEMl=4JFyE#a1>PcW!M}>1>r|ZR7yljXo`P|<Jyn@TMcW@165ZqH3zDH z^yI4K;t}Qts{b-`*-iyy4yTcXn@B?jUgAAIAnO~}2Xev{MNtl(D39u>3tzOtmN#0* z<<zBGZsAQXayK_3Fbk6VE3gK!I0nbsIK}j1$Xb!&8E?DZ*CMhC_fHCC=k8F&_9G4I zkV)n)>K}(_ZJIiU%D7%!^+7WNTsQ+u4Y&R6H)}4L&o{^#F3egj0a?psA!~Uo<{}D9 zum{ap^KB4_AoRgJEXQhWz%HD}MO?=XJV6Ge<k$*o33jaUkzBNljp}9lp?7EVXO)nW zRlmfk6P8n2Kld}=QuP*a0paG3*5WdQkN6v3k?jNfP*g=dG)5D&Ko9i901QDSCSnpM zV=MOJ0OD~J$B>9qxQH7dvt{ffB2~wCwG`A&4KUX=sznQPBJ_C)n|m?&PzvtjAu{m- zZ}ASsj~onOfh&sQ7gRts)I~k`q6OL@2%+c;cI$BoixR8}0}?tUH%N9&*|MswY0O>8 ztBPug-rR=$=56kz?rh6>j6P!iPVQ*hHhF6fS^dk*9&HNBJo}+P!tpDnU>2Uik8Ro? zdvONmZ~?N---3Q$EjlhTMc+MEw++?5ehjONy<w1=l!K#Uhat8r&6U(O{={Z&#?pTu zWbUBuYG!t~=9byqg<}_DU>D+o>Zk|Vr3}JQ%)lJX$3kqu4(!E2T*ock#RGi8H<;KB zIYD+!)zKPl(f)Ho(#=E!q7V()Z=Hu!YW0gx(pvhzUyCOWov8mwP3&i(8ZgDYM2%T! zuBHa8u_av}PQuC0UFLHQvLE~d_I)9b#$-qLm8}dlP!rA28hvpQNyzez`<@v5O=~&L zyx$nij?_@g{vr9mYt-Zewb2r{kdEib@txWgCgB0zAlP6s495#(F`5j1n2LC#Nu5~L z+*OT<;Ub?t<^rQf1*<(~a$SBfGh1Mv>34o-XGSvf!H@+^ge)WtvY@{p3kzZ)vcO@G zh5i9qu!#lA!izux=!+qk0ttqkUmq|1Ic+b^I*ZeY_VO>Qun~tq$cE4Og4!mNp$_Vz z9y*~j#vlgQaRZO=7@2rsGHLDSn713bwQHM;%t5{_-;_@~K3Oq~$xs<pF%X}iWHlMe zp$bOecRWUECzGKps^GDcNzHpkVJx2+RKIP{6O}t2J-YLjJ03i-tgbYn{bx`E+DetS z57;%&9A+g#gDkrWWZ45C%a6id{0)i4%yK23vT(#yjcJK10utLJNPG>6%W*y(GrE6L zOkn-=`stir|8OK^x2x7pF{sPtnA=O?F2xmRy|>8gn)K{$5pCXY%`fxu!6n?lBamLh zE4;=}*-VB~sDe7^f>~IC<#>TVVa{$c<VGG8LT?O2I7VVR)?f?n;W_@w-i%exL_V|0 zPyj6uh_2`c$2H?vHsC1s*bL_;Bf3R|>Lak&hp&rewBF^?a79LXp|-}8O%|}v;sP=k zmKL(_^si$s+u1`BB?-z$u&$6qB;z_H0Sa+Q@V(Fnw^@G9+!R6dL0|O4Jj_QlwA?1? z9ZkWw?aa6Z(qr)7;hkw)ol_kjVsTaHWyx7UUAWjh*eZz{j6|HoO{78=mW~X(z<U%_ z$a#383aX(Fn!y(>(Hd>g4ngRS{s_k~42QJKpxrZ%V2RF`9Gz}|CAVOrMKmMIEaPHZ z<{$>I+&PfED^{3n;~+@I&YyjtUIq448ES^NG72GQM{UjJt;J-{E3h7$u@yV93%juo zhj9w0aRt|K2fyPnp5Qg!;1jZ1OokkAg?<$}mW$ER$(efdnZ60_5*lz(SK0)%Rz0fa zXfL;yxtuH4bRCCBSGCwOYJGa`$Za6;ORX=cpv<s1envTXq894F3oX$WozNLw5Q@GS zfzh}LIc#&UAZ|c%2hPmm8pNrMFLU~MbOB4+){GwkS;#34*cH^BgE@5jEt3OfZVr@_ zmzzDp^2$73AtMI~M|@6`;T-PaK0d&h%Vfxoa16&JOvV(bScUAAJu`B^8L}f-$7}BB zUZefzj+S3@=~O<1rH8LHTV>sqvt4QZd!>1gPk#B1l<nLog(heTDeIll8&c+_yhkDm zQtoXh(d^SBIEAv^lTKbs0|+Vv?rPGq?3FZiwb|8JE9Z|J$vVEcA8ag!12~8iIEizR zOqK31)!o$kOS9KdllPj-YkgzP{fz#WAHO4?&%l5@1cXg_nFnrTQa<L1^BC-6GAzVm z96}LSN~o*J_M{9M*g|7qiwQ<wS@s1y##5w2=KmI-@dXB!QvxNyRpo7qto^Nl^&P{5 z>bqL?$|g3TRt=mjTBi->@y1#?<imB*06owT{ox2an1I7D5{yl<J!SE@(B_PGE6-r+ z97{v2pBgw**WX0F{`;(K7PZ<Y^UBH=`Sct_V-aE@S+E5MAz5(&DY%u_q*dB%<_W$` z8B!sc^b%$=NI?!X#7IoQL`Wvi!Fn8rBSUMrm^9xlG=%eH%FqJ+FbI;>3n1CO2$JPx z^Rr#$H))>R%r}g|WW4^D=KS?GJ|Ln1Q5Ph$QLzxE4l#vIhPBv-M4Z5wBJ7cinheEI z1|2aThmcg1J#V7(D%+SPjt2lg@MFmaSyopJf-Ex~vfM%}w>D(?Dwbg-9^w(25swcf zHsaF!cA57XJslBFAfh#JL@E(Jz*D>d(Q2N1NOOBf+!Av=IO3kk^jz%25u63-Fr?uF ziWQ@Jf_m`Be=ryuic!J&jS5bHd|Lj>Ukt}^1|^G=T7;kn{)P)<g@izHBL`6(oiGp? z$W_8*2q?iOvCiVHUvO5Bm2wPD*y9CL`Y66>b!Du=cT{C~W_ntHEOayCupNhx014tO zZr~nX;uYS)NH7v$CDcX>v_?R2lNNBmyxZ7_DMJu~A<5_lM^bt+-3O8+caqZ$V=)o4 zF#9Ky*65Hq(b$eD!#u=bBep^kUkZ}=W{?b!#Ao6?J|R09kpnp)nNkStF{Fgn?yy|i zCzlLu?SGue@3q*EGbK%iyroQrM!!&Fz(#DsDV)X`T*EsQcGq`4HSB|}%VT=<hx5o_ z>$c~tlxRgOKmEb<-C8n)oj&AI+6~S|lg^p*sH2XWXLKFHLLC9@WO}zfkW>7=jvIK4 z5BLZp0h%Bqe-6YT48hZDht|<Lq{qk}&3iPTTY2tCc4F%MG;Zp?JTB*V$IMf5P;dOh z`!72CP3WZVo|VmAu0+Tm)T_tLWu<@Y?=_<IHzm{yiRKzsnXe;5+L0;Yn1bn;i3L~$ z70Yl27jXx7@fsz5=8%j&h{RaTz(S~4jWt+{BwWW0-1^z%Vz|x3V?4n#6!=A3aNHbb z3@AYM%PMLNf3!h2gyKJtRTqX0h=r`eeb8_c={HaB<F$59`iSm+wftls?WPVr$vqi{ zHB6+^`RN#Ei}QY^3exP9IliTQM~Z-~{;T+*2pHVl*%iVQ6;KJ4Q57}t^4_`K%NXHX zf7Q434c&6u{9MMC$_O2yUcAOZyucH4Ico9q?osVXK4$(YAeVf#AsWFS127L}4>A=c z;SLW}LS<AzHSCAn^^YFgD`70nsahwfd9P7dowCJTTYZ0?BfI|v^Imn#1rF~+6%Iwm zF4F~i@@Wc6shj4q&2v+<^##j995XeQHW}Oyg5LOm;$`?7Gz=+gGFUMY&oQ!`$=0$= z@1RJx#Ok(@#Ce`oPW9VG9wC<&ku9h8?JRfjn@Yszkc5{oGILp=6I>w+E`w@t1dz=1 z)AKvdGg88mKCSyK(bK3mrw_SEWp~X*^GEf{B`yR<#qm~^srj+ys<jO{<(m?I9>SI+ z`~*pcJABX_`yt7CbYbu6Y2jVM8<$l>e|9RS9lmU4?4oX$IMWKfXs*%LV3ALq#6x5! z;q}k~9T5h}nBf?KaTt#uGm14u?Q?8j8BL~b-#SwNDzEmv#LBpsB&+I*R6s9K*$lpF z-k@GtmCZ>lG120r4!mq`(>J$d^>;KVM|pu4hGPU+1qLgYU?28F!)c@-1E0{(lh0x* zVxf0tPG7HgX_j;R;3n$OeAx=9ZDO<Kw6#`Dl|hV(USU^u<(j#)6y-t9s_RABF&*`k zux-}^lQ~(7{i=`(X;88=+3XSMDxo>Tkx(QAS^UBB?B~#+g2`a1$i4wvq2VsFRw9Y$ zhzyjg%ql~x%J$OsZ#zc)QCIrIc=Tf*yI^<w1Fn82?v*#py{wYh&De_9_zQt7y#pkY zTaajq6OBX^j2;+_w@`@45v3zS7oy?{iCmH53ROHOI`L!Udj-@Akjtele@<fmD?e+} z_d$zGq4~TzkUfAkzkKf}xS=Ylp&lfqeJ~E|a1E03H;~j<L?u*%7n*|HFa#hF9T1FO z=!gCoiC-}qwhl_#_*>GFQT{L;o3I&i*nyqchXfqQ2_)evuHz9N<0;bd2dq^%JYX@_ zAO>6U2+xoXQ`LVmOEOHe-sVzLfP^m*JcMJeGPh-TjCp)(2{z*(F2S#w$uJbVu^0Pr z6|bw=kJ3HlDT(^d$2MZKetqY#()yo=>7})lXtE;@@*zJwP#R_6i7Jrg%ko;GGrFQb z24e_@R?}ME<8q)?0vZiRFxje8W{@9lD1l$#j;g4J>hMK#v_(5~!YD*yHs)XxHe)At zAs&Z8+1nJqV6?n6YZ}?vi7YV4k_*=02#I;MOord^4j+)eHiuReL}PfP3HqQf`e7XA z;vjD0du@}t`!NH^@$?xlqg57s1V`<Qsm5Ze+ZVT$--)=2>v)W3$Uw20<SH6tC`Ms4 zrei-Y;uap^8D66VA(ufp)Iy(HrYxjMoAj8|v_MH*G*%)8+p!yaA&E}Fdq~2~B*X<j zW<VL<zr1&e*FhQFrt5~6e)1H!LTcD*{Se*#skwxvJvBEs`sI<&mWLN4<0R7p(HoL^ zKW1Dk@Ap75@G7L!!J^EBl(GE+n*>%=+f-EYtDVx#;c84e7apg-G8f4%JB)Har>PTO z$q`_!xtuA&OHC}|%sKgNF5Cxam`B&jCG)bc5JQ1F6eW103EH3|x?m_GFb38-TFvL? z^TzJ1Mg2>k_+#$6lr;om2;SiXa@6Aj3l5-FeadnJ4#^EU$Y35e;T$sI)rid<J5a=n zOV&FWDP4a)k-jt5FIn@Wv0C9^j=X9Q8FX^n3v-~4mF3UGEG))ytiWCT4T&!ou}F+R zp%f~iA)3Gzx90OF9aelK0b!6tOh+^pVhgt6Bu?W7Qt%jW@D}f3OSI<mikVp@^*NCT zk_#138x0YR(HM*IP_Z8xj^h#@;uUg}b9qq$<>3c^bjCQW#s+M}R_w;@`X(<!8WRuj z3@`8!-;tfw;EbQ}Gs>bOY9Is=VArlD{$+O2uKi`MXtc_o#$g(!BMN)*8)U6&IEah5 zj3ivcT|C2Eyh8!jbRiT*5qP2kDxnIhq8jSK2mWZ)(3Hc_o{2yVZ>Y_BYmP8lr3{V4 zSVUtHq&!JkdV!ZPQI@hI8_dXulJG`TG=mR1p$mf14I$``-sp=6NZC}e0%Q*TjM+cd zm3P}ArS>$=;wDmY2aoXtS-gk@g+b{yl=sr=el(vpdX?u*T?C*F+93!-5P_MPg+*A5 zo#5JD%xqrL&Q!Y9sjKVL(Wv_;^ID^?%v|O(7>@5czIUF#U4?sNj!PJVNG!w-?1SRX zX6tSGcl1|{Az<4W>&kM^*}tFq!#wKn9d87pBSJ73VUYQc;$dpvNNB@Rym2gSJJYhT zBd{;fkcS1AL@8825XNFWZhG%)s2n%ey~*@Dd`7k=)Sr+CWiS{+VZ}sD#%x4kMH8*A zNnsdsQl@{XPE#&AU^1p+cr(6)NmvC9*N}<|J`_(}!b4Q?WeqeZbuGBwRMx2sE%QpN zw9MngT`uoSr##z0lJjGoa_Uc7F5#r4HC#a)Yq0^_umgLbAs(l28du;#NUm^%*{!M8 zFdG@rx*LBCMHt3m3MBqTSc;X{ig+AB0*>Mg&f-4O@DR_NYOT%69%IAjyvf9$c!L}y zx(JHl7nDUMG(&6jL^y_Fcr&e`g~+UugCh|MM@}wcdL<k=dX;I((Fc%R^+qeS$56~e zG!|kTF5n_0*I$FpPCCQWRO`Q9(wu<aq{>8NYx&eWm{>=7kq?z2>#Qj{V-UjdD@Nly zF5n^>vtE5=-Qrnut#vN)$NG#nvckW^wFRXVWl$D1(FD!W0__oqj_8CiP*4mru?oAf z7l&~a#+C$&EGU9XsD<Wefp#rTxeb9#bU;T8ZmC7(QHB{C$y_5K-weZ0WbtPw9>CQd zOu=d##4)(GVegBHZK(jawO{+*^_B+;@$3<vYjK@BRs1NezSz&1TJbtL3fc~`A@8^l z)zn2f95mRzq#^dDjpX+<Ovij|LnA+K8=y4;(F38Fg~eEgHQ0)6IE}M@T9B&}YxF+L zn<QMt13W@HUf@r>#77uNrU{bVyvT<FaPy}VtHQvfZoKJ$9_WuD7>h~RfLQFnUL3(? zTtO0?T5;4yKIBI+6vs~}g|euMYN(G!XpWX>i_lgk&02`UXl2UK55o|NNtlgjEX8K* z#6cXxX`I1XBq0TlkO808R6?*7`dx=@RvJAeZX2*|(YBO!DRsB$Hy-q6HAQm1<~*@$ zCG}2m<rnqJ5S}@)y@=A@=q2CHM@jHNbx296g?jMA07%K13`gm)Z*nw`WP~LBc7z;j z)HpY#qv}^$sVGALWK#ojaz*%fG38OHvlO`lkRo>$|D)I$;wXNHa0V&3iCcJ&56Ie% z-5*>b_j)sJy<gX}{LtAEZ0Pep$uN<6qs#y|7ORh5M?9s~TieWK+vKBc>of9T2Ai=3 z+hAx<4JnYFR41-JVj&h`4G!Wu?x0d<b{B}m<jyABz`*|wmBD3NTD0kx!Ce?UOMlAU z+}=DHE6r1JQ^%E5CR-)+l8^{$peCB2CAuI8eK8ngF%A<k11gqcBjO;De@6kLFNhMT zfXWC$B(~!cULa4PslA~o$+Th)5^)uG@d;m0paV%nQ#3~aq_Nq5OXqn_yljnOR_r3# zN$v_QeR^{RWM^qEZwCCVOi=^=!>!-)GKbFSf}ZG&Fbu`77>}t~i*<;@UL3-4oWOb9 zMh4#F3r4U)WQ9dT?r5gdi7$#VIQS9SOL`0>9SD$4JrR}?YQJK{w7M4;jNIIn!S)VG zrIeZ~#YAr?<<h2*%;(3Izl!&(;V1;jOiLkn1V=$=LP79HKX7A`ex-EH;^kk9z9e$- zcSKdCfNgOBMd^`cElXLvT$OFlYcCIF;Rb(2b^G6pmf_Y+v8Wq8l-M@8WnRBx6zm1f zu!?C7M{x!&UDyGk2s}|9wa^RFjD|sbd4;x!2$hDbh1GTyNWb3VA+Clkf^t8EakM)B zy10z8zejFLwZ5<e_JuhXG&+cK8qA8sT+G9`uI#fg2b++HyLg0J-Ke49CjLOZ5UzrC z*DFN<dUpl7sx;;~s5Dn+IPL0cLRqff4wZJ8`rVAvo=V+%l9=9@h8cK(?<hhnRUt9W z#B9ukp78Y%vO7@2+eovwDqI}YQ*EuJv{f&gNv8iQF4`uK=cuMnrB+frRKHbbi+Z)Z zG9e^~%qJR)u@oDz6+5s8`*8q=k%&{cf+VD(IQjAuB(H2Mg56YzjJU~|n`-!Z=b~zx z&E|rtTNS0U>Xu!hMP3ym*jR<#<-Cf@bldPGRb<~)fhXI#5uP=lBjX1$(@~g?D9B1! zjdeJSbGV9Yc#c2t7Vq#8Uy+}c^9wv6ZDYAqK+D)@y6np+1!HUVlB)yLf1Sl)Vn)dv zGL(vHuBL2alo0~{T!z4wR#ql=$S>coh-#>V0CdJ6jKNq)0kL8-90g@H)3J~O!?lXc zxXifd1nJLMy_c<xb(ja&Ai_OZRfTIPvuqt1SuSg{tZh?u{XYvb+2v%-<0yuAn7b6i zOh{4mM<;YcKMcZXEW-+{LM*mmKW-oeQgpw=nc`a%#ZVVgoLi$OA}|UQL#Q85Vd6S& zAO(KiIr1YC954UZi@uZc$VtaPP<d6uJd_IB%bE&fHh9R_UV}}?p!A?<!4p+c4PI!4 zc4&`o2tf~oViY35?F+*u#N!A~;~a8?k~ZYTFQ|jYkh?qyv4!=ADar#CquHg|U%cZ; z`?|K0%cze0J9|*m;u4%JWCCPHqc9pd|3eL^4*}s<L}MHFB70vFgc1GNhWpuToN`j6 zR$j&_6K&)4=iX86457%q;Es;1?m4HZQvtPHJtbwZgxL=5(G?-+jvn|G5=A5=5-a8- z8q2XCEqYQ5MQ4P-whGvVlho*1(UMwwy@_9H$$^&Ys$<_-K}~L;FpkFu20U`>z;69Q zZG!aAE4!C&mI|u1uu?wEMP@nx1F;BeupV*Phy6&xHQdG>Wa0(>!UufB-!PGt7C3{d z9YY`SbJ5sEV-x!Z$SYCq|5ee?^;OS;?CbQJ4~LgPTazs72Ois)5~`F{zk16}0hy1i zo}ws*5-5xA7=Yo3#5Byo4(!4K9KjjfLMm<}cQ2|SC<Zrppft*$JZK5TaBK|7#w$J~ zCqF~@%@3cbcrCuGrKwT%Yot`R7L^ZILwz)W4_crd0uhXX7>2Q!j5%106<CKoIEWKC zk0e~hHL#WwxFM#u%A$ps?RNtiT*=l>%-2#@wKkD`b8nhvQDfi=X*W)MwiQ;qe(2Vm z+F0>uTu^3s8)<lfH)zwF3t!lWVifesXb9O58bfLc2|PlVE=BfAv%bR{*P0SktQk8z zz43HvaSjSnJy)ro(`c=`CD7I|Y-$q@2+lI2X6OLfx+37%!nQIkTUb0CTUkA}wECEV znK+IUaAxbv2_N`EwnmOuJf=?{>q~Flt#^P4{dZGfW6+0k@%L5ss#n~|DqCH@DaYCk zt(CIY0`_g%u#&lL$03}<d0apSp5p_u^(RWWqA<#!ENY?w{Lu<Q=z$>^iV+xtS(uHb zScx_L-PwAW&^sAO->q2s#QZPmYIq*!!fL5nmTKzy7BtoUo+P(FTQD?wl9jfNOm$Ra zdQ(*hXu-&@a&T!{g8h^px5T*utMuiu+WEb7AP1H(Dzcb{>DYmt*o6mp820ZOLv?l6 zMNX>IzVI;gw3bQ<Myg~k$^bTV<U}sGpagzKD-1#mj^PQiu+&-@1}lEUNnF7Tyo54{ zT{~)_9=zcPe{?`+gbp%QH2jB&0SJfwaG|7hePn0p4EOIVg6W7Po~L`#DZe_Qmy%U| zRU$`O^`*ZuT}`P(tN57d7Am%_D9)URRq9$wW;Y6puox>5i|yEl{WyY4xQh(DL|<}D za&!tDxk`;HHl8+~V{NxU)gJZDt{mE&<N@Y2E2<?2D`nJ|_JT;8N*7BT_IC<TK&-;k zWAs*@#93H9=B*S`OO(v!-Z-CQT`grP+ac>r)>k6ZU|(;BM@*;VIb;W%nX+hXuYkJl z>VQw#D%$F5sT<86+VD0?Ph)duR<-_>8bkPvuP8K>eItfrBr=gZoZ^nA@WUFcMfqXu zErxMeEM+OGR_;xEh9T{gXrs3*zB2Qwit3R0d%+jY;g3NWjJ?>8R6M{#JQ|{U7qHY) z*M8#J%=$yE*A%d1)5ZiULB_Uu9FZ0zGKsV_B-#;>h^J#d)?+(%ViyiVcC6`CWg@9Y z)^%rn#FuWOCQZmzTAkWO8Le*ZqR=MfyE(VIs-tqdelGdSNu0tN+(rhTLo((qa*+{| zL1iGLHf)nDXC$qOpPZ}N4t1%)ibr<Yb9;54t;TGj;-L3&+SFP3&6K5;TJk~mGFkqK zBejd-(LaaGOme&lT0(NYJtWun;x`<{Dcr*&e1(ZM;tUUzgD323iL|qe;f_2v<om|= zZO4z~2DUqI<ARjG)udofjYkG6K~`7RslgY1XoDbxU?9RV5~DE{8?Y6Jk%0S1!yCNC zJ1E0hBUpho*oZxl?KhV0fb;{D&?4g_Lpg=l#&=aF8GR)PnRzS<ji62zL7f#}QSes^ z7wTXx=Hb*R)(;v)au~zD(HxV<+3RetI`V*%f3JDyH8mL>M*9|`n2hZtn7z1*XUN2B ze8YDXWcd<<2TH>emCz7P(GqRY0iDo&gx0QyvcuT0J8$}900v?LW?(kvU@kNq#4#k| zGOpn22(4jHE=;$(%9~qwhz$IN&oGYUo)8oiKtU8n36w@fG(bZ%f-hPjXr$Jz7tu8f z;!O`6K}oW;6lP)-B)fND4-O(3j_jAKEF60s-Ku01ujKwzHLu*u=A;elqvSMF9pQj9 z^aEE9QoAW0-EzuWE5KTkHCF|-A#1NOWbLiPUL@co%CROZ-~>*>v3Ap#)(@Jo>G9F& zW7GSlN5`w7trZv9!P>`_3s>yp%DwBVl-ADnQ|MQmPrmpV8F+&a$VxG>AQxQl6QuYw zMF(_3G!`Hh6(~}*Q6Jt2KpRA23T7Y*E3gv3fna0flM3@Iiie-Xb1{l%o`m|_e^O1k zRA1>J8=pmeKS0@T@0$?Lfhj4HQ_Q%5><)^{jHEoDz)76NMclyyJi`n8g}3;EY-6ai zz>MN>M;VkwIS`S(vK!BtztnSmqU37OFY25@%5!yFI5j%G--LCr(lOXoz7mLz=!Oss z#2|!WB&?W*d02|o*oau{#c$Y;BRGi*xIIP-3ggnb*KOY1!CgGYb9}&81dXL+;3z!C zadM01_@RfN{kao=B*;~(dR&wUAIh=bHilfda=nAIe4hP*VLA3g!y#P4ExbVRcoK!d z7=^KziMf~u$ulllaT#}Zn?}53sLpcgwM85?DjhMqX-kJG4UAp$$YNynGFzF|d|bsV zd_Z0+H!!df+wc;vkz)d%#TvvS1DP;RWWzz(iF&gWdggSMr@R&7u*Gn7)z!*7xxrC6 zo?V>d0#zPcTd!>+l|U~ETq0PG-|+&qSz0$p6dT}(WCzm+@W;)gTaGS1I<9w{+SD~8 zIWk;{ROky3p-eM+JIf~|=BmWj2@>;aIO5*S^d3n3j@ZdMh8>Rx@ky^*(xCo6Mk%ER zY@>nSyisy>DN;@(Sc1wD?$}NX-KJ9jw?^={?U70;tFt`=49&=hB{+ifc!>{inM6RS zh6Wgl;TVCFxQf5<9^ddCohOqG2thxr!2$en{qXfo@>;NI^roIn^vtjS+BCZ5kEa;) zGqQ4Kape(D4jny_Owyb91x#e)ZIdN?R`uIxWtTH8i=Sl=<U$oc<>+6uM-kTJKS_{q zCB#LLFeMZT;~1Q$u#LcZDu)}4MZ;-qXIO)4h?q`U!%bwLK@DMsy(wVKG3Uni=To1R z3l`&Og36C1t0eF+ZXpfN@C~xG!e|H|gkv0*U^O=4FwWsTB(fWj=-lB6Uj(2d!XOdP z#18DogQ+H~;UyDhLeGPOsD%1x07+hRND`M~1vH$5B=<hDl2m8ZLSqD>FGgS_Bugeh zvPH5)zX_xFmX)dU`deG?+5i5R%>VUAu7$R9DyI5al^$x+Bi873EA{k^XR?*E){{BA zq6X@qF}yJmF<?a)w&Ed-Gdakh5~`sd>SH1HU@wl~Eq<BBSu?s~71m-MV!@e(Ey(rS z_z6^!+RH*53y_(}3_ip0<%4`F9#`=dMQ2kpM|*rnt~p$5MP~$I;v7m(YjX`5qlw4l z%5Fw~u8Mvd_$rBl{i-sBNt%>825WI*b9JIU|72xGfW){L8f4LjAd5eOL?pox%4in9 z#vVpa7Ohv!w=CN-b#Mo-4rTPsOpTtR#LEU$yzK$U2DB-=TNZsw;=#`UW82!0-Azp% z&0Ztm5<iYkP|648k~upPS&-?Hki>4rB@~!Tj>8@0Q4zH<1V@mF<Dkm3e)jN?;XbyB zD#O(-)0FzEbskxwKcVd9F!luVrm?$P7Ny(`%1ch_Gk45bW;h+bQPjCmVjh(=%z%p3 zcz{QEg8cK@k}w#Pun}#e`L5dbuu|N1PeQ*tp|2#40Q7C#$*R$N4fU9*#CS{Cmv9rA z@L{R4^p#kJP1uc7aAS#W5DtlG3DkL-_bl#3dpW|3;g4J32=g)166!N#!V&UCLbcsh zm>tq0q{?jluB+B_j<VX=QvU6=Jt^HKIp~Z27>+IY1h)n3kr9DkF&+~z3yDw`YAvIb z{l@l=8ORs6AsO;T$Cu>8XW_JvodFd1q6;>{u!!Rq_Tnu<7Ms+ylN7c9IiBhdkCwjC z8cq1~7+cG?b09Yya|vO(C;DInreXtR?pu(E(>RaIxPml%U#PWSK<kWl-+3cp<VR<O zVmz#vhFOS$gt-E1unoJg2NL=boWf;XU&QmYso#5F=Z&Q46S6GkBmf=J4W!f1AHxuV z1l-2&_zMM=aLThp^Ik#;XfGd@52=t3-hq6u5FcuU2{?%SDkp}RitRWC%TnrVXoEm> z#`2~5JvMJ?9m)N*`qFyCnS0Utm{6|<<S6pP&ZS;9p3NQ2c9k?!Zs3lz{m7%9UZ&Lb zkpMhU4z*Dq4Ix3bKwAW%2OL43WBNQkLjta<YCg*u@4a1B-qb?_NGdiX4&U${rHH(` zEqcRhe#hb?@-5>?fOhDGb=ZQ-%d~bYSr5S^SO37S<?LWqu;Nf>C0p4lK8(SuSs)f* z3r-^gIo5Ep1YeB78k|Pw7`9TZk6~{u&vu=^CC4NwtJS4{zFAF@JX^3v32S|sFl4E> z@d{;FvP9r*kK!c1dlShVEXE$}Ljv*;Sy8y75*Dx0TE|dcD=y}Zgr0;}ggFR~Bur*H z8j_SaY+0>UT&G+!`bfI=;Q&tHBu>GRR)us~;7D^Frt70A9O+-ZM)TRgnku)NKRPnw zCeyd@7T;kcV{+qXc*bbuVwDtQO;6rbfDbz0ha5B<;Qeu2#ASTIcbL{{H8(5gjecaa z{txTca<>ehP<|bKt&nv+1rP%<499RBxA6=uH*mQN7w};NZGw5~jK)X`6O0v2%*Fy| z6hvVZg*W<O3?^eO)~(elZX+AL9WgkTzrY?t2+JA(iDM8XmeH7jnK+6>9AB?_?~n#Y zjv$}%$5(iV_mF`7>_La|djh6m5tiUA?%)MTkRjVfs@`zNY(!xmR^bwoa25BFfsb&C zHD%{<Qmmg?ZQ3qnw6TfINwa?<j(@m>&zo2Wn_2sDY|HRN5V|4+W3UJZVcueE$*5LN z<?@=n*&;0&M@tvPXB-x37nV~?+as5-J(+iTjKc&>#5~Ay_aGieaUK^TvD`%lJ|j1A z<v|ke;1eWH3!IS;a$?Fu9T<EjIwdkLlH13TaVeoK<OYRi{f(woKJqDd)IwvlM_2Sf zPYl7YSb$YnhmF{Uy-2{5&6>}Cwukahc=HOc;X`&vmNkcDTT4jRNw!I|TeXU-v%6d^ z(K;Sb7%Nl$E?GGf(O8Y`&>&fR5@&H4nRthf_=;>>^sF}&=eHmHF$$wG6*I8}%drxx zunAP6952m!i0o+33e>+PpSXv&ux#Zl4k@U!jc=pMcIJu?2;M<-Sg?~T9_YG@@(qvO z6vN%z#aN%++twA8R`>Q>8M}VrtY}w)`F|c^MjcUR)RfS6;s6rxJ0zI<cmxURJ-*@_ z6auqs)oLcNm#|8-`B7M+g+x9U6A*(vxB*GcJv@Yo6uF`{B!x}ji@u1&N;p#8nG|<H zBxZnf7j80S>bDyBsacOni#_=l$)A<ji~Z1WAMcT${3?&?s0}NYU=tD``FR14@ChdJ zH5>Ax5*nZx{4oH-A#0QCfwD#m>8mwVeugG<eK6T^OHQqj%$ZZML?x$o<+#G&>BZ!m z(U7&b6l<X2GVbF&3bHmUq9*EM92Q|C4&y%F;~Pw@^%m%XaLm9wEWlnQ;5g3U!){Ls zF%voW$VMRp`utxn>ihA$Xq)6B_imK&>h6s)Cd69CWYI5A*v|JaaJJ!=NDYOQd8pP? zB=r4BCAe!z3ZY>>B!sUx&eF2%rE-gs=!&ms_#1mRbj3nc-bWHJ7xQoyefLu#!AYFn zuV2=taKE72wN(3;45!1SJ_LHqb!Q%lbw-I9ENSyV3j`nt!RUeB_!Uc_Vk;!Ni;xJj z!whE>MsYZzmcBa)nTz<J<~Rv7BI7kyeSM2fZ07||hl-_gL-OibPKS2RBWJAVlpxi3 zP8n^@FKMoYCh$WS48l}w#tt0BAsodiT*Wm!h2&Ls@<;Nk349TV&XD{YhVht&`B;y` zxQ{2lS=mQ2@fz>(1zE{hClrQcdR<7yM_@FjV>V<(Y{YIH#3|guYq+vPiohKn@PxgU zhV7UBlQwt1MAJM`UfhBD=cPa6;fFul^3i(9c3R05*b7RRusSl&DyWD0Xagw_;gCYH z9lMc$<FFSJ!&#;;A{p0lA8B}rtePWExe3E<7;cJjQJ)8AmAs;ar~!$DF!qYlP0pq} z>2U<+r{Mkb{V9C^6t)~-UxZBunIEPcqJoE;$Qe)3!7N<BHN3)KFdgRK4%;tQIfkF& zazkC(G3Za-$X!;R4V1)b*C2_t5xmeG-4KQ$7>aOA!em52;<|^&_<}6NR|t*aiw+2Z z+^=Jl^~B7?ltr1=OnHR1ml}T8$yKeGtV~o>ljXAH+UyonlO}50$@HL2*+=7)OP6T| zmwJPL+nTJDYm{H+G#En=iJ6#%If#Yi&~JDS$*G=_Q_{d9ntQ}QjOMLwyP>q#mzU*p z&EIUdC4*T4orYyy+@RI+_G`47A+~brw`)oztFz3iKZYU#R!qZOEW~a+gRGcWFtJiB z$b-s|m9-eL*o{3%grj`wJNBqvQ317hNt-*{^OBpjou#+AOS?&n;V~Ip{-*7LMJ<1m z+_`XF*)1t4ClOcbmS1Lf98xB(;W}R6CBDHxStx>HsD}n<j+PjVFpS4^%)}y`hm;|8 zXbP)BZ>lJdk<m7#D4mUd1sui8nIcxiR?G}_`Q0617=vk;fdfcE_9JY<@IW;*Me`$C z%UfJz=tMcyXCPm=3HeYwJdaYoj!|VlPI_QG!79K4%sa*QhKi>-ZXw?p8cCgHCw87= z+(q^qmu)9++OgY;mocb0v-3x948#;1fGp-1uHqUV;|ZSP8Pbt~=P)D?0`emi3$Zvs z3%bkwmDY=Svjj`A5xejk4&e-5;WNI&iFD;dIY=5SK+^dQ?Go8`61CR%q+>}4Z+asP zV=xEHunE867%m|RH<5-H_=X&0SYddeDjLBHl9^2*8TuNMsafn9JJFuGG5lV8g0qN? zOvIf~$N!}i(pIO@sv#(jzZ^gUPU1Y0a1FQd7*FsNpONJxH5_Dz8O2Z>zn}u@!VjHK zYC#Xl$e_-=>4V|0Vh-kEDOO=MHev_jaS^F_hPN<KC~_hX@}e-@Q2vw_^q2)SE6<y% z7=r1TgSm);l&YgRg=_d7Qp$2u!q}(8EgIW5A%It1X=+zV9dVuQQ0gn%xToCcR(C#f z+?EZ#PZO=2^0f*G!C1_~3ar6;9L90nL2e3gL6kvR)I)tVKtnWw7doO7GVur8DfFS} zh2a>FNk~uD#;0=;yS2QTfyGF`Ib1?A(jZ$+_H(QqI3o|-;0{kzK`qol<8xZ;=akH# z#=L2V_6S6OgkuCoA_B9q04uN=2XPwL@c=LI315+o&DI$%=e3|eSWEp}cvB2zQ5U}G zfSw4$7+5hKbFmyTc!y8;j4zP=!FQ~_pdXK<u`|t`GimP}ok=6l>fA+F>ZopSq(<;3 z-4*m(njKy$Tdc0~mG#(*12}_J+(rgI;WNzaZi=8NJW(GF&;>!b1lc7eA;%>ym?JNK zfd?v~GW7OUbYZalpHn(7#LS?j)q$a%hpJT$(5&g;UrK4carmQG%4ya5hDu=EYYJLX z`FbsQp%p?f5RsUM1z3Z1h{GNnMG}5TCO#tTWkN$fxPZN=p#a>m2uqNN6G+AlG{2&; zf0$$pkPpj0%0INdLW#stB;o>YARS*&B#DxW30R8d*p8Q&aFy>|wO3u{KjscB_hR+i zu%+#n9NsBu-p!dy0NOy7)*k<XEVUnoU?vt~BM##T5+G3>yP|o&=Tc40W4w_NPvIQS z!x8RHrtjbxB=qNagD+RKnjbkWZ7FHVM$83K7?Q3EsEtM#2S+-mF+C3|B+bk4Z@RUX zpEwq_lnls926&)4d@%&$VTEMQF_1xqOSp+QD0+>;hw`Y2fNNUIFU-(aJ}7_egMPS; zEXnMIQ5%i05Q}l;Iy-Rq-r&3j*HSqCq*8oR?N{yfp7va;=OGi{lr~1M0A|((?a>>K zg$!Ui3`dX($3ly-5b36)_e}}$si+Toqc`K)*W0qf=p+9wfz?7oNN~Q8;5OqRPU1YO z5@-!v!euyue|}x_F<Izd|C~Smi8uHPBPq%SR}?~Vl!2tSHM*k*hGPVFU?)zXB{|Un zUC<qau>@<e5nFK(S0TBUmSW0cc#xt^%4!*J?D&AcJV6FN;v2Hwq^^kE$cw`G8Na|C zb>WR>@PRMFF&v{Y`=-`0n`Mh}@NC{Jz)GygHta(@jw2bj@c`-g2*WLkEnH9-5x9*z z@MeWe&%s6Z9)$EC?3)s>t(NVc;guW~Zpr7c<Wim5QbpIt`iyh3l-9nPEk<LIt9-j7 zq}cSq08o4k=Wrg6@eSE-voa8bnfM5&J7fX$7M}VO7wE>@BD9LWWUY(E(#oi=&co?% zY7UEs`n8Q>R@)C(inB*_>Y7Iu;#k0U`vPR<UF|bZV8)k`gvh(B;osTw-e)(7K^Tm6 zSdR@jjuSX}UvIG6)pq_rVUlH}Gzcjz?VpR=`YCP8X$iDS+|AJkVc3Wxki{Oy30%Y_ zIKudo>A&#>1qtbAxT7>`pcW+5dDxD>@fn2)y(mh9HI)*Vn4(#8S-3tWe`$(A7>4<X z!B(8WWhCJmo+2Gt?y-+Y5tKwZc%nLL!3*AKfi~!bE(k?W^u;Jd-ZQxwCNMD(Q!yP; zn2!}$bx&KJ$I{c-d=+n2V<Td*1G{h(7jX?0$$D8m1MuT2(l3w5!;$|vx6?a}P0CNJ zW4*Uj>fdr!>BjY<P5CTsZT&z!T`bpqa>*JVk4adIAJ_Ii-Y4RRwQe}a`wL)^Tz``W z@u9ZoUYAwFTrE>neVMjlV~f+u=CiBic9Wd)g~xb`bY$QyKI01vY22JfNz_FH^guuK z$AC1tDDybn_LMvQ%LDl16s$okKH&?RJYZF$88+eOL-uxXenf2o6EPW6u@Z+KaScC* zQ&Dx-0Up8GdY^MnmFC1bWvYn!HCImB9>|Z}efig&O&OwK*M5dkdsT=A>g7*Z3aLX2 zTjtkw1hd*6%no}%pY1{AB9MacKvgt`H<~=q>K3t_Hv0U}s8fhoBA-Bn5^=T19L*7h zEBFS_C!`!(a14c?YCgr-!FM7_hI^>QhpIrn{N4VArhIS><cpP`5)F>v8S*}3H;dLt zLBVti1&-ioy8TuMJ$kFFa;Q@|)R8&%yQn<ZP6oTI(4HpbNkg2u5$I+KYgm}MdZH2> zOH%)xqv00Q&yWt+47Oa<Kpiy8&>EJo95?#1=zl&S|L_2hkmor&X#9#%*odRJjR&Za z$%cwee^AT$gYchZEu#%7Wr;TWG~??n&<Vllia{8GQ5cU2n2afyf%(`ES^Psh%Fuj% zA-iizEKiUD1Ix_~i7g)r;Kvx}^L_(1KG$k`Sh#-g2s)KNO3)c_1U`V^hu{E?;0->a zAqi@NNQ{R)frcwgr{M*@;48ktc3DNg+-4iIpI+(oGO`W-P=@{E0Qpq07aaOg4s}o$ zzVJsdx}raZf??PV6EGJGu@3982|I8E3AlhOxCZw>IR*HW=ZPrAv}xrmqm99=6n%-Z zgv&^>f6{|bzJJL{(O;wopJ95#@e`eK_ARw@G<?V52`}*)Z{Yi$a{JNNmqeqi4mDcq zGrI<84uAAUIL2clw&Fa#;U^Z`5TRI%B>awiuecG93h+ZK^u;7B#xlf!eIk7}<#~@h z@iAI|Y1WEz2$Fw|!xrqtejG(2&f*GE@E6|T6SBVM%m^-UMNxR7E_~4nr^p;fM*V;E z^p+K^j_k<;3H31uQp-|HSk;T?gt}F+q*)6|7Jss5vE_$sp2hTR%*QRH;vQVcdRG)i z2)d&emSH*8z_E&6F>PeE<U(=$1UJ}P!)4N8B_ACB+smakzl?>U3iKNuda!=JO1Xi> z<a-SutKAPl2u43hF&K++n1yJ>U@dmwH=MvpoW&K~!+rdLSCHc4L-FbM{)a-^u^WF0 zK~MC@U@X8Iti?K9L?+xmP&G$)Ou~M=#y3>^$VQ9S81zx=Sd%)cbr5gDFaztcABT{L z^SFTPxQR48L<U~r16=-QRiG%`Q6AM%1NGsLVDv*6o_=C~i-MooD<q|>*4mcBPU(yU zU{F_iSStS0E682-a_98l>g(uLtatbNr{hxKPi$iPj0!O$PjtX5nf}5yf-V@2C@e+> zGSTrH)fQaDXN>#K&IA*`>-Uyws6GA}F;IUbw&RHqH2!1kK#j}vd5nD}dRcHCG)6PD zMmq#Tg6V`ryo3by30Voi363B;Gwle}ac_A2?Dey`jW|3xgl=$pkMw`W-wbX=4sCD1 z#^ct&V$qh>w>TU7xJoMLLQ=U3j+FlNl|2RqVhA=O4lnTrWl4PnNN$YBJgmf4Y{Pb3 zfWD=u0~%T?>UYnVHnh;USl={uHnaHYz3;3A<%5!?sYpi#-b1q3LiXlBA-JI;Dxp5S z(H8B{5#2BdgE1Q8A*<&)GVuq<DLQ5UNE`2EnPhCwIyBtC24fZ;vysIRg*fa&R;Mh6 zYzWVm#V`%eP#}92!%{5AO1#2Rg<%Dq`Hf@FS=5PLc_IXj3+eS-!9sI5Z`Qw6qWFN% za5H2vlt&i?VHCDu2QDHv!8E~m%*HV!;ST=BXXNLcv@)8&7p>6=oe_#&7!2w7&Fw19 z+EjMv@|Piqz&K1n4Ax>Z_TV5AaUAE6igdigXACE699gy5o>d2a$gbLCSsic$PmtSq zGQ4nlth{<<3!uMO0EINdQdnK!MbB#6NUzQ4&8K(n8xmkCZtKlA!PjE77LoZhz*J1b zEF8r#oP@$Eu^<<kpedTevC5V)y#*Rh;|$K?Dae^0{wI@o9@LLr#M!@$?`bZsu4riC zNxqG_*Jj(HG`5sfV;a%V^r#nq)6Y`^T39@+1!SgDM&2R|<svKcLduLgJWvgF(E=^e z3EeOVgAtBVn2s4(jAf9r_7d65Sq$0ne;4RrqZ;Q&C`IHWIgk$pP#3;vi4ho$g*bzA zc!um0<8lbWGQ{EzGVva+7N)tOEj5K&^1r>V5H0=n3btP;x4D|M%x4H_sgC!zTvu0n zShB0z8(G@PZrZH=-po=;-CD~+XLXrV0aS(`LeLZaF$}{o7FNu_EJR}|)*v2-aRQfc z9e43N9^);t<j7*kg93<R!;}p)0qIHV_}Z2t|9=ONMizYp8CNwaz*0%oizE-cc4_>R zd|x*5L}bE}lU#;78o?I<Sb<eo1ARr&IozL-TcmYw8TD{yIxBVPAVpptd2a0>rAY2O z3~Xbu7~43r3(=S0n6npikvTi&`iSY0x!8Lk3`Z~`58Eb8c}Xcg;S2V<WU)2T)f+t1 z?2&!abQ*f`98t~(4|6V5B0NWFb$c1!>W3|!S5r*YpDQ}5y=6u}Nx^#T!$F+DLr4ry z@C@(pH;lwl9gWZoKJZ6tv_X4xg5JF)DT)q^`g0iNS&aT_u`U*FpX<Xu|4Pn$4&r9a zia<6zGKzK*9W0fsuJYy1kVH>J6jot14nr~`36Jp+pO7Ut+YCCQ6FTD(lJObC$u!Bl z*@(e*9LE(r1UHI!$$%a%_Lc~&%g`3KX)35)2(eKrgKQsrPtTSM9W4{p%Mo0@&_@IE z3}#y_CbM~jPmpz#pY>7}4bTY9;fJ}1LM-BO0{4)H2Y86T;aIoEd~Dxv!A~fKUm(@_ z*neJyWillyGcq*OKUN-}^Ur@W1jbY~X&_}>ZrrOx%cGMzTPiQPnk}okrHjQwpP10e z;%+S}Gp>%Vc!^K=hO92^<4_mP{vTiW0no(x2mU{ifSL>Ly>NjW_uil&E^q-ZKt%=X zKvCQVMce~i=ctO}sMfuLf&=#k#k#drt3`2lXq~_J=aRJa`~UraO<&{^bI-cxo_lUR z2Os#NAEGb;(U^{SEX7K!#X79V57>i!pu*}>aT0P{cIr0yQ<A?o<8Q`me|Vz>vSmYk z+bVCU+G_+!U)O@8iMwS=JMXi*uhCDv5@qDko}0+s<zZx_j0AfYX>cq;3xSewK~2;{ zPxvDUgD?WqU`8|!;wVny3@+meuHriG;1M3<1zzI=J{HkCsOHLfywv6Wj69FBE#oV= z%w?eSORe&{jdc0QPxM78O_V@IR6{*9M_Y72Ac7H&2#kjru~>qY_!GU0(Yb&eRNSGO zRr|Xf09LJ|i=>y8yVY!iQZS6w6dESRqnM<A8OgN*+AtXmm{F})Q3)p%KjATc#Zx?o zb8$AmD1^GGhx!OaZ}i6$&=ZjH9C@++H1M&G4fHP5ct9-^X&j`wmdzXOS3nlO1a1#x zDl?vfz65;=bj4cqEXB47k1(pVgYGWwV`*9X1?5Rh1=foS4)V;O@Eq-2`GVXBNPpZ} zE%QYV{On~@p6+bqmYhMxIc7<vL>Q0dSOtmv9IoLf+`%s>LLyw?3OCe*JL;f58lwp$ z!2>W7Q!x$SLo%@kG=_|2v51~&azTbuvAwvxJ9&UlvU<Ybc$@(%j8&{_;!vZ%`eF<V z=~AdPEHeLT+{Rrz##1yZN&IMno!F0i=s{sg!F`8lEW|P_$42bN0UX3}oWMz(!d*y# z|B1X5blK8o3V?~KsDTj}iCI{KL>$0D9K#8u;w0|CdVEK=j?yc)f0FktQUCd<eWi_c zc->_Mw>AY-Sg4JOuYL)nLou<pah7$g55L}w^y1RnSkvq-;oED(FHFC~@A!&bWgK+n z(E@3>i--6XZ&8XG<ceyjjTZ1nAVM$zqY;S-n2KpIL#|ZHh__4|#-4>)zL<kJEP+(b z4cLe+*o`#&iYIu3zwr&aa&#<ULLpQ|eKbHLw1OwPpeOnx2wG?VSk$rX0ofMwa60_K z@@+6e5Q`;Pj<wi`&G-R7Vh46&7xv*WPT~|UBMrB47r)?bIR{JdNaF_m2&Qx&kjsVI zfkG&a3aE-EXbm6uAppS`j4_yipU{+5w;48o_Uixdv{j__v=t*0nsc=Fbfp?9{E_F9 z-kM^ZrtThX^lM&3!a9gkkfz}*F5)F#;T;OnT-cfnT??lDk)5Ho9%C%4-7IfC1QlR( zv&<i3EX}U0JP-9wBzx6tVDhLtBaIdPoM~_VnRztR6L1+<VW`A*22(H%C0r@;Dy*`Y zQq@7X0(+4JQ#BgYYV1aKH2JFB|6o68Ew`rfTqf%nGiv#9#>_sF&Im|U(XdDNj_EIO zs7N!2;_!qw!Z94Huoj1K1i46-J((_*EPbMkTNqoFFDs!c>Y))l;e#&dj{cB*#b6nh zV-+koj3f91e<E*XRtT)YdThpi+{bUohBS%ETq;3ZXfaQq5(mk*Z}APqDLE-UH&j6l z)J7|`Lr3_b7XlEBa16tDh{hbu#{w*LwFFHvZqyH7$Oj7!;{>kZHXh*_-r*DUZVo(K zhsBBVr~-Gif)_fYH-eD@=|OJGSY{q-w!dfi%Hw8hP_uHY>!OTxENpn|>iZOxUzevs zRKOg352+-NAQeSV<(LF}h1p}PFehx4rU4bF5wu2C8{my0_;|&ui(4>0&YkJh*X%hQ z1sXri7^Lr9kV>X&jIYR7oz4*SHE8;3(kj&=E$*ZR710ju;e}~1BO0@@!QDX~;NxL^ z9=JA&zjjuYTS}bO@)H&As4gsZcNx#s;7n^_>;6S%VR~g@F~*f<NwcJ*9R^}EcHs%W zK+>0sv^l^8XV}y0&U90>z(9;d1jZm5GZ2R*kh~Q~Lr57(x1Oy}!Q=@UAvs<hGSu`~ z_CXl;sE+L3JIUj9xJ-K*yM-qfGtADJXya_vFP2WSUo1nB{`+90UX-x8j0C?6dvF!$ zxR1Y4fugN~_UMHWOh61`F&k^J7D>2-G~C3`$iy?ez@K=JuW)2>nUJrR54*ff6h|4< zf;$?b5t@Nh^71TIZjZLUYd0crbc{!=PRt19d;Vo&#+K!&d4g2)T<gwoan(1L&XRV9 z)OR+muDx`49_VbNTVNFlxCK1X9)9SK9_WL<7=*zXi|Lq+$B@eALPe4aXRW+4T8TV8 z+&W;1^?5=rbBzJ&x@jyKZQNI)jkb+XJJ;yeqF~P2TAzR#!xK_-rPfYG&YCNi0J4(! zHV&<*28S9MId;BrkJ@sM@nI)LYW6xLfZDCw2@8I~bNr6nwP^=nM0GSpOFX%<Pc`ow zx{p!(8k?_JhY2w*HpZ#xi`mo4p2uKhz2_OvcgQCJOQ4ULsc;=uYfM8lreg+TFcXK+ zt}YvSOhhzp;AUO=xEqb(mOTrMetIv7zZ-fW2<veWnRtY^_y~z^0w&|h#U~ecU0gE0 z@A%f0tUFbfNpYOY&^K1&<BjFiqk*ik=6MW?7#B||ZCYe(=w*@_CB62vN*d>4KK9}u zB+aQfj|;eh$LII2o4amwzjkxo=dR;sk>YCCNltmy9?OlDEGL&3Tk6%eamJ>db<XnR zmw1IDWVAS%!2_PK7sdppr7-5eRv>IZk`m)4C8iJT!mFVyf%0nfCbrl<2dTK7ml}(y zna^{VwR~A-<T_7za;F-(j5RkOrKx+167^^Vu?lOk2Prs;2Y85YSl56eMp#2~j6*nq zRQ!TRFg0Qir7>$YUVt+gNeM{_b9g01Bqan|r`jaxbb6iT=at6tdNuzB>IiA|4=W)l zl9Y6WH=%XK2ttt%XF@_fi*`*Ye_VodQ&xElLTod(a!AD~<ZDhvMJQgup#{4;EwsJ{ z7sa?b_091RW9^3Sxath(yEB!$c(fDbnd^-%>Lt}!)SOb|l1^7ra^y*z_W12_tR?K1 zwm8la#{(2@NnX$o@i>jEt>}2QrnKPNhRs`B_7*VRgMDk9!voaxWL>~a%mPC?vUXwz zQgH>Jkh>kdWQ2IpuSGp?0>ca}!*XoJ9%$ESrYBk761Y;+F30G2@{jytPWqgGj+<x` z>ZlHmC9Jio<XW~9+m7<*@JcQ-n7Y<jQ+>A5=oaQq$!a;b=UQ^?V9T-OwkDDxInJ5e z++;*@DjAu9bi75S_8bNvQymZlTPD@%a~z}8^nqOaq1}mJC)}~EJgU5bny|(g;w!~) z9iJh^P`Lwj0I|4+Tx>FiViR_EBsHB#4NiBa{JXI3;scz!(uj7YuGGsDZoS(-?gobv zwJ~1pj}LWLWvDQ<{CZ<%kQA}RHOdxOa*p^K+T#3<_$1Cr#3%7a6Q{%*Lwq^omXpNV z6|}55at&>I8*QWn>jHR|K<m0~Ej!0QZ!tDgC(818_Px<9xKNH{>(WSm3t!qt_+ufq z;XK^@*hXLo!Z8;Q@DNYXvKzJK#)%y_<dwB7Yf5P6DOnBFs7=O?dN*~$RytO@FR;?y z*-C?{P0iiJ)TmxGEr%0~ZXF6yaQ~#h9%IhXV~F8bgm!123#ah_zhP1jQrna5c`pZb z^g~A)`;9dA?vf~(O=g*iWBA`$|K_`oP<mM0w-~SUm?FX|2v<}?b<{-%_+kh~AQk6P znRs1M1@4%K`H=K%#aUd$GrT~lURpYJop|qz$B;EBL0hNhSj<02hhDzb`E#@c_2C5{ zgral+Yb_d~1ANd4K^TgeP;mf%BUd0j9=O5{)dDR++v(8vpt!UE=Mrclj^PYSGLuA7 zMf))w1>U<N3^AC8hsZ=|Z^{p)`>-|W^FPPZ8DgQMX`DO_hFvrU|Fn<9P*ly_OEanN zG=`h25r_mXfz=`)cMQNlEW;YS#|KD64T&fm!=d67(vg81cz|rY#-YA+06_V&MM;{& zi>u4+uQ_dKs4V7Pl(#oY*CpVkZBEyIENz5iCg$U3{DRy4IY5JZ_zUmx0e|;*(4K&! z#!cbAaT$KX!XH0<M@hmv{Ek17hd_)_AQ2T~W;fJDH-us))?y=eV?XZow{+ZRJfwG% znE!;t-YUpJ*9L9jg$@{r$w3yk1ID|0Z<3|`s5M{Oe;Cbl>0k;Ieh9#i*ok~09E!n4 zTpCE>4dQdCwgXdDyP3{1<&bfvzT;%VkZ|T>36?@d5*{KOuTYXOB`%307!t>MyuxRE z3AS`hB3E8t_+TPZNkDZpLKAqv8{N?Z!I*-%SOR-uQ<yF|z~Xg;%eVRz96*m5<xv@a z=#72|#b69U1PYSN;;4(3=#CzU#UiXmBBV6#4Yc%0VaLDEJwAMZ1I1&4Gm4-DD!>g* z(GLC?gGrc)g;<2;ScQ$)itRWx$kOK+5wt(WhjX}yH2i|6kmb=hlznxuTy#wblWHu& z_mC|?R>GVybNYDnsm`FaoUYn=h6evacT*)b{fx1;<?#t)8GQ$5nfW~IGh3M1ID~ct zhj0{ShH_jA(U^ffxQ6jzR8RB?*Sgof|2_`VvgagqeuSiC2lhh(K8h>2f%|xY-|;s- zLQiCla6(>4LJFV?YQqbiA**s$y8JI4#E8H-ZFs2z-sLW)W}Ks6v3omPnYpKpC)90{ zX`eGj|E@)4#xCds$z3QWBL=In50YaGQXo0Mj=xZn+)61(u_o|JQU{!+?b7ZOj5%w( zs6IHyQC2NlpL4QZJ<Xqq=ZtR63&?C$Py<cS0<9ng>VpuNVK3O<nf9YluZ3Bfo#*;d z^EE#FiuWiKPW?hr^adrbGh-RjkdAA3h}U?7x9}Op)&X6x3|nywH*xMe$yXK|pE(hM zNw!x+Qeb*un?S8?yeMsB&X^>`5AbI0oFPkSpHP4hha(cHIE6DHChOrkuKIA+9uH<= zgW#w4lq6h0I;IXMOW2FkID>m=If8W(=`fCDeMNH&LD)#G(QT+|U9C4W<b<t#j1D!E zXE#|gud>VFF7dpBKjHn~;&{OKEePKlm&HAuzCd@0bO>fcBL5XmL~2ijE7MINiSflC z*b=2nWBM`vhVv+nLgVQuOZV$W9-2<7ZC|j&BODlNm><Jo3=Ic{;uP{l(iEaDUgIr3 zpyycja>r_CZ#=XIR#_O6gvZi7C6aQ4QwxpJ3=)12Mq?#*;1Yg@#Q6c!M_ZcRlq;5} zk7iF1aafKO*od7-!bzOQZQR8xyv7^oNw8!f-x!P6ZQ9^g`S?%>E~o@o<jkEtXG6$Q z3{)J#MWjVqTHWP3VUILENY*9W&SYD%?vFkgfWa7w2#i4##)IO~rQr9m7LWT}V(uwl z9I<^_ejIBdf-nQG;5?r07DnR=icg@Mg{HWPP7}5A_LWE4X#>H~r;!JQS^M*jTwJa_ zDs0Lqd0fNK#+x3$6PZNR3KCg=NQA>N4HEHOtic9sLK2d31sUTk9+{-PV+J2?;yEOx z4pD4%u^Q`<fE}<P1y}J1zv2TFawEAbG2YVg5nEc{5_~9wYN&<U$eHz5e0~czvRw`K zV(7%QFJ9b!ar-pq9;WaL^=lz}8rA6L|B^{JKaE5G>fuc3+&`cxewImdsDEPoW|kTK z5rz>kBNlV;J=S9{EI5LzNW(Q;M+Sa^EQ^X0wdJ8xc|U=ZxB!xMd(Y|h);}*!znDLM z(ELI3PivP#j*Bw7$iBz}TOxD))lr?^kP#Ur#SUjj9#<0>22f2;SMoai)p5I;!03SL z@tb5s%hFuQk~T$_Y*Sh`<-1%dZfdu0#xi~-s3reNQRPWAmY9QiNW><@Or}CiA=h{e z*Qqp`NJWonEIT}zrZt+hZNG8}N}aVz+kXZjqJPP_Git3bxr?ho&x{-WB=-*?@zq9s zv_U&~LDC@cZ-k`bXJjH5>Bve?`H`2JK4VySZ6NdI<)hU%Q8Ko;D@V2Nyp$4q%)<12 z$+7sI&y5xJ{`q9ad~kteW(hW8Gg5FJPGn3$A(TXU^n+wvHsox;Ilkk`tA=*WfH6>C z6GPt@#!j3<dMu}qh`V2Y`F$|fK?>{#?7#t};w&CP3i3S+6k;A!h7@cSw1mXTb3%h6 z6SC5S(zCqWxq>b2Efuu=TVn&u;#WrQoi8XqY=sW!gE1I~37C%sSb-mK0<y%;;VQE6 z5w^3o+8e{vTJPynd%rQBQeT9b$ktnmwDeo!fyM>o=T%wQ-4TdjEW}|vhOHv#o-&=w z%*u}{W=o@Y+-KlT4Y7SeyTw0b!!eqIMiorPRHUL|3=3s8yDspX$N8Q`G)0)Th`xQ- zJRb6lD(yK{+QU2d1ac+RzgyB;74mY`Q#dCnw4+?@{xqg^tU_ds(H31G37C%gScp|v zj}15o3ohX@B%zYP+FAlF9si<PY9=Y2k9F9H6Ofdj#ceoF=kOIwsD-BRN5FKR9?RCN zSpXkaV<S%E0zTp!d}mO$SctXQiPN}%KW12(eI$TJfAAp><x~#!&;U|yo#Bsx2*YH| zz!D_HSQ>q1VR$9*VK2_$9PZ&Eo*)bF@d5goEJ--P07ob&iefV@USHXEdKBYBDU?Pf zR6$kLMnkkf8?=Qtx}iG)5QyNJ2R)QydiP+aLogUaFal#S8Pj0KbS%ZPnHKk4%5{CS zWqkM^o3RtSa1e)(f}=Q%Gq{W^NJIKeOEZIVRv(nkhlj|5Q!HB_6h$qxL~C?L7x*Fo z127I#5QBM$gNpS?zy@rLwFEgS8}<Gh`LGT9aU5rH9e406vhf}t@DaIYQFV|H#Zdw- zsEDelhMKc1{&|$``c^ghPz$xu8_V%MwqPd?;S4V03U1&g9^m0Do&u|!)c1VIhgW!m z_xON3tbRrmL}8RbDU?QaG)7AVVLarDg=`+tG+^QupDh!&)K%ju@+{Ij`4wxMY*}Mc zLK!ApemV(Dp<*}o;R@1m4feJFA=7VAb`DJ>I^ZCz$9XyW&fY+qzzEu8u3Po<QKviR zsj8Z5E49=;A83;g=TqMNn*eniN%1Qn^B={qxugSAkc9L28NVVwtxhF0MHl!&TB6Y) zo1AUj62%~|K0)Ntx<^-7sj0@hE2q^O1(ogQ{PM%8h`~~<!#<qFdECd(cnZUO)+{)o z7|Nj%s-XdzqdmH!2l^lsgE0}Ym<MgYZ+;}>^%jauke5%6zm~W{N=dzH{=zn7TVaKB zn=;E1tioz+z(#DwejLSlT*Xbi!dK`Pu$CYn3ZMikq6vDS7sg;LR%0V}U>__vg46}= zXnB};i&_iGCt9IBI)eqAoF(@{*k86K{_o-ZsH_3$s(Te4q7~t)R97P|DEU?2qRM17 zA;2lWy4av_IT%j{3U`y>`Xdx0F%D6fg*jM^I3!>rwqY+$A`L&`FNCoL3WscstY<d4 zwt>frgk~j&Ci8?mH6p(fuD&iL5sx#~R^Jv=9`-9@-*)}LTzl{pro}8|R77jEL3;#X zCgx!~ipR0q<1(~`E4`38a-PZ4J%J8Ea%E+SWnl@WkiKU@wvD<Cka#{r;*oIo#Z!Y< zurq=SE9rcEPYuUclw8a97h@5HB-Bb^!E9owZ?f&JGDcMc>u`c0i`l5k#mAO6rIZ5t z0g|lyFcL*6R7YEQVKic~2D`Brl9UWQ#9yenge1ZPGH`OTj5N*Ia~VE$GlHZeqV6uC z)K$y4uy|8$a)ZHfcV&fo+>HX(mhtWyOlc22aQ(z7zd{m@KYAks(_lt4;*f~#*n?!8 z#AW<~EWF0w_=tQ<DH>EoHPk^9v_>0vqXRmjHwG>3!Pbe1If%m#NWu}E!+BiCeP}HR zr|lU9?VrD#q~}G;lJljuy_%=88vKr~?L<d9)}14HxQ>?Xh@uLkqZH*kN~W5*ngshA z?@@Xg4JMkQEyiIgW@9N<V=XpeJ8q!Ba;h6DpeowH8{H6y-U!Ec7=uW}AQlUj`>@qv zVg)v1AChnfQg3s<<O#5e=@ZjKH9QhlUe+$P{FSw)m-^L19%td2x4!CI*4~zrZLS8E zp0-N`#jTU81b!EtsMwt$mAp5;!%D0}D%@3$&*CwD$DfeiwYDzx^-8Flz`5%ZmL-*y z5qj&s!`6z5Td#cbySl6}Z4rq6n1k=J4`*>6&+#X!uc8G*8}vi~f*?n&=*rJe$coHT zechCLmRW8}CB1s7jN)%DD8HD3shEaESb;UzfF0P6qd1F8xQ_dHfVcR9T&r0RQ4obt z5~WZUHP8@k;DxRjf~eJj>?<%4i&==nYOKRf?7<~m!E?Mop)~}I%BYUosE4L#jc{yU zW4T#XsjeTsnGZW~2uJY~?&B$5;uXF^M`M&5c~AnSPyx;0jV>68QOJbW)5wU=n4;lA z%`F+B>ga)as%TgEMdwj?f=qs;j>?j(ZuwMQG3fghmHB>wy#bVlud1!#o5}kMtcC^B z5FUlHj=eH0fvwI2MzoRBGPb?I|LJxZE&XdMWAy#<%M7b=4c_ai3|NlMNI@!IKu2p^ z4AoH+UC{@T*aodx{HI~`a!+OrS>Id<QIl^P-7U0-#q{Qa^24Jzjttzy1AM|~e1Y=@ z+A~x^Ei^%Ebbt?nFc`xTh4Gk=wb+a;*olLXI|7q466LihF~d1ADu^dX@-Q7QsG}T} zX0nF<yRNc1RM{Mo>>An_NiMY&9z0%GeleOI%x%r>jaX?3JOxK_8fS1GH<5|2aNI~{ z;EIN5jCN=bU-ZUkEQg8%NXBcthdz<{Q3S<N4wcb0(Txo+6Y*GsjW~i-T*7r^K;2bO z=}0{@sv}Fu11KGM6lLdc+(P!>Ov~UWVO3>@$9RGlc!@9g1}C<%`B4BasEK;$fu1;n zvyiQE1}bc(fq`s2vNN_ZiXyLx1AKUsYY^RS+ll<t4(k1X%3r!8U-Iyi<8^3GKU7qz zc@~kNe#CxM+v1=LK?HW;7=FTCIBumiL2Y=VJ%%E3tHr~e{Wec}3OX;o2>OvgFaz81 zBX*$34we*rF$|+|2InwtCynw>+qqb|(9p8Ji84TMjwHOX*oLDxjttzy1AM|~e1Y>1 z?6IK~%A*GAp#|EbBf6n4`e76zFa^^w7jcLOSE@?Cv#7PVxk&46%3rD8QSw;I(rQE{ zdO^|o>|IWl`o9&N<4$#zJ?63!)Jm+v_t=gDIF2*8f+zSB?_t<RIU_$xq9(lIgCPjR zBCJ3Hw%|wX!a*eC2`X%-P2285{+VcsZV1Fcgku=8)xCFll=q3djs|Bgap&5}DWTd1 zSWRn9o5_v&wN=0ArruJaZ9T0|t*B2_@@l=@B!o$rf*8!iGOWN_9KtDFz;k4yAGM%A z>@~z*gSqLD$AQOBwC*TQ{QuP4|9c&_9_ee%Ugdk5_qGLc);Xzff8ZkuQ@^C{Nj-av zchFPc%0e3R`H=~IJ!^Q@VDn#0)wUTEJ(XEn7r+wSh7PX3Nq*V_UI;}bq{>Dk7IUx( zr|=f<Ky}uAM4nx&%8<5_ho~gZ&z_$cNrW87^QM@!qm+w16h^|4J(uGi%53XC>o!mR zm6TLbo5d>CniR+x-Xy|%fkM04V58C=>J!f4B?j!Jkwn5i?F2wW#z|pBq@!IGXG=mm zB}Cs|5+s3~u?19&KwMB!0z(xvg$FvI4}zg}V&p2fz=Sqc)o$;MMJ&C&l%9I^fwxl8 znwM?fid$=E`SEDPLQ)uq-AKlD+`%t+f@k;)$wh6{-(zXjfrAmP>hqxmTEiCs=!;;4 zVkm|q0%Nfnn{gUv2&5x{_}k0nDPLxx66GT0GY@gti33Q%El9cL+eb5k>Zk`_jKfC! zgsgoQ|IQq9@uq;aFQ4%~c|R-d0ooljLMKeXX57bP7!T5!#6W~%9#$P>56d?2504P- zs>JJqvItMYbSKP)Xo;SXIOapeR_w-kyh6^nC0=_RIeOk)P!bW?E>L@J8z&a_`YCRf z-F`|py;%~o5~pz=*>E^Srv&ve4fC)7n{WaT@C8LIG`OgX#^?-x499rP!xC)4Zd|}^ zJi}|~lN@sE@+8sCN>Zb`D=un$ccr)`rMu#(52--u=#ua=oQSLux<eAQ7^k2kkV<HV z-k5~t*oS*~2Zit(pc|%O8e)?;j@(m;QxlAiGt`isrmE_CM@9`h)Jy4TmKiFdF506j zhGGmRLjsu!GiHLobj1%-TJS(OBq9~*cz{QEg1$#+2w~m4XeYDhaQy0@m+Szg^=19v z{eesS!~GR6eTNbf!Fn7)DvA=2M0gz%STJI-4Eu2x`eZVIE|`dU$=cq0KXu(e+JZfS zil4rXeO@!akA{S?6!vgr{`E-4G2DjKDH_hck)Dy(cC$@?Ipz_f{Ag{)O7>M|^)wNi zHpeI4%cW40(G%kkhn={ImvB1D%8$+%kBNxJY8*rg3LN`)d2!S8PA-mo@dM*z{rm${ z{E>%pIm?|0Jd{hG0W&FBnPrybet<+Ik&HkTB$5e`ND3WeRYOa3#yX_n5^m!GGU0!m z%_#cdBeFA&Z(Y1~eDHYhe_z4lwT-C#k2<oFV}9FaWq{&oeLT5#Q1V$H`VR5^lvs7k zV5PTTF><FR<O=WhNX8P$VywV(yuc?EJ3(R*ie=b?i@1mUsbnIR<;*ZsD#J|K#t}Qw zj3*4qVpm!0RV*(CDn;~dBop@VBpeCj4NQbl4L%4s$x_5QoQKxwUz9j8k!`m1ip^J{ ztV1^kE7jEev5KSmyt`6cJszU$>1-k$x>1;g%{Yr+@D)`Es}&^tXsm^Ve-U?Z53kVZ z6o+R{{k!DJKoVO;210w=UVeW8GS6kC;}&j1!ng|w$3z$nAYt`^Z1?5zIyq`=-Hxe; z!#GC#%#W3BTR20St_fATH+Gia4#pTbpXO8y_TvB!!GdqlozcpLXQU<el~FT0IJ!A8 zT=<b51=U@X={?1LF&I?y3?5G8GlG8koe{QU;c9RgS<#MWlnf_o5)q(Qy`)s@X(Y>9 zloJSEqC5zDloFjDxzGVV=!ng5IZyk7ei)6t=yHL!>jFjCim?i~+KF-I{izMwhyf?c z@lmEMJb9{szP&wcZ^DwWCEQJru(!kcEODSL;pU8oThwndDo7|V+bDecs_O2^3fJlX zM&|wMIvdpF;hbqVkCH5pqK<4HrPNSU=CCVrd^ms7=W|eJ?_{Oie~XJ7*oQ0C!kr~E z3HT8O$xs<oy2y%)w&;y84967A!$K^=5~x^()mVcAkQ-5XC3ChSegLnD@jeZ?cUkGL zW<+uze_W)}SDiAQ_4LI^mQLqUN`2LJ6ekagP@1|Kn2QJa8TLd-;K{fL*UM}PFa+^P zL4_-9Sx^mK5qZUSh*djjZXLo^ZVc2$bzndTF5M`}($c1CoicLze6+H$mn2_eIgYEi ziMx<k|3te>bhHtJ4cLhD_}>)0xF@euyH@c!rTQIFDyb*ODo50mlcwtGj&bCD$~f|V zV~pZsE+|=8j@4L;A0b(KgPhrFMYdX_1G-=k!Y~43K$dmUScC*@z%{(S_xj?!eXIAy zj)?7L)iSna>}ncQ)}}oUWfYydVeEgZRMGJYBh{5xUmi1+SI3W4I{Fotz^~&53|HCg zU?R5T6{e-pyGv*Jq0u$A-q-`z>$LEQ!5%zB=JlLwjrPo0Z2^Tiv({)I?RUgwnk54{ z<8>yk@^D21NIE(o6yqUjnt|n5jct%L9>pEJfTZ^m%8=&T$hwj8gUTyrRLrP<CIVUq zP(bRnsfxS0c@l@p8%<U&<k9iu$Oqxp604l2K&jW<X#F5uo&I<3%56$WSas13ozWdV z5QeFcGMb5{Sck2kw{jrs`<cW2J?p5W3po|#;D^Z)GDS(yca(qLkE6JVOSp<mWaB-G zQ`}PQW=w|^|7<M7O8kH$>6VVultcQiNBD3S>3D#L_!*gK$g+~<<^eDGBLJf?7Sk~U zF_2{&cg@l@TG^-fh~vXX?1C)t6kNhBJjHML3-9p(QX!h6J)~j`xNh;7!J&?!1Nab% zFpR}`OoG&$d035Y*a@jgDL98)_zi!;kioto6coqndl&D$zPE4fzB&6M_ubpqmv^m{ ztvAXgPF3nSxYy~VhMcFRG)t3II97Slp$HXJ3!*VWG(|6rM(!J|k!S%=s91&8KhcTD zE%dp?kpN7%r8PiR)wma&<I$c%sQoGbK(45;$ffW+KTKU1PERJi8c#dTTuwXQb+)pv znWVfT>Ohjv1d@!Nkfa1)I3gg)q7KP3q=S4K*p8xb@2EUnXiY!0f^%M1%fLAtejlmG zPg8In>9~(4cnisy<Vte00~Q>|NnAxbuHzQ&;wiH5T;6T%Jsax2kzReRe`Is*qMjT{ z!7iT1G0EKv*+BVi<>0Y-AuS(&DyVO^uyg+BJY`Rhq7u%Z_zSrxMI-W~5XzwfDxxM@ zK}y^UozM&1q?om3(XlK!R_amBL;Cuc7c2GDeAhS%I(V^CS#??OsHiCm=qT7z5v^XC zWvpTS=(|vH3(YSfg<>#9U_NBIF2yP&VjuP+2{$3j{3TxDBR-?nP4-OB{dn&2xh3Fz z(!fa_>uJ4LH7%a(`)=i8F?F)qt+12pKk2cS3dc6Nk@lao*IKOfleFhkgBL3e&ALJo zc5}3Z2ioB~497T($9C+-Sv<#IXh5B8i$L^7IHaDA2X$4q086kM>yU^o_yM*f<%!8f zw3}ZSWkh8R;FajZD}#gPD$Qg1i97~1dKG=Jgr%~S<K@s@EgqWwI!?(9D<e^C!)@Hh zQ+z<4+jJyR46dk$Mre;77>r1a$4somHtfVn+`(()zC##y*siSPzMu4E3XcPmluMMm za0-`@h8wsANy;7EgCyw*Bw5*bfj{sk-b0f56;2WrB-sii=|v&QFM|rG46+iStIkAS zNS^AWAtZ0D;DL6Ke0GPeh^>!e&ftg^hoKWQvUw_e6dw>J-|#f)`Pw11C2>^gh@GrI z+Un#YrLBErit42*o#Ys~xw-@`#Tbkb3`8iTSjRw$HVRU_F_0owA;tUyq^Ng5iaQy{ zkqRmL+mPaafM4+vuON%Vx<6AgkvpY1k0Gzn#N@=#jO@gW&KcRPovAC?A8=7=6w0V% z#X36N8fh8g`Hm{YRR@y2-Rqe$ujiVIvJ$R=#q0!G-1(3ng;5kNeqC9(pa$Gg8!gca zt>Fc4bcQed5P;qogis8|5R5|<w4rAfl}t~bm^C1)v-OkqA)QZ*ucW4~P+YBznRyL~ z=eh}QikBRu*Puf_c|HAIdz({17E4H3Nvb4Gk|arx=p?EI*o5=AgKXrv%N4lrKrliv z4XcoVKkyd<@6mOH=L0r8&7Ib&3BNM3qV^Q5J#R>s*0HK}SSe`T-0WDZ^fXJHF_??_ zkoXfJX*dT-$8AVjo<q`;o46!Ru8?%Kg`}-7f*@%OfuvK?^#KObl@GF|%JDL3Cj^qy zId~fsDMKwaP?xV`w>NEzz42hlce53(twC|@QCdPOivUQjgAtBM%)oY};v}x(J@VXV z<;Ojge85piw1o${Kd^L9P<H8uQgpf=7=RUcfM1Y}FK~XyUJ^>f9j)Ps?g+scL}Mo6 zu^ESO1ZjAHtcTj+<Em<U1E<Amx(82$*8XVwDb^c^<uJ?HM5URzJ8?>SLLh0Hj2O&D z9F{}UxdwZ25*Kj^mvI&Ma37MFhscEF={Y1{Z}1VHA$fEljS5T;9n4yW3-CcQT?&%% z3aE}+kV0sHmS_bjkT&pu{Y++d#(dhX`Mk2F3DX)eX~>eJcqL*!GPH}#icW6#@8F0u zL|@~m2ferQhps{$X%HG&*QDK>6+g4P#3IGt4YCM=A&X%YMne{d8L~)XAd4jqvS>Cz z7SBP*B03CNOy_YKS0Rh+J|5vWyu>TK#=D38IUT{odwfOipQ&WXi*hKB3aE<Or~`7( zWld5DoEVa#ke3vNb>wcwnqYt{2HcpKyhZIcmfH(nm!}nR*~aM$tpSm2_p3n-(vl#t zOKcL0gzkgh7=~!XVGEAo5q^hbCjBV1K|f5yG^|5Prfs*3M?ask-bfSjqmp2jup6TT zB#r<CLgETRI3&)|n2KpIL(;Gql8&`V#AZmEjzZG)3nXptAn7xZ4oPDLNIF|*I+W28 z+m{cL;0cgKPXY;7*E}+nEUZ28Fy8t%!*;&y?G83DzP~YWr0-5;k6MdHxrJMftm<wN z!b`luU-*R2_zL4Mtn841s^X^(pBmV%j&x{UEk|}K?e*%<6F3@r_85H~ZLwV1!O;ta z;?u&C`RXA6v#=J2@c^Gt{t>+b>_q*?Y?2X=1Gt3eP=5Wlk>Ha5aIV4sQi8pO=#6=} zX?ze*EBJY!(pBw0!a27Zv7ZCAVSAO8?Iq^ID2cLgM{P)ITA?QfBMdQ+)Wt!r_&Aoq zpz%Rb9B1qHD|_L+_bJwgE*;*doKRiHv1^hxR`FAh4|H-;&HLG$#O+e5`8mt%t09@( zh%NXLJ8%e+@e8<!yO2V7fe(=5g>vs+5*K|WRn>aOmfZ(9dakCOBEFIqMYfiC)xs8~ zrhh(}!(M!YD7sMWuodGo-VGF6KGcI0s}!je=S|$jU$Dl=5lXJ}OKMZ2jZW1kE5%og zcPwssd`Kxn#NRnOsyz=Vea!{r_a9N@S1y}D9W+1>1YkHKF&^`=7~f+D_8<)z_yZr{ z@PsxM&d3M*>VJF}uNB$aYg%|Wtr+N2bXdd)d_NtLH9vsvbi-t&FzGC!*4s^ABmNM7 zG7r%t%2Mc1oa&-;gC`_iF_5&J!6QhV`Oy)9c#VXo?91Q)ZsN^T2X*fOQ<OX)gF~7B z)HbPimaj=lF8xqRwggiM4bd3(AlEXz2|KU{2XP(})h84pii)TXcQk`9<a9Mpz2Oo7 z9~_hSe|BOEs39Glisd-E|2jpns7<;#(Y@-yXehgn(mL*TbkaIi^@>Pvkr)Si?)EdC zBZs=Yzp-a_Y5$s8BYU^2sgCx`Q{A%sm@-W7tZQ5}tU&G*4(BBF2vbw5I~P`8_~g#7 zru=3w4%X$RbadsJw>3gB7fDD%Hk2%my`wYw;|_wKaV!o;k%{*x_MBovcZ|YH?8f=$ zwzikCMY^ioSzT&Hs`5Ror(ZaOmREhzPAQ`9*vrbFnW~gGOIGYjQkh<jgE)!HxPgbL zOi~uxl2nu=NU|jQeh7gXF_5IJM<O^Pw#oKdkg_0UY%s4*&2+l*#lluLJ)~`;)lSDa zq4?^gQc%yMPt<M)XblG(Q|h!UCIMKG4DzMBjr;h7Zz!KlqEH)6&=k$k9Ie2iQ?<hp zrH*#JS($UnV|DX6>srday-G=KHMo3I@oAS|LVt^V%q5{n2xBn=C10@ri`%%14^Uom z^ctVg;uXd6imtLEhwqbUO(}I}b%&F4DNE*QrMx~&(h{5_#B)qv#ZBDB&v*xk$ra7e z5#8aB5RAhrtbwG4&AnW%Ap3M&vcP*EkNMW;foT^>e0P?<&WX3C{A$??O8Xo&pMRKb zt@N(vsPsO^*&!<Ozu7BIw#uM3>ca~i;g8<vgV7j=dDx4iNX0#5;{&v<-jsNGS+AiT zx}`e{U;B?k#?6WqWHs5S-oB_z<?+mH6}0Ou?xaxzvX620!Rt7O^pBob+*%Zs;Qq!) zN_!eM;UX^KGSZNaU+@B2bHJu3h|^%QcG|AH8X@}wt9bZi>-8o_wOyLBO5Ho$$xXd; zi8%j_z0*0`MY%A&gTkWKB9ch1!XA-C@)EC*_cePgn2w)t9}n;l-fw73-q^Ro@+iKD z6sJ;_qn9~>-u{0B$<GXhPz=RU3N_ITebEmR5s#<bIB(;;as9`27*}6yd)le8x;Onl zr)FHQDR<Q~8C-w7;40@Yon@|YjKCyJgCutemSPpY#|`{%7C!Kub|QlF5YtbEciDBS zp*nhOo^sYQJ=}(k_}L7li8?Kv4T*NTZ1*)5=1<pbE1T~%4&LobSA5#!m!LkQI;G-n zEg9Ve-X~!J79k$rBN3aR^=%m~et=JXb#$Y=6<D2}^flBCx0KRq+%094`eSj9zG-J| zv#%?K)y!z8;%f4B&ecV9;)LqaHk>pml%Z5>XJR>Mp(}4`G*Rjudm<<UcTB=h_zm5D zr@$}|dvO)%zdNXLKbT5ef^KlbP#a0y54eDPc!<0NE5R2;M@TfIu^Y!B=jJ!2FC4e9 ze|xPbSf2B618#CQE8`A-df!y$tL631dDW@6l-AOpu--CR_Lkz`)+F<v#;?dmE|OUi zk_~$ne3+JOY=UG(8`7B*e=_K|^gOFt&vpkJO|#Vxw^=S)ycO;!LF%?UEXXN$lxodQ zGUroBLHvb!WZn-_DE%-PQaE!V1w_H<ivB^p{ln7iE;nrX$`^m5i1sBj@;(8Fq5MgJ zh=l$xc5D!iX!Lkbl|%;We&CQS27Is`0M`aO)ShOko#ol{nce(1ew=*cP&fy`2ea5S zpU~m^{(-^(!w-}>=3+!w1HO<X1Y;0JV;sgqk~IVKuoSBx$-IiU_=<1HOL8UYB~cbN zP#bk2*=d1x=z<;~dlvIUWxC$Oo>3DS%#XsT09V*EAH}p8QV5Sxj{@ihDUh)D+_=q| zjap%Rh{R$@DSZzqsRzhQNf{xf=8Ya|%K|1B<4z_I!SuJq{}C5OsRas|+Ng#SrZVcI zR_qPL-Ob%qt@AQZU-gZ4R&%kVcD~s*V7>P2vL#QHkp)bD)B8guY`}_QrkaH>eY9@j z7mQsnHrPAZyWUuD4k{M4^n0qb)2oZ_amIM!Z!}A3zj0i*PBBx7auq+Z$wo~~##F4w zR&4uZX_Td0)T?DmakkJ<##BVnwsJgW#V4bITs>P&?YBklIcQENW_MW=+ly^^jh5HX z={l%I%9tvvhH|D7mKHCR(|WZ;IaAegQD0dTuobDehU@qW<(tLpm2!mWN|+iH?xZ*9 zPN7dOgYF&XI~rsh|9)DrSUB$Gr!T2|qYO|1{+NNiIIk8hZ>n$U{7yNbHy8+HMMYDY zN?n-PhLezx&)^&C5W2+DFPFjM`G;~;UxO(v&U_9AT>%Wn5R`N@@ca!eExMz;A9FNV zYW$`Aq;JiXE)|z>8EL5OWYE<{b9kcz0x=ZBFbbnF-N|5S{Xt39dorc_h)KB(Jnq7v zTaR7Xi$k#BE#Bb|1mrR3dSfP*VtF2N@R1yNQd-)t<QF;qRj2a#0IuL2+U7Or_Tdgn z87T|&!3d+ldijI(D5Kmfyr;6Mt=uqdJH5p)rlomcq;jn_v1(yTSpK%~PVjyj*KrfK zVUI(??~ftYcr2~Il6P-n<mna$-71{HIo!ctXs#G^Ezko!u?Wks1G{hnXK_(69P~CF z*7uOW>;cJ)GE+2UhSeqt7q8*rY|yR4W?aN;l*wn%mBWVoEJi#+u>uBl^xeGuRz&7$ zz%A4~z4s2QD(A9uj(FwFP-p4QjU3@?&VKd|2UE}1BuIA|H*gnIh;tE^VioLZxxn;Y zlp+3FkaV?krdk+Gsd`_gbp9BO@tBBtkd$wNq&^iV@f5!y8!sR^dJD-_S!>QLzD}mS z`c9I^@~DPdXpYwC3_tXOKLSvaGU$x{h`>T5z*a_<PI*iR^}abuOV_i2K^Kf71zA)$ zf)pG>8lIt4A##dHd;|L?TT`+YXN?c`uFXpwokuBQVZ+$g)^y!bOtwKMn5yE<LeXW| zqA(MjJ&L1D+oO>v?7_PgX5GU?oQ8W*DnwCRJ=aE;v0h9PCtI=Y?4)NlW3U<RG;T=y z+y&Hj&Zd;+l1^u4E(jM?f-7<czMRi0PC+8-Ttth^(mbE(jJ~f#8;FtEVoieX1n<R* z8FUrU1zj-?6EOwzumUTw372sNX}FEY$S!8E^etf8toJ2TT4)l2eGb3ktZ<lubvTP( z@fnp$7<66;!y;_LAv{OEl3KId(E5~E?Mwsr8gO|{x(viq*p%6bcy({^H+%^#XH5Sa z3q8l=#Kp3FtzDmfJM!jLgNv9f)@{?aDlFjkMNP@x_9P7<3HD^IV0slcAZHStOKQo~ zRpPxeI-w8xmo!+si_skTl8Jx*rCKT4Ow2@JX@gEz#-NMEVRS7^3^;=!<qWzxxPlv~ z=t3BXbg|VK?ZPmv^TYl_18Es4kdmg%=ESQ@z>heF6L^H@c!59QOzdUg278J|mNHnH zm!gU^W=b~!Gq4i}k%SXCi8RzD?M)E?$;Xn?220~IrVIK`OzG0_5})x6lFP>MMtAf< z1SViIVlWd@5=oHK_^ph=(y1IPc1NbPvXOH61Ml(CRz{a?Wpve6PWO3#j%-w*yeiqs z&71czE|!kvO^5UzW2^<KGxI(l3$PH2upK+_6wjb5Z_w#+paN@JMT!i86)heWO~>@! zEDdcY`SN&WgYGKQaUHLb$CbtnlaY-=Zfr#mj-}XwYi<U4N=DTjSNU=ASXY%tWpFK- z^kj2f&mqr9ZRcuAX%$F}{V)W>un)f@S0$2&s;CYxQqc>?ASskoO?I`kax<OOH<M(= z*^>4*?_Z#hr2HrddvYbIE3h7t<j-!FW>rmR^*u;CAIM`BgRVVBVHIMlQb^V4UsPw= zVm9XDE^5@^-?0F@aUD0%qZWOUS_XCcE=O%dng(igJ^JzyPdM4A4H+`RpN+pZ6>=|k zSq|aluBg`DYpksXxw7dCtIMS>XKR?6nI%DAk)MP}!X!a!umgvX1aA^J6Oz!`ScsL7 zME5}qw%9TdNunhav5<@$fOf!Fy9-t>OO2Sr{e>L-jY!~7hQ(adG+p0Sesu<pWUUw^ z+aVZ@nXnhZ7N)o20xsez(jdi>0V$fBH7s4-P5bn1Zt@{dO@l5kjJS+%C_vd&f+xDe zR+hSDOlx<&FG`*`Aj^IQupAMxd{@V`T;GWT*M4-4_ZWA!7pPsEDuv-#j@KwshkwIa z{Ek2HCyLf3cPL)hR*5<J$hl$rAZ*$re=S$*nd<31BrOt+fhh9lh^i^Ud!ilwH`-i8 zQ2-Ks`8pPl2CQ`5%k!Z!>Y))D!yCTn0e^%d4BsIVt03t=1IfdAT!u9-mhO#AyBM8? zFC<e=WJoebrgUB5i|z<OZ<rB-nOI!c(x{2)qCP-=EI;%^H^>a~gF^KTx|;AtS8T*4 zyhn-p23_Gs^hD6O2@NW`VlXzKMN@-Z7~ar&VR)UvPR{DuEv8Zyt`2Xb_gGBmE1+Tx zl97T(c!E5{PyhvCPlXrLk_vxptY`6PL4lg>NjlD#Pa#R0PLgIok|fEwjpj|YB<be! z{<^tA=hK3v*^(-bo@myJ>|+Ujz!Ow%%}RxsHY|PYY)gj_{XNMdCbu&vy5sHWLE=_B z%e+>mDE&|}uElbjch_dLVu;0FVokzJ*i#ToDpJvl6b!=$NGj|pkk~gsVwaddV77-A zyE^?Y=OrRiO<iTbm-FQt=~`&RDc2cCTa#ndZEur{ddbsNDy*a=`rq_Y!tH4(FwBc6 zP}!TN5Yw@(gF&|kXK@}bJ`@JxQK2IncRWIqPHaYS0Zlqn!8+SE^64v#>2emIQ+4tH z2Q6s{o~97<ElR5$v2M1-{sZsFa1OWe5?@i16t#q;&Yps6#C{#+C1x~*A9_PlR8dla z39zTiiBw6-`gUO}(8W++XYNV|6RUj<x`){3$G#FWde8&v$#%(~NHH9XF*v}oubru@ zekgg95VV;u5`fGsGk!qzZtMf#3@UVItwntTTw)8fI{}|SfnM|^VayRptSzE)0d!6R zZLN`3VCnrhk9p#VV<}6zmx;@_2J?&IIFAdsgzIn*r0qi|48uq)L>!Lc1ZMZ9%yApp z$lHhSaSt!?3UA=hmrfYA;V3TS3ex);%#6`Xq4ziF+TeSv#a-kJVr4}Ogkc;eU?OH9 z4$IItnCxQ>cHt6ILWl(I2hdI-25Yenzu`Gv!*yUTT8s)lrV?riA5+#)ib~6vWW*gE zFbKnN43fF4)`aUG@-Au5-;YIwx`@SW<R$&<aRRMKV|y&IrI+-{GZH+sVMw%r%PoxC zTt^=)3I7xMNqBYCMJ#3`n#4|rWJEHt9tqe0$xs%aK{8f-AnO=1@d>#G(ZUU)E76hX zz!FtkHKMswTlGsm=Td6RUi6mj=eM~avN?VJ^g-NeEvt7xaaU%S;2NR@TB0omVg**= zG$gt}qKU*d96|R`+Or{44E%*WLun4sf2hU3t7*Hw2Wiq~k{^5WWBUwi_>or_3l;Cs zE}YtjQz$u%NH7U^@dd5Eqw-+ncLufFZbx5r&mVGIh$kIJ83x<JLC^yFp8W|m3KIHr zlp|z`<yDSYx)Z}NjKu;h!wwvW#QyBs;l#s?PSn>^d(}`!_A>R;PM$CBZtAZM_p7$= zVLD<iAiutVUt})mNoP?=`d!c%tr37xkUZJ*W6O(fFL}y8oC3pMB;gjyj9`Tr$u0wC zV?CCSqO!p?f-PEv8x@8LE(4R{X03lWX;U1F?5B}`;b>$LZOD2{YEM&My*(o}dzPmt zb&Ju6=p=fH(gOiFgrmquv;|NIMIgyIgS%)#Qd(m%;<0qpe~w_WRMb7Q*t&$gq#fdZ zo&x&5{6x!z%KJKW)^cLa$Wo@4VLMEtX$_Hpdw2xrF*G4)j%txqKU5sc>Wd>|wVLlC z+YBB^@G=i00o~)8pMUNhQn`1it$gRKE*R`oLd|Sz-MSTZs6K)RYIieLP@nfU6*EhT zN<t(70gwdTf+WI7#FB_ckc8M1@rNxT55}?U6h$>3PjyC5^u`#B$6PGJR_wrD$hnXl zFVm)^1!Mc!UUC;~Ep_D_QyoiEA5(FCSZT7Uv&YhwnAYMMoCwJo*N}m`Xgq<vC9K7I zI89_P310XP_wZ#Bo5aZm-2fa#o++%oQ&@^)9s8*XRpr3rXD+ViaymK+CFteKph_H( z)1J;zQq7z%g*eDm%3M<NBC)#?Q#IIQ-^uho9K}i8#$WgdNl^)ug)1a=P0$kUAt@b* zp@>E-7GWI{aR7&La$+5}W=!0IWJ?NllUA&(1-#oOr3Xt{^G98@glh%c#BvbbCEQd? zO^D|%%~8V`&3oE=Qw=rtGb=h}?yOD?HdQoNlt8OfR_;i_Wn4oB9wQ6(vV1@}K0-0d zvNUQS0R6BKOOS{kkczXogsXUu&rqha)}buCrq-hMU}7v-p?OLf|8HHK&TH~8+sj{j z=Py^gEF5eaqqYt<)m4veGWAlAN70qq^T?QAjeKEp3#-8L)zT#Kc@g9>oWMC$n#OmS zjk(x}M9ehPyNRaN$1BvG&V~xt5ITb;iuWiQ!xF^I7+XtFr!|LY-sF<&GD|p}lHMh? z##4^k4l>mlBsq$~94v<<MUqjFD2u|L97)OsNOF!M6`9CIvO2>Ll0;6>p4+YNR%6tW z{=Bt?_11}XOE@uN9eC}V$zAQT#=fAJFEZ7!me7e5Zf=MlY#M1UEI}>BYOKd5SdfCN z$iOqaf`QV=i-IVEk|>W#sEQs4fRtVsMqw;|z&>yVbb3~z?X@T|Yf)kzK4=&4sL>Zq zb+qRC_z;uz0x~87)S$tndCFsI?dxJDC)H=D$=_T`!a9T_IF8G>hL`vX2bNR;6hR%- zM|*TcC-lM~gdrL+n1$t7jWyVe{YXMOWa;0<&(q7(0pMZ`2HDa6a49NJ_TtE+eIiI5 zUEZm*y0{e=yd4i?-MSxYs{G%q`HrVnR10UpM1_+-eo(Es%g==V847i45Qbwk{)D~G zePFr>bx!JD71TtN7)!HZ9IP=*Wo!o@^hF5bupHa43x{wPmv99S@Cc8QYbM(yY{Xt1 z!V%oY9Xv$kSc($eFcL>FbQW9tS%%!Y2~2F6WtlbHG)ey*tA!R~8Rlw?R#*awK|<>` zo2<<z%NW0iKI;-XU)YbU_zBgPvif2qeqGK&T1~S8r?oVq8z=&_-9R6y6a7GT>3AN` zLsq{!HS+RDKGq3fl{_}e<YC@I+796)&fzigk%V%ngr@L8SNK7aHwF_i4Q4FEDs06L zq$3kg@EhLaGroalIV(LeN&e5`Ds_uFf`dk8`4^`-6eC>WhDPv#AN(-@VHktiScK(R zj|3b*8gAktp5Q57;uYTF8}iPjfZ&cs=sMTXR~N)Y2u5HeCSV5EA{D2QiQiCq9z}y% zXo@!QL`V2x5)R=g&dsyj9b<CSo6qs#DxTsc-s3C2L19rBKp~VwDY&5qYM}vIq7}NJ z4?^%eq^jr_aF_+(ArlK1vOFM{p~i2S63QQS@>r8Gw~W^3n=wU=TViUWb{@~Iv)U<S z-?^sgGKw8n0mif1al1t|a~TO>9TIRKS$K)O)X4^D2Ok7u6viS7E3qD%uo?Sc!8zPR zHs0VJaxFIKa>EEYvM6KEWy$|Z&IyqTNkK{J^CP|ZU)}qe1gACOGOmO-2CfAe&*n@^ zy7?BFaFLG%25@tW%R;6i7MiMS?Fv7uX)Y~+7esB;L0z<k54xf!f-wXUn22eJ#bU%^ z6ZYUBj^Z@V;4-ct9S@O(-|;u}aV*Waeypub)Ibw7g(tdT5T+p-Yq1_@a0R#U0FUql zFYpd!;@OizFv8=lb!$jCA0jXZi?Ip`*npkbhXY7P3eMvS(r^>6@fo>jT9!ka9BE#f z!W*68w^SWD)>PafV@qeb0-=P~C6&$4|Dz6-^kc>mkaj8(Nw|$J%jo>UiMC5YQ~014 z`XCA$uos7L8TauE9z)tZ#}&*At@F${jZx`AUX1FtC`$ehN?)YY<)R-nYli8KREWjq z67u5$C<s?nM-#Nf0E|WyCSVR0A`U7J;t(u2hr9R%zu_JJhJ#8^7A|l@9n?j8gs5%U z9xyQqQ5cVDFk=Sduo_7?j&t}KukjXNRm-tyCJ(*&D<8fg?@A7#!X4ew6QeN!J8%HU za1qyV1NZO?lvONObVVS7F&@(}2a6Gh@38@i*p44p8C-N0CQ@(=XK)p1c!=y(mUYpl zfqHW`AKqdn8ztE|Ex|2(#Hck?<L~Jip%!Z6JB-H^ti&l~;5J_2D;(IkIid<`p&sg^ z4YWO9Mnl`Oh;GxOC{xguMe@Hk%AfjnhRHgX-|HyOcv?G6Gp+so+UC+SdwYaqBBmi4 zaafM^IErI9jx^lDeLTWT{DH5?y^ftm6h>K;Lp`*DCpw`!q+wpf|4~7O>=$ZVFV~h& zYTQiI0vT<PHB0tQ=)2car?uoG-_=&9wlulYx;dK5NJu@<2YnHQ;fTU?%*JADg$0Lk z7Uysc_wW{`^=$G{1GUfteK8o{Ap((@glKHXQ#q9Rl8N{Died?58CBqp+Gq|Lx8nct z+LFbPZdp^ZwC575A?|q{)lc<gSY+7{X_=1LV5)7dDnYe@2Yk>G{^*PT2*p&)LmVp6 z1CpN5VVuKHxQmDQgwN1#<je)aAzkn-S?Tc;8R%7B119>&8>hA8KXu}1c@*jYY3{BA zqS*e&|G#D^ft?iv1O-g61G^Q)YqwY!*zL8kUAw!+7Q3(QT35wxQN-@V?ym3iEb@Ne z_vicmeSiOa|M-fJ-C^0CIdjhJnNu?-1!L-_EVU$EM8V0$QDt<TFS)bgILoFEeiXW- zDO$r0wRyFvKFf)rHN+6+uH$bT`5Uf7-^8&EXLP}2ti~anMEcFtCU6clw(w2gLgz>h z`U+K<&K@^jHSMZhxCP&3^dG>)0$jr*JcAoyD1h>)gl6c9p6HF)ScGNRiNA3Qad;2s z734bbL;y0PGODa_E+kc1h(uTPhGW1QBeVB#nXUT2XIb-Q&6(aex;Z!C<TrlIDzCXe z@W0REjykI2EdFXDH5_#o|6M#OZpmuPqSiV9qc9P(FdOTz1-ozvhj9h(@D=(>f(;L( zLTdOT3-X{E>LL<7F&rZ?4b!mzD_7Pc17P7E9za_~I|)jm0%{@>Ezt&@(F5~w8AL}s z!_=Rtq3Y@<+T1+b65zCKf|$eFP_$V**;3DpDXA{=HZ4PKdDUlbArY_OwwkXf{E-0} zksJ9@5G7C&l~5fuQ6J3_g+DP6!{Ea)sE)<V=#ELy*K+27%9x(To6!R-DN`if+qu?C z^X4L2cpT-f43Cq`T^#NMlWrW|Z4!+P6drTfg47x|Vh;}BCp<XXQz91{pdC767^Y!1 z=3qAt;uwx20oU*o*7anm@I?r6qAuzo0&UP`eIQZJLSGEWILyETELm@#H`CHivn}D5 z)!2fqIErJ4#}(YcV<h4gUgI6K4IKAKgFpnM6sn^pnxHA#p*u!k5n}K+_T%9O=TLdU z!YBNI{ud`SSdbc}&=0>4mVX^4_LH+MMYLAxPd1FhRIJ8E?7{)W;tVd}BCg{G67d4B z@DVA=a{`eW+mW0Xz1e8~Il$tluZ&kWCk{#)A5C_b)BJVx|CH?hZ&=AksEkZyV%1R> zDl;2}@lY99DTJXqnxHRcBL@3$2G?*K_wW-zWO&u^JL8j9EdPmKn1p#-N>hnvVFz~N zHl9Hh3zx<1oUpSO|EWpza{Q=g^`iQTW9H-EU%y{tX>tf#OjBRfYnH03*1%eQlJa*) zlVDaA2Oj2z`IgL0gUNs$;ZU1ux|PJnSIpf;VRAdo;b@1O7_@_Zw-edu0@=y_VhjGp z1-S1bUNCGIqaEKm*Gjr>Cig0W)AfoAL($b`H2j(_X-cdN3oUnTY8PL_gYEhuD+;18 zRG6YM5K}M{tFRt>a0d^e!t6ts{ZR=u(EzQ{9zCJ<X$>}G2ae+GHs>O8orT+Yj@0aE zQVEPoz2k?wmhn6`Zfq~aB{~+G5ZiCYS{T6cnE~pr+F87lF2^CG4@_Dj1zP`(_l=zN zv#9l|$ZU+}=!w1<k11G$LpTl<*`M$YIf?ZAD2|G#iuzEAF%dH{7i+K?`*0BF@Bu2Z za@vbhh+&~DDxe-5bqx+IuCnBjUG1fISM|H}N^Fw!$N!I=WY_kai>Il*ukG$_%c9oS z2%Vvhi_sX5E!c%voWxmNg*tA$;Ey2WL1C0ZdDKE5sAEeVR|F=8*#~1t03H(^3r)s` zJ4!PIv0n=ATEKUEoB2wWgu|9mLGt^b$79HDD$1ycJ{W)*h{1lG#w%!h$WV|8b<h`6 zFcX_`1{bhtFUKA#{hb`XM8f#{XRLk5a?5b7310#ki(PmM6^Lx8iDnp#HAsL5D-D6# zXe*dVz-OdnLwQjPoiJu^a%;3|`f}W1kgrtDSwr2@{SW`RKyd0ROZQrQ(h>AyJgeZl z6a1{GgL;TWZ%n~#JjHXY-p5yRKgooq=!^;boy}AmEFJ%SM@Tz&gv_MbRGid?T4`OV zm8zAbU?mp#BOCg|#7b<%PV7N`R-U}ES}aGP6VygWU@Vs4FQ{XK(OZsbd&jEBn4Nap zTAJaS5InKtKKu``Mns`IR^UEdV>tp*3eC_Dv#<{dcnQCQv=Jc+Ez#j1k^lP^rhU{c zF=MK#fSkcK{6I=pofG-65KEypxgXbY2Wk^)_4Qe0^WUp)anN4%FUB_7S|n{pzVe*r z5RGWaiozI!71)MY9K{KgJ<Jh~aNNfOe8vx?IYJo`<xvYgF%pZh90!pIIm%i5sB=om z%t9H2BhxYa<V}{IT0{0+hGQX?<1<tUcd+&3EjMFp{a`~p5}-mNtUWgxVG>qDZ8iRg zqXO{z_NWK8Fea)suSp6vToD~H6pL{H*YO#dj?v(OIv4;G2XPqjNI)VA9w+aC=Lyau z*o>_w{+)vKB<<vSGRLqiu5C8dMYU$l?UpT7)fUv+cOn*Q?T3)O1&y`3A`JqN3!$it z>S%=4m~g^gbq9$WIpO!_xAXiHzfkEUA3#;Cz;0Z{O+3X1R69kYp()y<*=Y_$bi)8l zI&F{KX<4a7v0t(cY6EKJ!iP1e4OGEDH}Z|&=diLZID?DG&dPE+R!CrYegXe890Ztj zmUJrVI>HQ{t6JdcHBIVCb=-Ym=voGHbMu%?=K4LBh;EbkocjDGY{xE~z-2tZ6FkFn zByXeq@9i|>+2brR2?jlKmm_6D->9kue%~W2Dce^!C*<CQX*zhNGdCCIHp2VW%@g13 zrCV(1W9OusU)o>nwWQXHrc&!7{IUyYaUD<a5l-hgMWPWpAsT(L@|?ZMK86H#{^tkP zn~Px;{=!XI;y9t8FIM3;@|`E8U`NCS8Ya*<o_ygV*$5`VIe`{?w81nSNFai5TNq!H z-KCrvbJDFz(nE`5?m><@5Aq%IU`q5@OGewue*|F<%g1p7mv9+3pn~=kpYRzj1j`kk zP(e<Q+$e)^RKOqTjpW@S{)zqx@l<e=p5pg#*;Yln?V#%BNZ#SYeBuPI;uhZFGkn<j zOvsKrP?1s{b<h&+kQ_+|SU!SBc!#g}1&xTa!WZd~8QGEJf-^U)xL_ZC*fK<mR8bs> zj_8fS7>5N|f~8miI}YM3UP2{H1Cpf?RPwY(7j(x^Opmum9_5Q=o6awbuo*kB3o0%B z5QvNjMSfI4Lo`J*sPt}+E*OmoQ0YGl^RNb+u>(hN6bZP5%iuV%+l~|Ak?M$1M@wf6 z#CS}GI(p_}5!PTAPT(>g;VE9=1HK~NB{D1oq9}@8vPYg|H`{Xv%0Z|%t2e1P6hj1F z!0j?AfE*YMn_9lYcLuSjaE<q(6=vWdjv@~C@D?AhIePL6o85D8nA3?@&YU`#93|;W zh@}i^NgA-3K<nTX?p;zXtqMU2)PoAiVywb?Y{Oo};v_EMGE`_)NL2`@V>LEiwpTr? zPOh8yWjkVV0%vg(kMIoN;Kc5vfCXw7Ls1xIQ4@Wjc6%^JU=kMK08~`a1eg4O*_c1a z)aA$VNakg?#i_54de>!K!2|eRrTmABxP$aWRxXrBIO;(~ZcC^L9)yt?i%FOc73mwW z9lNj(u}}#i*ZC?TB?7K9fH9DTAY?#B<V8M|LTOY-P1HhDG(!utL|6QYVHl3-n1R_a zu>xzb4ysm>)M^@+xRM`L)mWKm|9QcpYn?e993fMoQUOu{QGrkaP#aboRU1?rQyWqn zQ5#r~L%51JkQ?+*AqPsJHd-JWld<K7qr_a^oH~}VK913Zjx5%3VZy!y`i@ml)mjfi zt@#+v;xev4ZRsUmLv8UhenD;74gOFe$cF4tAqhoss1TJy4b(&}s1Qa$g|h1n`XYL< z&<85Wlc0jV83bJp-Z1A~vSiodXT_#yWM;T*xziz=di@X*@D^S-$<a{-HPHbhFdnyX z2jy>(@gUC~q8QaM6vuE133!Z8_y(7|L|bo{sp_oHpz7Y7=DA**yT!Gl5ruKN$-}D? zsL#hWvxM3X{tnc|-vN8`J8&u4xC&q{s6bYR3TRcRz^cIA!%KXI8-Xkb72sy*f|*!{ z_1KBKNWM>w<D#(m2^MwhjAcxRq<+k4SAO@E%(`NEoOI*KS7!<M^LCaTwgC0<x7c-? zj2BMquMct|H%dXpQB|mTYKyMufdQ~V#oc;r!%?VsB+kSS{z#8($c`MyiQLF@*G3yB z3#Cv6RnZtt&=eif30?6g24Em2V+s}{2FtJ<Td)H=u?t6W8t0+90~nJNw~`<A?Ng5{ zvrMNWL)~vrz5K5y$9t0A$BSmhcnecp->3IN-8Q33akXn|x74oWfeO6}xeBogtqQ3M zr3#@6oeG%>%`sfSRouioc;4eAgMtW01Ug{=rrt{~3&pr}P+bF@B-VO%F!xbDvZ-CV zj4MzpyaBb+yGX<vyoK6G3RdO;wXxJl3$@WqC;+wbawrcKh^nXu6__Syj}GVv6}bNQ zoGUv*IEG&)VG0PXtio!Xg5#J}rB-#j&dKr5`ZG!8?}d04+o*fG@ngn5Vql(Q8coN2 z!uFp{ZbWk2B6Z_^j#S6ezmC~9+0>@gW=`WKUcqvo;|dkg8XYheD{&QHkmUiH4~Ahb zw&4msBJd%JiM7c8h=_ma+%f6<o;2t>2WMy1#6Zm`n`5>I$L)qre^5iNA6i1Ys9jd! zxd9cXmr&vIWV<SCIiSM#2UHkaL4~so{u$O?{JswdaRvYQYO5<gCqzGM{><!g(h}gf z^Uw1~miFf0$Clyd;u-X0{g>FX`Kq-f$G|U^UD#W9q(KH`go>Gh2tyMzM=SKk5KO={ z%*G<D#yV`mJNOW5X%UGiw1Db(*cb0dr)YFMouCf%g+5b@@yunV?p#Bblr#d4g*;|p zA9_nN?576fxP{vMN0w?y{iU?j)^T)@2B{URB)Wr#cnp$D8lySJVKPqP60YGRzQX4* z-&=&D5bB{Jx?lm;V-wCH9`ErPPKhe_P>q9rYM7~GE=4t;;)IyKQ4<_LYBXYQbJ;rf zfw7s})owAXKxgi=knV{kSDPRe!j_nZZBU_m3QyLa72!~!7y%WMBe(~HEvG~^G{#%3 zctQ~#yKo&JkoD>RUse8@WlKr59~P*!TA|jQ8lfnRA}EIBt*NW+xHV1x$-nP2<ix$d z%ze$-wJNX33`vwoGs7|NTWxzqLUljJV4XA1>FV-SLG6XUSd5kU3tM2vUL3$Fs9pMr zRP06?wJXSr0w{xUR6+#$VE~e&fSh}0;?8CKB<`F{o2_H9r&Hw4@@7;gOA*!XoObpJ z&mbnQryPB_6t&{GUdb)f|ItS6=q1RiK9Jj%R>kg4s2EnU>-v<GLP`+RQV|W%8bdJ& ztFaCn5sOo}f?K$cXZV26_<<77_@bc&mcTK5U}f~=m6N^I)XqtwS4OvtW-4nM*@s)| zJH|i#>kC7_-S0ze^lQt;E`iAb>(0vO;Vd3OW96Ap8m-YAZ_w{KfyNblL+TfNkx&<1 zF&<lS68B+wNgjrXm%sBy#{@6kKXAR7<AJ85a^}7doSD?_ti-C{Tgt}Tb0aU*R%5UN zaY%sLT3-yrJS>9RvfAo9d_o$woDL;X7FAIXNngvPE{fmZNNdtpvQl!p__=i)tF;=E zJFZ#BxrFcMDD%l%UUPg&8SRv>RXVjQc1-G{0UDzZ24EnjVi9&?FCO3--r*CzLwiNm z3YC&f=drS7mHt)oSIPe@KX-CY?j@=1?xQ-v3z})w7s$~&-hCRs{_o$S+Kp1H0I9$v zZ@efge}vEY3jf!X(y$k~-w=<8#drLKyd_Z3;S3kJz9plW<5Ji@@w273)<}id3u@Kj zh(Kd>L=W_V4I?oYv#<+$@Xw&ABGfV-CiBxXGO>Kpu;A{MT~ht4%dw$(^bNh@d<lQw ztdOyaBa_B%cYDKNfK<u5RFd5(g(|3x`e=-H=!%{gf)N;vF_?$NScYxbh4V<jUA%!O zQIZmY$bp<#jAhvLCY;j+3o7n@AUW<F=dhKW$J7rAtNuGCN#>V$bwAMf=$5|^G!psQ zPs@bg!?^oeB2->us4?l8YX|?AbPzw%BPVhpHwvRDilGFmp*dRM*}2_IC-qS`^N8xh zv*Ugq+fNupG;`cfORGjHN!R~ams&@0sP(9IL_w|R5U$}H!ryVqL&o>CW#blZ;|}x> zoc2CAzUhvsoPJ-s{<{EFPR-<GnBUuQ5wGJ)_P=Q|PU^|rSHs1^y=>fk&E;-JI;R|6 zrkOq7Ir}+13Fa2yPDa_PDirnEYBRJ&C-g)w?88x9!gV~tV<d<0=6{6JUe(#49YY28 z4K#wRf*pcT6h$$VLNjzlcg)8EEW~PT#6BFrJv_ieJi=ozz0jIz1E;m#w`SkKeV3*U zbUamClbq^i@oiiW74L22PMS0ATnZypYwAbji8EAa)Rxp*lh>HYvgIS^VOTK|cTw{b z87B^)Rc%9B)-fb^T|@F>24-SbUBm2ALbZ>orcp<|{db~pQB(<zH@cF^<Z93`J>`{a zka;w%k%6g*jUbgC8QP{%d!)Ai<$r|1pY5kZdZ_SBh6>X&yg>oNq{7z-jnNI$K^bAi zo=JQ9U{aqw%_<jcR#435&csG-C$~K28b5=x6mw?V=cYC++MnL)Gs*jSlI1uE`>OW0 z3%X(wHsKId9CSt(EW=S;g^HIvP;pZL)b3U;Puw#_-SZ~tvDK8S|F}Eisq}`UZ`x14 zRNc&U*Db_6p2jF>UiCAwdWci~6dF^3)O0a7|LvLGthIz;)3sE{SNa+GG+*<Li<ZeO zeb;%}j&w#Tr#fnT#ZdwkQ3(yu1g&Aicuc|+Ov7~iBMp-Z$CFjALIKOHv&F^7-Zs6# z?Rgyc7)%bWzxgq}k=oI}oW+ZzmsQw~9oUV-ID-2p|2jEih^Yk{*USZ(jGW$ud^@Cc z3ZY{lA$v7-E7I~gUCd#VJ<|Dh4~>ytmEHM%_;zseYMJy7F6D8_?V8{5ZpX5@=!dhr z6Q6bbW-zMv-y2gS)dI|YIheT1E6|vuIc{9xs<y+xtjvb)-p)Crq!vv)P4{3UgSN=b z5o|oxR-36ph|Qg5xe%kEYX?oFvSuF=V(6M#JJ?`ajI10W{^q2tMnm`PjPt$1I}+_L zvKl3|bj4V1gwII9-~7=4Lv-_A4x_tmkZ55VgM$Z&#mir=)}AU;#Z4llqx6=Z(pEA` ze!j2S36n=w@vO*K@2FLri|X~9{&XJiqQ1)B%cp8S2+Jy6gSFgJBE_(<u|85hr-WC{ zD7C6`E~+Y0hv()zx8$|%9sG(klioz-0GsHJ%@1JnY5(iy)x0Jl1kfX^mb7_Kar)QB zy_X*sAB1Jq*tY!V#smM$#sk@S#H5RkjsGc5VTRiGKiPOXwQ=)TPQ$lKh;Yxmtor|H zYr5K6hU8rhulm1lO6{H5IG1rl3p0!4Hfm|z%+a}xhFS~rR&HY;FGl7urt#wQJjQC@ zn)0*T+h5!+L@Y#fQX+Vo(+U`AZ5fj{Qa-1<icb}PT`OChlj5)!OGzJ|=J>Fl{Nevd z!2+aWxU?iag{6O`kFLVq5=rY*(W2H@(Gi#>T15imRQA8Fu;4#d=$E|0q_z1w)~41Y zVd5QTZp+74GtB&$&xnNXv&do2~`w}^9dWT<i3z1Cgs@LO5^+9tnI#$KqP@j$n3 z9vAU$y{pKI0Fg9e{wibm+nzVB)h*x;pZ!_h1XUc^t#!8Obd~z7y|Ou=Lwv=}O)lQ= z*LQEpGtbX<YPaBG(TnM)P4#l=5tF*;RIl1=X6>Bmogt*Q^B+$e-Z^vn<$!F>XDpu- zGyGB9wXOU6|GM4n*7|%=yZj3F4jZ|=RL6lICKOIN?eJr*#=#wZJ73wq=~1RN-BY(X z>TSF5ab<-84U60w{J22#hN;H65C1W)>9MZ)>gH?~6*;|3?$-UMtqLC2zIEPK>+h^f zVd}$DmizPc?Ae{SC#>*~KOF8px!m*6uU`VZqI;EES>{cVo=-}<=1d*(VfeYjVW+ZQ zot?VKm5rT8E;yOjJ5jdoa2u}=DHi-`<{1Ck9_hFJJ@3oA*|s8i^WFW>#k-#8$Jrl0 zoQc|z@4DCXd;tqH2l`fh_M_sn3k@>emO1l|eHiffpBtMWFDTEy-C47JMeeQVqt^B9 zIX7hLk7D`uH0gXPUEY1cwzg*<HCPqjaYunB>uWo0$q>-%^Y&|<TKBpd8!+`q(Z{bR zoo#2|^Yo5!{9ePyuYXkAkT7~eQCrN|^KER_4c^yYwZGtbe9qPvRX?XYaJf_3L8FIv z%D%SRI{$YS@~qwNfBWImlw!1Lbl!PQ$EruKj4AN)Uccb%mpopVh+UB_`h?l5TBP6f zeKBh~4ScoAKeAQUR}Z(oYF=jG@X0UBmfrpA{`nDZl|I=v4PVggdNKD?dzugWaboe5 zG8Js4Y+s%pIdpFAn=KQ6efTzI$d@Paoic7acY49&#btlKcyj-7)S&O*>?w2InXgYd z`8w02aTSUl&vfm6{$lNx-ixeR@m`mbqf@PX7&O01_8!Bx&-VCI+P8ROK)usjo)?Sm zJvJcrx}LbqqhFt%m-F}Y8aHmK@4StFY<9YFcR`<>t0x{TykVWsBir3z_jR)-R7q<e z^QPRamw9V0`2I0#j@Rv)&z^k$=GbEGUKUu8J#hNS?8_Iw8C*W+-aX-Kye|hm_00RF z(UOureL^=_PE4J=pwqmr*H-3#&^Gd6!3WpJojKd};@$NppXKR!C-ahAq3c42RG#B~ zbX~ut-J6E=9NU_^()U@vG-npKdUwqprEP06#%F37_(9LyHeu0x{d=B}AL(3=uC4yf zI{#?iy4iO}g}f{AXz#=u_rBdsajc_nbl8m569?CN89uJnwo~<e2aVYiv~+)X`tDmo zZ`yP8xG=atz>TF#T3=Wn_I}2=)yE&!Ke+H~Q1z?+-r<GAo?06oEA*x0y>>oxu6HU{ z_MYq7K|dcZvw7^f9dYv3$oO?@+wYi?>O<xmJqEn&nJTX6;)V9t!B<1#yxvv1*rex> zYG-fR7A^4m@a{{!w-ZMVi}{edm0Q<>(Z@Vjz0BXXOU%lNP0e<%XLtYTJh;)tZ>ML? z@Ud?yG<?eL8RdqJ@N_9MaO$0>PHUHz8(Gi)+OtJzQlG5eJA0jzAx+bqvGrWhWzv|~ zsH^MR)r%^hyI1A)(fwMO4d3@1ayk29|8?biEji=6p@X)n{*InGygl~)J$}pXB2O<~ zdwR4``1r{?4z>+y)hoxCseXUOwn|mQzmwO*@?H<??|k1mq5IX?iOwZn7OB)fvU-}c z1^*~;P&?6c`Hw~C>f8*@v2j-MO4~B*@PB{gjcw%WS=+X6yK*@$dS39Xgu-c7pW6DV zMB|gW`ppiR8of8Daos;_&W<^><8r6GMN2=pzwO1Oy9^b+@3STEhrn@-Q*@g@D5T5P z#aB+RJk|bcmxq&g)u=tDVTK|vds$1Cn(DD;$EJy0I?k!o*nLxl&Rag_E1GHj<A-4` z0SnKLpH(>fXxkZ&v9@LNBMYSWj+!;2S>*Z6TcZl*eCYkh;fx;E^J8lqPCxqnv$`%e zJ?Gs%V_G`@aJhBnNr(BB@)mDjqv4P&?Yc(?Z7p;#?ailY&Xl}*(8%OlWKOq`cL(fM zuTSdLzVDH3-;3|6oA>^&xw*cU8pc;>*x8{eUyXLDxVzr9^nN+-9Vp+i!jFAJZLzW4 z-6A~q-X3+VcEsz^*S_aFKJ4f1j|*nCyp}HSv`$k-SFT-bN<?sqt1giR68a9`G$1;< z@wD9DZE~({^H=o^SF`jCyHdN?owa4Im-Z>QCZNcP4hQZ`zP$Kb>1Q!@R*zZGbAR#b z4Ho>p!|msj6UT}aEcWp2rnDX2e)h|n=6>w+i0$9be6)Rko~Pu}45yE-uXxKhW_@p; zZCiHO{_sBA?_%W9dGGq|nj7HOc)=(CG!uqpAJw;V<zG&ZGx(O-x<5M6sn79GLz|@f z-fzjMa#zFZM{OG6cEP!$U!~AuSN~{IJ#wbewMdC4s~?W}P`uXeQMX#hUYfly>+SZI z===+IJzdbe)VUVzQ$@Gxdbwbl(dh~d-1|q%jtipNRBv_qRhx%VTRtb|4Ibb*q~M&; zkQ(`8Uq$GLETuyS%b9M4=WPhEX?AOABSG`{_u0&RQO1bScetCOrHveBm$HVJw%I<o ztP!r+R11NRNTk78`WOEsg~&k<;g+4$sV%~-I7Ql6MQWxLIfO7Tk$I^^`lqIJ<t<Xr zms4dLk*|It71N4rNheYxP{b`rWIg6&5NV!KWI-m8##vbxb7Hj1AyPQE$iv)XldO3~ zKIRj-K#9+%pvb5~+`FN$h*q3>25NAVc3Vl2rlmx3lo5G`nPo-hhKUp^C$b%(<wc4x zurhT;k-an|rLQd9+eoA#6Il(eK~c1pNTu4`39zon@_OtbvtZV5EV3rjCNjR6$n+@o zss$TtC9<gv<(2j#X*-DY>nIY_S)_MYkuu#x+IJVZgmyhBQ&O<W+Djw>;k`ws3=%0Y zMC1uh4;3jkTx8q`0y9da=x72nMr12ejTc!rktm<U-)&qYXHF3bm`V>j?oAVUIh~cv zAapa?;4Gqfwn)LbA`9n>WLh9{8#NY*+*vH*vQ*^UGLbPWSn+C+__ZQE*NI%ktMx?p z1_JgMv9pPQZWdX&m7UqnPVNxNW+!G(^AN@;?9sS_BfEq#o+3|Cb&rVGUXlENvp4%h zT=$cvXm&uDJDQc?-a$Thh!{Cc`W_Woa!h2y36TsZ2{6i@68VIJXV|H8B8$!w;0q$B zE{cpzApP}AtP~NK+29qC!+3aAB+D&Uen({DJ(2GBMM^yod4m-X*~3S?_E=<iqR0vK ze!_;Ia*#a}$@N@h!b^@RRDVUxz9xC!@ZPr~ecp-4dyz?K`$6RO2OH`8k!bqF5&c<Y z=@*foU#X{jBW=HP^rFBI0)?2LY>0w#fUe1Yv~$uV(pi&>`0Aobn42bdQ)sf?Lz8u$ znuJrzkFsiV%1e{RsWd5`T9f?Vn)F2?B7Inw%~z9+sGmmTPNJGL@YAG*zb0+c@_}@k zTnS+1ftrj8(nL$I$#D2&(Bup<WYnZ=CjO4vSu_cucF;3KlLXYts>x|I&8A6}?3ygi zp~)NU&#B3{+!TfLXmUHRCN}?2O>*VeB%**OPf)#(CasES5?fT0J|#6dS4xwjWi&C% zYT_EE$wU+>r%9!7_PBy3B`a#Ou#zSp(5{LmHLGeeqM9b3(6+iJ4Qpt!7AtEKV9MZ^ z(4n>_2kK}tudZg34iTD^YrskxYSO+jdlIQho+g?+!|0}(3~i=K-sYObMe*Slnw)J( z^tRHZKpRauwbdj=J56GcuRVe2q)FAztQ;e|XmYKaCZRnw>D6146Md-T^ws2ie@%7{ z)MVHoP1X;wv5}#q!*EUfMzDvYHQ79tl~2&bK2hTuV^%a>lT|ZG4wLkot4Z)YRt(QY znxtK<$x*CXqRE40MC}URyOLvIl_qajYtnJ8Cau?LGGV>OH7NXjBQdjyzi%O_w`o$w zwu9)jYqDe~Z{9_kA?0pO24UtNO?>x~hJS1F3w`!!;=Ny!u?IA%7fV_m)MV=+_V_RX zJwjR@BkE6RvgI_(XNj>mO`PIc??p}Sp=$y=cuA9imo=GtRg?MGc;6=;4qfLUyg_u{ zB28{<a^#LCsqS-7KENXm$V8$J-=1o6{W-_P3)1=}fqAWQzkdRPweK`}_+FEzA2|R& zk(5;ZuYA$u<Tp0_lLMIQ)(c&iGA_C_qe-BbyDmN+x=k*7=weB!%M_eICNEw3q|)UI z3VZ8P+*g;pv>yyir_1s{U1|mCG9kS#-7+GRE@^^wIgG*~y6niROMEt6?6gNb&7sT6 zT)KGY(`7)YE_wl7x);=CZy~l-RF~|<bU9zlri-n(E)gYk@hquJbZJ6XMwj_zb;%v3 z%SQAor_1H?ycSN#E3jhp`a_pD6?J)BS(mO=bva&5mkiZ)X<0*;bv1QaRExc<OJM8k zGOeL59UAG<rm-%QB6SIG!qhTNby<b}wkTc7wbZ3~D`KHF8*QV@1(a*2OYaW4yzQt< zk1o25{*w*kem7lqbtm*acu!AVw)D~^syBOr$UeIKh}Pv!KV7yB&?V<UU9O?>VD@;3 zE<4#-zhOL&(8X;mu``~XHzw+GaFWhRNSD)7b#b4e%P(A<sf+(?T?&{wmlx|?hO5ik zMeNyPU2??`olA6Cii6AeeWfm`SL^Z+P1mqzYiT%Hr_0z4#MDMzj4dSVR^GQm7iT*= zyHl4|yL5@&P5QsxLkRz71N-<xtS)N~>C)&hF>yqflt*<Lew;l$K{}pf<EL~9J;VFY z>2d(y@hXmJzMxBBJTY`pm%EoZJ}&E0{;DonuIrNRrY;L_kxaLBIfYJlNP@e%q<y5z zA5Vyq`%iRP@l=<e&voX{(Iw_JQTUeh{6Knt)TPU3qU{@d@|_j@)aCgvR;DvIj|=ls zxH3mx3Z|CuVCFXq(+3#Lqh)1&DlaDqPR+DM-pse<!z49nm}%aRNu>OlMJa&U6@r*M zB|URG*mziykz4p@Vv5f!Opy`HWIiEGTbGqtRdX;SRW2r6$>Ss$^E$~;l+MRo1))xI z2AA?P6-rT7T8SBMYVfx@Oe9c`DI4lDV|*k2-h`<@n9y%vb0$HIVj7T^{N9RbV_P#@ zLtCbGYDYi<+cOhE2PVes%p5;m*`sdE#nOY>hk7!-OfTlI>&>(deV8q*FEdy4V}6nT z%=Iyl`Je`|!NKeuve}qCVJLe(jG4iPGf&kBX5Sde3>TP*I4m8-L<^&tmjr#sFsaj6 zX1*BDY>eY45Ryqw(rGf2=S*dm#p%phGlOWF#YD9x(KMF{_U1F$)B@(2Sj5Z>F?@Il zfm+7IN-LOyViohKtmgA;outJ&ro-64d=r1M@r}$Ew2A4$khsN3+H5Cwb`tR2OrNxe zfbVCrgoA`U@{kk79zt`RS+!2GveQX3%&Upd)okTzf^jt;xSGn_FP`^7&Frk^RaWyB zs~LIKjI?SdS2gvhn#fblaj7P9RI?1K>G{+oc4}5RHQ$?>gH263re^kXw>?gpn@UZ~ zq-H)+Qwynyc+?a*YJM6ut&5s!MNNXDCJ<56cc_^+)D#$M#)~!Im^|b=(f&hCBEf`l z8pE1&I!Ig?HRDPLU<x`?Jm?knWSpx(cY&4R5-Ax1n411wUpfobEzH#&$JL#?)xEc; z2hfWWNEc5A`VKPFn;JqVTUL7Ma?;I{i_vU(oVgor(oJ~PO<>jiTh$Fg+cu={q!sIF zPp4H!`q{fP46rZVLjCE&9!wtvBgfRek!}y8muCch3Zn_c7{+s|o3g0;oTyubsGDf0 z`&FphM5voAs9PAQdjqJe?A6uh9hb7Q6>M-7J=1IHh+oh1UvzkE<h@(y6W>lRvpwnR zD|I!Gy1+$UlcKJPP?s^N5&mjay&8$G#(_s%=*Aw$J4P!zh77AQwrYf{8da&r1ggPy zYT%X{ETo3zsL?EHRE8Qbp++63u5;BFt@>qEf2is<R2^ojk4yF3sNNIR`=DCmRkQyf z^UV*#I|muCjKnC60hzIk!vv5Y3;D53#uT&kPs7ihELi4XuG#jdk;|O<)9`7zp5Mt{ zh3r)}fh<<GVLQlXg=|*HVr4hTVTBx4$YCkDijd37L6Fl5xvY@O3c0M1%L=)yoW>dR zNlhcbMrJBkKxQh}a06thLWU}2rb0$4_wWD@@fe99PnBmNPvx{vod)Eq@&@nl9^|h= z{wn0J@)hK-@&n|rB77$`CoyN#GJ<Ahw_4m&@`4vqnX$DD@BDr&`Xe0z5D2nT$$(7A zj9`QyE3(a6Xw4Q>kflN>jG`!p;wXWVW}VuGpKo~<!|?|yqB5$OA(}Od7GW;o9qy65 z(iF|i*xK|+ZPKj%2AQPvK{WcBH#MuDW;65GF#^m$-5O|?QV&Dx7z`%RtrnLhylbgB zPPYc6CBu^SAk&hKAhVLq*lN;gmciJ|;y&!h0aJ6b`k8@sjT8pil#ory8JsnXJ6QwF z>U9k-gRDnxfUJjGmkj3hREaDyIi5TPnT$L)>E7~odB@^=^E_)z^_@ks5BUkQ5Gtga zv(-Dln=^ekpzBG<J%qM(AqNq15b;7Pq=pa3NhFQg*x4EoM82VJTQ8ZA8CgIcBIF^G z&0Oeg&1c3rTbZ4%o)Ktfbg^bME4Wy_%+K`<f3vrX)yK>jK|IB%*TNzUFY~mE)jwz; zA07lU5*Y$A6Cop!;TU0#i!idNI||8EkcG%}%)~5^mB<{BmB@T709lGGGW)w)Gq|s2 zaShg*Yg~!N?DdUc^R=th*_W(C4j>j}A#w<Z%~WoDh8#rBA<iu4Mv63bV|Vt}H!LoX zc`?yEU*GV{|As{}0--lt$Oz;kKI03%;v2r>Cw_rQPhs^Aa&sZl;SLX2V89A5vrYrP z{#{a7{ZnP(_h5t|E3%tQ8W?^-`B)4^eiT4K6h;vgGw-qmm$EE|nI9U^%^d8`VOc>v zv{4Tu-K{>UI`HR?=!DMbVs3V~dS~jzVl?`qKL%hR2E&G-rsiSw3mMDeIH*3l37Cv2 zn1<<?fth9<536^o`7AELLM*~!bFhcCnt9s8TF7+vwEC1j&Wk5-5~pwmXAy@BxQI)* zf~&ZW8@L6IeNStEOCpO;Os%nzCFBE(AMqJq@D1Pb13w|IWH@G>#)h|%f<+H_!eaJl zZ1`zDW*v*w&lbolK}e4b$cW6yf)HdyHe^Rm<U$_gMJV#401BcIil8WpqXbH#G|HeX z%Aq{|KqXhYq^hz|9W_uJby3f(VQ>_7Fo?Jq!y0Jo!HYf73%$`7{V@Q8F$6;~3?ncS zqc9p{Fb?A}0h2HVQ!yPgF$=RX2XiqG3$PH2U1`#ZVPOfDVL4V}71m-MR2yTAK_-_{ zq(f@{mX7GlK%SV5CcdHsv{X_P-=;7=ubTHN(i&HdoUj&0K?G6JnD)pPd@0(qoel)J z8|m4D_w}Q_atKX2uZQx&D3Kl$IG@tO_KKFZ7SlPLXjOYUlS5`MNAF_JMzof>Zs9dr z#4gehwq_@3OT*WA8of#$CU$7dns%DTF50Iy(mr*EcByoaIDlwpI!OCcd)kvO(R36^ zGm(d;ad4?By@mR{mnMaMG})V0lOGv08Ip-MhOC-Q&8|tt+?qV6=|#1&=%uNqm!nOH z){_FXoD8Cs#Iv3z6&h+%jmD4rE$IPoM;k>4YTh(voas-q%}|<i#!@4nN~6bI8aoyy zwK)u>ogs7+Rr(>c8!VtbAl)fVy2a5xL=|6E>3>k2ul!n*(%&`Nqv`U%g_?3oT~_<( z5*I)%DkHU`5Nh8!b*T|b1-Bqo!D70k3!`#O1-M%kU1rzOWke(DrBS+!>!8a$>ZGb3 zT4k^<Ifm)7WGq#>VU%H7OrttCOP6_bbXgXo%cteKq*$xV<juMqrGOH&mm2a}>VW5U znNI2AFr|sz_jTD%>0vLW20uy#!zc+HusF$9Z|14vtZt=3w1i5Ks`yMRMai2J^x&Gz zH&~yU@;EJjX~wL1ZEO_jJ0?|VI{eAJ+MJuK^>>noLzo+SGE?a-r&7b|HikOE-0e;> zYA4g}?Qs$>&a>5Hse@1*Xn%r|Hs{tm6#4s6yiY^1KAa-GnxtIKh^?k3R+Hzdsan;X zoN6vdHOnBg1Iphv&ZTM&GF9wO!--N&Nu*}sQS-H^IZM>E7iz)=HP673aEjp78OYg) zGG-LR2U}AL@67c=-MFT<x3jtju#6nRVE-i)R=4okU5uaGOJSC?le(-~U2?20pH)|T zs>|TibxAgLg^jx8L5;ds1DVxGQ#CeGjX6`poRSNpB$*7yXpF~H%*H&d05y2|3#6D( zdzYOc)#LyU;~1!r3zcx80xnd#g$lP#?yx{o3N>tbidUdQEuZiORHlWBwCEHz++YP2 zWJ!x4WJDHZM*$Q8$t@L72~|-KP0$=|(FMKGk1C~*)G`udFa;)JuncSQ7f62Dfxkhr z%Q2k7Ia~tCEhM!(#tXc~2YiFZ3ELH<u%v`H{E!~OHXgF05XyoimWrr@28aa7EM3tZ zy)XbnF%n}j88cvF9u|W-kE{cSfp8eeK9Kx!2IoQ5MM!b6k>o<%M4sa{-h+CG{D8)( z&J~_W314JJHsnPi6h(2A!5^rCI%tfRXpgSwiQedgei(!yE~Ni37RF#ACSfXOVIE?z z6|p#m(>RCoh(`i0;~H+_4j$tL-rzkx;VXVY=X~M<cNj?JO8Wb<5P(bwMh@ggJ`_eV zltLK7Q2`ZE8C6gXHBk$75P?W^KzH;(H2Ps62Em5m7^_bH6EPXnFasv$V-c2O1=gEK zS{fg1zc`mDuU;hSuW6zTcS^D~6Ro@$8=RzDF>-aJDw8CEQ-_k3Q-`u}nkJ8t&P>ui zmd03|`;cTH)gh%6-yYcHO*1OcFkg{9$o~zT;TdT|W}&gye9zTaaXD0Z*q=00WiEeW zV1PT(Hjjt&9;5+Er{XBXMjwiF@bTq{#Edi?G`Q<WX5r6KnVv5_-euvl!IVDo@Lk5Y zd>qZ86psqAa^xyP+M#_>N;_DKohVjJqy-Ka<7j=(LU3_5jyh<9fmn{hRR|DbDR~^i z+`1HV&@GBX9e?8rKEkC1B@s#^^RXG%;nk6KV1H-6tLWH;uMNgVQ^LVt(Ki0T!V|ne z@xFZTu(}_i#mB)EQ&C_fdjh{Plqg|hK9*rKUX3L-@D0{+#2D6K*?2Mz6q&%0jaKM} ziCBm|HXhC(5ue~ak-Qfxum-1a7w(fN3?mfbsDO%yUrHu}-W%8}T*hsDgzH}fn2yKl zXpPQTgUvXC$FLRN%pPL`X5s`c;2Gtz6!caWr!3Y4{r3_5*m#H!<K$s74m3MPsTO(8 z@}0(N9Kl&!zzw{>C!{?`){NZfjeh4y|8*>EL|_~T4%%We?wqGd1KKT)Run=6CgU%h zx<??<@ILu7z98KL@_2N^s7F-maS%uG3Bix~T0AG$!s{1&BVLgH12hVL7{NDw6x=CA z8t@FD(1>d2gbnE_0HRVxzR}p0iJmNsCuf+9`MLP^BRk!BIdG~F-*|K<x9EwjID|?i z`8-mSgOsuHaHlLqS1b&tcM91mXi^Yw@db_l(4+|lRisY`8rh8xF5xEHR;GlDef0kw zKsK_Wa%hT!m|0ts*|<o__8Csrr=tri8dF-m!GnJ!9fxpjPJbSP&;#C46mfC4BfX<I z(?gRRI5U7^FqRIbyAG2n4lhI?d0qnyTto*ZCN8H#3td-{XX0!uF@ml~H5rV9N9lk( z%)-QDL?519pqDb9;_?+u;t~3dayh=jonmuCH(lDH19suCJ7XU)!;=mS<n_{}A)5M9 z`o)Ssx>>La#}Jf}eg)Vv=`s}d%r;#vWu_dRU6)6gLfLyZKILO0l)(q%8ayeBXF*s| zHiYrTct*G4bRwa6DP1a|TRA$h(5IFzi_yOk8$#dabVOlOJ32g+_Vg8Dxvdi+MCl&7 zl!ae^3i8-R$?!a4$J4t7m#KsvU1!prhP60~{FL!4;lNz_f>4#xV|7$oOotTSQhL;B zoD4z<#2%p+1qn!mZOBm`5POV1pW}RxB4ri)I;V?k98sL0%M*0Eq{~PQyGjiNqp$$^ zt`P|2qUc!xgFmo7csenuHNLshVd2KPjwZtf7(^*^2nMBR;^_38|0)JM$xsa9q&Nf> zveEpGZh4$!K3-DWaH1F*LNPQqj?ij&6TxNZ148?<G}B{WIsS%Y;q;Q=GmHvOvbG|X z4;-W^@g~Mqr^z2hYdT5In$%XVQ<nXVFDMtmEbvrk3S&o8Y7?l`f*K5BTe5NtZbiQh zHsc6Nx90DNgGU?sc~BCss0F=2+0N_`{QhJrZye}GVDONdk&~?tolbCxrVC{xRV3V- z&aBipvXo8<v|2~^3EpmSl0uZ72Vn^E(^6RjeYaB0!pt2`auQ{B(ieo|xC&!8)hOsx zv#Mazar%K!lxmhOf(N&gOk|CEXIUA_QV4H{s5mx^a~J6o!cDwG;{=in{Vx#^WV}LP zFpYZJHmG*cl&FeEh`GV*ct)Y#^A^c=ml(py2c&=81G-n}kGY9nk5~x;6P+Y4^1q~? z2k(*P6}3<7!YL|zcQO7W@5jiWPBIJWC_jZF5?!IXV&*~3iG2?~G^*OL8+*~mliI=@ zT36fAy6TuAnHJXN*iVJ=Eb0Z&>w!u^R0Po@0~J7w%E)c>a5xJ$o(SgRfIM98f%*lw zLI-b(aNQa97pFr5XUY-)915o|2p|98@0il64JAJeZA;${Rvo6>1UaZu)J8bfica`W zts?hhE>J=X+@XfyOvUm6)Mbl_us)+}g<8h}s4MJ#fKsIy+TJK`mTu2ACjU=7WHdXr zH_E%J@!(Ek-`w7q;O=`hjgVZ9mMMA2v-+3TUZ;l<?rfja$C%@6FEqgL*X^|j89uJ| z4#SNuuJ#*ajSiZ<@_1vtll}7~<6;UkZnhC&&u$tuob3JQ87W=t6Bip@H1m6malkc2 zvr!V))_!t{am&-beuFX8!wlVN9I(INX{^@lF}sa8tJ(X6G1UI~gyHYx7?-C?<mw;A zX!#YUaiTjEmL%!be=n=o)jz$u<B12dYMBlXR>AS5uH95a{bDGSN*L9!q#h;pT+Aiu zcOSJee$SnP-<?^AF=w1HqMUQeopR>KGsXb56mIrD%k@$@%@t>jLTPko7bh2IS0~+> zmYO@ioYk5so4z`0v<_D<te4;6qJ)$bKv7o&bm2OWR$LcA!C1<rpZfbR>Z9zZ`dqM- zSIcTe>CBDijNp>h_KwJ=#iwcSnz}?yf=+qx2S<5VM-LiRmZ=|7{Lfd_E9ze+yETq0 zAl$rOaOva=XLZR<X>-kaW1FG=>Zu<1cf<bY1*5k%`=a6O<f`fBt9OR4J@BHDM$_{b zG7BXbIm+FbHunW}lrZ)7ecnBq_B^XOmOI6^8J6>W(y~5fc^>VO=EPgNLOrXns^=dC z?28hNcGl$8r!j*b81n;EFx8(&=}FHjnCf?m@#gghMq2yx2S!8=XH}6jD_E`FoqsY& z)7)vbCYE`^YfteE&+!5;@d~f;25<2W@9_a2@d=+@r&TReF@+lid#H7K@@#<tD^kJ> zsi6Mu&9e`Dkp_P7M_M=YR!VF6R5@AB1@&GfuRXt)wVF0NwY96Iy3-mJEqVAe_wi0` z9q9TOVfeDc{F>To(<03Q-qr!ShnxA)+d4!~?Pf;%Si4ocE{+d*{eE`D$?u1QQb%H? zp`4WjIV=TmQR?ygX=xxerK;SN%Tk};YS2ZK%hy`M_>Xm&J$<dC^=o2&^|cProXtLI ztTq=?R(h&~qncU4&w4y5n!Vl|J}!>PvFGu(#%t4JoXsNXtXFiyL)}3js~HwxZ4g|( zeBmOY#flZrlRvz0@jQhJ6)%{lc#-n?^As*vsCdPqMGF@QFIdpNJHT2|H@W^Q?0*4r CA!CUE diff --git a/other/slitherine_config.doc b/other/slitherine_config.doc index ace35ef8dcd11a71e25d9cba986842eb6308491d..3f06748b28075c82ae8a36a3015d321c624e8ed9 100644 GIT binary patch delta 7354 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 delta 6384 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 W@v&)a3H{<z`t<FyzbsT+Y55QM06lF0 diff --git a/other/slitherine_script.doc b/other/slitherine_script.doc deleted file mode 100644 index 1045612e3a4b6b729a3f576ae19b86b0510f4c81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 551936 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	>#<c>g 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 diff --git a/todo.txt b/other/todo.txt similarity index 100% rename from todo.txt rename to other/todo.txt diff --git a/slitherine.R b/slitherine.R index c64a0c3..669c045 100644 --- a/slitherine.R +++ b/slitherine.R @@ -1,6 +1,6 @@ ######################################################################### ## ## -## SLITHERINE v1.0.0 ## +## SLITHERINE ## ## ## ## Gael A. Millot ## ## Vittore F. Scolari ## @@ -17,7 +17,8 @@ # check that for all path, a / is added because R does not care if // is present # why alternative adj.mean.fun function does not gives the same result? # solve the problem of mean sorting to generate the theo matrices. Rigth now, sorting is performed. Code to modified is in red -# update the other slitherine files +# Take the new dev from anova contrast: 2) check no var in argument +# fun_mat_fill does not recognize half matrix anymore ################################ Aim @@ -32,7 +33,6 @@ ################################ Introduction -# Compatible with R v6.3.1 # Increase the R console window width if columns of tables are subjected to carriage return in the ...report.txt file @@ -61,7 +61,7 @@ rm(list=ls()) erase.objects = TRUE } erase.graphs = TRUE # write TRUE to erase all the graphic windows in R before starting the algorithm and FALSE otherwise -script <- "slitherine v1.0.0" +script <- "slitherine v2.0.0" ################################ End Initialization @@ -70,115 +70,53 @@ script <- "slitherine v1.0.0" ################################ Parameters that need to be set by the user -################ Mandatory settings +# see the slitherine.config file -######## File names and locations - - -project.name <- "slitherine" # name of the output folder -file.name1 <- "AT_Dndj1_D_T0.filt.2500.rebin_1162-1388.txt" # name of the first matrix file. Must be made of integer, except if theo.import parameter is set to TRUE (see below). Indeed, integers are required to generate the theoretical matrice (use of discrete distributions) -file.name2 <- "AT200_Aurel_T6.filt.2500.rebin_1162-1388.txt" # name of the second matrix file. Must be made of integer, except if theo.import parameter is set to TRUE (see below), meaning that this matrix is already serpentine binned -path.in <- "C:/Users/Gael/Documents/Hub projects/20190611 Scolari 13341/dataset/Meio/" # absolute pathway of the folder containing the input data files (file.name1 and file.name2) -path.out <- "C:/Users/Gael/Desktop/" # absolute pathway of the destination folder that will contain the results (exported data) - - -######## R packages and cute_little_R_functions file locations - - -lib.path <- NULL # vector of character that define the absolute pathway of the folder containing the R packages. Write NULL for the default path. BEWARE: default path is dependent on the system and interface used. For instance, using cygwin64 on windows 7, the path is "C:/Program Files/R/R-3.5.3/library". On the same cmputer using the R classical interface, the paths are [1] "C:/Users/Gael/Documents/R/win-library/3.5" [2] "C:/Program Files/R/R-3.5.3/library" -path.function1 <- "C:/Users/Gael/Documents/Git_projects/cute_little_R_functions/cute_little_R_functions.R" # file (and absolute pathway) of the required cute_little_R_functions toolbox. With ethernet connection available, this can also be used: "https://gitlab.pasteur.fr/gmillot/cute_little_R_functions/raw/v5.1.0/cute_little_R_functions.R" - - -######## Matrix structure - - -empty.cell.string <- 0 # if the imported matrix are half filled, put here the character string ("-" for instance) or number (0 for instance) or reserved R word (NA for instance) used to fill the empty part of the matrix. Slitherine will automatically complete the imported matrix. Write NULL if the imported matrix are not half empty - - -######## Number of Threads available - - -thread.nb <- NULL # Integer specifying the number of threads available. BEWARE: it is possible to have several threads per cpu (https://en.wikipedia.org/wiki/Thread_(computing)). Slitherine can parallelized some part of its job (including serpentine job) using thread.nb to speed up the run. If NULL, slitherine will take the number of threads available - 1. If non null, will use thread.nb if thread.nb <= number of threads available and number of threads available otherwise - - -################ End Mandatory settings - - -################ Optional settings - - -######## Serpentine - - -serp.binning <- TRUE # logical. Serpentine binning required? See https://github.com/koszullab/serpentine -python <- "C:/ProgramData/Anaconda3/python.exe" # python executable file (and pathway) to use for serpentine -path.python.lib <- "c:/programdata/anaconda3/lib/site-packages/" # vector of character that define the absolute pathway of the folder containing the serpentine package. Write NULL for the default path -serp.threshold <- 70 # serpentine threshold parameter -serp.minthreshold <- 7 # serpentine min threshold parameter -serp.iter.nb <- 128 # total serpentine iteration number parameter (this number will be split by thread.nb parameter, by progressively decreasing thread.nb til serp.iter.nb %% thread.nb != 0 (to have the same serp.iter.nb per thread) -serp.symmet.input <- TRUE # are input matrices symmetric? - - -######## HICcompare - - -hiccomp <- TRUE # logical. HICcompare required? See https://bioconductor.org/packages/release/bioc/manuals/HiCcompare/man/HiCcompare.pdf. If TRUE, the binning parameter must be non null -binning <- 2500 # integer that specifies the binning size of the imported matrices (in bp). If NULL, Hic Compare cannot be used - - -######## Theoretical matrix computation - - -# THEO1 and THEO2 matrices are synthetic matrices that are computed by slitherine using data from the 2 oberved matrices. These theoretical matrices are used to define significant difference between the two observed matrices (i.e., pixel difference far from random fluctuations). Each THEO1 and THEO2 matrix are made of n colums, each column of THEO1 representing the diagonales of OBS1, and each column of THEO2 representing the diagonales of OBS2. Thus, the number of colums of column in THEO1 and THEO2 is defined by the dimension of the observed matrices. Now the number of rows of THEO1 and THEO2, set by the n.row parameter (see below), is a variable associated to power of the significance. Greater n.row is, greater is the puissance but longer is slitherine to achieve a run, in particularly during the permutation process. Of note, In observed matrices, if the dimension is 4, 4 (square matrix) the first diagonal (main diagonal) is made of 4 values, and the last diagonal (corner diagonal) of 1 value. In theoretical matrices, such number of value is constant among the different columns representing the diagonals of the observed matrices - -theo.import <- FALSE # logical. Import theoretical matrices already obtained using slitherine? If TRUE, matrix comparison is preformed without serpentine binning (serp.binning automatically set to FALSE) -theo.file.name1 <- "mat1.theo.serp.txt" # name of the first matrix file -theo.file.name2 <- "mat2.theo.serp.txt" # name of the second matrix file -theo.path.in <- "C:/Users/Gael/Documents/Hub projects/20190611 Scolari 13341/dataset/Meio/" # absolute pathway of the folder containing the input data files (file.name1 and file.name2) -n.row <- 300 # integer value setting the number of rows of the theoretical matrices. If NULL, n.row will take the number of column of the theoretical matrices -win.size <- 20 # nb of cv values taken in the sliding windows on the CV / MEAN plot to define an average cv at the rupture slope on the CV / MEAN plot (must be less than matrix dimension - 2). Increase this value if warning messages appears saying: "PARAMETER MUST BE SUCH THAT cv^2 > 1/mu" -cv.rho.obtained <- FALSE # coefficient of variation (cv) of observed matrices 1 and 2, as well as correlation between observed matrices 1 and 2 already obtained ? If TRUE, will use the path.cv.rho parameter to load the data -path.cv.rho <- "C:/Users/Gael/Desktop/cv1_cv2_rho1_rho2_backup.RData" # file and absolute pathway to download the cv1, cv2, as well as rho1 and rho2 (which are identical) of observed matrices 1 and 2 already obtained. Write NULL if not required. Not considered if cv.rho.obtained is FALSE -correl.mat.obtained <- FALSE # theoretical matrix with permutation already obtained ? If TRUE, will use the path.theo1.theo2 parameter to load the matrices -path.theo1.theo2 <- "C:/Users/Gael/Desktop/permut_mat1_mat2_backup.RData" # file and absolute pathway to download the theoretical matrix with permutation already obtained. Write NULL if not required. Not considered if correl.mat.obtained is FALSE -single.corr <- "MAX" # either "VALUE", "MAX", "DEC1", "QUART1", "MED", "MIN" or "NO" # use MAX by default. if VALUE, a unique arbitrary value, defined in the abs.corr.limit parameter below, is used as reference to generate the correlation between the related diagonals of the theoretical theo1 and theo2 matrices (all the correlations between theo1 and theo2 diagonals will be close to abs.corr.limit). If MAX, the maximal correlation value between the observed mat1 and mat2 matrix diagonals will be used to generate the correlation between the related diagonals of theo1 and theo2 matrices (all the correlations between theo1 and theo2 diagonals will be close to max(rho1)). If DEC1, QUART1 MED or MIN, the same as MAX but using the first decile, first quartile, median or minimal correlation value between the observed mat1 and mat2 matrix diagonals, respectively. If NO, each of the observed correlations between the related diagonals of the mat1 and mat2 matrices will be used to generate the correlation of the corresponding theo1 and theo2 diagonal. In the case of NO, any observed correlation below the abs.corr.limit parameter will be set to abs.corr.limit (to avoid very long computing needed for very weak correlations) -abs.corr.limit <- 0.2 # parameter used when single.corr <- "VALUE" or single.corr <- "NO". See the single.corr parameter description -print.count <- 1e6 # during the correlation adjustment process, print a message every print.count loops ? -keep <- TRUE # keep the intermediate matrices and big objects in the working environment til the end? If TRUE, everything is saved in the final all_objects.RData. If FALSE, intermediate matrices are saved in different .RData files and then removed all along the script execution - - -######## Significant regions between the two compared matrices - - -ratio.limit.sig <- 2 # ratio value between the two matrice pixel, below which ratio is not significant? From 1 to +Inf (2 means coverage ratio less than 2 is not significant, 1 means no cutoffs in ratio values) -error <- 0 # from 0 to 1. Proportion of false positives (i.e., theo dots considered as observed dots). 0.05 means 5%, 0 means that the significant observed dot are outside of the theo cloud -range.split <- 25 # for the significant dots. If x.range is the range of the dots on the x-axis, then abs(diff(x.range) / range.split) gives the window size. Window size decreases when range.split increases -step.factor <- 10 # for the significant dots. x.win.size / step.factor gives the shift step of the window. When step.factor = 1, no overlap during the sliding. If step.factor = 2, 50% of overlap during 1 slide -ratio.normalization <- TRUE # logical. Divide the cell ratio matrix mat2 / mat1 (differential matrix) by the ratio factor mean(mat2) / mean(mat1)? If TRUE, this means that the mean of the normalized cell ratio matrix is 1, and log (parameter transfo <- TRUE)is 0 - - -######## Graphical and display parameters +################################ End Parameters that need to be set by the user -# all plots -activate.pdf <- TRUE # write TRUE for pdf display and FALSE for R display (main graphs) -optional.text <- "" # write here an optional text to include in results and graphs -width.wind <- 7 # window width (in inches) -height.wind <- 7 # window height (in inches) -dot.size <- 2 # increase or decrease the value to increase or decrease the size of the dots -line.size <- 0.75 # increase or decrease the value to increase or decrease the size of the lines -heatmap.text.size <- 8 # increase or decrease the value to increase or decrease the size of the heatmap scale text -text.size <- 12 # increase or decrease the value to increase or decrease the size of the axis text and legend text -title.text.size <- 4.5 # increase or decrease the value to increase or decrease the size of the title text -raster <- TRUE # raster mode for dot plots ? -transfo <- "log2" # Either "log2" (matrix values will be log2 converted, and sometimes log2(x +1) converted, +1 to deal with zero) or "log10" ((matrix values will be log10 converted and sometimes log10(x +1) converted, +1 to deal with zero). BEWARE: observed matrices must remain integers for serpentine. Log is only applied for display, the reason why the option "no" is not proposed (which would mean data already log converted) +################################ Config import -################ End Optional settings +if(interactive() == FALSE){ # if(grepl(x = commandArgs(trailingOnly = FALSE), pattern = "R\\.exe$|\\/R$|Rcmd\\.exe$|Rcmd$|Rgui\\.exe$|Rgui$|Rscript\\.exe$|Rscript$|Rterm\\.exe$|Rterm$")){ # detection of script usage +run.way <- "SCRIPT RUNNING DETECTION" +cat(paste0("\n\n", run.way, "\n")) +command <- paste0(commandArgs(trailingOnly = FALSE), collapse = ",") # recover the full command +args <- commandArgs(trailingOnly = TRUE) # recover arguments written after the call of the R script +if(any(is.na(args))){ +stop(paste0("\n\n================\n\nERROR IN SLITHERINE\nTHE args OBJECT HAS NA\n\n================\n\n"), call. = FALSE) +} +tempo.arg.names <- c("config.path") # objects names exactly in the same order as in the bash code and recovered in args. Here only one, because only the path of the config file to indicate after the SLITHERINE script execution +if(length(args) != length(tempo.arg.names)){ +stop(paste0("\n\n================\n\nERROR IN SLITHERINE\nTHE NUMBER OF ELEMENTS IN args (", length(args),") IS DIFFERENT FROM THE NUMBER OF ELEMENTS IN tempo.arg.names (", length(tempo.arg.names),")\nargs:", paste0(args, collapse = ","), "\ntempo.arg.names:", paste0(tempo.arg.names, collapse = ","), "\n\n================\n\n"), call. = FALSE) +} +for(i1 in 1:length(tempo.arg.names)){ +assign(tempo.arg.names[i1], args[i1]) +} +rm(tempo.arg.names, args, i1) +if( ! file.exists(config.path)){ +stop(paste0("\n\n============\n\nERROR IN SLITHERINE\nCONFIG FILE NAME AND PATH INDICATED IN EXECUTION COMMAND DOES NOT EXISTS: ", config.path, "\n\n============\n\n"), call. = FALSE) +}else{ +source(config.path) # source the config parameters +rm(config.path) +} +}else if(sys.nframe() == 0L){ # detection of copy-paste/direct execution (for debugging). With script it is also 0, with source, it is 4 +run.way <- "DIRECT RUNNING DETECTION" +cat(paste0("\n\n", run.way, "\n")) +source("C:/Users/Gael/Documents/Git_projects/SLITHERINE/slitherine.config", local = .GlobalEnv) +}else{ +run.way <- "SOURCE RUNNING DETECTION" +cat(paste0("\n\n", run.way, "\n")) +if( ! file.exists(paste0(dirname(parent.frame(2)$ofile), "/slitherine.config"))){ +stop(paste0("\n\n============\n\nERROR IN SLITHERINE\nslitherine.config FILE NOT PRESENT WHERE THE anova.contrast_source FILE IS LOCATED:\n", dirname(parent.frame(2)$ofile), "\nPLEASE, DO NOT MODIFY THE NAME OF THE slitherine.config FILE (OR MODIFY THE CODE IN THE anova.contrast_source FILE, CONFIG IMPORT SECTION)\n\n============\n\n"), call. = FALSE) +}else{ +source(paste0(dirname(parent.frame(2)$ofile), "/slitherine.config"), local = .GlobalEnv) # source the parameters used below +} +} -################################ End Parameters that need to be set by the user +################################ End Config import ################################ Recording of the initial parameters @@ -188,6 +126,8 @@ param.list <- c( "erase.objects", "erase.graphs", "script", +"run.way", +if(run.way == "SCRIPT RUNNING DETECTION"){"command"}, "project.name", "file.name1", "file.name2", @@ -235,7 +175,8 @@ param.list <- c( "text.size", "title.text.size", "raster", -"transfo" +"transfo", +"warn.secu" ) if(any(duplicated(param.list))){ stop(paste0("\n\n================\n\nINTERNAL CODE ERROR IN SLITHERINE\nTHE param.list OBJECT CONTAINS DUPLICATED ELEMENTS:\n", paste(param.list[duplicated(param.list)], collapse = " "), "\n\n================\n\n")) # message for developers @@ -932,7 +873,8 @@ y.tick.nb = 8, title = tempo.title, text.size = text.size_5fun, title.text.size = title.text.size_5fun, -classic = TRUE, +article = TRUE, +legend.width = NULL, raster = raster_5fun, x.left.extra.margin = 0, x.right.extra.margin = 0.05, @@ -1004,7 +946,8 @@ y.tick.nb = 8, title = tempo.title, text.size = text.size_5fun, title.text.size = title.text.size_5fun, -classic = TRUE, +article = TRUE, +legend.width = NULL, raster = raster_5fun, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, @@ -1016,7 +959,7 @@ y.bottom.extra.margin = 0 # y.range <- range(volcano$P_VALUE, na.rm = TRUE, finite = TRUE) # already computed above # if(transfo_5fun != "no"){fold.y.range.limit.inf <- ratio.cutoff.inf_5fun - mean.for.fold ; fold.y.range.limit.sup <- ratio.cutoff.sup_5fun - mean.for.fold }else{ fold.y.range.limit.inf <- ratio.cutoff.inf_5fun / mean.for.fold ; fold.y.range.limit.sup <- ratio.cutoff.sup_5fun / mean.for.fold} # tempo.title <- paste0("OBS MATRICES\nVOLCANO PLOT (USING FOLD CHANGE AS RATIO / MEAN(RATIO))\n", if(transfo_5fun == "log2"){"LOG2(x) FOLD CHANGE AND LOG10(y) P VALUE"}else if(transfo_5fun == "log10"){"LOG10(x) FOLD AND LOG10(y) P VALUE"}else{"NO LOG TRANSFORMATION FOR FOLD AND LOG10(y) P VALUE"}, "\nX SCALE RANGE: ", paste(fun_round(x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(y.range, 2), collapse = " , "), "\nHIC COMPARE USING ", pvalue.text_5fun, " P VALUES\nCUT-OFFS (ADJUSTED ON THE MEAN OF THE OBS RATIOS): ", fun_round(fold.y.range.limit.inf), " AND ", fun_round(fold.y.range.limit.sup)) -# fun_gg_scatter(data1 = list(L1 = volcano, L2 = data.frame(y = c(fold.y.range.limit.inf, fold.y.range.limit.sup), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "FOLD", L2 = "y"), y = list(L1 = "P_VALUE", L2 = NULL), categ = list(L1 = "SIGNIF", L2 = "CUTOFFS"), color = list(L1 = c(grey(0.40), "red"), L2 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_vline"), legend.name = list(L1 = "P VALUE", L2 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), alpha = list(0.2, 1), dot.size = dot.size_5fun, line.size = line.size, x.log = transfo_5fun, x.lab = "FOLD CHANGE", x.tick.nb = 8, y.log = "log10", y.lab = "P VALUE", y.lim = rev(y.range), y.tick.nb = 8, title = tempo.title, text.size = text.size_5fun, title.text.size = title.text.size_5fun, classic = TRUE, raster = raster_5fun, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0) # +# fun_gg_scatter(data1 = list(L1 = volcano, L2 = data.frame(y = c(fold.y.range.limit.inf, fold.y.range.limit.sup), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "FOLD", L2 = "y"), y = list(L1 = "P_VALUE", L2 = NULL), categ = list(L1 = "SIGNIF", L2 = "CUTOFFS"), color = list(L1 = c(grey(0.40), "red"), L2 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_vline"), legend.name = list(L1 = "P VALUE", L2 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), alpha = list(0.2, 1), dot.size = dot.size_5fun, line.size = line.size, x.log = transfo_5fun, x.lab = "FOLD CHANGE", x.tick.nb = 8, y.log = "log10", y.lab = "P VALUE", y.lim = rev(y.range), y.tick.nb = 8, title = tempo.title, text.size = text.size_5fun, title.text.size = title.text.size_5fun, article = FALSE, raster = raster_5fun, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0) # # end volcano plot # mask computation log.cutoff <- df_5fun$RATIO > ratio.cutoff.inf_5fun & df_5fun$RATIO < ratio.cutoff.sup_5fun # dots that are NOT outside of the 2 cutoffs. obs obtained above. 1D Vector of position @@ -1101,13 +1044,13 @@ tempo <- fun_check(data = file.name1, class = "vector", mode = "character", fun. if(tempo$problem == FALSE & substr(file.name1, nchar(file.name1) - 3, nchar(file.name1)) != ".txt"){ tempo.warning <- paste0("THE file.name1 OBJECT SETTING SHOULD BE A TXT FILE BUT DOES NOT FINISH BY \".txt\" LOWERCASE WRITTEN") cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # } tempo <- fun_check(data = file.name2, class = "vector", mode = "character", fun.name = "SLITHERINE") ; eval(ee) if(tempo$problem == FALSE & substr(file.name2, nchar(file.name2) - 3, nchar(file.name2)) != ".txt"){ tempo.warning <- paste0("THE file.name2 OBJECT SETTING SHOULD BE A TXT FILE BUT DOES NOT FINISH BY \".txt\" LOWERCASE WRITTEN") cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # } tempo <- fun_check(data = path.in, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) if(tempo$problem == FALSE & ! dir.exists(path.in)){ @@ -1172,13 +1115,13 @@ tempo <- fun_check(data = theo.file.name1, class = "vector", mode = "character", if(tempo$problem == FALSE & substr(theo.file.name1, nchar(theo.file.name1) - 3, nchar(theo.file.name1)) != ".txt"){ tempo.warning <- paste0("THE theo.file.name1 OBJECT SETTING SHOULD BE A TXT FILE BUT DOES NOT FINISH BY \".txt\" LOWERCASE WRITTEN") cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # } tempo <- fun_check(data = theo.file.name2, class = "vector", mode = "character", fun.name = "SLITHERINE") ; eval(ee) if(tempo$problem == FALSE & substr(theo.file.name2, nchar(theo.file.name2) - 3, nchar(theo.file.name2)) != ".txt"){ tempo.warning <- paste0("THE theo.file.name2 OBJECT SETTING SHOULD BE A TXT FILE BUT DOES NOT FINISH BY \".txt\" LOWERCASE WRITTEN") cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # } tempo <- fun_check(data = theo.path.in, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) if(tempo$problem == FALSE & ! dir.exists(theo.path.in)){ @@ -1265,6 +1208,7 @@ path.python.lib_2fun = path.python.lib ################ Ignition +function.name <- "slitherine.R EXECUTION" set.seed(1014) options(scipen = 7) analysis.nb <- trunc(as.numeric(Sys.time())) # to provide a specific number ot each analysis @@ -1309,7 +1253,7 @@ graphics.off() }else{ tempo.warning <- paste0("GRAPHICS HAVE NOT BEEN ERASED. GRAPHICAL PARAMETERS MAY HAVE NOT BEEN REINITIALIZED") fun_report(data = tempo.warning, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # } @@ -1326,7 +1270,7 @@ mat1.mix <- as.matrix(read.table(paste0(theo.path.in, "/", theo.file.name1))) mat2.mix <- as.matrix(read.table(paste0(theo.path.in, "/", theo.file.name2))) tempo.warning <- paste0("IMPORT OF THEORETICAL MATRICES, WHICH WOULD MEAN THAT THE OBSERVED MATRICES IMPORTED HAVE ALREADY BEEN BINNED USING SERPENTINE") cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # } @@ -1389,7 +1333,7 @@ cat(paste0("\n\n============\n\nERROR IN SLITHERINE: MATRIX 1 AND 2 MUST BE SQUA tempo.cat <- paste0("MATRIX 1 AND 2 HAVE IDENTICAL CONTENT") cat(paste0("\nWARNING: ", tempo.cat, "\n")) fun_report(data = tempo.cat, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # } if(theo.import == TRUE){ # check the variable names. Still mix ? for(i0 in 1:2){ @@ -1408,7 +1352,7 @@ cat(paste0("\n\n============\n\nERROR IN SLITHERINE: DIMENSIONS OF THEORETICAL M tempo.cat <- paste0("THEORETICAL MATRIX 1 AND 2 HAVE IDENTICAL CONTENT") cat(paste0("\nWARNING: ", tempo.cat, "\n")) fun_report(data = tempo.cat, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # } if(ncol(mat1.mix) != ncol(mat1.obs.ini)){ param.check <- c(param.check, TRUE) @@ -1443,10 +1387,10 @@ if( ! any(mat1.obs.ini %in% empty.cell.string)){ # works for NA, Inf, etc. stop(paste0("\n\n============\n\nERROR IN SLITHERINE\nPARAMETER empty.cell.string SET TO ", empty.cell.string, ", WHICH IS NOT PRESENT IN THE IMPORTED MATRIX 1\n\n============\n\n")) } tempo.mat1.obs <- fun_mat_fill(mat = mat1.obs.ini, empty.cell.string = empty.cell.string) -if( ! is.null(tempo.mat1.obs$warnings)){ +if( ! is.null(tempo.mat1.obs$warn)){ mat1.modif <- TRUE -fun_report(data = tempo.mat1.obs$warnings, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.mat1.obs$warnings) +fun_report(data = tempo.mat1.obs$warn, path = path.out, output = log.file) +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.mat1.obs$warn) }else{ fun_report(data = paste0("MATRIX 1 DETECTED AS SYMMETRIC"), path = path.out, output = log.file) } @@ -1455,10 +1399,10 @@ if( ! any(mat2.obs.ini %in% empty.cell.string)){ # works for NA, Inf, etc. stop(paste0("\n\n============\n\nERROR IN SLITHERINE\nPARAMETER empty.cell.string SET TO ", empty.cell.string, ", WHICH IS NOT PRESENT IN THE IMPORTED MATRIX 2\n\n============\n\n")) } tempo.mat2.obs <- fun_mat_fill(mat = mat2.obs.ini, empty.cell.string = empty.cell.string) -if( ! is.null(tempo.mat2.obs$warnings)){ +if( ! is.null(tempo.mat2.obs$warn)){ mat2.modif <- TRUE -fun_report(data = tempo.mat2.obs$warnings, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.mat2.obs$warnings) # in fact, abs(tempo.cor) is systematically used +fun_report(data = tempo.mat2.obs$warn, path = path.out, output = log.file) +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.mat2.obs$warn) # }else{ fun_report(data = paste0("MATRIX 2 DETECTED AS SYMMETRIC"), path = path.out, output = log.file) } @@ -1486,7 +1430,7 @@ mat2.obs[as.matrix(as.data.frame(list(1:nrow(mat2.obs), 1:ncol(mat2.obs))))] <- mat2.modif <- TRUE tempo.warning <- paste0("MAIN DIAGONAL OF MATRIX 2 HAS BEEN REPLACED BY 0") fun_report(data = tempo.warning, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # } # end diagonal removal @@ -1805,7 +1749,7 @@ tempo.data.plot2$MEAN.MINUS.SD[is.na(tempo.data.plot2$MEAN.MINUS.SD)] <- tempo.d } tempo.data.plot2 <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot2), tempo.data.plot2) tempo.title <-paste0("MAT1 OBS\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nDIAGONAL NB FROM MAIN TO CORNER\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot2), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.x.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot2), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "DIAGONAL NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.x.range, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot2$COLUMN_NB, xend = tempo.data.plot2$COLUMN_NB, y = tempo.data.plot2$MEAN.MINUS.SD, yend = tempo.data.plot2$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) +fun_gg_scatter(data1 = list(tempo.data.plot2), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "DIAGONAL NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.x.range, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot2$COLUMN_NB, xend = tempo.data.plot2$COLUMN_NB, y = tempo.data.plot2$MEAN.MINUS.SD, yend = tempo.data.plot2$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) # end mean versus index plot # Mean Deviation (MD) plot of the observed matrix if(activate.pdf == TRUE){ @@ -1814,7 +1758,7 @@ invisible(dev.set(pdf.nb)) fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) } tempo.title <- paste0("MAT1 OBS\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\n") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("SD", "y.sd.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range, y.log = transfo, y.lab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("SD", "y.sd.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range, y.log = transfo, y.lab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # end Mean Deviation (MD) plot of the observed matrix # mean / cor of the observed matrix @@ -1824,7 +1768,7 @@ invisible(dev.set(pdf.nb)) fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) } tempo.title <- paste0("MAT1 OBS\nMEAN VERSUS MAT1 OBS / MAT2 OBS SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range, y.log = "no", y.lab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range, y.log = "no", y.lab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # end mean / cor of the observed matrix # mean / cv of the observed matrix @@ -1834,7 +1778,7 @@ invisible(dev.set(pdf.nb)) fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) } tempo.title <- paste0("MAT1 OBS\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND CV LOG2(x) "}else if(transfo == "log10"){"MEAN AND CV LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cv.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cv.y.range, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\n") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_cv.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cv.y.range, y.log = transfo, y.lab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_cv.coord.obs +fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_cv.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cv.y.range, y.log = transfo, y.lab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_cv.coord.obs # end mean / cv of the observed matrix # cv selection using increasing windows to detect the average constant cv @@ -1846,7 +1790,7 @@ win.size.ini <- win.size if(win.size >= length(sort.cv1)){ tempo.warning <- paste0("THE win.size PARAMETER SETTING (", win.size, ") IS OVER OR EQUAL TO THE NUMBER OF NON NA DIAGONAL CV OF THE OBSERVED MATRIX 1 (", length(sort.cv1), ")\nTHE win.size PARAMETER HAS BEEN RESET TO VALUE: ", length(sort.cv1) - 1) cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # win.size <- length(sort.cv1) - 1 fun_report(data = tempo.warning, output = log.file, path = path.out) } @@ -1899,7 +1843,7 @@ invisible(dev.set(pdf.nb)) fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) } tempo.title <- paste0("MAT1 OBS\nSLIDING CV COMPUTATION\nBLUE DOTS: MEAN+/-SD OF CV IN INCREASING WINDOWS OF CV VALUES\nGREEN LINE: SELECTED CV VALUE IS ", round(cv.select.mat1.obs, 2), ", BASED ON MEDIAN OF ", cv.select.nb, " BLUE DOTS\nRED LINE: POISSON DISTRIB\n", if(transfo == "log2"){"LOG2(x) "}else if(transfo == "log10"){"LOG10(x) "}else{"NO "}, "TRANSFORMATION") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_cv.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cv.y.range, y.log = transfo, y.lab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0, add = paste0('+ ggplot2::geom_point(data = data.frame(x = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean)), ggplot2::aes(x = x, y = y), color = "blue", size = dot.size, alpha = 0.3) + ggplot2::geom_segment(data = data.frame(x = get(transfo)(mean.win.median), xend = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean - cv.win.sd), yend = get(transfo)(cv.win.mean + cv.win.sd)), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = "blue", alpha = 0.3) + ggplot2::geom_hline(data = data.frame(y = get(transfo)(cv.select.mat1.obs)), ggplot2::aes(yintercept = y), color = "green", size = line.size) + ggplot2::theme_classic(base_size = text.size)', if(raster == TRUE){'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size), aspect.ratio = 1)'}else{'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size))'})) +fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_cv.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cv.y.range, y.log = transfo, y.lab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0, add = paste0('+ ggplot2::geom_point(data = data.frame(x = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean)), ggplot2::aes(x = x, y = y), color = "blue", size = dot.size, alpha = 0.3) + ggplot2::geom_segment(data = data.frame(x = get(transfo)(mean.win.median), xend = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean - cv.win.sd), yend = get(transfo)(cv.win.mean + cv.win.sd)), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = "blue", alpha = 0.3) + ggplot2::geom_hline(data = data.frame(y = get(transfo)(cv.select.mat1.obs)), ggplot2::aes(yintercept = y), color = "green", size = line.size) + ggplot2::theme_classic(base_size = text.size)', if(raster == TRUE){'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size), aspect.ratio = 1)'}else{'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size))'})) # cv selection using increasing windows to detect the average constant cv # END MATRIX 1 @@ -1949,7 +1893,7 @@ tempo.data.plot2$MEAN.MINUS.SD[is.na(tempo.data.plot2$MEAN.MINUS.SD)] <- tempo.d } tempo.data.plot2 <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot2), tempo.data.plot2) tempo.title <-paste0("MAT2 OBS\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nDIAGONAL NB FROM MAIN TO CORNER\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot2), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.x.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot2), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "DIAGONAL NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.x.range, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot2$COLUMN_NB, xend = tempo.data.plot2$COLUMN_NB, y = tempo.data.plot2$MEAN.MINUS.SD, yend = tempo.data.plot2$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) +fun_gg_scatter(data1 = list(tempo.data.plot2), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "DIAGONAL NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.x.range, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot2$COLUMN_NB, xend = tempo.data.plot2$COLUMN_NB, y = tempo.data.plot2$MEAN.MINUS.SD, yend = tempo.data.plot2$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) # end mean versus index plot # Mean Deviation (MD) plot of the observed matrix if(activate.pdf == TRUE){ @@ -1958,7 +1902,7 @@ invisible(dev.set(pdf.nb)) fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) } tempo.title <- paste0("MAT2 OBS\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\n") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("SD", "y.sd.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range, y.log = transfo, y.lab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("SD", "y.sd.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range, y.log = transfo, y.lab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # end Mean Deviation (MD) plot of the observed matrix # mean / cor of the observed matrix @@ -1968,7 +1912,7 @@ invisible(dev.set(pdf.nb)) fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) } tempo.title <- paste0("MAT2 OBS\nMEAN VERSUS MAT1 OBS / MAT2 OBS SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range, y.log = "no", y.lab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range, y.log = "no", y.lab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # end mean / cor of the observed matrix # mean / cv of the observed matrix @@ -1978,7 +1922,7 @@ invisible(dev.set(pdf.nb)) fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) } tempo.title <- paste0("MAT2 OBS\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND CV LOG2(x) "}else if(transfo == "log10"){"MEAN AND CV LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cv.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cv.y.range, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\n") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_cv.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cv.y.range, y.log = transfo, y.lab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_cv.coord.obs +fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_cv.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cv.y.range, y.log = transfo, y.lab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_cv.coord.obs # end mean / cv of the observed matrix # cv selection using increasing windows to detect the average constant cv @@ -1990,7 +1934,7 @@ win.size <- win.size.ini # in case modified during first MAT1 analysis if(win.size >= length(sort.cv2)){ tempo.warning <- paste0("THE win.size PARAMETER SETTING (", win.size, ") IS OVER OR EQUAL TO THE NUMBER OF NON NA DIAGONAL CV OF THE OBSERVED MATRIX 2 (", length(sort.cv2), ")\nTHE win.size PARAMETER HAS BEEN RESET TO VALUE: ", length(sort.cv2) - 1) cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # win.size <- length(sort.cv2) - 1 fun_report(data = tempo.warning, output = log.file, path = path.out) } @@ -2044,7 +1988,7 @@ invisible(dev.set(pdf.nb)) fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) } tempo.title <- paste0("MAT2 OBS\nSLIDING CV COMPUTATION\nBLUE DOTS: MEAN+/-SD OF CV IN INCREASING WINDOWS OF CV VALUES\nGREEN LINE: SELECTED CV VALUE IS ", round(cv.select.mat2.obs, 2), ", BASED ON MEDIAN OF ", cv.select.nb, " BLUE DOTS\nRED LINE: POISSON DISTRIB\n", if(transfo == "log2"){"LOG2(x) "}else if(transfo == "log10"){"LOG10(x) "}else{"NO "}, "TRANSFORMATION") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_cv.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cv.y.range, y.log = transfo, y.lab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0, add = paste0('+ ggplot2::geom_point(data = data.frame(x = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean)), ggplot2::aes(x = x, y = y), color = "blue", size = dot.size, alpha = 0.3) + ggplot2::geom_segment(data = data.frame(x = get(transfo)(mean.win.median), xend = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean - cv.win.sd), yend = get(transfo)(cv.win.mean + cv.win.sd)), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = "blue", alpha = 0.3) + ggplot2::geom_hline(data = data.frame(y = get(transfo)(cv.select.mat2.obs)), ggplot2::aes(yintercept = y), color = "green", size = line.size) + ggplot2::theme_classic(base_size = text.size)', if(raster == TRUE){'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size), aspect.ratio = 1)'}else{'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size))'})) +fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, x.lim = m_cv.x.range, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cv.y.range, y.log = transfo, y.lab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0, add = paste0('+ ggplot2::geom_point(data = data.frame(x = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean)), ggplot2::aes(x = x, y = y), color = "blue", size = dot.size, alpha = 0.3) + ggplot2::geom_segment(data = data.frame(x = get(transfo)(mean.win.median), xend = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean - cv.win.sd), yend = get(transfo)(cv.win.mean + cv.win.sd)), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = "blue", alpha = 0.3) + ggplot2::geom_hline(data = data.frame(y = get(transfo)(cv.select.mat2.obs)), ggplot2::aes(yintercept = y), color = "green", size = line.size) + ggplot2::theme_classic(base_size = text.size)', if(raster == TRUE){'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size), aspect.ratio = 1)'}else{'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size))'})) # cv selection using increasing windows to detect the average constant cv # END MATRIX 2 @@ -2270,7 +2214,7 @@ tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.d tempo.data.negbinom <- data.frame(x.green = mean.nb1, y.green = cv.nb1 * mean.nb1) # neg binomiale distrib } tempo.title <- paste0("MAT1 THEO\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\nGREEN LINE: NEG BINOM DISTRIB") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range2, y.log = transfo, y.lab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range2, y.log = transfo, y.lab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # end Mean Deviation (MD) plot of the observed matrix # mean versus index plot if(activate.pdf == TRUE){ @@ -2287,7 +2231,7 @@ tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.dat } tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) tempo.title <- paste0("MAT1 THEO\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) +fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) # end mean versus index plot @@ -2328,7 +2272,7 @@ tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.d tempo.data.negbinom <- data.frame(x.green = mean.nb2, y.green = cv.nb2 * mean.nb2) # neg binomiale distrib } tempo.title <- paste0("MAT2 THEO\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\nGREEN LINE: NEG BINOM DISTRIB") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range2, y.log = transfo, y.lab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range2, y.log = transfo, y.lab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # end Mean Deviation (MD) plot # mean versus index plot if(activate.pdf == TRUE){ @@ -2345,7 +2289,7 @@ tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.dat } tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) tempo.title <- paste0("MAT2 THEO\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) +fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) # end mean versus index plot @@ -2374,7 +2318,7 @@ if(transfo != "no"){ tempo.data.plot[, "MEAN"] <- get(transfo)(tempo.data.plot[, "MEAN"]) # log(x + 1) only for heatmap } tempo.title <- paste0("(MAT1 OBS / MAT2 OBS) MEAN VERSUS (MAT1 OBS / MAT2 OBS) SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range2, y.log = "no", y.lab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range2, y.log = "no", y.lab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # end mean / cor of the observed matrix # mean / cor of the theoretical matrices if(activate.pdf == TRUE){ @@ -2387,7 +2331,7 @@ if(transfo != "no"){ tempo.data.plot[, "MEAN"] <- get(transfo)(tempo.data.plot[, "MEAN"]) # log(x + 1) only for heatmap } tempo.title <- paste0("(MAT1 THEO / MAT2 THEO) MEAN VERSUS (MAT1 THEO / MAT2 THEO) SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range2, y.log = "no", y.lab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range2, y.log = "no", y.lab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # Permutation of the mat1.ini values to have the mat1.obs correlation on the diagonales between mat1 and mat2 if(correl.mat.obtained == TRUE){ tempo.cat <- paste0("BEWARE: mat1.ini, mat1.perm, mat2.ini and mat2.perm THERORETICAL MATRICES USED HAVE BEEN DOWNLOADED FROM:\n", path.theo1.theo2) @@ -2585,7 +2529,7 @@ for(i0 in 1:length(paral.output.list)){ # compartment relatives to each parallel for(i1 in 1:length(paral.output.list[[i0]])){ # compartment relatives to each diagonal inside parallelization permut.list[[as.integer(names(paral.output.list[[i0]])[i1])]] <- paral.output.list[[i0]][[i1]]$data names(permut.list)[as.integer(names(paral.output.list[[i0]])[i1])] <- names(paral.output.list[[i0]])[i1] -warning.list[[as.integer(names(paral.output.list[[i0]])[i1])]] <- if(is.null(paral.output.list[[i0]][[i1]]$warnings)){"NO WARNING"}else{paral.output.list[[i0]][[i1]]$warnings} # no NULL assignation in list +warning.list[[as.integer(names(paral.output.list[[i0]])[i1])]] <- if(is.null(paral.output.list[[i0]][[i1]]$warn)){"NO WARNING"}else{paral.output.list[[i0]][[i1]]$warn} # no NULL assignation in list names(warning.list)[as.integer(names(paral.output.list[[i0]])[i1])] <- names(paral.output.list[[i0]])[i1] cor.list[[as.integer(names(paral.output.list[[i0]])[i1])]] <- paral.output.list[[i0]][[i1]]$cor names(cor.list)[as.integer(names(paral.output.list[[i0]])[i1])] <- names(paral.output.list[[i0]])[i1] @@ -2645,13 +2589,13 @@ tempo.title <- paste0("BEFORE PERMUTATION | (MAT1 THEO / MAT2 THEO) SPEARMAN C # par(xpd = TRUE) # text(x = tempo.coord$x.left.plot.region, y = tempo.coord$y.top.fig.region, labels = tempo.title, cex = 0.65, adj = c(0, 1)) # par(xpd = FALSE) -fun_gg_scatter(data1 = tempo.data.plot, x = "MAT1", y = "MAT2", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, x.lim = if(diff(x.tempo.range) == 0){c(unique(x.tempo.range) - 1, unique(x.tempo.range) + 1)}else{x.tempo.range}, x.tick.nb = 8, y.lim = if(diff(y.tempo.range) == 0){c(unique(y.tempo.range) - 1, unique(y.tempo.range) + 1)}else{y.tempo.range}, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = FALSE) +fun_gg_scatter(data1 = tempo.data.plot, x = "MAT1", y = "MAT2", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, x.lim = if(diff(x.tempo.range) == 0){c(unique(x.tempo.range) - 1, unique(x.tempo.range) + 1)}else{x.tempo.range}, x.tick.nb = 8, y.lim = if(diff(y.tempo.range) == 0){c(unique(y.tempo.range) - 1, unique(y.tempo.range) + 1)}else{y.tempo.range}, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = FALSE) tempo.data.plot <- data.frame(MAT1 = permut.list[[i0]], MAT2 = mat2.perm[, i0]) x.tempo.range <- range(tempo.data.plot[, "MAT1"], na.rm = TRUE, finite = TRUE) y.tempo.range <- range(tempo.data.plot[, "MAT2"], na.rm = TRUE, finite = TRUE) tempo.cor <- suppressWarnings(cor(x = tempo.data.plot[, "MAT1"], y = tempo.data.plot[, "MAT2"], use = "pairwise.complete.obs", method = "spearman")) tempo.title <- paste0("AFTER PERMUTATION | (MAT1 THEO / MAT2 THEO) SPEARMAN CORRELATION\nOBS MATRIX CORRESPONDING DIAGONAL NUMBER: ", i0, "\nCORRELATION VALUE: ", if(is.na(tempo.cor)){NA}else{fun_round(tempo.cor)}, "\nCORRELATION INDICATED BY THE fun_permut() FUNCTION: ", if(is.na(cor.list[[i0]])){NA}else{fun_round(cor.list[[i0]])}, "\nX SCALE RANGE: ", paste(fun_round(x.tempo.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(y.tempo.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MAT1", y = "MAT2", color = fun_gg_palette(1), geom = "geom_point", alpha = 0.5, dot.size = dot.size, x.lim = if(diff(x.tempo.range) == 0){c(unique(x.tempo.range) - 1, unique(x.tempo.range) + 1)}else{x.tempo.range}, x.tick.nb = 8, y.lim = if(diff(y.tempo.range) == 0){c(unique(y.tempo.range) - 1, unique(y.tempo.range) + 1)}else{y.tempo.range}, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = FALSE) +fun_gg_scatter(data1 = tempo.data.plot, x = "MAT1", y = "MAT2", color = fun_gg_palette(1), geom = "geom_point", alpha = 0.5, dot.size = dot.size, x.lim = if(diff(x.tempo.range) == 0){c(unique(x.tempo.range) - 1, unique(x.tempo.range) + 1)}else{x.tempo.range}, x.tick.nb = 8, y.lim = if(diff(y.tempo.range) == 0){c(unique(y.tempo.range) - 1, unique(y.tempo.range) + 1)}else{y.tempo.range}, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = FALSE) # fun_prior_plot(param.reinitial = FALSE, xlog.scale = FALSE, ylog.scale = FALSE, remove.label = TRUE, remove.x.axis = TRUE, remove.y.axis = TRUE, std.x.range = FALSE, std.y.range = FALSE, down.space = height.wind / 7 * 1, left.space = width.wind / 7 * 1, up.space = height.wind / 7 * 1, right.space = width.wind / 7 * 1, orient = 1, dist.legend = 5, tick.length = 0.5, box.type = "n", amplif.label = 1, amplif.axis = 1, display.extend = FALSE, return.par = FALSE) # plot(tempo.data.plot[, "MAT1"], tempo.data.plot[, "MAT2"], col = hsv(1, 0.5, 1, 0.5), pch = 16, x.lim = if(diff(x.tempo.range) == 0){c(unique(x.tempo.range) - 1, unique(x.tempo.range) + 1)}else{x.tempo.range}, y.lim = if(diff(y.tempo.range) == 0){c(unique(y.tempo.range) - 1, unique(y.tempo.range) + 1)}else{y.tempo.range}) # tempo.coord <- fun_post_plot(x.side = 1, x.lab = "MAT1", y.side = 2, y.lab = "MAT2", x.axis.magnific = 1, x.label.magnific = 1, y.axis.magnific = 1, y.label.magnific = 1) @@ -2688,7 +2632,7 @@ if(transfo != "no"){ tempo.data.plot[, "MEAN"] <- get(transfo)(tempo.data.plot[, "MEAN"]) # log(x + 1) only for heatmap } tempo.title <- paste0("AFTER PERMUTATION\n(MAT1 THEO / MAT2 THEO) MEAN VERSUS (MAT1 THEO / MAT2 THEO) SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range2, y.log = "no", y.lab = "CORRELATION",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range2, y.log = "no", y.lab = "CORRELATION",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # end mean / cor of the theoretical matrices # correlation versus index before and after permutation if(activate.pdf == TRUE){ @@ -2702,7 +2646,7 @@ stop(tempo.cat) } tempo.data.plot <- data.frame(CORRELATION = c(rho2, unlist(cor.list)), COLUMN_NB = c(1:length(rho2), 1:length(rho2)), KIND = rep(c("OBS", "THEO"), each = length(rho2))) tempo.title <- paste0("SPEARMAN CORRELATION BETWEEN MAT1 OBS / MAT2 OBS\nCOMPARISON WITH MAT1 THEO / MAT2 THEO AFTER PERMUTATION\nX SCALE RANGE: ", paste(range(1:length(rho2), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: -1, 1") -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("CORRELATION"), categ = list("KIND"), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "DIAGONAL INDEX", x.tick.nb = 8, y.log = "no", y.lab = "CORRELATION", y.lim = c(-1, 1), y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster) +fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("CORRELATION"), categ = list("KIND"), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "DIAGONAL INDEX", x.tick.nb = 8, y.log = "no", y.lab = "CORRELATION", y.lim = c(-1, 1), y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster) # end correlation versus index before and after permutation @@ -2777,7 +2721,7 @@ tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.dat } tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) tempo.title <- paste0("MAT1 THEO\nAFTER PERMUTATION AND BEFORE SUB SAMPLING\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) +fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) if(activate.pdf == TRUE){ invisible(dev.set(pdf.nb)) }else{ @@ -2792,7 +2736,7 @@ tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.dat } tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) tempo.title <- paste0("MAT2 THEO\nAFTER PERMUTATION AND BEFORE SUB SAMPLING\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) +fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) # end mean versus index plot before sub sampling if(keep == FALSE){ tempo.list <- c("mat1.perm", "mat2.perm") @@ -2814,7 +2758,7 @@ tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.dat } tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) tempo.title <- paste0("MAT1 THEO\nAFTER PERMUTATION AND AFTER SUB SAMPLING\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) +fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) if(activate.pdf == TRUE){ invisible(dev.set(pdf.nb)) }else{ @@ -2829,7 +2773,7 @@ tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.dat } tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) tempo.title <- paste0("MAT2 THEO\nAFTER PERMUTATION AND AFTER SUB SAMPLING\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) +fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "COLUMN NB", x.tick.nb = 8, y.log = transfo, y.lab = "MEAN", y.lim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) # end mean versus index plot after sub sampling @@ -2851,7 +2795,7 @@ tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.d tempo.data.negbinom <- data.frame(x.green = mean.nb1, y.green = cv.nb1 * mean.nb1) # neg binomiale distrib } tempo.title <- paste0("MAT1 THEO\nAFTER PERMUTATION AND SUB SAMPLING\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\nGREEN LINE: NEG BINOM DISTRIB") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range2, y.log = transfo, y.lab = "SD",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range2, y.log = transfo, y.lab = "SD",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # end MD plot for the theoretical matrix 1 after sub sampling and permutation # MD plot for the theoretical matrix 2 after sub sampling and permutation @@ -2867,7 +2811,7 @@ tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.d tempo.data.negbinom <- data.frame(x.green = mean.nb2, y.green = cv.nb2 * mean.nb2) # neg binomiale distrib } tempo.title <- paste0("MAT2 THEO\nAFTER PERMUTATION AND SUB SAMPLING\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\nGREEN LINE: NEG BINOM DISTRIB") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range2, y.log = transfo, y.lab = "SD",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, x.lim = m_sd.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_sd.y.range2, y.log = transfo, y.lab = "SD",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # end MD plot for the theoretical matrix 2 after sub sampling and permutation # mean / cor of the theoretical matrices @@ -2881,7 +2825,7 @@ if(transfo != "no"){ tempo.data.plot[, "MEAN"] <- get(transfo)(tempo.data.plot[, "MEAN"]) # log(x + 1) only for heatmap } tempo.title <- paste0("AFTER PERMUTATION AND SUB SAMPLING\n(MAT1 THEO / MAT2 THEO) MEAN VERSUS (MAT1 THEO / MAT2 THEO) SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range2, y.log = "no", y.lab = "CORRELATION",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs +fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, x.lim = m_cor.x.range2, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.lim = m_cor.y.range2, y.log = "no", y.lab = "CORRELATION",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs # correlation versus index before and after subsampling tempo.cor <- suppressWarnings(mapply(FUN = "cor", c(data.frame(mat1.mix)), c(data.frame(mat2.mix)), use = "pairwise.complete.obs", method = "spearman")) if(activate.pdf == TRUE){ @@ -2895,7 +2839,7 @@ stop(tempo.cat) } tempo.data.plot <- data.frame(CORRELATION = c(rho2, unlist(cor.list), tempo.cor), COLUMN_NB = c(1:length(rho2), 1:length(rho2), 1:length(rho2)), KIND = rep(c("OBS", "THEO_AFTER_PERMUTATION", "THEO_AFTER_DOWNSAMPLING"), each = length(rho2))) tempo.title <- paste0("SPEARMAN CORRELATION BETWEEN MAT1 OBS / MAT2 OBS\nCOMPARISON WITH MAT1 THEO / MAT2 THEO 1) AFTER PERMUTATION AND 2) AFTER PERMUTATION AND DOWNSAMPLING\nX SCALE RANGE: ", paste(range(1:length(rho2), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: -1, 1") -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("CORRELATION"), categ = list("KIND"), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "DIAGONAL INDEX", x.tick.nb = 8, y.log = "no", y.lab = "CORRELATION", y.lim = c(-1, 1), y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster) +fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("CORRELATION"), categ = list("KIND"), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, x.log = "no", x.lab = "DIAGONAL INDEX", x.tick.nb = 8, y.log = "no", y.lab = "CORRELATION", y.lim = c(-1, 1), y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, article = TRUE, legend.width = NULL, raster = raster) # end correlation versus index before and after subsampling @@ -2910,7 +2854,7 @@ if(serp.binning == TRUE){ serp.binning <- FALSE tempo.warning <- paste0("THE serp.binning PARAMETER SETTING HAS BEEN SET TO TRUE, BUT THEORETICAL MATRICES HAVE BEEN IMPORTED\n-> PRE SERPENTINE ANALYSIS IS SUFFICIENT (IF YOU NEED MORE SERPENTINE BINNING, INCREASE THE VALUE OF THE serp.iter.nb PARAMETER)\n-> serp.binning PARAMETER RESET TO FALSE") cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # } } @@ -3064,9 +3008,9 @@ fun_gg_empty_graph(text = "SIGNIFICANT DIFFERENCES PRE SERPENTINE\n(SLITHERINE)" fun_report(data = paste0("SEGMENTATION OF THE THEORETICAL DOT CLOUD (MEAN CELL / RATIO CELL PLOT) PERFORMED ON NON NORMALIZED DATA\nBECAUSE OF DISCRETE RATIO VALUES THAT ARE PRESENTS FOR LOW MEANS\nINDEED, NORMALIZATION SLIGHTLY SHIFTS THE RATIO VALUES BETWEEN THEO AND OBS CLOUDS, WHICH INDUCES LOW MEAN CELL DOTS (I.E., NOISE) TO BE SIGNIFICANT AFTER SEGMENTATION. THEN, DEPENDING ON USER SETTINGS (SEE ABOVE), RATIO NORMALIZATION ARE PERFORMED ON SEGMENTATION RESULT DATA, BEFORE APPLYING THE CUTOFFS FILTERING"), output = log.file, path = path.out) segment.pre.serp <- fun_segmentation(data1 = theo.df.pre.for.segm, x1 = "MEAN", y1 = "RATIO", x.range.split = range.split, x.step.factor = step.factor, error = error, data2 = obs.df.pre.for.segm, x2 = "MEAN", y2 = "RATIO", data2.pb.dot = "signif", plot = FALSE, graph.in.file = FALSE) fun_report(data = "UNKNOWN DOTS HAVE BEEN CONSIDERED AS SIGNIFICANTS (ARGUMENT data2.pb.dot OF fun_segmentation() SET TO \"signif\")", output = log.file, path = path.out) -# cat(paste0("\n", segment.pre.serp$warnings, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), segment.pre.serp$warnings) # in fact, abs(tempo.cor) is systematically used -fun_report(data = segment.pre.serp$warnings, output = log.file, path = path.out) +# cat(paste0("\n", segment.pre.serp$warn, "\n")) +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), segment.pre.serp$warn) # +fun_report(data = segment.pre.serp$warn, output = log.file, path = path.out) if( ! is.null(segment.pre.serp$hframe)){ names(segment.pre.serp$hframe)[names(segment.pre.serp$hframe) == "x"] <- "MEAN" # names(segment.pre.serp$hframe)[names(segment.pre.serp$hframe) == "y"] <- "RATIO" # @@ -3177,10 +3121,10 @@ fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wi } if( ! is.null(signif.theo.dot.pre)){ # signif dots in theo matrices tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nTHEO MAT ALONE + THEO SIGNIFICANT DOTS\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.pre, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.pre, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.pre), " AND ", fun_round(ratio.cutoff.sup.pre)) -fun_gg_scatter(data1 = list(L1 = theo.df.pre, L2 = signif.theo.dot.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = theo.df.pre, L2 = signif.theo.dot.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) }else{ tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nTHEO MAT ALONE (NO THEO SIGNIFICANT DOTS)\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.pre, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.pre, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.pre), " AND ", fun_round(ratio.cutoff.sup.pre)) -fun_gg_scatter(data1 = list(L1 = theo.df.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = theo.df.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) } if(activate.pdf == TRUE){ invisible(dev.set(pdf.nb)) @@ -3189,10 +3133,10 @@ fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wi } if( ! is.null(signif.obs.dot.pre)){ # signif dots in obs matrices tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS MAT ALONE + OBS SIGNIFICANT DOTS\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.pre, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.pre, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.pre), " AND ", fun_round(ratio.cutoff.sup.pre)) -fun_gg_scatter(data1 = list(L1 = obs.df.pre, L2 = signif.obs.dot.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = obs.df.pre, L2 = signif.obs.dot.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) }else{ tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS MAT ALONE (NO OBS SIGNIFICANT DOTS)\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.pre, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.pre, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.pre), " AND ", fun_round(ratio.cutoff.sup.pre)) -fun_gg_scatter(data1 = list(L1 = obs.df.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = obs.df.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) } if(activate.pdf == TRUE){ invisible(dev.set(pdf.nb)) @@ -3201,10 +3145,10 @@ fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wi } if( ! is.null(signif.obs.dot.pre)){ # signif dots in obs matrices tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS AND THEO MAT + OBS SIGNIFICANT DOTS\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.pre, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.pre, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.pre), " AND ", fun_round(ratio.cutoff.sup.pre)) -fun_gg_scatter(data1 = list(L1 = final.df.pre, L2 = signif.obs.dot.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = final.df.pre, L2 = signif.obs.dot.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) }else{ tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS AND THEO MAT (NO OBS SIGNIFICANT DOTS)\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.pre, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.pre, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.pre), " AND ", fun_round(ratio.cutoff.sup.pre)) -fun_gg_scatter(data1 = list(L1 = final.df.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = final.df.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.pre, ratio.cutoff.sup.pre), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.pre, y.lim = segm.y.range.pre, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) } # end plot verif obs dots outside # end MD overlay plot before serpentine @@ -3454,7 +3398,7 @@ y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, -classic = TRUE, +article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, @@ -3507,7 +3451,7 @@ y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, -classic = TRUE, +article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, @@ -3980,9 +3924,9 @@ fun_gg_empty_graph(text = "SIGNIFICANT DIFFERENCES POST SERPENTINE\n(SLITHERINE) fun_report(data = paste0("SEGMENTATION OF THE THEORETICAL DOT CLOUD (MEAN CELL / RATIO CELL PLOT) PERFORMED ON NON NORMALIZED DATA\nBECAUSE OF DISCRETE RATIO VALUES THAT ARE PRESENTS FOR LOW MEANS\nINDEED, NORMALIZATION SLIGHTLY SHIFTS THE RATIO VALUES BETWEEN THEO AND OBS CLOUDS, WHICH INDUCES LOW MEAN CELL DOTS (I.E., NOISE) TO BE SIGNIFICANT AFTER SEGMENTATION. THEN, DEPENDING ON USER SETTINGS (SEE ABOVE), RATIO NORMALIZATION ARE PERFORMED ON SEGMENTATION RESULT DATA, BEFORE APPLYING THE CUTOFFS FILTERING"), output = log.file, path = path.out) segment.post.serp <- fun_segmentation(data1 = theo.df.post.for.segm, x1 = "MEAN", y1 = "RATIO", x.range.split = range.split, x.step.factor = step.factor, error = error, data2 = obs.df.post.for.segm, x2 = "MEAN", y2 = "RATIO", data2.pb.dot = "signif", plot = FALSE, graph.in.file = FALSE) fun_report(data = "UNKNOWN DOTS HAVE BEEN CONSIDERED AS SIGNIFICANTS (ARGUMENT data2.pb.dot OF fun_segmentation() SET TO \"signif\")", output = log.file, path = path.out) -# cat(paste0("\n", segment.post.serp$warnings, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), segment.post.serp$warnings) # in fact, abs(tempo.cor) is systematically used -fun_report(data = segment.post.serp$warnings, output = log.file, path = path.out) +# cat(paste0("\n", segment.post.serp$warn, "\n")) +warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), segment.post.serp$warn) # +fun_report(data = segment.post.serp$warn, output = log.file, path = path.out) if( ! is.null(segment.post.serp$hframe)){ names(segment.post.serp$hframe)[names(segment.post.serp$hframe) == "x"] <- "MEAN" # names(segment.post.serp$hframe)[names(segment.post.serp$hframe) == "y"] <- "RATIO" # @@ -4093,10 +4037,10 @@ fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wi } if( ! is.null(signif.theo.dot.post)){ # signif dots in theo matrices tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nTHEO MAT ALONE + THEO SIGNIFICANT DOTS\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.post, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.post, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.post), " AND ", fun_round(ratio.cutoff.sup.post)) -fun_gg_scatter(data1 = list(L1 = theo.df.post, L2 = signif.theo.dot.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = theo.df.post, L2 = signif.theo.dot.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) }else{ tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nTHEO MAT ALONE (NO THEO SIGNIFICANT DOTS)\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.post, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.post, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.post), " AND ", fun_round(ratio.cutoff.sup.post)) -fun_gg_scatter(data1 = list(L1 = theo.df.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = theo.df.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) } if(activate.pdf == TRUE){ invisible(dev.set(pdf.nb)) @@ -4105,10 +4049,10 @@ fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wi } if( ! is.null(signif.obs.dot.post)){ # signif dots in obs matrices tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS MAT ALONE + OBS SIGNIFICANT DOTS\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.post, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.post, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.post), " AND ", fun_round(ratio.cutoff.sup.post)) -fun_gg_scatter(data1 = list(L1 = obs.df.post, L2 = signif.obs.dot.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = obs.df.post, L2 = signif.obs.dot.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) }else{ tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS MAT ALONE (NO OBS SIGNIFICANT DOTS)\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.post, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.post, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.post), " AND ", fun_round(ratio.cutoff.sup.post)) -fun_gg_scatter(data1 = list(L1 = obs.df.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = obs.df.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) } if(activate.pdf == TRUE){ invisible(dev.set(pdf.nb)) @@ -4117,10 +4061,10 @@ fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wi } if( ! is.null(signif.obs.dot.post)){ # signif dots in obs matrices tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS AND THEO MAT + OBS SIGNIFICANT DOTS\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.post, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.post, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.post), " AND ", fun_round(ratio.cutoff.sup.post)) -fun_gg_scatter(data1 = list(L1 = final.df.post, L2 = signif.obs.dot.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = final.df.post, L2 = signif.obs.dot.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) }else{ tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS AND THEO MAT (NO OBS SIGNIFICANT DOTS)\n", ifelse(ratio.normalization == TRUE, "THEO AND OBS RATIOS HAVE BEEN NORMALIZED (EACH CENTERED ON RATIO 1)\n", ""), if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range.post, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range.post, 2), collapse = " , "), "\nCUT-OFFS DEFINED BY THE USER: ", fun_round(ratio.cutoff.inf.post), " AND ", fun_round(ratio.cutoff.sup.post)) -fun_gg_scatter(data1 = list(L1 = final.df.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) +fun_gg_scatter(data1 = list(L1 = final.df.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(ratio.cutoff.inf.post, ratio.cutoff.sup.post), CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "MEAN", L4 = NULL), y = list(L1 = "RATIO", L3 = "RATIO", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, x.log = transfo, x.lab = "MEAN", x.tick.nb = 8, y.log = transfo, x.lim = segm.x.range.post, y.lim = segm.y.range.post, y.lab = "RATIO", y.tick.nb = 8, title = tempo.title, article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) } # end plot verif obs dots outside # end MD overlay plot after serpentine @@ -4366,7 +4310,7 @@ y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, -classic = TRUE, +article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, @@ -4419,7 +4363,7 @@ y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, -classic = TRUE, +article = TRUE, legend.width = NULL, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, @@ -4518,6 +4462,12 @@ rm(list = tempo.list) # not saved because initial matrices fun_close() +################ Seeding inactivation + + +set.seed(NULL) + + ################ Environment saving @@ -4534,9 +4484,22 @@ save(list = ls(), file = paste0(path.out, "/all_objects.RData")) ################ Warning messages +fun_report(data = "\n\n################################ RECAPITULATION OF WARNING MESSAGES", path = path.out, output = log.file, sep = 4) +if(warn.secu == TRUE){ +tempo <- fun_secu(pos = 1, name = function.name) # check variables of anova_contrasts script added in the Global ENV. SCRIPT remains to be tested +if( ! is.null(tempo)){ +tempo.warn <- paste0(if(erase.objects == FALSE){"IT COULD BE POSSIBLE THAT "}, tempo, if(erase.objects == FALSE){paste0("\nHOWEVER, SINCE erase.objects == FALSE, THE MATCH COULD COME FROM PRE-EXISTING VARIABLES\nPLEASE, SET erase.objects TO TRUE AT THE BEGINNING OF THE ", script, " SCRIPT AND RERUN TO CONFIRM THAT")}) +cat(paste0("\n\nWARNING:\n", tempo.warn, "\n\n")) +warning.message <- paste0(ifelse(is.null(warning.message), tempo.warning.message, paste0(warning.message, "\n\n", tempo.warn))) +} +}else{ +tempo.warn <- paste0("warn.secu PARAMETER SET TO FALSE -> NO CHECK OF VARIABLE CONFLICTS") +warning.message <- paste0(ifelse(is.null(warning.message), tempo.warn, paste0(warning.message, "\n\n", tempo.warn))) +} if( ! is.null(warning.message)){ -fun_report(data = "\n\n################################ WARNING MESSAGES", path = path.out, output = log.file, sep = 4) fun_report(data = warning.message, path = path.out, output = log.file) +}else{ +fun_report(data = "NO WARNING MESSAGE TO REPORT", path = path.out, output = log.file) } @@ -4546,7 +4509,10 @@ fun_report(data = warning.message, path = path.out, output = log.file) fun_report("\n\n################################ INITIAL SETTINGS OF PARAMETERS", output = log.file, path = path.out) fun_report(data = param.ini.settings, path = path.out, output = log.file, vector.cat = TRUE) fun_report("\n\n################################ R SYSTEM AND PACKAGES", output = log.file, path = path.out) -fun_report(data = sessionInfo(), path = path.out, output = log.file, vector.cat = TRUE) +tempo <- sessionInfo() +tempo$otherPkgs <- tempo$otherPkgs[order(names(tempo$otherPkgs))] # sort the packages +tempo$loadedOnly <- tempo$loadedOnly[order(names(tempo$loadedOnly))] # sort the packages +fun_report(data = tempo, path = path.out, output = log.file, vector.cat = TRUE) if(serp.binning == TRUE){ fun_report("\n\n################################ PYTHON SYSTEM AND PACKAGES", output = log.file, path = path.out) fun_report(data = reticulate::py_config(), path = path.out, output = log.file, vector.cat = TRUE) # to get the version of python, or use a python chunk ```{python} import IPython; python_session = IPython.sys_info();``` then reticulate::py$python_session diff --git a/slitherine.config b/slitherine.config index a60a96d..0f7a0f5 100644 --- a/slitherine.config +++ b/slitherine.config @@ -31,8 +31,8 @@ path.out <- "C:/Users/Gael/Desktop/" # absolute pathway of the destination folde ######## R packages and cute_little_R_functions file locations -path.lib <- NULL # vector of character that define the absolute pathway of the folder containing the R packages. Write NULL for the default path. BEWARE: default path is dependent on the system and interface used. For instance, using cygwin64 on windows 7, the path is "C:/Program Files/R/R-3.5.3/library". On the same cmputer using the R classical interface, the paths are [1] "C:/Users/Gael/Documents/R/win-library/3.5" [2] "C:/Program Files/R/R-3.5.3/library" -path.function1 <- "C:/Users/Gael/Documents/Git_projects/cute_little_R_functions/cute_little_R_functions.R" # file (and absolute pathway) of the required cute_little_R_functions toolbox. With ethernet connection available, this can also be used: "https://gitlab.pasteur.fr/gmillot/cute_little_R_functions/raw/v5.1.0/cute_little_R_functions.R" +lib.path <- NULL # vector of character that define the absolute pathway of the folder containing the R packages. Write NULL for the default path. BEWARE: default path is dependent on the system and interface used. For instance, using cygwin64 on windows 7, the path is "C:/Program Files/R/R-3.5.3/library". On the same cmputer using the R classical interface, the paths are [1] "C:/Users/Gael/Documents/R/win-library/3.5" [2] "C:/Program Files/R/R-3.5.3/library" +path.function1 <- "https://gitlab.pasteur.fr/gmillot/cute_little_R_functions/-/raw/c1dd8832f14d76c1901a60ca2a7c87af01a82b61/cute_little_R_functions.R" # file (and absolute pathway) of the required cute_little_R_functions toolbox. With ethernet connection available, this can also be used: "https://gitlab.pasteur.fr/gmillot/cute_little_R_functions/raw/v5.1.0/cute_little_R_functions.R" ######## Matrix structure @@ -50,6 +50,11 @@ thread.nb <- NULL # Integer specifying the number of threads available. BEWARE: ################ End Mandatory settings + + + + + ################ Optional settings @@ -81,7 +86,7 @@ theo.import <- FALSE # logical. Import theoretical matrices already obtained usi theo.file.name1 <- "mat1.theo.serp.txt" # name of the first matrix file theo.file.name2 <- "mat2.theo.serp.txt" # name of the second matrix file theo.path.in <- "C:/Users/Gael/Documents/Hub projects/20190611 Scolari 13341/dataset/Meio/" # absolute pathway of the folder containing the input data files (file.name1 and file.name2) -n.row <- NULL # integer value setting the number of rows of the theoretical matrices. If NULL, n.row will take the number of column of the theoretical matrices +n.row <- 300 # integer value setting the number of rows of the theoretical matrices. If NULL, n.row will take the number of column of the theoretical matrices win.size <- 20 # nb of cv values taken in the sliding windows on the CV / MEAN plot to define an average cv at the rupture slope on the CV / MEAN plot (must be less than matrix dimension - 2). Increase this value if warning messages appears saying: "PARAMETER MUST BE SUCH THAT cv^2 > 1/mu" cv.rho.obtained <- FALSE # coefficient of variation (cv) of observed matrices 1 and 2, as well as correlation between observed matrices 1 and 2 already obtained ? If TRUE, will use the path.cv.rho parameter to load the data path.cv.rho <- "C:/Users/Gael/Desktop/cv1_cv2_rho1_rho2_backup.RData" # file and absolute pathway to download the cv1, cv2, as well as rho1 and rho2 (which are identical) of observed matrices 1 and 2 already obtained. Write NULL if not required. Not considered if cv.rho.obtained is FALSE @@ -89,17 +94,18 @@ correl.mat.obtained <- FALSE # theoretical matrix with permutation already obtai path.theo1.theo2 <- "C:/Users/Gael/Desktop/permut_mat1_mat2_backup.RData" # file and absolute pathway to download the theoretical matrix with permutation already obtained. Write NULL if not required. Not considered if correl.mat.obtained is FALSE single.corr <- "MAX" # either "VALUE", "MAX", "DEC1", "QUART1", "MED", "MIN" or "NO" # use MAX by default. if VALUE, a unique arbitrary value, defined in the abs.corr.limit parameter below, is used as reference to generate the correlation between the related diagonals of the theoretical theo1 and theo2 matrices (all the correlations between theo1 and theo2 diagonals will be close to abs.corr.limit). If MAX, the maximal correlation value between the observed mat1 and mat2 matrix diagonals will be used to generate the correlation between the related diagonals of theo1 and theo2 matrices (all the correlations between theo1 and theo2 diagonals will be close to max(rho1)). If DEC1, QUART1 MED or MIN, the same as MAX but using the first decile, first quartile, median or minimal correlation value between the observed mat1 and mat2 matrix diagonals, respectively. If NO, each of the observed correlations between the related diagonals of the mat1 and mat2 matrices will be used to generate the correlation of the corresponding theo1 and theo2 diagonal. In the case of NO, any observed correlation below the abs.corr.limit parameter will be set to abs.corr.limit (to avoid very long computing needed for very weak correlations) abs.corr.limit <- 0.2 # parameter used when single.corr <- "VALUE" or single.corr <- "NO". See the single.corr parameter description -count.print <- 1e6 # during the correlation adjustment process, print a message every count.print loops ? +print.count <- 1e6 # during the correlation adjustment process, print a message every print.count loops ? keep <- TRUE # keep the intermediate matrices and big objects in the working environment til the end? If TRUE, everything is saved in the final all_objects.RData. If FALSE, intermediate matrices are saved in different .RData files and then removed all along the script execution ######## Significant regions between the two compared matrices -ratio.limit.sig <- 2 # ratio value between the two matrice pixel, below which ratio is not significant? From 1 to +Inf (2 means coverage ratio less than 2 is not significant) +ratio.limit.sig <- 2 # ratio value between the two matrice pixel, below which ratio is not significant? From 1 to +Inf (2 means coverage ratio less than 2 is not significant, 1 means no cutoffs in ratio values) error <- 0 # from 0 to 1. Proportion of false positives (i.e., theo dots considered as observed dots). 0.05 means 5%, 0 means that the significant observed dot are outside of the theo cloud range.split <- 25 # for the significant dots. If x.range is the range of the dots on the x-axis, then abs(diff(x.range) / range.split) gives the window size. Window size decreases when range.split increases step.factor <- 10 # for the significant dots. x.win.size / step.factor gives the shift step of the window. When step.factor = 1, no overlap during the sliding. If step.factor = 2, 50% of overlap during 1 slide +ratio.normalization <- TRUE # logical. Divide the cell ratio matrix mat2 / mat1 (differential matrix) by the ratio factor mean(mat2) / mean(mat1)? If TRUE, this means that the mean of the normalized cell ratio matrix is 1, and log (parameter transfo <- TRUE)is 0 ######## Graphical and display parameters @@ -112,13 +118,19 @@ width.wind <- 7 # window width (in inches) height.wind <- 7 # window height (in inches) dot.size <- 2 # increase or decrease the value to increase or decrease the size of the dots line.size <- 0.75 # increase or decrease the value to increase or decrease the size of the lines -heatmap.text.size <- 8 # increase or decrease the value to increase or decrease the size of the heatmap scale text +heatmap.text.size <- 16 # increase or decrease the value to increase or decrease the size of the heatmap scale text text.size <- 12 # increase or decrease the value to increase or decrease the size of the axis text and legend text -title.text.size <- 4.5 # increase or decrease the value to increase or decrease the size of the title text +title.text.size <- 6 # increase or decrease the value to increase or decrease the size of the title text raster <- TRUE # raster mode for dot plots ? transfo <- "log2" # Either "log2" (matrix values will be log2 converted, and sometimes log2(x +1) converted, +1 to deal with zero) or "log10" ((matrix values will be log10 converted and sometimes log10(x +1) converted, +1 to deal with zero). BEWARE: observed matrices must remain integers for serpentine. Log is only applied for display, the reason why the option "no" is not proposed (which would mean data already log converted) +######## Others + + +warn.secu <- FALSE # logical. Display if internal homemade functions of anova_contrasts and anova_contrasts have variables that are present in other environments? + + ################ End Optional settings diff --git a/slitherine_script.R b/slitherine_script.R deleted file mode 100644 index 4139c6d..0000000 --- a/slitherine_script.R +++ /dev/null @@ -1,3125 +0,0 @@ -######################################################################### -## ## -## SLITHERINE v1.0.0 ## -## ## -## Gael A. Millot ## -## Vittore F. Scolari ## -## Lyam Baudry ## -## ## -######################################################################### - - - -################################ Aim - - -# Slitherine help to define significant coverage differences when comparing two contact matrices - - -################################ End Aim - - -################################ Introduction - - -# Compatible with R v6.3.1 -# Increase the R console window width if columns of tables are subjected to carriage return in the ...report.txt file - - -################################ End Introduction - - -################################ Acknowlegments - - - - -################################ End Acknowlegments - - -################################ Initialization - - -# R version checking -if(version$version.string != "R version 3.6.1 (2019-07-05)"){ -cat(paste0("\n\nWARNING: THE ", version$version.string, " IS NOT THE 6.3.1 RECOMMANDED\n\n")) -} -# other initializations -erase.objects = TRUE # write TRUE to erase all the existing objects in R before starting the algorithm and FALSE otherwise. Beginners should use TRUE -if(erase.objects == TRUE){ -rm(list=ls()) -erase.objects = TRUE -} -erase.graphs = TRUE # write TRUE to erase all the graphic windows in R before starting the algorithm and FALSE otherwise -script <- "slitherine v1.0.0" - - -################################ End Initialization - - -################################ Parameters that need to be set by the user - - -# see the slitherine.config file - - -################################ End Parameters that need to be set by the user - - -################################ Config import - - -slitherine.command <- paste0(commandArgs(trailingOnly = FALSE), collapse = ",") # recover the full command -args <- commandArgs(trailingOnly = TRUE) # recover arguments written after the call of the Rscript -if(any(is.na(args))){ -stop(paste0("\n\n================\n\nERROR: THE args OBJECT HAS NA\n\n================\n\n")) -} -tempo.arg.names <- c("config.path") # objects names exactly in the same order as in the bash code and recovered in args -if(length(args) != length(tempo.arg.names)){ -stop(paste0("\n\n================\n\nERROR: THE NUMBER OF ELEMENTS IN args (", length(args),") IS DIFFERENT FROM THE NUMBER OF ELEMENTS IN tempo.arg.names (", length(tempo.arg.names),")\nargs:", paste0(args, collapse = ","), "\ntempo.arg.names:", paste0(tempo.arg.names, collapse = ","), "\n\n================\n\n")) -} -for(i0 in 1:length(tempo.arg.names)){ -assign(tempo.arg.names[i0], args[i0]) -} -rm(tempo.arg.names, args, i0) -if( ! file.exists(config.path)){ -stop(paste0("\n\n============\n\nERROR: CONFIG FILE NAME AND PATH INDICATED IN SLITHERINE EXECUTION COMMAND DOES NOT EXISTS: ", config.path, "\n\n============\n\n")) -}else{ -source(config.path) # source the config parameters -} - - -################################ End Config import - - -################################ Recording of the initial parameters - - -param.list <- c( -"erase.objects", -"erase.graphs", -"script", -"slitherine.command", -"config.path", -"project.name", -"file.name1", -"file.name2", -"path.in", -"path.out", -"path.lib", -"path.function1", -"empty.cell.string", -"thread.nb", -"serp.binning", -"python", -"path.python.lib", -"serp.threshold", -"serp.minthreshold", -"serp.iter.nb", -"serp.symmet.input", -"theo.import", -"theo.file.name1", -"theo.file.name2", -"theo.path.in", -"n.row", -"win.size", -"cv.rho.obtained", -"path.cv.rho", -"correl.mat.obtained", -"path.theo1.theo2", -"single.corr", -"abs.corr.limit", -"count.print", -"keep", -"ratio.limit.sig", -"error", -"range.split", -"step.factor", -"activate.pdf", -"optional.text", -"width.wind", -"height.wind", -"dot.size", -"line.size", -"heatmap.text.size", -"text.size", -"title.text.size", -"raster", -"transfo" -) -if(any(duplicated(param.list))){ -stop(paste0("\n\n================\n\nERROR: THE param.list OBJECT CONTAINS DUPLICATED ELEMENTS:\n", paste(param.list[duplicated(param.list)], collapse = " "), "\n\n================\n\n")) # message for developers -} -if(erase.objects == TRUE){ -created.object.control <- ls()[ ! ls() %in% "param.list"] -if( ! (all(created.object.control %in% param.list) & all(param.list %in% created.object.control))){ -stop(paste0("\n\n================\n\nERROR: INCONSISTENCIES BETWEEN THE param.list ELEMENTS AND THE CREATED OBJECTS\nTHE CREATED OBJECTS (created.object.control) NOT PRESENT IN THE param.list ARE: ", paste(created.object.control[ ! created.object.control %in% param.list], collapse = " "), "\nTHE param.list ELEMENTS NOT PRESENT IN THE CREATED OBJECTS (created.object.control) ARE: ", paste(param.list[ ! param.list %in% created.object.control], collapse = " "), "\n\n================\n\n")) # message for developers -} -} -char.length <- nchar(param.list) -space.add <- max(char.length) - char.length + 5 -param.ini.settings <- character(length = length(param.list)) -for(i in 1:length(param.list)){ -param.ini.settings[i] <- paste0("\n", param.list[i], paste0(rep(" ", space.add[i]), collapse = ""), paste0(get(param.list[i]), collapse = ",")) -} - - -################################ End Recording of the initial parameters - - -################################ Functions - - -################ fun_ functions import - - -if(length(path.function1) != 1){ -stop(paste0("\n\n============\n\nERROR IN SLITHERINE\npath.function1 PARAMETER MUST BE LENGTH 1: ", paste(path.function1, collapse = " "), "\n\n============\n\n")) -}else if(grepl(x = path.function1, pattern = "^http")){ -tempo.try <- try(suppressWarnings(source(path.function1)), silent = TRUE) -if(any(grepl(x = tempo.try, pattern = "[Ee]rror"))){ -stop(paste0("\n\n============\n\nERROR IN SLITHERINE\nHTTP INDICATED IN THE path.function1 PARAMETER DOES NOT EXISTS: ", path.function1, "\n\n============\n\n")) -}else{ -source(path.function1) # source the fun_ functions used below -} -}else if( ! grepl(x = path.function1, pattern = "^http")){ -if( ! file.exists(path.function1)){ -stop(paste0("\n\n============\n\nERROR IN SLITHERINE\nFILE INDICATED IN THE path.function1 PARAMETER DOES NOT EXISTS: ", path.function1, "\n\n============\n\n")) -}else{ -source(path.function1) # source the fun_ functions used below -} -} - - -################ package import - - -# R Packages required -req.package.list <- c( -"reticulate", -"parallel", -"lubridate", -"reshape2", -"ggplot2", -"Cairo" -) - - -# Python Packages required -req.python.package.list <- c( -"serpentine" -) - - -# A function is created in order to import packages after parameter checkings -package.import.fun <- function(){ -# R Packages verification and import -fun_pack(req.package = req.package.list, path.lib = path.lib) # packages are imported even if inside functions are written as package.name::function() in the present code -# Python Packages verification and import -if(serp.binning == TRUE){ -fun_python_pack(req.package = req.python.package.list, path.python.exec = python, path.lib = path.python.lib, R.path.lib = path.lib) -} -} - - -################ local functions - - -adj.mean.fun <- function(x_fun, text_fun = ""){ -# compute a weighted mean, according to the number of cells per diagonal, such as the main diagonal has the max weight and the corner the min -# x_fun: a matrix -# text: text for error messages -# argument checking -arg.check <- NULL # for function debbuging -checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools -ee <- expression(arg.check <- c(arg.check, tempo$problem) , checked.arg.names <- c(checked.arg.names, tempo$param.name)) -tempo <- fun_check(data = x_fun, class = "matrix", mode = "numeric", na.contain = TRUE, fun.name = "adj.mean.fun INTERNAL FUNCTION OF SLITHERINE") -tempo <- fun_check(data = text_fun, class = "vector", typeof = "character", length = 1, fun.name = "adj.mean.fun INTERNAL FUNCTION OF SLITHERINE") -if(any(arg.check) == TRUE){ -stop() # nothing else because print = TRUE by default in fun_check() -} -# end argument checking -cell.rm <- is.na(x_fun) | ! is.finite(x_fun) # matrix indicating the positions of the NA and Inf in x_fun -x_fun[cell.rm] <- 0 # replacing NA and Inf by 0, because after, we are doing sum -if(all(cell.rm) == TRUE){ -tempo.cat <- paste0("\n\n============\n\n", ifelse(text_fun == "", "", paste0(text_fun, "\n")), "ERROR IN adj.mean.fun INTERNAL FUNCTION OF SLITHERINE\nTHE MATRIX HAS ONLY NA, NaN AND Inf\nNOT POSSIBLE TO COMPUTE THE MEAN\n\n============\n\n") -stop(tempo.cat) -} -mean.output <- sum(apply(x_fun, 2, sum, na.rm = TRUE) * ncol(x_fun):1) / (sum(ncol(x_fun):1) * nrow(x_fun)) # here, instead of doing mean(theo$RATIO[is.finite(theo$RATIO)], na.rm = TRUE), we wheighted the cell ratio using sum(r.ij * (c - j - 1)) / sum(c - j - 1), with r.ij the ratio in cell ij, c the number of column in theo matrices (which is the number of diag in the obs matrices) and j the column index. Thus we weight each value inside theo column by the number of values in diagonals -if(all(is.na(mean.output)) | all( ! is.finite(mean.output))){ -tempo.cat <- paste0("\n\n============\n\n", ifelse(text_fun == "", "", paste0(text, "\n")), "ERROR IN adj.mean.fun INTERNAL FUNCTION OF SLITHERINE: THE ADJUSTED MEAN IS NA, NaN OR Inf: ", paste(mean.output, collapse = " "), "\n\n============\n\n") -stop(tempo.cat) -}else{ -return(mean.output) -} -} - -mask.plot.fun <- function(mask_fun, mat1_fun, mat2_fun, serp_kind, mask_kind, text_fun = ""){ -# plot the sup, inf and full masks -# x_fun: a matrix -# text_fun: text for plotting messages -# argument checking -arg.check <- NULL # for function debbuging -checked.arg.names <- NULL # for function debbuging: used by r_debugging_tools -ee <- expression(arg.check <- c(arg.check, tempo$problem) , checked.arg.names <- c(checked.arg.names, tempo$param.name)) -tempo <- fun_check(data = mask_fun, class = "matrix", mode = "numeric", na.contain = TRUE, fun.name = "mask.plot.fun INTERNAL FUNCTION OF SLITHERINE") ; eval(ee) -tempo <- fun_check(data = mat1_fun, class = "matrix", mode = "numeric", na.contain = TRUE, fun.name = "mask.plot.fun INTERNAL FUNCTION OF SLITHERINE") ; eval(ee) -tempo <- fun_check(data = mat2_fun, class = "matrix", mode = "numeric", na.contain = TRUE, fun.name = "mask.plot.fun INTERNAL FUNCTION OF SLITHERINE") ; eval(ee) -tempo <- fun_check(data = serp_kind, options = c("BEFORE", "AFTER"), length = 1) ; eval(ee) -tempo <- fun_check(data = mask_kind, options = c("POSITIVE (MAT2 > MAT1)", "NEGATIVE (MAT2 < MAT1)", "FULL"), length = 1, fun.name = "mask.plot.fun INTERNAL FUNCTION OF SLITHERINE") ; eval(ee) -tempo <- fun_check(data = text_fun, class = "vector", typeof = "character", length = 1, fun.name = "mask.plot.fun INTERNAL FUNCTION OF SLITHERINE") ; eval(ee) -if(any(arg.check) == TRUE){ -stop() # nothing else because print = TRUE by default in fun_check() -} -# end argument checking -# mask -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0(serp_kind," SERPENTINE ", mask_kind, " MASK (INVERTED)", text_fun) -fun_gg_heatmap(data1 = mask_fun, low.color1 = "white", mid.color1 = NULL, high.color1 = "black", title = tempo.title, title.text.size = title.text.size, show.scale = FALSE) # I tried without meltedbefore. Add flip in fun_heatmap to reverse x and y if required -# end mask -# Heatmap -loop.mat.names <- c("mat1_fun", "mat2_fun") -loop.heatmap.title <- c(paste0("OBS MAT1 ", serp_kind, " SERPENTINE"), paste0("OBS MAT2 ", serp_kind, " SERPENTINE")) -for(i0 in 1:length(loop.mat.names)){ -tempo.data.plot <- get(loop.mat.names[i0]) / mean(get(loop.mat.names[i0])[is.finite(get(loop.mat.names[i0]))], na.rm = TRUE) -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot + 1) -} -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0(loop.heatmap.title[i0], "\n", if(transfo == "log2"){"LOG2(x + 1) "}else if(transfo == "log10"){"LOG10(x + 1) "}else{"NO "}, "TRANSFORMATION\nSCALE RANGE: ", paste(fun_round(heatmap.range, 2), collapse = " , "), "\nNORMALIZED DISPLAY (GLOBAL MEAN DIVISION, WHICH WOULD EXPLAIN INTENSITY VARIATION)", text_fun) -fun_gg_heatmap(data1 = tempo.data.plot, legend.name = "", limit1 = c(min(heatmap.range, na.rm = TRUE), max(heatmap.range, na.rm = TRUE)), midpoint1 = mean(heatmap.range, na.rm = TRUE), title = tempo.title, text.size = heatmap.text.size, title.text.size = title.text.size) -tempo.title <- paste0(loop.heatmap.title[i0], " + ", mask_kind, " MASK\n", if(transfo == "log2"){"LOG2(x + 1) "}else if(transfo == "log10"){"LOG10(x + 1) "}else{"NO "}, "TRANSFORMATION\nSCALE RANGE: ", paste(fun_round(heatmap.range, 2), collapse = " , "), "\nNORMALIZED DISPLAY (GLOBAL MEAN DIVISION, WHICH WOULD EXPLAIN INTENSITY VARIATION)", text_fun) -fun_gg_heatmap(data1 = tempo.data.plot, legend.name = "", limit1 = c(min(heatmap.range, na.rm = TRUE), max(heatmap.range, na.rm = TRUE)), midpoint1 = mean(heatmap.range, na.rm = TRUE), title = tempo.title, text.size = heatmap.text.size, title.text.size = title.text.size, data2 = mask_fun, color2 = "black", alpha2 = 0.5, invert2 = TRUE) -} -# end Heatmap -# differential heatmap -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- (mat2_fun / mat1_fun) # BEWARE: convention in serptentine is this one -tempo.data.plot[tempo.data.plot == 0] <- NA # replacement of zero by NA -tempo.data.plot <- tempo.data.plot / mean(tempo.data.plot[is.finite(tempo.data.plot)], na.rm = TRUE) # mean normalization -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot) # log transfo -} -tempo.range <- max(abs(tempo.data.plot[is.finite(tempo.data.plot)]), na.rm = TRUE) -tempo.range <- c(-tempo.range, tempo.range) -tempo.title <- paste0("OBS DIFF MAT ", serp_kind, " SERPENTINE (OBS2 / OBS1)\n", if(transfo == "log2"){"LOG2(x) "}else if(transfo == "log10"){"LOG10(x) "}else{"RAW VALUES"}, " TRANSFORMATION\nSCALE RANGE: ", paste(fun_round(tempo.range, 2), collapse = " , "), "\nNORMALIZED DISPLAY (GLOBAL MEAN DIVISION)\n0 VALUES REPLACED BY NA\nGREY COLOR WHEN NaN (DIVISION BY ZERO) OR NA", text_fun) -fun_gg_heatmap(data1 = tempo.data.plot, legend.name = "", limit1 = tempo.range, midpoint1 = 0, title = tempo.title, text.size = heatmap.text.size, title.text.size = title.text.size) -tempo.title <- paste0("OBS DIFF MAT ", serp_kind, " SERPENTINE (OBS2 / OBS1) + ", mask_kind, " MASK\n", if(transfo == "log2"){"LOG2(x) "}else if(transfo == "log10"){"LOG10(x) "}else{"NO "}, "TRANSFORMATION\nSCALE RANGE: ", paste(fun_round(tempo.range, 2), collapse = " , "), "\nNORMALIZED DISPLAY (GLOBAL MEAN DIVISION)\n0 VALUES REPLACED BY NA\nGREY COLOR WHEN NaN (DIVISION BY ZERO)", text_fun) -fun_gg_heatmap(data1 = tempo.data.plot, legend.name = "", limit1 = tempo.range, midpoint1 = 0, title = tempo.title, text.size = heatmap.text.size, title.text.size = title.text.size, data2 = mask_fun, color2 = "black", alpha2 = 0.5, invert2 = TRUE) -# end differential heatmap -} - - -################################ End Functions - - -################################ Main code - - -################ Pre-ignition checking - -warning.message <- NULL -param.check <- NULL # -checked.param.names <- NULL # -ee <- expression(param.check <- c(param.check, tempo$problem) , checked.param.names <- c(checked.param.names, tempo$param.name)) -tempo <- fun_check(data = erase.objects, class = "vector", typeof = "logical", length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = erase.graphs, class = "vector", typeof = "logical", length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = script, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = project.name, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = file.name1, class = "vector", mode = "character", fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & substr(file.name1, nchar(file.name1) - 3, nchar(file.name1)) != ".txt"){ -tempo.warning <- paste0("THE file.name1 OBJECT SETTING SHOULD BE A TXT FILE BUT DOES NOT FINISH BY \".txt\" LOWERCASE WRITTEN") -cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used -} -tempo <- fun_check(data = file.name2, class = "vector", mode = "character", fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & substr(file.name2, nchar(file.name2) - 3, nchar(file.name2)) != ".txt"){ -tempo.warning <- paste0("THE file.name2 OBJECT SETTING SHOULD BE A TXT FILE BUT DOES NOT FINISH BY \".txt\" LOWERCASE WRITTEN") -cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used -} -tempo <- fun_check(data = path.in, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & ! dir.exists(path.in)){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: DIRECTORY PATH INDICATED IN THE path.in PARAMETER DOES NOT EXISTS: ", path.in, "\n\n============\n\n")) -} -if(tempo$problem == FALSE & ! file.exists(paste0(path.in, file.name1))){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: file.name1 PARAMETER\n", file.name1, "\nDOES NOT EXIST AT path.in:\n", path.in, "\n\n============\n\n")) -} -if(tempo$problem == FALSE & ! file.exists(paste0(path.in, file.name2))){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: file.name2 PARAMETER\n", file.name2, "\nDOES NOT EXIST AT path.in:\n", path.in, "\n\n============\n\n")) -} -tempo <- fun_check(data = path.out, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & ! dir.exists(path.out)){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: DIRECTORY PATH INDICATED IN THE path.out PARAMETER DOES NOT EXISTS: ", path.out, "\n\n============\n\n")) -} -# tempo <- fun_check(data = path.lib, class = "character") ; eval(ee) # path.lib already cheked above in the fun_pack() function. Not rechecked because can be NULL -tempo <- fun_check(data = path.function1, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) # full check above -if( ! is.null(empty.cell.string)){ -tempo <- fun_check(data = empty.cell.string, class = "vector", na.contain = TRUE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -} -if( ! is.null(thread.nb)){ -tempo <- fun_check(data = thread.nb, typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & thread.nb < 1){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: thread.nb PARAMETER MUST EQUAL OR GREATER THAN 1: ", ratio.limit.sig, "\n\n============\n\n")) -} -} -tempo <- fun_check(data = serp.binning, class = "vector", typeof = "logical", length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = python, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & ! file.exists(python)){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: FILE AND PATH INDICATED IN THE python PARAMETER DOES NOT EXISTS: ", python, "\n\n============\n\n")) -} -if( ! is.null(path.python.lib)){ -tempo <- fun_check(data = path.python.lib, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & ! dir.exists(path.python.lib)){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: DIRECTORY PATH INDICATED IN THE path.python.lib PARAMETER DOES NOT EXISTS: ", path.python.lib, "\n\n============\n\n")) -} -} -tempo <- fun_check(data = serp.threshold, typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = serp.minthreshold, typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = serp.iter.nb, typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = serp.symmet.input, class = "vector", typeof = "logical", length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = hiccomp, class = "vector", typeof = "logical", length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & is.null(binning)){ -if(hiccomp == TRUE){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: binning PARAMETER CANNOT BE NULL IF hiccomp PARAMETER IS TRUE\n\n============\n\n")) -} -} -if( ! is.null(binning)){ -tempo <- fun_check(data = binning, class = "vector", typeof = "integer", double.as.integer.allowed = TRUE, na.contain = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -} -tempo <- fun_check(data = theo.import, class = "vector", typeof = "logical", length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & theo.import == TRUE){ -tempo <- fun_check(data = theo.file.name1, class = "vector", mode = "character", fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & substr(theo.file.name1, nchar(theo.file.name1) - 3, nchar(theo.file.name1)) != ".txt"){ -tempo.warning <- paste0("THE theo.file.name1 OBJECT SETTING SHOULD BE A TXT FILE BUT DOES NOT FINISH BY \".txt\" LOWERCASE WRITTEN") -cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used -} -tempo <- fun_check(data = theo.file.name2, class = "vector", mode = "character", fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & substr(theo.file.name2, nchar(theo.file.name2) - 3, nchar(theo.file.name2)) != ".txt"){ -tempo.warning <- paste0("THE theo.file.name2 OBJECT SETTING SHOULD BE A TXT FILE BUT DOES NOT FINISH BY \".txt\" LOWERCASE WRITTEN") -cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used -} -tempo <- fun_check(data = theo.path.in, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & ! dir.exists(theo.path.in)){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: DIRECTORY PATH INDICATED IN THE theo.path.in PARAMETER DOES NOT EXISTS: ", theo.path.in, "\n\n============\n\n")) -} -} -if( ! is.null(n.row)){ -tempo <- fun_check(data = n.row, typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -} -tempo <- fun_check(data = win.size, typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = cv.rho.obtained, class = "vector", typeof = "logical", length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & cv.rho.obtained == TRUE){ -if( ! is.null(path.cv.rho)){ -tempo <- fun_check(data = path.cv.rho, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & ! file.exists(path.cv.rho)){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: FILE AND PATH INDICATED IN THE path.cv.rho PARAMETER DOES NOT EXISTS: ", path.cv.rho, "\n\n============\n\n")) -} -} -} -tempo <- fun_check(data = correl.mat.obtained, class = "vector", typeof = "logical", length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & correl.mat.obtained == TRUE){ -if( ! is.null(path.theo1.theo2)){ -tempo <- fun_check(data = path.theo1.theo2, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & ! file.exists(path.theo1.theo2)){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: FILE AND PATH INDICATED IN THE path.theo1.theo2 PARAMETER DOES NOT EXISTS: ", path.theo1.theo2, "\n\n============\n\n")) -} -} -} -tempo <- fun_check(data = single.corr, options = c("VALUE", "MAX", "DEC1", "QUART1", "MED", "MIN", "NO"), length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = abs.corr.limit, prop = TRUE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = count.print, typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = keep, class = "vector", typeof = "logical", length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = ratio.limit.sig, class = "vector", mode = "numeric", neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & ratio.limit.sig < 1){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: ratio.limit.sig PARAMETER MUST EQUAL OR GREATER THAN 1: ", ratio.limit.sig, "\n\n============\n\n")) -} -tempo <- fun_check(data = error, prop = TRUE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = range.split, class = "vector", mode = "numeric", neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = step.factor, class = "vector", mode = "numeric", neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == FALSE & step.factor < 1){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: step.factor PARAMETER MUST EQUAL OR GREATER THAN 1: ", ratio.limit.sig, "\n\n============\n\n")) -} -tempo <- fun_check(data = activate.pdf, class = "vector", typeof = "logical", length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = optional.text, class = "vector", typeof = "character", length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = width.wind, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = height.wind, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = dot.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = line.size, class = "vector", mode = "numeric", length = 1, neg.values = FALSE, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = heatmap.text.size, class = "vector", mode = "numeric", neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = text.size, class = "vector", neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = title.text.size, class = "vector", neg.values = FALSE, length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = raster, class = "vector", typeof = "logical", length = 1, fun.name = "SLITHERINE") ; eval(ee) -tempo <- fun_check(data = transfo, options = c("log2", "log10"), length = 1, fun.name = "SLITHERINE") ; eval(ee) -if(any(param.check) == TRUE){ -stop() # nothing else because print = TRUE by default in fun_check() -} - - -################ End pre-ignition checking - - -################ package import - - -package.import.fun() - - -################ End package import - - -################ Ignition - - -set.seed(1014) -options(scipen = 7) -analysis.nb <- trunc(as.numeric(Sys.time())) # to provide a specific number ot each analysis -log.file <- paste0(project.name, "_", analysis.nb,"_report.txt") -name.dir <- paste0(project.name, "_", analysis.nb) -path.out<-paste0(path.out, name.dir) -if(dir.exists(path.out)){ -tempo.cat <- paste0("\n\n============\n\nERROR IN SLITHERINE: DIRECTORY ALREADY EXISTS: ", path.out, "\n\n============\n\n") -stop(tempo.cat) -}else{ -suppressWarnings(dir.create(path.out)) -} -cat("\nSLITHERINE IGNITION\n") -fun_report(data = paste0("\n\n################################ ", log.file, " ################"), output = log.file, no.overwrite = FALSE, path = path.out, sep = 4) -ini.date <- Sys.time() -ini.time <- as.numeric(ini.date) # time of process begin, converted into seconds -fun_report("\n\n################################ RUNNING DATE AND STARTING TIME", output = log.file, path = path.out) -fun_report(data = ini.date, path = path.out, output = log.file, vector.cat = TRUE) -cat("\nINITIAL SETTINGS AND DATA MODIFICATIONS\n") -fun_report(data = "\n\n################################ INITIAL SETTINGS AND DATA MODIFICATIONS", path = path.out, output = log.file, sep = 4) -if(optional.text != ""){ -fun_report(data = "OPTIONAL TEXT: ", path = path.out, output = log.file) -fun_report(data = optional.text, path = path.out, output = log.file) -} - - -################ End ignition - - -################ Graphical parameter initialization - - -fun_open(pdf.disp = activate.pdf, path.fun = path.out, pdf.name.file = "initialization") -par.ini <- par(no.readonly = TRUE) # to recover the initial graphical parameters if required (reset) -invisible(dev.off()) # close the new window -if(activate.pdf == TRUE){ -invisible(file.remove(paste0(path.out, "/initialization.pdf"))) -} -zone.ini <- matrix(1, ncol=1) -if(erase.graphs == TRUE){ -graphics.off() -}else{ -tempo.warning <- paste0("GRAPHICS HAVE NOT BEEN ERASED. GRAPHICAL PARAMETERS MAY HAVE NOT BEEN REINITIALIZED") -fun_report(data = tempo.warning, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used -} - - -################ End graphical parameter initialization - - -################ Data import - - -mat1.obs.ini <- as.matrix(read.table(paste0(path.in, file.name1))) -mat2.obs.ini <- as.matrix(read.table(paste0(path.in, file.name2))) -if(theo.import == TRUE){ -mat1.mix <- as.matrix(read.table(paste0(theo.path.in, theo.file.name1))) -mat2.mix <- as.matrix(read.table(paste0(theo.path.in, theo.file.name2))) -tempo.warning <- paste0("IMPORT OF THEORETICAL MATRICES, WHICH WOULD MEAN THAT THE OBSERVED MATRICES IMPORTED HAVE ALREADY BEEN BINNED USING SERPENTINE") -cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used - -} - - -################ End data import - - -################ Checking - - -param.check <- NULL # -checked.param.names <- NULL # -ee <- expression(param.check <- c(param.check, tempo$problem) , checked.param.names <- c(checked.param.names, tempo$param.name)) -for(i0 in 1:2){ -if(theo.import == FALSE){ # obs matrix must be integer for serpentine binning or for theoretical matrix design -tempo <- fun_check(data = get(paste0("mat", i0, ".obs.ini")), data.name = paste0("mat", i0, ".obs.ini"), class = "matrix", typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == TRUE & all(typeof(get(paste0("mat", i0, ".obs.ini"))) %in% "character")){ -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: IMPORTED MATRIX IS TYPE \"CHARACTER\". CHECK THAT IT HAS NO ROW OR COLUMN NAMES, WHICH WOULD HAMPER THE MATRIX IMPORT:\n\nMATRIX ", i0," (", get(paste0("file.name", i0)), "):\n\n")) -print(fun_head(get(paste0("mat", i0, ".obs.ini")))) -cat("\n\n============\n\n") -}else if(tempo$problem == TRUE & all(typeof(get(paste0("mat", i0, ".obs.ini"))) %in% "double")){ -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: IMPORTED MATRIX ", get(paste0("file.name", i0)), " HAS DECIMAL VALUES (TYPE \"DOUBLE\"),\nWHILE THE GENERATION OF THEORETICAL MATRICES REQUIRES INTEGERS (USE OF DISCRETE DISTRIBUTIONS).\nARE YOU SURE THAT theo.import PARAMETER IS CORRECTLY SET TO FALSE?\n\n")) -print(fun_head(get(paste0("mat", i0, ".obs.ini")))) -cat("\n\n============\n\n") -}else if(tempo$problem == TRUE){ -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: ", get(paste0("file.name", i0)), " PARAMETER MUST BE INTEGER MATRIX (OR DECIMAL MATRIX IF ALREADY SERPENTINE BINNED): ", paste(typeof(get(paste0("mat", i0, ".obs.ini"))), collapse = " "), "\n\n============\n\n")) -} -}else{ # obs matrix can be decimal (serpentine binned matrix imported), but theo.import must be TRUE -tempo <- fun_check(data = get(paste0("mat", i0, ".obs.ini")), data.name = paste0("mat", i0, ".obs.ini"), class = "matrix", mode = "numeric", neg.values = FALSE, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == TRUE & all(typeof(get(paste0("mat", i0, ".obs.ini"))) %in% "character")){ -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: IMPORTED MATRIX IS TYPE \"CHARACTER\". CHECK THAT IT HAS NO ROW OR COLUMN NAMES, WHICH WOULD HAMPER THE MATRIX IMPORT:\n\nMATRIX ", i0," (", get(paste0("file.name", i0)), "):\n\n")) -print(fun_head(get(paste0("mat", i0, ".obs.ini")))) -cat("\n\n============\n\n") -} -tempo <- fun_check(data = get(paste0("mat", i0, ".obs.ini")), data.name = paste0("mat", i0, ".obs.ini"), class = "matrix", typeof = "integer", double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = "SLITHERINE", print = FALSE) -if(tempo$problem == FALSE & all(typeof(get(paste0("mat", i0, ".obs.ini"))) %in% "integer")){ -tempo.cat <- paste0("OBSERVED MATRIX ", i0, " MADE OF INTEGERS WHILE THEORETICAL MATRICES IMPORTED. ARE YOU SURE THAT OBSERVED MATRICES ARE ALREADY SERPENTINE BINNED?") -cat(paste0("\nWARNING: ", tempo.cat, "\n")) -fun_report(data = tempo.cat, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) -} -tempo <- fun_check(data = get(paste0("mat", i0, ".mix")), data.name = paste0("mat", i0, ".mix"), class = "matrix", mode = "numeric", double.as.integer.allowed = TRUE, neg.values = FALSE, fun.name = "SLITHERINE") ; eval(ee) -if(tempo$problem == TRUE & all(typeof(get(paste0("mat", i0, ".mix"))) %in% "character")){ -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: IMPORTED MATRIX IS TYPE \"CHARACTER\". CHECK THAT IT HAS NO ROW OR COLUMN NAMES, WHICH WOULD HAMPER THE MATRIX IMPORT:\n\nMATRIX ", i0," (", get(paste0("file.name", i0)), "):\n\n")) -print(fun_head(get(paste0("mat", i0, ".mix")))) -cat("\n\n============\n\n") -}else if(tempo$problem == TRUE & ! all(mode(get(paste0("mat", i0, ".mix"))) %in% "numeric")){ -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: ", paste0("theo.file.name", i0), " PARAMETER MUST BE DECIMAL MATRIX: ", paste(mode(get(paste0("mat", i0, ".mix"))), collapse = " "), "\n\n============\n\n")) -} -} -} -tempo <- fun_comp_2d(mat1.obs.ini, mat2.obs.ini) -if(tempo$same.dim == FALSE){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: DIMENSIONS OF MATRIX 1 AND 2 MUST BE THE SAME.\n\nMATRIX 1: ", paste(dim(mat1.obs.ini), collapse = " "), "\n\nMATRIX 2: ", paste(dim(mat2.obs.ini), collapse = " "), "\n\n============\n\n")) -}else if(tempo$dim[1] != tempo$dim[2]){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: MATRIX 1 AND 2 MUST BE SQUARE MATRICES. HERE DIMENSIONS ARE: ", paste(tempo$dim, collapse = " "), "\n\n============\n\n")) -}else if(tempo$identical.content == TRUE){ -tempo.cat <- paste0("MATRIX 1 AND 2 HAVE IDENTICAL CONTENT") -cat(paste0("\nWARNING: ", tempo.cat, "\n")) -fun_report(data = tempo.cat, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used -} -if(theo.import == TRUE){ -for(i0 in 1:2){ -tempo <- fun_check(data = get(paste0("mat", i0, ".mix")), data.name = paste0("mat", i0, ".mix"), class = "matrix", mode = "numeric", neg.values = FALSE, fun.name = "SLITHERINE") ; eval(ee) # not necessary integer because serpentine binned matrices are means of binning -if(tempo$problem == TRUE & all(typeof(get(paste0("mat", i0, ".mix"))) %in% "character")){ -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: IMPORTED MATRIX IS TYPE \"CHARACTER\". CHECK THAT IT HAS NO ROW OR COLUMN NAMES, WHICH WOULD HAMPER THE MATRIX IMPORT:\n\nMATRIX ", i0," (", get(paste0("mat", i0, ".mix")), "):\n\n")) -print(fun_head(get(paste0("mat", i0, ".mix")))) -cat("\n\n============\n\n") -} -} -tempo <- fun_comp_2d(mat1.mix, mat2.mix) -if(tempo$same.dim == FALSE){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: DIMENSIONS OF THEORETICAL MATRIX 1 AND 2 MUST BE THE SAME.\n\nMATRIX 1: ", paste(dim(mat1.mix), collapse = " "), "\n\nMATRIX 2: ", paste(dim(mat2.mix), collapse = " "), "\n\n============\n\n")) -}else if(tempo$identical.content == TRUE){ -tempo.cat <- paste0("THEORETICAL MATRIX 1 AND 2 HAVE IDENTICAL CONTENT") -cat(paste0("\nWARNING: ", tempo.cat, "\n")) -fun_report(data = tempo.cat, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used -} -if(ncol(mat1.mix) != ncol(mat1.obs.ini)){ -param.check <- c(param.check, TRUE) -cat(paste0("\n\n============\n\nERROR IN SLITHERINE: NUMBER OF COLUMN MUST BE THE SAME BETWEEN THEORETICAL AND OBSERVED MATRICE.\n\nMATRIX 1: ", paste(ncol(mat1.mix), collapse = " "), "\n\nTHEO MATRIX 1: ", paste(ncol(mat1.obs.ini), collapse = " "), "\n\n============\n\n")) -} -} -if(any(param.check) == TRUE){ -stop() # nothing else because print = TRUE by default in fun_check() -} - - -################ Info - - -fun_report(data = "MATRIX 1 INFO:", path = path.out, output = log.file, sep = 1) -fun_report(data = fun_info(mat1.obs.ini)[c("CLASS", "TYPE", "DIMENSION", "SUM", "RANGE", "MEAN", "NA.NB", "INF.NB")], path = path.out, output = log.file, sep = 1) -fun_report(data = "MATRIX 2 INFO:", path = path.out, output = log.file, sep = 1) -fun_report(data = fun_info(mat2.obs.ini)[c("CLASS", "TYPE", "DIMENSION", "SUM", "RANGE", "MEAN", "NA.NB", "INF.NB")], path = path.out, output = log.file, sep = 1) - - -################ End Info - - -################ Modification of imported matrices - - -# detection of half matrix -mat1.modif <- FALSE -mat2.modif <- FALSE -if( ! is.null(empty.cell.string)){ -if( ! any(mat1.obs.ini %in% empty.cell.string)){ # works for NA, Inf, etc. -stop(paste0("\n\n============\n\nERROR IN SLITHERINE\nPARAMETER empty.cell.string SET TO ", empty.cell.string, ", WHICH IS NOT PRESENT IN THE IMPORTED MATRIX 1\n\n============\n\n")) -} -tempo.mat1.obs <- fun_mat_fill(mat = mat1.obs.ini, empty.cell.string = empty.cell.string) -if( ! is.null(tempo.mat1.obs$warnings)){ -mat1.modif <- TRUE -fun_report(data = tempo.mat1.obs$warnings, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.mat1.obs$warnings) -}else{ -fun_report(data = paste0("MATRIX 1 DETECTED AS SYMMETRIC"), path = path.out, output = log.file) -} -mat1.obs <- tempo.mat1.obs$mat -if( ! any(mat2.obs.ini %in% empty.cell.string)){ # works for NA, Inf, etc. -stop(paste0("\n\n============\n\nERROR IN SLITHERINE\nPARAMETER empty.cell.string SET TO ", empty.cell.string, ", WHICH IS NOT PRESENT IN THE IMPORTED MATRIX 2\n\n============\n\n")) -} -tempo.mat2.obs <- fun_mat_fill(mat = mat2.obs.ini, empty.cell.string = empty.cell.string) -if( ! is.null(tempo.mat2.obs$warnings)){ -mat2.modif <- TRUE -fun_report(data = tempo.mat2.obs$warnings, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.mat2.obs$warnings) # in fact, abs(tempo.cor) is systematically used -}else{ -fun_report(data = paste0("MATRIX 1 DETECTED AS SYMMETRIC"), path = path.out, output = log.file) -} -mat2.obs <- tempo.mat2.obs$mat -}else{ -mat1.obs <- mat1.obs.ini -mat2.obs <- mat2.obs.ini -tempo.warning <- paste0("IMPORTED MATRICES NOT DECLARED HALF FILLED BY THE USER (empty.cell.string PARAMETER SET TO NULL)") -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) -fun_report(data = tempo.warning, path = path.out, output = log.file) -} -# detection of the matrix orientation, and t() potentially to always have the same orientation? -> done with the message provided by fun_mat_fill() and the rotate option of fun_heatmap() -# end detection of half matrix - -# diagonal removal -if( ! all(unique(as.matrix(as.data.frame(list(1:nrow(mat1.obs), 1:ncol(mat1.obs))))) == 0)){ -mat1.obs[as.matrix(as.data.frame(list(1:nrow(mat1.obs), 1:ncol(mat1.obs))))] <- 0 -mat1.modif <- TRUE -tempo.warning <- paste0("MAIN DIAGONAL OF MATRIX 1 HAS BEEN REPLACED BY 0") -fun_report(data = tempo.warning, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # -} -if( ! all(unique(as.matrix(as.data.frame(list(1:nrow(mat2.obs), 1:ncol(mat2.obs))))) == 0)){ -mat2.obs[as.matrix(as.data.frame(list(1:nrow(mat2.obs), 1:ncol(mat2.obs))))] <- 0 -mat2.modif <- TRUE -tempo.warning <- paste0("MAIN DIAGONAL OF MATRIX 2 HAS BEEN REPLACED BY 0") -fun_report(data = tempo.warning, path = path.out, output = log.file) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used -} -# end diagonal removal - -# heatmap: matrix checking -if(theo.import == FALSE){ -loop.mat.names <- c("mat1.obs.ini", "mat1.obs", "mat2.obs.ini", "mat2.obs") -loop.heatmap.title <- c("MATRIX 1 IMPORTED", "MATRIX 1 AFTER MODIFICATIONS", "MATRIX 2 IMPORTED", "MATRIX 2 AFTER MODIFICATIONS") -}else{ -loop.mat.names <- c("mat1.obs.ini", "mat1.obs", "mat2.obs.ini", "mat2.obs", "mat1.mix", "mat2.mix") -loop.heatmap.title <- c("MATRIX 1 IMPORTED", "MATRIX 1 AFTER MODIFICATIONS", "MATRIX 2 IMPORTED", "MATRIX 2 AFTER MODIFICATIONS", "THEORETICAL MATRIX 1 IMPORTED", "THEORETICAL MATRIX 2 IMPORTED") -} -# graphic range (min and max value inside matrix) recovering: to have same matrix resolution -# BEWARE: this means that I take the log2(... + 1) of the matrix that I normalize by the mean of this. Thus, I plot log2(... + 1) on get(loop.mat.names[i0]) / mean(get(loop.mat.names[i0]), na.rm = TRUE) -heatmap.range <- NULL -for(i0 in 1:length(loop.mat.names)){ -# data transformtation -tempo.data.plot <- get(loop.mat.names[i0]) / mean(get(loop.mat.names[i0])[is.finite(get(loop.mat.names[i0]))], na.rm = TRUE) # mean normalization -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot + 1) # log transfo -} -# end data transformtation -heatmap.range <- range(c(heatmap.range, tempo.data.plot), na.rm = TRUE, finite = TRUE) -} -# end graphic range (min and max value inside matrix) recovering: to have same matrix resolution -# heatmap -loop.heatmap.title <- paste0(loop.heatmap.title, "\n", if(transfo == "log2"){"LOG2(x + 1) "}else if(transfo == "log10"){"LOG10(x + 1) "}else{"NO "}, "TRANSFORMATION\nSCALE RANGE: ", paste(fun_round(heatmap.range, 2), collapse = " , "), "\nNORMALIZED DISPLAY (GLOBAL MEAN DIVISION, WHICH WOULD EXPLAIN INTENSITY VARIATION)") -for(i0 in 1:length(loop.mat.names)){ -# data transformtation -tempo.data.plot <- get(loop.mat.names[i0]) / mean(get(loop.mat.names[i0])[is.finite(get(loop.mat.names[i0]))], na.rm = TRUE) -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot + 1) -} -# end data transformation -if(activate.pdf == TRUE){ -if(i0 == 1){ -fun_open(pdf.disp = activate.pdf, path.fun = path.out, pdf.name.file = paste0("plots_", analysis.nb), width.fun = width.wind, height.fun = height.wind) -pdf.nb <- dev.cur() -}else{ -invisible(dev.set(pdf.nb)) -} -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -if(i0 == 1){ -fun_gg_empty_graph(text = "MATRIX MODIFICATION\nCHECKING", text.size = 3) -} -if((loop.mat.names[i0] == "mat1.obs" & mat1.modif == FALSE) | (loop.mat.names[i0] == "mat2.obs" & mat2.modif == FALSE)){ -fun_gg_empty_graph(title = loop.heatmap.title[i0], text = "NO MODIFICATION OF THE IMPORTED MATRIX\n(HALF FILLING\n&\nMAIN DIAGONAL REPLACEMENT BY ZERO", text.size = 3, title.size = title.text.size) -}else{ -fun_gg_heatmap(data1 = tempo.data.plot, legend.name = "", limit1 = c(min(heatmap.range, na.rm = TRUE), max(heatmap.range, na.rm = TRUE)), midpoint1 = mean(heatmap.range, na.rm = TRUE), title = loop.heatmap.title[i0], text.size = heatmap.text.size, title.text.size = title.text.size) -} -} -if(keep == FALSE){ -rm(list = c("mat1.obs.ini", "mat2.obs.ini")) # not saved because initial matrices -} -# end heatmap -# end heatmap: matrix checking - - -################ end modification of imported matrices - - -################ detection of diagonales with mean zero - - -if(theo.import == FALSE){ - - -# means of matrix diagonales will then be modified such as when one is mean zero, the other one is also mean zero -tempo.cat <- "MEANS OF MATRIX DIAGONALES ARE MODIFIED SUCH AS WHEN ONE IS MEAN ZERO, THE OTHER ONE IS ALSO MEAN ZERO" -fun_report(data = tempo.cat, output = log.file, path = path.out) -# Means and sd are computed for each diagonal -tempo.coord <- row(mat1.obs) - col(mat1.obs) # BEWARE: diag 0 is first diagonal and diag n-1 is last diagonal !! row(pmat)-col(pmat) generate a matrix with same number on upleft/rightdown diag, with 0 for main diag and negative number for half right part -diag.mean.mat1.obs <- sapply(0:-(nrow(mat1.obs) - 1), FUN = function(x){mean(mat1.obs[tempo.coord == x], na.rm = TRUE)}) # work on the diagonales -diag.mean.mat2.obs <- sapply(0:-(nrow(mat2.obs) - 1), FUN = function(x){mean(mat2.obs[tempo.coord == x], na.rm = TRUE)}) # work on the diagonales -common.null.mean.pos <- diag.mean.mat1.obs == 0 | diag.mean.mat2.obs == 0 - - -################ end detection of diagonales with mean zero - - -################ Analysis of observed matrices and data extraction - - -# MATRIX 1 -cat("\nCOLLECTION OF DIAGONAL PARAMETERS FROM OBSERVED MATRICES\n") -fun_report(data = "\n\n################################ COLLECTION OF DIAGONAL PARAMETERS FROM OBSERVED MATRICES", path = path.out, output = log.file, sep = 4) -# Means and sd are computed for each diagonal -tempo.coord <- row(mat1.obs) - col(mat1.obs) # row(pmat)-col(pmat) generate a matrix with same number on upleft/rightdown diag, with 0 for main diag and negative number for half right part -# diag.mean.mat1.obs already obtained above -diag.sd.mat1.obs <- sapply(0:-(nrow(mat1.obs) - 1), FUN = function(x){sd(mat1.obs[tempo.coord == x], na.rm = TRUE)}) # BEWARE: the last is NA because a single value for this corner diag -diag.cor.mat1.obs <- suppressWarnings(sapply(0:-(nrow(mat1.obs) - 1), FUN = function(x){cor(x = mat1.obs[tempo.coord == x], y = mat2.obs[tempo.coord == x], use = "pairwise.complete.obs", method = "spearman")})) # BEWARE: the last is NA because a single value for this corner diag # to remove the sd null message -mean.sd.cv.cor.mat1.obs <- as.matrix(data.frame(MEAN = diag.mean.mat1.obs, SD = diag.sd.mat1.obs, CV = diag.sd.mat1.obs / diag.mean.mat1.obs, COR = diag.cor.mat1.obs)) - -# replacement of the NA SD CV and CORR on the last line by ZER0: no consequence because we do not use SD, we use CV for taking one of them among the max and CORR we also use high values -if( ! all(is.na(mean.sd.cv.cor.mat1.obs[nrow(mean.sd.cv.cor.mat1.obs), c("SD", "CV", "COR")]))){ -tempo.cat <- paste0("\n\n========\n\nINTERNAL ERROR CODE IN SLITHERINE\nTHE LAST LINE (I.E., CORNER DIAGONAL) OF mean.sd.cv.cor.mat1.obs SHOULD BE NA FOR SD, CV AND CORR, BECAUSE A SINGLE VALUE IN THE CORNER DIAGONAL\n\n========\n\n") -cat(tempo.cat) -print(mean.sd.cv.cor.mat1.obs[nrow(mean.sd.cv.cor.mat1.obs), ]) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -# fun_report(data = mean.sd.cv.cor.mat1.obs[nrow(mean.sd.cv.cor.mat1.obs), ], output = log.file, path = path.out, rownames.kept = TRUE) -}else{ -mean.sd.cv.cor.mat1.obs[nrow(mean.sd.cv.cor.mat1.obs), c("SD", "CV", "COR")] <- 0 -tempo.cat <- paste0("FOR SD, CV AND CORR COLUMNS, REPLACEMENT OF the NA IN THE LAST LINE (I.E., CORNER DIAGONAL) OF mean.sd.cv.cor.mat1.obs BY ZERO\nNO CONSEQUENCE BECAUSE WE DO NOT USE SD, WE USE CV FOR TAKING ONE OF THEM AMONG THE MAX AND FOR CORR WE ALSO USE HIGH VALUES\n") -# cat(paste0("\n", tempo.cat, "\n")) -# print(mean.sd.cv.cor.mat1.obs[nrow(mean.sd.cv.cor.mat1.obs), ]) -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = mean.sd.cv.cor.mat1.obs[nrow(mean.sd.cv.cor.mat1.obs), ], output = log.file, path = path.out, rownames.kept = TRUE) -} -# replacement of c(-Inf, NA, Inf) by NA -# tempo.detect <- apply(apply(mean.sd.cv.cor.mat1.obs, 2, FUN = "%in%", c(0, -Inf, NA, Inf)), 1, "any") # per row -tempo.detect <- apply(mean.sd.cv.cor.mat1.obs, 2, FUN = "%in%", c(-Inf, NA, Inf)) # in the matrix -if(all(is.na(tempo.detect[nrow(tempo.detect), c("SD", "CV", "COR")])) == TRUE & (tempo.detect[nrow(tempo.detect), "MEAN"] == FALSE)){ -tempo.cat <- paste0("THE LAST LINE (I.E., CORNER DIAGONAL) OF mean.sd.cv.cor.mat1.obs IS NA FOR SD, CV and CORR, BUT THIS IS EXPECTED BECAUSE A SINGLE VALUE IN THE CORNER DIAGONAL") -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = mean.sd.cv.cor.mat1.obs[tempo.detect, ], output = log.file, path = path.out) -}else if(all(is.na(tempo.detect[nrow(tempo.detect), c("SD", "CV", "COR")])) == TRUE & (tempo.detect[nrow(tempo.detect), "MEAN"] == TRUE)){ -tempo.cat <- paste0("\n\n========\n\nINTERNAL ERROR CODE IN SLITHERINE\nTHE LAST LINE (I.E., CORNER DIAGONAL) OF mean.sd.cv.cor.mat1.obs CANNOT BE -Inf, NA OR Inf FOR THE MEAN COLUMN\n\n========\n\n") -cat(tempo.cat) -print(mean.sd.cv.cor.mat1.obs[nrow(tempo.detect), ]) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -# fun_report(data = mean.sd.cv.cor.mat1.obs[nrow(tempo.detect), ], output = log.file, path = path.out, rownames.kept = TRUE) -}else if(any(tempo.detect[-nrow(tempo.detect), ]) == TRUE | any(tempo.detect[nrow(tempo.detect), "MEAN"]) == TRUE){ -tempo.cat <- paste0("BEWARE: EXCEPT THE LAST ROW (I.E., CORNER DIAGONAL), ALSO PRESENCE OF -Inf, NA, OR Inf DETECTED IN mean.sd.cv.cor.mat1.obs, WHICH WILL PUT NA IN THEORETICAL MATRIX 1, WHICH IS NOT COMPATIBLE WITH SERPENTINE. REPLACEMENT OF NA WILL BE MADE THENAFTER") -# cat(paste0("\n", tempo.cat, "\n")) -# print(mean.sd.cv.cor.mat1.obs[apply(tempo.detect, 1, FUN = any), ]) -# print(mean.sd.cv.cor.mat1.obs[tempo.detect, ]) -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = mean.sd.cv.cor.mat1.obs[apply(tempo.detect, 1, FUN = any), ], output = log.file, path = path.out, rownames.kept = TRUE) -# fun_report(data = mean.sd.cv.cor.mat1.obs[tempo.detect, ], output = log.file, path = path.out, rownames.kept = TRUE) -mean.sd.cv.cor.mat1.obs[tempo.detect] <- NA # NA, -Inf and Inf replaced by NA -} -mean.sd.cv.cor.mat1.obs <- as.data.frame(mean.sd.cv.cor.mat1.obs) -# end replacement of c(-Inf, NA, Inf) by NA -# replacement of mean, sd, cor by zero if common null diag between mat1.obs and mat2.obs -if(any(common.null.mean.pos)){ -mean.sd.cv.cor.mat1.obs[common.null.mean.pos, c("MEAN", "SD", "COR")] <- 0 -tempo.cat <- paste0("BEWARE: IF AT LEAST ONE OF THE OBSERVED DIAG MEAN IS ZERO, THE CODE WILL CONSIDER THAT THE DIAG MEANS, SD, AND CORR ARE ZERO FOR THE TWO THEO CORRESPONDING DIAGONALES") -# cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -tempo.cat <- "REPLACEMENT BY ZERO IN THE THEO MAT 1" -# cat(paste0("\n", tempo.cat, "\n")) -# print(mean.sd.cv.cor.mat1.obs[apply(tempo.detect, 1, FUN = any), ]) -# print(mean.sd.cv.cor.mat1.obs[tempo.detect, ]) -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = mean.sd.cv.cor.mat1.obs[common.null.mean.pos, ], output = log.file, path = path.out, rownames.kept = TRUE) -} -# end replacement of mean, sd, cor by zero if common null diag between mat1.obs and mat2.obs -# END MATRIX 1 - - - -# MATRIX 2 -# Means and sd are computed for each diagonal -tempo.coord <- row(mat2.obs) - col(mat2.obs) # row(pmat)-col(pmat) generate a matrix with same number on upleft/rightdown diag, with 0 for main diag and negative number for half right part -# diag.mean.mat2.obs already obtained above -diag.sd.mat2.obs <- sapply(0:-(nrow(mat2.obs) - 1), FUN = function(x){sd(mat2.obs[tempo.coord == x], na.rm = TRUE)}) # BEWARE: the last is NA because a single value for this corner diag -diag.cor.mat2.obs <- suppressWarnings(sapply(0:-(nrow(mat2.obs) - 1), FUN = function(x){cor(x = mat1.obs[tempo.coord == x], y = mat2.obs[tempo.coord == x], use = "pairwise.complete.obs", method = "spearman")})) # BEWARE: the last is NA because a single value for this corner diag # to remove the sd null message -mean.sd.cv.cor.mat2.obs <- as.matrix(data.frame(MEAN = diag.mean.mat2.obs, SD = diag.sd.mat2.obs, CV = diag.sd.mat2.obs / diag.mean.mat2.obs, COR = diag.cor.mat2.obs)) - -# replacement of the NA SD CV and CORR on the last line by ZER0: no consequence because we do not use SD, we use CV for taking one of them among the max and CORR we also use high values -if( ! all(is.na(mean.sd.cv.cor.mat2.obs[nrow(mean.sd.cv.cor.mat2.obs), c("SD", "CV", "COR")]))){ -tempo.cat <- paste0("\n\n========\n\nINTERNAL ERROR CODE IN SLITHERINE\nTHE LAST LINE (I.E., CORNER DIAGONAL) OF mean.sd.cv.cor.mat2.obs SHOULD BE NA FOR SD, CV AND CORR, BECAUSE A SINGLE VALUE IN THE CORNER DIAGONAL\n\n========\n\n") -cat(tempo.cat) -print(mean.sd.cv.cor.mat2.obs[nrow(mean.sd.cv.cor.mat2.obs), ]) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -# fun_report(data = mean.sd.cv.cor.mat2.obs[nrow(mean.sd.cv.cor.mat2.obs), ], output = log.file, path = path.out, rownames.kept = TRUE) -}else{ -mean.sd.cv.cor.mat2.obs[nrow(mean.sd.cv.cor.mat2.obs), c("SD", "CV", "COR")] <- 0 -tempo.cat <- paste0("FOR SD, CV AND CORR COLUMNS, REPLACEMENT OF the NA IN THE LAST LINE (I.E., CORNER DIAGONAL) OF mean.sd.cv.cor.mat2.obs BY ZERO\nNO CONSEQUENCE BECAUSE WE DO NOT USE SD, WE USE CV FOR TAKING ONE OF THEM AMONG THE MAX AND FOR CORR WE ALSO USE HIGH VALUES\n") -# cat(paste0("\n", tempo.cat, "\n")) -# print(mean.sd.cv.cor.mat2.obs[nrow(mean.sd.cv.cor.mat2.obs), ]) -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = mean.sd.cv.cor.mat2.obs[nrow(mean.sd.cv.cor.mat2.obs), ], output = log.file, path = path.out, rownames.kept = TRUE) -} -# replacement of c(-Inf, NA, Inf) by NA -# tempo.detect <- apply(apply(mean.sd.cv.cor.mat2.obs, 2, FUN = "%in%", c(0, -Inf, NA, Inf)), 1, "any") # per row -tempo.detect <- apply(mean.sd.cv.cor.mat2.obs, 2, FUN = "%in%", c(-Inf, NA, Inf)) # in the matrix -if(all(is.na(tempo.detect[nrow(tempo.detect), c("SD", "CV", "COR")])) == TRUE & (tempo.detect[nrow(tempo.detect), "MEAN"] == FALSE)){ -tempo.cat <- paste0("THE LAST LINE (I.E., CORNER DIAGONAL) OF mean.sd.cv.cor.mat2.obs IS NA FOR SD, CV and CORR, BUT THIS IS EXPECTED BECAUSE A SINGLE VALUE IN THE CORNER DIAGONAL") -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = mean.sd.cv.cor.mat2.obs[tempo.detect, ], output = log.file, path = path.out) -}else if(all(is.na(tempo.detect[nrow(tempo.detect), c("SD", "CV", "COR")])) == TRUE & (tempo.detect[nrow(tempo.detect), "MEAN"] == TRUE)){ -tempo.cat <- paste0("\n\n========\n\nINTERNAL ERROR CODE IN SLITHERINE\nTHE LAST LINE (I.E., CORNER DIAGONAL) OF mean.sd.cv.cor.mat2.obs CANNOT BE -Inf, NA OR Inf FOR THE MEAN COLUMN\n\n========\n\n") -cat(tempo.cat) -print(mean.sd.cv.cor.mat2.obs[nrow(tempo.detect), ]) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -# fun_report(data = mean.sd.cv.cor.mat2.obs[nrow(tempo.detect), ], output = log.file, path = path.out, rownames.kept = TRUE) -}else if(any(tempo.detect[-nrow(tempo.detect), ]) == TRUE | any(tempo.detect[nrow(tempo.detect), "MEAN"]) == TRUE){ -tempo.cat <- paste0("BEWARE: EXCEPT THE LAST ROW (I.E., CORNER DIAGONAL), ALSO PRESENCE OF -Inf, NA, OR Inf DETECTED IN mean.sd.cv.cor.mat2.obs, WHICH WILL PUT NA IN THEORETICAL MATRIX 2, WHICH IS NOT COMPATIBLE WITH SERPENTINE. REPLACEMENT OF NA WILL BE MADE THENAFTER") -# cat(paste0("\n", tempo.cat, "\n")) -# print(mean.sd.cv.cor.mat2.obs[apply(tempo.detect, 1, FUN = any), ]) -# print(mean.sd.cv.cor.mat2.obs[tempo.detect, ]) -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = mean.sd.cv.cor.mat2.obs[apply(tempo.detect, 1, FUN = any), ], output = log.file, path = path.out, rownames.kept = TRUE) -# fun_report(data = mean.sd.cv.cor.mat2.obs[tempo.detect, ], output = log.file, path = path.out, rownames.kept = TRUE) -mean.sd.cv.cor.mat2.obs[tempo.detect] <- NA # NA, -Inf and Inf replaced by NA -} -mean.sd.cv.cor.mat2.obs <- as.data.frame(mean.sd.cv.cor.mat2.obs) -# end replacement of c(-Inf, NA, Inf) by NA -# replacement of mean, sd, cor by zero if common null diag between mat2.obs and mat2.obs -if(any(common.null.mean.pos)){ -mean.sd.cv.cor.mat2.obs[common.null.mean.pos, c("MEAN", "SD", "COR")] <- 0 -tempo.cat <- paste0("BEWARE: IF AT LEAST ONE OF THE OBSERVED DIAG MEAN IS ZERO, THE CODE WILL CONSIDER THAT THE DIAG MEANS, SD, AND CORR ARE ZERO FOR THE TWO THEO CORRESPONDING DIAGONALES") -# cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -tempo.cat <- "REPLACEMENT BY ZERO IN THE THEO MAT 2" -# cat(paste0("\n", tempo.cat, "\n")) -# print(mean.sd.cv.cor.mat2.obs[apply(tempo.detect, 1, FUN = any), ]) -# print(mean.sd.cv.cor.mat2.obs[tempo.detect, ]) -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = mean.sd.cv.cor.mat2.obs[common.null.mean.pos, ], output = log.file, path = path.out, rownames.kept = TRUE) -} -# end replacement of mean, sd, cor by zero if common null diag between mat2.obs and mat2.obs -# END MATRIX 2 - - -################ End Analysis of observed matrices and data extraction - - -################ plot verification - - -# homogeneous scale -m_sd.coord.obs <- fun_gg_scatter(data1 = list(L1 = if(transfo != "no"){get(transfo)(mean.sd.cv.cor.mat1.obs[, c("MEAN", "SD")])}else{mean.sd.cv.cor.mat1.obs[, c("MEAN", "SD")]}, L2 = if(transfo != "no"){get(transfo)(mean.sd.cv.cor.mat2.obs[, c("MEAN", "SD")])}else{mean.sd.cv.cor.mat2.obs[, c("MEAN", "SD")]}), x = list(L1 = "MEAN", L2 = "MEAN"), y = list(L1 = "SD", L2 = "SD"), geom = list("geom_point", "geom_point"), alpha = list(0.5, 0.5), xlog = transfo, ylog = transfo, plot = FALSE, return = TRUE) -m_sd.x.range <- m_sd.coord.obs$axes$x.range -m_sd.y.range <- m_sd.coord.obs$axes$y.range -m_cor.coord.obs <- fun_gg_scatter(data1 = list(L1 = data.frame(MEAN = if(transfo != "no"){get(transfo)(mean.sd.cv.cor.mat1.obs[, "MEAN"])}else{mean.sd.cv.cor.mat1.obs[, "MEAN"]}, mean.sd.cv.cor.mat1.obs["COR"]), L2 = data.frame(MEAN = if(transfo != "no"){get(transfo)(mean.sd.cv.cor.mat2.obs[, "MEAN"])}else{mean.sd.cv.cor.mat2.obs[, "MEAN"]}, mean.sd.cv.cor.mat2.obs["COR"])), x = list(L1 = "MEAN", L2 = "MEAN"), y = list(L1 = "COR", L2 = "COR"), geom = list("geom_point", "geom_point"), alpha = list(0.5, 0.5), xlog = transfo, ylog = "no", plot = FALSE, return = TRUE, ylim = c(-1, 1)) -m_cor.x.range <- m_cor.coord.obs$axes$x.range -m_cor.y.range <- m_cor.coord.obs$axes$y.range -m_cv.coord.obs <- fun_gg_scatter(data1 = list(L1 = if(transfo != "no"){get(transfo)(mean.sd.cv.cor.mat1.obs[, c("MEAN", "CV")])}else{mean.sd.cv.cor.mat1.obs[, c("MEAN", "CV")]}, L2 = if(transfo != "no"){get(transfo)(mean.sd.cv.cor.mat2.obs[, c("MEAN", "CV")])}else{mean.sd.cv.cor.mat2.obs[, c("MEAN", "CV")]}), x = list(L1 = "MEAN", L2 = "MEAN"), y = list(L1 = "CV", L2 = "CV"), geom = list("geom_point", "geom_point"), alpha = list(0.5, 0.5), xlog = transfo, ylog = transfo, plot = FALSE, return = TRUE) -m_cv.x.range <- m_cv.coord.obs$axes$x.range -m_cv.y.range <- m_cv.coord.obs$axes$y.range -# end homogeneous scale - -# MATRIX1 -# heatmap: matrix checking -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "OBSERVED MATRIX 1:\nCOLLECTION OF DIAGONAL PARAMETERS", text.size = 3) -# if(activate.pdf == TRUE){ -# invisible(dev.set(pdf.nb)) -# }else{ -# fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -# } -# tempo.title <- paste0("MAT1 OBS\n", if(transfo == "log2"){"LOG2(x + 1) "}else if(transfo == "log10"){"LOG10(x + 1) "}else{"NO "}, "TRANSFORMATION\nSCALE RANGE: ", paste(fun_round(heatmap.range, 2), collapse = " , "), "\nNORMALIZED DISPLAY (GLOBAL MEAN DIVISION)") -# tempo.data.plot <- mat1.obs / mean(mat1.obs[is.finite(mat1.obs)], na.rm = TRUE) # -# if(transfo != "no"){ -# tempo.data.plot <- get(transfo)(tempo.data.plot + 1) -# } -# fun_gg_heatmap(data1 = tempo.data.plot, legend.name = "", limit1 = c(min(heatmap.range, na.rm = TRUE), max(heatmap.range, na.rm = TRUE)), midpoint1 = mean(heatmap.range, na.rm = TRUE), title = tempo.title, text.size = heatmap.text.size, title.text.size = title.text.size) -# end heatmap: matrix checking - -tempo.data.plot <- mean.sd.cv.cor.mat1.obs -tempo.data.plot2 <- data.frame(MEAN = tempo.data.plot$MEAN, MEAN.MINUS.SD = tempo.data.plot$MEAN - tempo.data.plot$SD, MEAN.PLUS.SD = tempo.data.plot$MEAN + tempo.data.plot$SD) # created here to be before log transformation -if(transfo != "no"){ -tempo.data.plot[, c("MEAN", "SD", "CV")] <- get(transfo)(tempo.data.plot[, c("MEAN", "SD", "CV")]) # log(x + 1) only for heatmap -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN / 2, y.cv.pois = get(transfo)(1) - tempo.data.plot$MEAN / 2) # because poisson distrib is mean = variance, thus sd = mean ^0.5, ie each mean as x is square rooted for y and then x.MEAN / 2 because log2(mean^0.5) = 0.5 * log2(mean). For cv, cv = sd/m -> log(cv) = log(sd/m) = log(m/m^0.5) = log(1/m^0.5) = log(1) - log(m^0.5) = log(1) - log(m)/2 -}else{ -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN^0.5, y.cv.pois = 1 / tempo.data.plot$MEAN^0.5) -} - -# mean versus index plot -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -if(transfo != "no"){ -tempo.data.plot2 <- suppressWarnings(get(transfo)(tempo.data.plot2)) # log(x + 1) only for heatmap -if(any(is.na(tempo.data.plot2$MEAN.MINUS.SD))){ -tempo.data.plot2$MEAN.MINUS.SD[is.na(tempo.data.plot2$MEAN.MINUS.SD)] <- tempo.data.plot2$MEAN[is.na(tempo.data.plot2$MEAN.MINUS.SD)] -} -} -tempo.data.plot2 <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot2), tempo.data.plot2) -tempo.title <-paste0("MAT1 OBS\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nDIAGONAL NB FROM MAIN TO CORNER\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot2), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.x.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot2), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, xlog = "no", xlab = "DIAGONAL NB", x.tick.nb = 8, ylog = transfo, ylab = "MEAN", ylim = m_sd.x.range, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot2$COLUMN_NB, xend = tempo.data.plot2$COLUMN_NB, y = tempo.data.plot2$MEAN.MINUS.SD, yend = tempo.data.plot2$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) -# end mean versus index plot -# Mean Deviation (MD) plot of the observed matrix -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0("MAT1 OBS\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\n") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("SD", "y.sd.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, xlim = m_sd.x.range, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_sd.y.range, ylog = transfo, ylab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# end Mean Deviation (MD) plot of the observed matrix - -# mean / cor of the observed matrix -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0("MAT1 OBS\nMEAN VERSUS MAT1 OBS / MAT2 OBS SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, xlim = m_cor.x.range, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_cor.y.range, ylog = "no", ylab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# end mean / cor of the observed matrix - -# mean / cv of the observed matrix -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0("MAT1 OBS\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND CV LOG2(x) "}else if(transfo == "log10"){"MEAN AND CV LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cv.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cv.y.range, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\n") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, xlim = m_cv.x.range, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_cv.y.range, ylog = transfo, ylab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_cv.coord.obs -# end mean / cv of the observed matrix - -# cv selection using increasing windows to detect the average constant cv -tempo.cv.mean.mat <- mean.sd.cv.cor.mat1.obs[ ! (mean.sd.cv.cor.mat1.obs$CV == 0 | mean.sd.cv.cor.mat1.obs$MEAN == 0 | is.na(mean.sd.cv.cor.mat1.obs$MEAN) | is.na(mean.sd.cv.cor.mat1.obs$CV)), ] # remove 0 and NA in mean and CV -sort.cv1 <- sort(tempo.cv.mean.mat$CV) -sort.mean <- tempo.cv.mean.mat$MEAN[order(tempo.cv.mean.mat$CV, na.last = NA)] # means sorted like cv -# n.cv <- length(sort.cv1) -win.size.ini <- win.size -if(win.size >= length(sort.cv1)){ -tempo.warning <- paste0("THE win.size PARAMETER SETTING (", win.size, ") IS OVER OR EQUAL TO THE NUMBER OF NON NA DIAGONAL CV OF THE OBSERVED MATRIX 1 (", length(sort.cv1), ")\nTHE win.size PARAMETER HAS BEEN RESET TO VALUE: ", length(sort.cv1) - 1) -cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used -win.size <- length(sort.cv1) - 1 -fun_report(data = tempo.warning, output = log.file, path = path.out) -} -if(win.size < 2){ -tempo.cat <- paste0("\n\n========\n\nINTERNAL ERROR CODE IN SLITHERINE\nwin.size IS LESS THAN 2. NO BEST CV CAN BE COMPUTED\n\n========\n\n") -stop(tempo.cat) -} -if(win.size < length(sort.cv1)){ -cv.win.mean <- vector("numeric", win.size - 1) # mean cv in the increasing window of the sorted cv -cv.win.mean[] <- NA -cv.win.sd <- vector("numeric", win.size - 1) # sd cv in the increasing window of the sorted cv -cv.win.sd[] <- NA -mean.win.median <- vector("numeric", win.size - 1) # median in the increasing window of the sorted mean -mean.win.median[] <- NA -mean.win.mean <- vector("numeric", win.size - 1) # for the cv selection: mean in the increasing window of the sorted mean -mean.win.mean[] <- NA -for(i0 in 2:win.size){ # to take at least 2 values, to avoid a first NA -cv.win.mean[i0 - 1] <- mean(sort.cv1[1:i0], na.rm = TRUE) -cv.win.sd[i0 - 1] <- sd(sort.cv1[1:i0], na.rm = TRUE) -mean.win.median[i0 - 1] <- median(sort.mean[1:i0], na.rm = TRUE) -mean.win.mean[i0 - 1] <- mean(sort.mean[1:i0], na.rm = TRUE) -} -if(any(is.na(cv.win.mean))){ -tempo.cat <- paste0("\n\n========\n\nINTERNAL ERROR CODE IN SLITHERINE\ncv.win.mean SHOULD NOT HAVE ANY NA\n\n========\n\n") -stop(tempo.cat) -# fun_report(data = tempo.cat, output = log.file, path = path.out) -} -} -if(any(is.na(cumsum(diff(cv.win.sd / mean.win.mean))))){ -tempo.cat <- paste0("\n\n========\n\nINTERNAL ERROR CODE IN SLITHERINE\nNO NA SHOULD BE PRESENT IN cv.win.sd / mean.win.mean\n\n========\n\n") -cat(tempo.cat) -print(cv.win.sd / mean.win.mean) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -# fun_report(data = cv.win.sd / mean.win.mean, output = log.file, path = path.out, rownames.kept = TRUE) -}else{ -cv.select.nb <- which.min(cumsum(diff(cv.win.sd / mean.win.mean))) -} -i0 <- 1 -while(median(sort.cv1[i0:cv.select.nb], na.rm = TRUE) == 0 | median(sort.mean[i0:cv.select.nb], na.rm = TRUE) == 0){ # loop to avoid to take zero values in sort.cv1 and sort.mean -i0 <- i0 + 1 -cv.select.nb <- cv.select.nb + 1 -} -cv.select.mat1.obs <- median(sort.cv1[i0:cv.select.nb], na.rm = TRUE) # cv selected is the median of the xxx first cv -mean.select.mat1.obs <- median(sort.mean[i0:cv.select.nb], na.rm = TRUE) - -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0("MAT1 OBS\nSLIDING CV COMPUTATION\nBLUE DOTS: MEAN+/-SD OF CV IN INCREASING WINDOWS OF CV VALUES\nGREEN LINE: SELECTED CV VALUE IS ", round(cv.select.mat1.obs, 2), ", BASED ON MEDIAN OF ", cv.select.nb, " BLUE DOTS\nRED LINE: POISSON DISTRIB\n", if(transfo == "log2"){"LOG2(x) "}else if(transfo == "log10"){"LOG10(x) "}else{"NO "}, "TRANSFORMATION") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, xlim = m_cv.x.range, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_cv.y.range, ylog = transfo, ylab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0, add = paste0('+ ggplot2::geom_point(data = data.frame(x = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean)), ggplot2::aes(x = x, y = y), color = "blue", size = dot.size, alpha = 0.3) + ggplot2::geom_segment(data = data.frame(x = get(transfo)(mean.win.median), xend = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean - cv.win.sd), yend = get(transfo)(cv.win.mean + cv.win.sd)), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = "blue", alpha = 0.3) + ggplot2::geom_hline(data = data.frame(y = get(transfo)(cv.select.mat1.obs)), ggplot2::aes(yintercept = y), color = "green", size = line.size) + ggplot2::theme_classic(base_size = text.size)', if(raster == TRUE){'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size), aspect.ratio = 1)'}else{'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size))'})) -# cv selection using increasing windows to detect the average constant cv -# END MATRIX 1 - - -# MATRIX2 -# heatmap: matrix checking -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "OBSERVED MATRIX 2:\nCOLLECTION OF DIAGONAL PARAMETERS", text.size = 3) -# if(activate.pdf == TRUE){ -# invisible(dev.set(pdf.nb)) -# }else{ -# fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -# } -# tempo.title <- paste0("MAT2 OBS\n", if(transfo == "log2"){"LOG2(x + 1) "}else if(transfo == "log10"){"LOG10(x + 1) "}else{"NO "}, "TRANSFORMATION\nSCALE RANGE: ", paste(fun_round(heatmap.range, 2), collapse = " , "), "\nNORMALIZED DISPLAY (GLOBAL MEAN DIVISION)") -# tempo.data.plot <- mat2.obs / mean(mat2.obs[is.finite(mat2.obs)], na.rm = TRUE) # -# if(transfo != "no"){ -# tempo.data.plot <- get(transfo)(tempo.data.plot + 1) -# } -# fun_gg_heatmap(data1 = tempo.data.plot, legend.name = "", limit1 = c(min(heatmap.range, na.rm = TRUE), max(heatmap.range, na.rm = TRUE)), midpoint1 = mean(heatmap.range, na.rm = TRUE), title = tempo.title, text.size = heatmap.text.size, title.text.size = title.text.size) -# end heatmap: matrix checking - -tempo.data.plot <- mean.sd.cv.cor.mat2.obs -tempo.data.plot2 <- data.frame(MEAN = tempo.data.plot$MEAN, MEAN.MINUS.SD = tempo.data.plot$MEAN - tempo.data.plot$SD, MEAN.PLUS.SD = tempo.data.plot$MEAN + tempo.data.plot$SD) # created here to be before log transformation -if(transfo != "no"){ -tempo.data.plot[, c("MEAN", "SD", "CV")] <- get(transfo)(tempo.data.plot[, c("MEAN", "SD", "CV")]) # log(x + 1) only for heatmap -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN / 2, y.cv.pois = get(transfo)(1) - tempo.data.plot$MEAN / 2) # because poisson distrib is mean = variance, thus sd = mean ^0.5, ie each mean as x is square rooted for y and then x.MEAN / 2 because log2(mean^0.5) = 0.5 * log2(mean). For cv, cv = sd/m -> log(cv) = log(sd/m) = log(m/m^0.5) = log(1/m^0.5) = log(1) - log(m^0.5) = log(1) - log(m)/2 -}else{ -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN^0.5, y.cv.pois = 1 / tempo.data.plot$MEAN^0.5) -} - - -# mean versus index plot -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -if(transfo != "no"){ -tempo.data.plot2 <- suppressWarnings(get(transfo)(tempo.data.plot2)) # log(x + 1) only for heatmap -if(any(is.na(tempo.data.plot2$MEAN.MINUS.SD))){ -tempo.data.plot2$MEAN.MINUS.SD[is.na(tempo.data.plot2$MEAN.MINUS.SD)] <- tempo.data.plot2$MEAN[is.na(tempo.data.plot2$MEAN.MINUS.SD)] -} -} -tempo.data.plot2 <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot2), tempo.data.plot2) -tempo.title <-paste0("MAT2 OBS\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nDIAGONAL NB FROM MAIN TO CORNER\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot2), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.x.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot2), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, xlog = "no", xlab = "DIAGONAL NB", x.tick.nb = 8, ylog = transfo, ylab = "MEAN", ylim = m_sd.x.range, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot2$COLUMN_NB, xend = tempo.data.plot2$COLUMN_NB, y = tempo.data.plot2$MEAN.MINUS.SD, yend = tempo.data.plot2$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) -# end mean versus index plot -# Mean Deviation (MD) plot of the observed matrix -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0("MAT2 OBS\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\n") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("SD", "y.sd.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, xlim = m_sd.x.range, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_sd.y.range, ylog = transfo, ylab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# end Mean Deviation (MD) plot of the observed matrix - -# mean / cor of the observed matrix -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0("MAT2 OBS\nMEAN VERSUS MAT1 OBS / MAT2 OBS SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, xlim = m_cor.x.range, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_cor.y.range, ylog = "no", ylab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# end mean / cor of the observed matrix - -# mean / cv of the observed matrix -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0("MAT2 OBS\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND CV LOG2(x) "}else if(transfo == "log10"){"MEAN AND CV LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cv.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cv.y.range, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\n") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, xlim = m_cv.x.range, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_cv.y.range, ylog = transfo, ylab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_cv.coord.obs -# end mean / cv of the observed matrix - -# cv selection using increasing windows to detect the average constant cv -tempo.cv.mean.mat <- mean.sd.cv.cor.mat2.obs[ ! (mean.sd.cv.cor.mat2.obs$CV == 0 | mean.sd.cv.cor.mat2.obs$MEAN == 0 | is.na(mean.sd.cv.cor.mat2.obs$MEAN) | is.na(mean.sd.cv.cor.mat2.obs$CV)), ] # remove 0 and NA in mean and CV -sort.cv2 <- sort(tempo.cv.mean.mat$CV) -sort.mean <- tempo.cv.mean.mat$MEAN[order(tempo.cv.mean.mat$CV, na.last = NA)] # means sorted like cv -# n.cv <- length(sort.cv2) -win.size <- win.size.ini # in case modified during first MAT1 analysis -if(win.size >= length(sort.cv2)){ -tempo.warning <- paste0("THE win.size PARAMETER SETTING (", win.size, ") IS OVER OR EQUAL TO THE NUMBER OF NON NA DIAGONAL CV OF THE OBSERVED MATRIX 2 (", length(sort.cv2), ")\nTHE win.size PARAMETER HAS BEEN RESET TO VALUE: ", length(sort.cv2) - 1) -cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used -win.size <- length(sort.cv2) - 1 -fun_report(data = tempo.warning, output = log.file, path = path.out) -} -if(win.size < 2){ -tempo.cat <- paste0("\n\n========\n\nINTERNAL ERROR CODE IN SLITHERINE\nwin.size IS LESS THAN 2. NO BEST CV CAN BE COMPUTED\n\n========\n\n") -stop(tempo.cat) -} -if(win.size < length(sort.cv2)){ -cv.win.mean <- vector("numeric", win.size - 1) # mean cv in the increasing window of the sorted cv -cv.win.mean[] <- NA -cv.win.sd <- vector("numeric", win.size - 1) # sd cv in the increasing window of the sorted cv -cv.win.sd[] <- NA -mean.win.median <- vector("numeric", win.size - 1) # median in the increasing window of the sorted mean -mean.win.median[] <- NA -mean.win.mean <- vector("numeric", win.size - 1) # for the cv selection: mean in the increasing window of the sorted mean -mean.win.mean[] <- NA -for(i0 in 2:win.size){ # to take at least 2 values, to avoid a first NA -cv.win.mean[i0 - 1] <- mean(sort.cv2[1:i0], na.rm = TRUE) -cv.win.sd[i0 - 1] <- sd(sort.cv2[1:i0], na.rm = TRUE) -mean.win.median[i0 - 1] <- median(sort.mean[1:i0], na.rm = TRUE) -mean.win.mean[i0 - 1] <- mean(sort.mean[1:i0], na.rm = TRUE) -} -if(any(is.na(cv.win.mean))){ -tempo.cat <- paste0("\n\n========\n\nINTERNAL ERROR CODE IN SLITHERINE\ncv.win.mean SHOULD NOT HAVE ANY NA\n\n========\n\n") -cat(tempo.cat) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -} -} -if(any(is.na(cumsum(diff(cv.win.sd / mean.win.mean))))){ -tempo.cat <- paste0("\n\n========\n\nINTERNAL ERROR CODE IN SLITHERINE\nNO NA SHOULD BE PRESENT IN cv.win.sd / mean.win.mean\n\n========\n\n") -cat(tempo.cat) -print(cv.win.sd / mean.win.mean) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -# fun_report(data = cv.win.sd / mean.win.mean, output = log.file, path = path.out, rownames.kept = TRUE) -}else{ -cv.select.nb <- which.min(cumsum(diff(cv.win.sd / mean.win.mean))) -} -i0 <- 1 -while(median(sort.cv2[i0:cv.select.nb], na.rm = TRUE) == 0 | median(sort.mean[i0:cv.select.nb], na.rm = TRUE) == 0){ # loop to avoid to take zero values in sort.cv2 and sort.mean -i0 <- i0 + 1 -cv.select.nb <- cv.select.nb + 1 -} -cv.select.mat2.obs <- median(sort.cv2[i0:cv.select.nb], na.rm = TRUE) # cv selected is the median of the xxx first cv -mean.select.mat2.obs <- median(sort.mean[i0:cv.select.nb], na.rm = TRUE) - -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0("MAT2 OBS\nSLIDING CV COMPUTATION\nBLUE DOTS: MEAN+/-SD OF CV IN INCREASING WINDOWS OF CV VALUES\nGREEN LINE: SELECTED CV VALUE IS ", round(cv.select.mat2.obs, 2), ", BASED ON MEDIAN OF ", cv.select.nb, " BLUE DOTS\nRED LINE: POISSON DISTRIB\n", if(transfo == "log2"){"LOG2(x) "}else if(transfo == "log10"){"LOG10(x) "}else{"NO "}, "TRANSFORMATION") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois), x = list("MEAN", "x.pois"), y = list("CV", "y.cv.pois"), color = list(grey(0.40), "red"), geom = list("geom_point", "geom_line"), alpha = list(0.5, 1), dot.size = dot.size, line.size = line.size, xlim = m_cv.x.range, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_cv.y.range, ylog = transfo, ylab = "CV", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0, add = paste0('+ ggplot2::geom_point(data = data.frame(x = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean)), ggplot2::aes(x = x, y = y), color = "blue", size = dot.size, alpha = 0.3) + ggplot2::geom_segment(data = data.frame(x = get(transfo)(mean.win.median), xend = get(transfo)(mean.win.median), y = get(transfo)(cv.win.mean - cv.win.sd), yend = get(transfo)(cv.win.mean + cv.win.sd)), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = "blue", alpha = 0.3) + ggplot2::geom_hline(data = data.frame(y = get(transfo)(cv.select.mat2.obs)), ggplot2::aes(yintercept = y), color = "green", size = line.size) + ggplot2::theme_classic(base_size = text.size)', if(raster == TRUE){'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size), aspect.ratio = 1)'}else{'+ ggplot2::theme(text = ggplot2::element_text(size = text.size), plot.title = ggplot2::element_text(size = title.text.size))'})) -# cv selection using increasing windows to detect the average constant cv -# END MATRIX 2 - - -################ End plot verification - - -################ Theoretical matrices - - -# MATRIX 1 -cat("\nTHEORETICAL MATRIX DESIGN\n") -fun_report(data = "\n\n################################ THEORETICAL MATRIX DESIGN", path = path.out, output = log.file, sep = 4) -n1 <- nrow(mean.sd.cv.cor.mat1.obs) -mu1 <- sort(mean.sd.cv.cor.mat1.obs$MEAN, decreasing = TRUE, na.last = TRUE) # need the ordering to work on correlation (see below), decreasing = TRUE to have the first column in theo1 as the main diagonal -if(cv.rho.obtained == TRUE){ -source(path.cv.rho) # -tempo.cat <- paste0("BEWARE: THE SAVED FILE:\n", paste0(path.out, "/cv1_cv2_rho1_rho2_backup.RData"), "\nIS MAD OF VALUES COMING FROM THE DOWNLOAD OF:\n", path.cv.rho) -fun_report(data = tempo.cat, output = log.file, path = path.out) -}else{ -rho1 <- mean.sd.cv.cor.mat1.obs$COR[order(mean.sd.cv.cor.mat1.obs$MEAN, decreasing = TRUE, na.last = TRUE)] -cv1 <- cv.select.mat1.obs # see above -} -# mean correction before subsampling -# Subsampling is necessary because we cannot have any mean of a diagonal less than t = 1/cv1^2. -# Thus, we have to multiply all the value to increase diagonal means, then use the BN law, and then subsample to go back to the initial means -# see Negative binomial law, CV m relationship and subsampling.docx do understand the origin of these formula (equation numbers) -t1 <- 1 / cv1^2 # equation (1) -p1 <- exp(-t1 /mu1) # equation (8). Related to equation (9). In these equations, m cannot go below mt, but we do not care here for the correction -r1 <- t1 / p1 # equation (7) -# Beware: one sub.factor per diagonal: meaning that we do not apply the same up raising and dowsampling coeff for all the diag -sub.factor1 = t1 / ( mu1 * ( 1 - p1)) # equation (9), with mt = m1 (obs) and m = mean.nb1 (theo mean of NB). equation (9) / m1 -> t1 / ( mu1 * ( 1 - exp(-t1/mu1))) and sub.factor1 = m / mt, ie, sub.factor1 = mean.nb1 / m1. Thus, for the down sampling, to go back to m1, we will have to divide by sub.factor1 -mean.nb1 <- p1 * r1 / (1 - p1) # equation (2), just for graphs -sd.nb1 <- (p1 * r1 / (1 - p1)^2)^0.5 # equation (3), just for graphs -# end mean correction before subsampling -# because in two contact matrix, the values in the largest diagonal, where the mean is the biggest, are very correlated, and because this correlation decreases in other diagonales when taking distance from the largest diag, we have to sort the generated values by the neg binom distrib, more or less depending on the mean used. - -if(is.null(n.row)){ -n.row <- n1 -} -mat1.ini <- matrix(NA, nrow = n.row, ncol = n1) # each column of mat1.ini is filled with random values according to neg binom distrib, with mean increasing for each column of mat1.ini -# solving the fact that when p is less than 1e-16, 1-p is rounded by R to 1, which results in prob = 1 in the rnbinom() function and only 0 returned -p1.rd <- p1 -r1.rd <- r1 -cutoff.pb <- 1e-13 # cut-off at which p is ok -if(any(p1.rd < cutoff.pb & p1.rd > 0)){ -cutoff.pos1 <- which.max(p1.rd < cutoff.pb & p1.rd > 0) - 1 -if(cutoff.pos1 == 0){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nCODE CANNOT WORK IF cutoff.pos1 IS EQUAL TO ZERO\n\n============\n\n") -fun_report(data = tempo.cat, output = log.file, path = path.out) -stop("\n", tempo.cat, "\n") -}else{ -r1.rd[p1.rd < cutoff.pb & p1.rd > 0] <- r1.rd[cutoff.pos1] # beware: must be before p2.rd -p1.rd[p1.rd < cutoff.pb & p1.rd > 0] <- p1.rd[cutoff.pos1] -} -} -# end solving the fact that when p is less than 1e-16, 1-p is rounded by R to 1, which results in prob = 1 in the rnbinom() function and only 0 returned -for(i1 in 1:length(mu1)){ -if( mu1[i1] != 0){ # otherwise cannot compute rnbinom() because p Infinite -mat1.ini[, i1] <- rnbinom(n = n.row, size = r1.rd[i1], prob = 1 - p1.rd[i1]) # because prob is the proba of success in R, while it is the proba of failure in the equation -}else{ -mean.nb1[i1] <- 0 # just for graphs -sd.nb1[i1] <- NA # just for graphs -mat1.ini[, i1] <- 0 -tempo.cat <- paste0("BEWARE: IN LOOP ", i1,", mu1 HAS A ZERO VALUE: NO NEG BINOM LAW USED -> MATRIX COLUMN FILLED WITH ZERO") -# cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -} -} -cv.nb1 <- sd.nb1 / mean.nb1 # just for graphs -options.ini <- options()$digits -options(digits = 22) -if(any((cv1^2 < 1/mean.nb1[ ! (is.na(mean.nb1) | ! is.finite(1 / mean.nb1))]) | (sapply(FUN = all.equal, 1/mean.nb1[ ! (is.na(mean.nb1) | ! is.finite(1 / mean.nb1))], cv1^2) == TRUE))){ # because we need sigma^2 > mean.nb1 for neg binom (otherwise, we have to use poisson) -# Then sigma^2 / mean.nb1^2 < mean.nb1 / mean.nb1^2 -> cv1^2 > 1/mean.nb1 -tempo.cat <- paste0("\n\n========\n\nPROBLEM: cv1 PARAMETER MUST BE SUCH THAT cv1^2 > 1/mean.nb1\ncv1 : ", cv1, "\ncv1^2 : ", cv1^2, "\nmean.nb1 VALUES DO NOT RESPECTING THE FORMULA (ZERO NOT CONSIDERED): ", paste(mean.nb1[ ! (is.na(mean.nb1) | ! is.finite(1 / mean.nb1))][cv1^2 <= 1/mean.nb1[ ! (is.na(mean.nb1) | ! is.finite(1 / mean.nb1))]], collapse = " "), "\n1/mean.nb1: ", paste(1 / mean.nb1[ ! (is.na(mean.nb1) | ! is.finite(1 / mean.nb1))][cv1^2 <= 1/mean.nb1[ ! (is.na(mean.nb1) | ! is.finite(1 / mean.nb1))]], collapse = " "), "\n\n========\n\n") -# cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -} -options(digits = options.ini) - - -# MATRIX 2 -# see matrix1 for the explanaition -n2 <- nrow(mean.sd.cv.cor.mat2.obs) -if( ! identical(n1, n2)){ # important -tempo.cat <- paste0("\n\n================\n\nINTERNAL ERROR CODE IN SLITHERINE\nTHE TWO ROW NUMBERS OF OBS MAT1 AND MAT2 ARE DIFFERENT: ", paste(c(n1, n2), collapse = " "), "\n\n================\n\n") # message for developers -stop(tempo.cat) -} -mu2 <- sort(mean.sd.cv.cor.mat2.obs$MEAN, decreasing = TRUE, na.last = TRUE) # need the ordering to work on correlation (see below) -if(cv.rho.obtained == TRUE){ -# source(path.cv.rho) # inactivated because already done above -}else{ -rho2 <- mean.sd.cv.cor.mat2.obs$COR[order(mean.sd.cv.cor.mat2.obs$MEAN, decreasing = TRUE, na.last = TRUE)] -cv2 <- cv.select.mat2.obs # see above -} -if( ! identical(sort(rho1), sort(rho2))){ # important because rho1 will be modified, and rho2 kept as the initial correlation between obs mat1 and mat2 -tempo.cat <- paste0("\n\n================\n\nINTERNAL ERROR CODE IN SLITHERINE\nTHE TWO CORRELATIONS rho1 AND rho2 ARE NOT IDENTICAL\n\n================\n\n") # message for developers -stop(tempo.cat) -} -save(list = c("cv1", "rho1", "cv2", "rho2"), file = paste0(path.out, "/cv1_cv2_rho1_rho2_backup.RData")) -tempo.cat <- paste0("CORRELATIONS AND SELECTED COEFFICIENTS OF VARIATION SAVED IN: ", paste0(path.out, "/cv1_cv2_rho1_rho2_backup.RData")) -fun_report(data = tempo.cat, output = log.file, path = path.out) - -t2 <- 1 / cv2^2 # equation (1) -p2 <- exp(-t2 /mu2) # equation (8). Related to equation (9). In these equations, m cannot go below mt, but we do not care here for the correction -r2 <- t2 / p2 # equation (7) -sub.factor2 = t2 / ( mu2 * ( 1 - p2)) # equation (9), with mt = m2 (obs) and m = mean.nb2 (theo mean of NB). equation (9) / m2 -> t2 / ( mu2 * ( 1 - exp(-t2/mu2))) and sub.factor2 = m / mt, ie, sub.factor2 = mean.nb2 / m2. Thus, for the down sampling, to go back to m2, we will have to divide by sub.factor2 -mean.nb2 <- p2 * r2 / (1 - p2) # equation (2), just for graphs -sd.nb2 <- (p2 * r2 / (1 - p2)^2)^0.5 # equation (3), just for graphs -mat2.ini <- matrix(NA, nrow = n.row, ncol = n2) # each column of mat2.ini is filled with random values according to neg binom distrib, with mean increasing for each column of mat2.ini. n.row defined above -# solving the fact that when p is less than 1e-16, 1-p is rounded by R to 1, which results in prob = 1 in the rnbinom() function and only 0 returned -p2.rd <- p2 -r2.rd <- r2 -# cutoff.pb # defined above for Mat1 -if(any(p2.rd < cutoff.pb & p2.rd > 0)){ -cutoff.pos2 <- which.max(p2.rd < cutoff.pb & p2.rd > 0) - 1 -if(cutoff.pos2 == 0){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nCODE CANNOT WORK IF cutoff.pos2 IS EQUAL TO ZERO\n\n============\n\n") -fun_report(data = tempo.cat, output = log.file, path = path.out) -stop("\n", tempo.cat, "\n") -}else{ -r2.rd[p2.rd < cutoff.pb & p2.rd > 0] <- r2.rd[cutoff.pos2] # beware: must be before p2.rd -p2.rd[p2.rd < cutoff.pb & p2.rd > 0] <- p2.rd[cutoff.pos2] -} -} -# end solving the fact that when p is less than 1e-16, 1-p is rounded by R to 1, which results in prob = 1 in the rnbinom() function and only 0 returned -for(i1 in 1:length(mu2)){ -if( mu2[i1] != 0){ # otherwise cannot compute rnbinom() because p Infinite -mat2.ini[, i1] <- rnbinom(n = n.row, size = r2.rd[i1], prob = 1 - p2.rd[i1]) # because prob is the proba of success in R, while it is the proba of failure in the equation -}else{ -mean.nb2[i1] <- 0 -sd.nb2[i1] <- NA -mat2.ini[, i1] <- 0 -tempo.cat <- paste0("BEWARE: IN LOOP ", i1,", mu2 HAS A ZERO VALUE: NO NEG BINOM LAW USED -> MATRIX COLUMN FILLED WITH ZERO") -# cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -} -} -cv.nb2 <- sd.nb2 / mean.nb2 -options.ini <- options()$digits -options(digits = 22) -if(any((cv2^2 < 1/mean.nb2[ ! (is.na(mean.nb2) | ! is.finite(1 / mean.nb2))]) | (sapply(FUN = all.equal, 1/mean.nb2[ ! (is.na(mean.nb2) | ! is.finite(1 / mean.nb2))], cv2^2) == TRUE))){ # because we need sigma^2 > mean.nb2 for neg binom (otherwise, we have to use poisson) -# Then sigma^2 / mean.nb2^2 > mean.nb2 / mean.nb2^2 -> cv2^2 > 1/mean.nb2 -tempo.cat <- paste0("\n\n========\n\nPROBLEM: cv2 PARAMETER MUST BE SUCH THAT cv2^2 > 1/mean.nb2\ncv2 : ", cv2, "\ncv2^2 : ", cv2^2, "\nmean.nb2 VALUES DO NOT RESPECTING THE FORMULA (ZERO NOT CONSIDERED): ", paste(mean.nb2[ ! (is.na(mean.nb2) | ! is.finite(1 / mean.nb2))][cv2^2 <= 1/mean.nb2[ ! (is.na(mean.nb2) | ! is.finite(1 / mean.nb2))]], collapse = " "), "\n1/mean.nb2: ", paste(1 / mean.nb2[ ! (is.na(mean.nb2) | ! is.finite(1 / mean.nb2))][cv2^2 <= 1/mean.nb2[ ! (is.na(mean.nb2) | ! is.finite(1 / mean.nb2))]], collapse = " "), "\n\n========\n\n") -# cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -} -options(digits = options.ini) - - -################ End Theoretical matrices - - -################ plot verification - - -# homogeneous scale -# heatmap range -loop.mat.names <- c("mat1.ini", "mat2.ini") -heatmap.range2 <- NULL -for(i0 in 1:length(loop.mat.names)){ -# data transformtation -tempo.data.plot <- get(loop.mat.names[i0]) / mean(get(loop.mat.names[i0])[is.finite(get(loop.mat.names[i0]))], na.rm = TRUE) # mean normalization -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot + 1) # log transfo -} -# end data transformtation -heatmap.range2 <- range(c(heatmap.range, heatmap.range2, tempo.data.plot), na.rm = TRUE, finite = TRUE) -} -# end heatmap range -# sd homogeneous scale -tempo1 <- data.frame(MEAN = apply(X = mat1.ini, MARGIN = 2, FUN = "mean", na.rm = TRUE), SD = apply(mat1.ini, MARGIN = 2, FUN = "sd", na.rm = TRUE)) -tempo2 <- data.frame(MEAN = apply(X = mat2.ini, MARGIN = 2, FUN = "mean", na.rm = TRUE), SD = apply(mat2.ini, MARGIN = 2, FUN = "sd", na.rm = TRUE)) -tempo.range <- fun_gg_scatter(data1 = list(L1 = if(transfo != "no"){get(transfo)(tempo1)}else{tempo1}, L2 = if(transfo != "no"){get(transfo)(tempo2)}else{tempo2}), x = list(L1 = "MEAN", L2 = "MEAN"), y = list(L1 = "SD", L2 = "SD"), geom = list("geom_point", "geom_point"), alpha = list(0.5, 0.5), xlog = transfo, ylog = transfo, plot = FALSE, return = TRUE) -m_sd.x.range2 <- range(c(m_sd.x.range, tempo.range$axes$x.range), na.rm = TRUE, finite = TRUE) -m_sd.y.range2 <- range(c(m_sd.y.range, tempo.range$axes$y.range), na.rm = TRUE, finite = TRUE) -# end sd homogeneous scale -# cv homogeneous scale -tempo1 <- tempo1$SD / tempo1$MEAN -tempo2 <- tempo2$SD / tempo2$MEAN -m_cv.x.range2 <- range(c(m_cv.x.range, tempo1, tempo2), na.rm = TRUE, finite = TRUE) -m_cv.y.range2 <- range(c(m_cv.y.range, tempo1, tempo2), na.rm = TRUE, finite = TRUE) -# cor homogeneous scale -m_cor.x.range2 <- range(c(m_cor.x.range, m_cv.x.range2), na.rm = TRUE, finite = TRUE) # because same x-axis -m_cor.y.range2 <- m_cor.y.range # because same x-axis -# end cor homogeneous scale -# end sd homogeneous scale - -# MATRIX 1 -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "THEORETICAL MATRIX 1 DESIGN", text.size = 3) -# heatmap -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0("MAT1 THEO\nEACH COLUMN REPRESENTS A DIAGONAL OF MAT1 OBS (MAIN DIAG FULL OF ZERO INCLUDED)\n", if(transfo == "log2"){"LOG2(x + 1) "}else if(transfo == "log10"){"LOG10(x + 1) "}else{"NO "}, "TRANSFORMATION\nSCALE RANGE: ", paste(fun_round(heatmap.range2, 2), collapse = " , "), "\nNORMALIZED DISPLAY (GLOBAL MEAN DIVISION)") -tempo.data.plot <- mat1.ini / mean(mat1.ini[is.finite(mat1.ini)], na.rm = TRUE) # was not here before. I tried that -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot + 1) -} -fun_gg_heatmap(data1 = tempo.data.plot, legend.name = "", limit1 = c(min(heatmap.range2, na.rm = TRUE), max(heatmap.range2, na.rm = TRUE)), midpoint1 = mean(heatmap.range2, na.rm = TRUE), title = tempo.title, text.size = heatmap.text.size, title.text.size = title.text.size) -# end heatmap - -# Mean Deviation (MD) plot -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- data.frame(MEAN = apply(X = mat1.ini, MARGIN = 2, FUN = "mean", na.rm = TRUE), SD = apply(mat1.ini, MARGIN = 2, FUN = "sd", na.rm = TRUE)) -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot) # log(x + 1) only for heatmap -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN / 2, y.cv.pois = get(transfo)(1) - tempo.data.plot$MEAN / 2) # because poisson distrib is mean = variance, thus sd = mean ^0.5, ie each mean as x is square rooted for y and then x.MEAN / 2 because log2(mean^0.5) = 0.5 * log2(mean). For cv, cv = sd/m -> log(cv) = log(sd/m) = log(m/m^0.5) = log(1/m^0.5) = log(1) - log(m^0.5) = log(1) - log(m)/2 -tempo.data.negbinom <- data.frame(x.green = get(transfo)(mean.nb1), y.green = get(transfo)(cv.nb1 * mean.nb1)) # neg binomiale distrib -}else{ -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN^0.5, y.cv.pois = 1 / tempo.data.plot$MEAN^0.5) -tempo.data.negbinom <- data.frame(x.green = mean.nb1, y.green = cv.nb1 * mean.nb1) # neg binomiale distrib -} -tempo.title <- paste0("MAT1 THEO\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\nGREEN LINE: NEG BINOM DISTRIB") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, xlim = m_sd.x.range2, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_sd.y.range2, ylog = transfo, ylab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# end Mean Deviation (MD) plot of the observed matrix -# mean versus index plot -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- data.frame(MEAN = apply(X = mat1.ini, MARGIN = 2, FUN = "mean", na.rm = TRUE), MEAN.MINUS.SD = apply(X = mat1.ini, MARGIN = 2, FUN = "mean", na.rm = TRUE) - apply(mat1.ini, MARGIN = 2, FUN = "sd", na.rm = TRUE), MEAN.PLUS.SD = apply(X = mat1.ini, MARGIN = 2, FUN = "mean", na.rm = TRUE) + apply(mat1.ini, MARGIN = 2, FUN = "sd", na.rm = TRUE)) -if(transfo != "no"){ -tempo.data.plot <- suppressWarnings(get(transfo)(tempo.data.plot)) # log(x + 1) only for heatmap -if(any(is.na(tempo.data.plot$MEAN.MINUS.SD))){ -tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.data.plot$MEAN[is.na(tempo.data.plot$MEAN.MINUS.SD)] -} -} -tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) -tempo.title <- paste0("MAT1 THEO\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, xlog = "no", xlab = "COLUMN NB", x.tick.nb = 8, ylog = transfo, ylab = "MEAN", ylim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) -# end mean versus index plot - - -# MATRIX 2 -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "THEORETICAL MATRIX 2 DESIGN", text.size = 3) -# heatmap -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.title <- paste0("MAT2 THEO\nEACH COLUMN REPRESENTS A DIAGONAL OF MAT2 OBS (MAIN DIAG FULL OF ZERO INCLUDED)\n", if(transfo == "log2"){"LOG2(x + 1) "}else if(transfo == "log10"){"LOG10(x + 1) "}else{"NO "}, "TRANSFORMATION\nSCALE RANGE: ", paste(fun_round(heatmap.range2, 2), collapse = " , "), "\nNORMALIZED DISPLAY (GLOBAL MEAN DIVISION)") -tempo.data.plot <- mat2.ini / mean(mat2.ini[is.finite(mat2.ini)], na.rm = TRUE) # was not here before. I tried that -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot + 1) -} -fun_gg_heatmap(data1 = tempo.data.plot, legend.name = "", limit1 = c(min(heatmap.range2, na.rm = TRUE), max(heatmap.range2, na.rm = TRUE)), midpoint1 = mean(heatmap.range2, na.rm = TRUE), title = tempo.title, text.size = heatmap.text.size, title.text.size = title.text.size) -# end heatmap - -# Mean Deviation (MD) plot -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- data.frame(MEAN = apply(X = mat2.ini, MARGIN = 2, FUN = "mean", na.rm = TRUE), SD = apply(mat2.ini, MARGIN = 2, FUN = "sd", na.rm = TRUE)) -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot) # log(x + 1) only for heatmap -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN / 2, y.cv.pois = get(transfo)(1) - tempo.data.plot$MEAN / 2) # because poisson distrib is mean = variance, thus sd = mean ^0.5, ie each mean as x is square rooted for y and then x.MEAN / 2 because log2(mean^0.5) = 0.5 * log2(mean). For cv, cv = sd/m -> log(cv) = log(sd/m) = log(m/m^0.5) = log(1/m^0.5) = log(1) - log(m^0.5) = log(1) - log(m)/2 -tempo.data.negbinom <- data.frame(x.green = get(transfo)(mean.nb2), y.green = get(transfo)(cv.nb2 * mean.nb2)) # neg binomiale distrib -}else{ -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN^0.5, y.cv.pois = 1 / tempo.data.plot$MEAN^0.5) -tempo.data.negbinom <- data.frame(x.green = mean.nb2, y.green = cv.nb2 * mean.nb2) # neg binomiale distrib -} -tempo.title <- paste0("MAT2 THEO\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\nGREEN LINE: NEG BINOM DISTRIB") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, xlim = m_sd.x.range2, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_sd.y.range2, ylog = transfo, ylab = "SD", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# end Mean Deviation (MD) plot -# mean versus index plot -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- data.frame(MEAN = apply(X = mat2.ini, MARGIN = 2, FUN = "mean", na.rm = TRUE), MEAN.MINUS.SD = apply(X = mat2.ini, MARGIN = 2, FUN = "mean", na.rm = TRUE) - apply(mat2.ini, MARGIN = 2, FUN = "sd", na.rm = TRUE), MEAN.PLUS.SD = apply(X = mat2.ini, MARGIN = 2, FUN = "mean", na.rm = TRUE) + apply(mat2.ini, MARGIN = 2, FUN = "sd", na.rm = TRUE)) -if(transfo != "no"){ -tempo.data.plot <- suppressWarnings(get(transfo)(tempo.data.plot)) # log(x + 1) only for heatmap -if(any(is.na(tempo.data.plot$MEAN.MINUS.SD))){ -tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.data.plot$MEAN[is.na(tempo.data.plot$MEAN.MINUS.SD)] -} -} -tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) -tempo.title <- paste0("MAT2 THEO\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, xlog = "no", xlab = "COLUMN NB", x.tick.nb = 8, ylog = transfo, ylab = "MEAN", ylim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) -# end mean versus index plot - - -################ End plot verification - - -################ Taking correlation into account - - -cat("\nINCLUDING THE OBS MAT1 / MAT2 DIAGONAL CORRELATIONS INTO THEO MATRICES\n") -fun_report(data = "\n\n################################ INCLUDING THE OBS MAT1 / MAT2 DIAGONAL CORRELATIONS INTO THEO MATRICES", path = path.out, output = log.file, sep = 4) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "INCLUDING THE OBS\nMAT1 / MAT2\nDIAGONAL CORRELATIONS\nINTO THEO MATRICES", text.size = 3) -# mean / cor of the observed matrix -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- data.frame(MEAN = (mean.sd.cv.cor.mat1.obs$MEAN + mean.sd.cv.cor.mat2.obs$MEAN) / 2, COR = mean.sd.cv.cor.mat1.obs$COR) -if(transfo != "no"){ -tempo.data.plot[, "MEAN"] <- get(transfo)(tempo.data.plot[, "MEAN"]) # log(x + 1) only for heatmap -} -tempo.title <- paste0("(MAT1 OBS / MAT2 OBS) MEAN VERSUS (MAT1 OBS / MAT2 OBS) SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, xlim = m_cor.x.range2, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_cor.y.range2, ylog = "no", ylab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# end mean / cor of the observed matrix -# mean / cor of the theoretical matrices -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- suppressWarnings(data.frame(MEAN = (apply(X = mat1.ini, MARGIN = 2, FUN = "mean") + apply(X = mat2.ini, MARGIN = 2, FUN = "mean")) / 2, COR = mapply(FUN = "cor", x = as.data.frame(mat1.ini), y = as.data.frame(mat2.ini), use = "pairwise.complete.obs", method = "spearman", SIMPLIFY = TRUE))) -if(transfo != "no"){ -tempo.data.plot[, "MEAN"] <- get(transfo)(tempo.data.plot[, "MEAN"]) # log(x + 1) only for heatmap -} -tempo.title <- paste0("(MAT1 THEO / MAT2 THEO) MEAN VERSUS (MAT1 THEO / MAT2 THEO) SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, xlim = m_cor.x.range2, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_cor.y.range2, ylog = "no", ylab = "CORRELATION", y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# Permutation of the mat1.ini values to have the mat1.obs correlation on the diagonales between mat1 and mat2 -if(correl.mat.obtained == TRUE){ -tempo.cat <- paste0("BEWARE: mat1.ini, mat1.perm, mat2.ini and mat2.perm THERORETICAL MATRICES USED HAVE BEEN DOWNLOADED FROM:\n", path.theo1.theo2) -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -load(paste0(path.theo1.theo2)) -}else{ -if(any(is.na(mat1.ini))){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nSHOULD NOT HAVE ANY NA IN mat1.ini\n\n============\n\n") -cat(tempo.cat) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -} -if(any(is.na(mat2.ini))){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nSHOULD NOT HAVE ANY NA IN mat2.ini\n\n============\n\n") -cat(tempo.cat) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -} -mat1.perm <- mat1.ini -mat2.perm <- mat2.ini -# modifiying rho1 -if(single.corr == "VALUE"){ # all the observed corr between mat1.obs and mat2.obs replaced by abs.corr.limit -rho1[ ! is.na(rho1)] <- abs.corr.limit -tempo.cat <- paste0("BEWARE: ALL THE OBSERVED CORRELATIONS BETWEEN mat1.obs AND mat2.obs REPLACED BY abs.corr.limit") -fun_report(data = tempo.cat, output = log.file, path = path.out) -}else if(single.corr == "MAX"){ -rho1[ ! is.na(rho1)] <- max(rho1, na.rm = TRUE) -tempo.cat <- paste0("BEWARE: ALL THE OBSERVED CORRELATIONS BETWEEN mat1.obs AND mat2.obs REPLACED BY MAX CORRELATION OF rho1: ", max(rho1, na.rm = TRUE)) -fun_report(data = tempo.cat, output = log.file, path = path.out) -}else if(single.corr == "DEC1"){ -rho1[ ! is.na(rho1)] <- quantile(rho1, probs = 0.1, type = 7, na.rm = TRUE) -tempo.cat <- paste0("BEWARE: ALL THE OBSERVED CORRELATIONS BETWEEN mat1.obs AND mat2.obs REPLACED BY FIRST DECILE CORRELATION OF rho1: ", quantile(rho1, probs = 0.1, type = 7, na.rm = TRUE)) -fun_report(data = tempo.cat, output = log.file, path = path.out) -}else if(single.corr == "QUART1"){ -rho1[ ! is.na(rho1)] <- quantile(rho1, probs = 0.25, type = 7, na.rm = TRUE) -tempo.cat <- paste0("BEWARE: ALL THE OBSERVED CORRELATIONS BETWEEN mat1.obs AND mat2.obs REPLACED BY FIRST QUARTILE CORRELATION OF rho1: ", quantile(rho1, probs = 0.25, type = 7, na.rm = TRUE)) -fun_report(data = tempo.cat, output = log.file, path = path.out) -}else if(single.corr == "MED"){ -rho1[ ! is.na(rho1)] <- median(rho1, na.rm = TRUE) -tempo.cat <- paste0("BEWARE: ALL THE OBSERVED CORRELATIONS BETWEEN mat1.obs AND mat2.obs REPLACED BY THE MEDIAN CORRELATION OF rho1: ", median(rho1, na.rm = TRUE)) -fun_report(data = tempo.cat, output = log.file, path = path.out) -}else if(single.corr == "MIN"){ -rho1[ ! is.na(rho1)] <- min(rho1, na.rm = TRUE) -tempo.cat <- paste0("BEWARE: ALL THE OBSERVED CORRELATIONS BETWEEN mat1.obs AND mat2.obs REPLACED BY MIN CORRELATION OF rho1: ", min(rho1, na.rm = TRUE)) -fun_report(data = tempo.cat, output = log.file, path = path.out) -}else if(single.corr == "NO"){ -tempo.cat <- paste0("BEWARE: ALL THE OBSERVED CORRELATIONS BETWEEN mat1.obs AND mat2.obs WILL BE USED FOR THE PERMUTATIONS, EXCEPT THOSE BELOW abs.corr.limit: ", abs.corr.limit) -fun_report(data = tempo.cat, output = log.file, path = path.out) -}else{ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\n\n============\n\n") -fun_report(data = tempo.cat, output = log.file, path = path.out) -stop("\n", tempo.cat, "\n") -} -# end modifiying rho1 -# sorting mat1 according to the rho1 values -for(i0 in 1:ncol(mat1.perm)){ -if(is.na(rho1[i0])){ -if( ! all(mat1.perm[, i0] == 0 )){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nrho1 IS NA AND COLUMN ", i0, " OF mat1.perm IS NOT ZERO FOR LOOP:", i0, "\n\n============\n\n") -cat(tempo.cat) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -} -}else if(any(is.na(mat1.perm[, i0]))){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nSHOULD NOT HAVE NA IN COLUMN ", i0, " OF mat1.perm\n\n============\n\n") -cat(tempo.cat) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -}else if(rho1[i0] < 0){ -mat1.perm[, i0] <- sort(mat1.perm[, i0], decreasing = TRUE) # Beware: decreasing order here because we want a negative correlation with mat2[, i0] starting at -1, and increasing during permut -}else if(rho1[i0] >= 0){ -mat1.perm[, i0] <- sort(mat1.perm[, i0], decreasing = FALSE) # Beware: increasing order here because we want a positive correlation with mat2[, i0] starting at 1, and decreasing during permut -}else{ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\n\n============\n\n") -cat(tempo.cat) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -} -} -# end sorting mat1 according to the rho1 values -# sorting mat2.perm systematically in the ascending order -for(i0 in 1:ncol(mat2.perm)){ -if(is.na(rho2[i0])){ -if( ! all(mat2.perm[, i0] == 0 )){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nrho2 IS NA AND COLUMN ", i0, " OF mat2.perm IS NOT ZERO FOR LOOP:", i0, "\n\n============\n\n") -cat(tempo.cat) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -} -}else if(any(is.na(mat2.perm[, i0]))){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nSHOULD NOT HAVE NA IN COLUMN ", i0, " OF mat2.perm\n\n============\n\n") -cat(tempo.cat) -stop() -# fun_report(data = tempo.cat, output = log.file, path = path.out) -}else{ -mat2.perm[, i0] <- sort(mat2.perm[, i0], decreasing = FALSE) -} -} -# end sorting mat2.perm systematically in the ascending order -# parallelization -perm.ini.date <- Sys.time() # time of process begin, converted into seconds -perm.ini.time <- as.numeric(perm.ini.date) # time of process begin, converted into seconds -tempo.cat <- paste0("PERMUTATION RUN INITIATED ON THEO MATRICES (DIMENSION ", paste(dim(mat1.perm), collapse = " x "), ") AT: ", perm.ini.date) -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -tempo.thread.nb = parallel::detectCores(all.tests = FALSE, logical = TRUE) # detect the number of threads -if(is.null(thread.nb)){ -thread.nb <- tempo.thread.nb - 1 -}else if(tempo.thread.nb < thread.nb){ -thread.nb <- tempo.thread.nb -} -tempo.cat <- paste0("NUMBER OF THREADS USED: ", thread.nb) -cat(paste0("\n ", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -# trick to correctly dispatch the amount of work per cpu -pos.rho1.decrease <- order(rho1, decreasing = TRUE, na.last = NA) # remove the NA positions -tempo.list <- vector("list", thread.nb) # will contain a good repartition of the higher corr per cpu -count <- 0 -for(i0 in 1:length(pos.rho1.decrease)){ -count <- count + 1 -tempo.list[[count]] <- c(tempo.list[[count]], pos.rho1.decrease[i0]) -if(count == thread.nb){ -count <- 0 -} -} -tempo.list <- unlist(tempo.list) -# end trick to correctly dispatch the amount of work per cpu -Clust <- parallel::makeCluster(thread.nb, outfile = paste0(path.out, "/cor_parall_log.txt")) # outfile to print or cat during parallelization (only possible in a file, outfile = "" do not work on windowsâ—‹) -tempo.cat <- paste0("COLUMN NUMBER SPLIT FOR PARALLELISATION") -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = parallel::clusterSplit(Clust, tempo.list), output = log.file, path = path.out) -paral.output.list <- parallel::clusterApply( # paral.output.list is a list made of thread.nb compartments, each made of n / thread.nb (mat theo column number) compartment. Each compartment receive the corresponding results of fun_permut(), i.e., data (permuted mat1.perm), warning message, cor (final correlation) and count (number of permutations) -cl = Clust, -x = parallel::clusterSplit(Clust, tempo.list), # split 1:ncol(mat1.perm) vector according to the number of cluster and put into x for each cpu. Allow to take only the column of mat1.perm with no NA corr -rho1 = rho1, -mat1.perm = mat1.perm, -mat2.perm = mat2.perm, -count.print = count.print, -# very important because another R -path.function1 = path.function1, -req.package.list = req.package.list, -path.lib = path.lib, -req.python.package.list = req.python.package.list, -path.python.lib = path.python.lib, -# end very important because another R -fun = function(x, mat1.perm, mat2.perm, rho1, count.print, path.function1, req.package.list, path.lib, req.python.package.list, path.python.lib){ -# check again: very important because another R -source(path.function1) -fun_pack(req.package = req.package.list, path.lib = path.lib, load = TRUE) # load = TRUE to be sure that functions are present in the environment. And this prevent to use R.path.lib argument of fun_python_pack() -# end check again: very important because another R -output <- vector("list", length(x)) -names(output) <- as.character(x) # paste0("V", x) -# see also Protocol 100-rev0 Parallelization in R.docx -if(exists(".Random.seed", envir = .GlobalEnv)){ # if .Random.seed does not exists, it means that no random operation has been performed yet in any R environment -tempo.random.seed <- .Random.seed -on.exit(assign(".Random.seed", tempo.random.seed, env = .GlobalEnv)) -}else{ -on.exit(set.seed(NULL)) # inactivate seeding -> return to complete randomness -} -for(i0 in 1:length(x)){ -if(i0 == 1){ -set.seed(x[i0]) # take the first number of x for seed, which is different for each parallelization -} -tempo.cor <- suppressWarnings(cor(mat1.perm[, x[i0]], mat2.perm[, x[i0]], use = "pairwise.complete.obs", method = "spearman")) -if(length(table(mat1.perm[, x[i0]])) == 1){ -output[[i0]] <- list(data = mat1.perm[, x[i0]], warnings = paste0("NO PERMUTATION PERFORMED BECAUSE MAT1 MADE OF IDENTICAL ELEMENTS: ", names(table(mat1.perm[, x[i0]]))), cor = NA, count = 0) -}else if(length(table(mat2.perm[, x[i0]])) == 1){ -output[[i0]] <- list(data = mat1.perm[, x[i0]], warnings = paste0("NO PERMUTATION PERFORMED BECAUSE MAT2 MADE OF IDENTICAL ELEMENTS: ", names(table(mat2.perm[, x[i0]]))), cor = NA, count = 0) -}else if(tempo.cor <= rho1[x[i0]]){ -output[[i0]] <- list(data = mat1.perm[, x[i0]], warnings = paste0("NO PERMUTATION PERFORMED BECAUSE THE ABSOLUTE VALUE OF THE CORRELATION ", fun_round(tempo.cor), " BETWEEN MAT1 AND MAT2 HAS BEEN DETECTED AS BELOW THE CORRELATION LIMIT PARAMETER ", fun_round(rho1[x[i0]])), cor = tempo.cor, count = 0) -}else{ -output[[i0]] <- fun_permut(data1 = mat1.perm[, x[i0]], data2 = mat2.perm[, x[i0]], seed = NULL, text.print = paste0("DIAG NB ", x[i0]), count.print = count.print, cor.method = "spearman", cor.limit = rho1[x[i0]]) # with seed = NULL, take the global random seed that already exist because set above -} -} -return(output) -} -) -parallel::stopCluster(Clust) -tempo.date <- Sys.time() -tempo.time <- as.numeric(tempo.date) -tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - perm.ini.time)) -tempo.cat <- paste0("PERMUTATION RUN ON THEO MATRICES ACHIEVED AT: ", tempo.date, " | TIME LAPSE: ", tempo.lapse) -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -# end parallelization -# recover the results -permut.list <- vector("list", ncol(mat1.perm)) # list containing all the columns of mat.perm permuted -warning.list <- vector("list", ncol(mat1.perm)) # list containing the corresponding warnings messages -cor.list <- vector("list", ncol(mat1.perm)) # list containing the corresponding final correlations -count.list <- vector("list", ncol(mat1.perm)) # list containing the corresponding permutation count -# BEWARE: erratic situations when NULL is assigned to a list. See https://stackoverflow.com/questions/7944809/assigning-null-to-a-list-element-in-r -for(i0 in 1:length(paral.output.list)){ # compartment relatives to each parallelization -for(i1 in 1:length(paral.output.list[[i0]])){ # compartment relatives to each diagonal inside parallelization -permut.list[[as.integer(names(paral.output.list[[i0]])[i1])]] <- paral.output.list[[i0]][[i1]]$data -names(permut.list)[as.integer(names(paral.output.list[[i0]])[i1])] <- names(paral.output.list[[i0]])[i1] -warning.list[[as.integer(names(paral.output.list[[i0]])[i1])]] <- if(is.null(paral.output.list[[i0]][[i1]]$warnings)){"NO WARNING"}else{paral.output.list[[i0]][[i1]]$warnings} # no NULL assignation in list -names(warning.list)[as.integer(names(paral.output.list[[i0]])[i1])] <- names(paral.output.list[[i0]])[i1] -cor.list[[as.integer(names(paral.output.list[[i0]])[i1])]] <- paral.output.list[[i0]][[i1]]$cor -names(cor.list)[as.integer(names(paral.output.list[[i0]])[i1])] <- names(paral.output.list[[i0]])[i1] -count.list[[as.integer(names(paral.output.list[[i0]])[i1])]] <- paral.output.list[[i0]][[i1]]$count -names(count.list)[as.integer(names(paral.output.list[[i0]])[i1])] <- names(paral.output.list[[i0]])[i1] -} -} -if( ! identical(as.integer(names(permut.list)), sort(unlist(parallel::clusterSplit(Clust, tempo.list))))){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nnames(permut.list) AND sort(unlist(parallel::clusterSplit(Clust, tempo.list))) SHOULD BE IDENTICAL\n\n============\n\n") -fun_report(data = tempo.cat, output = log.file, path = path.out) -stop("\n", tempo.cat, "\n") -} -if( ! identical(names(permut.list), names(warning.list))){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nnames(permut.list) AND names(warning.list) SHOULD BE IDENTICAL\n\n============\n\n") -fun_report(data = tempo.cat, output = log.file, path = path.out) -stop("\n", tempo.cat, "\n") -} -if( ! identical(names(permut.list), names(cor.list))){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nnames(permut.list) AND names(cor.list) SHOULD BE IDENTICAL\n\n============\n\n") -fun_report(data = tempo.cat, output = log.file, path = path.out) -stop("\n", tempo.cat, "\n") -} -if( ! identical(names(permut.list), names(count.list))){ -tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nnames(permut.list) AND names(count.list) SHOULD BE IDENTICAL\n\n============\n\n") -fun_report(data = tempo.cat, output = log.file, path = path.out) -stop("\n", tempo.cat, "\n") -} -# end recover the results -# result print -tempo.cat <- paste0("THE CORRELATION THRESHOLD SET FOR THE PERMUTATION STEP IS: ", paste(fun_round(as.numeric(names(table(rho1)))), collapse = " ")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -tempo.cat <- paste0("THE FINAL CORRELATION BETWEEN THE COLUMNS OF MAT THEO 1 AND 2 (OBS CORRESPONDING DIAGONAL CORRELATION) ARE:\nCOLUMN\tCORR\n", paste(names(cor.list), fun_round(unlist(cor.list)), sep = "\t", collapse = "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -tempo.cat <- paste0("THE ASSOCIATED WARNING MESSAGES FROM THE fun_permut() FUNCTION ARE:\n", paste("COLUMN NB ", names(unlist(warning.list)), ": ", unlist(warning.list), collapse = "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_open(pdf.disp = TRUE, path.fun = path.out, pdf.name.file = paste0("correlation_plots_", analysis.nb), width.fun = width.wind, height.fun = height.wind) -tempo.max <- max(as.integer(names(permut.list)), na.rm = TRUE) -if(tempo.max > 40){ -cor.print.loop <- c(1:20, (tempo.max - 19):tempo.max) -tempo.max <- 40 -tempo.cat <- paste0("ONLY THE 20 FIRST AND 20 LAST DIAGONALS ARE PLOTTED IN THE correlation_plots.pdf FILE") -fun_report(data = tempo.cat, output = log.file, path = path.out) -}else{ -cor.print.loop <- 1:tempo.max -} -count.loop <- 0 -for(i0 in cor.print.loop){ -count.loop <- count.loop + 1 -tempo.data.plot <- data.frame(MAT1 = mat1.perm[, i0], MAT2 = mat2.perm[, i0]) -x.tempo.range <- range(tempo.data.plot[, "MAT1"], na.rm = TRUE, finite = TRUE) -y.tempo.range <- range(tempo.data.plot[, "MAT2"], na.rm = TRUE, finite = TRUE) -tempo.cor <- suppressWarnings(cor(x = tempo.data.plot[, "MAT1"], y = tempo.data.plot[, "MAT2"], use = "pairwise.complete.obs", method = "spearman")) -tempo.title <- paste0("BEFORE PERMUTATION | (MAT1 THEO / MAT2 THEO) SPEARMAN CORRELATION\nOBS MATRIX CORRESPONDING DIAGONAL NUMBER: ", i0, "\nCORRELATION VALUE: ", if(is.na(tempo.cor)){NA}else{fun_round(tempo.cor)}, "\nX SCALE RANGE: ", paste(fun_round(x.tempo.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(y.tempo.range, 2), collapse = " , ")) -# fun_prior_plot(param.reinitial = FALSE, xlog.scale = FALSE, ylog.scale = FALSE, remove.label = TRUE, remove.x.axis = TRUE, remove.y.axis = TRUE, std.x.range = FALSE, std.y.range = FALSE, down.space = height.wind / 7 * 1, left.space = width.wind / 7 * 1, up.space = height.wind / 7 * 1, right.space = width.wind / 7 * 1, orient = 1, dist.legend = 5, tick.length = 0.5, box.type = "n", amplif.label = 1, amplif.axis = 1, display.extend = FALSE, return.par = FALSE) -# plot(tempo.data.plot[, "MAT1"], tempo.data.plot[, "MAT2"], col = hsv(0, 0, 0.5, 0.5), pch = 16, xlim = if(diff(x.tempo.range) == 0){c(unique(x.tempo.range) - 1, unique(x.tempo.range) + 1)}else{x.tempo.range}, ylim = if(diff(y.tempo.range) == 0){c(unique(y.tempo.range) - 1, unique(y.tempo.range) + 1)}else{y.tempo.range}) -# tempo.coord <- fun_post_plot(x.side = 1, x.lab = "MAT1", y.side = 2, y.lab = "MAT2", x.axis.magnific = 1, x.label.magnific = 1, y.axis.magnific = 1, y.label.magnific = 1) -# par(xpd = TRUE) -# text(x = tempo.coord$x.left.plot.region, y = tempo.coord$y.top.fig.region, labels = tempo.title, cex = 0.65, adj = c(0, 1)) -# par(xpd = FALSE) -fun_gg_scatter(data1 = tempo.data.plot, x = "MAT1", y = "MAT2", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, xlim = if(diff(x.tempo.range) == 0){c(unique(x.tempo.range) - 1, unique(x.tempo.range) + 1)}else{x.tempo.range}, x.tick.nb = 8, ylim = if(diff(y.tempo.range) == 0){c(unique(y.tempo.range) - 1, unique(y.tempo.range) + 1)}else{y.tempo.range}, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = FALSE) -tempo.data.plot <- data.frame(MAT1 = permut.list[[i0]], MAT2 = mat2.perm[, i0]) -x.tempo.range <- range(tempo.data.plot[, "MAT1"], na.rm = TRUE, finite = TRUE) -y.tempo.range <- range(tempo.data.plot[, "MAT2"], na.rm = TRUE, finite = TRUE) -tempo.cor <- suppressWarnings(cor(x = tempo.data.plot[, "MAT1"], y = tempo.data.plot[, "MAT2"], use = "pairwise.complete.obs", method = "spearman")) -tempo.title <- paste0("AFTER PERMUTATION | (MAT1 THEO / MAT2 THEO) SPEARMAN CORRELATION\nOBS MATRIX CORRESPONDING DIAGONAL NUMBER: ", i0, "\nCORRELATION VALUE: ", if(is.na(tempo.cor)){NA}else{fun_round(tempo.cor)}, "\nCORRELATION INDICATED BY THE fun_permut() FUNCTION: ", if(is.na(cor.list[[i0]])){NA}else{fun_round(cor.list[[i0]])}, "\nX SCALE RANGE: ", paste(fun_round(x.tempo.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(y.tempo.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MAT1", y = "MAT2", color = fun_gg_palette(1), geom = "geom_point", alpha = 0.5, dot.size = dot.size, xlim = if(diff(x.tempo.range) == 0){c(unique(x.tempo.range) - 1, unique(x.tempo.range) + 1)}else{x.tempo.range}, x.tick.nb = 8, ylim = if(diff(y.tempo.range) == 0){c(unique(y.tempo.range) - 1, unique(y.tempo.range) + 1)}else{y.tempo.range}, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = FALSE) -# fun_prior_plot(param.reinitial = FALSE, xlog.scale = FALSE, ylog.scale = FALSE, remove.label = TRUE, remove.x.axis = TRUE, remove.y.axis = TRUE, std.x.range = FALSE, std.y.range = FALSE, down.space = height.wind / 7 * 1, left.space = width.wind / 7 * 1, up.space = height.wind / 7 * 1, right.space = width.wind / 7 * 1, orient = 1, dist.legend = 5, tick.length = 0.5, box.type = "n", amplif.label = 1, amplif.axis = 1, display.extend = FALSE, return.par = FALSE) -# plot(tempo.data.plot[, "MAT1"], tempo.data.plot[, "MAT2"], col = hsv(1, 0.5, 1, 0.5), pch = 16, xlim = if(diff(x.tempo.range) == 0){c(unique(x.tempo.range) - 1, unique(x.tempo.range) + 1)}else{x.tempo.range}, ylim = if(diff(y.tempo.range) == 0){c(unique(y.tempo.range) - 1, unique(y.tempo.range) + 1)}else{y.tempo.range}) -# tempo.coord <- fun_post_plot(x.side = 1, x.lab = "MAT1", y.side = 2, y.lab = "MAT2", x.axis.magnific = 1, x.label.magnific = 1, y.axis.magnific = 1, y.label.magnific = 1) -# par(xpd = TRUE) -# text(x = tempo.coord$x.left.plot.region, y = tempo.coord$y.top.fig.region, labels = tempo.title, cex = 0.65, adj = c(0, 1)) -# par(xpd = FALSE) -cat(paste0("\nPRINT CORR GRAPH NB ", count.loop, " / ", tempo.max, " (DIAG NB ", i0, ")")) -} -cat("\n") -dev.off() -# end result print -# mat1.perm filling -for(i0 in 1:ncol(mat1.perm)){ -mat1.perm[, i0] <- permut.list[[i0]] # final permutation of the values using the permuted positions -} -# end mat1.perm filling -} -if(keep == FALSE){ -tempo.list <- c("mat1.ini", "mat1.perm", "mat2.ini", "mat2.perm") -tempo.cat <- paste0("INITIAL AND PERMUTED THEO MATRICES SAVED IN: ", paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -save(list = tempo.list, file = paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -rm(list = c("mat1.ini", "mat2.ini")) # .perm still needed -} -# end Permutation of the mat1.ini values to have the mat1.obs correlation on the diagonales between mat1 and mat2 -# mean / cor of the theoretical matrices -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- suppressWarnings(data.frame(MEAN = (apply(X = mat1.perm, MARGIN = 2, FUN = "mean") + apply(X = mat2.perm, MARGIN = 2, FUN = "mean")) / 2, COR = mapply(FUN = "cor", x = as.data.frame(mat1.perm), y = as.data.frame(mat2.perm), use = "pairwise.complete.obs", method = "spearman", SIMPLIFY = TRUE))) -if(transfo != "no"){ -tempo.data.plot[, "MEAN"] <- get(transfo)(tempo.data.plot[, "MEAN"]) # log(x + 1) only for heatmap -} -tempo.title <- paste0("AFTER PERMUTATION\n(MAT1 THEO / MAT2 THEO) MEAN VERSUS (MAT1 THEO / MAT2 THEO) SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, xlim = m_cor.x.range2, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_cor.y.range2, ylog = "no", ylab = "CORRELATION",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# end mean / cor of the theoretical matrices -# correlation versus index before and after permutation -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -if(length(rho2) != length(unlist(cor.list))){ # important because rho1 will be modified, and rho2 kept as the initial correlation between obs mat1 and mat2 -tempo.cat <- paste0("\n\n================\n\nINTERNAL ERROR CODE IN SLITHERINE\nTHE TWO CORRELATIONS rho2 AND cor.list DO NOT HAVE THE SAME LENGTH\n\n================\n\n") # message for developers -stop(tempo.cat) -} -tempo.data.plot <- data.frame(CORRELATION = c(rho2, unlist(cor.list)), COLUMN_NB = c(1:length(rho2), 1:length(rho2)), KIND = rep(c("OBS", "THEO"), each = length(rho2))) -tempo.title <- paste0("SPEARMAN CORRELATION BETWEEN MAT1 OBS / MAT2 OBS\nCOMPARISON WITH MAT1 THEO / MAT2 THEO AFTER PERMUTATION\nX SCALE RANGE: ", paste(range(1:length(rho2), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: -1, 1") -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("CORRELATION"), categ = list("KIND"), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, xlog = "no", xlab = "DIAGONAL INDEX", x.tick.nb = 8, ylog = "no", ylab = "CORRELATION", ylim = c(-1, 1), y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster) -# end correlation versus index before and after permutation - - -################ End Taking correlation into account - - -################ sub sampling - - -cat("\nTHEO MATRICES SUBSAMPLING\n") -fun_report(data = "\n\n################################ THEO MATRICES SUBSAMPLING", path = path.out, output = log.file, sep = 4) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "THEO MATRICES\nSUBSAMPLING", text.size = 3) - - -# theoretical matrix subsampling (this allow to have smaller values on the mean x of the MD plot) -# division of the coverage in each cell of column i0 of theo mat by sub.factor1[i0] (reduction of the coverage), and then random sampling of one value considering that the coverage is a mean coverage of the poisson law (is poisson law, lamnda = mean = variance). Thus, sapply(lambda, FUN = rpois, n = 1) -mat1.down <- mat1.perm -for(i0 in 1:ncol(mat1.down)){ -if( ! all(is.na(mat1.down[, i0]))){ -mat1.down[, i0] <- sapply(mat1.down[, i0] / sub.factor1[i0], FUN = rpois, n = 1) -} -} -mat2.down <- mat2.perm -for(i0 in 1:ncol(mat2.down)){ -if( ! all(is.na(mat2.down[, i0]))){ -mat2.down[, i0] <- sapply(mat2.down[, i0] / sub.factor2[i0], FUN = rpois, n = 1) -} -} -# randomize the mat1.down row values in each column, to break the order in the first matrix, and use the same row order in mat2.down before using serpentine to keep the correlation between columns intact -# In fact, change nothing to shuffle or not -if(nrow(mat1.down) > 1){ -shuffled.row.pos <- sample(x = 1:nrow(mat1.down), size = nrow(mat1.down), replace = FALSE) -}else{ -stop("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nA SINGLE DIAGONAL PRESENT IN THEO MATRIX 1 (mat1.down)\n\n============\n\n") -} -# shuffling the rows of mat1.down and mat2.down (same repositionning for both matrix, to keep the relationship between rows (correlation)) -mat1.mix <- mat1.down[shuffled.row.pos, ] -mat2.mix <- mat2.down[shuffled.row.pos, ] -if(keep == FALSE){ -tempo.list <- c("mat1.down", "mat2.down") -tempo.cat <- paste0("DOWNSAMPLED THEO MATRICES SAVED IN: ", paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -save(list = tempo.list, file = paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -rm(list = tempo.list) # not saved because initial matrices -} -# export of theo matrices before binning -loop.mat.names <- c("mat1.mix", "mat2.mix") -for(i0 in 1:length(loop.mat.names)){ -write.table(get(loop.mat.names[i0]), file = paste0(path.out, "/mat", i0, "theo.txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -} -# end export of theo matrices before binning -# end theoretical matrix subsampling (this allow to have smaller values on the mean x of the MD plot) - - -# mean versus index plot before sub sampling -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- data.frame(MEAN = apply(X = mat1.perm, MARGIN = 2, FUN = "mean", na.rm = TRUE), MEAN.MINUS.SD = apply(X = mat1.perm, MARGIN = 2, FUN = "mean", na.rm = TRUE) - apply(mat1.perm, MARGIN = 2, FUN = "sd", na.rm = TRUE), MEAN.PLUS.SD = apply(X = mat1.perm, MARGIN = 2, FUN = "mean", na.rm = TRUE) + apply(mat1.perm, MARGIN = 2, FUN = "sd", na.rm = TRUE)) -if(transfo != "no"){ -tempo.data.plot <- suppressWarnings(get(transfo)(tempo.data.plot)) # log(x + 1) only for heatmap -if(any(is.na(tempo.data.plot$MEAN.MINUS.SD))){ -tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.data.plot$MEAN[is.na(tempo.data.plot$MEAN.MINUS.SD)] -} -} -tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) -tempo.title <- paste0("MAT1 THEO\nAFTER PERMUTATION AND BEFORE SUB SAMPLING\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, xlog = "no", xlab = "COLUMN NB", x.tick.nb = 8, ylog = transfo, ylab = "MEAN", ylim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- data.frame(MEAN = apply(X = mat2.perm, MARGIN = 2, FUN = "mean", na.rm = TRUE), MEAN.MINUS.SD = apply(X = mat2.perm, MARGIN = 2, FUN = "mean", na.rm = TRUE) - apply(mat2.perm, MARGIN = 2, FUN = "sd", na.rm = TRUE), MEAN.PLUS.SD = apply(X = mat2.perm, MARGIN = 2, FUN = "mean", na.rm = TRUE) + apply(mat2.perm, MARGIN = 2, FUN = "sd", na.rm = TRUE)) -if(transfo != "no"){ -tempo.data.plot <- suppressWarnings(get(transfo)(tempo.data.plot)) # log(x + 1) only for heatmap -if(any(is.na(tempo.data.plot$MEAN.MINUS.SD))){ -tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.data.plot$MEAN[is.na(tempo.data.plot$MEAN.MINUS.SD)] -} -} -tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) -tempo.title <- paste0("MAT2 THEO\nAFTER PERMUTATION AND BEFORE SUB SAMPLING\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, xlog = "no", xlab = "COLUMN NB", x.tick.nb = 8, ylog = transfo, ylab = "MEAN", ylim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) -# end mean versus index plot before sub sampling -if(keep == FALSE){ -tempo.list <- c("mat1.perm", "mat2.perm") -# save(list = tempo.list, file = paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) # not saved here because already saved before -rm(list = tempo.list) # not saved because initial matrices -} -# mean versus index plot after sub sampling -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- data.frame(MEAN = apply(X = mat1.mix, MARGIN = 2, FUN = "mean", na.rm = TRUE), MEAN.MINUS.SD = apply(X = mat1.mix, MARGIN = 2, FUN = "mean", na.rm = TRUE) - apply(mat1.mix, MARGIN = 2, FUN = "sd", na.rm = TRUE), MEAN.PLUS.SD = apply(X = mat1.mix, MARGIN = 2, FUN = "mean", na.rm = TRUE) + apply(mat1.mix, MARGIN = 2, FUN = "sd", na.rm = TRUE)) -if(transfo != "no"){ -tempo.data.plot <- suppressWarnings(get(transfo)(tempo.data.plot)) # log(x + 1) only for heatmap -if(any(is.na(tempo.data.plot$MEAN.MINUS.SD))){ -tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.data.plot$MEAN[is.na(tempo.data.plot$MEAN.MINUS.SD)] -} -} -tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) -tempo.title <- paste0("MAT1 THEO\nAFTER PERMUTATION AND AFTER SUB SAMPLING\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, xlog = "no", xlab = "COLUMN NB", x.tick.nb = 8, ylog = transfo, ylab = "MEAN", ylim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- data.frame(MEAN = apply(X = mat2.mix, MARGIN = 2, FUN = "mean", na.rm = TRUE), MEAN.MINUS.SD = apply(X = mat2.mix, MARGIN = 2, FUN = "mean", na.rm = TRUE) - apply(mat2.mix, MARGIN = 2, FUN = "sd", na.rm = TRUE), MEAN.PLUS.SD = apply(X = mat2.mix, MARGIN = 2, FUN = "mean", na.rm = TRUE) + apply(mat2.mix, MARGIN = 2, FUN = "sd", na.rm = TRUE)) -if(transfo != "no"){ -tempo.data.plot <- suppressWarnings(get(transfo)(tempo.data.plot)) # log(x + 1) only for heatmap -if(any(is.na(tempo.data.plot$MEAN.MINUS.SD))){ -tempo.data.plot$MEAN.MINUS.SD[is.na(tempo.data.plot$MEAN.MINUS.SD)] <- tempo.data.plot$MEAN[is.na(tempo.data.plot$MEAN.MINUS.SD)] -} -} -tempo.data.plot <- data.frame(COLUMN_NB = 1:nrow(tempo.data.plot), tempo.data.plot) -tempo.title <- paste0("MAT2 THEO\nAFTER PERMUTATION AND AFTER SUB SAMPLING\nMEAN PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x)\nABSENT SD IF LOG2(M - SD) < 0 "}else if(transfo == "log10"){"MEAN AND SD LOG10(x)\nABSENT SD IF LOG10(M - SD) < 0 "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(range(1:nrow(tempo.data.plot), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("MEAN"), color = list(grey(0.40)), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, xlog = "no", xlab = "COLUMN NB", x.tick.nb = 8, ylog = transfo, ylab = "MEAN", ylim = m_sd.y.range2, y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, add = paste0('+ ggplot2::geom_segment(data = data.frame(x = tempo.data.plot$COLUMN_NB, xend = tempo.data.plot$COLUMN_NB, y = tempo.data.plot$MEAN.MINUS.SD, yend = tempo.data.plot$MEAN.PLUS.SD), ggplot2::aes(x = x, y = y, xend = xend, yend = yend), color = grey(0.40), alpha = 0.3)')) -# end mean versus index plot after sub sampling - - -# MD plot for the theoretical matrix 1 after sub sampling and permutation -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -x.MEAN <- apply(X = mat1.mix, MARGIN = 2, FUN = "mean", na.rm = TRUE) -y.SD <- apply(mat1.mix, MARGIN = 2, FUN = "sd", na.rm = TRUE) -tempo.data.plot <- data.frame(MEAN = x.MEAN, SD = y.SD) -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot) # log(x + 1) only for heatmap -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN / 2, y.cv.pois = get(transfo)(1) - tempo.data.plot$MEAN / 2) # because poisson distrib is mean = variance, thus sd = mean ^0.5, ie each mean as x is square rooted for y and then x.MEAN / 2 because log2(mean^0.5) = 0.5 * log2(mean). For cv, cv = sd/m -> log(cv) = log(sd/m) = log(m/m^0.5) = log(1/m^0.5) = log(1) - log(m^0.5) = log(1) - log(m)/2 -tempo.data.negbinom <- data.frame(x.green = get(transfo)(mean.nb1), y.green = get(transfo)(cv.nb1 * mean.nb1)) # neg binomiale distrib -}else{ -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN^0.5, y.cv.pois = 1 / tempo.data.plot$MEAN^0.5) -tempo.data.negbinom <- data.frame(x.green = mean.nb1, y.green = cv.nb1 * mean.nb1) # neg binomiale distrib -} -tempo.title <- paste0("MAT1 THEO\nAFTER PERMUTATION AND SUB SAMPLING\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\nGREEN LINE: NEG BINOM DISTRIB") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, xlim = m_sd.x.range2, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_sd.y.range2, ylog = transfo, ylab = "SD",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# end MD plot for the theoretical matrix 1 after sub sampling and permutation - -# MD plot for the theoretical matrix 2 after sub sampling and permutation -x.MEAN <- apply(X = mat2.mix, MARGIN = 2, FUN = "mean", na.rm = TRUE) -y.SD <- apply(mat2.mix, MARGIN = 2, FUN = "sd", na.rm = TRUE) -tempo.data.plot <- data.frame(MEAN = x.MEAN, SD = y.SD) -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot) # log(x + 1) only for heatmap -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN / 2, y.cv.pois = get(transfo)(1) - tempo.data.plot$MEAN / 2) # because poisson distrib is mean = variance, thus sd = mean ^0.5, ie each mean as x is square rooted for y and then x.MEAN / 2 because log2(mean^0.5) = 0.5 * log2(mean). For cv, cv = sd/m -> log(cv) = log(sd/m) = log(m/m^0.5) = log(1/m^0.5) = log(1) - log(m^0.5) = log(1) - log(m)/2 -tempo.data.negbinom <- data.frame(x.green = get(transfo)(mean.nb2), y.green = get(transfo)(cv.nb2 * mean.nb2)) # neg binomiale distrib -}else{ -tempo.data.pois <- data.frame(x.pois = tempo.data.plot$MEAN, y.sd.pois = tempo.data.plot$MEAN^0.5, y.cv.pois = 1 / tempo.data.plot$MEAN^0.5) -tempo.data.negbinom <- data.frame(x.green = mean.nb2, y.green = cv.nb2 * mean.nb2) # neg binomiale distrib -} -tempo.title <- paste0("MAT2 THEO\nAFTER PERMUTATION AND SUB SAMPLING\nMEAN DEVIATION (MD) PLOT\n", if(transfo == "log2"){"MEAN AND SD LOG2(x) "}else if(transfo == "log10"){"MEAN AND SD LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_sd.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_sd.y.range2, 2), collapse = " , "), "\nRED LINE: POISSON DISTRIB\nGREEN LINE: NEG BINOM DISTRIB") -fun_gg_scatter(data1 = list(tempo.data.plot, tempo.data.pois, tempo.data.negbinom), x = list("MEAN", "x.pois", "x.green"), y = list("SD", "y.sd.pois", "y.green"), color = list(grey(0.40), "red", "green"), geom = list("geom_point", "geom_line", "geom_line"), alpha = list(0.5, 1, 1), dot.size = dot.size, line.size = line.size, xlim = m_sd.x.range2, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_sd.y.range2, ylog = transfo, ylab = "SD",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# end MD plot for the theoretical matrix 2 after sub sampling and permutation - -# mean / cor of the theoretical matrices -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -tempo.data.plot <- suppressWarnings(data.frame(MEAN = (apply(X = mat1.mix, MARGIN = 2, FUN = "mean") + apply(X = mat2.mix, MARGIN = 2, FUN = "mean")) / 2, COR = mapply(FUN = "cor", x = as.data.frame(mat1.mix), y = as.data.frame(mat2.mix), use = "pairwise.complete.obs", method = "spearman", SIMPLIFY = TRUE))) -if(transfo != "no"){ -tempo.data.plot[, "MEAN"] <- get(transfo)(tempo.data.plot[, "MEAN"]) # log(x + 1) only for heatmap -} -tempo.title <- paste0("AFTER PERMUTATION AND SUB SAMPLING\n(MAT1 THEO / MAT2 THEO) MEAN VERSUS (MAT1 THEO / MAT2 THEO) SPEARMAN CORRELATION\n", if(transfo == "log2"){"MEAN LOG2(x) "}else if(transfo == "log10"){"MEAN LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(m_cor.x.range2, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(m_cor.y.range2, 2), collapse = " , ")) -fun_gg_scatter(data1 = tempo.data.plot, x = "MEAN", y = "COR", color = grey(0.40), geom = "geom_point", alpha = 0.5, dot.size = dot.size, line.size = line.size, xlim = m_cor.x.range2, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylim = m_cor.y.range2, ylog = "no", ylab = "CORRELATION",y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster, x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0) # x.left.extra.margin = 0, x.right.extra.margin = 0, y.top.extra.margin = 0, y.bottom.extra.margin = 0 because already in m_sd.coord.obs -# end correlation versus index before and after subsampling -tempo.cor <- suppressWarnings(mapply(FUN = "cor", c(data.frame(mat1.mix)), c(data.frame(mat2.mix)), use = "pairwise.complete.obs", method = "spearman")) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -if(length(rho2) != length(tempo.cor)){ # -tempo.cat <- paste0("\n\n================\n\nINTERNAL ERROR CODE IN SLITHERINE\nTHE TWO CORRELATIONS rho2 AND tempo.cor DO NOT HAVE THE SAME LENGTH\n\n================\n\n") # message for developers -stop(tempo.cat) -} -tempo.data.plot <- data.frame(CORRELATION = c(rho2, unlist(cor.list), tempo.cor), COLUMN_NB = c(1:length(rho2), 1:length(rho2), 1:length(rho2)), KIND = rep(c("OBS", "THEO_AFTER_PERMUTATION", "THEO_AFTER_DOWNSAMPLING"), each = length(rho2))) -tempo.title <- paste0("SPEARMAN CORRELATION BETWEEN MAT1 OBS / MAT2 OBS\nCOMPARISON WITH MAT1 THEO / MAT2 THEO 1) AFTER PERMUTATION AND 2) AFTER PERMUTATION AND DOWNSAMPLING\nX SCALE RANGE: ", paste(range(1:length(rho2), na.rm = TRUE, finite = TRUE), collapse = " , "), "\nY SCALE RANGE: -1, 1") -fun_gg_scatter(data1 = list(tempo.data.plot), x = list("COLUMN_NB"), y = list("CORRELATION"), categ = list("KIND"), geom = list("geom_point"), alpha = list(0.5), dot.size = dot.size, line.size = line.size, xlog = "no", xlab = "DIAGONAL INDEX", x.tick.nb = 8, ylog = "no", ylab = "CORRELATION", ylim = c(-1, 1), y.tick.nb = 8, title = tempo.title, text.size = text.size, title.text.size = title.text.size, classic = TRUE, raster = raster) -# end correlation versus index before and after subsampling - - -################ end sub sampling - - -################ significant differences pre serpentine (SLITHERINE) - - -}else{ -if(serp.binning == TRUE){ -serp.binning <- FALSE -tempo.warning <- paste0("THE serp.binning PARAMETER SETTING HAS BEEN SET TO TRUE, BUT THEORETICAL MATRICES HAVE BEEN IMPORTED\n-> PRE SERPENTINE ANALYSIS IS SUFFICIENT (IF YOU NEED MORE SERPENTINE BINNING, INCREASE THE VALUE OF THE serp.iter.nb PARAMETER)\n-> serp.binning PARAMETER RESET TO FALSE") -cat(paste0("\nWARNING: ", tempo.warning, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), tempo.warning) # in fact, abs(tempo.cor) is systematically used -} -} - - -cat("\nSIGNIFICANT DIFFERENCES PRE SERPENTINE (SLITHERINE)\n") -fun_report(data = "\n\n################################ SIGNIFICANT DIFFERENCES PRE SERPENTINE (SLITHERINE)", path = path.out, output = log.file, sep = 4) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "SIGNIFICANT DIFFERENCES PRE SERPENTINE\n(SLITHERINE)", text.size = 3) -# theo dataframe alone -if(transfo != "no"){ -fun_report(data = paste0("SIGNIFICANT DIFFERENCES PERFORMED ON ", toupper(transfo), " TRANSFORMED DATA"), output = log.file, path = path.out) -theo <- data.frame(MEAN = get(transfo)(as.vector((mat1.mix + mat2.mix) / 2)), RATIO = get(transfo)(as.vector(mat2.mix / mat1.mix)), MATRICES = "Theo", coord_1D = 1:(nrow(mat1.mix) * ncol(mat1.mix)), stringsAsFactors = FALSE) # mat2.mix / mat1.mix to respect serpentine convention # the coord_1D coordinate is the 1D position of a cell in a matrix -}else{ -fun_report(data = paste0("SIGNIFICANT DIFFERENCES PERFORMED ON ", toupper(transfo), "N TRANSFORMED DATA"), output = log.file, path = path.out) -theo <- data.frame(MEAN = as.vector((mat1.mix + mat2.mix) / 2), RATIO = as.vector(mat2.mix / mat1.mix), MATRICES = "Theo", coord_1D = 1:(nrow(mat1.mix) * ncol(mat1.mix)), stringsAsFactors = FALSE) # mat2.mix / mat1.mix to respect serpentine convention # the coord_1D coordinate is the 1D position of a cell in a matrix -} -# observed dataframe -if(transfo != "no"){ -obs <- data.frame(MEAN = get(transfo)(as.vector((mat1.obs + mat2.obs) / 2)), RATIO = get(transfo)(as.vector(mat2.obs / mat1.obs)), MATRICES = "Obs", coord_1D = 1:(nrow(mat1.obs) * ncol(mat1.obs)), stringsAsFactors = FALSE) # mat2.obs / mat1.obs to respect serpentine convention # the coord_1D coordinate is the 1D position of a cell in a matrix -}else{ -obs <- data.frame(MEAN = as.vector((mat1.obs + mat2.obs) / 2), RATIO = as.vector(mat2.obs / mat1.obs), MATRICES = "Obs", coord_1D = 1:(nrow(mat1.obs) * ncol(mat1.obs)), stringsAsFactors = FALSE) # mat2.obs / mat1.obs to respect serpentine convention # the coord_1D coordinate is the 1D position of a cell in a matrix -} -final <- rbind(theo, obs) -# BEWARE: segment.pre.serp, final, obs and theo integrate log transfo already -segment.pre.serp <- fun_segmentation(data1 = theo, x1 = "MEAN", y1 = "RATIO", x.range.split = range.split, x.step.factor = step.factor, error = error, data2 = obs, x2 = "MEAN", y2 = "RATIO", data2.pb.dot = "signif", plot = FALSE, graph.in.file = FALSE) -fun_report(data = "UNKNOWN DOTS HAVE BEEN CONSIDERED AS SIGNIFICANTS (ARGUMENT data2.pb.dot OF fun_segmentation() SET TO \"signif\")", output = log.file, path = path.out) -if( ! is.null(segment.pre.serp$hframe)){ -names(segment.pre.serp$hframe)[names(segment.pre.serp$hframe) == "kind"] <- "FRAMES" # only dot nb are finally kept -}else{ -tempo.cat <- paste0("BEWARE: NO HORIZONTAL FRAME DETECTED DURING SEGMENTATION PRE SERPENTINE") -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -} -# cat(paste0("\n", segment.pre.serp$warnings, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), segment.pre.serp$warnings) # in fact, abs(tempo.cor) is systematically used -fun_report(data = segment.pre.serp$warnings, output = log.file, path = path.out) - - -# second y filtering: -# weighting the cell ratio before computing the global mean ratio, after moving NA, Inf columns and also NA, Inf cells in columns with values -if(transfo != "no"){ -ratio.center.adj <- adj.mean.fun(get(transfo)(mat2.mix / mat1.mix), text = "BEFORE SERPENTINE ratio.center.adj PARAMETER THRESHOLD ADJUSTEMENT ACCORDING TO THE WEIGHTED MEAN") -tempo.sup <- get(transfo)(max(ratio.limit.sig, 1 / ratio.limit.sig, na.rm = TRUE)) -tempo.inf <- get(transfo)(min(ratio.limit.sig, 1 / ratio.limit.sig, na.rm = TRUE)) -y.range.limit.sup <- tempo.sup - ifelse(ratio.center.adj > 0, - abs(ratio.center.adj), abs(ratio.center.adj)) # minus to adjust on the mean coverage ratio. Because the idea is to remove ratio less than 2, but taking the difference of coverage between the mat1 and mat2. Thus, we want an absolute ratio less than 2 for the removal -y.range.limit.inf <- tempo.inf - ifelse(ratio.center.adj > 0, - abs(ratio.center.adj), abs(ratio.center.adj)) # minus to adjust on the mean coverage ratio. Because the idea is to remove ratio less than 2, but taking the difference of coverage between the mat1 and mat2. Thus, we want an absolute ratio less than 2 for the removal -}else{ -ratio.center.adj <- adj.mean.fun((mat2.mix / mat1.mix), text = "AFTER SERPENTINE ratio.center.adj PARAMETER THRESHOLD ADJUSTEMENT ACCORDING TO THE WEIGHTED MEAN") -y.range.limit.sup <- ratio.center.adj * ratio.limit.sig # -y.range.limit.inf <- ratio.center.adj / ratio.limit.sig # minus to adjust on the mean coverage ratio. Because the idea is to remove ratio less than 2, but taking the difference of coverage between the mat1 and mat2. Thus, we want an absolute ratio less than 2 for the removal -} -# end weighting the cell ratio before computing the global mean ratio, after moving NA, Inf columns and also NA, Inf cells in columns with values -signif.theo.dot.pre <- segment.pre.serp$data1.signif.dot # significant table of data1 pre serpentine -if( ! is.null(signif.theo.dot.pre)){ -if(all(signif.theo.dot.pre$RATIO > y.range.limit.inf & signif.theo.dot.pre$RATIO < y.range.limit.sup)){ -tempo.cat <- paste0("BEWARE: SIGNIFICANT THEO DOTS DETECTED DURING SEGMENTATION PRE SERPENTINE\nBUT NOT ANYMORE AFTER USING THE ratio.limit.sig PARAMETER (", ratio.limit.sig, ")\nTAKING INTO ACCOUNT THE GLOBAL MEAN RATIO (", fun_round(ratio.center.adj), "), THE SIGNIFICANT LIMITS WHERE: ", paste(fun_round(c(y.range.limit.inf, y.range.limit.sup)), collapse = " ")) -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = "THE SIGNIFICANT DOTS ARE:", output = log.file, path = path.out, sep = 1) -fun_report(data = "THE SIGNIFICANT DOTS ARE:", output = log.file, path = path.out, sep = 1) -fun_report(data = signif.theo.dot.pre, output = log.file, path = path.out) -signif.theo.dot.pre <- NULL -}else{ -signif.theo.dot.pre <- unique(signif.theo.dot.pre[ ! (signif.theo.dot.pre$RATIO > y.range.limit.inf & signif.theo.dot.pre$RATIO < y.range.limit.sup), ]) # only dot nb are finally kept -} -}else{ -tempo.cat <- paste0("NO SIGNIFICANT THEO DOTS DETECTED DURING SEGMENTATION PRE SERPENTINE") -# cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -} -signif.obs.dot.pre <- segment.pre.serp$data2.signif.dot # significant table of data2 pre serpentine -sup.signif.obs.dot.pre <- NULL -inf.signif.obs.dot.pre <- NULL -if( ! is.null(signif.obs.dot.pre)){ -if(all(signif.obs.dot.pre$RATIO > y.range.limit.inf & signif.obs.dot.pre$RATIO < y.range.limit.sup)){ -tempo.cat <- paste0("BEWARE: SIGNIFICANT OBS DOTS DETECTED DURING SEGMENTATION PRE SERPENTINE\nBUT NOT ANYMORE AFTER USING THE ratio.limit.sig PARAMETER (", ratio.limit.sig, ")\nTAKING INTO ACCOUNT THE GLOBAL MEAN RATIO (", fun_round(ratio.center.adj), "), THE SIGNIFICANT LIMITS WHERE: ", paste(fun_round(c(y.range.limit.inf, y.range.limit.sup)), collapse = " ")) -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = "THE SIGNIFICANT DOTS ARE:", output = log.file, path = path.out, sep = 1) -fun_report(data = signif.obs.dot.pre, output = log.file, path = path.out) -signif.obs.dot.pre <- NULL -}else{ -signif.obs.dot.pre <- unique(signif.obs.dot.pre[ ! (signif.obs.dot.pre$RATIO > y.range.limit.inf & signif.obs.dot.pre$RATIO < y.range.limit.sup), ]) # -sup.signif.obs.dot.pre <- signif.obs.dot.pre[signif.obs.dot.pre$RATIO > 0, ] # positive log ratio, i.e., mat2 > mat1 -inf.signif.obs.dot.pre <- signif.obs.dot.pre[signif.obs.dot.pre$RATIO < 0, ] # negative log ratio, i.e., mat2 < mat1 -} -}else{ -tempo.cat <- paste0("NO SIGNIFICANT OBS DOTS DETECTED DURING SEGMENTATION PRE SERPENTINE") -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -} -# end second y filtering: - -fun_report(data = paste0("PRE SERPENTINE SEGMENTATION DATA (POTENTIALLY LOG TRANSFORMED) SAVED IN: ", paste0(path.out, "/segmentation_pre_serp.RData")), output = log.file, path = path.out) -save(list = c("segment.pre.serp", "signif.theo.dot.pre", "signif.obs.dot.pre", "sup.signif.obs.dot.pre", "inf.signif.obs.dot.pre", "theo", "obs"), file = paste0(path.out, "/segmentation_pre_serp.RData")) -# segment.pre.serp result of segmentation (no second y filtering) -# signif.theo.dot.pre significant theo dot after second y filtering -# signif.obs.dot.pre significant obs dot after second y filtering -# theo mean and ratio cells of the 2 theo matrices, without transformation, used for the segmentation -# obs mean and ratio cells of the 2 theo matrices, without transformation, used for the segmentation - -# plot verif obs dots outside -# MD overlay plot before serpentine -segm.x.range <- range(final$MEAN, na.rm = TRUE, finite = TRUE) -segm.y.range <- range(c(final$RATIO, y.range.limit.inf, y.range.limit.sup), na.rm = TRUE, finite = TRUE) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -if( ! is.null(signif.theo.dot.pre)){ # signif dots in theo matrices -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nTHEO MAT ALONE + THEO SIGNIFICANT DOTS\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = theo, L2 = signif.theo.dot.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -}else{ -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nTHEO MAT ALONE (NO THEO SIGNIFICANT DOTS)\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = theo, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -} - -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -if( ! is.null(signif.obs.dot.pre)){ # signif dots in obs matrices -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS MAT ALONE + OBS SIGNIFICANT DOTS\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = obs, L2 = signif.obs.dot.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -}else{ -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS MAT ALONE (NO OBS SIGNIFICANT DOTS)\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = obs, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -} -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -if( ! is.null(signif.obs.dot.pre)){ # signif dots in obs matrices -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS AND THEO MAT + OBS SIGNIFICANT DOTS\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = final, L2 = signif.obs.dot.pre, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -}else{ -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS AND THEO MAT (NO OBS SIGNIFICANT DOTS)\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = final, L3 = segment.pre.serp$hframe, L4 = data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -} -# end plot verif obs dots outside -# end MD overlay plot before serpentine - - -# Mask of the obs data outside the cloud of the theo data on the MDMR plot (MEan Difference Mean Ratio) -if(is.null(signif.obs.dot.pre)){ -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(title = "PRE SERPENTINE MASK", text = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT DOT DETECTED", text.size = 3, title.size = title.text.size) -fun_report(data = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT DOT DETECTED", output = log.file, path = path.out) -}else{ -# file saving -sup.obs.mask.pre <- matrix(0, nrow = nrow(mat1.obs), ncol = nrow(mat1.obs)) # matrix same dim as obs full of zero -inf.obs.mask.pre <- matrix(0, nrow = nrow(mat1.obs), ncol = nrow(mat1.obs)) # matrix same dim as obs full of zero -if(nrow(sup.signif.obs.dot.pre) > 0){ -sup.obs.mask.pre[sup.signif.obs.dot.pre$coord_1D] <- 1 # create the mask. If signif.obs.dot.pre is NULL, no 1 added -fun_report(data = paste0("PRE SERPENTINE MAT2 > MAT1 MASK DATA SAVED IN: ", paste0(path.out, "/sup_mask_pre_serp.txt")), output = log.file, path = path.out) -write.table(sup.obs.mask.pre, file = paste0(path.out, "/sup_mask_pre_serp.txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -} -if(nrow(inf.signif.obs.dot.pre) > 0){ -inf.obs.mask.pre[inf.signif.obs.dot.pre$coord_1D] <- 1 # create the mask. If signif.obs.dot.pre is NULL, no 1 added -fun_report(data = paste0("PRE SERPENTINE MAT2 < MAT1 MASK DATA SAVED IN: ", paste0(path.out, "/inf_mask_pre_serp.txt")), output = log.file, path = path.out) -write.table(inf.obs.mask.pre, file = paste0(path.out, "/inf_mask_pre_serp.txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -} -obs.mask.pre <- sup.obs.mask.pre + inf.obs.mask.pre -fun_report(data = paste0("PRE SERPENTINE FULL MASK DATA SAVED IN: ", paste0(path.out, "/mask_pre_serp.txt")), output = log.file, path = path.out) -write.table(inf.obs.mask.pre, file = paste0(path.out, "/mask_pre_serp.txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -# end file saving -# heatmaps -if(nrow(sup.signif.obs.dot.pre) > 0){ -mask.plot.fun(mask_fun = sup.obs.mask.pre, mat1_fun = mat1.obs, mat2_fun = mat2.obs, serp_kind = "BEFORE", mask_kind = "POSITIVE (MAT2 > MAT1)") -}else{ -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(title = "PRE SERPENTINE MASK", text = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO MAT2 > MAT1 SIGNIFICANT DOTS DETECTED", text.size = 3, title.size = title.text.size) -fun_report(data = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO MAT2 > MAT1 SIGNIFICANT DOTS DETECTED", output = log.file, path = path.out) -} -if(nrow(inf.signif.obs.dot.pre) > 0){ -mask.plot.fun(mask_fun = inf.obs.mask.pre, mat1_fun = mat1.obs, mat2_fun = mat2.obs, serp_kind = "BEFORE", mask_kind = "NEGATIVE (MAT2 < MAT1)") -}else{ -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(title = "PRE SERPENTINE MASK", text = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO MAT2 < MAT1 SIGNIFICANT DOTS DETECTED", text.size = 3, title.size = title.text.size) -fun_report(data = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO MAT2 < MAT1 SIGNIFICANT DOTS DETECTED", output = log.file, path = path.out) -} -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -mask.plot.fun(mask_fun = obs.mask.pre, mat1_fun = mat1.obs, mat2_fun = mat2.obs, serp_kind = "BEFORE", mask_kind = "FULL") -# end heatmaps -} -if(keep == FALSE){ -tempo.list <- c("obs.mask.pre", "sup.obs.mask.pre", "inf.obs.mask.pre") -tempo.cat <- paste0("PRE SERPENTINE MASK MATRICES SAVED IN: ", paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -save(list = tempo.list, file = paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -rm(list = tempo.list) # not saved because initial matrices -} - - -################ end significant differences pre serpentine (SLITHERINE) - - -################ significant differences pre serpentine (HIC COMPARE) - - -# see https://bioconductor.org/packages/release/bioc/manuals/HiCcompare/man/HiCcompare.pdf -if(hiccomp == TRUE){ -cat("\nSIGNIFICANT DIFFERENCES PRE SERPENTINE (HIC COMPARE)\n") -fun_report(data = "\n\n################################ SIGNIFICANT DIFFERENCES PRE SERPENTINE (HIC COMPARE)", path = path.out, output = log.file, sep = 4) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "SIGNIFICANT DIFFERENCES PRE SERPENTINE\n(HIC COMPARE)", text.size = 3) -# p values computations -sparse.name <- cumsum(c(0, rep(binning, ncol(mat1.obs) - 1))) -mat1.obs.sparse <- mat1.obs -colnames(mat1.obs.sparse) <- sparse.name -mat1.obs.sparse <- HiCcompare::full2sparse(mat1.obs.sparse) -mat2.obs.sparse <- mat2.obs -colnames(mat2.obs.sparse) <- sparse.name -mat2.obs.sparse <- HiCcompare::full2sparse(mat2.obs.sparse) -hic.table <- HiCcompare::create.hic.table(mat1.obs.sparse, mat2.obs.sparse, chr = "chr5") -norm.hic.table <- suppressMessages(HiCcompare::hic_loess(hic.table)) # see the help of the hic_loess() function for the description of the returned table -diff.res <- suppressMessages(HiCcompare::hic_compare(norm.hic.table)) -diff.res <- as.data.frame(diff.res) -diff.res <- data.frame(diff.res, PVAL_MASK = 0L, PADJ_MASK = 0L) # add two columns to make the mask matrices -tempo.log.pvalue <- diff.res$p.value <= 0.05 -tempo.log.padj <- diff.res$p.adj <= 0.05 -if(sum(tempo.log.pvalue, na.rm = TRUE) > 0){ -diff.res$PVAL_MASK[tempo.log.pvalue] <- 1 -} -if(sum(tempo.log.padj, na.rm = TRUE) > 0){ -diff.res$PADJ_MASK[tempo.log.padj] <- 1 -} -# end p values computations -# heatmaps -# mask 1 -hiccomp1.mask.pre <- NULL -if(sum(tempo.log.pvalue, na.rm = TRUE) <= 0){ -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(title = "PRE SERPENTINE MASK", text = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT CELL DETECTED\n(NON ADJUSTED P VALUES)", text.size = 3, title.size = title.text.size) -fun_report(data = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT CELL DETECTED\n(NON ADJUSTED P VALUES)", output = log.file, path = path.out) -}else{ -# hiccomp.mask.pre <- HiCcompare::sparse2full(diff.res, hic.table = TRUE, column.name = "PVAL_MASK") # does not work because full2sparse() function removes the row of columns full of zero (dimension decreased) -hiccomp1.mask.pre <- matrix(0L, nrow = nrow(mat1.obs), ncol = ncol(mat1.obs)) -tempo.mat.coord <- as.matrix(data.frame(match(diff.res$start1[tempo.log.pvalue], sparse.name), -match(diff.res$start2[tempo.log.pvalue], sparse.name))) -tempo.mat.coord <- rbind(tempo.mat.coord, tempo.mat.coord[, c(2, 1)]) # to have a symmetric mask -hiccomp1.mask.pre[tempo.mat.coord] <- 1 -# end mask 1 -# file saving -fun_report(data = paste0("PRE SERPENTINE FULL MASK DATA SAVED IN: ", paste0(path.out, "/hicc_mask_pre_serp.txt")), output = log.file, path = path.out) -write.table(hiccomp1.mask.pre, file = paste0(path.out, "/hicc_mask_pre_serp.txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -# end file saving -# heatmaps -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -mask.plot.fun(mask_fun = hiccomp1.mask.pre, mat1_fun = mat1.obs, mat2_fun = mat2.obs, serp_kind = "BEFORE", mask_kind = "FULL", text_fun = "\nHIC COMPARE (NON ADJUSTED P VALUES)") -} -# end mask 1 -# mask 2 -hiccomp2.mask.pre <- NULL -if(sum(tempo.log.padj, na.rm = TRUE) <= 0){ -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(title = "PRE SERPENTINE MASK", text = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT CELL DETECTED\n(ADJUSTED P VALUES)", text.size = 3, title.size = title.text.size) -fun_report(data = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT CELL DETECTED\n(ADJUSTED P VALUES)", output = log.file, path = path.out) -}else{ -# hiccomp.mask.pre <- HiCcompare::sparse2full(diff.res, hic.table = TRUE, column.name = "PVAL_MASK") # does not work because full2sparse() function removes the row of columns full of zero (dimension decreased) -hiccomp2.mask.pre <- matrix(0L, nrow = nrow(mat1.obs), ncol = ncol(mat1.obs)) -tempo.mat.coord <- as.matrix(data.frame(match(diff.res$start1[tempo.log.padj], sparse.name), -match(diff.res$start2[tempo.log.padj], sparse.name))) -tempo.mat.coord <- rbind(tempo.mat.coord, tempo.mat.coord[, c(2, 1)]) # to have a symmetric mask -hiccomp2.mask.pre[tempo.mat.coord] <- 1 -# end mask 1 -# file saving -fun_report(data = paste0("PRE SERPENTINE FULL MASK DATA SAVED IN: ", paste0(path.out, "/hicc_padj_mask_pre_serp.txt")), output = log.file, path = path.out) -write.table(hiccomp2.mask.pre, file = paste0(path.out, "/hicc_padj_mask_pre_serp.txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -# end file saving -# heatmaps -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -mask.plot.fun(mask_fun = hiccomp2.mask.pre, mat1_fun = mat1.obs, mat2_fun = mat2.obs, serp_kind = "BEFORE", mask_kind = "FULL", text_fun = "\nHIC COMPARE (ADJUSTED P VALUES)") -} -# end mask -# end heatmaps -if(keep == FALSE){ -tempo.list <- c("mat1.obs.sparse", "mat2.obs.sparse", "diff.res", "hiccomp1.mask.pre", "hiccomp2.mask.pre") -tempo.cat <- paste0("PRE SERPENTINE HIC COMPARE MASK MATRICES SAVED IN: ", paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -save(list = tempo.list, file = paste0(path.out, "/pre_serp_hiccomp_backup.RData")) -rm(list = tempo.list) # not saved because initial matrices -} -} - - -################ serpentine - - -if(serp.binning == FALSE){ -tempo.cat <- "NO SERPENTINE BINNING (USER REQUEST OR THEORETICAL MATRICES IMPORTED)" -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, path = path.out, output = log.file, vector.cat = TRUE) -}else{ - - -# First randomize the mat1.mix row order, and use the same row order in mat2.mix before using serpentine -# In fact, change nothing to shuffle or not -cat("\nSERPENTINE BINNING\n") -fun_report(data = "\n\n################################ SERPENTINE BINNING", path = path.out, output = log.file, sep = 4) -# see https://rstudio.github.io/reticulate/reference/index.html for all the functions of reticulate -# reticulate::py_discover_config() # version of python displayed. Not necessary here because do at the end of the run using reticulate::py_config() which is more complete - - -# Theo Serpentine -theo.ini.date <- Sys.time() # time of process begin, converted into seconds -theo.ini.time <- as.numeric(theo.ini.date) # time of process begin, converted into seconds -# parallelization -tempo.thread.nb = parallel::detectCores(all.tests = FALSE, logical = TRUE) # detect the number of threads -if(is.null(thread.nb)){ -thread.nb <- tempo.thread.nb - 1 -}else if(tempo.thread.nb < thread.nb){ -thread.nb <- tempo.thread.nb -} -while (serp.iter.nb %% thread.nb != 0) { -thread.nb <- thread.nb - 1 -} -tempo.cat <- paste0("NUMBER OF THREADS USED: ", thread.nb) -cat(paste0("\n ", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -tempo.cat <- paste0("NUMBER OF ITERATION PER THREAD: ", serp.iter.nb / thread.nb) -cat(paste0("\n ", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -tempo.cat <- paste0("SERPENTINE RUN INITIATED ON THEO MATRICES (DIMENSION ", paste(dim(mat1.mix), collapse = " x "), ") AT: ", theo.ini.date) -cat(paste0("\n ", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -tempo.x <- 1:thread.nb -Clust <- parallel::makeCluster(thread.nb, outfile = paste0(path.out, "/theo_serp_parall_log.txt")) # outfile to print or cat during parallelization (only possible in a file, outfile = "" do not work on windows) -tempo.cat <- paste0("COLUMN NUMBER SPLIT FOR PARALLELISATION") -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = parallel::clusterSplit(Clust, tempo.x), output = log.file, path = path.out) -res.theo <- parallel::clusterApply( -cl = Clust, -x = parallel::clusterSplit(Clust, tempo.x), # split 1:thread.nb vector into thread.nb number of threads, thus 1 for thread 1, 2 for thread 2, etc. This is to set the seed. -mat1.mix = mat1.mix, -mat2.mix = mat2.mix, -serp.threshold = serp.threshold, -serp.minthreshold = serp.minthreshold, -serp.iter.nb = serp.iter.nb, -thread.nb = thread.nb, -serp.symmet.input = serp.symmet.input, -# very important because another R -path.function1 = path.function1, -req.package.list = req.package.list, -path.lib = path.lib, -python = python, -req.python.package.list = req.python.package.list, -path.python.lib = path.python.lib, -path.out = path.out, -# end very important because another R -fun = function(x, mat1.mix, mat2.mix, serp.threshold, serp.minthreshold, serp.iter.nb, thread.nb, serp.symmet.input, path.function1, req.package.list, path.lib, python, req.python.package.list, path.python.lib, path.out){ -# check again: very important because another R -source(path.function1) -fun_pack(req.package = req.package.list, path.lib = path.lib, load = TRUE) # load = TRUE to be sure that functions are present in the environment. And this prevent to use R.path.lib argument of fun_python_pack() -reticulate::use_python(Sys.which(python), required = TRUE) # required to avoid erratic python version use by reticulate when importing packages (see fun_python_pack()) -fun_python_pack(req.package = req.python.package.list, path.python.exec = python, path.lib = path.python.lib, R.path.lib = path.lib) -# end check again: very important because another R -serpentine <- reticulate::import("serpentine") # serpentine <- reticulate::import_from_path("c:/programdata/anaconda3/lib/site-packages/serpentine") -# saving random seed. see also Protocol 100-rev0 Parallelization in R.docx -# may not be required here but left in case -if(exists(".Random.seed", envir = .GlobalEnv)){ # if .Random.seed does not exists, it means that no random operation has been performed yet in any R environment -tempo.random.seed <- .Random.seed -on.exit(assign(".Random.seed", tempo.random.seed, env = .GlobalEnv)) -}else{ -on.exit(set.seed(NULL)) # inactivate seeding -> return to complete randomness -} -# end saving random seed. see also Protocol 100-rev0 Parallelization in R.docx -reticulate::py_set_seed(x) -# tempo.file <- file(description = paste0(path.out, "/theo_serp_parall_log.txt"), open = "a+") # open a connection file -# sink(file = tempo.file, append = TRUE, type = "output") # try to divert the stdout and stderr to the file, append = TRUE because file already exists -# sink(file = tempo.file, append = TRUE, type = "message") # try to divert the stdout and stderr to the file, append = TRUE because file already exists -serpentine$serpentine$print <- serpentine$serpentine$alternate_print(paste0(path.out, "/theo_serp_parall_log.txt")) # 1) Lyam has added a small function def alternate_print(logfile): return functools.partial(print, file=open(logfile, "a")) inside serpentine. 2) this function can be called using serpentine$serpentine$alternate_print in R, after having imported serpentine as module using reticulate. 3) serpentine$serpentine$alternate_print function has a single argument. Here I gave to this argument paste0(path.out, "/theo_serp_parall_log.txt"). Thus, print is modified. 4) This modification has to be assigned to the print function of serpentine$serpentine -output <- serpentine$serpentine$serpentin_binning(A = mat1.mix, B = mat2.mix, threshold = serp.threshold, minthreshold = serp.minthreshold, iterations = as.integer(serp.iter.nb / thread.nb), parallel = 1, force_symmetric = FALSE, verbose = TRUE) # BEWARE: must be parallel = 1, because the parallelization must be controled by R not python. In serpentine, the parall argument split iterations argument to speed the code up. Then, perform the average of the iterations matrices as output matrices. The code here does the same in R # force_symmetric = FALSE because we do not have symmetric matrix with theo matrices -# sink(file = NULL) # close the diversion, the connection file is close when the R session is closed -# sink(file = NULL) # twice because 2 opened -return(output) -} -) -parallel::stopCluster(Clust) -tempo.date <- Sys.time() -tempo.time <- as.numeric(tempo.date) -tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - theo.ini.time)) -tempo.cat <- paste0("SERPENTINE RUN ON THEO MATRICES ACHIEVED AT: ", tempo.date, " | TIME LAPSE: ", tempo.lapse) -cat(paste0("\n ", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -# end parallelization -# average of the matrices from serpentine -if(thread.nb > 1){ -mat1.theo.serp <- vector("list", thread.nb) -mat2.theo.serp <- vector("list", thread.nb) -mat.diff.theo.serp <- vector("list", thread.nb) -for(i0 in 1:thread.nb){ -mat1.theo.serp[[i0]] <- res.theo[[i0]][[1]] -mat2.theo.serp[[i0]] <- res.theo[[i0]][[2]] -mat.diff.theo.serp[[i0]] <- 2^res.theo[[i0]][[3]] # diff because log2(mat2) - log2(mat1) -> log2(mat2 / mat1). BEWARE the mat2 / mat1 convention for the ratio in serpentine. BEWARE: already log2 transformed. Thus, I removed using by 2^ -} -mat1.theo.serp <- fun_mat_op(mat1.theo.serp, kind.of.operation = "+") / thread.nb -mat2.theo.serp <- fun_mat_op(mat2.theo.serp, kind.of.operation = "+") / thread.nb -mat.diff.theo.serp <- fun_mat_op(mat.diff.theo.serp, kind.of.operation = "+") / thread.nb -}else{ -mat1.theo.serp <- res.theo[[1]][[1]] -mat2.theo.serp <- res.theo[[1]][[2]] -mat.diff.theo.serp <- 2^res.theo[[1]][[3]] -} -# end average of the matrices from serpentine -if(keep == FALSE){ -tempo.list <- c("mat1.mix", "mat2.mix", "res.theo") -tempo.cat <- paste0("THEO MATRICES JUST BEFORE SERPENTINE AND SERPENTINE PARALLELIZATION SAVED IN: ", paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -save(list = tempo.list, file = paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -rm(list = tempo.list) # not saved because initial matrices -} - - -# Obs Serpentine -obs.ini.date <- Sys.time() # time of process begin, converted into seconds -obs.ini.time <- as.numeric(obs.ini.date) # time of process begin, converted into seconds -tempo.cat <- paste0("SERPENTINE RUN INITIATED ON OBS MATRICES (DIMENSION ", paste(dim(mat1.obs), collapse = " x "), ") AT: ", obs.ini.date) -cat(paste0("\n ", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -# parallelization -tempo.x <- rev(1:thread.nb) # rev to do not have the same for theo and obs -Clust <- parallel::makeCluster(thread.nb, outfile = paste0(path.out, "/obs_serp_parall_log.txt")) # outfile to print or cat during parallelization (only possible in a file, outfile = "" do not work on windowsâ—‹) -tempo.cat <- paste0("COLUMN NUMBER SPLIT FOR PARALLELISATION") -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = parallel::clusterSplit(Clust, tempo.x), output = log.file, path = path.out) -res.obs <- parallel::clusterApply( -cl = Clust, -x = parallel::clusterSplit(Clust, tempo.x), # split 1:thread.nb vector into thread.nb number of threads, thus 1 for thread 1, 2 for thread 2, etc. This is to set the seed. -mat1.obs = mat1.obs, -mat2.obs = mat2.obs, -serp.threshold = serp.threshold, -serp.minthreshold = serp.minthreshold, -serp.iter.nb = serp.iter.nb, -thread.nb = thread.nb, -serp.symmet.input = serp.symmet.input, -# very important because another R -path.function1 = path.function1, -req.package.list = req.package.list, -path.lib = path.lib, -python = python, -req.python.package.list = req.python.package.list, -path.python.lib = path.python.lib, -path.out = path.out, -# end very important because another R -fun = function(x, mat1.obs, mat2.obs, serp.threshold, serp.minthreshold, serp.iter.nb, thread.nb, serp.symmet.input, path.function1, req.package.list, path.lib, python, req.python.package.list, path.python.lib, path.out){ -# check again: very important because another R -source(path.function1) -fun_pack(req.package = req.package.list, path.lib = path.lib, load = TRUE) # load = TRUE to be sure that functions are present in the environment. And this prevent to use R.path.lib argument of fun_python_pack() -reticulate::use_python(Sys.which(python), required = TRUE) # required to avoid erratic python version use by reticulate when importing packages (see fun_python_pack()) -fun_python_pack(req.package = req.python.package.list, path.python.exec = python, path.lib = path.python.lib, R.path.lib = path.lib) -# end check again: very important because another R -serpentine <- reticulate::import("serpentine") # serpentine <- reticulate::import_from_path("c:/programdata/anaconda3/lib/site-packages/serpentine") -# saving random seed. see also Protocol 100-rev0 Parallelization in R.docx -# may not be required here but left in case -if(exists(".Random.seed", envir = .GlobalEnv)){ # if .Random.seed does not exists, it means that no random operation has been performed yet in any R environment -tempo.random.seed <- .Random.seed -on.exit(assign(".Random.seed", tempo.random.seed, env = .GlobalEnv)) -}else{ -on.exit(set.seed(NULL)) # inactivate seeding -> return to complete randomness -} -# end saving random seed. see also Protocol 100-rev0 Parallelization in R.docx -reticulate::py_set_seed(x) -serpentine$serpentine$print <- serpentine$serpentine$alternate_print(paste0(path.out, "/obs_serp_parall_log.txt")) # 1) Lyam has added a small function def alternate_print(logfile): return functools.partial(print, file=open(logfile, "a")) inside serpentine. 2) this function can be called using serpentine$serpentine$alternate_print in R, after having imported serpentine as module using reticulate. 3) serpentine$serpentine$alternate_print function has a single argument. Here I gave to this argument paste0(path.out, "/theo_serp_parall_log.txt"). Thus, print is modified. 4) This modification has to be assigned to the print function of serpentine$serpentine -output <- serpentine$serpentine$serpentin_binning(A = mat1.obs, B = mat2.obs, threshold = serp.threshold, minthreshold = serp.minthreshold, iterations = as.integer(serp.iter.nb / thread.nb), parallel = 1, force_symmetric = serp.symmet.input, verbose = TRUE) # BEWARE: must be parallel = 1, because the parallelization must be controled by R not python. In serpentine, the parall argument split iterations argument to speed the code up. Then, perform the average of the iterations matrices as output matrices. The code here does the same in R # force_symmetric = TRUE to force the output as symmetrical matrix (should be used when the input matrices are symmetrical -return(output) -} -) -parallel::stopCluster(Clust) -tempo.date <- Sys.time() -tempo.time <- as.numeric(tempo.date) -tempo.lapse <- round(lubridate::seconds_to_period(tempo.time - obs.ini.time)) -tempo.cat <- paste0("SERPENTINE RUN ON OBS MATRICES ACHIEVED AT: ", tempo.date, " | TIME LAPSE: ", tempo.lapse) -cat(paste0("\n ", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -# end parallelization -# average of the matrices from serpentine -if(thread.nb > 1){ -mat1.obs.serp <- vector("list", thread.nb) -mat2.obs.serp <- vector("list", thread.nb) -mat.diff.obs.serp <- vector("list", thread.nb) -for(i0 in 1:thread.nb){ -mat1.obs.serp[[i0]] <- res.obs[[i0]][[1]] -mat2.obs.serp[[i0]] <- res.obs[[i0]][[2]] -# mat.diff.obs.serp[[i0]] <- 2^res.obs[[i0]][[3]] # diff because log2(mat2) - log2(mat1) -> log2(mat2 / mat1). BEWARE the mat2 / mat1 convention for the ratio in serpentine. BEWARE: already log2 transformed. Thus, I removed using by 2^ -# if( ! fun_comp_2d(round(mat2.obs.serp[[i0]] / mat1.obs.serp[[i0]], 4), round(mat.diff.obs.serp[[i0]], 4))$identical.content){ # test because I use below mat2.obs.serp / mat1.obs.serp and not mat.diff.obs.serp -# tempo.cat <- paste0("\n\n============\n\nINTERNAL ERROR CODE IN SLITHERINE\nTHE 2^mat.diff.obs.serp MATRIX IS NOT IDENTICAL TO mat2.obs.serp / mat1.obs.serp in loop ", i0, ". THIS WILL AFFECT DIFFERENTIAL HEATMAP PLOTTING USING THE mask.plot.fun() FUNCTION\n\n============\n\n") -# stop(tempo.cat) -# } -} -mat1.obs.serp <- fun_mat_op(mat1.obs.serp, kind.of.operation = "+") / thread.nb -mat2.obs.serp <- fun_mat_op(mat2.obs.serp, kind.of.operation = "+") / thread.nb -# we agree with Lyam that we first make the mean of mat1, and mean of mat2, and finally the ratio of mean(mat2)/mean(mat1), more than mean(mat2/mat1). Thus, this would not be good: mat.diff.obs.serp <- fun_mat_op(mat.diff.obs.serp, kind.of.operation = "+") / thread.nb -}else{ -mat1.obs.serp <- res.obs[[1]][[1]] -mat2.obs.serp <- res.obs[[1]][[2]] -} -mat.diff.obs.serp <- mat2.obs.serp / mat1.obs.serp -# end average of the matrices from serpentine -if(keep == FALSE){ -tempo.list <- c("mat1.obs", "mat2.obs", "res.obs") -tempo.cat <- paste0("OBS MATRICES JUST BEFORE SERPENTINE AND SERPENTINE PARALLELIZATION SAVED IN: ", paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -save(list = tempo.list, file = paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -rm(list = tempo.list) # not saved because initial matrices -} -# export of binned obs and theo matrices -loop.mat.names <- c("mat1.theo.serp", "mat2.theo.serp", "mat1.obs.serp", "mat2.obs.serp") -for(i0 in 1:length(loop.mat.names)){ -write.table(get(loop.mat.names[i0]), file = paste0(path.out, "/", loop.mat.names[i0], ".txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -} -# end export of binned obs and theo matrices - - -################ end serpentine - - -################ heatmaps post serpentine - - -# heatmap -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "POST SERPENTINE HEATMAP", text.size = 3) -loop.mat.names <- c("mat1.theo.serp", "mat2.theo.serp", "mat1.obs.serp", "mat2.obs.serp") -loop.heatmap.title <- c("THEO MAT1 AFTER SERPENTINE", "THEO MAT2 AFTER SERPENTINE", "OBS MAT1 AFTER SERPENTINE", "OBS MAT2 AFTER SERPENTINE") -loop.heatmap.title2 <- c("NO SYMMETRIC MATRIX", "NO SYMMETRIC MATRIX", ifelse(serp.symmet.input == TRUE, "SYMMETRIC MATRIX (FORCED BY USER OPTION)", "NO SYMMETRIC MATRIX"), ifelse(serp.symmet.input == TRUE, "SYMMETRIC MATRIX (FORCED BY USER OPTION)", "NO SYMMETRIC MATRIX")) -heatmap.range3 <- NULL -for(i0 in 1:length(loop.mat.names)){ -tempo.data.plot <- get(loop.mat.names[i0]) / mean(get(loop.mat.names[i0]), na.rm = TRUE) -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot + 1) # log transfo -} -heatmap.range3 <- range(c(heatmap.range3, tempo.data.plot), na.rm = TRUE, finite = TRUE) -} -loop.heatmap.title <- paste0(loop.heatmap.title, "\n", if(transfo == "log2"){"LOG2(x + 1) "}else if(transfo == "log10"){"LOG10(x + 1) "}else{"NO "}, "TRANSFORMATION\nFINAL MATRIX IS CELL AVERAGE OF ", thread.nb, " SERPENTINE BINNED MATRICES (PARALLELIZATION)\nSCALE RANGE: ", paste(fun_round(heatmap.range3, 2), collapse = " , "), "\nNORMALIZED DISPLAY (GLOBAL MEAN DIVISION)\n", loop.heatmap.title2) -for(i0 in 1:length(loop.mat.names)){ -tempo.data.plot <- get(loop.mat.names[i0]) / mean(get(loop.mat.names[i0]), na.rm = TRUE) -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot + 1) -} -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_heatmap(data1 = tempo.data.plot, legend.name1 = "", limit1 = heatmap.range3, midpoint1 = mean(heatmap.range3, na.rm = TRUE), title = loop.heatmap.title[i0], text.size = heatmap.text.size, title.text.size = title.text.size) -} -# end heatmap - - -# differential heatmap -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "POST SERPENTINE DIFFERENTIAL HEATMAP", text.size = 3) -# range computation -heatmap.range4 <- NULL -tempo.data.plot <- mat.diff.obs.serp / mean(mat.diff.obs.serp, na.rm = TRUE) # no log data -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot) -} -heatmap.range4 <- range(c(heatmap.range4, tempo.data.plot), na.rm = TRUE, finite = TRUE) -tempo.data.plot <- mat.diff.theo.serp / adj.mean.fun(mat.diff.theo.serp, text = "AFTER SERPENTINE THEO HEATMAP NORMALIZATION ACCORDING TO THE WEIGHTED DIAGONAL MEAN") # weighted diag for theo only -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot) -} -heatmap.range4 <- range(c(heatmap.range4, tempo.data.plot), na.rm = TRUE, finite = TRUE) -heatmap.range4 <- max(abs(heatmap.range4), na.rm = TRUE) -heatmap.range4 <- c(-heatmap.range4, heatmap.range4) # to center on zero -# end range computation - - -# plot -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -heatmap.title <- paste0("DIFFERENTIAL THEO AFTER SERPENTINE (THEO2 / THEO1)\n", if(transfo == "log2"){"LOG2(x) "}else if(transfo == "log10"){"LOG10(x) "}else{"NO "}, "TRANSFORMATION\nSCALE RANGE: ", paste(fun_round(heatmap.range4, 2), collapse = " , "), "\nNORMALIZED DISPLAY (WEIGHTED DIAGONAL MEAN DIVISION)") -tempo.data.plot <- mat.diff.theo.serp / adj.mean.fun(mat.diff.theo.serp, text = "AFTER SERPENTINE THEO HEATMAP NORMALIZATION ACCORDING TO THE WEIGHTED DIAGONAL MEAN") # weighted diag for theo only -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot) -} -fun_gg_heatmap(data1 = tempo.data.plot, legend.name = "", limit1 = heatmap.range4, midpoint1 = 0, title = heatmap.title, title.text.size = title.text.size) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -heatmap.title <- paste0("DIFFERENTIAL OBS AFTER SERPENTINE (OBS2 / OBS1)\n", if(transfo == "log2"){"LOG2(x) "}else if(transfo == "log10"){"LOG10(x) "}else{"NO "}, "TRANSFORMATION\nSCALE RANGE: ", paste(fun_round(heatmap.range4, 2), collapse = " , "), "\nNORMALIZED DISPLAY (GLOBAL MEAN DIVISION)", ifelse(serp.symmet.input == TRUE, "\nSYMMETRIC MATRIX (FORCED BY USER OPTION)", "\nNO SYMMETRIC MATRIX")) -tempo.data.plot <- mat.diff.obs.serp / mean(mat.diff.obs.serp, na.rm = TRUE) -if(transfo != "no"){ -tempo.data.plot <- get(transfo)(tempo.data.plot) -} -fun_gg_heatmap(data1 = tempo.data.plot, legend.name = "", limit1 = heatmap.range4, midpoint1 = 0, title = heatmap.title, title.text.size = title.text.size) -# end plot -# end differential heatmap - - -################ significant differences post serpentine - - -cat("\nSIGNIFICANT DIFFERENCES POST SERPENTINE (SLITHERINE)\n") -fun_report(data = "\n\n################################ SIGNIFICANT DIFFERENCES POST SERPENTINE (SLITHERINE)", path = path.out, output = log.file, sep = 4) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "SIGNIFICANT DIFFERENCES POST SERPENTINE\n(SLITHERINE)", text.size = 3) -# theo dataframe alone -if(transfo != "no"){ -fun_report(data = paste0("SIGNIFICANT DIFFERENCES PERFORMED ON ", toupper(transfo), " TRANSFORMED DATA"), output = log.file, path = path.out) -theo <- data.frame(MEAN = get(transfo)(as.vector((mat1.theo.serp + mat2.theo.serp) / 2)), RATIO = get(transfo)(as.vector(mat2.theo.serp / mat1.theo.serp)), MATRICES = "Theo", coord_1D = 1:(nrow(mat1.theo.serp) * ncol(mat1.theo.serp)), stringsAsFactors = FALSE) # mat2.theo.serp / mat1.theo.serp to respect serpentine convention # the coord_1D coordinate is the 1D position of a cell in a matrix -}else{ -fun_report(data = paste0("SIGNIFICANT DIFFERENCES PERFORMED ON ", toupper(transfo), "N TRANSFORMED DATA"), output = log.file, path = path.out) -theo <- data.frame(MEAN = as.vector((mat1.theo.serp + mat2.theo.serp) / 2), RATIO = as.vector(mat2.theo.serp / mat1.theo.serp), MATRICES = "Theo", coord_1D = 1:(nrow(mat1.theo.serp) * ncol(mat1.theo.serp)), stringsAsFactors = FALSE) # mat2.theo.serp / mat1.theo.serp to respect serpentine convention # the coord_1D coordinate is the 1D position of a cell in a matrix -} -# observed dataframe -if(transfo != "no"){ -obs <- data.frame(MEAN = get(transfo)(as.vector((mat1.obs.serp + mat2.obs.serp) / 2)), RATIO = get(transfo)(as.vector(mat2.obs.serp / mat1.obs.serp)), MATRICES = "Obs", coord_1D = 1:(nrow(mat1.obs.serp) * ncol(mat1.obs.serp)), stringsAsFactors = FALSE) # mat2.obs.serp / mat1.obs.serp to respect serpentine convention # the coord_1D coordinate is the 1D position of a cell in a matrix -}else{ -obs <- data.frame(MEAN = as.vector((mat1.obs.serp + mat2.obs.serp) / 2), RATIO = as.vector(mat2.obs.serp / mat1.obs.serp), MATRICES = "Obs", coord_1D = 1:(nrow(mat1.obs.serp) * ncol(mat1.obs.serp)), stringsAsFactors = FALSE) # mat2.obs.serp / mat1.obs.serp to respect serpentine convention # the coord_1D coordinate is the 1D position of a cell in a matrix -} -final <- rbind(theo, obs) -# BEWARE: segment.post.serp, signif.theo.dot.post, signif.obs.dot.post, final, obs and theo integrate log transfo already -segment.post.serp <- fun_segmentation(data1 = theo, x1 = "MEAN", y1 = "RATIO", x.range.split = range.split, x.step.factor = step.factor, error = error, data2 = obs, x2 = "MEAN", y2 = "RATIO", data2.pb.dot = "signif", plot = FALSE, graph.in.file = FALSE) -fun_report(data = "UNKNOWN DOTS HAVE BEEN CONSIDERED AS SIGNIFICANTS (ARGUMENT data2.pb.dot OF fun_segmentation() SET TO \"signif\")", output = log.file, path = path.out) -if( ! is.null(segment.post.serp$hframe)){ -names(segment.post.serp$hframe)[names(segment.post.serp$hframe) == "kind"] <- "FRAMES" # only dot nb are finally kept -}else{ -tempo.cat <- paste0("BEWARE: NO HORIZONTAL FRAME DETECTED DURING SEGMENTATION POST SERPENTINE") -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -} -# cat(paste0("\n", segment.post.serp$warnings, "\n")) -warning.message <- paste0(warning.message, ifelse(is.null(warning.message), "", "\n"), segment.post.serp$warnings) # in fact, abs(tempo.cor) is systematically used -fun_report(data = segment.post.serp$warnings, output = log.file, path = path.out) - - -# second y filtering: -# weighting the cell ratio before computing the global mean ratio, after moving NA, Inf columns and also NA, Inf cells in columns with values -if(transfo != "no"){ -ratio.center.adj <- adj.mean.fun(get(transfo)(mat2.theo.serp / mat1.theo.serp), text = "BEFORE SERPENTINE ratio.center.adj PARAMETER THRESHOLD ADJUSTEMENT ACCORDING TO THE WEIGHTED MEAN") -tempo.sup <- get(transfo)(max(ratio.limit.sig, 1 / ratio.limit.sig, na.rm = TRUE)) -tempo.inf <- get(transfo)(min(ratio.limit.sig, 1 / ratio.limit.sig, na.rm = TRUE)) -y.range.limit.sup <- tempo.sup - ifelse(ratio.center.adj > 0, - abs(ratio.center.adj), abs(ratio.center.adj)) # minus to adjust on the mean coverage ratio. Because the idea is to remove ratio less than 2, but taking the difference of coverage between the mat1 and mat2. Thus, we want an absolute ratio less than 2 for the removal -y.range.limit.inf <- tempo.inf - ifelse(ratio.center.adj > 0, - abs(ratio.center.adj), abs(ratio.center.adj)) # minus to adjust on the mean coverage ratio. Because the idea is to remove ratio less than 2, but taking the difference of coverage between the mat1 and mat2. Thus, we want an absolute ratio less than 2 for the removal -}else{ -ratio.center.adj <- adj.mean.fun((mat2.theo.serp / mat1.theo.serp), text = "AFTER SERPENTINE ratio.center.adj PARAMETER THRESHOLD ADJUSTEMENT ACCORDING TO THE WEIGHTED MEAN") -y.range.limit.sup <- ratio.center.adj * ratio.limit.sig # -y.range.limit.inf <- ratio.center.adj / ratio.limit.sig # minus to adjust on the mean coverage ratio. Because the idea is to remove ratio less than 2, but taking the difference of coverage between the mat1 and mat2. Thus, we want an absolute ratio less than 2 for the removal -} -# end weighting the cell ratio before computing the global mean ratio, after moving NA, Inf columns and also NA, Inf cells in columns with values -signif.theo.dot.post <- segment.post.serp$data1.signif.dot # significant table of data1 post serpentine -if( ! is.null(signif.theo.dot.post)){ -if(all(signif.theo.dot.post$RATIO > y.range.limit.inf & signif.theo.dot.post$RATIO < y.range.limit.sup)){ -tempo.cat <- paste0("BEWARE: SIGNIFICANT THEO DOTS DETECTED DURING SEGMENTATION POST SERPENTINE\nBUT NOT ANYMORE AFTER USING THE ratio.limit.sig PARAMETER (", ratio.limit.sig, ")\nTAKING INTO ACCOUNT THE GLOBAL MEAN RATIO (", fun_round(ratio.center.adj), "), THE SIGNIFICANT LIMITS WHERE: ", paste(fun_round(c(y.range.limit.inf, y.range.limit.sup)), collapse = " ")) -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = "THE SIGNIFICANT DOTS ARE:", output = log.file, path = path.out, sep = 1) -fun_report(data = signif.theo.dot.post, output = log.file, path = path.out) -signif.theo.dot.post <- NULL -}else{ -signif.theo.dot.post <- unique(signif.theo.dot.post[ ! (signif.theo.dot.post$RATIO > y.range.limit.inf & signif.theo.dot.post$RATIO < y.range.limit.sup), ]) # only dot nb are finally kept -} -}else{ -tempo.cat <- paste0("NO SIGNIFICANT THEO DOTS DETECTED DURING SEGMENTATION POST SERPENTINE") -# cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -} -signif.obs.dot.post <- segment.post.serp$data2.signif.dot # significant table of data2 post serpentine -sup.signif.obs.dot.post <- NULL -inf.signif.obs.dot.post <- NULL -if( ! is.null(signif.obs.dot.post)){ -if(all(signif.obs.dot.post$RATIO > y.range.limit.inf & signif.obs.dot.post$RATIO < y.range.limit.sup)){ -tempo.cat <- paste0("BEWARE: SIGNIFICANT OBS DOTS DETECTED DURING SEGMENTATION POST SERPENTINE\nBUT NOT ANYMORE AFTER USING THE ratio.limit.sig PARAMETER (", ratio.limit.sig, ")\nTAKING INTO ACCOUNT THE GLOBAL MEAN RATIO (", fun_round(ratio.center.adj), "), THE SIGNIFICANT LIMITS WHERE: ", paste(fun_round(c(y.range.limit.inf, y.range.limit.sup)), collapse = " ")) -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -fun_report(data = "THE SIGNIFICANT DOTS ARE:", output = log.file, path = path.out, sep = 1) -fun_report(data = signif.obs.dot.post, output = log.file, path = path.out) -signif.obs.dot.post <- NULL -}else{ -signif.obs.dot.post <- unique(signif.obs.dot.post[ ! (signif.obs.dot.post$RATIO > y.range.limit.inf & signif.obs.dot.post$RATIO < y.range.limit.sup), ]) # only dot nb are finally kept -sup.signif.obs.dot.post <- signif.obs.dot.post[signif.obs.dot.post$RATIO > 0, ] # positive log ratio, i.e., mat2 > mat1 -inf.signif.obs.dot.post <- signif.obs.dot.post[signif.obs.dot.post$RATIO < 0, ] # negative log ratio, i.e., mat2 < mat1 -} -}else{ -tempo.cat <- paste0("NO SIGNIFICANT OBS DOTS DETECTED DURING SEGMENTATION POST SERPENTINE") -cat(paste0("\n", tempo.cat, "\n")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -} -# end second y filtering: - -fun_report(data = paste0("POST SERPENTINE SEGMENTATION DATA (POTENTIALLY LOG TRANSFORMED) SAVED IN: ", paste0(path.out, "/segmentation_post_serp.RData")), output = log.file, path = path.out) -save(list = c("segment.post.serp", "signif.theo.dot.post", "signif.obs.dot.post", "sup.signif.obs.dot.post", "inf.signif.obs.dot.post", "theo", "obs"), file = paste0(path.out, "/segmentation_post_serp.RData")) -# segment.post.serp result of segmentation (no second y filtering) -# signif.theo.dot.post significant theo dot after second y filtering -# signif.obs.dot.post significant obs dot after second y filtering -# theo mean and ratio cells of the 2 theo matrices, without transformation, used for the segmentation -# obs mean and ratio cells of the 2 theo matrices, without transformation, used for the segmentation - -# plot verif obs dots outside -# MD overlay plot before serpentine -segm.x.range <- range(final$MEAN, na.rm = TRUE, finite = TRUE) -segm.y.range <- range(c(final$RATIO, y.range.limit.inf, y.range.limit.sup), na.rm = TRUE, finite = TRUE) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -if( ! is.null(signif.theo.dot.post)){ # signif dots in theo matrices -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nTHEO MAT ALONE + THEO SIGNIFICANT DOTS\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = theo, L2 = signif.theo.dot.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -}else{ -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nTHEO MAT ALONE (NO THEO SIGNIFICANT DOTS)\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = theo, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[2], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -} - -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -if( ! is.null(signif.obs.dot.post)){ # signif dots in obs matrices -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS MAT ALONE + OBS SIGNIFICANT DOTS\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = obs, L2 = signif.obs.dot.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -}else{ -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS MAT ALONE (NO OBS SIGNIFICANT DOTS)\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = obs, L3 = segment.post.serp$hframe, L4 =data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2)[1], L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -} -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -if( ! is.null(signif.obs.dot.post)){ # signif dots in obs matrices -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS AND THEO MAT + OBS SIGNIFICANT DOTS\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = final, L2 = signif.obs.dot.post, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L2 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L2 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L2 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L2 = "SIGNIF DOTS", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L2 = "black", L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L2 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L2 = 1, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -}else{ -tempo.title <- paste0("SEGMENTATION OF THE MEAN / RATIO MATRIX CELLS\nOBS AND THEO MAT (NO OBS SIGNIFICANT DOTS)\n", if(transfo == "log2"){"MEAN AND RATIO LOG2(x) "}else if(transfo == "log10"){"MEAN AND RATIO LOG10(x) "}else{"NO LOG TRANSFORMATION"}, "\nX SCALE RANGE: ", paste(fun_round(segm.x.range, 2), collapse = " , "), "\nY SCALE RANGE: ", paste(fun_round(segm.y.range, 2), collapse = " , ")) -fun_gg_scatter(data1 = list(L1 = final, L3 = segment.post.serp$hframe, L4 = data.frame(y = c(y.range.limit.inf, y.range.limit.sup), FACTOR_2_CUTOFFS = c("INF_LIMIT", "SUP_LIMIT"))), x = list(L1 = "MEAN", L3 = "x", L4 = NULL), y = list(L1 = "RATIO", L3 = "y", L4 = "y"), categ = list(L1 = "MATRICES", L3 = "FRAMES", L4 = "FACTOR_2_CUTOFFS"), legend.name = list(L1 = "MATRICES", L3 = "FRAMES", L4 = paste0(fun_round(ratio.limit.sig), " X CUTOFFS")), color = list(L1 = fun_gg_palette(2), L3 = "blue", L4 = "orange"), geom = list(L1 = "geom_point", L3 = "geom_path", L4 = "geom_hline"), alpha = list(L1 = 0.25, L3 = 0.5, L4 = 0.5), dot.size = dot.size, line.size = line.size, text.size = text.size, title.text.size = title.text.size, xlog = transfo, xlab = "MEAN", x.tick.nb = 8, ylog = transfo, xlim = segm.x.range, ylim = segm.y.range, ylab = "RATIO", y.tick.nb = 8, title = tempo.title, classic = TRUE, raster = raster, x.left.extra.margin = 0.05, x.right.extra.margin = 0.05, y.top.extra.margin = 0.05, y.bottom.extra.margin = 0.05) -} -# end plot verif obs dots outside -# end MD overlay plot before serpentine - - -# Mask of the obs data outside the cloud of the theo data on the MDMR plot (MEan Difference Mean Ratio) -if(is.null(signif.obs.dot.post)){ -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(title = "POST SERPENTINE MASK", text = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT DOT DETECTED", text.size = 3, title.size = title.text.size) -fun_report(data = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT DOT DETECTED", output = log.file, path = path.out) -}else{ -# file saving -sup.obs.mask.post <- matrix(0, nrow = nrow(mat1.obs.serp), ncol = nrow(mat1.obs.serp)) # matrix same dim as obs full of zero -inf.obs.mask.post <- matrix(0, nrow = nrow(mat1.obs.serp), ncol = nrow(mat1.obs.serp)) # matrix same dim as obs full of zero -if(nrow(sup.signif.obs.dot.post) > 0){ -sup.obs.mask.post[sup.signif.obs.dot.post$coord_1D] <- 1 # create the mask. If signif.obs.dot.post is NULL, no 1 added -fun_report(data = paste0("POST SERPENTINE MAT2 > MAT1 MASK DATA SAVED IN: ", paste0(path.out, "/sup_mask_post_serp.txt")), output = log.file, path = path.out) -write.table(sup.obs.mask.post, file = paste0(path.out, "/sup_mask_post_serp.txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -} -if(nrow(inf.signif.obs.dot.post) > 0){ -inf.obs.mask.post[inf.signif.obs.dot.post$coord_1D] <- 1 # create the mask. If signif.obs.dot.post is NULL, no 1 added -fun_report(data = paste0("POST SERPENTINE MAT2 < MAT1 MASK DATA SAVED IN: ", paste0(path.out, "/inf_mask_post_serp.txt")), output = log.file, path = path.out) -write.table(inf.obs.mask.post, file = paste0(path.out, "/inf_mask_post_serp.txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -} -obs.mask.post <- sup.obs.mask.post + inf.obs.mask.post -fun_report(data = paste0("POST SERPENTINE FULL MASK DATA SAVED IN: ", paste0(path.out, "/mask_post_serp.txt")), output = log.file, path = path.out) -write.table(inf.obs.mask.post, file = paste0(path.out, "/mask_post_serp.txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -# end file saving -# heatmaps -if(nrow(sup.signif.obs.dot.post) > 0){ -mask.plot.fun(mask_fun = sup.obs.mask.post, mat1_fun = mat1.obs.serp, mat2_fun = mat2.obs.serp, serp_kind = "AFTER", mask_kind = "POSITIVE (MAT2 > MAT1)", text_fun = ifelse(serp.symmet.input == TRUE, "\nSYMMETRIC MATRIX (FORCED BY USER OPTION)", "\nNO SYMMETRIC MATRIX")) -}else{ -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(title = "POST SERPENTINE MASK", text = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO MAT2 > MAT1 SIGNIFICANT DOTS DETECTED", text.size = 3, title.size = title.text.size) -fun_report(data = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO MAT2 > MAT1 SIGNIFICANT DOTS DETECTED", output = log.file, path = path.out) -} -if(nrow(inf.signif.obs.dot.post) > 0){ -mask.plot.fun(mask_fun = inf.obs.mask.post, mat1_fun = mat1.obs.serp, mat2_fun = mat2.obs.serp, serp_kind = "AFTER", mask_kind = "NEGATIVE (MAT2 < MAT1)", text_fun = ifelse(serp.symmet.input == TRUE, "\nSYMMETRIC MATRIX (FORCED BY USER OPTION)", "\nNO SYMMETRIC MATRIX")) -}else{ -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(title = "POST SERPENTINE MASK", text = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO MAT2 < MAT1 SIGNIFICANT DOTS DETECTED", text.size = 3, title.size = title.text.size) -fun_report(data = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO MAT2 < MAT1 SIGNIFICANT DOTS DETECTED", output = log.file, path = path.out) -} -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -mask.plot.fun(mask_fun = obs.mask.post, mat1_fun = mat1.obs.serp, mat2_fun = mat2.obs.serp, serp_kind = "AFTER", mask_kind = "FULL", text_fun = ifelse(serp.symmet.input == TRUE, "\nSYMMETRIC MATRIX (FORCED BY USER OPTION)", "\nNO SYMMETRIC MATRIX")) -# end heatmaps -} - - -################ significant differences post serpentine (HIC COMPARE) - - -# see https://bioconductor.org/packages/release/bioc/manuals/HiCcompare/man/HiCcompare.pdf -if(hiccomp == TRUE){ -cat("\nSIGNIFICANT DIFFERENCES POST SERPENTINE (HIC COMPARE)\n") -fun_report(data = "\n\n################################ SIGNIFICANT DIFFERENCES POST SERPENTINE (HIC COMPARE)", path = path.out, output = log.file, sep = 4) -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(text = "SIGNIFICANT DIFFERENCES POST SERPENTINE\n(HIC COMPARE)", text.size = 3) -# p values computations -sparse.name <- cumsum(c(0, rep(binning, ncol(mat1.obs.serp) - 1))) -mat1.obs.serp.sparse <- mat1.obs.serp -colnames(mat1.obs.serp.sparse) <- sparse.name -mat1.obs.serp.sparse <- HiCcompare::full2sparse(mat1.obs.serp.sparse) -mat2.obs.serp.sparse <- mat2.obs.serp -colnames(mat2.obs.serp.sparse) <- sparse.name -mat2.obs.serp.sparse <- HiCcompare::full2sparse(mat2.obs.serp.sparse) -hic.table <- HiCcompare::create.hic.table(mat1.obs.serp.sparse, mat2.obs.serp.sparse, chr = "chr5") -norm.hic.table <- suppressMessages(HiCcompare::hic_loess(hic.table)) # see the help of the hic_loess() function for the description of the returned table -diff.res.serp <- suppressMessages(HiCcompare::hic_compare(norm.hic.table)) -diff.res.serp <- as.data.frame(diff.res.serp) -diff.res.serp <- data.frame(diff.res.serp, PVAL_MASK = 0L, PADJ_MASK = 0L) # add two columns to make the mask matrices -tempo.log.pvalue <- diff.res.serp$p.value <= 0.05 -tempo.log.padj <- diff.res.serp$p.adj <= 0.05 -if(sum(tempo.log.pvalue, na.rm = TRUE) > 0){ -diff.res.serp$PVAL_MASK[tempo.log.pvalue] <- 1 -} -if(sum(tempo.log.padj, na.rm = TRUE) > 0){ -diff.res.serp$PADJ_MASK[tempo.log.padj] <- 1 -} -# end p values computations -# heatmaps -# mask 1 -hiccomp1.mask.post <- NULL -if(sum(tempo.log.pvalue, na.rm = TRUE) <= 0){ -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(title = "POST SERPENTINE MASK", text = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT CELL DETECTED\n(NON ADJUSTED P VALUES)", text.size = 3, title.size = title.text.size) -fun_report(data = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT CELL DETECTED\n(NON ADJUSTED P VALUES)", output = log.file, path = path.out) -}else{ -# hiccomp.mask.post <- HiCcompare::sparse2full(diff.res.serp, hic.table = TRUE, column.name = "PVAL_MASK") # does not work because full2sparse() function removes the row of columns full of zero (dimension decreased) -hiccomp1.mask.post <- matrix(0L, nrow = nrow(mat1.obs.serp), ncol = ncol(mat1.obs.serp)) -tempo.mat.coord <- as.matrix(data.frame(match(diff.res.serp$start1[tempo.log.pvalue], sparse.name), -match(diff.res.serp$start2[tempo.log.pvalue], sparse.name))) -tempo.mat.coord <- rbind(tempo.mat.coord, tempo.mat.coord[, c(2, 1)]) # to have a symmetric mask -hiccomp1.mask.post[tempo.mat.coord] <- 1 -# end mask 1 -# file saving -fun_report(data = paste0("POST SERPENTINE FULL MASK DATA SAVED IN: ", paste0(path.out, "/hicc_mask_post_serp.txt")), output = log.file, path = path.out) -write.table(hiccomp1.mask.post, file = paste0(path.out, "/hicc_mask_post_serp.txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -# end file saving -# heatmaps -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -mask.plot.fun(mask_fun = hiccomp1.mask.post, mat1_fun = mat1.obs.serp, mat2_fun = mat2.obs.serp, serp_kind = "AFTER", mask_kind = "FULL", text_fun = "\nHIC COMPARE (NON ADJUSTED P VALUES)") -} -# end mask 1 -# mask 2 -hiccomp2.mask.post <- NULL -if(sum(tempo.log.padj, na.rm = TRUE) <= 0){ -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -fun_gg_empty_graph(title = "POST SERPENTINE MASK", text = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT CELL DETECTED\n(ADJUSTED P VALUES)", text.size = 3, title.size = title.text.size) -fun_report(data = "NO MASK TO APPLY OVER HEATMAPS\nBECAUSE\nNO SIGNIFICANT CELL DETECTED\n(ADJUSTED P VALUES)", output = log.file, path = path.out) -}else{ -# hiccomp.mask.post <- HiCcompare::sparse2full(diff.res.serp, hic.table = TRUE, column.name = "PVAL_MASK") # does not work because full2sparse() function removes the row of columns full of zero (dimension decreased) -hiccomp2.mask.post <- matrix(0L, nrow = nrow(mat1.obs.serp), ncol = ncol(mat1.obs.serp)) -tempo.mat.coord <- as.matrix(data.frame(match(diff.res.serp$start1[tempo.log.padj], sparse.name), -match(diff.res.serp$start2[tempo.log.padj], sparse.name))) -tempo.mat.coord <- rbind(tempo.mat.coord, tempo.mat.coord[, c(2, 1)]) # to have a symmetric mask -hiccomp2.mask.post[tempo.mat.coord] <- 1 -# end mask 1 -# file saving -fun_report(data = paste0("POST SERPENTINE FULL MASK DATA SAVED IN: ", paste0(path.out, "/hicc_padj_mask_post_serp.txt")), output = log.file, path = path.out) -write.table(hiccomp2.mask.post, file = paste0(path.out, "/hicc_padj_mask_post_serp.txt"), row.names = FALSE, col.names = FALSE, append = FALSE, quote = FALSE, sep = "\t") -# end file saving -# heatmaps -if(activate.pdf == TRUE){ -invisible(dev.set(pdf.nb)) -}else{ -fun_open(pdf.disp = activate.pdf, width.fun = width.wind, height.fun = height.wind) -} -mask.plot.fun(mask_fun = hiccomp2.mask.post, mat1_fun = mat1.obs.serp, mat2_fun = mat2.obs.serp, serp_kind = "AFTER", mask_kind = "FULL", text_fun = "\nHIC COMPARE (ADJUSTED P VALUES)") -} -# end mask -# end heatmaps -if(keep == FALSE){ -tempo.list <- c("mat1.obs.serp.sparse", "mat2.obs.serp.sparse", "diff.res.serp", "hiccomp1.mask.post", "hiccomp2.mask.post") -tempo.cat <- paste0("POST SERPENTINE HIC COMPARE MASK MATRICES SAVED IN: ", paste0(path.out, "/", paste0(tempo.list, collapse = "_"), "_backup.RData")) -fun_report(data = tempo.cat, output = log.file, path = path.out) -save(list = tempo.list, file = paste0(path.out, "/post_serp_hiccomp_backup.RData")) -rm(list = tempo.list) # not saved because initial matrices -} -} - - -} - - -################ Pdf window closing - - -fun_close() - - -################ Environment saving - - -fun_report("\n\n################################ RUNNING END", output = log.file, path = path.out) -end.date <- Sys.time() -end.time <- as.numeric(end.date) -total.lapse <- round(lubridate::seconds_to_period(end.time - ini.time)) -fun_report(data = end.date, path = path.out, output = log.file, vector.cat = TRUE) -fun_report(data = paste0("LAPSE: ", total.lapse), path = path.out, output = log.file, vector.cat = TRUE) -cat(paste0("\nSLITHERINE END\n\nTOTAL TIME LAPSE: ", total.lapse, "\n")) -fun_report(data = paste0("ALL DATA SAVED IN: ", paste0(path.out, "/all_objects.RData")), output = log.file, path = path.out) -save(list = ls(), file = paste0(path.out, "/all_objects.RData")) - - -################ Warning messages - - -if( ! is.null(warning.message)){ -fun_report(data = "\n\n################################ WARNING MESSAGES", path = path.out, output = log.file, sep = 4) -fun_report(data = warning.message, path = path.out, output = log.file) -} - - -################ Parameter printing - - -fun_report("\n\n################################ INITIAL SETTINGS OF PARAMETERS", output = log.file, path = path.out) -fun_report(data = param.ini.settings, path = path.out, output = log.file, vector.cat = TRUE) -fun_report("\n\n################################ R SYSTEM AND PACKAGES", output = log.file, path = path.out) -fun_report(data = sessionInfo(), path = path.out, output = log.file, vector.cat = TRUE) -if(serp.binning == TRUE){ -fun_report("\n\n################################ PYTHON SYSTEM AND PACKAGES", output = log.file, path = path.out) -fun_report(data = reticulate::py_config(), path = path.out, output = log.file, vector.cat = TRUE) # to get the version of python, or use a python chunk ```{python} import IPython; python_session = IPython.sys_info();``` then reticulate::py$python_session -fun_report(data = as.matrix(system("pip freeze", intern = TRUE)), path = path.out, output = log.file, vector.cat = TRUE) # bash command to get the version of the python packages installed on my computer -} -cat("\nSLITHERINE JOB END\n") - - -################################ End Main code - - -- GitLab