ecodist/0000755000176200001440000000000014517747122011716 5ustar liggesusersecodist/NAMESPACE0000644000176200001440000000117414500423773013133 0ustar liggesusers## Functions export(bcdist, distance, fixdmat, pathdist, relrange) export(mantel, mgroup, mgram, pmgram, MRM) export(cor2m, corgen, crosstab, full, lower) export(pco, nmds, nmds.min, min.nmds, vf, addord, rotate2d) export(plot.vf, plot.mgram, plot.nmds, residuals.mgram) export(xdistance, xmantel, xmgram) ## import for S3 import(stats, graphics) ## import for graph methods importFrom(igraph, add_edges, make_empty_graph, distances) ## S3 methods S3method(min, nmds) S3method(plot, nmds) S3method(plot, vf) S3method(plot, mgram) S3method(residuals, mgram) S3method(dim, dist) ## Compiled code useDynLib(ecodist, .registration = TRUE) ecodist/README.md0000644000176200001440000000455714500174306013176 0ustar liggesusers**ecodist R package** Dissimilarity-based analysis functions including ordination and Mantel test functions, intended for use with spatial and community data. ** CHANGES in ecodist 2.1.2** - fixed a scaling error in pco that resulted in the wrong magnitude (but correct pattern) of vectors ** CHANGES in ecodist 2.1.1** - added relrange to standardize matrices - updated mgram, pmgram, xmgram to be compatible with nclass.Sturges when calculating default number of breaks - added equiprobable option to mgram, pmgram, xmgram to calculate equal-number bins instead of default equal-width - added mstdist to use a minimum spanning tree calculation to estimate distances for pairs sites with no species in common - fixed distance to correctly return simple difference **CHANGES in ecodist 2.0.10** The proxy package (as of version 0.4-27), loaded by many spatial packages including spdep, overwrites the base behavior of dim() for dist objects, which breaks ecodist functions. A fix has been added to ecodist 2.0.10 that returns dim.dist() to its base state, as long as ecodist is loaded after all other packages. The maintainer plans to remove the problematic dim.dist() eventually, since ecodist is not the only package it breaks. Until then, load ecodist last. Since dim() is called by functions outside of ecodist, I can't simply specify ecodist::dim() in all relevant cases. dim(dist(matrix(1:15, ncol=3))) should return NULL and ***not*** c(5, 5) if the correct (base) dim() is being used. **CHANGES in ecodist 2.0** - fixed bug in crosstab() that affected expansion of single-row or -column tables using allrows or allcols; changed result to data frame - added icov argument to distance() for use with Mahalanobis distance - changed stress calculation in nmds() to match vegan and MASS calculations; formerly was a similar method that was monotonically related, but not identical. - added plot.nmds to display stress and r2 for NMDS ordinations across a range of dimensions - added addord method to add new data to an existing NMDS ordination. - added clusterlevel to calculate Mantel tests for specified groupings - added logistic regression to MRM - added xdistance cross-distance function, and cross-dissimilarity analysis functions xmantel, xmgram - updated examples in help files to be more helpful - added a vignette listing dissimilarity-based analyses ecodist/data/0000755000176200001440000000000014452055674012631 5ustar liggesusersecodist/data/iris.vfrot.rda0000644000176200001440000000043214452055674015425 0ustar liggesusers r0b```b`f@& `d`a\EzeiE% |@F?(b.ͳ}ö+w_O}ccm,1?VEg ֶ}n%w=ٽVe[ N*c> Ǖph.dNR`O E PI^bnj1- U'V N-HIK/ɀqC3SB<% be2F0FRPHb0A4 >]W̬ecodist/data/z.z1.rda0000644000176200001440000000122614452055674014124 0ustar liggesusers r0b```b`f@& `d`aq j 4P! uT:GǁJ~DEY(_qC9Pqy7[ 7(;s?禃Tb[qP槊?q..Xurk-TL\s`rXnAi}> B_ jW:oPZ"~A?[z z=B7@(E- (^e?E=d7N^i߮aڴM;~ǵ7y}t̼KmW0{| G΢ 3O-?|MvSVmx& tú㴒s7 uuJ}St~ICu")֮mFMI>ceŕ?Yanq0PO&\yN#>asW}CuO_-XbdOV5o'Aּb C 9P&[^zQ~iLx s ,/׃ Jՠ;t[saRKҊ ,$AڙCu0M(83?PsCqɜecodist/data/bump.rda0000644000176200001440000000043314452055674014264 0ustar liggesusersJ@mH O>Ff&}KuQ ecodist/data/bump.pmgram.rda0000644000176200001440000000113614452055674015547 0ustar liggesusers r0b```b`f@& `d`aIzE ` L|@9:_?2QAqC9>n(A*%n9*ڦA`ɭ2ys;&mr067u{[irز_Pw- &r3Wrqsp`(݂'!|t@ߠ:D$ B]@M3 z.n `K˞_\ǯaɒs5Dy|/s&]c>o Wbɷ̈m>#QWn_Jx{.'a&?96~{tMi68^s~~Rf^80T{Y ;25Jɥy2/<]=ZRcN&1^Hc%E4%@%y@64)2bZ19P&[^zQ~iWZ%@2#$Pc% * P3R3S%$1Tzecodist/data/z.no.rda0000644000176200001440000000110314452055674014200 0ustar liggesusers r0b```b`f@& `d`aqj 4P! ٿuT:GǁW&*:|=n B_ jW:oPZ"~A?[z z=B7@(חh< f8c~k;{JgrڮEWbMiȵWod~'o DU]f^F笰E$_GrԼߑr*7?tzߙeG HqBAּb C 9P&[^zQ~iLx s ,/׃ Jՠ;t[saRKҊ ,$AڙCu0M(83?Ps{Uecodist/data/graze.rda0000644000176200001440000000476314452055674014443 0ustar liggesusersZ}lT?Mc!p\߻;l&~6H" @RеԪԒ?Z5T*m%RAiUhH4MJ)BU#G$MPMBKz~>YY̛ٝînlx<=3dz0k#O,owBC/U^Mwo]?<},)~?wCwxln? >xQ׫MϾ{_Vz(ߛ;~3{T6 S`ݭ{|}#}gn?vz O>G _lK[_uw_B[No> ~zlㅏ"~';H~90~yJ:?|f|%ܕ/+^lW/&ڟTEe=r"~w>z95b`ARگhl?$|a(֣ZM`s`DZݰr[_j24♡V{#ױB*Cj.FwbIg5}cK6os']eZumτ_v>*6 vko% ]Mw;RZZE;3)]u~b]W20 ~M"dOFK[cZ&\vQF3^~Ac)Y%:u6xz?򑬓@Oq?YǙs֍'|%wuy&[ޯ;v~_/DZe󫊥/0.qf_>G1.nִ]@wXG=rw{U.`oabЇ~*/"zCu9 Os);NP~Sre}f`l(I^Binv0yz0^Gم*o9pS뉌?掞wL_ F˪~X*M|0Oҟ׃oO+zc<̋s'@&>1>t_|Ir鉗* ?W; N6]pSMz!7SW<'~ 澂s.^8ckC }lHLOM#%KW?ye\QWpUS1/3zgGzuxqf&yź$7F1rQ\2q'b\3v ǵ[ q/IKÐ| (ӍWGb6s4@^:(_V:֬[ =ahêzWAkc~OZk|N0Ϛz7y{M%_uw%76|d=yg<=o?G`c>1/s^?'y~D4KM2xN8h;&fo5tLef}r瓿_sB'<5k!yBOg}>'w7w.wO{ߧ ?{ k \6NkN}CA.}))?.,uU7\>ǸM_y@罄2'}/%q¸XSil9CO۫azn|o{X@,h+|{0~5o'kwbC}OE"; ~1u8~˼?[ɟ D?=?3OE&?Ρ]?yX20gMw]wJ|{={]]={?v9#Ñ& Hf5Vo;:!SJHS+|op3 n{Ns,lkkwl{G'ښ[FݶXmm3yG$[#d[Ψ5n-(*k[Cђ[k_!n=;s*}0a}pJ[3K2[.tK RUn %AzPЃ!Mx yB^WzxP!=(AA zEV'_ʆuX{#4ÒHJIC8` ~90ecodist/data/iris.nmds.rda0000644000176200001440000070472714452055674015250 0ustar liggesusersym}:]oyGCJ3 C1_8м%x2o|?ꞥR8H!qor~M;v!_ egAI^-FƵ>3.Z L,4g\o.9)ߔ~`pϙs>'`RK AG& (9mטּF1L7.UX0.^Wu)},h :[vNtWR} zy[oMo+<;c{Цyw }|G@'k[pضpu…<8'::ԭ&p]G?x2 0&kb U'_#3".l󻺥&1< Ĺ`¹~"=|js: {=BL& 6zѮ9PN7<0F柏_ lZn]m5yV1[^3}9Q&e >4N\?E>Ჾkx18"kp,/ځqf8HRlS4f^٩c2S͊ I@ ؗ5A2/;zΦ/[EQz,0ab8cr6W0 ݼz4'0nG.O?#fW};y#ݭ1z'0 W/i..VQæ^E/,11Nh|MQoQ|p"i+U_X1ڠ)ep#+`|c"xB[#\nDɾw+z cZaqIF0+$2O7/{cڴ `Z];BT$hovXs-܄ƦϘUWxl.HoS $PSܽJNCQ[Ara|%d/:=5b)Ұv9.-pp[ԊS~JԔuc>WI׿ dʀIpKx`zYGkSK. Ȝr8J*/>}V6tZ; oY%(TzgC"0—{n`.߬KP}fd)Tj1#*? KFp^ޝi/\%q^@ g̓D@u蘞:{_?eh?FixX-q# PTy#n$"NLֆ;n>ݗdv¶v6{1Cr FfL&?z0Ֆhq^f^D6}SDpEy?ߋc#ۮ7*!\ci- (|G|J,ApYgͻ!| œo)3"LĜP;aw T#qp:QV-fVj`7"4| RkbTʅtKLFLCD=BHr=3Lj"g¶i6o) 'Fc|N&m"x)c{]1}`4țМnX)I6RC/hO|GTmM[kpjie#rz=Jpb:E+i`pC-ah4Pv[?0Wet/ Me LT}&P~apظɩiݎ%zksAPo5~T}aoAGjʶ`oZaX{TnpJ{k jiCA_g ~S;;}$|,뿵*DNʫ%Pkӓ7VTj (_EGSh {3)( =rllK<Snk3],`ȃ9>m=p(Xz1qIbZ1W=`eZ, ,NY[d /lH`Lɝ  >`LG$~zh3P^V2zO}1&uk`Meb>XJns>N䣢 Nxy?/Up fϢ,h^y ]pt LU{eᱞ/wb,42>{\`5'8XW|IC} oFYԀid'/ec99r;M~RQ"ڊ>3:5E1:'4*"\3W]~D D|_s2A۟sW[I ќ\B_/# Wo+"?0C#(c[}pY@D֏[E]D2fjt[ C?`'"CsƢ"<+\wF>FaNFw/"ўQӋo8bc2&KwUz6":lνDj"9΄'#Bek^:{yľ04=b K[oX ߡ/ۃ)Id)̾CV`$Oj;*,}#-YAE.x0)0N9NϰVFkVAI\!$h蛰%McqZ{EPnm ܦ)ɠ{NS]z f?T3mX}os77MB`u/.`j9\k_fv~j΀: ѻ|X) y#s d wɉ?A=H|裆'Rґ"PTp#(r0sTt2{tfWcF>xf;7t^7 I;%|!=ǞXoV]80hVoySR `KW5l8FQ'uy|X*ۭ?2:Y(0X\(hVV+CS:Ms6u;!u39E_>3Gr!D0Sc7e/ 2O28޷Ls~ K-MnaKW{S Lǧhڢhmu!,%v&`tv/dY6~$>&7]Ư:HFc ֺ|G%*vG+jbxfs`xo30<;loY 5FɋkP4V DJ>ň5_JNb${ZUDr3 |'zm3њED,ϨB$yA"F+HĈw-Y֒Wh q(MbNb놬l "h1 Lj7L`H{;)kbicg(.+[8|t3Uv?Ҍ-"loy##zi:tm AEf*(U1Mx:F3HE||QK8WuDtܥb1-)(e"0_i>c?!!ỽWb)+CR[gC1Bv+ V5za'8LR_-!+)̞^6m|ߗ~߼E?⌘X9Le`={Ζjsdh e-Ys-Q(@϶ 㮫F~ 'P)hkܟy$hOy:or ojݥ'bjTK$PH}E({w6QOFw-X ԽC_tnYWnyUͿ@w0_l8}1 km^슸"h5ځPxЛ|)dt o{=8$*W=a%5y1qOni])¥E̠ fv;.p(oQ'<4=[V^(-=O-\S@ R#G2i7 ɶK'8a5#\:aKs'F mʹ.F6d&S7sE;> ۙZ'2}lj'ræ<%?>MR?h/ʾN&>"FX\Z֜sv҆Cʼ:QBͳs&I|2ksu^ZnV64IU.]&cC>D([&p\pD ձܩ#&2 hw[8$RplK{?DQQ'Aqi11QMDbcrRGlq#O-!RCͽ{1F:?Tt#|Ȏ(umxaT.og ~[DkQ hT_z]헧1rˮ/)ǵ# 1^"N<}5 j_ 1BWw)D}r+?}MB%=DLxQ >!BD\]~9O""˓t]BX>?(Q/ՆqFyKX8Fk[v"'Ğu/(aܪ}FRٝYFqc{]pU Tz0ve#T6r5WtXl&F}]{_,\l. {0A @鴯18 G O,'i?_΀O?w+S@_i]0c1 (hKVV%I nk|CCE.LnUAP.bzo{êBb@uƛY_auDqefoC&˜%c3<p0lXsj=IR N4dzpjvHlx\;ZCJiy/g-AIShX:pu#e>$Reo;\|RM qitɠvimpԔ݋W Sj"`.#EE`#n}#\0p(Su weÑD|ppEL^ X?"]\pXBF/%30&jPDlKۚ/"㛱T Gnяk1z3p8IƨvHݰU1Bۚ .I'uB`Ӎ' _Įyp^C2\ *i9ζX`[Nf8ZnYY 3ӳoZkIWد;pj<άVh 'w7ȍ.[rk9}=)[ c?Aͼw;Vo{Pa8"w""c7S~D2zf+H]nݯوdK"j7XD,/!҉2‘{o,{7qQ o$V7!iOW/{g/"kҮp Er|qÆ\-|cf( ?(GTa*!-HIDqi(&n]Fw+D:tt}j>^B%qís "" \=8&D~R?^:GCjA{cuAD/erpLʗAyUU{hϨb Xzpx5#p_{:bD4cN-+@ #N9w&Jmc`] փ9O2؂ De!X|7ZE6p|/+A*8M#Yd]#vt~c H7naTj;2J3Xy|WZFQQi[EaLAt"V?Dh5hDn r1ٯWG&>ꡚ/\Y&Ł9=]yiH%a5à)pd|0\=O.ewXuHʮgVpƥ 0"_eSt0r'/ L)PϽ S/YlA6;]l,& N [#*{9!*kׄY,FYP`B p)$NDg0BUA<|^F7[J7DŽ)j:D|}h"/pλY?NDqo$1fY17e:̟HBbμBoDx K Y0U[F+7SF``2ef0%64xQ[݈mǒ({;.Ib$F߃<i Ņf]F;>/}(Ɂ E(6v^c][ߗeËղw`[խo` wHN;#Q F'6T/&[mlb[Q79kOGfTG惎Y+pkk@ | {;5E pnFr!86g1 ^U Ij܏VvX3lN?~7(zcrK78l>"Wv+Ie&rq#`aܺyF>\t=(NԎ9mS4g Zʮ!ЄƼn<e'YN` %; q.  ,$pvO-z.ച͠4܌iJApʹhv=Q,]a_E]Tr}0wp.N{vg[;&4c:pi gq2h|jq>jt *'(nj=je7aM毛h{?V8$ )kwo8sϓE?lp>mchKr9i=d 887:5 m,&g8]9 SnԑΝf+(v? g5 ; |"Oʺ G_ecK 7rHȧ:<:f7`A=[0„ C=Jc0#Kň/;N$G'?̭bq7NQb#˱s;s8ٞ z}1KJu`"R$;aO0i?xtR$#q5ye _Vl[.Kv9^t{ on~QDWt;DIei6H:NHäwy!vFp. ED-<ok|ݗ^ՇH" =2Y7f5xE^>%}"]Z>%j  Z÷B5jF' a]G&bZ6̌<@^?p#^5'O"2{`oPFlgH7g@~oWϡ,Y8l:յw=ǺEm6 %*GF3XpJ _8rp/Uӄ mė"ڊεbPnqX?e[Nò]a{f ֛?A bv͎ݔ1֭rR]oأ^O [zu|hAU[ %TYt$qlJ |2%,u AGYؤ8j j2M؁/FJTߠrvVw4l|R=%*EYnko3{~wC00j=&hNfD &w%#qu/GJjjX AB!8p pN$CLNo,DM!Ehi;#_<3,AWiwl1F ~E[~f N *tq0.M7Ol}H'͔8/{)\>&nr?M~Pv1IdvٷQp*˓CA nX> [+)dqzΘR8Mj0 ?Mhtճ ww&pXBQ 9"{Sl^ Fg=_w2F<;F0u[5"~GQO{LD{}{}QF({?GF,%ވ\R41a;Xi"fKDV8]u"q/8~150FPyDB. HRv"o&:҇(EMT R1ft`BswS汋;"| "K\w.DNYW#b񱎆IDY#xdvA#8Dv)0Uci('Mˁ?02|!+0_dxBSջ.0`k;q0/;`yE˚zFplm=0awF&> 0F*@?I&/;@qg&ϗm"R/du"0>:-su#oVH^ˈ,lzݏCa;ej1DT6J4!EV"HF{3v6! j/RaD2LT8Oz[sfVF1!^Q_HWY;܇孈zP/=uQt^|V%026<]Oua2"f #d Uk$@(S.-P7s59vڞ%:g 3p.yԀ{V5Ap(8*׶I~78 k_ ~%1 }C|_O>%]ߢe-W L`u~ D>qϥAn<^i~\d0(8# #>)m=9ֻX݀h Mʶaَ6p\@%S z gaf {"2Z*J[X|g Xfe ,ZbZNzK[ ^o@gǐT1W= KxmC<*#dvӜ18"KWJv̴TELkSDb7nAm 'S.K61PĉSPC5u+vK:vGh}Mgou>TvՆ[uZR+`}`m!("qL6א !2G1~!?&ϝ:^qaB`?0]3>+o8я] cky5Y\"ͧԿ[FC:8|Kˆ=V>ci*+' FSG"ZQ._Y9'c"vƞ3{<~zmS#Z?lF.O#yhuZu`iΊ8I|ԧ1pv,9hk4 UL@{Ζb˥Wje:micԤ Ҳñt%Z`GحOp|6ӂI2T\u[ΰ7\ ^ b&LC2AbN ݕakr?]_-P%zY۰yOq.bc?rbϋJނ8`dk.wvYȰP=/ENZ:/b0n z߮ -Wq>pH  F4+2IDuOD5]s@8/j|±"cxyQ\ =$#Ԯ[>=+D**ܠnxh~#]'v3v +_VpLAL'`a~.?M!{p^Iy7ʫ:>BTApWfσ+WġnJ3\ ~NOh3]+F{a2[/=# 02k7W1|X#R%1rj';KˎQTf GM?*E˸h=O.k>^M,Bh9AnQNW0҂jƾs#o5y {>#Dice\K$sQD\2F;h|G5"zfg8Lx1r2bV¹c]_6dh^%p[s$~()\ֺ3!2z"Y$0*J/DѤEMD8Rrt5I Vш:2J`D$D1CSL$Ye~MWR ]lz 2=æ YEEؤK̻.[-m>ś"۾j I}J2lh5_a)i@*gAW zX( _W >ZM^ϮB~4WU.KTW0e=n-`=#nB$|!1<'1+b`7g]<֑ 3^l85ZS6$H(>+@OLKX5Z;#g~KW"UK`[#X˺JiVp5zf3*Ƚ]߂ÊE>%B2_  y X6J 4O;ÙRҀ("8M0kwScx .O ӞqBԀKp˄x洱.v}&' ,wmkַ>:a?+w_ZL&S@RڄVv *s=sRg=!5r3,Tg'`}CѠ;\uP/Ё7J|a9CbaʻFzL怱cu0:{w 0u0><2wsCŴ5 表P8Iv#X:Ux0ox(Vnܾg4`DhQݜ7`Lwʧ YbK hћQ]QHq AJwFpy߆wZE+wqolg+Vڠob-uͲ=1{q~NR,Fb⶝=n(Wmkޡ(s  ؘ}aGR1: #A퐳189bfB1&s>fHCg^ngWhF>pQd/s_ÈGdl߲}1j]jO2Fz\bT+ۻncANQ?5F|7e;cWQ^zʎYct}&>r~F$.}|1s(*j1Md3t梫$F]'ī7ép%}+ƨhU3Ǟ}z;d gO σHHy8ʘ7 Rfy1ðX/ R]Lwg^T): N'}Ot]&uJ|ﵢ= 'V#p9Q F*Wl?WIޮH\b"eBoڪpI"Rc؏Uȶ'#}hpt0pK$"Fyr+m,u6Ο>և|tǾbJƷ#1j:MFpKGduK{{ d e}Dĭݥ70 ÿ1ZQ $cYiL0Ijѧ+aK L|³}1g[^I˰""$6Lj enbm۠84If;}޲ 's=Oҁt)pJ Õ{ܫХƍhv`peL޿ia&)! v;Kp8x\Y8 ΕeO{I{G>:õ`;CxνQ{ȓqmgspu܁Gpkw"zpH:"\o_1\|$@.G| νQlpi?i 7o $lϼ7g'Έכ,\y"6v[cwvs/WhåFop_}dtm[ w2\hVo\ yZvxT ֥w}u3ਸΧ^a$fv E"="ѵQXL(Vv6D\D{'쌈5_wKN"ldovDuӔmd v >r -cTQ#i {TH 5eB~|g lrXDNZwQ󸾈""Dl|8$(/b65G`g\C`dΘb>rv6{?QZLκcўK%_,\Gcozaшqrmԭ_ynE4b31k'è0 Mby &1ǜna,'>#հ1 }23ռU_Vؖ4/r\B؏?@4>t2t2ͤ2lȱ8wS9Q!m7"ak|g+%>]P+. f?`3!V0vA#0V? o /mS^ۛҡAo[;O<ba_'o?wj/(?I[^^GX@U08A9 3%ͫnk\J3W('?',v g zjesႰ7(۳0gt[ɂEC m_=ct-0K~sY7 TTWܸıRǙC,ǴYPCi:fq1ĝϹo4 =V ާh4_И(:51YpbB^5"z Δc]7~ 2LU%Fv _sÉsxHc "?ھ߾2(hm]ݘkv)bGlxو hX÷F!⅞6G8ˇQy`h;! xhXvgX0|9U^DZv6Dd5lV342$q1v ua;M><'D10*`Evo%pTs#H![U}V~7W42*Z6}m3A%Mӷgr[pWekD [bɠol5 >\=%:.dڈ( Źl` {8О`gͯE`|34r)6q'mp)YQg4ۢ;/>wO +.aGL8^瘸ꜝ^F8[y:KNQmWb:+џxoloџeUR {f=0j||LIIv9JNT-#XkPaDP Jv}3ݘN4$W/CK'135pq/'eL( răr$C<ޭf2= gr̓R޹ԬsΚEOl kpuX r1ԨxSݠ@cҦe&oUgL[l0ndk7L FvP7z9Lm21r' ޅ׶:e\;yF|;#] siyyIv aԭTمH|}'"80R);4qy!7:h&vJhYlkhF3B$@&`oi&VIxPOnDq3F|۷UOUhNEP1B|#Supd; k<9Uk?ooLFF3hv||$Ĉ-rU7zT\wQ|-L|0_E3uI""Y~ptNkIʶeOV|ծ|C@TLo8p\>tL֔MtR).(x&?XX^$C0OdM}8/ JMlپ(?l_e1_=0•N;*oFi^9FO#+HYIFZG-1=OWF&ۛt\4F7{{.y`; >^!j#<54z: Ѯ= 0J9!]ڝ@5F\~qtOY1tucQ.?cd6#&Ma[k-nkᏣg1lL+!YEfEogp !F>m|>5i*X/,`y]裲Qʮ̼b0!JovT9{7NϽ-'QWK0rsf ;8$rH~.t,K톅jl_ =sSzC 8ckexi0Thij~`)skp^-, ?.UրSԡ q^38n{/ [a,Gx8in!jT^ oaõup>$p8ޖlu9DZ8U?l&8RhSys䲩%dQF. p w-=8k{(yVr80%[}f-2o3`m5}t|,ۻAz? &h\`$[:BĶ Q$\O#!dA1=U~gK%ZǔJ`ig@u_6DMzwz{Wz]ֈ\$L3r}pQ0/o]o|7ZV֭+qOԔB4~0WxkKFD{݃~:2H Β6JC %\ޕ B /sM;?o1k ڢ29QzH#ڶ+{jwpi3mjt2x:j l ..%uLY F# 7vM1|Fbᦆfқ: ;oEVHfpF9ufgXnEi>Ȱd)&^1sn#OeA)H va;!3Ng~iɨ羘 e>M?m"B8P.?8e Ly FY&5`,Ѯ:~tۧ'/»7Xi5*zw*< 7+{.D ޕP@?o`lLEX--Vm3<`_ ^ѧxjP0@d ~;& e? [w= ._^gZ57?LX֣{fwd*)uݽ|"ޕ=\\~g<z=KCq7pmQ/E^uڨ3DZ8꘭(u:lQmy j88T ZʇcQTe8k-?\kwo sҔgqcqs*5鉬r~g?lctE =yVuL'j/4  ރLSquhr/Ɨ fZ! pkLn>l4kAy?$J|bսaK|K>5/=Xnډ<{Agpk0Xo?s~"3–_"fᴤ*Ϥ!IQ] ^S_ԉ/~+ʤ_p؂( ?{lmX zcK`ot0Eu)gځyԝ0бL\y><ȼI=?Ž6]bLES8j\Juծ.ⱑۈq8F#W\\P@igv#0h:x+%ñk wMA=X38rjw7:e+S0D_ fNYhs|x8\_ad~ oͱy9'xe, ,3/|@S2h,q>iph;V*90Wf =(~ >18x ։{ )>O¶}RysTވ ̼Suz<Հpv^5,߂lQra?T0t`JpFH] 0okjI`l^On!9azm)K +#3aV9w3Vky #V$7;3SH{tPN>?nvJ9lk{XJOr%Ůw^\W̺Opw"x ;5\' {w4ķ}wDq]*Of%EbgASb^LnO}2JP ,NH,fg@pX_kXspp0@]"g;,gÁTݑ7)ѠXF%rc>]Wcu=0S%#2Y*l=MD8LN8J~rX1Dѥ`<(Wt]Ve+`pGf$Z04 A“_\eX{Ymw,T^s3g`~ݱ7s@ 0B7v}ZxޣO=mF&ϏnK!ji* ;Dj.depx g}MyaJ[AUjl9ߺ,ti${6ao.!`:ϱNr4`c=@;?xlʒgfF|%jZu&׹yrAE c8ƫ 2a;\2lz J@稊5 T ,v h?mvj`8?4FqXfd'2bSy00>]-,\%HrƂbAkIV X .>Qwvj[r=28] -tsZj`j<x`ӦTt<}R+96< %$Nʀ+`@2yA`}ĩt~ a D+{m:yxsGeH~^~dmeiCw#jETZ紫ڈBÁۿo{9]BW3+#=L,H{\ziRʫQY8!yr-#ż>K!t~0aÈtG"DJg# .sđ_clvwX1DG- ڌ-{!Z+e.~+.5EkbBk0"M:>yHqՈbנHG}Bao) D?%yE0&sCڧ>F(}8ie4D䬏j#ZǾ1&-; R 3m{WO!ru1"~"-b@dEUu'`r ΍&聹O6q(x#.=`L+E־Nwo{XSqJ_!̿^p= twv|E/A 0 #yO^Ge~Ɓat sf땵Am{qӻKNA0 Zz/U^4SCY<+0[W 0gˀQn;{XnyJl6_u w]z jY1ˎ$ou.4m/lu^'qjbc1LUu`̞^3ˠ]#Y}mz;kfY}t9 sU)a\dFJD+F{=Cli:!T]fsp ,t~B<0\q}s5aXۨP1 eao>D|]m/AҠ0bURyHZ?F7>`%1UmyUg".P mjyۭa UNPrg90j n,+ pgG~$cg|wʹ(|#~7o`xmw5_70dViRxbэտM\ˣN<{䙈Fd"fr^p:WL`$@_ڻ`1V\4Ͻl ־Lpc-:G`)Nʃ-Uo 'Z<3COKQᒸKy=\H_g/8_ J5ZN=.f/e_Ͻv_*@-* F/?š?祊_]' pW5 ' p)2A_.:9[iLНcЗw;Eo;h1 y/׀l90if jIV_w\S^u\%݅TҚ]OtƍrSe`z*HM"v} `>(ct(W:B;q0,^5xZ8P?%災6\{ۋ@ɢe@o-͓6C&I&? cu +SJ QCx怚MpwƮ20R{=,q-/ D4A_gtj@&Uq%Gh4Zj%S"H}p 9? sMA+;_`)4ޭ>>|lu LX%{e0~l,I}`tY?Vs"=`,SMtql<i 5< O963S7c | 5f?h<98 \y􏔘}fU`㌹A0de}.c|w;nq ݬI-K s[*Pf9UGs{54AJ.3G/Ͷ̸&k?{U&~оE`঎y:nn=C[?X([nP4I% nO"fkUWE9|AXD}s1" 0u8#|JHn-_өlX,ɝQ#T.^3ڣ֙gx`dghdBLǨ&qp' 1"Yփ cNKv6MCtb)ؾéj^xEZ+ow<G=fdm OLyY\p]KaxÛ~a6oFcxcvX[sFpymH W1ܮ NS`2#) l>,;!v#D $`?vax/1i{ j穯fYa4Wϻ|| ~Irm*]4ӹs^ ]ظ eb961냐(i+ #>: [:4vCDPz1 g?OP>4 gIt.71jyD1NWgSZ7:9[,) 5]ERX,\KS +Y.Y hῚkʃ[M秢v =O!`~%խ89YP"pMڷX{6Ϛo<X3A'0\/b^>kXzHڟbfQp9_Y=fi|$0`͙n)SW`!8mPxYÿb̴e~% ;OU]'Ӄ5Ok`fig`~,2is70<$1d V8m9»}Z9g)Xm(}|u/>5/Rj\tfj’ Ke%G|9=U"؊;PB:R r4bgԹ5`fߓZqr$ʂh] L.0>ɶ+Q["8 /ax֢Kwx\sa[WX;zi:ؘOzRpxW8>Tt1\H$‰_5X2a޽q`.GWy/vwX8 z2g}uBR&VD,u_N~2M]M}pxTGe6`Qa g.4=FW>>v<`M!v827ʇ,5p21';l)&&ÅAvრݠ(.yBd9q"(j1o¡xHYO8HE[$ee<5IZ}{S2 "Ϳ}Uaك`>lqr8n1TDku,Kޅ;c?aoaLE¿MsKbWEo*#j!BƗ~"Mы v#ʈn _ ܮpv0+^ Uؼ-VAIVp=?g#\koO=39jh&nrqٔ!A؀GFf_pBBᘌ\azv4\fH x8?}q;}~|;' L".g.B~\|d*N܎ey ^0rCQ+802$A[q^eUpQCC3-kwvWj1\%S"ޞG z_pDfԛLu=TND.Ǽ2*O!fAH+9 Sr3 p5\ڣ "U\ Cp+o*QL Q Ӑ-\q<ұ/ Fd8RxxQ \jk riE "ר 3k3 |]ZF7*iB޳c$<?> ԋpZAʦ1 W25 7v[D8 BWdHlUT]1"v_. tp=-zpw}+Yb7O.~ yDg$"<0#O[0|ISYmjpkOwfyw;}XRs );\7VIDx'~erRW ZTu0X~6#}pWn?2ztn%s|?cI5 \5g^BRgAXBC*gػ-mҥ~{X|lc$s+& @cְ[0]+'s2(x37&7MngT>9P]=9PX+CV୤1苊| vLl1*[m/6r˝AꁃOܺ:W n߯Zxt8d@{AŲK*nla?뢰kj;ILYfBA+AqPy 蓶J-&ByFK}DcfqxFS 0ܣW-ұ`)OPތ ,q k]'sIa`Aן$,K}aNlf`}HWh WI N% `U~1"GO3WmqJ1`AI3>Ҁs]`m) X{ DKWCN0NA V,.U~]yTAJJ{_/\?XK IE݌G0k1 VG&fCr-d֚OX hh3`.A#X* N L>&ZL1 3U,rO 0`YZ04uߟ`>=n ׃[VӃ[9!.e4Cv^^u \| EC$ ດKpYu)m_XF՟pɋ6 HqJ\F9y4^>s ?L۹p .ݰF8}!+ /(g,7_^hANDD߉ 6Or ]Ή;peOp=zBĽpg\RT4j v?}#'7k'5Dz}m ־@pUHpԞم"En>hinѭ.ѿdFvcVDp&+$í߹uoG)|ơ=fpmԂC"e঻ZNI6vm?2t,nKofēk9Fc J⯎ŀI. T=?նB;nمzM0>[vvM̚9~2SX_WvoAQ[}0k-P]5E1؟SY-ٕR(EcTJ$)%YR^P$Y-Yc}pry>_>SƏUX}G -t.H"m 3^*/Kђ [-ix ONs3|;v~8q̣ͤUhs}FEst%2NzʷD'yu`}uhF)OPaA6~ӕCZD\K _C]>n5U\ qakihiGCq (PaknYQ-6ao_eu)(r:], Zj'a/z~09DFL]T/1JN . sEޅZe,҉h, h"ּfct-锟݆_ܣFx\L|G댱U9hiNu}[:bzW$w"h&=Jlz}aDߢijU}o1~anˆ[-V1uwlrYwFf6\tx)F.U6~x>ƃK\nCkWF1"uwoAf<63̊b=E0V FZ E Ѿ~FK+;YY-a$Y uz#)?Qlՙ74q~柉f&raIv`QOČh# ^u}6c@ cґ~g,٘_6 14Es'-⁤P|vs&!$Ffv4j57/u63϶.(F#B&3ZZ7rw :ebr?Ѣ"$FD"?WzZJv蛂Nί_Bə&3U1kj g@O ^4@g 4CwÅ J T6}5FO޶n}=詭{} 'df!K}`zM::.@;Txݠ@C؈غ3h 9 < 351ՠg/fgモiT "a]?u.BCy:To?3E #64j*z8xlR?܂3O:AI/stO=# 0[ȥy96>=Z.^`h;r@/{0Bh2~c2Z-+ܢAs6͡׎/AA^CDž4- \owfJM3hnM4I KA0Qbx^Du K +zPp;hG޻lk*ңBU'uɊ`x:dT6#[=,(n/bo+ݐ|Qz!tµ4nlCiy7\EAm^EU}_miT>`s!f?K #!arЋu^X=]Sd`xJq:dZ,1n;豍 MO.㑂#0/Vڿ}woSok ּ4d.X8{g3F-~)(=bol#{!ɹ>9U Fx{ΗhU=`Tѥ <V;;V-2`mJ+FJ0pPʦGL6=:0B{Rʏ1b]p|L2G1⩖1Ŗu$"&q F.SuW>roHct3mXF^HĨ:\-1&%{1E |X F#t2Ibq~ߞ` 9EcZF1ʊ^LF>}? #Ϯ+Q1фs%3BʊJWQ6 4k:888v sO<4?%Sk4O)ڃ)i]&^: ˓D;Xa q5MJOtpPm+t lO%BrqMOd+ 螪@i5j`'QPyN #u'EaH0E!yrD^XR4:}s*Pۯ~ ZP드v\Ԗ1 O-*ai<[Qb/Fc;&&S)7?(<(Y73(W,˽0*-V6F"cץ̡@Delkˍ̂e;W%ڏh=HP`N?'3@~WONU{#y81'01U<H 'Kjw4 ଚh6|gnj snO.*œipg=ގĉM)'B`/{\Ixpl+B8IQ\N#yf阆SW^俜lO5`\(q; VĔa@0̺׎f <]Gfh=w]G4t*DXX`D ϽԮ+b,v0:PsDCh͞OEJeq?֢4dsvm#3>JLZ)I$#V4{qJ^DhMdkDvkh#xɬw G:izkw17;}N@*b ЬZR;Tvz_߁9~o2%:pԕz,m,Dcwm, ,h1`3cx$ (GU? A͕2>Dcz'/@V뺍;mP2jmsoҘQ0t:+v,Š2Y0X '饐1>|rrﰛfUB,0Kf/8]Rj0H;p& W&7OGU8j~hr߆FLʕ06'_+lZ!`?ł #Gon%Nd=2pAj?N2 r` h/"b8}8tGN&x7N>!8Մ:N<9yg\|;{^%I `W κ%Ga{*YXW0=+kaC*VZQx,& f:f8<6ȍ 'pT6^%ٿ!|qRg8;XРV=CvgݭDVtO[8Y\wwDӶt"8ᝓ2i۽# 4]:- 偆h-{ER4:/Sֽ[@}BӯkAa 뻣б;V[uW{Tl2Є'1A{U /4FlS4IKFFBr#J%N7AŃFȮ($颡{J@dƬ_~B+oQtWz̲.?<BYMv87Rl]| -߇/ZhCI\:X)Ot0凾KgJsBTZ w3Gu }6L/;"cV'-IJŠEZ\2z+Xoxb,+Z PfX8q&1K`[R2~8"h!_ Qϸ +|] M={)9V8 1}F&BX&KdЊrU"\%~^+VryZͩ-GKK˟u%:)'`ns{(&"9c9FR_M#`>׌} D8h1(-^ kДݷ{+D5Խ@ DsW&:oJkFD&q0}Jȑ 1D0jfjc2 \=Vaqbm3YAk -hI~ E*O6E:yMМ;0wv y\G Q Y'v<b.v+ЬnEZr$*#~4]VH?o8#X*ZRR14B6oҮTf7\AKVnͽ{ w،9H8*Z( ѦhߋѬK_;Dl,dќGtwJǞ4<-@-CU7P&9}^F&@w'50"ksg zsOJKg"Tj˕)t%6ԒuX <#3 FY%Z|hų#5aWE|Z8~aa 0ۥ*j7:2xꡟ+mK+ ٣+#v #%Ӡ^ZIh8jyxrӳ2歶A۶SjzW:7>7|2 tYe^NƗW`>޼3K= OU`8n8O}4 꼊,NZSk0yտ Jb5s@Sl)vO0<$]U]0'x`%L *Kan{Ƭ0_$T'ʧ>G~eE0rq'o KH0}"^DLcPq:2Jk{ϿQ:ՁtE~| ~ZW_`d=45> Fn>HЇBb 9=r@'TU}z;`"Ǯ@#c ԓ'aX?(K7X` `2FݹЈ1*Q5*1;0W i#UIQ wcKD0g&^ Ǩ 'EaԽRchy&?#_}S`F5:PԷ}sbTqiz+QL~. czLOcze4H[`1}1FsE^t#ę0j;,n<~f0 bjFT?W[IEԑ➐}abhk](>a)/x#* ^ԨVU%seEP^bfۊbg[`nyX~J^tc+%D^T^lO 2ĝ 5m4I ~8tw(hr\/: _ZG``x12M!.mP7w䜘 os`L̀>x@?MpE/DP\ɎS?g,(Gq'Yj`nGoj?N.qONQNqՐl ڔe7NT6od`uH2x E'zޯv*>zF̼mcNt&m'gz'h7N3'0ڨ.^ i,^b()ؐ ޕ7zNT9S$35+o&T|á sg.Bg5hBŝ036 TuB5yӨ;u#g.sbx/ (Ġfڨ{"̪/-߭ӿg ihoa\SpgB;">sN : ! PzSu67(v+1vTT)y3+G4鞻%vb+[QtJl*2ykKuf|y i܁W?qN#hZ;uR'l?=ds\3P%6 EmcN0dZlT=BӒ^vDzu1P)'z$ɾ@g~2*:ׇ Y/2=wT>"?Uv֨mAH+ζ7FM]jA}r L@^TCYQw9f'3 70{#42_~Y$h GO︴zDu*CE4V.T pt7DMF3_AU"T9'c6nU~(2OǚV C_g)}t{ލoʨ]hc[jPhE$+zp0> د|8?VYF`1ehPTy{&6!Llî@vγ~o"niT Mn;1o.n)jBLaxTJ]TPq捔M/zes,D)9Mg*  $*[J`ʒI `4w|#/4VF@KWܠoGQU!/0NHo Ag&n Y6eV=C J*")8c}F[Ic5+Դ[T 강;z0$yRfS0S(L_pȾ Cc0S?,<V, thgП2[@WUl)iw<$i9[=׎W$ B߾ctqg,j6q]0.G0QWEZ_C=0zoObĪilƖ1PWt1j(Fh;֙Q]4_rz-Q.rkdY#_ԏH2Ȏ2B!/݃iiA$~c`4eS12i:(p 2Eg `$W_cBg+0b-fclcy#,ۆO-ǛqWamKc$DQg#; (rdiwȝ].Fc4 cUbrkFaa׫7g|8z"47;-oƘiA7b3gbnEv43n=1 7w6bwDGnu5g铲F0N}C֛V Z#ߛX aJ=U*xk6T= {OmYhu~fuh[r;nO$ZۢIdlh/Y;nwy|TTAƖ,|{A3gm]B '25h*#y Sڕ/f`$$ 4 CӁ)֧a NX`iLRGgPgi˼}>V.;#)0c vƋp$-fY+wn{c}^CcC(U5߹E|I gEB}5^zbnx?6[|њ^VCC3d7 f%~8NN49-kzi8lm9;~8H: Npm9gG7,} KStuO8niQIYʨS6ڵHM-e9l2~/,*`bqՁE 8YeONmc8pୗ8XN-_ ۥSŎ0Ǣn充_Q]8'XwĕZ570]hfNdNLIۊ# kqjXSN^ɉ6fq"?Ds#WVvﺡ;"6`26tpvZ;yy xUu5_iKQO="0Λap-OΉ^Ck~vGj)kZ+pDk.gEv꣍.l=Uy3o ^w{׋V~/M2e,ZgZhַ:`2EoW0Qc6[z\Ox4FaK;c*Z}C/Ϭ2w4}P@#??dʊԽNYa~Ӯ1'޸>)UL yَ=6yYWFЪG1b]n:xzQ10˹rUhرULVGFAot ^dz | 60t)v?;vjOVXuS%cl9IN| ,hv 99|ΔK*o4h9Ӊ`{4K `zW̆X]L_t_|7zYG@[l⌆*~j:es VA%-X~In y:KiC*0T30 S m~,*vqvg~@tTnGay2xjx8k%EKB.b+ݘ9 tO2 ѲYdۛkg4Z6uy'R]N*`a҃v5֔~ad uo]!i?^QX"{c5}һu^֖FyFR:s9x-ZcTch խc澜?^闎HEvr"Ik`59~bV^eɊ7x?Z~XV~v*rɮ:K )Z3J{f4m7`oI!ًhnuA #Rc/2,Dv[:aAQied>=Wzsn. KȓPv}$ͱBxTEؠޠ[\;nCqP;?x0ٴ/C5ɓ%T XPJccޕ5C-[H` y>e>;yàʂ t?)^CI@?R9-އSア'\(|XreЦT>hD7_[$6B[M> fʧ c4̌?<=× =y}7 Qa;O<} ~(Ӻ0ҋ]uҐ-le9Cȓ_-h:fL FhZauஆS6 p"1=#,] t2gƭ'66P]'Y7{%8o V˿=/=au7+66J$. /U80[ܨM}b~*)NJ۹Oa歇mͪC8MGISLuBw| ͅu\j0VBC}0:)rB5H7{Gs> }C՘JjNM. t:vG#p/+x䅟}IX}z %m'y rn[]\NĽ05"A辦xZ 6C粎̱4j!L_Ga7ߴ7)B+[0ĵ %@3/DWZC݀9$\,ԅd7~Qn=[ 2Vk4?ˬ*E'|.jjb ŘDy%vKZmCy/lrRտ7W},}"~Mt7Wڨ{v[*ܗBڡmJ^6ot,&ߡ%s6x7%e|&ՃP~7?&^ޟC7Cq9!+sGՑj\q( s"m+Y_F{aIrkDs; _946Jo1 mߍoمjn0#OXn;GorIiI-N}Ӊ%?0v1Ѱ{O kJbUVUXiaK̤7a.r3Fud#{',]a}3n(pk`Uo0Ǜtlh,'[̇ehY<+nK[^,Vw70_~[ Km՗WgT]+,~}s3, oZG%a.fݽŖxIaxYyX*kтщ44eǂch~nb>̳M䎶2֢ܛ|0KI~d\ˀo$'@O͍{W.%,:%hy5>IЏz%pP!H}~~kK֫(p!?hhp>NFm%PZ95:ٷG#BQ'cwhplz2&c;/!mEDwޱB"jxJđδJ ))o,wrE}\yztt ^%I6kpuc?HVcMv^F/3XၤM96J?LNjZ)0bP(c1MOfWϔ`)}м#GXYU#s^hq-9R5#GDbmSRJ4ܐ &4۾ח[9QUqc(|vҝ6>6~VF%ijnp` 闥?gFֻN9qsX;{w ڵo=fLh6ZBFdMパ`om/;q_( fpFiZk\UGK24#o-k?q pLqeCNE_=-g+kc ZeK2BNJ&тg_(C¯=NAp[pol.NVI?|puɎUc8YuoPFɚ ,csdFp苛ݣTd͂t5%aՂѮo5]Ὂo) kc-k:Wqut}D>4 V ;z{quqYT2aG–}Ro^K1U$Ͷᔐ7š?[Z`#KੳZ8g2a研 H[$$vNM81ûDrvOb-k ޹zqo6N9y|ыh|"KNY@Ehѫ0 Q$[iGZ<䗏Gm|Q8)nH/ۀFcj~BHScNڒ VJd_QDȧ,e4F7* XRԕS'Do[8QcġWljx>$|fv4 ]|. digCBUtlqT5t0[t:B쨏tmjMA5E-1W~N _51 G_F@/ϪۇQO+m#S eyNGCvĿPBf[GZ-0RcǛ)qO:4܃fw~DF Rhf/:Z*&N@k2K~eymhAtGm$Z{)H5V|jB6HZkK&T>rzFLi@|ޏhEca8ShuΧtGC%vPK^@{N|xxǦ۾EpCkG}v:#Y?B$m7pCbux -_1,Yƣy1%vۼ2:򠍓JNqAp奻1.TU{vI;y Z5U)՜5[ߞMocPkK&c5nk 萴 F p?[30kaWSI%1jc9J:FQtco/0*vc)xK!7Ff9],кHEIc ^BAȕىUk#8r؍a*FKF(bd#G1@i]vJ12CׯG.<lY8"#492 #>ę Yb{YWac 60꫄҄qirJ)Fř[{c^?bjWbEc?1 I#PFk+tf1~!1p^)oÈagx*1 ̳-ݰp[^{V2 fഅ%ZA{;Z@ZmZaM>3D#]ɷ*=SMحf)_#uk.03WOf}'P3@RޅoOJc|* ^+37(0rV> jY)1f?ߘޅgqUsMȜA &hwQʪ(AT-gB}bayvg< =Wkx,!wPȾ/(m 5(g&1.9W 雫,kEˠGzMVMhHzϦAzfelN-ԣƸcύ':llGшhU+w]ʋ)|hd9)ȆW'bKK=PﵫT.:x7u =[(R>1~uvMn_D)C9>Ç{*Q{pCD3Z`sM{ڷͼ4/+.(ĻZl'.@acXCLv1 /e'o6K~!#]c0}~Z,TUl,||ĹlcGQwv룲p4M NN#DIC^K0*;%Km E̫-z9ʹxǮ#wJ%5PVU~Ew+g@m-Z@PKu73m,[LBoR蛠NKvEuVo lh2f6P/e<aVA$g}iAryhUv nqAN_Ŕy_Fc^[υ!(Ou.?n5xVo2 ]+.k&Uv#_6 ɿBlm}0OgtK[:6;0;M| Evt!ڑgq8V=x@<)+B|rlIv>?*7uvrUPZnT=iIُ7@|\&8{{2t/ly!Gfr`+ȯgwemנ\.|HtG1#o@'= ?y3~O0Tw<0 6B+)ف9rf1P7\mvWq^7iƏcSi_)n{h[ؾlnhiIʍޘ |j[osoNi1*7mar =U]҇ n4|ͅ)k#(b[eWo,Ln&N,>σ=g1wPRj6j{U\1[fpsЬ=-hL5ţULR \_{yѯ|1S A#WAA3LZ*z`B~G.)Gx#a.2mLؾ&Q[bS b0s͵@ &o4Re?觅ܫjOmE\QOj5euϗL]Y5MԼ&U3Gō {|Z7x*~cgǿ+aOt1X9J@ C~HBɖAh>ί 569f֜$3(hu71i=mؖ_ѢD0*ň.WTV.1(-XGM:|^Yw6$?F<:^4$;b/H)|?aAhGj `{{0jpr9Fڷ+*Z%_fvylWHD"1"b OGNj3<_`$ YkvU -虾 ehpfbhᵃs7`ahíFhFtTB'S  }!T{tx=RD#ͻ|2GKMp4]*՘5=Hfcxl6YBKp?$x:֢ެZ:[Ւ(zOQW9몵VsVs+6gNͅj3IMe/pKw(9'QrL _-VvD3?:bkO?z M;&N697+2Whq' h1 494cLsusN76<(>47{};J(vBR׹3 YxT1 #fj0}X}`RfVv$6W0&Vh`6K*Υ_ 53b;Q/NXh L>dRܙPFSq@uj ʟ=>U3;PUY{4/0U L$C^zM!{P 4=ԇ>1頑++(_1; 4UA=`B֤0|>oFߑ \ FdѴ䎇c"]8t 67[go= 㢋[.:4>勏Z행wQYRŠ?Sq?uu.ZN}`SbSctx`u235aL@܆$*;zP7'EvbѲX*Fz4c&jFk;or8˕r/|F *8UO 0f==6rV=b'X_a%Ѳs8>TUۊ_t U`Gs3}OG:9'9l`qGg6cq)hSu J=b0w]:85˶Rxƾ(%4N]w>9Kg`9tbW2N$(v s1_7,4gw/9L5}xzhQ>Hᔱ٬*F޿8r nZ:5hLP_8\3aSuc;p nm8"n/m<3e8crS>NM8Ia5u7R>/X 8to|QTvS>NX- *vԿK8.?SK~\3J^7ũz]9O ϶L[HqpJeu1AwI᥋Q }N)O'{Ĭfq785ًr!91g>8tdsA"xdexcBp~sԔsY֜Ϫ XqE8'Aca+9VlvΰFu JP@ d UP=S'\#eiX"R%W_56{&ID4TEƐk}EteA+}>\vB+r'nZ Oc,?ׅbS-Grã8ׇƚ'nq=J%0ҙK0j ۈHDZ`KDaDg'DaWvWc.mX~t F4܂z_n_Fk9/v7bLKȋ'q.ZYBBlx!lm~]_Ѻko:b᯵.PHC ΠjhJLjVOY|@kxAB?\45:Jw%`q *Q==}*nf~Z(;~~2$Q_k]CO$Ugg?p-tXս#RN{`:X}HT:;BuR򻚠>V_&ǡ|ZFo*ѣIRm w힝W43:JAU~25Sʎ籑4DOws{,[B=|Ft$w#شB+hHin ;F#98X4xg->"oUy+|=jӽ8s8j%=!]44؆%CVo@? } :$Q}ˡeNbwhKQLI{}°O6 MdžLOKAܑjjÙ)s}zn ,wV0R[E@zq>"#k^jԝ'cbԻw~$4P4Bx?4v8^|F{YP5罓}WH\`~+2M.6pW8j Ԟq܀OR6hĝlj~x< } cQKFИPs:. b6y[wo=җK6C@ -u$]J^J0lŇ8GhR%~aO twx\n3Y>[2Ф#J?|j{/oOfmV.Xrݨv7_DH!엎"#_\SD~FaT6U5,Fڶ'羊rM1/YbGS*;0^R1&&TR}S[t ぢ=0&kֳRǨNg_(d1N+EjT'=F|e 9R2!) #394ygã@rX/6JpMshXC-L:"*]Sh/'VK*4 S"Cj>&?UMx%Á0aY#b>svfI'ˡ(퇈4_mdeA0n|ce"-:l`rFXǬTPOK(]#*r6̌ܜ&`'@| $H̕ 0pLx >܅Jʽ/!8,'d8M&L7Cchp>'̀ß MҔ/"7b ?[@m;8U׮/B0{lGҍL2+FlD%Ų8d/xc4r{jQtWe)hyL LѿG aEa;΁hx[q/!hZ97S][&q:)b2Zn]=BSWö 'bf?3YU~üX3L'U;-l~C%3dzC_Nd#M$z/[T%mCn'\Vıeh*heYʜam&/4Pۻ6IQ̝`͂-*wF1;Pp9U8e@GQp^p?{3#^|]zRď;dO0)ݠWU %S TGI4\!vj﹐{'ߴL6B&FG#vJ msQ"}lW{HbhqjT!qUyq7R-xܽ AVOg+? # `̱ʯ[C+=60o,s9_NazM44hH{<] QnC6P-Iɝx5 ]0 hc_]/򧁷añ:w2Fi8vEiM͔l.w)8tqKe쀻w"nY];ʋfW+VJ0`mnJٙLaD$=] |'r$n""ܚKԿ r4=݀R-\k`V@n'B7O$0j5;hm0YHUʭnl'jY`c2#XR6 }N|]ʑ0ΠyqNwƀv̀ls.4xWL ߴdx엂U2*e$+/'r_q!>wfv܃)%ƭ/"uz\}tחt7lam*sevZ*\9,Bqׁ\4:#ye!}B=3o~2jVh6nzDHYhfr<lqh|JeX>j,M~r}hC%)ۤXt5\<|[Ma6 ߜ` Cݒ=M=47OǽvcqC]7| F YxQ2jhi:ߨfwfɳJ"lDԱbltBAÏ3,_.}|W_=rQqe7<@/DN}.aYj4F5jtܫ1|vqР`ԁ \\xo_31l-U7-k0F s/̩FnQ9a \YzcR)a+sX- #ޯj Ek11߿FF1BaKɭ6}5+?H6d;FB2WXf\h^24bU0rD)%rNp$`3li{9NytKF|q |10=k.HEW5~ovOv41qXpcG Ej[ eF9pq-Y~ƱC.qI8NDeÙB8ްo,'(Kģ\@;8<k: dzzT9X~#Uʯҋ3_p򧟦&`rL 5?%W1[tqK?qOfҜU¬)Y{8hT͜') {Q,gV2ۇdoЇ#7bJB]ᢎo'r 9r?5!Fsa*GDٚdZRNI OS8Eo Nrd{26 ΟwyXX A֚f.毶xSBۀxpyiT ^o}`Fce*]-É1g)^l2M]5U ɿLJy`;Κ8QeN]q)V kROl%,;=W 9"D`y$Tgk%vއhb-;h3&{t`n9^ب74&Ve)i40b_< ^9gh]9 K4ׯC!70E3,kPI_e1. 0o~'> d?3駘ח}w`A/ ,RaھQ,m թٟ9*y[-+h%eG hNʽ=NC#{5__+ے̶SGe=aƕ%oݧN{d׮uJuL*m֘Up4U|}/1>uF2?I18hN{jyfz U7$F}cQf9tOLl݁^Wq4+p-qJh^}[|O[%⠩@$as<9œuҋʪFm;SnȮ@^½k.+/ӂh>>аu- :t#wb]) , A]_!O@8$f>0䵈&>/ZA_8NTȡOZ<'aaL>"v=-|h?^xmjL\k&ɟxy43$ F r<0a`v hC槼爖<~?>:wq 52@bQnp>>n@?O\4\Ǽa#8XƓG/Y NԑV.4ڸ=Bs=Ao3Т oƞtTC|-WL4wL%כwןQInRfc%4>v{8)$J3NQ]1>|>n:E)]/~|IXD?3et[qR.O!j;Ϡ89X-N:q^R' v)kzN8Shzؠ.eӤ P}z"≓tV ˽eQ8[ZNXMCpFۼypI9{tCI8956=6.pUKVq±w8k32Ϙ'V~ᔔS8Q-~8 d֊I{o_[NZ8Cdm|PCzV^ea*ԋD?jT8RT/,C}G_ßY1ߍw٤h&3mhuV +Eݐ-<{_(Z_OjRP{-h7Mn>]-u<~e 9_`ϊGA5'_D3_ɽ=i:mnkTPDH3IF#oGc!MΈwTЈ% _#ޗ"vhYRkW%gU_up)Tg2fZ}l˼?QԳ?Pg{h{y2DҗC톞scvP24to[SjXll79<>]B? ΪoQ#!HW u%=乸ΛtyRF*Zt0 !.>h@sj9F>S_uQUhZ Fj=#\ȇ;p-KDˍh%w;6Zt`>hEXA-y,Iڏ;hQaLoEc#=h=$Z8(4F3m?}k;ZQdAN_2B6>4 ^ M4'=c#Fh])ZTҽ#? *5ZXopQqJ96_D?YOhEK$͝Ա8$oEcTj쿙aq}[^`4P)*9T͸n6ʽ?D4EcQeչ`Ee1Yr|alk 4{ݲ@s7]Gū;:#z*ySh:tR7ڤ&?:TQ)[w\QOrLgOj8g`N"UׁFL4_ R`J(xldWCY$qbw;mۥI'`Я&q1vlF{WT,? ^}\J= `X>luϗa? 55<4P;s1t6G3a v8M{_E @!˵ 2Ji&YJ?(t\a\>PDٮ9Ba:crBkI_qBsFF*>!:)VX E {2s{M.&=m pB3뛚ޙTE*dq6R 2zsc4K.8\3ztn{7[nzi<ۢG1J-S*׃@.[-/N|fuLaL=N\6i(u!cQA;";_mS =}9b ۷^c|"clVuJ%<;<2txX*S=/WA]zpL2n'g]#HY8V-+gi-^b_B澰J,gi9҇_hB?VMM8߀Z$ZѧtṵCqb%fXh =^y0-T K_+ t_+pl%Oxm0U5˟۴>ZX4z1vj Ld\^Vk>1}`j9ed\?B}HcKmDN& "<"țY t{{f=:# ݿ8={ *l]=Z})t^L$`O%6|e'6Klla{Svճ-Rf9熭Ani0{=Aw\!ȳ9_6je=ѽ:aYl32b0YSZa9;ʧfr`@~)Trj[dM/k+  ,OB~ͩ|mω-rjc歛]anmY }]܆0TݹR #m3:o>pGL/$')lt;as-J9%? 3,g788yY*)w.[`Oݿ EZu#q|/8" mdtaB* as f[.ܐ ?m p삩 TEjyEOMBö-#{Ψ66zc>I1 S0g5P !~. ]^ŝ0BJKRh{DnY]yNci& J5Pƈð@YP+X.NdJB0 J9_a^ϰXUʆUѷl)Y~lI+#)t#s_Kca>[XU/Lf?i^VE3LІipWf ?nsɣdlҡ0^ͯDaec%e:.oY\B}`s2U!}Bv?}US'7SH`0kI-JHOdzr&O'm#Vm3̟? ȫ?=Z k:lsï av[yMG߭0Þa:wdӝ:|[]Kz,SY7~].Iay+8StOb6ɐufWq,থFN$SӸUM*fUֿ|7ᅙ NT5},EfV)$O V,0}\Ұ8)C6}eaC_y qcW7^cCزh^5If0)IVή32'+vB/nQ v X^ޥsvC8٣sMoۊyTL"|{#h\P}UW=dwWOlX]yVj X8(ZG=^4ü?蚪aѧ So7{psL_d粫O|O4@ˤÂ)ĨzƤWX4A2ڹ:5Żz? w.b+; n֪U?a l.0WMƽ*tҍ0l;j/MէHAWbYkaa X(eunq{<kyȦZ=wu} gDvE}| 5>h:Tnй$-60?=۳FVL/Z{ `esdQI'܉W&Iݫ{s/(;!7f 2i)m(t0q,:vrp+3 @[X\=PU'd{&H;#۷ k)@jIJtڄBqPBOLQ#E]9y]ba֞q?T^%^_|w>0|si?Lх>IYKPbU.d ]j?\`mG_RL%`Pـ ]Wmb[>wC O1߽!B84~ hlwzm"k+r:=Xb,DZȂޱ| P6u}{~0?뇕2آb 4ɿWVh0b$W+z3y"\=60z(NPx+OvV*Թ(ݱgS~% v~88ܿ V.#yFlora3>ɍ^[Ob7$|]E+)M\HEwJXptKf `yMYsZqP}tqLf<4֟[! tMq=gh#\S]fcQ.n.nMYeXŚ,<>|?-;Xhpj1%i7NK>filZOԜ?]a]djN9N.z#m+%y8z1`,V9tFư>sl̉?r^#CNalDZ֚+N[VCpcfz䌥AZ\soqDvщac;TeێmcOj4oI#)~c;ݝHط~ΡX>9hr{^Frt:X'GnZaXD8l0/zc{%{t8}ڶnxSJ 8flk/뽑^;SP&_"V w~dJxrFFLĖ`m}=. =H]Oq{`O'Z>I~s'r6q躹PP "ߞAꜷ-Ӻai+0zCG PN8cG>=P>YWإ7md蜖ZE0Tr ѝ[ G\qgaLT7`œ.B>#?U \>|po=3ŷ^ WSwFұ__߿‹V0Z L?zVCR8gh=|0 5'/VARlk;9W~+^OǾNԼt$VqnikVqɯ߾܃sCC8Aiw7aφmTAɆc{#?c}QS.=7a{HO[ 6 [͟S~`@ κD0[ %H|Kک#yV0Adl!h#qq&ԡ ni1}``>6A%\-pmU&mI]h)AwEeEN}vTԚ`pyoQ1m3 ;l7>Qlˌc&|ŪK3a7V!hfNl>G?Gy4#墂OZ# s07=)%`'&n}4]Oett!LiGǚTN| gmtd ,C'M;:!' GL>a dos3CmR\(8v% ]?/M>~> Dگ5@ؖF7Ч0Is ǵo1y&ﻆ02sk`W @ZL#VWW K-D6pa w`۸R7g#HK0Frэ|z!y\BX%v=r p 7|ՁlMU3z8v%\WscHB껞8uP z{U!u jT)7/%e ).;Kr\[\6Tа_Π0jWcv#rKg7٪%k}c cP), GMIz'M'@ndo?[Q:+%65宰d>͘M*JBy~݂Bkx)L |pPLo.߯Gyq$4BH)L*SB~ mIq:HE!%(ߠ$ڙ+y;~tj90M8wg8#l7,Vzoئ# *(4ZoB:㵻:PhsZSh=z7SP߻`&Tdn,~VHqy>v+Zp>tof$hl?\g* }XۃR'< :y&T7'p=A_`×妈\#h+)y$BĭjZm$υR r\]^)C7E %fm '\cuO=g A3!#ݖKݯq]5}~Ixz_rjdxOdU ҂'FY"HNӶ&a{I|22c݅nĿ@ݕp%gyJqzyI_ 4~975vN= 59x2v Oᐄd=Tp_2d~h{W@ꕡWoepwwx_˪M V0 5g0U^<{99K݅mJƵϲ*`APjeg t &HzR3լX?~z;(~(}f 3tu^m{l5sc|FvK2oG<'`[ge7Nq7f~.мx} Xn|^ȱ<?UEm`QnK錹_hD|4ki[i\f~Gʞ Gta5!M]`W=8=c<}%wb9zԎŁ |zd&!yeh `:cKOB0𯓱\ w~@tS)iTx0O2)`G1&|cY3CH2k; $D'5mw9GͿ6=Ƭ=BGyЃEbl3SltNX .!쁤*leIedO?E9Ӡ S5!4%KH*|3PʋmoMqLAPOyt9f1N> ݻ?V`/)yƩ3N@qw|u4>T av:Pn`놟m.6ގ>(g}ek]Hr蝗B+r% 3-gN`&#e7e&i)Ɵ.II _Zqg1'Ӎ]䙘^OsP{Q l#5ױmhf h|P(XuDP⑾SkJ}1+?q{ʨx{C$>AooǾYbвێc8թ8JU0ѦrAMQ+oq`z_4{v$g m{5cw|*}Չtq mB66Bk15GZt(3=Y(/_5ڠqA;W ڵ7FmX6bۢKs`XˈL)-!?0w}ζV/Thۿ݀ܦ{f ;QX?mU1ş+&CKKq}yuf.0'~cv&ޯ^z塕 ]{a>@M>{. P DfE,009!F.i[ٙAr??% < L#0]-οHNyBXzs (Qo:aVR}afKvL> Tlf/M}ٳ@?t.w6Tm|0`Y`Xΐqd%TXT~T)6Ϛ0o`} $B}aB8/fjv5v<J̘kuRLGTr^k{ebqCwӡ6@]nxk0:d=w9tKE63sϭ.πw?6`*댇T!'#Zّx$#ΞvHuǚ7w9Ee<opF ~NSK8zJ;mtel[/ AmߠL7L\:Xĕ΄[r8n"plc Vr#ϱuZm#1rngWJ@yCdc<ľli쎹s;´A&zW,owR7 o_"qM8`,}0^RwnuA"^kamXU,|֗LH{~wB7^Uj OUZ &w%PgL!Z-/;#8J. IbU<ϯ"Tn)vN\9X}Ѳm eae)6$I@SQ`/,WJoD^7YjCMnYܝDVL8`zqAErK>5{"n!/C_}]E&(HLzW$Q%:IBQx$TLDJC|YҞZX=G$CG=0a?+YMЮ =@mfPDS#{ֺ[ZSvK| ]"260(%?;m5{ js7n^Ij3ӼJd-|NKمB]Q&:[%@v!zg$T򅵙*AuN0tζ ҝ׾NB58yWI?y[:͍Pe Ok m ]oPQɾ-pwRK58uecELO yԹ >J ȁ*2r  :}\vw61%n3`4"&vbɍNڠT#F&Sl[ (Т/}2Z$m<_]u$nw  9qmZK Ac0{S|dg-vbՇKa6cChKT ʒ#?w\|#>X@ Ps߁LSxu%LLq8prǵĜyfeU?oJ(:}zEƁo{,:W6ets e~Hi~}XES eqCzn(Ч}m$Z%t/*2{3Z,zQ[:*\+ A:lJЩwL&DDFy|Gme&gA }8} |ZC\~peyf=bAH:J (tNKb^g RϷ' Fm%WRF5"HX~?SX< :/N%%=ks\mwAwg wV&.7$Hڝ!Hv? h0,T ]. })vMyE QNeIeZk9;tTR3nC8Ity#oS:$ZeA*kO&Ջ-̐ē[?a;'Lga !!g^U S;DqBsO(=ӁSdq y0h/YLOu~$Mddm{"eq]b}YnhToՅؾG`>#@miffl5%Ͻ0YŸ>ѦB %i٥@imq3_8x*L'eq̬ؒpyF+`*nH7ga=䶆Q݇Kô 'Yi^ߵ6gl?Qe>Z .geaI7*>˫FzsY2TOG~J[nfUV]d:VK)d)oq%!B>!Y^ +-"_QHk$o"M.u&@DOn sbm(,0bWKY^?д{)3Tjw~ 6L,Z)2S(lB*G`,п(tNC7\EXJz}7B{9H5) S^5.ְ*,adBK&.-ӵO&(ZMd9: sZaZk1?Z|I|yE )7XZ^1)` UQ_ǛW2(tE#7a*7_` '4a0;A7 0Bb.7%4/o;s;LiYŕL>kcߎHI&(`j9^T+vA8vlK,BߧxgX0YP &Q|xy;f!ersw"Ljc2۸;602Tx'#ikNcԄNҋ[7ؖ`ob[omu< +Bro3t&ޛ0&t6f: ~peT >}H? ig\9 p@olm };zcCOL#rʼn>J)+t ^ ЋA]0 {_}VM*g`UrWH|YQ|&,^m9L ! z[• pi ;԰}[84w- bgt1ނ9O$\X`462*jڈ n{>K>dƕBlҳp51iҍؑk"dF`ξ\ 8Cm6<8eJ{?g56nFegҌ12aHa.7jً Ukh.g }ڄõ_ qB u~@M؜yb;kˇ&+Wl7cw|ê_?0~v>ʣe]K/FcmI_u K^gv#3ߋLC^}j'6τAɌT. ʫooQuD`ٙ< SOz vT]W=CcO=G5`g [s9:` xK~9I48hK6V ¶^c 5cWO8Jb2l.(˻ fw6heYǙet8O7TS?*Lȅ-WW"|7f +\`~mRg,ᤍRKi\<$zr.{%\3D3J8[4NBWg ׳(8#6O"U 5vZܦTb\H}ٚNН7]pPZ> ~K}q(:}g4bo­k6027@\3\y9GYf( >ᎆ&! )onweʲmh))2In&𙻠l-?z,;3lIO*eCG0J/eKk. }WPAsK@6T}|,2{W%ZiӵN}. ty@M & @C\%l.4&p5cw]Bp{ h+S; OWBC G_7(t(wttBZ9'5k3U0IS *8̞BaR4S&/DѫX*`_,țz -2y 20yU7K>!( b%s`0C{qu(IlXHҩ>z*ʾWc 9ᰐJ0a*Mmլqk4sͦ'`~:̨z_C܅5DE=vX>>v/9>@7M8u[Сc= [{bbf'iQFNcAK$L 9տ2bցYXr5H([E HҾWƋ5J6a"RJ̩z +n=7f7݊E_xNKQHn)C[ZKKH$V 'E|;cSVoq:~&m! p=e2Ŏ]cqɔC>Io>f-Rex2Hcª</[>_;m ީcY 'c#@g7Tm,MȜn?Ƿ_= ~ :$s"ب95p?|q78[bmϸ 1dq%GfN\Sję'.;BpJK"q|eKFp2WpH g<͂j#eێdpw3P>ӺqhE&'++GLq~[8;%L7(gq\EQ{vHӍw` Cs'hy`w.~g>[B] [7ȢsrV:t4ھ.z{s g('qBW3yۧ,qP4셓w*Rc1h> %U]v8}g"j5R]IލSI$jztXHZ_PhxǤ)4L.luӗ8k1A+Xݑt= ršx۾10rx9.Xj2y(/Bc~'L}I07ٚvtt]xSjFys`ď{0t䘤%loU,_;U_c-a}Ha}-s} MLʥH^y u\ 3,>7\9 ,ϐu:f{? oΎj k =SĒYsB[A.,WʨmIa);QV"R=*aLvSTwb\s7 +Yzp &0|-fc%"3 go da?CW=*fܖ[U \QN(}2*vyʜ8V5o6 M0 fk_M!~?]i !${hR{}jkkcWvMe|WJ6TIƨݢ;3~&7dl}iZ=t( 67qpQux.Wkэzz‡ ie2/ Cjp2Az ΦWWfDU$rq0~U^bdoV7^9y8)2gl8wyF7Xm&7Lyk{#{#`¾A:s.p1׽ qzZs,%\+K^,Ae|A0۟0 3wOr`;8 zGӂ W=4U[/8#&᱇F5'pi3.lcu?+pM fZ\αj=7jp`|n8!*omto*=3}Mp?Caxo>M&#[ >'Zg7+iz9]/S!bAP|?Ŀ _{zڅK|.` Ibݽfu3 ׇ)kJ#ݎtNwiX+ѷ) u=&D5'Oi37>"tQ$reC vW )꽺쭶e ~2q; ڟ7hNTi6ο*,]NV gwNVd A O,/έT$q} '^"kl}ΟrQb%HL*s{ʓ$lT6`0#'fidY::k?] a~|þ(ãLjv۷`wC- O2Toca^Z^]RЀYUvaZXXjg w92`zS/)+b}8 _\?uLQP3|ʶ J^z aQo 0:aHXam;3(?po7ʿ lm;`6qr6xHm鄁M6u7`qgޯ0&3>EˋCw!_`{v朒@S,S w*>?ky>?TSG[zחn @=.#_}Cqo)=ک !зN! FºhTV [VUɰ\>4!(;dQhW`G4oNϟʺ+)4۵ ^#ӿ0uQP) V>X ]V,ֻ/nR(h-mhmB[LT˳wRy/' s=YQHj>bfwc`:^1@γDaJa+IG~yuҭ[F t S›l|ްSa"k4#]jQ0DqҺL}XF!i*UU3t5\=CCU>5As3]ʿSð<*Es9'fj0S{d34ߌZjz~˙k6CW1LsxxCܛ%쁮ygN8÷+/auϫ_a NLvKCE>ڙ{WA^9ObGBXX)ibbESu@16_jϸG'vl7[.Iy`5pB,PM`.';\ g5 ػ(9,c˦l̩Tdri=hoB;Հ53xI rFMILȲF9Ԃ&~cY€wJL,"!q<k9ucy)&, jx\KWwL[]kb~U~,l`jA!F'\1ʑ=W侊CvsѯZgqٚat@v\f-ߛi ;>b'ϛ_hΔ"Ve=<ٵ`ˉ6ՋKq1Rc\ͫOm"0#l|{#6p|}ʚsly1{[5NK;TVntG8ҹ*qyfڃ%Nd.洂>Z{|ip ZAɄlt+ɈR񃥿7^YñRqjRXZ2pOO݉m8p{,CyG и]Iddž-yp&U@! 1zM}ɋNg⸙_$v6-'mw6`"$yh0n[|o5 }?HƢj ]۰}ǹ^l)жPU9Xhpf vgc|Fe}>=޿++Ss;ɡ"UOσ˞Pe3ٳ= 5#z+B԰Kbu6On Srgs,`o),?öOgNFHaq/ M*cB:gF}뮣Xrglg UǪ4}0xHbni;"sOL(h:3~=~Wz¿+BN|Ov2K07nkB!RM y,q`eM<{3;_bQՠ@l2ihG5]vƊ [PHj /T}ݢqzo֭ߡ{iӟӞu 4UՐD7XD/֤=FMP7bRrI=3 懔A|iԏq Ŏ]NP*/pl0]/8âOMj-CܕBrK YvC_dy b59: #_>R<5Nܱ25lgKb*N~;$>pIm3LO~ ʹacR4 4 lClfk`g+?9@+v~IZ܊۠2Rʉj=|s\qKuGpGEW6e~гqƋډ{YYCw6zm/ *#MߙZ5o2Z7ۤ%]OjgXwb{rQSyNNwaֳW6 o!jf9WLDl3ۢ{s?냬)]Km!݇]s-pgpk)ƾdMu6.7 y21s;Eda@n)zJwfƇ5G@ RH7Wݭ=ORMiiWcm"ueF/ _SowB{?>~]5[Kd!ߧ~M-fj^:ht֪`׃Ju~ߖ쿈Civd&ݷNyLpc>ƇN8[@~cKorDh7Vm>s 2j3۱JRtn!e6'QuH~1fw? 3"a;,5{wPuK'8Ek }J(DŽ+y CNցza4.2\Uu?Xm2F纥Sf po4Ezϱ&;cʅ}oۜDrޑXtȰL{[; mJ7 a !JÇ,+"ٱ̇eQ1ݹ]6޻}s u֐J{W: }V-5gpVTnH\j6^Dy|44}]Ί1R[Gva爊SIv#g"Rfr%qhcDqJPƮk'1E`1 4N`z?|; ^?+oQqr Y|Zu=ɺgGNn`uF~lb}P2ҭiO ORX,H [5NN@t{*N1* sϿ6<S6B%(.k.:Fz}+ȟoGط[l6rߒ j=,/_n.hB{ ܱ7AɘKW)Vxj.'߲ dq,IT5Cß@g tﻹ*Ӽ }ؔ?Šϛd|?jzT%*:ڟD@HeVK CSat "*kXA3Y4S* Er3աQyF3̴ y#anKmd!eXF0, !9' 5r=Ҧ} -l"q] 4=FVhp[& f$ \mljWI>t'FdcfO)*VYvdە)%;:SoxteElY~ə+ roj ](CKak09*z=r~Ϊht ZH6t;nPVi;ҎSp荩cn[-Al0m.]^@ $[pY~{6gErZqKVy4 wPkuK2q8wr]U^Z] 7tW)rl<PR;7V;~It>gCwӤ5sn? U*W8WS_R s=@!/9NRh/q:>>4.P=BHȹfl}eE{a*kҷ)$CE *EXz8^D}ZŃSϊQ6wm)i0 LEOa(̚!h(]')d5Ns.Tyfv0Rh%e)N4)? 6PTw SHjBaCe:,6\0XSh`a^/f̕ړyBST4CmǢCo|OG? 9渑% |D~X^kPDc~<8]/?N٬Ks_U3kEO+Tk}V :atb[7V0T.z'FûH Pߔ*HlPb-z7-`W|^ŰR ^kCȨy]4D M!£YSCQYmbd>L:זAarQ[Ū0@*9=ɤUqFG]IUBg\06շw_ʩ=HJnr<UrnK HLb*j&sZ:CR[0$)5"ٶAS'KTuh=P`ZO {ubY][E=_܋=u$Sakw􊥽1棸-v9^he;ֺ+ylٵ*0@_icEJ%bt(-MϘߡϛEc Tjk+B> 6O[^/@vٳ4couފfh{Y|G<? Yr~5ҭ̎e`Omɉ[Md1;qk܅PC_k= g|_vZ6璱t5, hF N*_zqZVi ʍz^BXTa4:~6pxdB* E:iPs -+,"wvf͌8aY*߿ ֑?wB3Imv~?޶8Uhyl`%Xq.:7VeObB8ťl|}ՑaeN6U^AUIM'*<64Pv8)Ub58u*uv~L8>l_X7\4 ,~7ձGd""؉W/<6$ľA*HW8NShm>)(Ҹ%ݮf"~ qgbΘV?) ƸM%q*[1Rt{zǔ}OG|V{>u/$/$awqxe?+dȨ%uVyb7AD68c{}@paHZS-TC/\KѤd sڰ90_8oT(gog : klC6(_-|`$KǻЊڻ_WIY͋}S8wSunU}Wŭ*جrnU,Uw h)ylYHҺ`f3AT]C\NxX&X܄raɊ[|0xx峝;,͊k_葟,C.L]0gTTBsICV] yg dF6ׯKg`Z-ݰz4",LFTt%ad`bXXc^-swTe-sl $iLw_WvAmrqRKNݓT|m۠^'==Ux:[5 iIko]L NE$ml2u;v\cӈ*}@D.@#4s)HxrY4dP5g="X}%ț<+W8 !U2o& ݋jQH[0bFXS{;JO=K]{yE 6FFv?lD} gve }t86_*1 6!8 ~禟A3'h|3iJ>@o$Ns bKCn.Zo:I/frBKW_5? ={\r%ḫw뱇Q9גq2jh";84Yҹc㩋 Q8A8'O˹0BGDQNH}*ld1jdQqx.ҝt܎qT8o[83]O#_a3ֱ~1ӽnc7bK7m[FRh:F҉AR );Tqc~WD&}-X딌w~Z[ ;Ѽ~#[7v Qh%ImZR<vܻxB ⤐lϥZr4T~ RQK3y}*Xi)v)偕O]%2OXW8oJ!LjRHoMj]`uS &Q l?C:ޥ5]0Y}E!Sn5ah->x=RhxknxShOcé3K`]փX̃`uK Tz +G/'(SfC(4^q2;8P ;%_Ry5j;_CۘbM]%uGu=.}zƫUb%T%mǏ`KBsCA.NA{JcYd  Zo&ڍ-OnÑ| X+To+[U_XW͗ŰwP̄%}ʒ]}&?~k>~]z{mcl)t|Zb/8ku(|܅m{=ӖĀQwGC[bs?sBY=Fm!s,$1Upe%lsf}G^ErFB{ l嶾zSǃ%ZʳVvmO+u ^$^spYNqi_Y\˛2{XrO O nn%E5iEcCy*mJqMy}ƻ Wdq1e*/o˞%h뛇q٬\Sf\xI-rWvWY{ r;ڹm6p9aB l+aiJxgV{*#H[ :>f\c,.o H.*me 9u&`*q5A7)}%jm.\`'-'ww¥Aqܞ uY }^\bcDj`gB2AsUPH248fk'tz6 >4"zhEN. -3y @T^:m/fΆB;}ՓC1P@ l6ﶃA/ngGJhOٝ/7aX9՝ Yi) QZFa2%\f^}UڠZ탦NeԺ}9p{ ^(h/堟F`m^Q^e͐j6YKYtJFW6;lX7rNƶpurtkv6R4.=ij{'%C=*Aq/heeGgj6C VVf!ψ]1[y.0=,=rLsEUo `db[0: 3'ͪ)ilmm KWFa5WJL,].~sN0/ǂ|àu{Lx-aAVQaTT5/ΞбJ0.IQ[PX:k6 sߑPhY.%Wr&AX<<.։RaG>14y#Ǚ`z]V~X]6G ٓ?`Eծ<0+8m ?\Mҧ|q}:Xm+%`n0$Fj#0l>3sNl~eӗS`3ؿ?aGQa%{Ps'ڟ' 3]ȃ0s?vY*Z5*UUnZ׼p>15ݞ>S\NNlhoD:As[9,NoQ︴yɮ6.I[ƕhQ=Wn%O~Y{3831ۋi8jn~7nye?rj9K'N/oW\LR8{ =rT*'PpuV_/~17t;pW9[J/2"FVϰⲎ8oy#$^ǥp+1E2qe7A1Ǣliwc$rW7}~Qїc$įK%pi/y^Au'Y87u.<t#f;f_<u*5pB`־P 6[Dw10i}slfbmߒkœ!9T&LzuI["A8JI6CՍ|/Zoa8DS\EQzTkr֍AlnӯJT*_%,u/ά]Y5GiKf$PU$[{K{tX@?Jn9HV6.Iy^+@=43YHj%fF}afG+@EC1::Ek}@h0:A`|=fJv]G,h܍@2VbBPL&P{ Mƭŕԇ|SS`3xUl)/|;'| Ta*ƥj~]hhh.vj}Juf|°~\*vLEۋbl1:I~T}å$± $,{OlEQ{o V1 ѥRavF t"'T&9Ki44(ס ;qʢ&iRϔQAGjGp%3>tƹE;JUY,1-*U$P3WT3e5].eKf,2ڦeY6Bc9NP|YwybߨM^$;/r?5dfxsL o򧞇5Rp2suׂ.TGoZ쇆#8 H^a7.X ׎pH湼0j%[5Vkc7\ H98'Oi㪴rm[9aIGijNUҡ'Xu/s+ fg`VR;g7js.kOٯь4Ĕm;g[]]p*<_o0"mHz B??MYpk\Ty<')"%ӄUźt/d'^w1ǹ."cQuT#./dӝ/&ܜ85003}dQ?\X` 7Nm>U Dx"rc"MlZG*y. j&qv;7͊I U.#(/Vc/iOT|l_qAi0.\o/YCիJ!)"IVMM# eobW?^~Wo8͌cOxӘv㦎qg8%ZjizpFr} I6>ne굞TK!O]hyp z|{fB-|eyT:rA\f*#&wYBLiHhreg`w9fV2y~aݮI0i@'2'Lg:6MjeE NXҚ +n_ν7o#P+ +;\`.^,y UsÔb VHPȄsV0.j =oUʛnp1@Z^' fjVҾ]#{`~H_L0c鋊ɰ5i4=gu"כ*_6s5'+`E:b ,k?PLu#0c\1x ֯NRqB^vr[Ю!ֳXfz~[zy죮kr[.IVxa_S8ՙҙ̧u.KkaO& LeQ 5ص:&lovxT2RwK?k˖2sypz?7N\~%=K_11z|Ĭg EaBنp{wy4*ʉ-?, wy/췼Թ"^tu'8cQ8(K_s ǯ1ܬڰ߼5mO2>K w_vZ95c/$$v:fH{3O;Zp7ݦl- j%EW[|?3 ܞmͻRxw;&{G]^9 ?Ĥy1dGdڏwHZ\8Qn>`6rTQ#U$VtDŽQϚG2F-S;E>Z:f|yOHU 8,"xer8w󪦆}r`m.nfm?XW- r#qm8o%1~oC!㽕|+?p98 $PqQޙ|XH) _^dtX}Y=g7F>!&Qo쏷P'&硵]C8=:DwU[]Jh }7p uj3`ΝfC}ϐ'o8K]/Vux4 r_߸ &b0s5x}E,zy!00$ %-0/ҕs3d#j֔ =LwaϾh3b ht[2 z]^ACz)3uN #( 0 \V# BOz;j(s~gx{q豜S LCjGoEm&00ENd Sw_V.O9i1hxZv[L驗JaH0}s!%V:Ύm{CBGeMQ.Nybo(8a+ -fיjSٶ xߓ5\QN O/6GiUv Ęe]ŞsN5`yKrPqHB KOA[iW$2'^{Z jwYXm"gJWy8OV}J2htݣ.x%$[o>?p -M9u8c+!zV4۽>(/BW[BmUq0bjVq(uEj:ERSnq_ p6xѼ0y4$f`i7:}\Y ~+Za.yhl ] pfC}4+%=3C84lAߵM$UIFrtˍ?J/ޛ-7+etlؑf3*9̇*c2gҕCFvbSKOe]wĖGBxU=ɘ3k2Vr}v> )jn`ԡG"(Z'uznj#n|lH5-jj>%\AH9[^B6}3> ע/}&^F}a\o^}/1(MNpVCܬ?B%JSǠ %")3Z?6+qn"g\URdV$quǾ7?i ՙyXpi6p= )jש߱Ţm$?>NrGMW"N'oKq#KNZ d{puKM%;ki˳ u ~#7ۘ4#z?~|܉Dht"-/b\z(w 9ϫZᦾwvJ.׈7Ҝ p)ԃC\* LV[uڞާq0\-bֆ%€Vh~yeEiTnl9[b}.Ԇk-?%( ڣc7ͰvkOS0A? xsw//]tOkAdJ(]<6HLaY t}b-9r+W݅DhQzrl:9ry aXC_`Nms x} A5՝!e#J/"?O!0/_߹}IqF*8&LB}Q*T̽|Ն*D X/";pٕMVȹ^0jiKJjF34ݗ^gI7yȹf;@2e[ fw ?e_C)aXY~?&x}X{I 3O}L]pBV",d;zYXJ,x ! cf`&-*Xhk 9X:''Q8Ӂֆb ~:f+O:E.i{~m`cGqGװ~]n/La^X>[,,ǞھاS|6x*@+34 Zg20Q$u@v>>INeX;?aS_Xy5~r l33*  8B65]JJg a%쮯01gݰnT<sxp*hn? /ap"rj]oY"|~O=VQ0-6kyB@kͧ1QOցm7aʘPU*Ǟ39/ 1Q-Ǚ4-e QFdء`|3 d[_P!b者iPo)yCpn; 2at&={p o޷CgvOnlB_!XsN6c0fgu]/XahߛUP{z+[E:x~FWBKXAX8Ac]"pʻ ϯ׺cz@O` X oNAe '~ᣊh1:9;Ϭ व 7sӃ@m^}l3R|\SW%qк.c7׷k 1vt/cs؈2$`>UE8S Z~ፆnbv*woР<^q,idwi #yKaE{qblK)z_W}wE9(H8{huQ}o+Z&q@Ǧ]B|!8<7*/i8Frв!ֽ>ӟ7sCZ7k}@#o>'mρK0q#w94T8%)?]XB4Q$Ifpw[(T䦉Չ cׯB4 c/a[D{ZH>m$ ?$q)SmZe[+Vjwc8}R [O~0?DFIa= ۼD\v`:V{xm8 P[e-sgH 8k~V *I h( 0n4_H"0AY$~.۳ H{֗\M7˿>軘cV"Ꮝwn;C c'%YepafXZ2U }ǯQx#a]ڷ˘"b5֍MeiO AT`sBXo| +[&Pq.=M̬F4597)r, k|_i,oAa-)֭>-V먼?+h?q5Sh…|#PXw aCi7i6/7J^%Pr  fa%QLVdM'dn쇋o`&>R 7-E`͐\:E~ i:*Jr矓hzGLF|l+c<_ab? GTm2Yұ-GV˯SJ"O kG[aUXO8Rlj n.+Ē[8TJR qxǩQ=M|=T~BNJ-&9 .2cP/vMAqgu)MM ᲏;ٰWྜ݋:omͱG&),[e2KîxyN*CH:~-$*5E8$;d~JԊ8,Xۋ3W*V=W?ex<"rx~ lЈhB҂|X*vV& .8dG ϓŊ؛x tjY80 7{QR-1N:w36B 3=vUs8T_>% cݽޫt9+ֶzk߉+wlŷ9na-D+N#S]P'{Tn.IW7OS!ąS7萒{ U$oZp.y}Ugc%4P\C1R73X"/q=#.~'r J@N=zN5=Bś8.slkkw .nU)SWqݼӡ|P1l+SBpxsٮ!\:n|<.z.ZEDRZT}۽Z=98O EJ>$5MW M.#81a|&qtEM89^d0|8Չf*#18Ք8.1?]~(X8zV- tEh2l o /4`uΒ|iVbJX^X `dX/ n,A*]h@ݤQ ړr&E*[Game{'l-vg_`װ#Sg$Xunq&W_˻cG#a!NuY X yVO)qEqX8_&_F;u(&p.h^xc^q~wCY8,Sp G٣:vNޡp0azC;r+DV6YV֨¦ {!:[o]DvW<^K8l8|?1փK|̱t2L ^DL v-{&!I=8ν# %{ذs[s؞ۜhS]D_I|5˛yӰO>lv4-V.\%E쒨/"67n@BgWGŪWUaeuǑtp U1t^Vڥ#`.<蓍}BSұ~,[z%b#ςૐul+WpLf8.15(FʑTG H9x-(ʼnq%\;]V䋫xť c!p"6awj7pP74%X3,(8^Ԑ=KE8q)^&zӋ+(Tqnہ8aF ^1'RY|T~3kFWqv*[/`0B ϸdCԨ瘾ŕ/NQpnm"qK$m<ٶn'"gK|"l8qcHN 5_ۇCfzj_%8 ur1]8)lCgcypܦ;L_GƧW8"I}{'VVMLĕK{?õ>3 i\ϻR[fX}P{Dj~a9\~<7sL292NUOi.c3$fKBl\Vy9?fH1nGR*\}хe8/zĕ]#'J+7Y÷$01UYߗ/ldf7 bkѷ> \yB;)u;T٧f%g6p٤Nn%4.e/lęS{mq1A!JIOoD^!-u۲HtFx g%/Ǝ6$qz5x%.CSXP5w cE83z֦-3&W&U(eO)}ysy*oeDٴwl;pXmM$tJ{=<:W8zs{`p[i62M U8 |ĵUةHaAEetU[[)7^z3uzI%UK&Xj9BPr~ed*IzS[~{`MCR̩'>H⡹0i K4$ҠWr|8F ]U]qGԧK&OJP%+q>Ńoamj~:$ sUhI6m48w¥@ԕ@U9Q d9Sч|<ҹ;׏"ٙ>Syor|z|N+I0jSHv. h-w@"VFKg2}`NjϑB*viV߃EN8e'V¢׌r{ zO~'f> >Ǿ]Y_э..rR=`e5+t?,_>; x9ޏ f?X 6nŌS ${8,O8a7 K%@NV4=$LJ l ֮]9d&rtkC$WR4kgϷj^XRr aXVF}pePo2.kk2r*§`Iv#q{JG[qR?߽M?Rv>O`!p3A,3~|SRW7K"]cP뵃7`ڭ_aQ֯ۤՌūH0);_d 3Oia9ûV !Qѵb ˯.`cm׿;N$5x!餮T~#6x\xY31^:)mU;rQ멳v6v7Cfs_,"$ڶ+2^1'rϭvvMvP?-]ȨEs^zA8+y 3pKk.p"6Xd?/z'mXq#ߒ֗e-cmM39eso(.~ ^8ubc$ys@#yHJbMu --g`QK1rn%l|[vT8{cwʘ@^LDhWak].;a#sgD6M6ގ_CMX+7FW#]f)-2T7pSKSx[YU_˫YBx:?n4~%\Ǐ8ӱ=OՖg<^4 t3\ Nsčumwipe/6٨.oKOxy$(k;Mp!P2e{_}XFAf r-)OL;ebl"9o!k¶j&\ssm&\p@l-;.\ŵh/BQuEz'+Zd4+;^}8E5;<0uLnC ^usM|201s|ʇ| 3K {{ jYu"%%pBD\{nt*lHCU%R2'TwOWUSu2q@"u=q6QsW`m};w %ҟA6'g$y8Ml}iƽ47?gĶ>gVJJ͜tUgJ`ͿJ\9Â\绉TIr򨱵T1[Ic5翌u\u$;}It ūy.۬ŵp9r"U=Dj !uz"us7\Sd#R|99HmP5j)WkFׯ\؉^_#qбML$R:<./:V9œX&T1:`: l>PSf(Zr~[;-F{$a@FV1)SC3eݙ؄^3.byS Uq:|. U2˜3+F@2+4JqT瀑MSg0km=_WB>I_W4&4U3C䥣4W%L|=Lt݂osW}Ƥ'# :Ar oh1$~EM ĖivvC$m[^'hmrC,>z%VWڞ%P9=/WQs%a>q?;ԲiJlYì-ě >rI,y9v-jnfѳb:Ø7+;XC=^ M7 R5$x,r+#9?$fGe!'O`*,jlÚhC |iܠU;56 8V߹?XxʨX221 _.ާeC0oSR,YxM+[zqL1k˭5wlaXyNU'YZSe>dG<%.f򥻳Myk)بhlK_ڊ;^L~\ Ren;bgo gzn A{ 7q˂(ל6|H:v/Hږ5iCGׇr^e{gAG4'IJ@ m\c7$ɀW19i} zZu1eMeUB@4`L! HLq<_~Z|_˱W{pm̅]*"2h . zY;v'(_M;S-<..@wHM ʹK4oL?PD ?FUׅJgps(-;Y k/1aQPrg3@]8Xg$.w#2 m̢#2+=puT7K|Ήv6lϧlXNn\~ƐH2p %ͨT$Qb|uN >-%2x;'O>s);Wp2J3F"ݬ%NV4jB _LK}{py0K2.NH }>Knc4ޭre"{Ŷ7q妏!lNYk;5M3?yi_3]S`Џ8UθrupDz|ڃq4! $'Ÿ"=J0䳴9e_® Nhez$r=3~&`a_7PXb!N>x8gz|8>EuL {O8R}v G?ܝnʈ"K 8"`X> u؝-Hop]#3@);v̽b )?ޔ^{y*5aw.yh]}>?'5**XW=u~(~!EY۴mv*NV'`S!~b?{Z[j! ҒH(+s\6gfqTG{ oZbOSbډ/#~_q<C c g@C@l~t%FiKz =a:.As3J}Pu Cĺd$,Xω}s?39_ _|)S{^Dq(u;454)s;Jϝj:!ƨ}OΜ*'mdTx ze5TܳܮW"]~_ < Ͱf]oTND.=P[ŁՁ0q"t@~֓W|")ݕt;2voBrV ?;ҭf14mGQNƴ%̯T3YIҭPih%sY.¹n@1UpG¬ bvQ+=:*=&? Ht}{@g4E0Y^Cۮҿ=m5,9зfnBEQe}_PN6Oۿ6C{mÖ/]Ђ;kCcؠa2rۖO u g;NYD ۜz{OA瘓Vgrǯs04> 3r/I |˯}8*u d.1p3c5=puVzM̩Ta ]rȗ;g?/-c;{_jR8d~ N*9gapͣ }_u~ +̼S j=*@L3a8btG\2ۜ~j b1AZ 唹C,'mAAd+mow:)-q7POmt[=?X}a>IZ7uqc3Ϭ%v)rbT{;։v"Rq=\&/mP8*rv`mVZiA?`~oG=yM \8ψs~xRIo,b/շvrvO'0q 줿 ~ 4`ѥuh-=4Uм-mzpϕRЧ}==I< kgZd.~=#OۑIlPlY+{d"@Jr&xAOb߯ji-Xz]d'dk0L|c΍A=^K{Q`%z f)^l_lr}*ξJ,#0<`Gy!Y;BU&!F_* ԕ4S.ƞ,Zs"2hIbvYmhb81֓~{6)v #Ya d=z5mwod6LW[7VV䃲?A3B'UA9M{ZKn8lqz~:4qm&{ n-xU]cƅӟp{IOXMQt2/;F\Iߓ30ЎK ΍?"m@l+5h|ٜmǏR /xfJN&eP.&3q`@lw}ߖMu9Q%Kkh8,#WH~-}lBB8CGVk".pQSV7k&~_tܿۢep^ȥ#XD*Y/iX*.&6 ?s(ۓXE3y})w=ąo#!_lIwJqՏwrg[%9tϬoqnF.눔,01ٞ(66f\УQL@PQ\az IBJ䥐Hi$?{bR:Ը|p.TuX~)7x?8m͛8zsbO؈ ν^cr[!bό$% y! K\ tsnl?3Ͽ[pve|E5]]ܒ\XL+#pSpV&!u<(iǥ4Xm?a%\t(2yjnik6 rf[} ;b#աtv+fB7SX:-uV|!3;F(xxcBs[hhs7|  nj|H/i5|Mno휘(u*<%* Ty!cV{{|DqCsZ U`e >BSM9FVgC 4֘DBm,83Y2WZ1C, }5TQ"reIl}~3Jh<׉u'MuP@>=N#¨W+j0,հqZί3c3= twȞ{=D-BXa2Ԋܻ zR?iwEQlJcRWˣ%X,Vu ̤|~cyw/ǁr/"SH-Zl. 0&z뿁1ٸvX.%ġ\~nua<\G&*\ʠ3I!`a@&PM݇c+RՏ"ݥ=8r'ѧ1 ; s~ٷ\b.@==0?v+di]b!igFu;d=Hv_iJlq:m͵MoT F/:àъ .M y+ێNE7)̩1+K*|]JcԲU3iLsM?;p EYu딪1`~ϵ8ZDtO`vWM?*@CPUp UUAo%P!qa<5V"v]axb`Q%mHJa(eU`4͊T}'6iiØхU {']G=[vN),GGOB+1*{[]ZbV/ssl`μ^*d&֜n$gt6ehҺc^TDA_P)SpDڽ^7%hSt/: wmVкqs(tRSҠVzlD)mОɕ.Kkr@9=rHqR9ouBv0פ^(L|cY?߹wi蚌 yG{`0[یaN310]Zqra @:jU̍CW|[q9=EO2Y Bʌٗ[7sAkh9p+# ';E3B[кれ[y6|ˁ.3T$\Jeef\HJ<5 Nf;VZ'r qAʾd7}[K5j~P c'BATSCZ#VCтM␾4?{h"fk͚smP2^ DhYք k/`䥨g9. -vY3s R__AǡeUPI>RJVo ռV2MNDQ=m1~]˗W֧,D}*T Uw$ryzZ0`N)L6`Pn_9BFOE!WR/al=$xnFJ/(mgrsZ0pC`R$1K>{7aVѧE{3BAI LJKo `Km#CaLjXz|N&=Z- fK_̊٥9PK_ƃ@c cO aUqX:IlYg|#ț9J٘a9Y+xƥ+ m42v”wGϖ.3QΦz/`}EyMQ9v2R[a4ŕîjDZpkCk" !Ss+\zDmT9u['ÅwL3RDk yeH~@?߬g`OtpqA¼ٗ'%7 gǩrDgYN'F_ܠG`Չ@C7Dw!l_LY%wX%Ji'ث !lȷXX:13陔Jg*7wԔYyY8q`GnuL91md'8=|}u$1]۱X?u'Ʊ~VRiNT2`) CEyNש@l.7@16PqZze&}\"W{4ә 7t'm6ޖM#BjD>}D UMRHd%2lu "P"v/Ij\IA=_\gՉTOvip66p{ևƧѸ_;Kߩ>!Htk1aVq %*,(HIH#UזH[Ul\Eh EB {D*YH~"ԓ)D&w _nDj[p/Ao5:rGdkq$G۸0m!kSK$RY;[J(t{S2/.uҤ6g~n#.V?r5Ꞔ\[Ytv[X. `i F2@0%i(#E/7 #٫d90[;T%\&C ZC%0 w|q#G}iBYj?E?vqs&yzm++նT/&{o-t'BTKU[=ή׭a]d:rXZB8CC̚)ԃv_ƀkðHGn@Ј6Nh>D-tOu?Y59AQ|OZzZH{l=>:k0ȇVb#m[G1tl&Dƾ{"|=xļO({"+=Oa4ן>eCGp$-=218]ԏd1E(jC/4wb瞤š11)]n.:1aKhSadL)Q%Z_O++u]~O9+}j4 r%锊wh )ܭ~X }1  ͒+6CI߆Lf{^X cEWCo&*U0p!fIhaêίG)ttkYrݼ8]]y]n|8G] W_oǘlE5*AK:f/LDs޲=."z.L'Y?A]_T C PvXV 8矿qL96'7Ѐ%tn~z+|7oEoD`7[$4?'6Uw3ŖZP#UH"'3 D#&B+">욉`hWtk4}+av9'MthtpjM\ø'_3m|U!0$C„Mvf2:B4(m6J/Q.&rU6=s;=vdoߴ&+PܔT&~k7V3zE'>fQσS"frۏ3֫g|"-Q=E?y's;1s 90^05/n|I \wg"IHףM-Mg|mKj|w@ 5$B_w wPJmVڡRDѳixcN}@YG{KL4d<λˍgTJ ӸW:W7P'k=x]lXՕcmMO}M_qNYRd!^,IOUS*kWq\2ol4fc5~<^:zFX^UOS ](O`3Cxf%Nܱ<|ڽľ90hEr ٚg`#|캟N[oLA>cd`8YtE|{`[A;J4OWeld}BoGC;$-*GRWG"5 o/ w]8 ȲW8$,GgR:C-/xs}z :$buiMFm/:Kogd5; ^fZ`j~0p֠*<:3?ECWi,_{ V‪\]r60C,1/A@JQt;y?jšG!1c(36~F>eBW.r@񱷶vw{@D L۵}Kz G`b,HVG"/d#D:#6"}F6>/@fu:aC"#}DiwDzӮrDڔ75~??7#]O%N{ 'l‚a"AΎ @˾ula0`؞RH~*5-Crמl[vXVx O?G9Kp@`g$ ;]CC]0ѳLwS>: {?[_֬K6? ;.^!I]@>dY1_u6^֖'ЫS]+%P͆8: G`JQX2!" 䵺s*]&5{f*]u@NF'+XS082-E7~Cb$7M?j?·+@;E;P6+ԕ-!cV0dIgwᄢA{%K^L^h٣dfمXuY6M<`[~eY{X4=w'_RnKs`?Q(X67 %1]wjG^P=~(rm'R;=}b`{Av,`HU.+z+ۊ(}8i>wM&?V?^#ŏ*/7,H8Цri|쿰?` mtphב%|Tv:2&itTg]_u/Tb ½X*|ڠ3SExd6?W8 gF7 }'ԗkNH1y$KG{JfQFw[a-/8^o=5DSqj2;J~5`J̓7anV/e{M,d1Xs!Dƽ3а.!dCaљ0,|kPA?^Y`Y9[~NףWX%t:JЂz:!E= ?9éO{3;,yC#>!0p=}=٧S'7LuHkc y{7qqWMPM+dv*j :M^}ϱ, Ep=,2jr:HZER#';c(G`R'@v&nOR݋@gO`80:#FcKE&$:$z=Pi ʘh·ݓbk ףi!+ɾFH g!Kի"0*e_ ~|M a\2 Jf*‰f:E!} G::Sֿ;FO T/#~@w3G1@7<;C|v23@ǎ3C]N_Ztsgb<.\ԣ\ =\' ؾx]ݎꦇ s3{ L4c˲7-yIrL/Wꍫ'в]). 0pjRhyՋ2!Qk2½'qFwB65iשs}|>> ٯ87φtiy0wԛ=Nrtt\N_O<}w kNEir[P9hfg;UcJRpU 3Ho%@?k 8+(%lZߑU6 z8)Ș1 G>._ێ]؃mMqYYw-NkyleǗ8՟!x#Ϊ 2F{F G%2q+weپj ڬ, #. :r7$fy# *bAs]$MQ=8pn<- E')h/yBW.UhH#RD}fپ2JdEdu}cM *!.u ۻ,JqDf=t|jVWV8=yx.S Xe|;)=U1"c meܼ|*.X ٛJ@u`+C~ѵE&hx:hUZr<1uH~{nf@^yV}XNq^>P'CCKzՃ XjڧZT[6 'Yh‹)bt_=!Ac0swҗ6*c Ë~2Uth]NW-m"W"S*ʶP`wUhnzQm& ?iԃp uP0Oѹ0~%lrDu@U9CR,cA b5̄J 6#V/+22]Hd;}O5ދǶU,4^6a̢n֥PwƁ<^P\@/F0m ]QzC1>$Z8mo.wBT6n ǚHg6:9~gG& cx1(8'gWcmΜG_ gӪ,ؐCa]R TюJ5}q'DZy!% mF)˅m,/WHy,ZӖrecSw>X&UhN8>SY~14{tbsSIl᜞ޖ8+=pLSW}aVe7~.kb4[b'uR[;Cƺ,1frf 65G_e,(Vr7kUZt'o,F¶S3`N['aYe֭; kՆm8\ђzv}/ܐ m{ktR?:㘮! SoҷC-WY=%"\ldmӂ/, |hSKTf ľQ~`5mъ @<`&yFD[X}aF_ExY,U ; }.se]=nYo=v;_;ژ|hgh14;Ņ$"Ќq_ xOs<M\m\?ᗼْV6N;q*LbY@|>;Fe)ll܄G 51M+Ys^d<1>l^rZ*k4=`U%PUz(3CK!{B\ *xi},i[u!o7F1jga10؄|,}.lYêpC8~;nBkz?rjQ؟+ ,?ƩO#r$V<> +cuhy!N.jh_2вmgW,Q|,몿΀*(nP7]VR0U-G G)49{K]1K>䢃qvq]effY`<71>ȏx#{Lb՝ֈ@W[ US:/6v s;N-Mx}*ȫ"o RӒΪfێyīV};N W~8=afuCR(*2 `7X5 >Wqi#'Qt/dj3Îc_ukS:&,d6/yLz>4dsoؼj uvYkam%;6 LO~c p)T(sH ~zF$R5y%tOև?ϻ;$8¾uf:,%[Kzc@>}+-y2Do:[Vq8+yH^y-\|U~bNrO/=#y6oh[>V=>I S@]#NMmCl 6iaZvz,Tݦ;k H~֔BFgy,^X'%[l=E(z\;ufBu;:x0`m:IWZ(*(,-aII**uæP?r1eۧϲs@N5)VfeA};x=b=:_(BӗP|F+uȞ[$'SMc5hHv? KmÔ&f/b[̽[奾1:/n6owdv9ŶuJ0ri?q5BJRmS,d?v mTj - kV}]OᆑEt, ͰJ7c6or{WbD,¯q5]͏VO2~o1[Evo *(AFQ@DB E DPAiF: ]˹=ٿg{3sM>O²z^Ok僽ݡR?U.ĹzHBz 0 QbM)uP}8sk[X-cd*nz-އ٩?cqT$" xDe7c8SsfU+ՠB?,"9 C. zá3[!ʽ攂0 Q0Н#EAb(i"{nwmXڸd֛w? WQ[֋ KڙUaPE_MʇiZvA 0AR0ԘR/oc@({NvJ&R8У;쟒>ru6ߠVO++ Hjl>pAaaF}y*ww;bfa9 us= B>}o?Ȗy)%s+WUqAz_24ĭ-S <%2zbXIg1JD29q7&fqfv?.1g~/6 pSR'.s+mqa().ܛ mL޶8cEgˇv59S{أc9u; ~\8,g;w+Iw[+$3E^ ׸WX9䡈8EݿQ٧3'b,$QldJ8u ۟ZBcqV6/|y.`L3\~noø5e%TR_9p|FD&R4eb[$ սB/όBIzfԇg? Cu5=1'vCڇWl*[*um*AP' Dž?B~A'b pc_zV֦ʷ=o9_p3Cq55l1LpSjSamvM fK19!5Y¯.Oac̼/j auC%`ɃJsaGLY, ~φi#fFJV-/oE h] bg`f e +2}#k_|>3S20$]T[L9Uǜ ӹd)\H0L+5${$ OԞn?-k.gyЫiWh,_|n> >J??\`pt[0ؙR_e W\?'Btgw9%?uIVE -Af C1cz0-[NtUٗ|PT:\s~o}`|.Oh?r4o,P P_XKP}j4%ׯiB:?K>xFbhd=qZat|,āOa%Ѝ:8<%H?+f z2lm2+i/9|HJTyaq0'5&ڤyzԻ0&fHn -۰.vHsj "#;IQ} o.&;aa2qAnܭAtT(I f>_V*{T o.(H-R6HT= wS,D9:ۯa"~ޥ0^nKGʊz0zZk^9˃מr]UϳH TR`g-5dh49YvڞDj;DP%"КÖH3oHm~3"u~eXL:R"<_)ij e:c'ԯsA=\5Z"uՅ.DTNLD7a<D?l;Eg\:gJ$}l}HC{n*&j=JQjz6$R B$tΆHsD017mw< )j;L~H"#F)"Ү'ƌw֔nmWyixeǻ*RDZN#q!"ǾYtDslj.IEOXTkiX#{XTe;>~L&ZbFix/do%R;<8H%غ|}NI5K4'Kpv||p8}}++~,wG[p?ֽ9qU)jVNj{E>-g@ ÙpÜ?$axIJ9gUƁ7I~ƱKǑ,3Ul;6< *QMywYW=۱,gʋCOLWyepW<Hٿ^} G.^TKDD~QZ'33I<sG[s櫓" `>'ß1=m5ƙ15O6JOv9mtǑi>Ŋw=FdL`3=TNbcfI=wlw(Ǿ#~al1gljzDm1\ 7 ,SJqm.$37cF u Z0HE x{O>6,$*GCHai](Wf2}Ձ3*Ll?.~xGWn,}TK;h|&Oj-RĦt6\//xI U;gh":|l?瘴-|{>9M{"7QiIec2-1~kƝDH>7q|_"܈:D#WRmϋŕ#sNl Qߺmg5 }ۅ–хD%T$. ?.ewS%G0,HN<6Ġ3$'8}1Qko[k ⢙jOp~m:ؠv@Cɾ )7C8#=5j\f-LZ-[Z7zhz퀋c qݪIa})q9 [CjݥM8a}V*.7)ZgFp0g5p ɉݒp>|:(FY$FJbg]/N=J|xt8>(|#e,lՍP5l.mer V.#%ۑ+R/ ~vQ4N}о26φ=©Ij^oI"|ĥˌ/u1+ۏVq.^z9S ߽sDžċ$ 3g{3u5(T^wlwVkfC< 7I]BK尻'`B=3¤aH1d~+]÷'_bBnnhJ'6+ LB["?;*5qw(cTńuǿncS Ŭ,,d.l3Tfo ]o:M@U+0ΥL'z7gsз5";\=􃻬0hʗFB|)~{ {qd;y4;` m~"~Zk]GJwbw XG/(aGц2gD7f.>Ky] c( ɥena^yṮd/]a]"en{`'i0!  ok+ a>=3RQY3a뚧.q:i'WBo֊'sjrFrOcSs7>I[:"~(Lt!릌)|^_/Dר\JۅaۡMh,O<`l0"Edtd%5lPJ OAו0XuC':mE1w)2:vP r%2Ш>&һr&EqU@_R-]|-r-Z 0~n.ǠF媕oFC3ݣŭƓ/=M{{t 5Xe7/zUN0r|#)? k?-jb{EbW!,0(X]W%d5glg@X#ClY 6!8{Fo{_2js HM}?~R^p<6.V^Op+߼$`#HѶu=j2we6^ @Rm8A]ǩV~|-9[%t4q3gGh}Kvc󮩒ns^@0HANPrj[x+X 1+Xkp ~_d7_r1dK.=4؛A+;퐐szĮ.C81!Fe)ڝ*l=wC nϽe;Ϳ `?mӜ;qp-UZ8ᅭXi]o@-cs'r|5؅\Ol1jB>S쎮q6R"т e+qLV:c6&Vz߈QgQ"zZmT /G+_+c߁U8&%5.,!ep?c6RVˣTcB\Z!+ ^QZ?ScJ?q5qgqnqp4X~:=)GWYD-$3Ⱋ£Og9.U8EӨi$q$_ٚH4-|U$zIS$QR q~#M1rMfr3Ax;UBčEvۿ,$:I֦IM/MVhRvuO7#<'Iv}+/INmh9V&m7Y4B^۟Dme5-[HV!az $-Dw kVծ$V$MtS$ZgҮ]$:f{Yj$$:a%jS=__ $ WLzgCEJFa?Lq  w|Nн}4YUo8M~YB/n?9%^h)7?O8w}39}k6H}5 fΎK3bLfÊp%hi*k7s]d3k.'ax?0jz6<,JzOҔEhPy7.3_]AG_lc0?sz-H0\E /i`<NdCIo49); G?X]G pPlwq4حV$~ cCGG`P0,z'wnuKD{uWj0?r$vHY$Qp 6}Z&RY}-#2i>4@ΛԣD-gG#T `Rx_q*jH\ h exQ[ ں} ꤠҫ+Z%!:~1pYz2}IM=~ kGHH5qfcˢF04"Lmc``,Sr:to#mj#H0j,=~GrfIYmΣݍ L;_7>KǿPώDs,(rǪ6dʡƱy;^ͻՁr6=,H~ݺ䪯lF_:GᱸSuD4JT.ɒ9{׼>,L);& _{FP S {c|{%A51;( NywR%֟֩xK@Q>Jo)zͷ.LcECw;'4yqO h+oW,35gE~,ub.RDK^y[VC_kx+cJ5Ǒ4μ: yr-oEUyEjӲs^mQ5h1;{2IzsG }V-|jgj;&gXa X6EvcJxyJ'N8/ڵ|4Z>2Y} 1Klzթ{k=*M=ϩ:_ f.d?ƼX]ʯ-!?ToɻcGׯ#&17UO2Ix/q48{{IK82X%zJ]{>̄|)훚Xwҕj>Z2"o~Cˎ*,xNOij59Ci֊{1vşۅKUaWhW{D{Oh<"EՌ'am1Ld=k.<6jqi)ۺ>{F?g ]6{0)SE 1]&V?,`~B {iJcᗠ+S3}5 VpD ϥGcp4Lv٫vPАz( tmWn@8 ?%I@r sh)u Zq-C4ZաVjw҅tVAA&ޥpH=gkW`{\ .&vbtGm%ƈbA 9Pٜm=D UbXȓ+tz%| X|<;S`ah\]Wk)qwQʸw *2o<m<˨iJ3EҴl]6"P_0{0gg^)yJY #oז7_MuP_:䆈W_g #v<< tpR0hV2I Գ(>n6+أ#DH;m;6:^f;uRw0[~h[ $Ze߽?''W>4E;KCiQ+`t^W5>V5^V|Irh6O8j*}нSҧB,3'i~MZN ާ*l_=~%%[ #0z޸d4,Z*GO1 e7ΐ! 9>=~'_,)Z2oC:"ߏ̷9&Rs0Ia䁇Pq?F:!=?=LwȥT\]K*<4䙭o?'Usx{> CttySX,/Igo9EdwbBfhD?^^WC/w]j*m o٤MF6jb@G7] %5'@_2)F&U 28D3ؗ{ߺ&{>tzO1$Suչ1s~?o_a_yyt>O5a[@pT~}z#_˶';`~"o ^I]qMǨkh֖Ѧo,,DNOa?[3oc,?"0zi/+0׺ޞH <=3 -rvGz"1OhaӘНEzvy4bry KWanD kW 'OciM ? ,SA̓Nq} M8}y)PeܯIrU*ۡ GE>Zy)(R13sjuӕ@!Oѵv%$xh>,258۶ @]Qќl/=x+&|KۙeyFanwMu͎z IoRV8 ;5 q45$]jrUY=]. [^$m6] |G-݅0~6(t)v*X4qf i)+`L bX>KSK$ʠJ ,617yήU‚/5{饤IUՖ{:t,-ҩg8l;dlIe*v4g!T.5Wj1A#c8MZ Fia+zj[y7-y; GX?;lCwbmRaإ6lVb'X0#逳tӞZڃì>xX%=YA*97(SU2ŴMjv:C?Q$RKZ 0R1h]N꾪JR򱏁X'k ?|Ëeʗ!'9/oea jlWfAbd G+)ejXfc_ouojCҺ╻yk Rlv$93LU}?qlYkx]t0[[b*^ ' 4 ; 1B쏮rT'> R HxkFwA^GsP{;T =_+-u//UZiMI0-q!!: *̽5]Ŕ *C3V= }Y37`T{-S;x",׋` ]a&czk)20N.kF0 tt]`iĢQ4(Myy 4W_vW°Ɵ*[@g#>LR 7~ު삖B3:C芧;s&wkjtdީL0h9;#v:#{BMZI/cv2w%H=F7@O7诳f9fg`Lt[*,F]?͞sP"4Lg9@a_,MU F_D쭩c>)< {cGFnP)}RÜzY>KO.c7w!?/G,;OgY%M4UI%ktYdKޏEqD+.pٱn}ͦ僔G ͐,/]UDxR\CpQBq~IE+H?{ .\Pt^gB-/Wz\P|eiN, wrp낐*K5>H|?/qdz#!8 agqzNG8M3A_mD.Ӯ78X8Lgl|pag;sqIHޓg&AZԵ_M)Ӥ`\pf-U¥)ՕA\`:Uz߄p>)hBo,R/&ȧB}tr% /ڪ{%q:`7SHі.;V+z/: Wjp~KW7+`⧆Pu5 ߋ=cfXu eq|悔Vհ* ݁E}C0`8"I.uj)fe7Ӌl$].[L"!i %~gߤ`v/?F#{vrɾ&!$/%;Ìs稇@_RgZ&ϻ]BwMJǯ\-&$TULa VBl>a10]gu/T|~ FV8'B핡πbŎ51Co|/m .$_#l;׍7`HyӮS}o˅kתLA|`H`"=g(߄GO}y.U-߿;bG>LIG{eRIWƠZiRi!99h3jitGߞއC]͠1Y50s'T{mS2a+z趽C[iDU -1e54Qh |TB@6:̻޼vJt=`N? f Cm:O&2xVXeK!W,˧=q''DҲTGݗxԧ.Œ0YnDG7 ͟WGi*CFTy^ҍ2EXFһ%NrBzøe`|tV, %pU**KL0'ߘstϰn@> JlRgeEwoV\Z0 XqrRinq4n>VHǍCL?3e(qqy$mFܸ']ִseq9sq 8[Y7- Ii. >˹YzNଵů8oQ5\H \AE\оG7rs-%:r7,^\SVf8\£\8D]aC9n'q`Ha\+dz7O+f?ҙAyDwy˞SۙoKH+Mݎ$6 \"#ա3RO\ _p늜7׸_5n٣_`~&<œkv_zf8߉mB-uFy`j=U<Џ9inzBI0e$ < n e ,vs23ӿRcKr)vZ/1#NyvB\ԁ>G'9&oP5$0"6&1 ;C죴M+ f}8H~jO?҅ȃʀ2qu>ջ:*2fQeJ(r~k籫oa0fK@f3o%su! +9%6'~g]6TPyOaC'#rtXҭU8k3Qwm5?#hR33erd&Z=F|JH˵vX0" m`[逌X+ 7V/%>$+ )-74sȂ ]xNGaf`OnRϧY]`&.,y|o==Yn k["b09Ʃvx?,D]ql,?)Xvf ܄c@Vx2L>љQzdm뗭#0w_ǻ0vzw%q6U, Ӂ.ÒxwhA,ڼ1[u{z:}ֵU<|Xx~q֊ .,TICe S0,~5Ǽʉ9 :Kp3 Va?jD^$2أj&ܯq;ŝ8pתH]hWv/\ ʹ-Oy-^j+{.bwC<̈́T׊1x-4rڽL;Jr{}6-n(88A͸}En}ⱎjU/V1n5a"ie8L =R6䢑ȋ8q8o5-{.h 6[K8j=S\  '*M68SN&UM5Ty~>YguB;)̸ ~bH6w@+qO!g=V>{[!giv?Ǚ8q!""Æ'=\82)8{utSLñE{(3F+qOgq+v?0Ӌ>!e$waj0ZHnl2$M}d4AJLKRW%\,]pJGrt9̅]iD\qB>q~;N% Br啷H{lI(ܰ5gE2rH[wI1D1I_cL0Fm<&S i BJdpmp:ߍsƆz0ږzx3oj)n]QWvXO ǺjܵMNI%$܅m=?ءw5t@iۖ>L9CbR 8hHf$ʍ%rcؿ*O!K6xzĥh5\逎8ª *x9>+A9K 0hV a3=zb&hͯY[8{/F} c(zkb'b #8)t3s!\婾xua\ 㭀}PyWSCUjKTO>`d5+Y(/kׇN+H+7žCdSm6HLyNevZq!=w3~Weq⢓/zsPԾ< 6 N˨.4l>X ;荺:Gz@fWB)50T9LZ 9¿6%''m.IF0I"~_De"O~5%"ŷ#Xa$>̳|IZnCvS1NƑаuӃts h 0 Ye`ۢE*QXHw)e ,mhI FOkޛ 3OYߠg(:ͽ)xļR#0RcoY:;ިQf2?_ Iw^tA屉a n ˢоjXZ``(.~lf҇e@-}Wjǝҟ^]ێ sexg/V TY{/,gg=iwL9mNwH>3-?䳋D$ی$*d/1\T=K|xkv-.$k˷O|)Y8?f)8S=q9ugv|b=,pj!Bbm6Nv^H7 I4v' ]vkǍK[ yoOO*iz ?*+u^)})t,W|خkYd>ܢtD$۲ItM8؃K ,#rrsצOMNA^DDeh tzx<V 8;btyc5# Xa%!J5AIS~Tw: RA_qҥ6dk?rbs+S ʰo DZ0]ނ1(W!7d8€ˡp|~H<ԡoXYJ&ޏ0ؕ{uH-"'R`ҩڝp!:w*\鄎,nд[SڑLT|*> G{\Be#}_.PF5NcЛ~X6Yn7AڧYӜ#P a;ج!?.u1 .;yrBmK% \W{ b3>X0W#ۢP]疥 WkI֐xqT;SUU.jm;aܿ!#_ī^GڝTau"XY=+]elO- )g .y\{!d% ף5#`ָg$: wfya?d_ '?fC? ~&[ \j_¦2 R@4;` &_H/:03/Z2˞RN90'@NK Q,J}@2V%^+Y?ofύ9/pC><< szTSHʱ3+|g<0u=u=tiu>.#a^{h3,n2+foma*wJ#_Bh'Y%Dx=Lt'l\17a;xA8 fI]7JDôk0MwYZ K~v-ksVQ$*}z,$%* ح{o39Y4s?~N z+i֛WxN5T/l/4d1!:H`NjAFW^`BA_',)f6uB,[y˖n[u9As " :sV[Nn(K6LP'5tÙ^X2,.YZԎ 8TIg M`* |#qf4pi0ŊjõعC'm~NqD2ԻɵͮبXj}07Ì ϼ!(m7::8+AÂn/JT+9R ޥt|ѻ-'m]p8{ķ9$k4ǾIWp$<\zOZަ;ELC86&Wzq%*>Sǃ_,+Ϩhv0=g1o∣KO|~ >GaW\op+L9O\&f1;:eu831 {q#(|b ǃ{>3??ɿ{pф'SH^36/SߎKcoEMCN=L)/;ny_`! `"V-:  2.X|3? ^my▱}-oڡ6 kS(aICV'<<9E]Swz,Huj_<k{0 _¯Yq{kX(>83f$a)B5̧'}H0|fϠYLgwneaC_v7џ)3m NqcI\jo3+.kgexȽXhqǣ.&QY P)"0Tt>,|{G=v}X|)^tIG%L %}ݲΆcq'vlIrcW+˘fKϘ`LֺګOioWӢ-WǰiQ]Vjs v|EI|&W1h$vm$pmo7׹CcpO[mDž|Ƕ)Vlw!Y tRG`@CSBlIN[ Uoiv5'{iIJSpZO8CXZNʼnڬq8IA{i 8|C XWQlNck$תJ+݊sY+w+qm=R^MCf]ӺӻיYpѼb3>ǽF2p(F]3@ѱddjhT:rѯ}-,潮BݎB{]5O6-Z أDա\[zuIy<(Wc R1O땊݌&PZtiܝ  #zCM\]}FH+RH5z߶HgNkN$r(QW; v4{c޻Ş\= +6{f(x}^>86DkH+oiՓ`!!k۸'le^U@lF+J"_\ +v f^>LD6VD*M΁ 2l^+GRku~)Y:.e6GX?zfX _8AX' _nD]<{KL"BX~U"o*J}#H>scE"=N"]蕔T'7rêR_Q\}H*lywvzvfN2 `»pKSW<)>9o0DM*=R R:gk2bJT~6b |)#eroㅙ^?1I( KYƂ6#™ <΀+3a]?J1կqpo_4>UJg!p`\(e9߉Jc81k*ۖ^? S>g8HtLd\sBY]vu~`&^(~ë͋Kj/s$Z$w{ CqzdDP#0}\$y[8++Kq@KD+SԳS i:R0ĕK79H5S>$:疏R$& <5piۿf$3ZO0>NXˮ vF8r42n;g7vr5+'|ᨒ;DH,՛8IҶ7,܁+w_`ɷ4ٗp15M\erޖS_՛ָzԮ~k\Yl܁4y엙7SXoî&~yjZz렄,ֻty@A@\"JՄvp~ 僘*ڧϒܶ^*^:IeI^ qh`6cHQ7Gq'VRʛ\(SkBwvKbWΗW2S\vA!`ǙWLi(bG}J NO*rUan~-xYL k5|̘aXS Rv"/|1V _ɶ2=ٹw6-}wʑB9z٧ p?X3&VҿR?X_D+> x'>U>1\)PsUV< QǜG9j-SO&Խ  Ul0!iq` \<]JuYC[!' tgpĹs.Y{'v\>R8'CMq0l8QGcU) *|g`_ks+ƹFgN@'slrPz}h5 *i9F,YJ 9+[?r9O'4J>pcjn(p(clGt 4L6=(q=vhvnsH?/&C ]-;+\zz _`Y̺D;dI?3|p[ytˊQb/T<&:Jj7n|Qc١ŀ)bk 2ۈӲ 9ļg|/3(CߡN>U"SM})F*1P>wO4ަmgjֹBRBP0= ]LyCY2)j t׳1۰[G%!k_Ou6=dMJ 2sgi௑Wh}/jjӖKn^kCġc:VxaǺ`h|#?i mv~ ("IGAYks0Pl[v AӮ0Gyp u(cwV9 lJ9exߏMC/rn`YR9(Vxׄ,P+1 hA# T8U:U[.,Ia鑐76E'^ oEfMTȽsY,*{y،'X9_ j,!B#UQ<097FM5۷\ :709tc-Y&%%uCۮL3uh$Fʉ @d@2Բwwe4h.4Iu;cRa[#S")r3<(32lwo`ٮRnl0zF F}rzUm/oez>pߨ_NUBejXr+ ^|6v82:uW^xHpb4`WrtMɄdQ Q]n[s 9F#cvnuG13=S%h_+ ڭ mܪBƓ?_Tn!vJ=V [缿CEN܈&3%Xtmݛig\|afȴmB>ef{~^abxcml%0j(2`.&!מ]Y<'cr4u"Y\obmxp6>{'0J(0QMâ+_pBmV}Ƨ;^TݩF/Ohͭ }:,{ ح>vV)D4xydT*bO_{C_G:82~/Zˈ\ފ;VL+1TF'6ۮ2c@V2Eyuf>eK/whk~2O –óyq5?l+=_޾=VL;,abb@z.֟V:K\%o:cI,)[t;[ah#){Yu*r .w1c0ʇneԿv(HYx ԶcN&Cq_f9CW.ᐍaDx​#Ň6=|쌮#)8brβ:ro3[bnA4+1x9?Np0Ճ*L^@!Gs'G~1áu 5sŲO/ϣ^w[ݺ9CbMaY[حD {[? pS8=S"Z]q <ʅ8C&N'+˿]3٧HH=\;V73 vg<1{bn1,x<-Ky&:+8hx?M8c FxaY.?<7Z냽q"6ES+!5!Le(-{w@ӿbЀY`!9AQE z~z [ͳXd|zoA,_d u mL}W`][1P2ם|27_4~tP>hb:0g^oP"G.Ga*ˇ!X^^$I lqW#z-̔wA#Hz2(X^SzfCTA+iSk$~CtbmDh^6z?jWWlOCzE42:/A􅲘5 v{qF>ޓ㭻bؤ%t>V㬄z ?k!\!vo?)|8`vtWn"&  :|"%QZEm%J"8 O$82bmPRN^* M^ eOR`WaxULHo.r;Έ^U=IMg {KvW$~$᳖iוߓh(rHt-,H޻/'y~;杔+ U+u5>Q%њrt؇DE&k\paUbFêF^N%1ph򥜓fu3kP$RF"H~:ќG.r!x3Z'h 9M;F)sO%Q/p@rw$e3Hww\AD@)폁? n$η޲Ý:*zo^3o=ARq%Q+Z+I&Q$<;wDY۰m՝Y[W5V%PGYI vOaa&o:e _YT y7ff^OS2p$E$7H8(ۍGD2-t?rԀ4>xmc;*y/q=Ll!_4+Dsl'r65 9 )IAI0D Y5o=\$ȕw.qgrLQe?O'ȃ%}ǡQs"6 |cv  X-5@u+FZhޭʸ/[zI3?/lkLr$i/x g2~t`?{ϖHxUfw$Pz"^]êkŃDB͋N5ǒDhy8\Eg:>ID\yDRu Bi&|u2&R>P8}t'Amy\s)|D|e+73By]/= _m}Ht.jʐ^olmgzAo5>C$\zQsH4 L{2>QD*o?57c7tA`vFξ }@ oK^J~ m~&TW=`u5XDy>KTσ H}'6}\ v&`Iў>V:2_}Be gkUaQPֱg&rlJF>^罛 `N$0 Zy(X[Nv*,L}U/ȇIݷanTViji7' qsxϵڎNq@ #u + e{B{B_ysmgsZW0Τ? -_Fn@^paV[L0mlg;,c$2 9wO9Zc g`h]Ud䒸^kp=`(e-e`Xs7bw9a-kR@@=js'=dAVc0N}Vyc$`6{0rӉzkg܀MDq*XΙqA8Q6DzNuovȼ>7&Qia,֡06GC|eF6sM" }<=:H1.پ$uqyZ{c$GW/Ucڷ7̵Oe?*dLz Fh#X17:x?lt骘31`'Qu#WQh1s5XI_Qs*qG@i CV4^U1ͤy}J{.a9#i+X.Ͽ~.|崅4KX35Q4?-zW;Y:a%q? ) 06JtNKbX^ ElSԿl#gjxv=?nx9sf_hОiDzc8x}ںC?!45qSO|Sh±pFfqC0 v]M oߣ6pΉH(|neu<ق?(ןa M %dIpei\y-]kWǍ'= A=,=e#]FQ_dp/곏6;A׋N|_kegR L긇_;lEq:7vlp嬕zO[|5SQm8@!(dÞ ԶJK鼯%qW7+5u{d~N~̫O$Jv"R^'e%Rw}RbNަ$IU@$4꜡$4s+'n懽?[Tvw"C.F%3"'Ɖas-Q3"K945nJ6Y-L4zAYf|Vɗ‰3TAjmfD)T{ތQ!R9G&TME">˼ Şݬ>.GC8u;k0T_o8ÅcbhB+Q˗X=M zʎdV$#c8f W-鴼w ƄbY% o5WKo6,Mb:\pAoẸ[C?.3 N5Ņԋ!mqJ&.isWr^G|Qǀ.Ov\[RU_2vb8)4pE)ES L\|RO{ډ%<2_킄OXmޖ^;Z*3 Nb-* ]) oRaWaW֙|(:l\ayg- 'ylŅ$)а0 24Kx> ;`|~d @UhǼ(9qҘDje7bF|;=mM^*{0'x|/=7%BC4D8"?x.Aó~PǛ*4y8s;T[ ׹sQM"^޹Q)FUwf;ATY{6G_V:qoէ,ogA"L&Lx)췹1P5l/V;Lۿ§0vrKJT|Ji nŷ`o&uh >ԏMgC(O÷`"HaA\whװ1}C n\EZ?n"J%daʢdǞOf"vC<z(ÂIP yFj'b~(g {\P@oM69%l3[Rl/'] ^[] zlѬv]=kk ȸ%,l8](njc7=g5/%`$X՛]]XJN2cuKuEدj0-ztCo* :YƨC܌]>(^M! UaO.2L;Zqh0Ѷ: ^8f2oo`Eq0/#rx l4~My;SxI ~ݍ?]GOŨ OWcwx%1hF#\\/eCЈ= [jo\O4r<}Th8zŪA 3ys 34nheK 2qW1_)-to\mj$Op\kz搜KձԸ3^MR%^<!ohqϥ*]?+\m.PjArs4W`O8G<L=}kPiyjr ŽqT 3eN 9]9=8U{S0.ȴġ&@\_8#W}/<[&[{p54yy矘ij*ˆ1awI<*v>s%j7UJF1N4;z]wvs!:o)>=$b׍ qV٣бIZ=6R8am9lŠWJl|q+{NLJy@^l'XPFCeU8}~\o歏`\a%U_~};;cGAvY*6+f[%fY:i"|Y&0wBٜr"' \_Q~ݺpH?<'('vB7?NcPB{w70ާj̫+n=*f/lԋ |eST w_cqM -vʪ _=RgRGBg)(p|\?LS~ B `.Or8e}`ӧ7AQ6$KPu=CְhDЊ,ф{55n8v.B0Z~L T@w(Ovy7T2ŒGixK^rQb+2<`X==E? LC i), 2 0|-'H>^~@Hw %PYN]wSDyt=kVc%\y ^};V #DTa? r;^y6o?GZ;_&|R@b0#RlӅ+n|`[\n0Br &*Z}R0h4, c~Q칂mJ0,JXtn MbcYj&k0dfUQ ːaRu)Xb`sZŸig}sG\„WK?M3} @ڵ]ƢNiKS`Ew 1AA $y .;5ahGMlM̆?TP M،% oy0e 3ٯs=Y7J3v09 "Le>;{V&7zügO) ż00{5Y{j$_~4K/ȩ F0=5O$4bWspP8j.Mof4vٸ6 W?BR/aNEXz[a(Ѩā1mbDX}tQ㠘k͡0!8Q[ѤYu Im[U,o̱>=/ۋav*ߠQA [(8,bi?o6Lm?OY@ 6<9wp!,/wڄGn b `#oc_^LAuLE̽{HsIq~ذ[I'ql47P ֗^ܣ@z[I_X{c܊3=m`NS|KS5VLOT "rVaMg,{'ސ<<124c23ׯ+i>β((hQ=e` }?&"wvk~ǰxí;Sxg{_bO_ϕ[m!{5<ίW1ΉmBF!_8qpfD$-Vji&~ ۳`KT>Tz>~uڨEcoTJS(Tz6lf\ v}DY3̡}6J$[Njc/3أxmPe-,N`_Əz/RHmJn;ppWD/|'X(}%Ovbv|~[r2nBD{dd'm`%A7ȐBFi\zp,Arm\*;w&h@pс5l i㷊VbXO{4U[hW\9ר)5"( J3}`-\4fT/ mVm vp](*Z7\~$Eм:ń -fGUBۭx7ͫ}%%_s$/O|nv=5l+m=4/]1]P˚r>MZsCSFp1jN|ȟ LOk&pݼ=*-C9Sw3w^;F~A[\i*W` G8dQhV;f}Q` ҕ~=4@:VaAY K'9Z/>sx=ɍw]! (G,xfô0/215%3>_ƭЗ=9%mRGT9ZNEJh :& WtIKQJ~nxvϵRwwWzXb̼\c^F֚s٨?Pa~8ρ_t] ?غzfh2 +Pnib&gny."5-D;.wUDQo]4/ j)T-էpQ>(՚e9"Փ;$DZm6H}3"JwkDjjN4J-’ĝ|fdpkǕ;qm{TDIDM>F\m2fwOS,%~9H||nW36;^YDLlj=pdʧB>L<7f_8 u_̕?]1wYPa±ͲO&硭T|Ft 9:NvÄbZv5"꾃7~A逸CkJx }Hy}fBg[f]!4]Aqcy 0aZ=Lp?g?2dnP]+lKϻy 2_܍O:o΃̩R0Ws:WS(#Ï)¡^ؽ.v> ƾVZgϦ87tm3aЋ3.6쁺Q?VG<7yT4ʼ䋆Y89?GZ`B?3u%PVM ^">]/ L$$* tbG(| Gi5rg")`Y [BcD |) 6H [+.zh?!]F6]s[u@YWaz<"61UJy{-#PHoYE',woӹ+!]dKdᾌnu-wp5lܒf>O=-[{hÇH" !#z8"훫9D \kUT"|=TIfەCq4q̠WWX.ju R׊<,MnSHys6xbH'8Bd|CuYHSP=ooiM*-ƇVԩJwDꎙ>nI FxHy7DR2lg'a!], m7O. ׼ pqu)x3F܃XVD2`dZ}+ze䌨~Q4SS541PurGT6#} Tb/xazehyXzCcq@qu.vW#|D_ر@1K7p'l~A;xgYX^L0 cʄa.Nf=c2WGb! ]8b]k 0<x@UeGt@Y2 Εr0+Qr?Xo*w/FN/+hz0!0uRnJhAa/[٬H45[W:x1HbZP^}tn@0e6PhzdK |ՅI0Hu[Z) .yCbOoJYx;, 6h  iq={8Otlɖ:j-lEU&Uh/M ymwvD#4J}8 T>r_ge %ok4 q[3|񆵏gб)^a8+-r[G9A! -U};1Cdu~ju>X>zy,JL V8 l B!fYz'JWh чYfPGMk w'&ٹV{%IX,NVi1y4C!Kh| (̤?띮Sg_,F͘ ~zx?)c(`[oqE=:ɪkdF\x"Q=cJJ՘EŦ X\R[a3Wv\Ĺ_ߤ%Z˄Fh@$gsd^$o{;,D`Goͨ .ɫ2ǵƺGN#l.~U#q=@,a]cE!·8{Q;P>>;u{޺<\8SR||72Yvwkä"EJsmP1$ "qQOwXr}HZ~ט>? FGp岽w_ 4fyvԸаg6H,ҷl@~fY9GE U ZjY<7.:~"(T?9 52rTTAYB@Zn+лo/ Ի)/M 3BW-ns";MmpzEh-p:=aO!Qb9 9qy';|2"EF`3tNs2=*ZςY^ihY5Gޭ g@[m(vJ`k  10}Q++ٴS;,}^͇&MʡCdh;Ll_y`oʃ Rp[VݛJ<plj+cЖӛ&&}xk IN8 ɖQDA`x 4.6쏨?=R6%r7sGEGӍ@ d ӹzbǁ\yjXk4ӭݬނ@lj T07Ch?qk+S f,;&YŒ6a"ݱW?e0iYM;G,/5I`1{Y< 3!L&,0>b~[LD1o8Y<i_1o;HaeT| ]v}g0g:HySf_F`䒹e,8:̗hmIEk8=0] v@>r5L^ZI9|IRaaiZf>yP4)PݫaB~_C!坕#9OL0aO}t3u~嚏vU/Y`z̷#ό_a]wr!bj@Su1-V?%9{lѓ5~XMFbC{ى-4?|JXd+ʆ2:aO\rwziuJWޮaY]c4Fvl g_@ܛ}+NJt+>ptyT]m>mZT1mw[!<"z wAboh!}_jޚ]WQgp[2b[&÷wXW,EjБyWgc qW8~H30Ƀ'E3ǿKC3*H9A>?U 2o/4{oub}Ӏ*l# ίwRct4! T1W͑?b '(C]уWB@ bh.ZOm{ۡ+PP<γC1\ޞl3JNPk6 ZPѿK {? J% `ӏ S´' #${т:vDžuXY4IF&qimH-MO}?CvfcCo.AJ3}{ zlEX^kzm 0lܔ{Z IN&6*t|v}.miz!1Pv+\n;AAsz"Uޛ8 &{Bjh1͘&^e5WP%,n0)'FOA㳬 0+_dui1_C6yCB\MG~G?Kg*_ auXٷe{+y4Hc+`lL{loslu8ճE"9u$nӜ;8\> &Œu/`֬7fhh.PbBcQwz4`f[[, /'H(_OnJv~,wu}T@*;+< eLvn]7A<$hzY?P?uL&Ҧ2̪,M~߾^)CRb].q\YNO]kij? 헨$2XDZ.m_&oH֞,FiTm²3m*A s:b/LG09w$2ȧV,x؋ nESö^qWi=V8*BM1g*)C!j7S|^rEm^W.( x@kY8^ls5}1= y!X1\)\66Dr:Iaw썣sOfٱ3SQɂm~mS0S?GbcBsoّH4"[ c=.s83zA(:( Α&UT+Ċoɶlohwgmڃoȏ]Rv/~PqOHj[}%w;KItXM jy{b,F{ ?/)W͚D8uq2h{{U"Z (pƸ`sf$= <"U8oqU%9*vQ8Yrřr%GGQ|/S gϼ.™ꁵXzbSH‰-q~aZ > ۿŗҚz#'N-%uёƒ,18z:Ԇ)NgV'͸d}w8ع#Fg Niэ6g$i32~~c>Ǒl'/~Y I]uY5y}8y'39v?ܦU|#B[{{Lql*C' WqF,>>$"/& LŠg551h>8+*#Ň LtA+H0%a3 64ϺgOԬPW%fETa7kV^lW\g!Dɺ=pr/iĪ9AǸh*QsŒ8ۣPPd]:OǴ бh5k~.. `īQHt ^xu/@q6j4(¾K$Xu-Ȗ#Nȴ.L{$E`2>uX<.W[\F;J}c9, ԺV_aP*G0A z?:Ip*;W6t[24ٳ_&U ֓YP^l1E~s:дJK{OX(; PKof׋>agO<]m c0+mJ3l"Xg ;2soÀ ]0f(Iw^Q3k>OxtϦ^q07FhGk*{v/'bX!)LC$0 tT!p 2 `GC')vbyltB܄/HL"đt c`M""֪뚼 dzo#ZfsC;mrɥ0nʴb#F #un. MU0rW(㵥WP7?$삵ӈ|bb=!D-V )_;Gsg$t#e)A ު{UĒj zE2^y$;|V`{ _`*Ysp}4_p=xf(\g<>#)RnfE=_%KC$1*7 sb(D^bǷ䕠zU3Mjaf*l[cذC6(g?KoZ#6~X8 ]SMϯJ|!aj Z_j=Pj!W~`\a8y{ǶtmqNKqW?]q`辥$ 8!/+ 2g8.J!B:_/,е)~:U aXœQal|. [,Hvk9st]o̪Uk6Y&e3vgJJ 68ǪcM0p턹R8E:>-*hX@`{:,u9(bz],-nׄImϱ̑unٻ%p{"t+܏MR)?R%R0fh"RE{\%R';DA-1%R}QbF/8O$NrЄHk\FMj#X :B ԅ+wZԿs$Rо<-D4vHys?/TS=z1p+KQ&=R$"nNч.DJ,CT~9J#2,'JN+6DO'qiys i &+D*D꓇ՒDlD[KFloT"RG\t{d4e_=Hy->cpHBq.[װR"UѤ;D_r;3aQĨn2ɇ3v<5(=#3'on׻Fz0zi˝ lNL饿.Cܤvv>z(t8,]!]?191*-儘IWZ |s9+]a϶ЃÚ,0T> :/*RkX}&6OpgzWl1Du &-7 01*%{ /^ٳ 꺬G~!!ү}p5 ׍'b`&Cf70+|~(RM~3m}2oO #)i/C[/Oy' ~AݕceVـ P&c>g3N&S){O?l?t2@Y,ݕ q CE9WÌɻ'|`j'NI4.3t4ӇqCz尠uC/7N$yC9 ûzTAgu.+~hL>7TYOӃ `Aߎ~ p%pT?-W:ٔQi{xkah/ŮSXsVZoެn70#jZ\aZ`#KtjeIKɎ[%G7p 4guLkֹDWݶQ8bhAZ-!bnΙd l'G&xn>f$R8Ȇ*?mB4_q[/u7Ήij؉[R_`tHa|S%GI"}(F"EI )w6o*'RO|Hعx#k۽jO) Ո4\?_;M`ڎטHJJd7ZOM(?yHOoH]'QH!.))e{]xʂz/5TbVJdE "S6&D*K?I`!U9t߸(dQwl# Y-#Twr~ү+P0Ї6^~o`&=~dø-;.O*;_O8F*hK"Ӱ tܿ9'r”\qc 2q-K&11JO9Gqyulb0\튭ŗ^Z`.]wV 2?Q߸IW`nC+>t}f_bjUhX+# B9mv=5O|x|k A.%~@ojF*hou.;gupzA},i >j7*N(Xo E=rZwu0&+*ˊێw@s ]h. XypH3r(&0\qHV?aM7 ֎]S}cNşq|[aztԑ YSa.t(@k}G b6g/]W~Ì@6b e[Ҫ2x"K?@y<) KưpJ̙v 冕DB? ?vG}h`Ϋ,|d2yڦKRr?Srd K&,1v2Nע6f]R.E[/sm[4=&&4w?n*ҁ&#i^%+^}R4u7W!՛#kNX]]&k]y#/)B#JgnBg[M V:\ PJxukf/0 w \SlLз]hx/iN6)]uxy~a ׾ck&gȺ{Q&TT 5nl6`S l9>cW7'O"ֽp|]a4lqHJ#m.CAﷰf)$S eݰƂBaȊ[aEu 鑶PAug+[ٻ.K=~)K=c Z2L)P59 b71J%vo$z#Z^a}&L}~yJin/?'(+fcRkd[bhl;RT#:zu3:v?z3,YCږXêR]͜ZI?ο,0[]@څsE=p.lps.TS`s2zXRLZ'Rj$~Zy u ..ܘkޟXTԁc"}A^B|8>z_?'e7>\֛4dJ.Lz֛ 4OTmcOn7ASeCG1Gɴ%=U%v!`&j"VŒZ;|06vCt__@=o*qO'^x)' \yMBQÉtm0`"&H9ԟmVogD]dvMgo&7 %[5_4!|᯾)v{p\s.3 _Ja`L 0,ʵ1̨DPj[0->k~ c0\ : ='dn?daQ`I5L-nAÞr 20O&lބ yA-gq:6NזYvŲ ,yӔ2f;`>lL{davAW[6Xch)}5/kai67[w3]oo3< $O5{J`I5a\_ZL+`輂8M2,J9^U\a~1l݃E%~0{ =TY/.'jOcVG"9Y.f2|3RB )X9E>aqMg|v5 ռIXr8aBk;-n0ݎPSc_U\}  }Uoay=o лXyBFzp7ZajN l梫m+eǟ=_2 Dž"]גj86 2=?V) BciTp{c̲/+VTd*M5g?=ϻo)[wpK{o2҇Oɟٞ1`n7F14 4"eH/So)=|}P݋Va+7W{IS Q$' y#DR6|9N<~nzzo*=n ?Ņ_ynS>)wFpcf8r>ӪI`#"%UT&)8$xi#6m|}ھ;*yt\$G8'wy=yKD${c.q|J@ :v0\Ɔj*Bm°cfKU,Ujg,GL{ _m-Jrj(ϑ7f I& :1waͯզ+lyMXW2²HÇ:X48-lܘID tkB+81Z&P󛄚^ϖ"aaYziLD4b<&J7qȻ$sa&Q=it\}~74ݽ%e.{gp#N&-9 H⌊:hg<*Pöq!{07ˏWqXcru8#[(MPS|1HBj#}9%u6v?GG&yksXȦ)sǞǴ?Bki[o/3G7aDA\l1E/RHyT1Wj7#iHOs{OMX| ŃJqwPGL9N{|H܏K)Q)uFn<.MĝkU';)8t'OnNƩ!5J"-?pVQׁղFFf),xyuo\8a>"/':t.RFӯlni%}܂[>{[q#%%NޜTrÍy,Q~"E]qH7U^joyE"e^šD*zFG#'Re6ٸC-_g\Kw$tVIX /6FbJĮZiERub=5]z5eݪMJ06nvj0DON MbFJMݙG>,,3ʱt] SϠFZE]]"eQzR7*2՘8b@l9uS^[OKn1`OM=MGFR!r ۲J2P3n2´1 u{jfcqg܆t}j+O9`z6 9+s5#VޤՏUAR=E%):k#w;쳉@ ` 0&n~g1уLܡ?5l 38͏ ]jҶ+>^8LW}V*`x"nlq2j *-EDmp>].x UIso8~w@_4og}F߰q: EoslAQ퇿NqN"d.sޔ]?v[XZ@_hPDj)/),44 oX#3D##n% y*ًS"8)O[зZbh~v'tQ}a=D}VK ?:-)Ն ;ҥ)XQq,?TJ{R/c= }X6~ѬIl[Xu v0g|^z^rZ &J\@'|.Gc?Ih GEZLkÿJjc!bMeNJV#18'CϫiΦȯWqyg/L\"fyR cY _Z0Sa5DܞoT!pl?>Lg V5&P"h= { mea_ Ǔ:I cH,0{!?k 9d yn̯<[9y*o#xto(YQ&bUG>9hYKUb9hJ-Ǭ]OCuY*Gj8/ٜ癦XY฾XTMI UN(8>"w;O\ه$)EB8.m^"L2Zq1æq|q%'{oJD*`$!?wy|R@IdkqTEW1IA_~N:m{h)&jO{-?r?ԡg# b3DZ `qCfgf*-p*,1XK\ Bo [ێ{~a g`M 'S-}qK%i&Ý6[*}<#eS7]ˊF3МO}cRfĔHJ(1ޑM 6 zBFz3/% P|W<}-DҲddgJPa۲!nǡ|u(V-Ħ4/C Sl[#. HjB׊L[),:e Μ1xT~%7OG @"P$yJJҳM΋ʑePSOV6uvV`ݓ7M?cN=c¶o跐6ya< <']=MlrRf{nNJCgFn S{ΐD`|s!T  *cO8c5`/G; 9})Ǡ*EƃwWv' _qK߉ZRtwq,-0NQ.T{ \DŽX^!xh*//0SM, |e0}5%|i] A5_uC= :E*3aV.^.%転zt=jn2Nz¬>r0b|x!]+Rm =-w`T.wС m̠{qsT{;j} k&)zk.-{wVŒCWtb8ʷ wg6k:_OT|P}DrdUrRăC/['4Fq@dLWU&6 \֣gx&`]_!h@GЦ9lIwb& ?QV/s@Etr z.NJ\3yξ rAr="PFɬC0tJi NlHKtبz2kx%CMٜ"`˞psSh&PGXgvv&bza/CmV&uw1NN;e sG2Rw+^[ ô[=`X۽40= @ΉWU*„n&*~㱶 Cr{agR)%kj=ab^WJ.~rUSg( ܳ`} Ojzy05)QW]*I?L#v0zJk>Ht!d߭&-3Ն *_4 rk- p8uNZmd)6Y lu7s$R|.]\.×|@L,5'֞]!8UFo#^Ғ/}Jsz |khMA{ihwP/v0x~'eLcuCx}kxu %t^*td0.L[jU@^09Kc/y?Aс^v[ SMڗaՊ%tf}yݘ?ָ[a0z U!/7+SbՎ 'ڧT8Vu(FJ|{Bm/?_x:Vd ZZ4;pnr) +i҆ƮpQ+k?geMi"_c}|סvás5q鋜ҚPyѬ ⅂/za9֝Urݠր7P`Ʋ'6?YL&ulpxoaQ"_-V)*K ?hJ8&ԔTVzy"x3滀3,?񒪑 eTߏ8 s$E6`˻Rg/(K)eBj}Dէn XQr,Dm^7c Pv^z82jmKGt!iG&$o Y<mMXl ŻRX$~ #8a+w.ΩIhۉCNp0FI kGI/ފ4["Y*hf5%9/"C?|* %.H=e›+2Ts9ᬄYtH*ĥs9 XcC9-Y;jӆf3Xa0yOX"gۙF'Q;wR,73BN5:_91[mt7bp_ȸ`6߆V@ghS[/Ht̄\2\X3yD6캞# b*qAZ^s+֐%o2Bpq`^iS$<H=pY>l[=|.(*9 OaS_+ӵBj\|Ձ%+>s8dq,"Mi)Lk7M1rf;ABQQ\ڜ ={< о[tZQ!rr<:b}d EzQeA \%} ru+4uLpPݠ*e9t\_- Nk/EW}ija]IakV9> 6EI CcCؚ^d/; ٌB/CC-uѴ#zL|c<F>_CKLIJ?m8;OBubN~B0?t޼ ќAVY0yy&3J9\!,u\הts q+EBE7w|[&Y7 ɺZ\hhw ROQGV`gt]VѼ)f[tSԥ\]'R5fo2S у4TPs$P@<50ʾQB< ict x;HȦ}߳$];kBgvc]ӻsϰCQ|j}%]$telUTQ<|M馋Фb2 IN4_aTiStS3g˻_;Fg);Y RA{ 0u"(zo}( 喏\לK&R[a*El]Nx'-ll!YWu5  Ï=XT!AĄ.r9rE=QVs>} hu3`}\X~TTq]ϟaOJ 0.[7 Աr.zv:}K=LNc=OV 'yv>d&=ؼeT(ƞNշݰDmHڽ.amGw8QuuR4ĺo#=/MI&br8U>qn749~nțU߻ GbŚ4I*u-d]44V"A0~\8}sBmp-|8 +eIIa{eOq:!a8Je8X\=;O:bW? 4aO0j#6Ί6PQ^Kv,\8;;/k.\ o=Qc8"u˶lq"Y}@n2} _ޱw2ov%g`V 3д;֎9Iߧ>vgpW#}KfkMކ8p';O@a/"M:ۖ[S.>|i1^w 1|6Эk9o@9߱|K.`} ?!! (8`kLTUvvd&hM[z# h@ )COy#,][x9bgT.?$<À1+$M[֧;Pݴ5B|sRI{`oU'ؕ[~ebTb3'N &:͚`E~dY,L-,.Cئ6lF,D>|j> 4%Q0<]lBD?gث׽ݛ޴>r˛kaPrU 3%v_9 H.gǯBkv0wUt;F@ś@MQEFͷ@@3"@mRFVXT@vcu@5;|zK.@=R9ɇ?NhJGh}:tCwh}Uǃ@cfy@q!GmIT ~|ִ; Ed fYT{]気ԧ8^k>/_{szU-qv :ėto $AGU>Z5PaJC?}u؛xׯ,?:-\#,Yv8UIfC HVړζF#L8`́wq2-S8*ىDڟgCu)݋E*ոQd;Evĩny)$}D8k#neTzf .<r@0 ;L֭]ub}o\J}{3Aͧ\nk_|ޟY*ž \)Bn`-gp!s;.H}?R.*(2+!쳁^XMag; z FU)_0 τ{J Erx\83QV)$_Yو__~e1M"\3L}|}7_J\Yips$DvW$ W?#[COq9HuSPuU8p!pwʐo~fNEDž|QH&xV~EW8+@gd&yq[CC/:ԯF0u˽RӴhAh6s- }A0!vn%&C=s{:FuOU 773Sȣ) yDu pIeL2hj̀nk3Ob{}] Ӟ/lVM)2Ʀw+ql^zO'j O yH8;RO`$+fB\nO-t/;_ $!KCuW̾WOt^g30gMXQZEebN[Hw07 ,%iAf.Y`.NY[kXC `]-!,!A$EY{3aFīk>|,(y# uk#0Ink5ͻMXlW F3 Y?H04y q>awW]v.܊{}ao5XZ0끑=,e%0wMR^w(Ir(=oM5>?3}՞S0tN?tFvnXz~'rZx.m țr0`7&ht9PPg} mN^Y/ a#ỏ?m |'pÁ1@J-?:ѱZMl#+'>Uxo)6$lxx ]L(?l'PEEkLQ^g- [A!ՙI>I2 J'|s_@#|㜲<-Z˜k5TrV2 t&]=q`q>E:8 Vt¦X ?IǨw^AwXq֟;>N Pkqe[!#;{ji;Ga]676)SZ9q&qEX٥A}V~fEâu.|E&J;% {1XM}*E`qf{1D%l  W>(.(@_" oO9at}f(&p@u`u'~UTXH%(d(G|:kTk8O<#< >i}'ކʠ:N<H,1ف$%T/R0kuП3qL-Ҷ4EftaNC *7ݸi~P éؐ; o{fzPsqW&agMV8#JC99Lpl%׀i F[ǐW\p9z6'Q]? = !dqBK=y;Fwax$,KO[Z`ɐ}P\Ɛ8 8>?RfRs3Z aL~f{z.yiJf8,E_ے ܲߊ*cݪ:LD(.%:D*r篸zb=#IH Etc.}5\|7^b RERYH}Wt2u?dҠHF0^ي)!٢2Bi2l{|<_ysx۹N+NGF)`&FGT|aWھ Ii?: p ^ " Uןe3n,Tލw$^ptz!DC8]{rfZ.-V"v+"@2 YΎ0/Ź04e.$znziqB/1F K I(9BD]6=&yC$%dUz׆.IzxMT~>\zK&ͱi$H,uGu:y1a%_ʮ-`6ۣX\ꆕc1AbqY:P/+`βc",fP2A:x0ò,|GF&GEqp=I~Qfe`_{اl?> &^ِ 㯂t6㟍ۼ:=E \Æ'ٰ^z&7>HJԄHil*SiA{z .M|Z =VVj*_~6p_>^^TrPWE2cǥg+in]׼Wx{C4{c׌# b T΋'Q!`I&CN媩x}=r B,4|~dafuI'\O>o8^Fao=gs0νd}MU# 6yMȗh*l ?`ZI3n}2J'rŰY?"W!o~ω/|;AQMf>'j11%H۟ sT13}-VYvo[B?|'˟G:?KgĮClJM5Y"iz6xnR{|+쵬F/xF FG>ҧh)T]2U W7ruC{4-3SADhmv("2"0`-S;'z`o+_R޸,R)z76 DEv`W vXq񻬳1@1;׸Ėɷd\ :a9? {` GNmB᤾#w&:NrrWӐ0@=׭6 sgѡwÆT qvKbeg)*~(FFs-AC/GAJlމ* '&/0fh?AR1 ՚jcTa5X8v%/kO#58 kB]pIEΩ@ SN+}3C#$k@MЖj2]q{r'Ҁߛ1V?ԦeYq>r3"c+0ʃEpBaESEhѝ>5QmM%9-Ηq֕Ik=^ S3#8pa'.LjOx|Ϸp,WrN&v<ͪb3b θ2A٥q=q(J)~ĶBG>3\8zLNn]ݬt'$ʐLByZ\yY3oWvj\lG'8RPߌ<]J9,wlܒ?SƍƲ8}\?NDV 2c78&H3d(0jFUTnѱ8sn}Ž'HYbvM! Uy{cjhlICEI4^{)}Q+E݋%_c>TY߻nL *ܱkIP KDnP 0_nWcv;#b ՇEUtFHya?ιe1zY,~f~T,!?d;硱o,٤13AV o?QfBLHQ{|F^<3LNůiC:3'JIޯD@e[[AkncP5]gHt=ޔڿ{ɢHH@zWB >ݩs JܙsEyjPQԻ=$ )~dy(-[9:_p 5%̫\wϖZ2N@g%5 0XmP f~sGk@uy1)Y)0ágh }tщMݲ#zi<=J?`cn1Pvht^ډamQjPt-͡{#y.o_}yAWAxVx (9ar[|-W sBE^(K,w#9`[ 57=VH* ^wzA + x|Q;CJ8Zʃqꚛ7a$[$ F{1Ao¶_8+wœ_fP>r|T{(s"8+tsQ_/΅51>23A]O~py~g.>3/hb;Ł3BQ85fbΓ?=.{ǷJ(SCߡ<;s7N>>ǙVX;"vL}AMv-.㨟;Y#0 KL*k8WcMĞƊ8 tk폟:tgbE^t`^G6R E dJ!Zl;\.WI Aww_!8-U I 3TlŘo87wLk/rѿg>P}*5*:#aƆ9q@LJaxYdG^SXBCOv= ~6-*{pN,9/ޘ^Obq}Y;`N!.Y:(KpfLJ̫5.JAi^Odj2- nGXy+ ]j`- 2Ԥ bC+>nTUQ rr@3q" 𶎰Bu-?CfXz9*XBOC0yPB/6=]l[]}5\bv^F=݌{b ۈ+wliK"T/t֙F, h_h-9qμg7s`'hv{ %|S/bi/i4ʑv@z@'l6-U1yK4;i7b!Y uL+|cqK+-_ށ1zzR]=a\N./[Fq=37M xEu;,ړ4eV *{V`.7W>,4h.Y2Cyğ\:{|uv}hrfblW`:w͍@*(p<];\!K[,tg,ٹӏ~%#.wVи1Sݪ{`TKi{0d8O@ΤdHjXr`7d}dnDrٟDr#H$/s@$;DT}*q?H%D2ױOH7^h ![zX))|z_v) %5I5"7fu"YA|A:RJCdctqH2O$dsw=rld6 DG/̅a>ѤY8Q_}M\+2 av * `޽N&^4ӆfL0xu](9*Y[7]z ?u,%3L*Ξ뎅2k0A|u?3헚ؼa{ T7I#e}Uy|R[f)$>r< F..t`Z|A8l1G`l]?i.5J>Ps2tK٨)dfLCa{{Tat2+BUOkE A59G:;B˹pEl<ʡ{ @3s>hIwy^No6&?j>NׂuX̢8G bl/Se $KK-=cǠ'@R՞N.Ȏ:%d%bc97n}c:=ROg$mHG#lfXyi3 +''tϪ mǵYSSQr f't {%4aK'{&{[@V:x)u׭s1=/ak62w2l+o וW, Tyex`kA29}&]BD`Wp2(s;2>ѧzKmY^өak܁MuW֐g:ɍw }&#?6)WڔJV5쳚%F0)G7-t*-C@;c1n.!,˻KNB7 MG^^Ճt{ Z߸ A]u'+H:xJ%e{(2FP}Pn#lυU9Б+c{5|OeP.z8D釨C-vNL9wVUBWLEA]z{!Ia@2wHx +/] TsCQ4Άٚ558Dwot aԉX {jEu93pĦZP&ug WIԆR) EoG\4`t."-Ô֚<ےL¢2-鮑ƠPeZI&`2{-o@p &}a=JB|XV)wGCɉWڸR+W|6![J*Cc l3qo4qVeT)xIs!ޯHv&1}l,=ui=οH AѬ}uPB[9hr]tT@?o@xe*oTd6k Ѕ\׋o1zelHb4 |UjI34*:? K<7$}la nz$M= r+*P㲧 ge NY?e`BUu2=f x?\:C:qKeEhc%dzdzI3`C.\R$8Z8 ]H)kI-l9wg-$oL "-A HI -jV z|zx 6ΉN%o̜VEu[ z?=ak;.)M9~-MŏgTjSQK{oa< OʴJw:ƃ5!KQVV]^Ht{IQ{&قŰMwI@lvy:cm-}co PSHL c6~L:MU5 '[Ɏȟ)R PL?S> E7Rֹ 3׶9v8?+L'?LH9+,Y2kt˸ڬ|UŒ8snnT坻0FR3F-G a쫙pqdJ&|m<8JT,sԹ+WkS6R^u̼j㪄c#W^Tw:#2?9Ze-~4gmQ٪P|AP7 y^{Y gB핶Rae_qƩR-uOnJʸ_,14 r}'o^S?FzcBvK: wqԧ͟O׾P?d3Lb=T0oKlaq|>ej>ӧxa^(ѸLv/+B \ FF8vh-.^ʹ:o3ipq@HհHQ94Ukv##;t*U⠀Fge"M{D$_%sG~:Hta |v qΪI+FH;eX=%5d> dcv2{S^_~қ㯒`b-|ƒkiFbn#9,ƾ|Ry$3{ACq 8om0V:uQhP7Ũ\zGv0q_шj\t"Ga~ء\,v2F>,6akP^/z&:h1k=<}hzy]:~N !yg`HqW= 7bUF}ܸX$uXΌf3+ Oayd΋ޡ<~m2WʃCwSwX=X֯}UkJ`VXW9vo- ![›~Ch lIr"njѸ]U]߹78܃V߆aiz,54s*\,`UD⊟,y)a#2)Xk ޛyh lf0z ] xvN1/Ɓ{ $q2 tۯw {i_s?_bui [<%Kc~&Lzs<5"GHDWb*ļZ-egᚬ8#d~1=}0i3 q/fF`M˙fO,ž7APd'aL\ғA ߾c­N8#jr ':xspp=C<6^S=lI)B6V4dbLE07kI)M ő8٢{8}Z .ѵ;x 8(ty/sP8RRtyJ-i^yخ٤3Mpu3 |zNJ*-7LEi\ܰHmsGJk\gbF;Hs{ęTT8xNLmu/[=. BRtFU+dLB ixT$;M&+A?0J&{:EGnC@ |E=Gأk͟0%hp6fy]' K`dv͆Fd ݡ*!ZܬACP-|) Er$,Xts譠8Sq_<7jHHm/]yWگX߅SAbz 4GO@I3*K0xAvΒqzy@KneQB=bk>Jot*|L^{jBS1!sHFωh$@͕zj2Pvq'$ 9@Gީ<*}˯V}ؐǦR UY|߰[jl)gx \+y?Z8ۇ-E,)e=lIT`Ă Kz X=8TH\_a[vBgxj -Vt8Xcq+C=9o|]n_Ke2_/aˮ(]n~vsEE(0KRqm{{ADK`/2%&r[,#^%aRQQ}H'/e%; ɫ律bBճp:X KwkP,gJ9cһGP^)K|2XusƤ;)k'C᎙DK?g*s՘<0_(bq1]{^;q|Ω{B\,Dd)0%+P>HowcW]5ۭtyC^&KB'ZL;x#8%癪;8i$δ3 :ðu% g??¬Ύ>(RM# ogiA2t𙺵96筰Bzɋ6޾x{B)vkMu"dWSN(HŠhkxJ[4aG^ ~]-]'[6´sӘ+#0!;_XUš~ZY :6'gtG%̠ #a}wُܿXYш%rwLJ@: M">BB$JȊRB ][=0*\ 0gKxG>.O߅rgLۋdVM2̋,СB6Q9h;Ik3{j<#g^\sRQkGC5 'pi:gwx%/Lt,Ƴd@=[2 gM|T,ʈ`=_ű,Wۡ޼tga J?C]t;c{@πtB̠4=.ڧuPyyg3H2`g?Pɾ8kwD801+דC&Au̠b`^\w~uW x<_582+G,+ب7N: lBd(,2–~# v)fd[$~zu:`= S3æ,ԓ>&sDըvq{'I. ga;%Eecp䰊Աr* u :"~JM%Z (誴٪'̰Q_Q)oנ5H F4^xJzM/'u 84]h޶i`cql_k}IF!^F–}U{)?s`-6<D;|`MrzƲOEl>x6fL{U`5wluNwڇ;sº}3~y%cҜF 1--"[ ?ta=oi 69/~_+x ]acYXecwגl qG_`)ik,S,V0R܍g{On?'JbOKfI n콺>qh|vHq C_?y7FFr;Fo Vcaˊc9q˘m=D?-r.eߕh.dU}+gjDq]tC4^qGK>jy+TO6Yu1S.&DOA^j8_KU# UO XmO˾boqHͮUŽgjdP gGϞKʸ)r Dz%ܳęRqI <\2o NKULKյzpCzn^%5_I\8 zX6Fs{ ?Gqys*6 ?|sf q}i6η|.ɄkbOc<=ʧ zdy\GYf?n[|Ɩ >gU޸pR9NSr~.=J5ZoK 2 DHx3o_-~H=m >M#;6TH?`̭ؐ4W>!M $MY]< uH/DEaXS?nk|&r@ˎ>3n NȈHÕOu ;W<ѩ;3Z/IO\CL+t?N1:c=79lغCpd&{ԧ >c{bk0%˻H!XyĶӦ/aQ o⎅W-8jJ3 9p򽔒<.w6(]#1ܮCP1#kbue 1b4с 'ùT&R1VDU,=_T]O%w<~h`k2_Ӭ a,\_ph&! 1/{wX1_o_^0˜mw,!x7h|h/Io9佃6nw_-{X,Cu0bAiܪt,8J$,lGD=mSi9ҁCME~:(\ 5SZ%^7 %Lv}'rڳpa^lJ}J5'6u;'4*| ӫbqCq!\q⟤8C$MH>m) rXt},w(uCC_9N:-, zI?n˔7G`=h7t=u*oJH}kst/=_nne R4_> 9(5J%c F{n7cW}!{E:;4؋nr}M 9,P>Ƥ0["y"5$$}mvb B9*6ZlfҘ =kgT ;Qȫ6 9d1bɏan\۳+P)qKs|ΧKɼrh9j ?AG"TmV'>qLStd$(2KUm4V^W!鉩4c Z$ɬ/YeG_B# 0s!7С\ ObN uD":F ޾3m*$ee 0(F,:xPf}/y=iY.RWNI߰RpKKz^OL^* aQb5GnXJxm;~Yf~rzoR0;giNi37UסWdaR(gH W( bN^i>q0T rI`5$$=%.]KAQNo{euއf'jWbY/ ';_0*?XuXy a6mGXh\SlԠ9~Zﰨ)o|f:ozby?sr>;w/ Kzj6ǯek NJ2X>@7Ć[{upưK%З*AH06Ipj]glٰF@j6Y,$)lQad _3Ywd~tvS:n{Elv'bׯ1hYW elZy{_ uaCmRXv&!7+^{4)X0c+#v];/m4úcxR;;e񳡇آ~G GI( (5ͼPV2F}Usr:6vs̞۾hkug69cʁu,&$79Dd]J}-"Z5jpjiR lbi̼; ?gCgpY>~N{)y5P.Nd,҉qk,qܹ~gq'-8Hop?qgw( P̫bO̴8|qy=NB Uy"PZ>.~Jsa,r2;E{_RzS|8O])Utd_t8g'pߎyp:oT<D#m q!znF_ݡ>86`ov{;I\ v:#cf68aO}p" ǒ.nq^y㚁.w}EOm ;s,4r=-ds sHZrHgݲ|Hr"9{ܦybB^g9;+I =O2HM}]b4Hʑge#n78e?CsqfWqNN}HV\rTe˄[{_R9I"iMq~\so 'ķL]7e5/֓*ܱU3ЧB$Q}n+GTZpO>B&B"Gt>W5])ԒKDW/9}qۙ*/=! in)=Gq.-FP~PW'/&d9B!a"?w0D8M*t)Ԡ]dg)[cֱq0_^v/t q;Nء8_I8' فs>'p$X &#|: S?%u Kf/}d `g]d$ߧ_ AjrqjzهwAK5Pb1dԛK_n}3t I29@fEef__Q&#l5C~cmG?FN@qIYYNB$fyz\ kQ2赂Xtzu  gFu˔ h_; ˟EK+aS;xfArNž! JAM'C$9$%X\%ai*#cG;8斨!=L \ֺs"o|<;x6 Ta}WQf| Œ-٦l鱐XۖMe3yf2f`1 ɉxC(ǤDŽR&lٜ=`}7o%>oxVΘfJ߼`pd_ȣ<-SK!eE\oeۅ+W qiS\ ` ޝg"i&ّy\ۚ{wc!n\xn7.5[9|ev(Dpk"d&ng6#G2b1\mI|.}kDޑ8?×*pwŠqN7!\\o9Nn2s}b7T#+pAԜ:nGatDqߨQ*pkmϋ)[] pC"G.3_kc9]_Ln*܇z˕ުBqS\R{doF5qqO,W@'ܙ'`0Gv*{&? n(rz}LvD,F}ݽ>B;_p|Oo68*3uwj`: Q8F8ݯgek4ęAJTzLUG6 7}R?Yܢ0Fەmgt #t),`X7>t^ &2~RPLXxaWyB0:Q74LB!{Lϔ#t.߹aDVu_y~fokES/8$A|eE0[y~&`qګ0$0@3I:ҹNC0bSh\7 C![LwVdZ)`?Fiu`>MUBa " Uޱ: }G&34hȅ^0/˃8.J ]!-a/B#c .h|u[40o(T[ĥNJnB}Nem = r_@)p*ݼSkZVR/Fj:ѽ< կ9-@{@19 v=u+TcLC^}QS3>D?> {;NCrṻ=}V<*Ut[ ~!LPtڿp 8wԚ0ex}117%qXiqrHm"`Z:NtTN1 ެc1Rv$f^yww9("K~qbgD)|o]1L,Hsf>o:%ha 5k33}PE y'x#8~ e4_^Ʊ3eBk35W6`q0F; #ނs17ɔL ~o7K RmqM8nf&' UwIzIo[%I[ps;jV"jw?UTVtc '"/qsDbg_Q"=+kXn~D7W9q[WrAkqL~28DVDl$y؇{^:/%Vkz߾Lz?Es.j#r%$S79^Dž=jzffn[ JVIkӳԗmǣDֵ"SBmMD{nIXcfo:8RwM i!yHzݞJnh%E^SHNnz|., ץ:ZX:Jz/7$\Z$gv2]5?Z4$ I0L970Cֻ{nuE v7[cP ̬H?9b.eM5=}-e\DbA2i^r<`_ploR,mqs{G2^'Fcw/QA KXrd ۉhj頹,~NI2=ĜXe tFcj 0,ʱoP*1k 5}{}$;u(ɏ!G $ \f*Ol n'maX"xT 6n%e`ڲ#ſίF@Dwoh+2q)KYWC޵?PKvU}I=S ;&bp`wm/谨zrpamПe)G{cĉNf(2~ULhÈH ܸ%s*wFLwW6 H@{ᙒC1)@ŜSn=܃PmbӪ<#y/qmACtb qIR|"BZafqHbt́#砢9 ,_{Lq>2 iRϱQ V/R><`u/ Z5ҷu"+,,;K +A:,n$V0׾_ fzsKNUs^OjV`]mHJrCY{kayν̱ўE }a罾',>e7UaY?+0#js 6øX`BYaQT݌ h*ZM1TX^fΫ psWXJ$?L-q7*Gh";w_ŠX6;.5+ט忓}aY:3ք bq҂6~q<1_XӄtqO#lQUVSYl,_: ll~׸2/,Pq~̰NXRb9_x {ˌ>}a87Jj&glެ2]XG`?+#*TöS9eHLF b f;Ex'[$.`>cX&=k"\\H ֚rૺǚ"?Cr$ (!?)`߳oW9&+_qbGNrL vYCʫHGwڸQA+?|pvu{-jeL4Y>^[[_=!S~yMNCWʟqr"SDzj'{7 X/8\ΪH|Վ 8~%Iox}B!.-?~VC{/OOqy<:?\+٬{.f_ $%⌱ճp\k]ݬ m- oSb ׂ.OlM}-Xb:JqdO88| ݓpWL(Ne/-ጁlo2+'qڎŘm;l+P?=5׻6p.ҕᢍ՟K8|JT$0}&^/ΚゖANc=vC+Sϊ^ +3E"g9qFo\yvhr%ο8T'S %pAFyDjuf3 NU|V4\b:.U6{ ?.s8zI!1[>}-_qmT627e(pZ% ΝcfN#q\W߷qjB70 ɑ1|կGqۀWq|/1_R2'Ž {iq5̈́\Ҹ@VLf' iH,.ܨQ3wq>[1tF_jڿ>Oo߹wh 0W^dx$|N qNX::w>ʱ\Vw.h{'B L,<: 5gK/C麗4'PF4G|F0zIbO^O i:n̈́*#?C!1hcn jM+ך׋!1Kt0iba0u+%/J4NA)r!:N(=O3,5ͨԄ9(>hxfM# 2x*d*ܮvlA%2wlOUU?#k+(682KQx6H(G(ZQ+˫>s`g%S8%Lד4Yοc?aX1o! ޹ cW%OC*{_i"I;ǑfTafy<,\K7utK25>NTzԶ0}g1zVa4wS{0P9 8`Nz%FKLtVf1Cǘ`cyVdLՀa;0ۯ! a~8<&B[A˃\1 aϑ_#c=)w:Z?ǒ2+0+RU0X;7$áZ JdD(WgYEחӒ‰꥿KgI\z&M^C'7ǥ HeaG-p4{e&Df_̆Peq s{NA+8ԪgE V>sxOK$Ǔ5-$~#=wL_BYak!j0"P$Is e*ћ^zd M{ތ,OPg3_`cDm޷AaMmp:.u#`#邠 uSitWgtILUh. ŗc  ±VN!܎pZOG:6}<- N3q X7+`Y'_<lag,evy\dAnjG =mkmY9W$] .4`ŠSx"BVV R:m[ן%X xҔo{ Ibl쐘u;EXD#owz-?T`vDB0Fu_/%pwgC- Q4fOOöQlmw㴅߾Ń/tmCM|RIǢs_*Fk YKVZasLUo0zu4.AL+?$L}><҈?`/5fz1:ȎM!Gdh8"R{7̳2h1 /l?0Wzl`:Q99J \6ܜ>b]7X2t^&X{RdSbF7R/pT0c{Ue|Ĵ%IVt=JwS$K kr:Cf*6(|=CBuٸҐ8wI 6 : ;eX &.Cx lS@'Up lzG3zزrىCP\ip+ԕ*G;B=*hֺA"LЏߟ=> 3V`ŰAo@UI Ӓ9( 7otZb}byng趃Ue.C:G+#,mZzwbVO?z'9!%y?UW5W K}91CŎ٫_P9a4?iDZLar\Jg_|..tx3~y}T=k`P.IQVE_j4*Eqf#N؃:3H:kTz /ic i e Hoo:*֖-aРVCi<Q˥#8uk Xd`h{ֹC١7٫pqL-=DPHke$9gl`H9 3)qcZPa1ES= 5vla+:wNY ~݅r9_c-ȉZHz]D bu|%</`sGn]s-D爵Y۹xB˪,;5yT34Q(xun`ZJ.nZ z'8LmR\/_lv@~E&\hW^ϒc5ha2 -z)$/CY^aаông³DZڮHV?8_Y GȈX1!Kv<Ƶ RmfؾB= Gk ;L{$^E0p`7"Pk20x?b7H m@jS.5H:Aʦw+!uE{ `ts6dԖxfߘ kC-[N,)Iv,+b8)]"v 7[*> `7y[QNW`+_/R?y'YXL`ǥri'U4xd}ţ };z~ܴրzғG5Y{~6EouO uTtשHC͢xKP/= ] +}jz^{1mOͦjP>'bZ'N~+H@GL|7K敄ϯ 4%=\O!6;ZD7_ЦcĖ 2<쥪TQl$v[/ 0V/<ElU[W;WM}PC~t5MqXQ7Cױ5{2=/ˊ=>}7`oy~Fe6,2z_P{,PS)4#\x'0P(0M58W#Ds0r߰9\4!*^85r1=#-<=[)R[#^]Opy $bg2OOFCfӕ~*~mҋ^ ,2(\.GfR=8Â3R-|z_ҟzEw(iMݾ/髏]S 4B/+`'.ǻcS84d.iP\OaˮFSRw)uЙ=n rx ⦝% .^ ŋZ]_Ҏ.|G(&( r~h٨&}+M 6zʔv8T\.c@|8GzhV\lC 8R6seR-o\ 1uùwkƍXn\PZz"칮ZlF> s9."T 2ӈϸ~Us,@ -mGM8i ٻ_\V|tian^V BâK" 79S .Ks߹dlrdd }hpJէs7'd.ܶEа6npŹ~3wp]x΋#|$Aa>/L?vZ~mAՁosTomORf<v;%sG6@FbXLFJEII eKal߷p  '9TCAzY =yvS : هc(l_ԝПj zڽ.ԅ[ e0g5&̾уV.uv_/"b/TH$|;I;^TAeGnx gD4l@VQǨ!lێ܁l*> mb}:tqR+bFkt_@[hPy>|~S#mbӱ~,Mq K]0vl݆7Zd X ;oG%<E&sHڹ{c+0tSr7S>8٢-k"rNjTBqdV-7V˙*dF% 0Ә6zhYaND#sLZ{`.LZԞ!}0zKF T_:G !9;J i}L|OFQnٻ=%̗ d)M_ $5N%|4E {RuT݌_6Q@}̈́@)45I;$v3<~g?SEF:T-}@~t~ U>t@b؍@Y{6X^sm>#=bG y5Ҳ(Jd $or٢ag|HGV@J7T(b*h@IZďsM@V7 iO g9N$ H;Ӥm l]we0lr%WLdIig :tM$6s۶KͩF@ svޑޝƪ4ȵ=r]ҁ3dԲz;k3/K˱OGg8Λ8S^O9ZudGF^a;5ssOgǒ[=5s'p\o$X.o;lU_}6>"]iƚ1ƻ38@Q& ྊM5dc˥K+q}rӇQo9{3TBMP㌖w$ tEgv/_Y f.C Qg|Xϑ~\n_Łx9}q1=9u8e>5!a5is=vznQR|_.J859l.ey6|N 'dnՌ%l'2?ES4ꌤ/ i1E$ I;X!ik >3'}Hqyyom>qRo")5\~4$ۛ Ib83F{I$44}/Jga "3)ZWj{xpptĂs[n)F;gt o|7 r^۱[ h4^e wEܠן9@O$er9&H"'/+^aTZ ʇ #E%DK&pG\OWTuO?Yfr<lZqcx(qI)" r!:QH%. ůbJN+V7>M<^AR+`xj8rƱ2 *KVQ}RaOC|@'&L!h%*Wu~^Bb5t6ӌ6=:%}邙8TP4¡w> tؐY p|{2 9<˕~^e~beNavwi /2Le5? utz_aiہ!cD+- IGGIȫ?2y7V5_={ZM~xpFS\0 Z<;kF/jW"*rǁ"^xs:qËc0=% |5sXiw >ˆyNY߷klV-879Xlɏj؟iiy/+Suc4/;NJ 5׏Aɛ"%q/7  )] I$4Ȑ1H*$2d& %It3̳}2p^\C~g>}γ~gLn^=/}32PNVG0";cp7 ZWCYmgK7b%$;=6 ._ :uhXW{:@V=ϑ\E~kͰ?/P/q{ 2kynK0h$S+j{UAjgV *_Ie2j~ ظ)tEd(}kԝ'?ցyah%znQw􈨷G1j@:S2 \zn_XWpWLwpW r tеZXf40.! Z.}Ec+tШ©vGū0^#)( f{WPN*ON(,~5-*\|q^ ԑ+sXX+)K.4ǫB}j މApX\۾=i+Fmzb j@&5VKF]Z٘ ~X\ guQ0y Or#L*j} +:lv.J!?ICcY"^u\ByQC.-YP^ HcU'^n;OPj? v2>G|Iz~% FLV@BM)u9vڢ1ZELC%Pܺ!ь2sZK0_q讖?ԢvѨv2k՗ι䆔oV1 >יF2y(yhnFue{Pl1oN?e}uہʵ$ٳo`F8"ܻ6)0MCSؼQqaIʼC? 촟XΡr#:¥ uT`@;#l_n?18G '(enoU{ U o3@S'2x*\NFR%:CbLN=}'%sqꢋ&M|^4{U^e4Ifnf mH}sr'7@Aqk1T}xT@e)_8Fk(i{"ܸݗиcΩc6(oLl޵aJkBm #' eDP߆c)qJ)XBٕ$#a|\Vx& zBjV=;ac7rG!S_*N,رòtA"?/_rWr"K#ih~|L\_ hܭ&E5#Wwk\FK> dè}{ZX`0z+~m2.WA=ʾeWîCLLp=s5~x<Sy00$zm;#b>؎/A9v &}&~ r-ϣZUh@KT74DOn~גQK!/!UāA[S lgOGo2..9N?}XS ;t2aJNTVsbL(:~>zǞNfvGCӅz}+e<%in#GץxEzLcV!;2.U[S9yRuu;Qf+RfhME;FUfF 87{,T &rb>娶;X'-p1i;|?}ǭhe JHѹ7U7me)]ҹ K6`R6^!;s6dpGp56r]m3eOnpB\.fTbW})},;Z4Xl B876c>Oȫ(]z&4t9Qv.z5Y͝j'iJE#gf/lPs |MOńް#'t` m,_{hㆈ.]P`ġ[N"ܑrE =ͳD^'"bMb4jHEɿw{?{a+FS_JAkcg~LE3 7fQQ}vLb5^V5y#҃۟\tѸy}!SlMqeVh^ORr_/ EVlZwL9,^u>)$i~^ ܔᔛOY[9H]R҃ >h}s#Qmy RњC;>^PU[ɈCbʁT{`{wʠ.u<-̅c-aYVo>y?w;Dm. ;$!/X?_2d=q/~1`{8mJkrM ƙN#Fo -Ajb+'O$a,9$7? 6햞9x"62Xc$#+Cϥ(&.UvYWk,fS_wڡ&˜bmVwA;bdۈ|< ,\ϐo> K,"|[^X*6RF,D(_}0a,ЖbZuRl6] [jܐO,^6Y!sBm~&Rȟ$bkY,/`ipx6+]Kj>&O^σ%mgvٜTRnihˠk9;~G[o=ʢeNF]c gHZZ\td/ (MQ^0HץSNj&0Igx0u5(?CXӖZ8BqLcK=s{{ }'ĕs`#h Ȃ~*0.~Ի|\o_nfxt$¨_^QVLq-FBt*&k95\eY ,jMÄ`(p\Bptadc<_q7|ڛ 8xU # l!7I-U8* An90~rO,l R}V,ؗ0~NH>_:p,\A+'';ҵ3hIX?hU6/^c02GsGp|}].Dzuf)&s~i d*| YJsͣwK[j]}ZYCAdOÈ?@HnA}8=tykvTš䓭6 &y<+KBOa#G<]~547º/X> {,OX~/ P '\'>=:Hfg`QP'HfՊ>Ϯ^uH{?=(~W"J͎Ia`O[a.S\*ޔoÆpSd!gXtV`)-uutatQ>X;#R_x $gOK9 HeRbԺ̢_!-uw \zy!b]"H5 >: X(ݗ;jUmhas|v}z(`Ґm> 8N:qhRSV寥C@)zI5aarx| sRR/b䨵qw=s-i@^%6QAjP04JIMVbFL:& `3]XTO -嫅Q0[OH_{'L|O.qUsyoZsWa2yLJ4q Lb\#at&CE.<51MM]vd5pv-0ӥauvDzBK$ua Wvf и3GI:%Qx9=0G[p>/Ԩ"fX =R2?0$.pW8FVnC4i].ζa'ĩ# 3a2Dܐif?yp,5M@@$9k9s[֊{ 'T٫c c,udJ_Rѩ L }0'ť+\;xsH* ƨs<&^f+k"`4o7WNdU0>&5Bd5(_L)E5Om_]y0VQ[sA\uYH.VU~he8PA&W"`5E6' €yt9%qԕ޷ɟ/H a>pjjB^6o~B)HNz~Wc{{)xuړ=/g xcUcZx)cx$;Lx ml237~R$s> ^3/o8 yOtK Y'@[)YAY=5vu>']s{xX8.52eI([}p`Bt¿ևC=o|8a[=;.;]`v4%B 0i ӿuw[{-xsVne zY lhֻfpUUOb"|9CojcfmA' SX \{jqƕqÒU? r7I$Oi v9ޅa3L ]6Y+"c<ՙ8 PZP jCх|4aZU‡̖VeN >QS1@[xi 4^°xnJmN |YU9( Y,U).QW?<B?\~N  lšv;h/v9/̐%atϤ֑y7)<;' mn\ď\TLAZJ\&4o\ eMsq8C5c({U! ^$Pr,k۳}p5o|Z4Oń pL$?Ri [F(s>˱R!|)8/r?SZ Г)I$کPpW t-R•sy'Sj\Ag&SԹy?~μ`~ST9_\?RQSܔvm-(33{5ӿQ?q[+;s+Y9;l;!V5ww;<ecodist/data/iris.vf.rda0000644000176200001440000000042614452055674014703 0ustar liggesusers r0b```b`f@& `d`aEzei |@d=.~اx:Uel?"+S-ՠ*\nI|O7 Y}޳}mUᅤݿं;k|/}\<\ PQp%Pu`uyԂ=Լ 7D,<3.Z "Qj*!acA,e9hdMI,.d;?Rϴgecodist/data/iris.fit.rda0000644000176200001440000000535414452055674015057 0ustar liggesusersWi8[ܕn2]E+zשh2"T( Mdj-L*?MSrxppn~CyZk?~kۘ:;A%htIL:U(a}w_T/ M; %D~J)$iF5r|IRW^NҥfJ̘ Uʛ򃑿WEűV׫I"qS~'oi/5Pt' nDk֋EOPi3MDJIJy>;=n&'NoĴx1C?Iu_9\*让4EęA(tJDRw9<}5bճI xeZK!)m!- (DC#+eIWm/HO/Aq~BX5욽InS6p?uxe!$J0kDž޳# q9W.kx}#^~􏆕@'llnPY)8gIbC>/{ƽWW tQDkJg@zT,2w5mĂh셜j0۠[#櫪Ώ@/hO76UL:o jy+a㨴34AOW(]7Y;ߧ-xG4y})Z =s+Ns]攌T͟kŁ=cwBWkƹ1B)|M=?k~d9C&x$/f:ߊ!s0!nw{mQ60Z$3ce{/0&Npd(dЩsf]9Nq JjJ%h˔Ő?qQjU?r!пA_RAoy:s\DJn ^ :CU\R8--* r| DYOXI |u2t;lk PQAў&Ǽ԰oXΠZ鹳5{Ɵ\)YПҺ C XܨIa@׉]kH:8Z$Ũdzq6껜$a究Pi{tV:58%'j0h5;' ڴ/UGad:>T=jY1mqr. @K-~u |knu r7LT|r%wL` ܡQj%;B+e_g<2qD!'F5Ͱ,¸k EdC|(A A'v_rnK{F|ˋE3BRrv< 8s4V|փ&g4:k˜{v,lK@n<1kծWǮ^ḼbcVVÜ5xZ>=Ǥ~/)ߎs$6vobjAn^}nR6> SZ~ȩ(h^%u,RtlJ6V[XM ]¦GEv&g8Bfi~!doRydB\>UjWtZ1a{T { WUc2d'9̯"?P̙^1 Q :/1 G`,),~4; ?Ncql損?#3 /6&*nUkq((fJ6/]YXO8p -[aG4inb`c￶>_#C>PP8޽ 07vѾ),ql}Kլjehqy-˛We$~U[]}1hm2\ȵ-yYzzaeiof2#/U~$WPFi<씮Z\q 6ę m _rz% Z-ʑg(^ S?h6hN[!G'tA2q,de{?, 5Oc`!2vYQGhf}`˭ 0BN6myQ*Wki&6Xq&_߶}Vtk* M)D⽑IS1'Jyz>,1nR~e9oI?} 9%Qv7wH%{3I4!s/~z'cf f$Ƥ93S.0#l әUZ_?\[yؗO|Cb}miߘ͖>[_=v>^W5`̍ecodist/man/0000755000176200001440000000000014517736751012477 5ustar liggesusersecodist/man/pmgram.Rd0000644000176200001440000001306214474123366014245 0ustar liggesusers\name{pmgram} \alias{pmgram} \title{ Piecewise multivariate correlogram } \description{ This function calculates simple and partial piecewise multivariate correlograms. } \usage{ pmgram(data, space, partial, breaks, nclass, stepsize, equiprobable = FALSE, resids = FALSE, nperm = 1000) } \arguments{ \item{data}{ lower-triangular dissimilarity matrix. This can be either an object of class dist (treated as one column) or a matrix or data frame with one or two columns, each of which is an independent lower-triangular dissimilarity in vector form. } \item{space}{ lower-triangular matrix of geographic distances. } \item{partial}{ optional, lower-triangular dissimilarity matrix of ancillary data. } \item{breaks}{ locations of class breaks. If specified, overrides nclass and stepsize. } \item{nclass}{ number of distance classes. If not specified, Sturge's rule will be used to determine an appropriate number of classes. } \item{stepsize}{ width of each distance class. If not specified, nclass and the range of space.d will be used to calculate an appropriate default. } \item{equiprobable}{ if TRUE, create nclass classes of equal number of distances; if FALSE, create nclass classes of equal width } \item{resids}{ if resids=TRUE, will return the residuals for each distance class. Otherwise returns 0. } \item{nperm}{ number of permutations to use. If set to 0, the permutation test will be omitted. } } \details{ The standard Mantel correlogram calculated by \code{\link{mgram}} tests the hypothesis that the mean compositional dissimilarity within a distance class differs from the mean of all the other distance classes combined. This function instead produces a piecewise correlogram by testing the relationship between dissimilarities within each distance class on its own, without reference to relationships across other distance classes. This function does four different analyses: If data has 1 column and partial is missing, calculates a multivariate correlogram for data. If data has 2 columns and partial is missing, calculates a piecewise Mantel cross-correlogram, calculating the Mantel r between the two columns for each distance class separately. If data has 1 column and partial exists, calculates a partial multivariate correlogram based on residuals of data ~ partial. If data has 2 columns and partial exists, does a partial Mantel cross-correlogram, calculating partial Mantel r for each distance class separately. The Iwt statistic used for the multivariate correlograms is not the standard Mantel r. For one variable, using Euclidean distance, this metric converges on the familiar Moran autocorrelation. Like the Moran autocorrelation function, this statistic usually falls between -1 and 1, but is not bounded by those limits. Unlike the Moran function, this correlogram can be used for multivariate data, and can be extended to partial tests. The Mantel r is used for piecewise cross-correlograms. The comparisons in \code{vignette("dissimilarity", package="ecodist")} may help. } \value{ Returns a object of class mgram, which is a list containing two objects: mgram is a matrix with one row for each distance class and 4 columns: \item{lag }{midpoint of the distance class.} \item{ngroup }{number of distances in that class.} \item{piecer or Iwt }{Mantel r value or appropriate statistic (see Details).} \item{pval }{two-sided p-value.} resids is a vector of the residuals (if calculated) and can be accessed with the \code{residuals()} method. } \author{ Sarah Goslee } \seealso{ \code{\link{mgram}}, \code{\link{mantel}}, \code{\link{residuals.mgram}}, \code{\link{plot.mgram}} } \examples{ data(bump) par(mfrow=c(1, 2)) image(bump, col=gray(seq(0, 1, length=5))) z <- as.vector(bump) x <- rep(1:25, times=25) y <- rep(1:25, each=25) X <- col(bump) Y <- row(bump) # calculate dissimilarities for data and space geo.dist <- dist(cbind(as.vector(X), as.vector(Y))) value.dist <- dist(as.vector(bump)) ### pmgram() is time-consuming, so this was generated ### in advance and saved. ### set.seed(1234) ### bump.pmgram <- pmgram(value.dist, geo.dist, nperm=10000) data(bump.pmgram) plot(bump.pmgram) #### Partial pmgram example # generate a simple surface # with complex nonlinear spatial pattern x <- matrix(1:25, nrow=25, ncol=25, byrow=FALSE) y <- matrix(1:25, nrow=25, ncol=25, byrow=TRUE) # create z1 and z2 as functions of x, y # and scale them to [0, 1] z1 <- x + 3*y z2 <- y - cos(x) z1 <- (z1 - min(z1)) / (max(z1) - min(z1)) z2 <- (z2 - min(z2)) / (max(z2) - min(z2)) z12 <- (z1 + z2*2)/3 # look at patterns layout(matrix(c( 1, 1, 2, 2, 1, 1, 2, 2, 3, 3, 4, 4, 3, 3, 5, 5), nrow=4, byrow=TRUE)) image(z1, col=gray(seq(0, 1, length=20)), zlim=c(0,1)) image(z2, col=gray(seq(0, 1, length=20)), zlim=c(0,1)) image(z12, col=gray(seq(0, 1, length=20)), zlim=c(0,1)) # analyze the pattern of z across space z1 <- as.vector(z1) z2 <- as.vector(z2) z12 <- as.vector(z12) z1.d <- dist(z1) z2.d <- dist(z2) z12.d <- dist(z12) space <- cbind(as.vector(x), as.vector(y)) space.d <- dist(space) # take partial correlogram without effects of z1 ### pmgram() is time-consuming, so this was generated ### in advance and saved. ### set.seed(1234) ### z.no <- pmgram(z12.d, space.d, nperm=1000, resids=FALSE) ### save(z.no, file="ecodist/data/z.no.rda") data(z.no) plot(z.no) # take partial correlogram of z12 given z1 ### pmgram() is time-consuming, so this was generated ### in advance and saved. ### set.seed(1234) ### z.z1 <- pmgram(z12.d, space.d, z2.d, nperm=1000, resids=FALSE) ### save(z.z1, file="ecodist/data/z.z1.rda") data(z.z1) plot(z.z1) } \keyword{ multivariate } ecodist/man/xmantel.Rd0000644000176200001440000000671014452055674014436 0ustar liggesusers\name{xmantel} \alias{xmantel} \title{ Cross-Mantel test } \description{ Simple and partial cross-Mantel tests, with options for ranked data and permutation tests. } \usage{ xmantel(formula = formula(data), data, dims = NA, nperm = 1000, mrank = FALSE) } \arguments{ \item{formula}{ formula describing the test to be conducted. For this test, y ~ x will perform a simple Mantel test, while y ~ x + z1 + z2 + z3 will do a partial Mantel test of the relationship between x and y given z1, z2, z3. All variables should be either non-symmetric square cross-dissimilary matrices of class xdist, or vector forms thereof. } \item{data}{ an optional dataframe containing the variables in the model as columns of dissimilarities. By default the variables are taken from the current environment. } \item{dims}{ if the dissimilarity matrices are not square, the dimensions must be provided as \code{c(nrow, ncol)}} \item{nperm}{ number of permutations to use. If set to 0, the permutation test will be omitted. } \item{mrank}{ if this is set to FALSE (the default option), Pearson correlations will be used. If set to TRUE, the Spearman correlation (correlation ranked distances) will be used. } } \details{ If only one independent variable is given, the simple Mantel r (r12) is calculated. If more than one independent variable is given, the partial Mantel r (ryx|x1 ...) is calculated by permuting one of the original dissimilarity matrices. Note that the cross-dissimilarity functions are for research purposes, and are not well-tested. } \value{ \item{mantelr }{Mantel coefficient.} \item{pval1 }{one-tailed p-value (null hypothesis: r <= 0).} \item{pval2 }{one-tailed p-value (null hypothesis: r >= 0).} \item{pval3 }{two-tailed p-value (null hypothesis: r = 0).} } \author{ Sarah Goslee } \seealso{ \code{\link{xdistance}}, \code{\link{xmgram}} } \examples{ data(graze) ### EXAMPLE 1: Square matrices # take two subsets of sites with different dominant grass abundances # use cut-offs that produce equal numbers of sites dom1 <- subset(graze, POPR > 50 & DAGL < 20) # 8 sites dom2 <- subset(graze, POPR < 50 & DAGL > 20) # 8 sites # first two columns are site info dom.xd <- xdistance(dom1[, -c(1,2)], dom2[, -c(1,2)], "bray") # environmental and spatial distances; preserve rownames forest.xd <- xdistance(dom1[, "forestpct", drop=FALSE], dom2[, "forestpct", drop=FALSE]) sitelocation.xd <- xdistance(dom1[, "sitelocation", drop=FALSE], dom2[, "sitelocation", drop=FALSE]) # permutes rows and columns of full nonsymmetric matrix xmantel(dom.xd ~ forest.xd) xmantel(dom.xd ~ forest.xd + sitelocation.xd) plot(xmgram(dom.xd, sitelocation.xd)) ### EXAMPLE 2: Non-square matrices # take two subsets of sites with different dominant grass abundances # this produces a non-square matrix dom1 <- subset(graze, POPR > 45 & DAGL < 20) # 13 sites dom2 <- subset(graze, POPR < 45 & DAGL > 20) # 8 sites # first two columns are site info dom.xd <- xdistance(dom1[, -c(1,2)], dom2[, -c(1,2)], "bray") # environmental and spatial distances; preserve rownames forest.xd <- xdistance(dom1[, "forestpct", drop=FALSE], dom2[, "forestpct", drop=FALSE]) sitelocation.xd <- xdistance(dom1[, "sitelocation", drop=FALSE], dom2[, "sitelocation", drop=FALSE]) # permutes rows and columns of full nonsymmetric matrix xmantel(dom.xd ~ forest.xd, dims=c(13, 8)) xmantel(dom.xd ~ forest.xd + sitelocation.xd, dims=c(13, 8)) plot(xmgram(dom.xd, sitelocation.xd)) } \keyword{ multivariate } ecodist/man/nmds.Rd0000644000176200001440000001160314517736706013730 0ustar liggesusers\name{nmds} \alias{nmds} \title{ Non-metric multidimensional scaling } \description{ Non-metric multidimensional scaling. } \usage{ nmds(dmat, mindim = 1, maxdim = 2, nits = 10, iconf, epsilon = 1e-12, maxit = 500, trace = FALSE) } \arguments{ \item{dmat}{ lower-triangular dissimilarity matrix. } \item{mindim}{ optional, minimum number of dimensions to use. } \item{maxdim}{ optional, maximum number of dimensions to use. } \item{nits}{ optional, number of separate ordinations to use. } \item{iconf}{ optional, initial configuration. If not specified, then a random configuration is used. } \item{epsilon}{ optional, acceptable difference in stress. } \item{maxit}{ optional, maximum number of iterations. } \item{trace}{ if TRUE, will write progress indicator to the screen. } } \details{ The goal of NMDS is to find a configuration in a given number of dimensions which preserves rank-order dissimilarities as closely as possible. The number of dimensions must be specified in advance. Because NMDS is prone to finding local minima, several random starts must be used. Stress is used as the measure of goodness of fit. A lower stress indicates a better match between dissimilarity and ordination. As of ecodist 1.9, the stress calculation used is the same as in \code{MASS:isoMDS}. In previous versions it was monotonically related, so the same configurations were produced, but the absolute value was different. } \value{ \item{conf }{list of configurations, each in the same units as the original dissimilarities.} \item{stress }{list of final stress values.} \item{r2 }{total variance explained by each configuration.} The first results are for the lowest number of dimensions (total number is (mindim - maxdim + 1) * nits). } \references{ Kruskal, J.B. 1964. Multidimensional scaling by optimizing goodness of fit to a nonmetric hypothesis. Psychometrika 29:1-27. Minchin, P.R. 1987. An evaluation of the relative robustness of techniques for ecological ordination. Vegetatio 96:89-108. } \author{ Sarah Goslee } \seealso{ \code{\link{plot.nmds}}, \code{\link{min.nmds}}, \code{\link{vf}}, \code{\link{addord}} } \examples{ data(iris) iris.d <- dist(iris[,1:4]) ### nmds() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.nmds <- nmds(iris.d, nits=20, mindim=1, maxdim=4) ### save(iris.nmds, file="ecodist/data/iris.nmds.rda") data(iris.nmds) # examine fit by number of dimensions plot(iris.nmds) # choose the best two-dimensional solution to work with iris.nmin <- min(iris.nmds, dims=2) # rotate the configuration to maximize variance iris.rot <- princomp(iris.nmin)$scores # rotation preserves distance apart in ordination space cor(dist(iris.nmin), dist(iris.rot)) # fit the data to the ordination as vectors ### vf() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.vf <- vf(iris.nmin, iris[,1:4], nperm=1000) ### save(iris.vf, file="ecodist/data/iris.vf.rda") data(iris.vf) # repeat for the rotated ordination ### vf() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.vfrot <- vf(iris.rot, iris[,1:4], nperm=1000) ### save(iris.vfrot, file="ecodist/data/iris.vfrot.rda") data(iris.vfrot) par(mfrow=c(1,2)) plot(iris.nmin, col=as.numeric(iris$Species), pch=as.numeric(iris$Species), main="NMDS") plot(iris.vf) plot(iris.rot, col=as.numeric(iris$Species), pch=as.numeric(iris$Species), main="Rotated NMDS") plot(iris.vfrot) # generate new data points to add to the ordination # this might be new samples, or a second dataset iris.new <- structure(list(Sepal.Length = c(4.6, 4.9, 5.4, 5.2, 6, 6.5, 6, 6.8, 7.3), Sepal.Width = c(3.2, 3.5, 3.6, 2.3, 2.8, 3, 2.7, 3.1, 3.2), Petal.Length = c(1.2, 1.5, 1.5, 3.5, 4.1, 4.2, 4.8, 5, 5.7), Petal.Width = c(0.26, 0.26, 0.26, 1.2, 1.3, 1.4, 1.8, 2, 2), Species = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), .Label = c("setosa", "versicolor", "virginica"), class = "factor")), .Names = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width", "Species"), class = "data.frame", row.names = c(NA, -9L)) # provide a dist object containing original and new data # provide a logical vector indicating which samples were used to # construct the original configuration iris.full <- rbind(iris, iris.new) all.d <- dist(iris.full[,1:4]) is.orig <- c(rep(TRUE, nrow(iris)), rep(FALSE, nrow(iris.new))) ### addord() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.fit <- addord(iris.nmin, iris.full[,1:4], all.d, is.orig, maxit=100) ### save(iris.fit, file="ecodist/data/iris.fit.rda") data(iris.fit) plot(iris.fit$conf, col=iris.full$Species, pch=c(18, 4)[is.orig + 1], xlab="NMDS 1", ylab="NMDS 2") title("Demo: adding points to an ordination") legend("bottomleft", c("Training set", "Added point"), pch=c(4, 18)) legend("topright", levels(iris$Species), fill=1:3) } \keyword{ multivariate } ecodist/man/z.no.Rd0000644000176200001440000000355114452055674013652 0ustar liggesusers\name{z.no} \alias{z.no} \docType{data} \title{Example for pmgram} \description{ An object of class mgram for use in the example for \code{\link{pmgram}}. Many of the functions in \code{ecodist} take a long time to run, so prepared examples have been included. } \usage{data(z.no)} \format{ See \code{\link{pmgram}} for current format specification. } \author{ Sarah Goslee } \seealso{ \code{\link{pmgram}}, \code{\link{z.z1}}, } \examples{ #### Partial pmgram example # generate a simple surface # with complex nonlinear spatial pattern x <- matrix(1:25, nrow=25, ncol=25, byrow=FALSE) y <- matrix(1:25, nrow=25, ncol=25, byrow=TRUE) # create z1 and z2 as functions of x, y # and scale them to [0, 1] z1 <- x + 3*y z2 <- y - cos(x) z1 <- (z1 - min(z1)) / (max(z1) - min(z1)) z2 <- (z2 - min(z2)) / (max(z2) - min(z2)) z12 <- (z1 + z2*2)/3 # look at patterns layout(matrix(c( 1, 1, 2, 2, 1, 1, 2, 2, 3, 3, 4, 4, 3, 3, 5, 5), nrow=4, byrow=TRUE)) image(z1, col=gray(seq(0, 1, length=20)), zlim=c(0,1)) image(z2, col=gray(seq(0, 1, length=20)), zlim=c(0,1)) image(z12, col=gray(seq(0, 1, length=20)), zlim=c(0,1)) # analyze the pattern of z across space z1 <- as.vector(z1) z2 <- as.vector(z2) z12 <- as.vector(z12) z1.d <- dist(z1) z2.d <- dist(z2) z12.d <- dist(z12) space <- cbind(as.vector(x), as.vector(y)) space.d <- dist(space) # take partial correlogram without effects of z1 ### pgram() is time-consuming, so this was generated ### in advance and saved. ### set.seed(1234) ### z.no <- pmgram(z12.d, space.d, nperm=1000, resids=FALSE) ### save(z.no, file="ecodist/data/z.no.rda") plot(z.no) # take partial correlogram of z12 given z1 ### pgram() is time-consuming, so this was generated ### in advance and saved. ### set.seed(1234) ### z.z1 <- pmgram(z12.d, space.d, z2.d, nperm=1000, resids=FALSE) ### save(z.z1, file="ecodist/data/z.z1.rda") plot(z.z1) } \keyword{datasets} ecodist/man/mantel.Rd0000644000176200001440000001056114452055674014245 0ustar liggesusers\name{mantel} \alias{mantel} \title{ Mantel test } \description{ Simple and partial Mantel tests, with options for ranked data, permutation tests, and bootstrapped confidence limits. } \usage{ mantel(formula = formula(data), data, nperm = 1000, mrank = FALSE, nboot = 500, pboot = 0.9, cboot = 0.95) } \arguments{ \item{formula}{ formula describing the test to be conducted. For this test, y ~ x will perform a simple Mantel test, while y ~ x + z1 + z2 + z3 will do a partial Mantel test of the relationship between x and y given z1, z2, z3. All variables can be either a distance matrix of class dist or vectors of dissimilarities. } \item{data}{ an optional dataframe containing the variables in the model as columns of dissimilarities. By default the variables are taken from the current environment. } \item{nperm}{ number of permutations to use. If set to 0, the permutation test will be omitted. } \item{mrank}{ if this is set to FALSE (the default option), Pearson correlations will be used. If set to TRUE, the Spearman correlation (correlation ranked distances) will be used. } \item{nboot}{ number of iterations to use for the bootstrapped confidence limits. If set to 0, the bootstrapping will be omitted. } \item{pboot}{ the level at which to resample the data for the bootstrapping procedure. } \item{cboot}{ the level of the confidence limits to estimate. } } \details{ If only one independent variable is given, the simple Mantel r (r12) is calculated. If more than one independent variable is given, the partial Mantel r (ryx|x1 ...) is calculated by permuting one of the original dissimilarity matrices. The bootstrapping is actually resampling without replacement, because duplication of samples is not useful in a dissimilarity context (the dissimilarity of a sample with itself is zero). Resampling within dissimilarity values is inappropriate, just as for permutation. } \value{ \item{mantelr }{Mantel coefficient.} \item{pval1 }{one-tailed p-value (null hypothesis: r <= 0).} \item{pval2 }{one-tailed p-value (null hypothesis: r >= 0).} \item{pval3 }{two-tailed p-value (null hypothesis: r = 0).} \item{llim }{lower confidence limit.} \item{ulim }{upper confidence limit.} } \references{ Mantel, N. 1967. The detection of disease clustering and a generalized regression approach. Cancer Research 27:209-220. Smouse, P.E., J.C. Long and R.R. Sokal. 1986. Multiple regression and correlation extensions of the Mantel test of matrix correspondence. Systematic Zoology 35:62 7-632. Goslee, S.C. and Urban, D.L. 2007. The ecodist package for dissimilarity-based analysis of ecological data. Journal of Statistical Software 22(7):1-19. Goslee, S.C. 2010. Correlation analysis of dissimilarity matrices. Plant Ecology 206(2):279-286. } \author{ Sarah Goslee } \seealso{ \code{\link{mgram}}, \code{\link{mgroup}} } \examples{ data(graze) grasses <- graze[, colnames(graze) \%in\% c("DAGL", "LOAR10", "LOPE", "POPR")] legumes <- graze[, colnames(graze) \%in\% c("LOCO6", "TRPR2", "TRRE3")] grasses.bc <- bcdist(grasses) legumes.bc <- bcdist(legumes) space.d <- dist(graze$sitelocation) forest.d <- dist(graze$forestpct) # Mantel test: is the difference in forest cover between sites # related to the difference in grass composition between sites? mantel(grasses.bc ~ forest.d) # Mantel test: is the geographic distance between sites # related to the difference in grass composition between sites? mantel(grasses.bc ~ space.d) # Partial Mantel test: is the difference in forest cover between sites # related to the difference in grass composition once the # linear effects of geographic distance are removed? mantel(grasses.bc ~ forest.d + space.d) # Mantel test: is the difference in forest cover between sites # related to the difference in legume composition between sites? mantel(legumes.bc ~ forest.d) # Mantel test: is the geographic distance between sites # related to the difference in legume composition between sites? mantel(legumes.bc ~ space.d) # Partial Mantel test: is the difference in forest cover between sites # related to the difference in legume composition once the # linear effects of geographic distance are removed? mantel(legumes.bc ~ forest.d + space.d) # Is there nonlinear pattern in the relationship with geographic distance? par(mfrow=c(2, 1)) plot(mgram(grasses.bc, space.d, nclass=8)) plot(mgram(legumes.bc, space.d, nclass=8)) } \keyword{ multivariate } ecodist/man/z.z1.Rd0000644000176200001440000000355114452055674013570 0ustar liggesusers\name{z.z1} \alias{z.z1} \docType{data} \title{Example for pmgram} \description{ An object of class mgram for use in the example for \code{\link{pmgram}}. Many of the functions in \code{ecodist} take a long time to run, so prepared examples have been included. } \usage{data(z.z1)} \format{ See \code{\link{pmgram}} for current format specification. } \author{ Sarah Goslee } \seealso{ \code{\link{pmgram}}, \code{\link{z.no}}, } \examples{ #### Partial pmgram example # generate a simple surface # with complex nonlinear spatial pattern x <- matrix(1:25, nrow=25, ncol=25, byrow=FALSE) y <- matrix(1:25, nrow=25, ncol=25, byrow=TRUE) # create z1 and z2 as functions of x, y # and scale them to [0, 1] z1 <- x + 3*y z2 <- y - cos(x) z1 <- (z1 - min(z1)) / (max(z1) - min(z1)) z2 <- (z2 - min(z2)) / (max(z2) - min(z2)) z12 <- (z1 + z2*2)/3 # look at patterns layout(matrix(c( 1, 1, 2, 2, 1, 1, 2, 2, 3, 3, 4, 4, 3, 3, 5, 5), nrow=4, byrow=TRUE)) image(z1, col=gray(seq(0, 1, length=20)), zlim=c(0,1)) image(z2, col=gray(seq(0, 1, length=20)), zlim=c(0,1)) image(z12, col=gray(seq(0, 1, length=20)), zlim=c(0,1)) # analyze the pattern of z across space z1 <- as.vector(z1) z2 <- as.vector(z2) z12 <- as.vector(z12) z1.d <- dist(z1) z2.d <- dist(z2) z12.d <- dist(z12) space <- cbind(as.vector(x), as.vector(y)) space.d <- dist(space) # take partial correlogram without effects of z1 ### pgram() is time-consuming, so this was generated ### in advance and saved. ### set.seed(1234) ### z.no <- pmgram(z12.d, space.d, nperm=1000, resids=FALSE) ### save(z.no, file="ecodist/data/z.no.rda") plot(z.no) # take partial correlogram of z12 given z1 ### pgram() is time-consuming, so this was generated ### in advance and saved. ### set.seed(1234) ### z.z1 <- pmgram(z12.d, space.d, z2.d, nperm=1000, resids=FALSE) ### save(z.z1, file="ecodist/data/z.z1.rda") plot(z.z1) } \keyword{datasets} ecodist/man/iris.nmds.Rd0000644000176200001440000000141114452055674014665 0ustar liggesusers\name{iris.nmds} \alias{iris.nmds} \docType{data} \title{Example for nmds} \description{ An object of class nmds for use in the example for \code{\link{nmds}}. Many of the functions in \code{ecodist} take a long time to run, so prepared examples have been included. } \usage{data(iris.nmds)} \format{ See \code{\link{nmds}} for current format specification. } \author{ Sarah Goslee } \seealso{ \code{\link{nmds}} } \examples{ data(iris) iris.d <- dist(iris[,1:4]) ### nmds() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.nmds <- nmds(iris.d, nits=20, mindim=1, maxdim=4) ### save(iris.nmds, file="ecodist/data/iris.nmds.rda") data(iris.nmds) # examine fit by number of dimensions plot(iris.nmds) } \keyword{datasets} ecodist/man/addord.Rd0000644000176200001440000001056414452055674014225 0ustar liggesusers\name{addord} \alias{addord} \title{ Fit new points to an existing NMDS configuration. } \description{ Uses a brute force algorithm to find the location for each new point that minimizes overall stress. } \usage{ addord(origconf, fulldat, fulldist, isTrain, bfstep = 10, maxit = 50, epsilon = 1e-12) } \arguments{ \item{origconf}{ The original ordination configuration. } \item{fulldat}{ The dataset containing original and new points. } \item{fulldist}{ A dissimilarity matrix calculated on \code{fulldat}. } \item{isTrain}{ A boolean vector of length \code{nrow(fulldat)} indicating which rows were training data used in determining \code{origconf} (TRUE), or are new points (FALSE). } \item{bfstep}{ A tuning parameter for the brute force algorithm describing the size of grid to use. } \item{maxit}{ The maximum number of iterations to use. } \item{epsilon}{ Tolerance value for convergence. } } \details{ A region comprising the original ordination configuration plus one standard deviation is divided into a grid of \code{bfstep} rows and columns. For a new point, the grid cell with the lowest stress is identified. That cell is divided into a finer grid, and the lowest-stress cell identified. This process is repeated up to \code{maxit} times, or until stress changes less than \code{epsilon}. } \value{ \item{fullfitconf }{The new ordination configuration containing training and new points.} \item{stress }{The stress value for each point.} \item{isTrain }{The boolean vector indicating training set membership, for reference.} } \author{ Sarah Goslee } \examples{ data(iris) iris.d <- dist(iris[,1:4]) ### nmds() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.nmds <- nmds(iris.d, nits=20, mindim=1, maxdim=4) ### save(iris.nmds, file="ecodist/data/iris.nmds.rda") data(iris.nmds) # examine fit by number of dimensions plot(iris.nmds) # choose the best two-dimensional solution to work with iris.nmin <- min(iris.nmds, dims=2) # rotate the configuration to maximize variance iris.rot <- princomp(iris.nmin)$scores # rotation preserves distance apart in ordination space cor(dist(iris.nmin), dist(iris.rot)) # fit the data to the ordination as vectors ### vf() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.vf <- vf(iris.nmin, iris[,1:4], nperm=1000) ### save(iris.vf, file="ecodist/data/iris.vf.rda") data(iris.vf) # repeat for the rotated ordination ### vf() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.vfrot <- vf(iris.rot, iris[,1:4], nperm=1000) ### save(iris.vfrot, file="ecodist/data/iris.vfrot.rda") data(iris.vfrot) par(mfrow=c(1,2)) plot(iris.nmin, col=as.numeric(iris$Species), pch=as.numeric(iris$Species), main="NMDS") plot(iris.vf) plot(iris.rot, col=as.numeric(iris$Species), pch=as.numeric(iris$Species), main="Rotated NMDS") plot(iris.vfrot) ####### addord example # generate new data points to add to the ordination # this might be new samples, or a second dataset iris.new <- structure(list(Sepal.Length = c(4.6, 4.9, 5.4, 5.2, 6, 6.5, 6, 6.8, 7.3), Sepal.Width = c(3.2, 3.5, 3.6, 2.3, 2.8, 3, 2.7, 3.1, 3.2), Petal.Length = c(1.2, 1.5, 1.5, 3.5, 4.1, 4.2, 4.8, 5, 5.7), Petal.Width = c(0.26, 0.26, 0.26, 1.2, 1.3, 1.4, 1.8, 2, 2), Species = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), .Label = c("setosa", "versicolor", "virginica"), class = "factor")), .Names = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width", "Species"), class = "data.frame", row.names = c(NA, -9L)) # provide a dist object containing original and new data # provide a logical vector indicating which samples were used to # construct the original configuration iris.full <- rbind(iris, iris.new) all.d <- dist(iris.full[,1:4]) is.orig <- c(rep(TRUE, nrow(iris)), rep(FALSE, nrow(iris.new))) ### addord() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.fit <- addord(iris.nmin, iris.full[,1:4], all.d, is.orig, maxit=100) ### save(iris.fit, file="ecodist/data/iris.fit.rda") data(iris.fit) plot(iris.fit$conf, col=iris.full$Species, pch=c(18, 4)[is.orig + 1], xlab="NMDS 1", ylab="NMDS 2") title("Demo: adding points to an ordination") legend("bottomleft", c("Training set", "Added point"), pch=c(4, 18)) legend("topright", levels(iris$Species), fill=1:3) } \keyword{ multivariate } ecodist/man/plot.nmds.Rd0000644000176200001440000000225414452055674014703 0ustar liggesusers\name{plot.nmds} \alias{plot.nmds} \title{ Plot information about NMDS ordination } \description{ Graphical display of stress and r2 for NMDS ordination along number of dimensions. } \usage{ \method{plot}{nmds}(x, plot = TRUE, xlab = "Dimensions", \dots) } \arguments{ \item{x}{ an object of S3 class \code{nmds}, created by \code{nmds()} } \item{plot}{ optional, if TRUE a figure is produced } \item{xlab}{ optional, label for x axis of graph } \item{\dots}{ optional, other graphics parameters } } \value{ Produces a two-panel plot with stress and r2 for ordination by number of dimensions. Points show the mean value; lines indicate minimum and maximum. } \author{ Dean Urban } \seealso{ \code{\link{nmds}}} \examples{ data(iris) iris.d <- dist(iris[,1:4]) ### nmds() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.nmds <- nmds(iris.d, nits=20, mindim=1, maxdim=4) ### save(iris.nmds, file="ecodist/data/iris.nmds.rda") data(iris.nmds) # examine fit by number of dimensions plot(iris.nmds) # choose the best two-dimensional solution to work with iris.nmin <- min(iris.nmds, dims=2) } \keyword{ multivariate } \keyword{ hplot } ecodist/man/iris.vf.Rd0000644000176200001440000000266614452055674014354 0ustar liggesusers\name{iris.vf} \alias{iris.vf} \docType{data} \title{Example for vector fitting on ordination} \description{ An object of class vf for use in the examples for \code{\link{nmds}} and \code{\link{vf}}. Many of the functions in \code{ecodist} take a long time to run, so prepared examples have been included. } \usage{data(iris.vf)} \format{ See \code{\link{vf}} for current format specification. } \author{ Sarah Goslee } \seealso{ \code{\link{nmds}}, \code{\link{vf}} } \examples{ data(iris) iris.d <- dist(iris[,1:4]) ### nmds() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.nmds <- nmds(iris.d, nits=20, mindim=1, maxdim=4) ### save(iris.nmds, file="ecodist/data/iris.nmds.rda") data(iris.nmds) # examine fit by number of dimensions plot(iris.nmds) # choose the best two-dimensional solution to work with iris.nmin <- min(iris.nmds, dims=2) # rotate the configuration to maximize variance iris.rot <- princomp(iris.nmin)$scores # rotation preserves distance apart in ordination space cor(dist(iris.nmin), dist(iris.rot)) # fit the data to the ordination as vectors ### vf() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.vf <- vf(iris.nmin, iris[,1:4], nperm=1000) ### save(iris.vf, file="ecodist/data/iris.vf.rda") data(iris.vf) plot(iris.nmin, col=as.numeric(iris$Species), pch=as.numeric(iris$Species), main="NMDS") plot(iris.vf) } \keyword{datasets} ecodist/man/relrange.Rd0000644000176200001440000000266314473454706014572 0ustar liggesusers\name{relrange} \alias{relrange} \title{ Relativize a compositional data matrix. } \description{ Relativizes the range of each column of a data frame or matrix x to 0-1. If globalmin and/or globalmax are provided, those are used to scale the columns, for instance to scale a subset to match a larger sample. If they are NA, the minimum and maximum values for each column are used. } \usage{ relrange(x, globalmin = NA, globalmax = NA) } \arguments{ \item{x}{ The data frame or matrix to be relativized. } \item{globalmin}{ A value other than the population minimum to be used. Should be the same length as the number of columns of x. } \item{globalmax}{ A value other than the population maximum to be used. Should be the same length as the number of columns of x. } } \details{ Relativizes the data using the minimum and maximum values. If globalmin and global max are not used, the range will be 0-1 for each variable. This can be useful for putting disparate variables to the same magnitude while keeping all non-negative values. } \value{ Returns an object of the same class as x (matrix or data frame) with the columns rescaled. } \author{ Sarah Goslee } \seealso{ \code{\link{scale}} } \examples{ x <- matrix(1:15, ncol = 3) # uses min and max of the data relrange(x) # uses min and max determined by other knowledge of the variables relrange(x, globalmin = c(0, 0, 0), globalmax = c(6, 10, 20)) } \keyword{ multivariate } ecodist/man/rotate2d.Rd0000644000176200001440000000422314474125057014504 0ustar liggesusers\name{rotate2d} \alias{rotate2d} \title{ Rotate a 2D ordination. } \description{ Rotates a two-dimensional ordination configuration to place the direction indicated along the horizontal axis. } \usage{ rotate2d(ord, x) } %- maybe also 'usage' for other objects documented here. \arguments{ \item{ord}{ A matrix or data frame with two columns, or a vf object, containing the points of an ordination configuration. } \item{x}{ The coordinates of a point in the ordination space. } } \details{ The configuration ord is rotated so that the vector defined by c(0, 0), and x is along the horizontal axis. This can be useful for placing a specific variable, for instance from vf(), in a consistent direction across multiple ordinations. Doing so can facilitate interpretation. } \value{ A rotated data frame of coordinates of the same size as ord and in the same order. If ord was produced by vf(), the complete vf object is returned. } \author{ Sarah Goslee } \seealso{ \code{\link{vf}}, \code{\link{nmds}} } \examples{ # Example of multivariate analysis using built-in iris dataset data(iris) iris.d <- dist(iris[,1:4]) ### nmds() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.nmds <- nmds(iris.d, nits=20, mindim=1, maxdim=4) ### save(iris.nmds, file="ecodist/data/iris.nmds.rda") data(iris.nmds) # examine fit by number of dimensions plot(iris.nmds) # choose the best two-dimensional solution to work with iris.nmin <- min(iris.nmds, dims=2) # fit the data to the ordination as vectors ### vf() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.vf <- vf(iris.nmin, iris[,1:4], nperm=1000) ### save(iris.vf, file="ecodist/data/iris.vf.rda") data(iris.vf) plot(iris.nmin, col=as.numeric(iris$Species), pch=as.numeric(iris$Species), main="NMDS") plot(iris.vf) # rotate configuration so Sepal Width is along the horizontal axis iris.nmin.rot <- rotate2d(iris.nmin, iris.vf[2, 1:2]) iris.vf.rot <- rotate2d(iris.vf, iris.vf[2, 1:2]) plot(iris.nmin.rot, col=as.numeric(iris$Species), pch=as.numeric(iris$Species), main="NMDS") plot(iris.vf.rot) } \keyword{ multivariate } ecodist/man/graze.Rd0000644000176200001440000000547414452055674014104 0ustar liggesusers\name{graze} \alias{graze} \docType{data} \title{ Site information and grazed vegetation data. } \description{ This data frame contains site location, landscape context and dominant plant species abundances for 25 of the plant species found in 50 grazed pastures in the northeastern United States. Elements are the mean values for canopy cover for ten 0.5 x 2 m quadrats. } \usage{data(graze)} \format{ A data frame with 50 observations on the following 25 variables. \describe{ \item{\code{sitelocation}}{Site location along a geographic gradient.} \item{\code{forestpct}}{Percentage forest cover within a 1-km radius.} \item{\code{ACMI2}}{Percentage canopy cover.} \item{\code{ANOD}}{Percentage canopy cover.} \item{\code{ASSY}}{Percentage canopy cover.} \item{\code{BRIN2}}{Percentage canopy cover.} \item{\code{CIAR4}}{Percentage canopy cover.} \item{\code{CIIN}}{Percentage canopy cover.} \item{\code{CIVU}}{Percentage canopy cover.} \item{\code{DAGL}}{Percentage canopy cover.} \item{\code{ELRE4}}{Percentage canopy cover.} \item{\code{GAMO}}{Percentage canopy cover.} \item{\code{LOAR10}}{Percentage canopy cover.} \item{\code{LOCO6}}{Percentage canopy cover.} \item{\code{LOPE}}{Percentage canopy cover.} \item{\code{OXST}}{Percentage canopy cover.} \item{\code{PLMA2}}{Percentage canopy cover.} \item{\code{POPR}}{Percentage canopy cover.} \item{\code{PRVU}}{Percentage canopy cover.} \item{\code{RAAC3}}{Percentage canopy cover.} \item{\code{RUCR}}{Percentage canopy cover.} \item{\code{SORU2}}{Percentage canopy cover.} \item{\code{STGR}}{Percentage canopy cover.} \item{\code{TAOF}}{Percentage canopy cover.} \item{\code{TRPR2}}{Percentage canopy cover.} \item{\code{TRRE3}}{Percentage canopy cover.} \item{\code{VEOF2}}{Percentage canopy cover.} } } \details{ Site locations fall along a southwest-northeast transect through the northeastern United States. This is a synthetic gradient calculated from latitude and longitude. Forest landcover is taken from the USGS 1992 National Land Cover Dataset. All forest classes were combined, and the percentage within 1 km of the sample sites was calculated using a GIS. } \source{ Details of these data are available in Tracy and Sanderson (2000) and Goslee and Sanderson (2010). The 1992 NLCD data can be obtained from http://www.mrlc.gov/. Species codes are from http://plants.usda.gov (2010). } \references{ Tracy, B.F. and M.A. Sanderson. 2000. Patterns of plant species richness in pasture lands of the northeast United States. Plant Ecology 149:169-180. Goslee, S.C., Sanderson, M.A. 2010. Landscape Context and Plant Community Composition in Grazed Agricultural Systems. Landscape Ecology 25:1029-1039. } \author{ Sarah Goslee } \examples{ data(graze) } \keyword{datasets} ecodist/man/mgroup.Rd0000644000176200001440000000322314500646343014264 0ustar liggesusers\name{mgroup} \alias{mgroup} \title{ Mantel test for groups } \description{ Mantel test across one or more group contrasts. } \usage{ mgroup(edist, groups, nperm = 1000, mrank = FALSE) } \arguments{ \item{edist}{ a dist object or lower triangular distance vector. } \item{groups}{ a vector of group memberships (numeric, character, or factor), or a matrix or data frame with columns describing multiple sets of groups. } \item{nperm}{ number of permutations to use. If set to 0, the permutation test will be omitted. } \item{mrank}{ if this is set to FALSE (the default option), Pearson correlations will be used. If set to TRUE, the Spearman correlation (correlation ranked distances) will be used. } } \details{ \code{mgroup} returns the Mantel correlations for group contrast matrices computed from cluster groups across a range of clustering levels. } \value{ \item{nclust }{Number of groups tested.} \item{mantelr }{Mantel coefficient.} \item{pval1 }{one-tailed p-value (null hypothesis: r <= 0).} } \references{ Legendre, P. and M. Fortin. 1989. Spatial pattern and ecological analysis. Vegetatio 80:107-138. } \author{ Sarah Goslee } \seealso{ \code{\link{mantel}} } \examples{ # Using a model matrix to test group membership data(iris) iris.d <- dist(iris[,1:4]) mgroup(iris.d, iris[,5]) # clustering-based example data(graze) graze.d <- dist(graze[, -c(1:2)]) graze.hclust <- hclust(graze.d) clust.groups <- data.frame( k2 = cutree(graze.hclust, k = 2), k4 = cutree(graze.hclust, k = 4), k6 = cutree(graze.hclust, k = 6), k8 = cutree(graze.hclust, k = 8)) mgroup(graze.d, clust.groups, nperm=1000) } \keyword{ multivariate } ecodist/man/corgen.Rd0000644000176200001440000000454014452055674014242 0ustar liggesusers\name{corgen} \alias{corgen} \title{ Generate correlated data } \description{ Generate correlated data of a given length. } \usage{ corgen(len, x, r, population = FALSE, epsilon = 0) } \arguments{ \item{len}{ Length of vectors. } \item{x}{ Independent data. If x is specified, the population parameter is automatically set to TRUE. } \item{r}{ Desired correlation between data vectors. } \item{population}{ TRUE for vectors drawn from two populations with correlation r, otherwise r is the sample correlation. } \item{epsilon}{ Desired tolerance. } } \value{ \item{x }{First data vector, either generated by corgen or given by the user. } \item{y }{Second data vector. } } \details{ Either x or len must be specified. If epsilon = 0, it has no effect, otherwise the sampling process is repeated until the sample correlation is within epsilon of r. This option allows the production of exactly-correlated data, within the limits of epsilon. Setting epsilon > 0 invalidates the population setting; data will be correlated within that range, rather than sampled from that population.If epsilon = 0, it has no effect, otherwise the sampling process is repeated until the sample correlation is within epsilon of r. This option allows the production of exactly-correlated data, within the limits of epsilon. Setting epsilon > 0 invalidates the population setting; data will be correlated within that range, rather than sampled from that population.If epsilon = 0, it has no effect, otherwise the sampling process is repeated until the sample correlation is within epsilon of r. This option allows the production of exactly-correlated data, within the limits of epsilon. Setting epsilon > 0 invalidates the population setting; data will be correlated within that range, rather than sampled from that population. } \author{ Sarah Goslee } \examples{ # create two random variables of length 100 with correlation # of 0.10 +/- 0.01 xy <- corgen(len=100, r=.1, epsilon=0.01) with(xy, cor(x, y)) # create two random variables of length 100 drawn from a population with # a correlation of -0.82 xy <- corgen(len=100, r=-0.82, population=TRUE) with(xy, cor(x, y)) # create a variable y within 0.01 of the given correlation to x x <- 1:100 y <- corgen(x=x, r=.5, epsilon=.01)$y cor(x, y) } \keyword{ distribution } ecodist/man/iris.fit.Rd0000644000176200001440000000465614452055674014524 0ustar liggesusers\name{iris.fit} \alias{iris.fit} \docType{data} \title{Example of adding to an ordination} \description{ A fitted ordination for use in the example for \code{\link{addord}}. Many of the functions in \code{ecodist} take a long time to run, so prepared examples have been included. } \usage{data(iris.fit)} \format{ The format of this object is a list with: X1, X2, etc: ordination configuration: coordinates for each point. stress: goodness of fit for each point. isTrain: logical vector indicating whether each point was used in the original ordination. } \author{ Sarah Goslee } \seealso{ \code{\link{nmds}}, \code{\link{addord}} } \examples{ data(iris) iris.d <- dist(iris[,1:4]) ### nmds() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.nmds <- nmds(iris.d, nits=20, mindim=1, maxdim=4) ### save(iris.nmds, file="ecodist/data/iris.nmds.rda") data(iris.nmds) # choose the best two-dimensional solution to work with iris.nmin <- min(iris.nmds, dims=2) # generate new data points to add to the ordination # this might be new samples, or a second dataset iris.new <- structure(list(Sepal.Length = c(4.6, 4.9, 5.4, 5.2, 6, 6.5, 6, 6.8, 7.3), Sepal.Width = c(3.2, 3.5, 3.6, 2.3, 2.8, 3, 2.7, 3.1, 3.2), Petal.Length = c(1.2, 1.5, 1.5, 3.5, 4.1, 4.2, 4.8, 5, 5.7), Petal.Width = c(0.26, 0.26, 0.26, 1.2, 1.3, 1.4, 1.8, 2, 2), Species = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), .Label = c("setosa", "versicolor", "virginica"), class = "factor")), .Names = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width", "Species"), class = "data.frame", row.names = c(NA, -9L)) # provide a dist object containing original and new data # provide a logical vector indicating which samples were used to # construct the original configuration iris.full <- rbind(iris, iris.new) all.d <- dist(iris.full[,1:4]) is.orig <- c(rep(TRUE, nrow(iris)), rep(FALSE, nrow(iris.new))) ### addord() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.fit <- addord(iris.nmin, iris.full[,1:4], all.d, is.orig, maxit=100) ### save(iris.fit, file="ecodist/data/iris.fit.rda") data(iris.fit) plot(iris.fit$conf, col=iris.full$Species, pch=c(18, 4)[is.orig + 1], xlab="NMDS 1", ylab="NMDS 2") title("Demo: adding points to an ordination") legend("bottomleft", c("Training set", "Added point"), pch=c(4, 18)) legend("topright", levels(iris$Species), fill=1:3) } \keyword{datasets} ecodist/man/crosstab.Rd0000644000176200001440000000525514452055674014611 0ustar liggesusers\name{crosstab} \alias{crosstab} \title{ Data formatting } \description{ Converts field data of the form site, species, observation into a site by species data frame. } \usage{ crosstab(rowlab, collab, values, type = "sum", data, allrows, allcols, na.as.0 = TRUE, check.names = TRUE, \dots) } \arguments{ \item{rowlab}{ row labels, e.g. site names. } \item{collab}{ column labels, e.g. species names. } \item{values}{ data values. } \item{data}{ optional data frame from which to take rowlab, collab and/or values. } \item{type}{ function to use to combine data, one of "sum" (default), "min", "max", "mean", "count". } \item{allrows}{ optional, list of all desired row names that may not appear in rowlab. } \item{allcols}{ optional, list of all desired column names that may not appear in collab. } \item{na.as.0}{ if TRUE, all NA values are replaced with 0. } \item{check.names}{ if FALSE, data frame names are not checked for syntactic validity, so that they match the input categories. Otherwise make.names() is used to adjust them. } \item{\dots}{ optional arguments to the function specified in type, such as na.rm=TRUE} } \details{ Field data are often recorded as a separate row for each site-species combination. This function reformats such data into a data frame for further analysis based on unique row and column labels. The three vectors should all be the same length (including duplicates). The three vectors may also be provided as names of columns in the data frame specified by the data argument. If allrows or allcols exists, rows and/or columns of zeros are inserted for any elements of allrows/allcols not present in rowlab/collab. If values is missing the number of occurrences of combinations of rowlab and collab will be returned. Thus, crosstab(rowlab, collab) is equivalent to table(rowlab, collab). If type is "count", the unique combinations of rowlab, collab and values will be returned. } \value{ data frame with rowlab as row headings, collab as columns, and values as the data. } \author{ Sarah Goslee } \examples{ # Make a random example plotnames <- rep(1:5, each = 6) speciesnames <- rep(c("A", "B", "C"), 10) freqdata <- runif(30) # number of samples of each species and plot crosstab(plotnames, speciesnames) # can use the data argument speciesdata <- data.frame(plots = plotnames, species = speciesnames, freq = freqdata, stringsAsFactors=FALSE) # mean frequency by species and plot crosstab(plots, species, freq, data=speciesdata, type="mean") # can specify additional possible row or column levels crosstab(plots, species, freq, data=speciesdata, type="mean", allcols=LETTERS[1:5]) } \keyword{ manip } \keyword{ multivariate } ecodist/man/vf.Rd0000644000176200001440000000432114474171516013373 0ustar liggesusers\name{vf} \alias{vf} \title{ Vector fitting } \description{ Fits ancillary variables to an ordination configuration. } \usage{ vf(ord, vars, nperm = 100) } \arguments{ \item{ord}{ matrix containing a 2-dimensional ordination result with axes as columns. } \item{vars}{ matrix with ancillary variables as columns. } \item{nperm}{ number of permutation for the significance test. If nperm = 0, the test will be omitted. } } \details{ Vector fitting finds the maximum correlation of the individual variables with a configuration of samples in ordination space. } \value{ an object of class vf, which is a data frame with the first 2 columns containing the scores for every variable in each of the 2 dimensions of the ordination space. r is the maximum correlation of the variable with the ordination space, and pval is the result of the permutation test. } \references{ Jongman, R.H.G., C.J.F. ter Braak and O.F.R. van Tongeren. 1995. Data analysis in community and landscape ecology. Cambridge University Press, New York. } \author{ Sarah Goslee } \seealso{ \code{\link{plot.vf}} } \examples{ # Example of multivariate analysis using built-in iris dataset data(iris) iris.d <- dist(iris[,1:4]) ### nmds() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.nmds <- nmds(iris.d, nits=20, mindim=1, maxdim=4) ### save(iris.nmds, file="ecodist/data/iris.nmds.rda") data(iris.nmds) # examine fit by number of dimensions plot(iris.nmds) # choose the best two-dimensional solution to work with iris.nmin <- min(iris.nmds, dims=2) # fit the data to the ordination as vectors ### vf() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.vf <- vf(iris.nmin, iris[,1:4], nperm=1000) ### save(iris.vf, file="ecodist/data/iris.vf.rda") data(iris.vf) plot(iris.nmin, col=as.numeric(iris$Species), pch=as.numeric(iris$Species), main="NMDS") plot(iris.vf) # rotate configuration so Sepal Width is along the horizontal axis iris.nmin.rot <- rotate2d(iris.nmin, iris.vf[2, 1:2]) iris.vf.rot <- rotate2d(iris.vf, iris.vf[2, 1:2]) plot(iris.nmin.rot, col=as.numeric(iris$Species), pch=as.numeric(iris$Species), main="NMDS") plot(iris.vf.rot) } \keyword{ multivariate } ecodist/man/mgram.Rd0000644000176200001440000000743514473453540014073 0ustar liggesusers\name{mgram} \alias{mgram} \title{ Mantel correlogram } \description{ Calculates simple Mantel correlograms. } \usage{ mgram(species.d, space.d, breaks, nclass, stepsize, equiprobable = FALSE, nperm = 1000, mrank = FALSE, nboot = 500, pboot = 0.9, cboot = 0.95, alternative = "two.sided", trace = FALSE) } \arguments{ \item{species.d}{ lower-triangular dissimilarity matrix. } \item{space.d}{ lower-triangular matrix of geographic distances. } \item{breaks}{ locations of class breaks. If specified, overrides nclass and stepsize. } \item{nclass}{ number of distance classes. If not specified, Sturge's rule will be used to determine an appropriate number of classes. } \item{stepsize}{ width of each distance class. If not specified, nclass and the range of space.d will be used to calculate an appropriate default. } \item{equiprobable}{ if TRUE, create nclass classes of equal number of distances; if FALSE, create nclass classes of equal width } \item{nperm}{ number of permutations to use. If set to 0, the permutation test will be omitted. } \item{mrank}{ if this is set to FALSE (the default option), Pearson correlations will be used. If set to TRUE, the Spearman correlation (correlation ranked distances) will be used. } \item{nboot}{ number of iterations to use for the bootstrapped confidence limits. If set to 0, the bootstrapping will be omitted. } \item{pboot}{ the level at which to resample the data for the bootstrapping procedure. } \item{cboot}{ the level of the confidence limits to estimate. } \item{alternative}{ default is "two.sided", and returns p-values for H0: rM = 0. The alternative is "one.sided", which returns p-values for H0: rM <= 0. } \item{trace}{ if TRUE, returns progress indicators. } } \details{ This function calculates Mantel correlograms, and tests the hypothesis that the mean compositional dissimilarity within a distance class differs from the mean of all the other distance classes combined. The Mantel correlogram is essentially a multivariate autocorrelation function. The Mantel r represents the dissimilarity in variable composition (often species composition) at a particular lag distance, and significance is tested in reference to all distance classes. } \value{ Returns an object of class mgram, which is a list with two elements. mgram is a matrix with one row for each distance class and 6 columns: \item{lag }{midpoint of the distance class.} \item{ngroup }{number of distances in that class.} \item{mantelr }{Mantel r value.} \item{pval }{p-value for the test chosen.} \item{llim }{lower bound of confidence limit for mantelr.} \item{ulim }{upper bound of confidence limit for mantelr.} resids is NA for objects calculated by mgram(). } \references{ Legendre, P. and M. Fortin. 1989. Spatial pattern and ecological analysis. Vegetatio 80:107-138. } \author{ Sarah Goslee } \seealso{ \code{\link{mantel}}, \code{\link{plot.mgram}}, \code{\link{pmgram}} } \examples{ # generate a simple surface x <- matrix(1:10, nrow=10, ncol=10, byrow=FALSE) y <- matrix(1:10, nrow=10, ncol=10, byrow=TRUE) z <- x + 3*y image(z) # analyze the pattern of z across space space <- cbind(as.vector(x), as.vector(y)) z <- as.vector(z) space.d <- distance(space, "eucl") z.d <- distance(z, "eucl") z.mgram <- mgram(z.d, space.d, nperm=0) plot(z.mgram) # data(graze) space.d <- dist(graze$sitelocation) forest.d <- dist(graze$forestpct) grasses <- graze[, colnames(graze) \%in\% c("DAGL", "LOAR10", "LOPE", "POPR")] legumes <- graze[, colnames(graze) \%in\% c("LOCO6", "TRPR2", "TRRE3")] grasses.bc <- bcdist(grasses) legumes.bc <- bcdist(legumes) # Does the relationship of composition with distance vary for # grasses and legumes? par(mfrow=c(2, 1)) plot(mgram(grasses.bc, space.d, nclass=8)) plot(mgram(legumes.bc, space.d, nclass=8)) } \keyword{ multivariate } ecodist/man/xdistance.Rd0000644000176200001440000000617214473442403014743 0ustar liggesusers\name{xdistance} \alias{xdistance} \title{ Cross-distance between two datasets. } \description{ Pairwise dissimilarity calculation between rows of one dataset and rows of another, for instance across different sampling periods for the same set of sites. } \usage{ xdistance(x, y, method = "euclidean") } \arguments{ \item{x}{A site by species or other matrix or data frame.} \item{y}{A a second site by species dataset, which must have at least the same columns.} \item{method}{This function calls \code{\link{distance}} to do the calculations, and will accept any symmetric method used there, currently: "euclidean", "bray-curtis", "manhattan", "mahalanobis" (squared Mahalanobis distance), "jaccard", "sorensen", "gower", "modgower10" (modified Gower, base 10), "modgower2" (modified Gower, base 2). Partial matching will work for selecting a method. The asymmetric "difference" method will not work for calculating cross-distances.} } \details{ This function will calculate rowwise dissimilarities between any pair of matrices or data frames with the same number of columns. Note that the cross-dissimilarity functions are for research purposes, and are not well-tested. } \value{ A non-symmetric and possibly not square matrix of dissimilarities of class \code{xdist}, where \code{result <- xdistance(x, y)} produces a matrix with \code{result[a, b]} containing the dissimilarity between \code{x[a, ]} and \code{y[b, ]}. } \author{ Sarah Goslee } \seealso{ \code{\link{distance}}, \code{\link{xmantel}}, \code{\link{xmgram}}} \examples{ data(graze) ### EXAMPLE 1: Square matrices # take two subsets of sites with different dominant grass abundances # use cut-offs that produce equal numbers of sites dom1 <- subset(graze, POPR > 50 & DAGL < 20) # 8 sites dom2 <- subset(graze, POPR < 50 & DAGL > 20) # 8 sites # first two columns are site info dom.xd <- xdistance(dom1[, -c(1,2)], dom2[, -c(1,2)], "bray") # environmental and spatial distances; preserve rownames forest.xd <- xdistance(dom1[, "forestpct", drop=FALSE], dom2[, "forestpct", drop=FALSE]) sitelocation.xd <- xdistance(dom1[, "sitelocation", drop=FALSE], dom2[, "sitelocation", drop=FALSE]) # permutes rows and columns of full nonsymmetric matrix xmantel(dom.xd ~ forest.xd) xmantel(dom.xd ~ forest.xd + sitelocation.xd) plot(xmgram(dom.xd, sitelocation.xd)) ### EXAMPLE 2: Non-square matrices # take two subsets of sites with different dominant grass abundances # this produces a non-square matrix dom1 <- subset(graze, POPR > 45 & DAGL < 20) # 13 sites dom2 <- subset(graze, POPR < 45 & DAGL > 20) # 8 sites # first two columns are site info dom.xd <- xdistance(dom1[, -c(1,2)], dom2[, -c(1,2)], "bray") # environmental and spatial distances; preserve rownames forest.xd <- xdistance(dom1[, "forestpct", drop=FALSE], dom2[, "forestpct", drop=FALSE]) sitelocation.xd <- xdistance(dom1[, "sitelocation", drop=FALSE], dom2[, "sitelocation", drop=FALSE]) # permutes rows and columns of full nonsymmetric matrix xmantel(dom.xd ~ forest.xd, dims=c(13, 8)) xmantel(dom.xd ~ forest.xd + sitelocation.xd, dims=c(13, 8)) plot(xmgram(dom.xd, sitelocation.xd)) } \keyword{ multivariate } ecodist/man/bcdist.Rd0000644000176200001440000000242514452055674014235 0ustar liggesusers\name{bcdist} \alias{bcdist} \title{ Bray-Curtis distance } \description{ Returns the Bray-Curtis (also known as Sorenson, 1 - percent similarity) pairwise distances for the objects in the data. It is duplicated by functionality within \code{\link{distance}} but remains for backward compatibility and because it is substantially faster. } \usage{ bcdist(x, rmzero = FALSE) } \arguments{ \item{x}{ matrix or data frame with rows as samples and columns as variables (such as species). Distances will be calculated for each pair of rows. } \item{rmzero}{ If rmzero=TRUE, empty rows will be removed from the data before distances are calculated. Otherwise, the distance between two empty rows is assumed to be 0 (the default). } } \value{ This function returns a column-order lower-triangular distance matrix. The returned object has an attribute, Size, giving the number of objects, that is, nrow(x). The length of the vector that is returned is nrow(x)*(nrow(x)-1)/2. } \author{ Sarah Goslee } \seealso{ \code{\link{dist}}, \code{\link{distance}}} \examples{ data(graze) system.time(graze.bc <- bcdist(graze[, -c(1:2)])) # equivalent to but much faster than: system.time(graze.bc2 <- distance(graze[, -c(1:2)], "bray-curtis")) all.equal(graze.bc, graze.bc2) } \keyword{ multivariate } ecodist/man/MRM.Rd0000644000176200001440000000525114452055674013420 0ustar liggesusers\name{MRM} \alias{MRM} \title{ Multiple Regression on distance Matrices } \description{ Multiple regression on distance matrices (MRM) using permutation tests of significance for regression coefficients and R-squared. } \usage{ MRM(formula = formula(data), data, nperm = 1000, method = "linear", mrank = FALSE) } \arguments{ \item{formula}{ formula describing the test to be conducted. } \item{data}{ an optional dataframe containing the variables in the model as columns of dissimilarities. By default the variables are taken from the current environment. } \item{nperm}{ number of permutations to use. If set to 0, the permutation test will be omitted. } \item{mrank}{ if this is set to FALSE (the default option), Pearson correlations will be used. If set to TRUE, the Spearman correlation (correlation ranked distances) will be used. } \item{method}{ if "linear", the default, uses multiple regression analysis. If "logistic", performs logistic regression with appropriate permutation testing. Note that this may be substantially slower.} } \details{ Performs multiple regression on distance matrices following the methods outlined in Legendre et al. 1994. Specificaly, the permutation test uses a pseudo-t test to assess significance, rather than using the regression coefficients directly. } \value{ \item{coef }{A matrix with regression coefficients and associated p-values from the permutation test (using the pseudo-t of Legendre et al. 1994).} \item{r.squared }{Regression R-squared and associated p-value from the permutation test (linear only). } \item{F.test }{F-statistic and p-value for overall F-test for lack of fit (linear only).} \item{dev }{Residual deviance, degrees of freedom, and associated p-value (logistic only).} } \references{ Lichstein, J. 2007. Multiple regression on distance matrices: A multivariate spatial analysis tool. Plant Ecology 188: 117-131. Legendre, P.; Lapointe, F. and Casgrain, P. 1994. Modeling brain evolution from behavior: A permutational regression approach. Evolution 48: 1487-1499. } \author{ Sarah Goslee } \seealso{ \code{\link{mantel}} } \examples{ data(graze) # Abundance of this grass is related to forest cover but not location MRM(dist(LOAR10) ~ dist(sitelocation) + dist(forestpct), data=graze, nperm=10) # Abundance of this legume is related to location but not forest cover MRM(dist(TRRE3) ~ dist(sitelocation) + dist(forestpct), data=graze, nperm=10) # Compare to presence/absence of grass LOAR10 using logistic regression LOAR10.presence <- ifelse(graze$LOAR10 > 0, 1, 0) MRM(dist(LOAR10.presence) ~ dist(sitelocation) + dist(forestpct), data=graze, nperm=10, method="logistic") } \keyword{ multivariate } ecodist/man/xmgram.Rd0000644000176200001440000001006714473453544014262 0ustar liggesusers\name{xmgram} \alias{xmgram} \title{Cross-Mantel correlogram } \description{ Calculates simple Mantel correlograms from cross-distance matrices. } \usage{ xmgram(species.xd, space.xd, breaks, nclass, stepsize, equiprobable = FALSE, nperm = 1000, mrank = FALSE, alternative = "two.sided", trace = FALSE) } \arguments{ \item{species.xd}{ non-symmetric square cross-distance matrix. } \item{space.xd}{ non-symmetric square matrix of geographic distances. } \item{breaks}{ locations of class breaks. If specified, overrides nclass and stepsize. } \item{nclass}{ number of distance classes. If not specified, Sturge's rule will be used to determine an appropriate number of classes. } \item{stepsize}{ width of each distance class. If not specified, nclass and the range of space.d will be used to calculate an appropriate default. } \item{equiprobable}{ if TRUE, create nclass classes of equal number of distances; if FALSE, create nclass classes of equal width } \item{nperm}{ number of permutations to use. If set to 0, the permutation test will be omitted. } \item{mrank}{ if this is set to FALSE (the default option), Pearson correlations will be used. If set to TRUE, the Spearman correlation (correlation ranked distances) will be used. } \item{alternative}{ default is "two.sided", and returns p-values for H0: rM = 0. The alternative is "one.sided", which returns p-values for H0: rM <= 0. } \item{trace}{ if TRUE, returns progress indicators. } } \details{ This function calculates cross-Mantel correlograms. The Mantel correlogram is essentially a multivariate autocorrelation function. The Mantel r represents the dissimilarity in variable composition (often species composition) at a particular lag distance. Note that the cross-dissimilarity functions are for research purposes, and are not well-tested. } \value{ Returns an object of class mgram, which is a list with two elements. mgram is a matrix with one row for each distance class and 6 columns: \item{lag }{midpoint of the distance class.} \item{ngroup }{number of distances in that class.} \item{mantelr }{Mantel r value.} \item{pval }{p-value for the test chosen.} resids is NA for objects calculated by mgram(). } \references{ Legendre, P. and M. Fortin. 1989. Spatial pattern and ecological analysis. Vegetatio 80:107-138. } \author{ Sarah Goslee } \seealso{\code{\link{xdistance}} \code{\link{xmantel}}, \code{\link{plot.mgram}} } \examples{ # Need to develop a cross-dissimilarity example data(graze) ### EXAMPLE 1: Square matrices # take two subsets of sites with different dominant grass abundances # use cut-offs that produce equal numbers of sites dom1 <- subset(graze, POPR > 50 & DAGL < 20) # 8 sites dom2 <- subset(graze, POPR < 50 & DAGL > 20) # 8 sites # first two columns are site info dom.xd <- xdistance(dom1[, -c(1,2)], dom2[, -c(1,2)], "bray") # environmental and spatial distances; preserve rownames forest.xd <- xdistance(dom1[, "forestpct", drop=FALSE], dom2[, "forestpct", drop=FALSE]) sitelocation.xd <- xdistance(dom1[, "sitelocation", drop=FALSE], dom2[, "sitelocation", drop=FALSE]) # permutes rows and columns of full nonsymmetric matrix xmantel(dom.xd ~ forest.xd) xmantel(dom.xd ~ forest.xd + sitelocation.xd) plot(xmgram(dom.xd, sitelocation.xd)) ### EXAMPLE 2: Non-square matrices # take two subsets of sites with different dominant grass abundances # this produces a non-square matrix dom1 <- subset(graze, POPR > 45 & DAGL < 20) # 13 sites dom2 <- subset(graze, POPR < 45 & DAGL > 20) # 8 sites # first two columns are site info dom.xd <- xdistance(dom1[, -c(1,2)], dom2[, -c(1,2)], "bray") # environmental and spatial distances; preserve rownames forest.xd <- xdistance(dom1[, "forestpct", drop=FALSE], dom2[, "forestpct", drop=FALSE]) sitelocation.xd <- xdistance(dom1[, "sitelocation", drop=FALSE], dom2[, "sitelocation", drop=FALSE]) # permutes rows and columns of full nonsymmetric matrix xmantel(dom.xd ~ forest.xd, dims=c(13, 8)) xmantel(dom.xd ~ forest.xd + sitelocation.xd, dims=c(13, 8)) plot(xmgram(dom.xd, sitelocation.xd)) } \keyword{ multivariate } ecodist/man/bump.Rd0000644000176200001440000000106014452055674013722 0ustar liggesusers\name{bump} \alias{bump} \docType{data} \title{Nine-bump spatial pattern} \description{ A two-dimensional artificial "landscape" illustrating the kind of spatial pattern that might be seen across mountain peaks. } \usage{data(bump)} \format{ The format is: int [1:25, 1:25] 2 2 2 2 2 2 2 2 2 2 ... - attr(*, "dimnames")=List of 2 ..$ : chr [1:25] "1" "3" "5" "7" ... ..$ : chr [1:25] "V1" "V3" "V5" "V7" ... } \author{ Sarah Goslee } \seealso{ \code{\link{bump.pmgram}}, \code{\link{pmgram}} } \examples{ data(bump) image(bump) } \keyword{datasets} ecodist/man/fixdmat.Rd0000644000176200001440000000176314452055674014425 0ustar liggesusers\name{fixdmat} \alias{fixdmat} \title{ Distance matrix conversion } \description{ Convert a row-order lower-triangular distance matrix to a full symmetric matrix. } \usage{ fixdmat(v) } \arguments{ \item{v}{ lower-triangular distance matrix in row order. } } \details{ R distance functions such as dist and bcdist return a lower triangular distance matrix in column order. Some other programs return the lower triangular matrix in row order. To use this matrix in R functions, it must be converted from row order to column order. } \value{ full symmetric distance matrix. } \author{ Sarah Goslee } \seealso{ \code{\link{lower}}, \code{\link{full}} } \examples{ x.vec <- seq_len(6) x.vec # Make an R-style column order symmetric matrix full(x.vec) # Extract the lower triangle from a symmetric matrix # in column order lower(full(x.vec)) # Convert to or from a row order symmetric matrix fixdmat(x.vec) lower(fixdmat(x.vec)) fixdmat(c(1, 2, 4, 3, 5, 6)) } \keyword{ manip } \keyword{ multivariate } ecodist/man/lower.Rd0000644000176200001440000000215314452055674014113 0ustar liggesusers\name{lower} \alias{lower} \title{ Lower-triangular matrix } \description{ Convert a symmetric distance matrix to a column order lower triangular matrix. } \usage{ lower(m) } \arguments{ \item{m}{ a symmetric distance matrix. } } \details{ Converts a symmetric matrix, for example a dissimilarity matrix, into a column order lower-triangular matrix. This may be useful to format the input for certain clustering and ordination functions. Note that \code{lower()} used on a 1x1 matrix will return the single element, which may not be the correct behavior in all cases, while \code{full()} used on a single element will return a 2x2 matrix. } \value{ column order lower triangular matrix. } \author{ Sarah Goslee } \seealso{ \code{\link{full}}, \code{\link{fixdmat}} } \examples{ x.vec <- seq_len(6) x.vec # Make an R-style column order symmetric matrix full(x.vec) # Extract the lower triangle from a symmetric matrix # in column order lower(full(x.vec)) # Convert to or from a row order symmetric matrix fixdmat(x.vec) lower(fixdmat(x.vec)) fixdmat(c(1, 2, 4, 3, 5, 6)) } \keyword{ manip } \keyword{ multivariate } ecodist/man/iris.vfrot.Rd0000644000176200001440000000351614452055674015074 0ustar liggesusers\name{iris.vfrot} \alias{iris.vfrot} \docType{data} \title{Example for vector fitting on rotated ordination} \description{ An object of class vf for use in the examples for \code{\link{nmds}} and \code{\link{vf}}. Many of the functions in \code{ecodist} take a long time to run, so prepared examples have been included. } \usage{data(iris.vfrot)} \format{ See \code{\link{vf}} for current format specification. } \author{ Sarah Goslee } \seealso{ \code{\link{nmds}}, \code{\link{vf}} } \examples{ data(iris) iris.d <- dist(iris[,1:4]) ### nmds() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.nmds <- nmds(iris.d, nits=20, mindim=1, maxdim=4) ### save(iris.nmds, file="ecodist/data/iris.nmds.rda") data(iris.nmds) # examine fit by number of dimensions plot(iris.nmds) # choose the best two-dimensional solution to work with iris.nmin <- min(iris.nmds, dims=2) # rotate the configuration to maximize variance iris.rot <- princomp(iris.nmin)$scores # rotation preserves distance apart in ordination space cor(dist(iris.nmin), dist(iris.rot)) # fit the data to the ordination as vectors ### vf() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.vf <- vf(iris.nmin, iris[,1:4], nperm=1000) ### save(iris.vf, file="ecodist/data/iris.vf.rda") data(iris.vf) # repeat for the rotated ordination ### vf() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.vfrot <- vf(iris.rot, iris[,1:4], nperm=1000) ### save(iris.vfrot, file="ecodist/data/iris.vfrot.rda") data(iris.vfrot) par(mfrow=c(1,2)) plot(iris.nmin, col=as.numeric(iris$Species), pch=as.numeric(iris$Species), main="NMDS") plot(iris.vf) plot(iris.rot, col=as.numeric(iris$Species), pch=as.numeric(iris$Species), main="Rotated NMDS") plot(iris.vfrot) } \keyword{datasets} ecodist/man/plot.mgram.Rd0000644000176200001440000000303614476615652015050 0ustar liggesusers\name{plot.mgram} \alias{plot.mgram} \title{ Plot a Mantel correlogram } \description{ Plot a Mantel correlogram from an object of S3 class \code{mgram}, using solid symbols for significant values. } \usage{ \method{plot}{mgram}(x, pval = 0.05, xlab = "Distance", ylab = NULL, \dots) } \arguments{ \item{x}{ an object of class \code{mgram} } \item{pval}{ cut-off level for statistical significance. } \item{xlab}{ x-axis label. } \item{ylab}{ y-axis label. } \item{\dots}{ optional, any additional graphics parameters. } } \value{ draws a plot (graphics device must be active). } \author{ Sarah Goslee } \seealso{ \code{\link{mgram}} } \examples{ # generate a simple surface x <- matrix(1:10, nrow=10, ncol=10, byrow=FALSE) y <- matrix(1:10, nrow=10, ncol=10, byrow=TRUE) z <- x + 3*y image(z) # analyze the pattern of z across space space <- cbind(as.vector(x), as.vector(y)) z <- as.vector(z) space.d <- distance(space, "eucl") z.d <- distance(z, "eucl") z.mgram <- mgram(z.d, space.d, nperm=0) plot(z.mgram) # data(graze) space.d <- dist(graze$sitelocation) forest.d <- dist(graze$forestpct) grasses <- graze[, colnames(graze) \%in\% c("DAGL", "LOAR10", "LOPE", "POPR")] legumes <- graze[, colnames(graze) \%in\% c("LOCO6", "TRPR2", "TRRE3")] grasses.bc <- bcdist(grasses) legumes.bc <- bcdist(legumes) # Does the relationship of composition with distance vary for # grasses and legumes? par(mfrow=c(2, 1)) plot(mgram(grasses.bc, space.d, nclass=8)) plot(mgram(legumes.bc, space.d, nclass=8)) } \keyword{ multivariate } \keyword{ hplot } ecodist/man/min.nmds.Rd0000644000176200001440000000250514452055674014507 0ustar liggesusers\name{min.nmds} \alias{min.nmds} \alias{nmds.min} \title{ Find minimum stress configuration } \description{ Finds minimum stress configuration from output of nmds() } \usage{ \method{min}{nmds}(\dots, na.rm = FALSE, dims = 2) nmds.min(x, dims = 2) } \arguments{ \item{\dots}{ output from nmds() } \item{x}{ output from nmds() } \item{dims}{ desired dimensionality of result. If dims = 0 then the overall minimum stress configuration is chosen. By default, the best two-dimensional configuration is returned. } \item{na.rm}{Not used; there should be no NA values in a NMDS configuration.} } \value{ Configuration of minimum stress ordination (dataframe of coordinates). The stress and r^2 for the minimum stress configuration are stored as attributes. } \details{ For back-compatibility, the \code{nmds.min} function remains. } \author{ Sarah Goslee } \seealso{ \code{\link{nmds}} } \examples{ data(iris) iris.d <- dist(iris[,1:4]) ### nmds() is timeconsuming, so this was generated ### in advance and saved. ### set.seed(1234) ### iris.nmds <- nmds(iris.d, nits=20, mindim=1, maxdim=4) ### save(iris.nmds, file="ecodist/data/iris.nmds.rda") data(iris.nmds) # examine fit by number of dimensions plot(iris.nmds) # choose the best two-dimensional solution to work with iris.nmin <- min(iris.nmds, dims=2) } \keyword{ multivariate } ecodist/man/dim.dist.Rd0000644000176200001440000000122214452055674014472 0ustar liggesusers\name{dim.dist} \alias{dim.dist} \title{ Dimension of a distance object } \description{ Returns NULL for the dimensions of a distance object. } \usage{ \method{dim}{dist}(x) } \arguments{ \item{x}{ object of class \code{dist} } } \details{ The spdep package overwrites the base R behavior of dim.dist() to return c(n, n) where n is the size of the full matrix. The base R behavior returns NULL. This function restores base R behavior within ecodist, because otherwise spdep being loaded breaks ecodist functionality. } \value{ NULL } \author{ Sarah Goslee } \examples{ data(graze) dim(dist(graze)) } \keyword{ manip } \keyword{ multivariate } ecodist/man/distance.Rd0000644000176200001440000000543114452055674014557 0ustar liggesusers\name{distance} \alias{distance} \title{ Calculate dissimilarity/distance metrics } \description{ This function calculates a variety of dissimilarity or distance metrics. Although it duplicates the functionality of dist() and bcdist(), it is written in such a way that new metrics can easily be added. distance() was written for extensibility and understandability, and is not necessarily an efficient choice for use with large matrices. } \usage{ distance(x, method = "euclidean", sprange=NULL, spweight=NULL, icov, inverted = FALSE) } \arguments{ \item{x}{ matrix or data frame with rows as samples and columns as variables (such as species). Distances will be calculated for each pair of rows. } \item{method}{ Currently 7 dissimilarity metrics can be calculated: "euclidean", "bray-curtis", "manhattan", "mahalanobis" (squared Mahalanobis distance), "jaccard", "difference", "sorensen", "gower", "modgower10" (modified Gower, base 10), "modgower2" (modified Gower, base 2). Partial matching will work for selecting a method.} \item{sprange}{Gower dissimilarities offer the option of dividing by the species range. If sprange=NULL no range is used. If sprange is a vector of length nrow(x) it is used for standardizing the dissimilarities.} \item{spweight}{Euclidean, Manhattan, and Gower dissimilarities allow weighting. If spweight=NULL, no weighting is used. If spweight="absence", then W=0 if both species are absent and 1 otherwise, thus deleting joint absences.} \item{icov}{Optional covariance matrix; only used if method="mahalanobis" since Mahalanobis distance requires calculating the variance-covariance matrix for the entire dataset. Providing icov directly makes it possible to calculate distances for a subset of the full dataset.} \item{inverted}{If TRUE, the optional covariance matrix for method="mahalanobis" is not inverted before solving. Providing an inverted matrix may speed up calculations.} } \value{ Returns a lower-triangular distance matrix as an object of class "dist". } \author{ Sarah Goslee } \seealso{ \code{\link{dist}}, \code{\link{bcdist}} } \examples{ data(iris) iris.bc <- distance(iris[, 1:4], "bray-curtis") # The effect of specifying icov: # calculate Mahalanobis distance for the full iris dataset iris.md <- full(distance(iris[, 1:4], "mahal")) iris.md[1, 2] # Mahalanobis distance between samples 1 and 2 # calculate Mahalanobis for just one species setosa.md <- full(distance(iris[iris$Species == "setosa", 1:4], "mahal")) setosa.md[1, 2] # Mahalanobis distance between samples 1 and 2 # use the covariance matrix for the full dataset to scale for one species setosa.scaled.md <- full(distance(iris[iris$Species == "setosa", 1:4], "mahal", icov=var(iris[,1:4]))) setosa.scaled.md[1, 2] # Mahalanobis distance between samples 1 and 2 } \keyword{ multivariate } ecodist/man/cor2m.Rd0000644000176200001440000000354614452055674014014 0ustar liggesusers\name{cor2m} \alias{cor2m} \title{ Two-matrix correlation table } \description{ Generate a correlation table between the variables of two data sets, originally for comparing species abundances and environmental variables. } \usage{ cor2m(x, y, trim = TRUE, alpha = 0.05) } \arguments{ \item{x}{ A matrix or data frame of environmental (or other) variables matching the sites of x } \item{y}{ A matrix or data frame of species (or other) variables } \item{trim}{ If trim is TRUE, set rho } \keyword{ package } ecodist/DESCRIPTION0000644000176200001440000000202214517747122013420 0ustar liggesusersPackage: ecodist Version: 2.1.3 Date: 2023-10-30 Title: Dissimilarity-Based Functions for Ecological Analysis Authors@R: c(person("Sarah", "Goslee", role = c("aut", "cre"), email = "Sarah.Goslee@usda.gov"), person("Dean", "Urban", role = "aut")) Author: Sarah Goslee [aut, cre], Dean Urban [aut] Maintainer: Sarah Goslee Depends: R (>= 3.0.0) LazyData: true Imports: stats, graphics, igraph Suggests: knitr, testthat, markdown VignetteBuilder: knitr Description: Dissimilarity-based analysis functions including ordination and Mantel test functions, intended for use with spatial and community ecological data. The original package description is in Goslee and Urban (2007) , with further statistical detail in Goslee (2010) . License: GPL (>= 2) BugReports: https://github.com/phiala/ecodist/issues NeedsCompilation: yes Packaged: 2023-10-30 14:30:01 UTC; sarahg Repository: CRAN Date/Publication: 2023-10-30 15:40:02 UTC ecodist/build/0000755000176200001440000000000014517736751013023 5ustar liggesusersecodist/build/vignette.rds0000644000176200001440000000032314517736751015360 0ustar liggesusersmO0l> 1Q9y /=xm&!!̥qtHs5%xpo2,e4m1 炛 ap;ݔ@+'x9g/FE,O;DYDjL0Y߳4=I_k?喙+^ Q?G7|qaӾecodist/build/partial.rdb0000644000176200001440000000735614517736747015170 0ustar liggesusers]suT 11I L$]&*tw}/>Ч>u3@CS:0@@vػ+6b'9:=ܝ,JᡁٟRi.M08MTK7k+}NJAnhE)u ^t!56UCx񓉣Q58i)| Z7#o]})A7NLL2[JMx 6;xK spDų F ߹yER_=}d2$9P\EK9%yl;xTr5eo\]l:hwKރņVk̳O,o+ap7JէV҂xGQIT#r9CST\{`2[l N#> !]q&IS0L" Wg\یrrCξ{ œTŔD-Zl߅CQR6vO18lVVog0]{Cq!Dt XpuϽh_' s,Kw+= {ԨJsgg>`+&^\lVn $֥K(..Eۧ U+ i% \8iN݈SSiJEɳlˏ7PVUGU+ I`nMY*Μ܅R|U1U"m(P 1^V4rר'd[-jzlجŦ&266!3B#Rk;uv+U UGٝ] U߰EEM2쌖c9ۨ;Sbm;vk;Ë/\WY`|Չf:1]C8ʰll1:$bpF9QY%pIJ{o++-UEW}pur 0kd\O!ʯD>-W6ktGcqbs Qj4ā0(s5_EF~1x^gsT&`I"LѕXNGuj48BJ+mP  @R`w%`YKnG 0U[CGz֖GR8!$ßL1kV,䦄boÙf9Ȱ,e5U^'#&iYL>#AeF uTLeirQd^M2zEtD(kp j5,WgD ? "sH/5']KD7!s/r &ML%)7m>YIa(WkIYq>ɘL"5'~×'ƾ̱Ǚ :3#Zs`t\|ʉ{"me\Ə0Kwr ` Z;-m$) R <ϙ?=V7iQ5x-Wjїr- !Vʲ벉zz/w*]$y.}1}T,}_9UBQ#T]NЧiZ{F#<|p/D2^@.#<p)3sk{3 )+% e/w+fb^ Z<$\ tg2{2˴όYNi2tZ@n^i\Df˸ D6}YRIG|†1,/Pvo"fz8P~: zZGQ/Br[Z\ܸu|tE񐭏sa* yU ҟEʈ˹C*[4gP,d ~glܾ`hQrZ1c{W n^mXObmجCԫ_O7!&(}AYbecodist/tests/0000755000176200001440000000000014452055674013062 5ustar liggesusersecodist/tests/testthat/0000755000176200001440000000000014517747122014720 5ustar liggesusersecodist/tests/testthat/test-crosstab.R0000644000176200001440000001151414452055674017644 0ustar liggesuserscontext("crosstab") test_that("different sizes and shapes of data", { expect_equal( crosstab(rep(letters[1:3], 4), rep(1:4, each=3)), structure(list(X1 = c(1, 1, 1), X2 = c(1, 1, 1), X3 = c(1, 1, 1), X4 = c(1, 1, 1)), .Names = c("X1", "X2", "X3", "X4"), row.names = c("a", "b", "c"), class = "data.frame") ) expect_equal( crosstab(rep(letters[1:3], 4), rep(1:4, each=3), allrows=letters[1:5]), structure(list(X1 = c(1, 1, 1, 0, 0), X2 = c(1, 1, 1, 0, 0), X3 = c(1, 1, 1, 0, 0), X4 = c(1, 1, 1, 0, 0)), .Names = c("X1", "X2", "X3", "X4"), row.names = c("a", "b", "c", "d", "e"), class = "data.frame") ) expect_equal( crosstab(rep(letters[1:3], 4), rep(1:4, each=3), allrows=letters[1:5], allcols=1:5), structure(list(X1 = c(1, 1, 1, 0, 0), X2 = c(1, 1, 1, 0, 0), X3 = c(1, 1, 1, 0, 0), X4 = c(1, 1, 1, 0, 0), X5 = c(0, 0, 0, 0, 0)), .Names = c("X1", "X2", "X3", "X4", "X5"), row.names = c("a", "b", "c", "d", "e"), class = "data.frame") ) expect_equal( crosstab(rep(letters[1], 12), rep(1:4, each=3), allrows=letters[1:5], allcols=1:5), structure(list(X1 = c(3, 0, 0, 0, 0), X2 = c(3, 0, 0, 0, 0), X3 = c(3, 0, 0, 0, 0), X4 = c(3, 0, 0, 0, 0), X5 = c(0, 0, 0, 0, 0)), .Names = c("X1", "X2", "X3", "X4", "X5"), row.names = c("a", "b", "c", "d", "e"), class = "data.frame") ) expect_equal( crosstab(rep(letters[1], 12), rep(1:4, each=3), allcols=1:5), structure(list(X1 = 3, X2 = 3, X3 = 3, X4 = 3, X5 = 0), .Names = c("X1", "X2", "X3", "X4", "X5"), row.names = "a", class = "data.frame") ) expect_equal( crosstab(rep(letters[1:3], 4), rep(1, each=12), allrows=letters[1:5], allcols=1:5), structure(list(X1 = c(4, 4, 4, 0, 0), X2 = c(0, 0, 0, 0, 0), X3 = c(0, 0, 0, 0, 0), X4 = c(0, 0, 0, 0, 0), X5 = c(0, 0, 0, 0, 0)), .Names = c("X1", "X2", "X3", "X4", "X5"), row.names = c("a", "b", "c", "d", "e"), class = "data.frame") ) expect_equal( crosstab(rep(letters[1:3], 4), rep(1, each=12), allrows=letters[1:5]), structure(list(X1 = c(4, 4, 4, 0, 0)), .Names = "X1", row.names = c("a", "b", "c", "d", "e"), class = "data.frame") ) expect_equal( crosstab(rep(1, each=12), rep(letters[1:3], 4), allcols=letters[1:5]), structure(list(a = 4, b = 4, c = 4, d = 0, e = 0), .Names = c("a", "b", "c", "d", "e"), row.names = "1", class = "data.frame") ) expect_equal( crosstab(rep(letters[1:3], 4), rep(1, each=12), allcols=1:5), structure(list(X1 = c(4, 4, 4), X2 = c(0, 0, 0), X3 = c(0, 0, 0), X4 = c(0, 0, 0), X5 = c(0, 0, 0)), .Names = c("X1", "X2", "X3", "X4", "X5"), row.names = c("a", "b", "c"), class = "data.frame") ) }) test_that("data interface", { x <- data.frame(a = rep(letters[1:3], 4), b = rep(1:4, each=3), c = seq_len(12)) expect_equal( crosstab(a, b, data=x), structure(list(X1 = c(1, 1, 1), X2 = c(1, 1, 1), X3 = c(1, 1, 1), X4 = c(1, 1, 1)), .Names = c("X1", "X2", "X3", "X4"), row.names = c("a", "b", "c"), class = "data.frame") ) }) test_that("function options", { x <- data.frame(a = rep(letters[1:3], 8), b = rep(1:4, each=6), c = rep(1:12, times=2)) expect_equal( crosstab(a, b, c, data=x, type="sum"), structure(list(X1 = c(5, 7, 9), X2 = c(17, 19, 21), X3 = c(5, 7, 9), X4 = c(17, 19, 21)), .Names = c("X1", "X2", "X3", "X4"), row.names = c("a", "b", "c"), class = "data.frame") ) expect_equal( crosstab(a, b, c, data=x, type="min"), structure(list(X1 = c(1, 2, 3), X2 = c(7, 8, 9), X3 = c(1, 2, 3), X4 = c(7, 8, 9)), .Names = c("X1", "X2", "X3", "X4"), row.names = c("a", "b", "c"), class = "data.frame") ) expect_equal( crosstab(a, b, c, data=x, type="max"), structure(list(X1 = c(4, 5, 6), X2 = c(10, 11, 12), X3 = c(4, 5, 6), X4 = c(10, 11, 12)), .Names = c("X1", "X2", "X3", "X4"), row.names = c("a", "b", "c"), class = "data.frame") ) expect_equal( crosstab(a, b, c, data=x, type="mean"), structure(list(X1 = c(2.5, 3.5, 4.5), X2 = c(8.5, 9.5, 10.5), X3 = c(2.5, 3.5, 4.5), X4 = c(8.5, 9.5, 10.5)), .Names = c("X1", "X2", "X3", "X4"), row.names = c("a", "b", "c"), class = "data.frame") ) expect_equal( crosstab(a, b, c, data=x, type="count"), structure(list(X1 = c(2, 2, 2), X2 = c(2, 2, 2), X3 = c(2, 2, 2), X4 = c(2, 2, 2)), .Names = c("X1", "X2", "X3", "X4"), row.names = c("a", "b", "c"), class = "data.frame") ) }) ecodist/tests/testthat/test-mantel.R0000644000176200001440000000041414452055674017301 0ustar liggesuserscontext("mantel") test_that("mantel r is the correlation", { set.seed(888) x <- runif(110) y <- runif(110) x <- dist(x) y <- dist(y) expect_equal(as.vector(mantel(y ~ x, nperm=0, nboot=0))[1], cor(x, y)) }) ecodist/tests/testthat/test-mgroup.R0000644000176200001440000000137114452055674017335 0ustar liggesuserscontext("mgroup") test_that("Mantel r is correct", { set.seed(888) x <- runif(110) groups.char <- sample(letters[1:5], size=length(x), replace=TRUE) x.d <- dist(x) groups.factor <- factor(groups.char) groups.numeric <- as.numeric(groups.factor) groups.d <- dist(groups.numeric) groups.d[groups.d > 0] <- 1 expect_equal(as.vector(mantel(x.d ~ groups.d, nperm=0, nboot=0))[1], mgroup(x.d, groups.char, nperm=0)[1, 2]) expect_equal(as.vector(mantel(x.d ~ groups.d, nperm=0, nboot=0))[1], mgroup(x.d, groups.factor, nperm=0)[1, 2]) expect_equal(as.vector(mantel(x.d ~ groups.d, nperm=0, nboot=0))[1], mgroup(x.d, groups.numeric, nperm=0)[1, 2]) }) ecodist/tests/testthat/test-MRM.R0000644000176200001440000000043214452055674016454 0ustar liggesuserscontext("MRM") test_that("MRM coefficients match lm", { set.seed(888) y <- runif(11175) x1 <- runif(11175) x2 <- runif(11175) expect_equal(as.vector(MRM(y ~ x1 + x2, nperm=0)$coef[,1]), as.vector(coefficients(lm(y ~ x1 + x2)))) }) ecodist/tests/testthat/test-distance.R0000644000176200001440000000146414452055674017621 0ustar liggesuserscontext("distance") test_that("Euclidean distance is correct", { set.seed(888) x <- matrix(runif(50), ncol=5) d.ecodist <- distance(x, "euclidean") d.base <- dist(x) expect_equal(attributes(d.ecodist), attributes(d.base)[names(attributes(d.base)) != "call"]) expect_equal(as.vector(d.ecodist), as.vector(d.base)) }) test_that("Bray-Curtis distance is correct", { set.seed(888) x <- matrix(runif(50), ncol=5) expect_equal(distance(x, "bray"), bcdist(x)) }) test_that("Mahalanobis icov is correct", { set.seed(888) x <- matrix(runif(50), ncol=5) x.md <- full(distance(x, "mahal")) sub.md <- full(distance(x[1:5, ], "mahal", icov=cov(x))) expect_equal(x.md[1:5, 1:5], sub.md) }) ecodist/tests/testthat.R0000644000176200001440000000005014452055674015040 0ustar liggesuserslibrary(testthat) test_check("ecodist") ecodist/src/0000755000176200001440000000000014517736751012513 5ustar liggesusersecodist/src/ecodist.c0000644000176200001440000004550214452055674014313 0ustar liggesusers#define USE_FC_LEN_T #include #include #ifndef FCONE # define FCONE #endif #include #include #include /* for dgemm */ #define RANDIN GetRNGstate() #define RANDOUT PutRNGstate() #define UNIF unif_rand() void bootstrap(double *x, double *y, int *n, int *xlen, int *nboot, double *pboot, double *bootcor, int *rarray, int *rmat, double *xdif, double *ydif) { int i, j, k, l; double r; double nsamp; double xmean, ymean; double xsum; double xxsum, yysum; /* Set random seed using Splus function */ RANDIN; for(i = 0; i < *nboot; i++) { /* Set up rarray. */ for(j = 0; j < *n; j++) { r = UNIF; if(r > *pboot) rarray[j] = 0; else rarray[j] = 1; } /* Turn rarray into a lower-triangular sampling matrix. */ /* 1 means include, 0 means omit. */ l = 0; for(j = 1; j < *n; j++) { for(k = 0; k < j; k++) { if(rarray[j] == 0 || rarray[k] == 0) rmat[l] = 0; else rmat[l] = 1; l++; } } nsamp = 0; for(j = 0; j < *xlen; j++) { nsamp += rmat[j]; } /* Calculate means for x and y. */ xmean = 0; ymean = 0; for(j = 0; j < *xlen; j++) { if(rmat[j] == 1) { xmean += x[j]; ymean += y[j]; } } xmean = xmean/nsamp; ymean = ymean/nsamp; /* Calculate deviations for x and y. */ for(j = 0; j < *xlen; j++) { if(rmat[j] == 1) { xdif[j] = x[j] - xmean; ydif[j] = y[j] - ymean; } else { xdif[j] = 0; ydif[j] = 0; } } xsum = 0; xxsum = 0; yysum = 0; for(j = 0; j < *xlen; j++) { if(rmat[j] == 1) { xsum += (xdif[j] * ydif[j]); xxsum += (xdif[j] * xdif[j]); yysum += (ydif[j] * ydif[j]); } } bootcor[i] = (xsum) / sqrt(xxsum * yysum); } /* Reset random seed using an Splus function. */ RANDOUT; } void permute(double *x, double *y, int *n, int *xlen, int *nperm, double *zstats, double *tmat, int *rarray) { int i, k, l, m; double cumsum; int temp; /* Set random seed using Splus function */ RANDIN; /* Calculate first z-statistic (unpermuted data). */ cumsum = 0; for(k = 0; k < *xlen; k++) { cumsum += x[k] * y[k]; } zstats[0] = cumsum / *xlen; /* Start permutation routine */ for(i = 1; i < *nperm; i++) { /* Set up rarray. */ for(k = 0; k < *n; k++) { rarray[k] = k; } /* Convert x to a full matrix. */ m = 0; for(k = 1; k < *n; k++) { for(l = 0; l < k; l++) { tmat[k * *n + l] = x[m]; tmat[l * *n + k] = x[m]; m++; } } /* Randomize rarray using an Splus function. */ for(k = 0; k < (*n - 1); k++) { l = *n - k - 1; m = (int)((float)l * UNIF); if(m > l) m = l; temp = rarray[l]; rarray[l] = rarray[m]; rarray[m] = temp; } /* Reorder x and take lower triangle. */ m = 0; for(k = 1; k < *n; k++) { for(l = 0; l < k; l++) { x[m] = tmat[rarray[k] * *n + rarray[l]]; m++; } } /* Calculate new sum of products. */ cumsum = 0; for(k = 0; k < *xlen; k++) { cumsum += x[k] * y[k]; } zstats[i] = cumsum / *xlen; } /* Reset random seed using an Splus function. */ RANDOUT; } void permpart(double *hmat, double *bmat, double *omat, double *y, double *xcor, double *ycor, int *n, int *ncol, int *xlen, int *nperm, double *zstats, double *tmat, int *rarray) { int i, k, l, m; double cumsum; double bsum; double w1, w2; int temp; /* Set random seed using Splus function */ RANDIN; /* Calculate first z-statistic (unpermuted data). */ cumsum = 0; for(k = 0; k < *xlen; k++) { cumsum += xcor[k] * ycor[k]; } zstats[0] = cumsum / *xlen; /* Start permutation routine */ for(i = 1; i < *nperm; i++) { /* Set up rarray. */ for(k = 0; k < *n; k++) { rarray[k] = k; } /* Convert y to a full matrix. */ m = 0; for(k = 1; k < *n; k++) { for(l = 0; l < k; l++) { tmat[k * *n + l] = y[m]; tmat[l * *n + k] = y[m]; m++; } } /* Randomize rarray using an Splus function. */ for(k = 0; k < (*n - 1); k++) { l = *n - k - 1; m = (int)((float)l * UNIF); if(m > l) m = l; temp = rarray[l]; rarray[l] = rarray[m]; rarray[m] = temp; } /* Reorder y and take lower triangle. */ m = 0; for(k = 1; k < *n; k++) { for(l = 0; l < k; l++) { y[m] = tmat[rarray[k] * *n + rarray[l]]; m++; } } /* Calculate residuals for y */ /* Calculate bmat */ for(k = 0; k < *ncol; k++) { bmat[k] = 0; } for(k = 0; k < *ncol; k++) { for(l = 0; l < *xlen; l++) { bmat[k] = bmat[k] + hmat[l * *ncol + k] * y[l]; } } /* Calculate ycor (residuals) */ for(k = 0; k < *xlen; k++) { ycor[k] = 0; } for(k = 0; k < *xlen; k++) { bsum = 0; for(l = 0; l < *ncol; l++) { bsum = bsum + bmat[l] * omat[l * *xlen + k]; } ycor[k] = y[k] - bsum; } /* Standardize residuals so z = r */ w1 = 0; w2 = 0; for(k = 0; k < *xlen; k++) { w1 = w1 + ycor[k]; w2 = w2 + ycor[k] * ycor[k]; } w1 = w1 / *xlen; w2 = sqrt(w2 / *xlen - w1 * w1); for(k = 0; k < *xlen; k++) { ycor[k] = (ycor[k] - w1) / w2; } /* Calculate new sum of products. */ cumsum = 0; for(k = 0; k < *xlen; k++) { cumsum += xcor[k] * ycor[k]; } zstats[i] = cumsum / *xlen; } /* Reset random seed using an Splus function. */ RANDOUT; } void bcdistc(double *x, int *pnrow, int *pncol, double *dist) { int i, j, k, l; int nrow, ncol; double sumi, sumj; double minsum; l = 0; nrow = *pnrow; ncol = *pncol; for(i = 0; i < (nrow - 1); i++) { for(j = (i + 1); j < (nrow); j++) { minsum = 0; sumi = 0; sumj = 0; for(k = 0; k < ncol; k++) { if(x[i * ncol + k] < x[j * ncol + k]) minsum += x[i * ncol + k]; else minsum += x[j * ncol + k]; sumi += x[i * ncol + k]; sumj += x[j * ncol + k]; } if((sumi + sumj) == 0) dist[l] = 0; else dist[l] = (1 - (2 * minsum) / (sumi + sumj)); l++; } } } void newpermone(double *x, int *dclass, int *n, int *xlen, int *nperm, double *zstats, double *tmat, int *rarray) { int i, k, l, m; double cumsum; int temp; /* Set random seed using Splus function */ RANDIN; /* Calculate first z-statistic (unpermuted data). */ cumsum = 0; for(k = 0; k < *xlen; k++) { if(dclass[k] == 0) { cumsum += x[k]; } } zstats[0] = cumsum; /* Start permutation routine */ for(i = 1; i < *nperm; i++) { /* Set up rarray. */ for(k = 0; k < *n; k++) { rarray[k] = k; } /* Convert x to a full matrix. */ m = 0; for(k = 1; k < *n; k++) { for(l = 0; l < k; l++) { tmat[k * *n + l] = x[m]; tmat[l * *n + k] = x[m]; m++; } } /* Randomize rarray using an Splus function. */ for(k = 0; k < (*n - 1); k++) { l = *n - k - 1; m = (int)((float)l * UNIF); if(m > l) m = l; temp = rarray[l]; rarray[l] = rarray[m]; rarray[m] = temp; } /* Reorder x. */ m = 0; for(k = 1; k < *n; k++) { for(l = 0; l < k; l++) { x[m] = tmat[rarray[k] * *n + rarray[l]]; m++; } } /* Calculate new sum of products. */ cumsum = 0; for(k = 0; k < *xlen; k++) { if(dclass[k] == 0) { cumsum += x[k]; } } zstats[i] = cumsum; } /* Reset random seed using an Splus function. */ RANDOUT; } void newpermtwo(double *x, double *y, int *n, int *xlen, int *nperm, double *zstats, double *tmat, int *rarray) { int i, k, l, m; double cumsum; int temp; float naval = -9999; /* Set random seed using Splus function */ RANDIN; /* Calculate first z-statistic (unpermuted data). */ cumsum = 0; for(k = 0; k < *xlen; k++) { if(x[k] != naval) { cumsum += x[k] * y[k]; } } zstats[0] = cumsum; /* Start permutation routine */ for(i = 1; i < *nperm; i++) { /* Set up rarray. */ for(k = 0; k < *n; k++) { rarray[k] = k; } /* Convert x to a full matrix. */ m = 0; for(k = 1; k < *n; k++) { for(l = 0; l < k; l++) { tmat[k * *n + l] = x[m]; tmat[l * *n + k] = x[m]; m++; } } /* Randomize rarray using an Splus function. */ for(k = 0; k < (*n - 1); k++) { l = *n - k - 1; m = (int)((float)l * UNIF); if(m > l) m = l; temp = rarray[l]; rarray[l] = rarray[m]; rarray[m] = temp; } /* Reorder x. */ m = 0; for(k = 1; k < *n; k++) { for(l = 0; l < k; l++) { x[m] = tmat[rarray[k] * *n + rarray[l]]; m++; } } /* Calculate new sum of products. */ cumsum = 0; for(k = 0; k < *xlen; k++) { if(x[k] != naval) { cumsum += x[k] * y[k]; } } zstats[i] = cumsum; } /* Reset random seed using an Splus function. */ RANDOUT; } void psum(double *x, int *pnrow, int *pncol, double *dist) { int row1, row2, col1; int nrow, ncol; int l; double thisval, thatval; l = 0; nrow = *pnrow; ncol = *pncol; for(col1 = 0; col1 < ncol; col1++) { for(row1 = 0; row1 < nrow; row1++) { thatval = x[row1 * ncol + col1]; for(row2 = 0; row2 < nrow; row2++) { thisval = x[row2 * ncol + col1]; dist[l] = thisval + thatval; l++; } } } } void pdiff(double *x, int *pnrow, int *pncol, double *dist) { int row1, row2, col1; int nrow, ncol; int l; double thisval, thatval; l = 0; nrow = *pnrow; ncol = *pncol; for(col1 = 0; col1 < ncol; col1++) { for(row1 = 0; row1 < nrow; row1++) { thatval = x[row1 * ncol + col1]; for(row2 = 0; row2 < nrow; row2++) { thisval = x[row2 * ncol + col1]; dist[l] = thisval - thatval; l++; } } } } void jpres(double *x, int *pnrow, int *pncol, double *dist) { int row1, row2, col1; int nrow, ncol; int l; double thisval, thatval; l = 0; nrow = *pnrow; ncol = *pncol; for(col1 = 0; col1 < ncol; col1++) { for(row1 = 0; row1 < nrow; row1++) { thatval = x[row1 * ncol + col1]; for(row2 = 0; row2 < nrow; row2++) { thisval = x[row2 * ncol + col1]; if((thisval > 0) & (thatval > 0)) { dist[l] = 1; } else { dist[l] = 0; } l++; } } } } void jabs(double *x, int *pnrow, int *pncol, double *dist) { int row1, row2, col1; int nrow, ncol; int l; double thisval, thatval; l = 0; nrow = *pnrow; ncol = *pncol; for(col1 = 0; col1 < ncol; col1++) { for(row1 = 0; row1 < nrow; row1++) { thatval = x[row1 * ncol + col1]; for(row2 = 0; row2 < nrow; row2++) { thisval = x[row2 * ncol + col1]; if((thisval == 0) & (thatval == 0)) { dist[l] = 1; } else { dist[l] = 0; } l++; } } } } void jfirst(double *x, int *pnrow, int *pncol, double *dist) { int row1, row2, col1; int nrow, ncol; int l; double thisval, thatval; l = 0; nrow = *pnrow; ncol = *pncol; for(col1 = 0; col1 < ncol; col1++) { for(row1 = 0; row1 < nrow; row1++) { thatval = x[row1 * ncol + col1]; for(row2 = 0; row2 < nrow; row2++) { thisval = x[row2 * ncol + col1]; if((thisval > 0) & (thatval == 0)) { dist[l] = 1; } else { dist[l] = 0; } l++; } } } } void jsec(double *x, int *pnrow, int *pncol, double *dist) { int row1, row2, col1; int nrow, ncol; int l; double thisval, thatval; l = 0; nrow = *pnrow; ncol = *pncol; for(col1 = 0; col1 < ncol; col1++) { for(row1 = 0; row1 < nrow; row1++) { thatval = x[row1 * ncol + col1]; for(row2 = 0; row2 < nrow; row2++) { thisval = x[row2 * ncol + col1]; if((thisval == 0) & (thatval > 0)) { dist[l] = 1; } else { dist[l] = 0; } l++; } } } } void mrmperm(double *x, double *y, int *p, int *nd, int *n, int *nperm, double *r2all, double *ball, double *fall, double *tmat, int *rarray, double *XX, double *XY, double *YY, double *b) { int i, k, l; int m; int temp; double SSE=0.0, SSTO=0.0, SSR=0.0; double r2=0, f=0; double btemp=0.0; int bcount = 0; char *transt = "T", *transn = "N"; double one = 1.0, zero = 0.0; int onei = 1; /* Set random seed using R function */ RANDIN; /* Start permutation routine */ for(i = 0; i < *nperm; i++) { /* first do the unpermuted values */ /* F77_CALL(dgemm)(transa, transb, &ncx, &ncy, &nrx, &one, x, &nrx, y, &nry, &zero, z, &ncx FCONE FCONE); */ /* take crossproduct t(X) %*% Y - WORKS */ F77_CALL(dgemm)(transt, transn, p, &onei, nd, &one, x, nd, y, nd, &zero, XY, p FCONE FCONE); /* take crossproduct t(Y) %*% (Y) - WORKS */ F77_CALL(dgemm)(transt, transn, &onei, &onei, nd, &one, y, nd, y, nd, &zero, YY, &onei FCONE FCONE); /* calculate regression coefficients XX %*% XY - WORKS */ F77_CALL(dgemm)(transn, transn, p, &onei, p, &one, XX, p, XY, p, &zero, b, p FCONE FCONE); /* calculate regression components - WORKS */ F77_CALL(dgemm)(transt, transn, &onei, &onei, p, &one, b, p, XY, p, &zero, &btemp, &onei FCONE FCONE); /* SSE - WORKS */ SSE = YY[0] - btemp; /* SSTO - WORKS */ SSTO = 0; for(k = 0; k < *nd; k++) { SSTO = SSTO + y[k]; } SSTO = YY[0] - (SSTO * SSTO) / *nd; SSR = SSTO - SSE; /* calculate R2 - WORKS */ r2 = 1 - SSE / SSTO; /* calculate F* - WORKS */ f = (SSR / (*p - 1)) / (SSE / (*nd - *p)); r2all[i] = r2; fall[i] = f; /* calculate pseudo-t for regression coefficients - WORKS*/ /* b / sqrt(1 - R2) */ for(k=0; k<*p; k++) { ball[bcount] = b[k] / sqrt(1 - r2); bcount++; } /* permute Y */ /* Set up rarray. */ for(k = 0; k < *n; k++) { rarray[k] = k; } /* Convert y to a full matrix. */ m = 0; for(k = 1; k < *n; k++) { for(l = 0; l < k; l++) { tmat[k * *n + l] = y[m]; tmat[l * *n + k] = y[m]; m++; } } /* Randomize rarray using an Splus function. */ for(k = 0; k < (*n - 1); k++) { l = *n - k - 1; m = (int)((float)l * UNIF); if(m > l) m = l; temp = rarray[l]; rarray[l] = rarray[m]; rarray[m] = temp; } /* Reorder y. */ m = 0; for(k = 1; k < *n; k++) { for(l = 0; l < k; l++) { y[m] = tmat[rarray[k] * *n + rarray[l]]; m++; } } } /* Reset random seed using an Splus function. */ RANDOUT; } void xpermute(double *x, double *y, int *nrow, int *ncol, int *xlen, int *nperm, double *zstats, double *newx, int *rarray, int *carray) { int i, k, l, m; double cumsum; int temp; int newk, newl; /* Set random seed using Splus function */ RANDIN; /* Calculate first z-statistic (unpermuted data). */ cumsum = 0; for(k = 0; k < *xlen; k++) { cumsum += x[k] * y[k]; } zstats[0] = cumsum; /* Start permutation routine */ for(i = 1; i < *nperm; i++) { cumsum = 0; /* Set up rarray. */ for(k = 0; k < *nrow; k++) { rarray[k] = k; } /* Set up carray. */ for(k = 0; k < *ncol; k++) { carray[k] = k; } /* Randomize rarray using an Splus function. */ for(k = 0; k < (*nrow - 1); k++) { l = *nrow - k - 1; m = (long)((float)l * UNIF); if(m > l) m = l; temp = rarray[l]; rarray[l] = rarray[m]; rarray[m] = temp; } /* Randomize carray using an Splus function. */ for(k = 0; k < (*ncol - 1); k++) { l = *ncol - k - 1; m = (long)((float)l * UNIF); if(m > l) m = l; temp = carray[l]; carray[l] = carray[m]; carray[m] = temp; } /* Reorder x. */ /* loop thru the rows * swapping each value with its replacement */ for(k = 0; k < *nrow; k++) { } for(l = 0; l < *nrow; l++) { newl = rarray[l]; if(newl != l) { for(k = 0; k < *ncol; k++) { newx[k*(*nrow) + l] = x[k*(*nrow) + newl]; } } } /* now x has the original info and newx has swapped rows */ /* go thru x and set x identical to newx before swapping columns */ for(k = 0; k < *ncol; k++) { for(l = 0; l < *nrow; l++) { x[k*(*nrow) + l] = newx[k*(*nrow) + l]; } } /* loop thru the columns * swapping each value with its replacement */ for(k = 0; k < *ncol; k++) { } for(k = 0; k < *ncol; k++) { newk = carray[k]; if(newk != k) { for(l = 0; l < *nrow; l++) { newx[k*(*nrow) + l] = x[newk*(*nrow) + l]; } } } /* Calculate new sum of products. */ cumsum = 0; for(k = 0; k < *xlen; k++) { cumsum += x[k] * y[k]; } zstats[i] = cumsum; } /* Reset random seed using an Splus function. */ RANDOUT; } void xpermpart(double *hmat, double *y, double *xcor, double *ycor, int *nrow, int *ncol, int *xlen, int *nperm, double *zstats, double *newy, int *rarray, int *carray) { int i, k, l, m; double cumsum; int temp; int newk, newl; /* Set random seed using Splus function */ RANDIN; /* Calculate residuals for y */ for(k = 0; k < *xlen; k++) { ycor[k] = 0; } for(k = 0; k < *xlen; k++) { for(l = 0; l < *xlen; l++) { ycor[k] = ycor[k] + hmat[k * *xlen + l] * y[l]; } } /* Calculate first z-statistic (unpermuted data). */ cumsum = 0; for(k = 0; k < *xlen; k++) { cumsum += xcor[k] * ycor[k]; } zstats[0] = cumsum; /* Start permutation routine */ for(i = 1; i < *nperm; i++) { /* Set up rarray. */ for(k = 0; k < *nrow; k++) { rarray[k] = k; } /* Set up carray. */ for(k = 0; k < *ncol; k++) { carray[k] = k; } /* Randomize rarray using an Splus function. */ for(k = 0; k < (*nrow - 1); k++) { l = *nrow - k - 1; m = (long)((float)l * UNIF); if(m > l) m = l; temp = rarray[l]; rarray[l] = rarray[m]; rarray[m] = temp; } /* Randomize carray using an Splus function. */ for(k = 0; k < (*ncol - 1); k++) { l = *ncol - k - 1; m = (long)((float)l * UNIF); if(m > l) m = l; temp = carray[l]; carray[l] = carray[m]; carray[m] = temp; } /* Reorder y. */ /* loop thru the rows * swapping each value with its replacement */ for(k = 0; k < *nrow; k++) { } for(l = 0; l < *nrow; l++) { newl = rarray[l]; if(newl != l) { for(k = 0; k < *ncol; k++) { newy[k*(*nrow) + l] = y[k*(*nrow) + newl]; } } } /* now y has the original info and newy has swapped rows */ /* go thru y and set y identical to newy before swapping columns */ for(k = 0; k < *ncol; k++) { for(l = 0; l < *nrow; l++) { y[k*(*nrow) + l] = newy[k*(*nrow) + l]; } } /* loop thru the columns * swapping each value with its replacement */ for(k = 0; k < *ncol; k++) { } for(k = 0; k < *ncol; k++) { newk = carray[k]; if(newk != k) { for(l = 0; l < *nrow; l++) { newy[k*(*nrow) + l] = y[newk*(*nrow) + l]; } } } /* Calculate residuals for y */ for(k = 0; k < *xlen; k++) { ycor[k] = 0; } for(k = 0; k < *xlen; k++) { for(l = 0; l < *xlen; l++) { ycor[k] = ycor[k] + hmat[k * *xlen + l] * y[l]; } } /* Calculate new sum of products. */ cumsum = 0; for(k = 0; k < *xlen; k++) { cumsum += xcor[k] * ycor[k]; } zstats[i] = cumsum; } /* Reset random seed using an Splus function. */ RANDOUT; } ecodist/src/init.c0000644000176200001440000000422414452055674013620 0ustar liggesusers#include // for NULL #include /* .C calls */ extern void bcdistc(void *, void *, void *, void *); extern void bootstrap(void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void jabs(void *, void *, void *, void *); extern void jfirst(void *, void *, void *, void *); extern void jpres(void *, void *, void *, void *); extern void jsec(void *, void *, void *, void *); extern void mrmperm(void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void newpermone(void *, void *, void *, void *, void *, void *, void *, void *); extern void newpermtwo(void *, void *, void *, void *, void *, void *, void *, void *); extern void pdiff(void *, void *, void *, void *); extern void permpart(void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void permute(void *, void *, void *, void *, void *, void *, void *, void *); extern void psum(void *, void *, void *, void *); extern void xpermute(void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void xpermpart(void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); static const R_CMethodDef CEntries[] = { {"bcdistc", (DL_FUNC) &bcdistc, 4}, {"bootstrap", (DL_FUNC) &bootstrap, 11}, {"jabs", (DL_FUNC) &jabs, 4}, {"jfirst", (DL_FUNC) &jfirst, 4}, {"jpres", (DL_FUNC) &jpres, 4}, {"jsec", (DL_FUNC) &jsec, 4}, {"mrmperm", (DL_FUNC) &mrmperm, 15}, {"newpermone", (DL_FUNC) &newpermone, 8}, {"newpermtwo", (DL_FUNC) &newpermtwo, 8}, {"pdiff", (DL_FUNC) &pdiff, 4}, {"permpart", (DL_FUNC) &permpart, 13}, {"permute", (DL_FUNC) &permute, 8}, {"psum", (DL_FUNC) &psum, 4}, {"xpermute", (DL_FUNC) &xpermute, 10}, {"xpermpart", (DL_FUNC) &xpermpart, 12}, {NULL, NULL, 0} }; void R_init_ecodist(DllInfo *dll) { R_registerRoutines(dll, CEntries, NULL, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } ecodist/src/Makevars0000644000176200001440000000004014452055674014175 0ustar liggesusersPKG_LIBS=$(BLAS_LIBS) $(FLIBS) ecodist/vignettes/0000755000176200001440000000000014517736751013734 5ustar liggesusersecodist/vignettes/dissimilarity.Rmd0000644000176200001440000000643714456245464017276 0ustar liggesusers--- title: "Dissimilarity Cheat Sheet" author: "Sarah Goslee" date: "2017-07-12" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Dissimilarity Cheat Sheet} %\VignetteEngine{knitr::rmarkdown} --- **Things to do with dissimilarity matrices** _(ecodist functions are marked in **bold**)_ _(untested ideas marked with ?)_ Description | Notation | Name | R function ------------|----------|------|----------- Relationship between two matrices | D1 ~ D2 | Mantel test | **mantel**(D1 ~ D2) Relationship between two matrices given more | D1 ~ D2 | D3 ... Dn | Partial Mantel test | **mantel**(D1 ~ D2 + D3 + ...) ||| Spatial structure in one matrix relative to all distance classes | D1 x S | Mantel correlogram | **mgram**(D1, S) Spatial structure in one matrix given more relative to all distance classes | D1 | D2 ... Dn x S | Partial Mantel correlogram | **?mgram**(residuals(lm(D1 ~ D2 + ...)), space) Spatial structuce in one matrix by distance class | D1 x S | Piecewise multivariate correlogram | **pmgram**(D1, S) Spatial structure in one matrix by distance class given more | D1 | D2 ... Dn x S | Piecewise partial multivariate correlogram | **pmgram**(D1, S, D2) ||| Spatial structure in the relationship between two matrices | D1 ~ D2 x S | Piecewise Mantel cross-correlogram | **pmgram**(cbind(lower(D1), lower(D2)), S) Spatial structure in the relationship between two matrices given more | D1 ~ D2 | D3 ... Dn x S | Piecewise partial Mantel cross-correlogram | **pmgram**(cbind(lower(D1), lower(D2)), S, D3) ||| Ordination of one matrix | | (N)MDS | **nmds**(y) or **pco**(y) Ordination of one matrix given more | | (Partial (N)MDS | **?nmds**(residuals(lm(y ~ z1 + ...))) ||| Grouping of items based on one matrix | | Cluster analysis | eg hclust(y) Grouping of items based on one matrix given more | | Partial cluster analysis | ?hclust(residuals(lm(y ~ z1 + ...))) Grouping of items given space | | Spatially-constrained cluster analysis | NA ||| Multiple regression | D1 ~ D2 | D3 ... Dn | Multiple regression on distance matrices | **MRM**(D1 ~ D2 + D3 + ...) **Ways to calculate dissimilarity matrices** Description | Result | R function ------------|--------|----------- From a site by sample matrix | Symmetric matrix with zero diagonals | dist(x) or **bcdist**(x) or **distance**(x) ----------------------------- **Things to do with cross-dissimilarity matrices** Description | Notation | Name | R function ------------|----------|------|----------- Relationship between two cross-dissimilarity matrices | D12 ~ D34 | Cross-Mantel test | **xmantel**(D12 ~ D34) Relationship between two cross-dissimilarity matrices given more | D12 ~ D34 | D56 ... Dn | Partial cross-Mantel test | **xmantel**(D12 ~ D34 + D56 + ...) ||| Spatial structure in one cross-dissimilarity matrix | D12 x S | Cross-Mantel correlogram | **xmgram**(D12, spaceX) Spatial structure in one cross-dissimilarity matrix given more | D12 | D34 ... Dn x S | Partial cross-Mantel correlogram | **?xmgram**(residuals(lm(D12 ~ D34 + ...)), spaceX) **Ways to calculate cross-dissimilarity matrices** Source | Result | R function -------|--------|----------- From 2 site by sample matrixes for the same sites and samples (e.g. different years) | nonsymmetric matrix with nonzero diagonals | **xdistance**(x, y) ecodist/R/0000755000176200001440000000000014500724315012106 5ustar liggesusersecodist/R/cor2m.R0000644000176200001440000000105114452055674013263 0ustar liggesusers# Correlate variables from 1 matrix with variables from another # matrix. If TRIM, set rho dmax] <- 1 ngroup <- length(space.dclass) - sum(space.dclass) answer.m[i,2] <- ngroup if(ngroup > 0) { mant <- mantel(species.d ~ space.dclass, nperm=nperm, mrank=mrank, nboot=nboot, pboot=pboot, cboot=cboot) answer.m[i,3] <- mant[1] if(alternative == "two.sided") answer.m[i,4] <- mant[4] else answer.m[i,4] <- mant[2] answer.m[i,5] <- mant[5] answer.m[i,6] <- mant[6] } if(trace) cat(i, "\t", answer.m[i,2], "\t", answer.m[i, 3], "\n") } results <- list(mgram = answer.m, resids = NA) class(results) <- "mgram" results } ecodist/R/corgen.R0000644000176200001440000000540014452055674013520 0ustar liggesuserscorgen <- function (len, x, r, population = FALSE, epsilon = 0) { # remember the sign of the correlation for later rsign <- sign(r) if (rsign == 0) rsign <- 1 r <- abs(r) # need to either specify x-data or the desired vector length if (missing(x)) { if (missing(len)) { stop("Must specify x or len.\n") } else { # if x wasn't given, sample it from a normal distribution x.rand <- TRUE x <- scale(rnorm(len)) x.orig <- x } } else { # can either draw from a population or simulate an exact # correlation (within epsilon), but not both if (population == TRUE) { # if x is given, population is set to FALSE warning("If x is specified population is ignored.\n") population <- FALSE } x.rand <- FALSE len <- length(x) x.orig <- x x <- scale(x) } if (epsilon != 0) { if (population == TRUE) { warning("If epsilon is specified population is ignored.\n") population <- FALSE } } ## Here's where the real work starts # First, draw y from a normal distribution y <- scale(rnorm(len)) if (!population & x.rand) { # if exact correlations are desired, use princomp to # create uncorrelated data # UNLESS x is given - princomp would trash the # specified x values xy <- princomp(cbind(x, y))$scores x <- xy[, 1] x.orig <- x y <- xy[, 2] } # create a new y based on x and the desired correlation a <- r/sqrt(1 - r^2) y <- x * a + y if (epsilon > 0) { itcounter <- 0 # check to see if cor(x, y) meets the given tolerances # this is kludgy, but works while (abs(cor(x, y) - r) > epsilon) { # sometimes takes too long or doesn't converge # with given starting point if(itcounter > 1000) { if(x.rand) { x <- scale(rnorm(len)) x.orig <- x itcounter <- 0 } else { # hopefully never get here stop("Doesn't converge.\n") } } itcounter <- itcounter + 1 # if not within epsilon, generate a new y y <- scale(rnorm(len)) if (!population & x.rand) { xy <- princomp(cbind(x, y))$scores x <- xy[, 1] x.orig <- x y <- xy[, 2] } a <- r/sqrt(1 - r^2) y <- x * a + y } } # return x and y with the correct sign of r restored list(x = x.orig, y = y * rsign) } ecodist/R/mantel.R0000644000176200001440000002103014452055674013520 0ustar liggesusersmantel <- function(formula = formula(data), data, nperm = 1000, mrank = FALSE, nboot = 500, pboot = 0.9, cboot = 0.95) { # Mantel test # Written by Sarah C. Goslee # 27 June 2000 # Updated 5 April 2001 # # formula is y ~ x + n1 + n2 + n3 + ... # NOT y ~ x | n1 + n2 + n3 + ... # The | means something else in S-Plus formulas. # # Uses C for permutation and bootstrap routines. # # This version calculates partial coefficients by permuting the y matrix. # # Will calculate the simple correlation or n-th order partial correlation # between two distance matrices in either of two ways: Pearson (mrank=FALSE) # or Spearman (mrank=TRUE) # # A permutation test is used to calculate the significance of r. # The permutation test was designed to be relatively fast, but because of the # way this was done, there is a possibility of repeating permutations of # 1/n! where the distance matrix is n by n. In particular, for small matrices # n < 8 or so, it may be better to enumerate the permutations. # # # As an added bonus, this function offers the option of calculating # bootstrapped confidence limits for the correlation coefficient. # nboot is the number of iterations. # pboot is the level to resample at. # cboot is the desired confidence limit. # NOTE: This is not bootstrapping with replacement. That doesn't make # much sense for dissimilarities because of the possibility of duplicates. # The dissimilarity between a sample and itself is always zero. # # mantel returns a five-element list: # mantelr is the correlation. # pval1 is the one-sided p-value (null hypothesis r <= 0) (0 if nperm == 0). # pval2 is the one-sided p-value (null hypothesis r >= 0) (0 if nperm == 0). # pval3 is the two-sided p-value (null hypothesis r = 0) (0 if nperm == 0). # llim is the lower confidence limit. # ulim is the upper confidence limit. # # requires mantel.c (Included in ecodist.c.) # # Stuff R needs to be able to use a formula m <- match.call(expand.dots = FALSE) m2 <- match(c("formula", "data"), names(m), nomatch=0) m <- m[c(1, m2)] m[[1]] <- as.name("model.frame") m <- eval(m, parent.frame()) m <- as.matrix(m) # End of R stuff. m is now the data for the Mantel test as # columns y, x, n1, n2, n3, ... # Determine the size of the matrices & do some error checking. n <- (1 + sqrt(1 + 8 * nrow(m)))/2 if(abs(n - round(n)) > 0.0000001) stop("Matrix not square.\n") n <- round(n) if(ncol(m) < 2) stop("Not enough data. \n") # If there are only x and y, then use the data as is. if(dim(m)[[2]] == 2) { ymat <- as.vector(m[, 1]) xmat <- as.vector(m[, 2]) if(mrank) { ymat <- rank(ymat) xmat <- rank(xmat) } ycor <- ymat xcor <- xmat } else { ymat <- as.vector(m[, 1]) omat <- m[, -1] if(mrank) { ymat <- rank(ymat) omat <- apply(omat, 2, rank) } omat <- cbind(rep(1, length(ymat)), omat) xmat <- as.vector(omat[, 2]) omat <- omat[, -2] omat <- as.matrix(omat) ycor <- lm.fit(omat, ymat)$residuals xcor <- lm.fit(omat, xmat)$residuals } mantelr <- cor(xcor, ycor) # Convert matrices to column order for compatibility with C routines. xmat <- full(xmat) ymat <- full(ymat) xmat <- xmat[col(xmat) > row(xmat)] ymat <- ymat[col(ymat) > row(ymat)] if(dim(m)[[2]] > 2) { for(i in 2:dim(omat)[[2]]) { curcoll <- omat[, i] curcoll <- full(curcoll) curcoll <- curcoll[col(curcoll) > row(curcoll)] omat[, i] <- curcoll } } # If using a permutation test, start here: if(nperm > 0) { # Set up the arrays needed. zstats <- numeric(nperm) tmat <- matrix(0, n, n) rarray <- rep(0, n) if(dim(m)[[2]] == 2) { # Standardize the columns of the matrices so # that z = r and we can do 2-tailed tests. ncor <- length(xmat) w1 <- sum(xmat)/ncor w2 <- sum(xmat^2) w2 <- sqrt(w2/ncor - w1^2) xmat <- (xmat - w1)/w2 w1 <- sum(ymat)/ncor w2 <- sum(ymat^2) w2 <- sqrt(w2/ncor - w1^2) ymat <- (ymat - w1)/w2 cresults <- .C("permute", as.double(xmat), as.double(ymat), as.integer(n), as.integer(length(xmat)), as.integer(nperm), zstats = as.double(zstats), as.double(as.vector(tmat)), as.integer(rarray), PACKAGE = "ecodist") } else { tomat <- t(omat) hmat <- solve(tomat %*% omat) hmat <- hmat %*% tomat bmat <- rep(0, ncol(omat)) xcor <- as.vector(lm.fit(omat, xmat)$residuals) ycor <- as.vector(lm.fit(omat, ymat)$residuals) # Standardize the columns of the matrices so # that z = r and we can do 2-tailed tests. ncor <- length(xcor) w1 <- sum(xcor)/ncor w2 <- sum(xcor^2) w2 <- sqrt(w2/ncor - w1^2) xcor <- (xcor - w1)/w2 w1 <- sum(ycor)/ncor w2 <- sum(ycor^2) w2 <- sqrt(w2/ncor - w1^2) ycor <- (ycor - w1)/w2 cresults <- .C("permpart", as.double(as.vector(hmat)), bmat = as.double(bmat), as.double(as.vector(omat)), as.double(ymat), as.double(xcor), ycor = as.double(ycor), as.integer(n), as.integer(length(bmat)), as.integer(length(xmat)), as.integer(nperm), zstats = as.double(zstats), as.double(as.vector(tmat)), as.integer(rarray), PACKAGE = "ecodist") } zstats <- cresults$zstats # Calculate the p-values. pval1 <- length(zstats[zstats >= zstats[1]])/nperm pval2 <- length(zstats[zstats <= zstats[1]])/nperm pval3 <- length(zstats[abs(zstats) >= abs(zstats[1])])/nperm } else { pval1 <- 0 pval2 <- 0 pval3 <- 0 } # If not using a permutation test, return 0 for the p-values. if(nboot > 0) { if(dim(m)[[2]] == 2) { ycor <- ymat xcor <- xmat } else { xcor <- as.vector(lm.fit(omat, xmat)$residuals) ycor <- as.vector(lm.fit(omat, ymat)$residuals) } bootcor <- numeric(nboot) rarray <- numeric(n) rmat <- numeric(length(xcor)) xdif <- numeric(length(xcor)) ydif <- numeric(length(xcor)) cresults <- .C("bootstrap", as.double(xcor), as.double(ycor), as.integer(n), as.integer(length(xcor)), as.integer(nboot), as.double(pboot), bootcor = as.double(bootcor), as.integer(rarray), as.integer(rmat), as.double(xdif), as.double(ydif), PACKAGE = "ecodist") bootcor <- cresults$bootcor bootcor <- sort(bootcor) pval <- (1 - cboot)/2 llim <- quantile(bootcor, pval) ulim <- quantile(bootcor, 1 - pval) } else { llim <- 0 ulim <- 0 } c(mantelr = mantelr, pval1 = pval1, pval2 = pval2, pval3 = pval3, llim = llim, ulim = ulim) } ecodist/R/nmds.R0000644000176200001440000000704714452055674013215 0ustar liggesusers# Non-metric multidimensional scaling function # using the majorization algorithm from # Borg & Groenen 1997, Modern Multidimensional Scaling. # # Sarah Goslee # 20 December 1999 # # dmat is a lower-triangular distance matrix. # mindim is the minimum number of dimensions to calculate. # maxdim is the maximum number of dimensions to calculate. # nits is the number of repetitions. # iconf is the initial configuration to use. # If iconf is not specified, then a random configuration is used. # epsilon and maxit specify stopping points. # Returns a list of configurations (conf) # and a vector of final stress values (stress), # along with the cumulative and incremental r^2 for each axis. # The first nits elements are for the lowest number of dimensions. # mindim, maxdim, nits are saved as part of the returned list # # stresscalc has been updated 2016-12-27 to be compatible with vegan::metaMDS # and MASS::isoMDS. # The method of finding the optimum is unchanged. sstress <- function(dmat, newconf) { # Calculates the stress-1 function for the original and # new NMDS configurations (Kruskal 1964). # Calculate stress based on isotonic regression # of distance matrices # uses stats::isoreg instead of MASS::Shepard dmat <- as.vector(dmat) dord <- order(dmat) cmat <- as.vector(dist(newconf, "minkowski", 2)) dmat <- dmat[dord] cmat <- cmat[dord] ir <- isoreg(dmat, cmat) dmat <- ir$y cmat <- ir$yf sstresscalc <- (dmat - cmat) ^ 2 sstresscalc <- sum(sstresscalc) / sum(dmat ^ 2) sqrt(sstresscalc) } nmdscalc <- function(dmat, ndim, iconf, epsilon, maxit, trace) { # This is the optimization routine for NMDS ordination. # Use front-end nmds. # not exported n <- (1 + sqrt(1 + 8 * length(dmat))) / 2 if(missing(iconf)) { iconf <- matrix(runif(n * ndim), nrow = n, ncol = ndim) } k <- 0 conf <- iconf stress2 <- sstress(dmat, iconf) stress1 <- stress2 + 1 + epsilon while(k < maxit && abs(stress1 - stress2) > epsilon) { stress1 <- stress2 dmat.full <- full(dmat) confd.full <- full(dist(conf)) confd2.full <- confd.full confd2.full[confd.full == 0] <- 1 b <- dmat.full / confd2.full b[confd.full == 0] <- 0 bsum <- apply(b, 2, sum) b <- -1 * b diag(b) <- bsum conf <- (1 / n) * b %*% conf stress2 <- sstress(dmat, conf) if(trace) cat(k, ",\t", stress1, "\n") k <- k + 1 } list(conf = conf, stress = stress1) } nmds <- function(dmat, mindim = 1, maxdim = 2, nits = 10, iconf, epsilon = 1e-12, maxit = 500, trace=FALSE) { conf <- list(1:((maxdim - mindim + 1) * nits)) stress <- list(1:((maxdim - mindim + 1) * nits)) r2 <- list(1:((maxdim - mindim + 1) * nits)) k <- 1 for(i in mindim:maxdim) { if(trace) cat("Number of dimensions: ", i, "\n") for(j in seq_len(nits)) { if(trace) cat("Iteration number: ", j, "\n") if(!missing(iconf) && ncol(iconf) == i) { nmdsr <- nmdscalc(dmat, ndim = i, iconf=iconf, epsilon=epsilon, maxit=maxit, trace=trace) } else { nmdsr <- nmdscalc(dmat, ndim = i, epsilon=epsilon, maxit=maxit, trace=trace) } conf[[k]] <- nmdsr$conf stress[[k]] <- nmdsr$stress r2[[k]] <- cor(dmat, dist(nmdsr$conf)) ^ 2 k <- k + 1 } } results <- list(conf = conf, stress = unlist(stress), r2 = unlist(r2), mindim=mindim, maxdim=maxdim, nits=nits) class(results) <- "nmds" results } ecodist/R/xdistance.R0000644000176200001440000000207314473442316014224 0ustar liggesusersxdistance <- function(x, y, method = "euclidean") { # calculate cross-dissimilarities between # rows of x and rows of y # returns a nonsymmetric matrix where # d[a, b] is the dissimilarity between # x[a, ] and y[b, ] # Sarah Goslee 2017-02-17, modified from legacy Splus code dated 01/01/01 if(method == "difference") { stop("xdistance only works with symmetric indices.\n") } if(is.null(ncol(x))) { x <- matrix(x, ncol=1) rownames(x) <- seq_len(nrow(x)) } if(is.null(ncol(y))) { y <- matrix(y, ncol=1) rownames(y) <- seq_len(nrow(y)) } if(!(ncol(x) == ncol(y))) stop("Matrices must have the same number of columns\n") x.names <- paste0("x", row.names(x)) y.names <- paste0("y", row.names(y)) x <- as.matrix(x) y <- as.matrix(y) d <- rbind(x, y) d <- full(distance(d, method=method)) d <- d[seq(1, nrow(x)), seq(nrow(x) + 1, nrow(x) + nrow(y)), drop=FALSE] rownames(d) <- x.names colnames(d) <- y.names class(d) <- "xdist" d } ecodist/R/lower.R0000644000176200001440000000040414452055674013372 0ustar liggesuserslower <- function(m) { # Takes the lower triangle of a matrix # Does NOT check for symmetric matrix m <- as.matrix(m) if(ncol(m) != nrow(m)) stop("Matrix not square.") if(ncol(m) == 1) { warning("Matrix is 1x1.") m } else m[col(m) < row(m)] } ecodist/R/fixdmat.R0000644000176200001440000000037214452055674013702 0ustar liggesusersfixdmat <- function(v) { # Converts a row-wise distance vector to a full distance matrix. n <- (1 + sqrt(1 + 8 * length(v)))/2 dist.m <- matrix(0, n, n) dist.m[row(dist.m) < col(dist.m)] <- v dist.m <- dist.m + t(dist.m) dist.m } ecodist/R/full.R0000644000176200001440000000054614452055674013213 0ustar liggesusersfull <- function(v) { # converts a lower-triangular distance vector to a symmetric matrix n <- (1 + sqrt(1 + 8 * length(v)))/2 if(abs(n - round(n)) > 0.0000001) stop("Matrix not square.") n <- round(n) full <- matrix(0, n, n) full[lower.tri(full)] <- v full2 <- t(full) diag(full2) <- 0 full + full2 } ecodist/R/pmgram.R0000644000176200001440000002443614473460564013541 0ustar liggesuserspmgram <- function(data, space, partial, breaks, nclass, stepsize, equiprobable = FALSE, resids = FALSE, nperm = 1000) # Piecewise Mantel correlogram # # results are: # 1 dmax # 2 ngroup # 3 piecewise mgram # 4 two-sided p-value # use breaks if it exists. # If nclass or stepsize aren't specified, use Sturge's rule to calculate nclass # classes are shifted so that they don't have to start with zero # 2023-08-29 added equiprobable option for distance classes of equal number # rather than equal width { epsilon <- 0.0000001 if(inherits(data, "dist")) { data <- as.matrix(as.vector(data)) } else { data <- as.matrix(data) } space <- as.vector(space) n <- ncol(full(space)) # 2023-08-18: changed from using round to ceiling in Sturges' rule # calculation for compatibility with nclass.Sturges if(missing(breaks)) { if(missing(nclass)) { if(missing(stepsize)) { nclass <- ceiling(1 + log2(length(space))) stepsize <- (max(space) - min(space)) / nclass } else { nclass <- round((max(space) - min(space))/stepsize) } } else { if(missing(stepsize)) { stepsize <- (max(space) - min(space)) / nclass } } if(equiprobable) { breaks <- quantile(space, seq(0, 1, length.out = nclass + 1)) } else { # equal width breaks breaks <- seq(0, stepsize * nclass, stepsize) } } else { nclass <- length(breaks) - 1 } answer.m <- matrix(NA, nrow=nclass, ncol=4) dimnames(answer.m) <- list(NULL, c("lag", "ngroup", "pieceR", "pval")) answer.m[,4] <- rep(NA, nrow(answer.m)) # standardize so mean = 0, variance = 1 for(i in seq_len(ncol(data))) { thiscol <- data[,i] ydif <- thiscol - mean(thiscol) yvar <- sqrt(sum(ydif^2)/length(ydif)) thiscol <- ydif / yvar data[,i] <- thiscol } if(!missing(partial)) { partial <- as.matrix(as.vector(partial)) for(i in seq_len(ncol(partial))) { thiscol <- partial[,i] ydif <- thiscol - mean(thiscol) yvar <- sqrt(sum(ydif^2)/length(ydif)) thiscol <- ydif / yvar partial[,i] <- thiscol } } if(resids) { mgresids <- rep(0, length(space)) } else { mgresids <- NA } if(missing(partial)) { if(ncol(data) == 1) { colnames(answer.m)[3] <- "wtI" for(i in seq_len(nclass)) { dmin <- breaks[i] dmax <- breaks[i + 1] answer.m[i,1] <- (dmin + dmax) / 2 space.dclass <- rep(0, length(space)) space.dclass[space <= dmin] <- 1 space.dclass[space > dmax] <- 1 if(sum(space.dclass== 0) > 0) { ngroup <- length(space.dclass) - sum(space.dclass) answer.m[i,2] <- ngroup answer.m[i,3] <- (-1/ngroup) * sum(data[space.dclass == 0]) # similar to Moran's I if(resids == TRUE) { mgresids[space.dclass == 0] <- residuals(lm(data[space.dclass == 0] ~ space[space.dclass == 0])) } if(nperm > 0) { zstats <- rep(0, nperm) tmat <- matrix(0, n, n) rarray <- rep(0, n) # cat(i, "\t", answer.m[i,1], "\t", answer.m[i,2], "\t", answer.m[i,3], "\n") cresults <- .C("newpermone", as.double(data), as.integer(space.dclass), as.integer(n), as.integer(length(data)), as.integer(nperm), zstats = as.double(zstats), as.double(as.vector(tmat)), as.integer(rarray), PACKAGE = "ecodist") zstats <- cresults$zstats answer.m[i,4] <- length(zstats[abs(zstats) >= abs(zstats[1])])/nperm } } } } else { for(i in seq_len(nclass)) { dmin <- breaks[i] dmax <- breaks[i + 1] answer.m[i,1] <- dmax space.dclass <- rep(0, length(space)) space.dclass[space <= dmin] <- 1 space.dclass[space > dmax] <- 1 if(sum(space.dclass== 0) > 0) { ngroup <- length(space.dclass) - sum(space.dclass) answer.m[i,2] <- ngroup if(ncol(data) == 2) { answer.m[i, 3] <- cor(data[space.dclass == 0, 1], data[space.dclass == 0, 2]) if(resids == TRUE) { mgresids[space.dclass == 0] <- residuals(lm(data[space.dclass == 0,1] ~ data[space.dclass == 0,2])) } if(nperm > 0) { if(is.na(answer.m[i, 3])) answer.m[i, 4] <- 1 else { zstats <- rep(0, nperm) tmat <- matrix(0, n, n) rarray <- rep(0, n) xmat <- data[,1] xmat[space.dclass == 1] <- -9999 # cat(i, "\t", answer.m[i,1], "\t", answer.m[i,2], "\t", answer.m[i,3], "\n") cresults <- .C("newpermtwo", as.double(xmat), as.double(data[,2]), as.integer(n), as.integer(length(xmat)), as.integer(nperm), zstats = as.double(zstats), as.double(as.vector(tmat)), as.integer(rarray), PACKAGE = "ecodist") zstats <- cresults$zstats answer.m[i,4] <- length(zstats[abs(zstats) >= abs(zstats[1])])/nperm } } } } } } } else { if(ncol(data) == 1) { colnames(answer.m)[3] <- "wtI" for(i in seq_len(nclass)) { dmin <- breaks[i] dmax <- breaks[i + 1] answer.m[i,1] <- dmax space.dclass <- rep(0, length(space)) space.dclass[space <= dmin] <- 1 space.dclass[space > dmax] <- 1 ngroup <- sum(space.dclass== 0) answer.m[i,2] <- ngroup if(ngroup > 0) { ngroup <- sum(space.dclass== 0) data.lm <- residuals(lm(data ~ partial)) answer.m[i,3] <- (-1/ngroup) * sum(data.lm[space.dclass == 0]) # similar to Moran's I if(resids == TRUE) { mgresids[space.dclass == 0] <- residuals(lm(data[space.dclass == 0] ~ partial[space.dclass == 0])) } if(nperm > 0) { zstats <- rep(0, nperm) zstats[1] <- answer.m[i,3] for(j in 2:nperm) { xmat <- full(data) xsamp <- sample(ncol(xmat)) xmat <- xmat[xsamp, xsamp] xmat <- lower(xmat) data.lm <- residuals(lm(xmat ~ partial)) zstats[j] <- (-1/ngroup) * sum(data.lm[space.dclass == 0]) } answer.m[i,4] <- length(zstats[abs(zstats) >= abs(zstats[1])])/nperm } } } } else { for(i in seq_len(nclass)) { dmin <- breaks[i] dmax <- breaks[i + 1] answer.m[i,1] <- (dmin + dmax) / 2 space.dclass <- rep(0, length(space)) space.dclass[space <= dmin] <- 1 space.dclass[space > dmax] <- 1 if(sum(space.dclass== 0) > 0) { ngroup <- length(space.dclass) - sum(space.dclass) answer.m[i,2] <- ngroup if(ncol(data) == 2) { data1.lm <- residuals(lm(data[space.dclass == 0,1] ~ partial[space.dclass == 0,])) data2.lm <- residuals(lm(data[space.dclass == 0,2] ~ partial[space.dclass == 0,])) answer.m[i, 3] <- cor(data1.lm, data2.lm) if(resids == TRUE) { mgresids[space.dclass == 0] <- residuals(lm(data1.lm ~ data2.lm)) } if(nperm > 0) { if(is.na(answer.m[i, 3])) answer.m[i, 4] <- 1 else { zstats <- rep(0, nperm) zstats[1] <- answer.m[i,3] for(j in 2:nperm) { xmat <- data[,1] xmat[space.dclass == 1] <- -9999 xmat <- full(xmat) xsamp <- sample(ncol(xmat)) xmat <- xmat[xsamp, xsamp] xmat <- lower(xmat) xmat <- xmat[xmat != -9999] data1.lm <- residuals(lm(xmat ~ partial[space.dclass == 0,])) zstats[j] <- cor(data1.lm, data2.lm) } answer.m[i,4] <- length(zstats[abs(zstats) >= abs(zstats[1])])/nperm } } } } } } } results <- list(mgram = data.frame(answer.m), resids = mgresids) class(results) <- "mgram" results } ecodist/R/bcdist.R0000644000176200001440000000210014452055674013505 0ustar liggesusersbcdist <- function(x, rmzero = FALSE) { # Calculates Bray-Curtis distance (1 - percent similarity) for the # rows of a matrix. # # If rmzero = TRUE, all empty rows of the matrix will be removed before calculating # distances. Otherwise the distance between empty rows will be set to 0. # # Sarah C. Goslee, November 1997 # # The same functionality appears in distance(), but bcdist is substantially faster. x <- as.matrix(x) if(rmzero == TRUE) { xsum <- apply(x, 1, sum) x <- x[xsum > 0, ] } dist.v <- rep(0, (nrow(x) * (nrow(x) - 1))/2) cresults <- .C("bcdistc", as.double(as.vector(t(x))), as.integer(nrow(x)), as.integer(ncol(x)), dist.v = as.double(dist.v), PACKAGE = "ecodist") dist.v <- cresults$dist.v ## give the results attributes similar to dist() attr(dist.v, "Size") <- nrow(x) attr(dist.v, "Labels") <- rownames(x) attr(dist.v, "Diag") <- FALSE attr(dist.v, "Upper") <- FALSE attr(dist.v, "method") <- "bray-curtis" class(dist.v) <- "dist" dist.v } ecodist/R/plot.mgram.R0000644000176200001440000000143414474135161014320 0ustar liggesusersplot.mgram <- function(x, pval = 0.05, xlab = "Distance", ylab = NULL, ...) { # x is the output from mgram # pval is the p-value to be considered signficant # ... are additional graphics parameters x <- x$mgram if(is.null(ylab)) { if(colnames(x)[3] == "wtI") ylab <- "Piecewise autocorrelation (I)" if(colnames(x)[3] == "mantelr") ylab <- "Mantel autocorrelation (r)" } pval.v <- x[, 4] pval.v[is.na(pval.v)] <- 1 plot(x[, 1], x[, 3], type = "l", xlab = xlab, ylab = ylab, ...) points(x[pval.v <= pval, 1], x[pval.v <= pval, 3], pch = 16, cex=2) points(x[pval.v > pval, 1], x[pval.v > pval, 3], pch = 1, cex=2) abline(h=0, lty=2, col="gray") invisible() } ecodist/R/MRM.R0000644000176200001440000001233414452055674012702 0ustar liggesusersMRM <- function(formula = formula(data), data, nperm = 1000, method="linear", mrank = FALSE) { # MRM: Multiple Regression on distance Matrices # Sarah Goslee 2008-07-18 # tests R^2 and regression coefficients using a # permutation test # added method argument # linear is the default, standard option # logistic adds capability to do logistic regression # - this will be much slower # mrank is ignored if method is not "linear" # Stuff R needs to be able to use a formula m <- match.call(expand.dots = FALSE) m2 <- match(c("formula", "data"), names(m), nomatch=0) m <- m[c(1, m2)] m[[1]] <- as.name("model.frame") m <- eval(m, parent.frame()) m <- as.matrix(m) # End of R stuff. m is now the data for the MRM test as # columns y, x, n1, n2, n3, ... # Determine the size of the matrices & do some error checking. n <- (1 + sqrt(1 + 8 * nrow(m)))/2 if(abs(n - round(n)) > 0.0000001) stop("Matrix not square.\n") n <- round(n) if(ncol(m) < 2) stop("Not enough data. \n") if(method == "linear") { if(mrank) { m <- apply(m, 2, rank) } # convert matrices to column order to ensure compatibility with C for(thiscol in seq_len(ncol(m))) { tempmat <- full(m[,thiscol]) m[,thiscol] <- tempmat[col(tempmat) > row(tempmat)] } # use matrix form to speed up calculations X <- m[ ,2:ncol(m), drop=FALSE] X <- cbind(rep(1, nrow(X)), X) Y <- m[ ,1, drop=FALSE] nd <- nrow(X) # only need to calculate (X'X)^-1 once XX <- crossprod(X) XX <- solve(XX) # will need to calculate Xy for each permutation XY <- crossprod(X, Y) YY <- crossprod(Y) # regression coefficients b <- XX %*% XY rownames(b) <- c("Int", colnames(X)[2:ncol(X)]) bXY <- crossprod(b, XY) SSE <- YY - bXY SSTO <- YY - sum(Y)^2/nd SSR = SSTO - SSE # R2 = 1 - SSE/SSTO R2 <- 1 - SSE/SSTO R2 <- as.vector(R2) # F* = MSR / MSE # MSR = SSR / (p - 1) # MSE = SSE / (n - p) p <- ncol(X) # number of parameters estimated F <- (SSR / (p - 1)) / (SSE / (nd - p)) R2.pval <- NA b.pval <- rep(NA, ncol(X)) F.pval <- NA if(nperm > 0) { R2.all <- numeric(nperm) # for regression coefficients, use pseudo-t of Legendre et al. 1994 b.all <- numeric(nperm*p) # try out an overall F-test for lack of fit F.all <- numeric(nperm) cresults <- .C("mrmperm", as.double(as.vector(X)), as.double(as.vector(Y)), as.integer(p), as.integer(nd), as.integer(n), as.integer(nperm), R2.all = as.double(R2.all), b.all = as.double(b.all), F.all = as.double(F.all), as.double(numeric(n*n)), as.integer(numeric(n)), as.double(as.vector(XX)), as.double(numeric(p)), as.double(0), as.double(numeric(p)), PACKAGE = "ecodist") R2.all <- cresults$R2.all R2.pval <- length(R2.all[R2.all >= R2.all[1]])/nperm F.all <- cresults$F.all F.pval <- length(F.all[F.all >= F.all[1]])/nperm # b.all contains pseudo-t of Legendre et al. 1994 b.all <- matrix(cresults$b.all, nrow=nperm, ncol=p, byrow=TRUE) b.pval <- apply(b.all, 2, function(x)length(x[abs(x) >= abs(x[1])])/nperm) } results <- list(coef=cbind(b, pval=b.pval), r.squared=c(R2=R2, pval = R2.pval),F.test=c(F=F, F.pval = F.pval)) } else { if(method == "logistic") { # extract data from formula object X <- m[ ,2:ncol(m), drop=FALSE] Y <- m[ ,1, drop=FALSE] colnames(Y) <- "Y" newdata <- data.frame(Y=Y, X) fit1 <- glm(Y ~ ., data=newdata, family=binomial(link = "logit")) # want to save coefficients, deviance & df b <- coefficients(fit1) dev <- summary(fit1)$deviance dev.df <- summary(fit1)$df.residual b.pval <- NA dev.pval <- NA if(nperm > 0) { b.all <- matrix(NA, nrow=nperm, ncol=length(b)) b.all[1,] <- b dev.all <- rep(NA, nperm) dev.all[1] <- dev for(i in 2:nperm) { newSample <- sample(n) newY <- full(Y) newY <- newY[newSample, newSample] newY <- lower(newY) newdata <- data.frame(Y=newY, X=X) newfit <- glm(Y ~ ., data=newdata, family=binomial(link = "logit")) b.all[i,] <- coefficients(newfit) dev.all[i] <- summary(newfit)$deviance } b.pval <- apply(b.all, 2, function(x) length(x[abs(x) >= abs(x[1])])/nperm) dev.pval <- length(dev.all[dev.all >= dev.all[1]])/nperm } results <- list(coef = cbind(b, pval = b.pval), dev = c(resid.dev = dev, resid.df = dev.df, dev.pval = dev.pval)) } else { stop("method must be 'linear' or 'logistic'\n") } } results } ecodist/R/distance.R0000644000176200001440000002140614457512321014031 0ustar liggesusersdistance <- function(x, method="euclidean", sprange=NULL, spweight=NULL, icov, inverted = FALSE) { # calculates similarity and dissimilarity coefficients # as described in Legendre and Legendre 1998 # returns lower-triangle ### # Sarah Goslee # 2 March 2006 # revised 31 March 2008 # bug-fix 15 December 2008 # improved mahalanobis 10 March 2022 ### # uses clever matrix math to calculate the pieces needed # by dissimilarity matrices, to make it easy to add new # indices. ### # to add a new metric: # add it to the commented list below # add it to the end of the METHODS <- c(...) list # add the code at the appropriate point at the bottom of # the function ### # Gower offers the option of dividing by the species range # if sprange=NULL no range is used # Euclidean, Manhattan, Gower allow weighting options # if spweight=NULL no weighting is used # if spweight="absence" then W is = 0 if both species are absent, # and 1 otherwise, thus deleting joint absences ### Available methods # 1: euclidean # 2: bray-curtis # 3: manhattan # 4: mahalanobis # 5: jaccard # 6: simple difference: not symmetric # 7: sorensen # 8: Gower # 9: Modified Gower base 10 (Anderson et al 2006) # 10: Modified Gower base 2 (Anderson et al 2006) ### Mahalanobis distance requires covariance matrix of full dataset, # making it impossible to calculate in chunks for a very large dataset. # Now can specify covariance matrix separately, to enable this. # argument icov. If missing, will be calculated from data as in previous version. # if inverted = FALSE, icov is inverted before calculating # providing an inverted covariance matrix may speed up calculations pairedsum <- function(x) { ### paired sums ### returns an N by N by P matrix containing each ### combination of N <- nrow(x) P <- ncol(x) A <- numeric(N * N * P) A <- .C("psum", as.double(as.vector(t(x))), as.integer(N), as.integer(P), A = as.double(A), PACKAGE = "ecodist")$A A <- array(A, dim=c(N, N, P)) A } paireddiff <- function(x) { ### paired differences N <- nrow(x) P <- ncol(x) A <- numeric(N * N * P) A <- .C("pdiff", as.double(as.vector(t(x))), as.integer(N), as.integer(P), A = as.double(A), PACKAGE = "ecodist")$A A <- array(A, dim=c(N, N, P)) A } jointpresence <- function(x) { ### joint count of presences N <- nrow(x) P <- ncol(x) A <- numeric(N * N * P) A <- .C("jpres", as.double(as.vector(t(x))), as.integer(N), as.integer(P), A = as.double(A), PACKAGE = "ecodist")$A A <- array(A, dim=c(N, N, P)) A } jointabsence <- function(x) { ### joint count of absences N <- nrow(x) P <- ncol(x) A <- numeric(N * N * P) A <- .C("jabs", as.double(as.vector(t(x))), as.integer(N), as.integer(P), A = as.double(A), PACKAGE = "ecodist")$A A <- array(A, dim=c(N, N, P)) A } firstonly <- function(x) { ### present only in first sample N <- nrow(x) P <- ncol(x) A <- numeric(N * N * P) A <- .C("jfirst", as.double(as.vector(t(x))), as.integer(N), as.integer(P), A = as.double(A), PACKAGE = "ecodist")$A A <- array(A, dim=c(N, N, P)) A } secondonly <- function(x) { ### present only in second sample N <- nrow(x) P <- ncol(x) A <- numeric(N * N * P) A <- .C("jsec", as.double(as.vector(t(x))), as.integer(N), as.integer(P), A = as.double(A), PACKAGE = "ecodist")$A A <- array(A, dim=c(N, N, P)) A } x <- as.matrix(x) isSymmetric <- TRUE # indicates what form of results to return ## code borrowed from dist() METHODS <- c("euclidean", "bray-curtis", "manhattan", "mahalanobis", "jaccard", "difference", "sorensen", "gower", "modgower10", "modgower2") method <- pmatch(method, METHODS) if (is.na(method)) stop("invalid distance method") if (method == -1) stop("ambiguous distance method") N <- nrow(x) P <- ncol(x) if(method == 1) { # Euclidean distance A <- paireddiff(x) if(is.null(spweight)) { D <- sqrt(apply(A, 1:2, function(x)sum(x * x))) } else if(spweight[1] == "absence") { W <- ifelse(jointabsence(x)==1, 0, 1) D <- sqrt(apply((W^2)*A, 1:2, function(x)sum(x * x))) / apply(W, 1:2, sum) } else if(length(spweight) == ncol(x)) { W <- array(rep(spweight, each=nrow(x)^2), dim=c(nrow(x), nrow(x), ncol(x))) D <- sqrt(apply((W^2)*A, 1:2, function(x)sum(x * x))) / apply(W, 1:2, sum) } else { stop("Unknown weighting method.\n") } } if(method == 2) { # Bray-Curtis distance A <- paireddiff(x) A <- apply(A, 1:2, function(x)sum(abs(x))) B <- pairedsum(x) B <- apply(B, 1:2, sum) D <- A / B } if(method == 3) { # unstandardized manhattan distance A <- paireddiff(x) if(is.null(spweight)) { D <- apply(A, 1:2, function(x)sum(abs(x))) } else if(spweight[1] == "absence") { W <- ifelse(jointabsence(x)==1, 0, 1) D <- apply(W*A, 1:2, function(x)sum(abs(x))) / apply(W, 1:2, sum) } else if(length(spweight) == ncol(x)) { W <- array(rep(spweight, each=nrow(x)^2), dim=c(nrow(x), nrow(x), ncol(x))) D <- apply(W*A, 1:2, function(x)sum(abs(x))) / apply(W, 1:2, sum) } else { stop("Unknown weighting method.\n") } } if(method == 4) { # pairwise squared Mahalanobis distance if(missing(icov)) { icov <- solve(cov(x)) } else { if(!inverted) { icov <- solve(icov) } } A <- paireddiff(x) D <- apply(A, 1:2, function(x)sum(x %*% icov * x)) } if(method == 5) { # Jaccard distance A <- jointpresence(x) A <- apply(A, 1:2, sum) B <- firstonly(x) B <- apply(B, 1:2, sum) C <- secondonly(x) C <- apply(C, 1:2, sum) D <- 1 - A / (A + B + C) } if(method == 6) { # simple difference, NOT symmetric isSymmetric <- FALSE D <- paireddiff(x)[, , 1, drop=TRUE] } if(method == 7) { # Sorensen distance A <- jointpresence(x) A <- apply(A, 1:2, sum) B <- firstonly(x) B <- apply(B, 1:2, sum) C <- secondonly(x) C <- apply(C, 1:2, sum) D <- 1 - (2*A) / (2*A + B + C) } if(method == 8) { # Gower distance # weighting A <- paireddiff(x) if(!is.null(sprange)) { if(length(sprange) == ncol(x)) { sprange <- array(rep(sprange, each=nrow(x)^2), dim=c(nrow(x), nrow(x), ncol(x))) A <- A / sprange } else { stop("sprange not recognized.\n") } } if(is.null(spweight)) { D <- apply(A, 1:2, function(x)sum(abs(x))) } else if(spweight[1] == "absence") { W <- ifelse(jointabsence(x)==1, 0, 1) D <- apply(A*W, 1:2, function(x)sum(abs(x))) / apply(W, 1:2, sum) } else if(length(spweight) == ncol(x)) { W <- array(rep(spweight, each=nrow(x)^2), dim=c(nrow(x), nrow(x), ncol(x))) D <- apply(W*A, 1:2, function(x)sum(abs(x))) / apply(W, 1:2, sum) } else { stop("Unknown weighting method.\n") } } if(method == 9) { # modified Gower, base 10 x <- ifelse(x == 0, 0, log10(x)) A <- paireddiff(x) if(is.null(spweight)) { D <- apply(A, 1:2, function(x)sum(abs(x))) } else if(spweight[1] == "absence") { W <- ifelse(jointabsence(x)==1, 0, 1) D <- apply(W*A, 1:2, function(x)sum(abs(x))) / apply(W, 1:2, sum) } else if(length(spweight) == ncol(x)) { W <- array(rep(spweight, each=nrow(x)^2), dim=c(nrow(x), nrow(x), ncol(x))) D <- apply(W*A, 1:2, function(x)sum(abs(x))) / apply(W, 1:2, sum) } else { stop("Unknown weighting method.\n") } } if(method == 10) { # modified Gower, base 2 x <- ifelse(x == 0, 0, log2(x)) A <- paireddiff(x) if(is.null(spweight)) { D <- apply(A, 1:2, function(x)sum(abs(x))) } else if(spweight[1] == "absence") { W <- ifelse(jointabsence(x)==1, 0, 1) D <- apply(W*A, 1:2, function(x)sum(abs(x))) / apply(W, 1:2, sum) } else if(length(spweight) == ncol(x)) { W <- array(rep(spweight, each=nrow(x)^2), dim=c(nrow(x), nrow(x), ncol(x))) D <- apply(W*A, 1:2, function(x)sum(abs(x))) / apply(W, 1:2, sum) } else { stop("Unknown weighting method.\n") } } if(isSymmetric) { ## Make the results lower triangular D <- D[col(D) < row(D)] ## give the results attributes similar to dist() attr(D, "Size") <- N attr(D, "Labels") <- rownames(x) attr(D, "Diag") <- FALSE attr(D, "Upper") <- FALSE attr(D, "method") <- METHODS[method] class(D) <- "dist" } D } ecodist/R/pathdist.R0000644000176200001440000000203714500724304014051 0ustar liggesuserspathdist <- function(v, maxv = 1) { # v is a lower-triangular distance matrix # maxv is the cutoff for distances: values greater or equal to this will be estimated # from the shortest path along the distance-weighted graph connecting the samples # note that this will not work with completely disconnected subsets n <- (1 + sqrt(1 + 8 * length(v)))/2 if (abs(n - round(n)) > 1e-07) stop("Matrix not square.") n <- round(n) ### v.ind <- data.frame(v1 = lower(row(full(v))), v2 = lower(col(full(v)))) v.ind$d <- v v.ind <- v.ind[v.ind$d < maxv, ] v.graph <- add_edges(make_empty_graph(n, directed = FALSE), edges = t(v.ind[, 1:2]), weight = v.ind$d) v.dist <- distances(v.graph) v.dist <- lower(v.dist) ## give the result appropriate attributes based on the original object attributes(v.dist) <- attributes(v) if(!is.null(attr(v.dist, "method"))) { attr(v.dist, "method") <- paste(attr(v.dist, "method"), "mst", sep="-") } else { attr(v.dist, "method") <- "mst" } v.dist } ecodist/R/xmgram.R0000644000176200001440000000576714473460624013554 0ustar liggesusersxmgram <- function(species.xd, space.xd, breaks, nclass, stepsize, equiprobable = FALSE, nperm = 1000, mrank = FALSE, alternative = "two.sided", trace = FALSE) # Cross-Mantel correlogram developed from mgram() # Sarah Goslee 2017-02-17 # # This function calculates a mantel correlogram for a full cross-distance (non-symmetric # but square) based on the geographic distances given in space.d, also a full cross-distance # (nonsymmetric but square) distance matrix. # nclass: number of distance classes # stepsize: width of distance classes # nperm: number of permutations for mantel test # # Default is two-tailed test (H0: rM = 0; alternative = "two.sided") # May also use one-sided test (H0: rM <= 0; alternative = "one.sided") # 2023-08-29 added equiprobable option for distance classes of equal number # rather than equal width { dims <- dim(species.xd) space.xd <- as.vector(space.xd) # use breaks if it exists. # If nclass or stepsize aren't specified, use Sturges' rule to calculate nclass # classes are shifted so that they don't have to start with zero # 2023-08-18: changed from using round to ceiling in Sturges' rule # calculation for compatibility with nclass.Sturges if(missing(breaks)) { if(missing(nclass)) { if (missing(stepsize)) { nclass <- round(1 + log2(length(space.xd))) stepsize <- (max(space.xd) - min(space.xd))/nclass } else { nclass <- round((max(space.xd) - min(space.xd))/stepsize) } } else { if (missing(stepsize)) { stepsize <- (max(space.xd) - min(space.xd))/nclass } } if(equiprobable) { breaks <- quantile(space.xd, seq(0, 1, length.out = nclass + 1)) } else { # equal width breaks breaks <- seq(0, stepsize * nclass, stepsize) } } else { nclass <- length(breaks) - 1 } answer.m <- matrix(0, ncol=4, nrow=nclass) dimnames(answer.m) <- list(NULL, c("lag", "ngroup", "mantelr", "pval")) answer.m[,4] <- rep(1, nrow(answer.m)) for(i in seq_len(nclass)) { dmin <- breaks[i] dmax <- breaks[i + 1] answer.m[i,1] <- (dmin + dmax) / 2 space.dclass <- rep(0, length(space.xd)) space.dclass[space.xd <= dmin] <- 1 space.dclass[space.xd > dmax] <- 1 ngroup <- length(space.dclass) - sum(space.dclass) answer.m[i,2] <- ngroup if(ngroup > 0) { space.dclass <- matrix(space.dclass, nrow=dims[1], ncol=dims[2]) mant <- xmantel(species.xd ~ space.dclass, dims=dims, nperm=nperm, mrank=mrank) answer.m[i,3] <- mant[1] if(alternative == "two.sided") answer.m[i,4] <- mant[4] else answer.m[i,4] <- mant[2] } if(trace) cat(i, "\t", answer.m[i,2], "\t", answer.m[i, 3], "\n") } results <- list(mgram = answer.m, resids = NA) class(results) <- "mgram" results } ecodist/R/xmantel.R0000644000176200001440000001442614452055674013723 0ustar liggesusersxmantel <- function(formula = formula(data), data, dims = NA, nperm = 1000, mrank = FALSE) { # Cross-mantel test # Written by Sarah C. Goslee # 01/01/01 # Updated 6 April 2001 # added to ecodist 10 July 2017 # # formula is y ~ x + n1 + n2 + n3 + ... # NOT y ~ x | n1 + n2 + n3 + ... # The | means something else in S-Plus formulas. # # Uses C for permutation and bootstrap routines. # # Cross-mantel is a variation of the standard Mantel test that # takes nonsymmetric full matrices such as those returned by # xdist and xbcdist. # # This version calculates partial coefficients by permuting the y matrix. # # Will calculate the simple correlation or n-th order partial correlation # between two distance matrices in either of two ways: Pearson (mrank=F) # or Spearman (mrank=T) # # A permutation test is used to calculate the significance of r. # The permutation test was designed to be relatively fast, but because of the # way this was done, there is a possibility of repeating permutations of # 1/n! where the distance matrix is n by n. In particular, for small matrices # n < 8 or so, it may be better to enumerate the permutations. # # # As an added bonus, this function offers the option of calculating # bootstrapped confidence limits for the correlation coefficient. # nboot is the number of iterations. # pboot is the level to resample at. # cboot is the desired confidence limit. # # xmantel returns a five-element list: # mantelr is the correlation. # pval1 is the one-sided p-value (null hypothesis r <= 0) (0 if nperm == 0). # pval2 is the one-sided p-value (null hypothesis r >= 0) (0 if nperm == 0). # pval3 is the two-sided p-value (null hypothesis r = 0) (0 if nperm == 0). # llim is the lower confidence limit. # ulim is the upper confidence limit. # Stuff R needs to be able to use a formula m <- match.call(expand.dots = FALSE) m2 <- match(c("formula", "data"), names(m), nomatch=0) m <- m[c(1, m2)] m[[1]] <- as.name("model.frame") m <- eval(m, parent.frame()) m <- as.matrix(m) # m is now the data for the Mantel test as # cbinded matrices # Determine the size of the matrices & do some error checking. # if dims is NA, matrices are assumed to be square # otherwise dims must be specified nr <- nrow(m) if(is.na(dims[1])) { nc <- nr } else { if(nr != dims[1]) stop("dims doesn't match data \n") nc <- dims[2] } nmat <- ncol(m) / nc if(round(nmat) != nmat) stop("Matrices don't match dims. \n") if(nmat < 2) stop("Not enough data. \n") # If there are only x and y, then use the data as is. if(nmat == 2) { ymat <- m[,1:nc] xmat <- m[,(nc+1):ncol(m)] if(mrank) { ymat <- rank(ymat) xmat <- rank(xmat) } ycor <- as.vector(ymat) xcor <- as.vector(xmat) } else { # If this is a partial Mantel test, get the regression residuals # for y ~ n1 + n2 + n3 + ... and x ~ n1 + n2 + n3 + ... ymat <- as.vector(m[,1:nc]) omat <- vector(nmat - 1, mode="list") for(i in seq(1, nmat - 1)) { omat[[i]] <- as.vector(m[, seq(i * nc + 1, (i+1) * nc)]) } omat <- do.call("cbind", omat) if(mrank) { ymat <- rank(ymat) omat <- apply(omat, 2, rank) } omat <- cbind(rep(1, length(ymat)), omat) xmat <- as.vector(omat[, 2]) omat <- omat[, -2] omat <- as.matrix(omat) ycor <- lm.fit(omat, ymat)$residuals xcor <- lm.fit(omat, xmat)$residuals } # Calculate the Mantel r mantelr <- cor(xcor, ycor) # Standardize the columns of the matrices so # that z = r and we can do 2-tailed tests. ncor <- length(xmat) w1 <- sum(xmat) / ncor w2 <- sum(xmat ^ 2) w2 <- sqrt(w2 / ncor - w1 ^ 2) xmat <- (xmat - w1) / w2 w1 <- sum(ymat) / ncor w2 <- sum(ymat ^ 2) w2 <- sqrt(w2 / ncor - w1 ^ 2) ymat <- (ymat - w1) / w2 if(nmat > 2) { for(i in 2:dim(omat)[[2]]){ curcoll <- omat[,i] w1 <- sum(curcoll) / ncor w2 <- sum(curcoll ^ 2) w2 <- sqrt(w2 / ncor - w1 ^ 2) curcoll <- (curcoll - w1) / w2 omat[,i] <- curcoll } } # If using a permutation test, start here: if(nperm > 0) { # Set up the arrays needed. zstats <- numeric(nperm) rarray <- rep(0, nr) carray <- rep(0, nc) if(nmat == 2) { cresults <- .C("xpermute", as.double(xmat), as.double(ymat), as.integer(nr), as.integer(nc), as.integer(length(xmat)), as.integer(nperm), zstats = as.double(zstats), as.double(xmat), as.integer(rarray), as.integer(carray), PACKAGE = "ecodist") } else { hmat <- solve((t(omat) %*% omat)) hmat <- omat %*% hmat %*% t(omat) hmat <- diag(dim(hmat)[[1]]) - hmat xcor <- as.vector(lm.fit(omat, xmat)$residuals) ycor <- rep(0, length(xcor)) cresults <- .C("xpermpart", as.double(as.vector(hmat)), as.double(as.vector(ymat)), as.double(xcor), as.double(ycor), as.integer(nr), as.integer(nc), as.integer(length(xmat)), as.integer(nperm), zstats = as.double(zstats), as.double(as.vector(ymat)), as.integer(rarray), as.integer(carray), PACKAGE = "ecodist") } zstats <- cresults$zstats # Calculate the p-values. pval1 <- length(zstats[zstats >= zstats[1]])/nperm pval2 <- length(zstats[zstats <= zstats[1]])/nperm pval3 <- length(zstats[abs(zstats) >= abs(zstats[1])])/nperm } # If not using a permutation test, return 0 for the p-values. else { pval1 <- 0 pval2 <- 0 pval3 <- 0 } # Return the Mantel r and the p-value. unlist(list(mantelr = mantelr, pval1 = pval1, pval2 = pval2, pval3 = pval3)) } ecodist/R/relrange.R0000644000176200001440000000100414456257762014044 0ustar liggesusers# modified 2017-11-20 relrange <- function(x, globalmin=NA, globalmax=NA) { # relativize the range of each column to 0-1 # if globalmin, globalmax are provided, uses those, eg to # scale a subset to match a larger sample # otherwise uses population min and max if(is.na(globalmin[1])) globalmin <- apply(x, 2, min) if(is.na(globalmax[1])) globalmax <- apply(x, 2, max) globalmax <- globalmax - globalmin x <- sweep(x, 2, globalmin, "-") x <- sweep(x, 2, globalmax, "/") x } ecodist/R/plot.nmds.R0000644000176200001440000000326514452055674014170 0ustar liggesusersplot.nmds <- function(x, plot=TRUE, xlab="Dimensions", ...) { # dlu, modified by scg 2017-05 # plot NMDS scores by dimension dims <- seq(x$mindim, x$maxdim, by=1) # summarize and plot the nmds object x: stress x.stress <- data.frame(matrix(x$stress, nrow=length(dims), byrow=TRUE)) colnames(x.stress) <- paste0("iter", sprintf("%02d", seq_len(x$nits))) x.stress$ndim <- dims x.stress$min <- apply(x.stress[, seq_len(x$nits)], 1, min, na.rm=TRUE) x.stress$mean <- apply(x.stress[, seq_len(x$nits)], 1, mean, na.rm=TRUE) x.stress$max <- apply(x.stress[, seq_len(x$nits)], 1, max, na.rm=TRUE) # summarize and plot the nmds object x: r2 x.r2 <- data.frame(matrix(x$r2, nrow=length(dims), byrow=TRUE)) colnames(x.r2) <- paste0("iter", sprintf("%02d", seq_len(x$nits))) x.r2$ndim <- dims x.r2$min <- apply(x.r2[, seq_len(x$nits)], 1, min, na.rm=TRUE) x.r2$mean <- apply(x.r2[, seq_len(x$nits)], 1, mean, na.rm=TRUE) x.r2$max <- apply(x.r2[, seq_len(x$nits)], 1, max, na.rm=TRUE) if(plot) { par(mfrow=c(1,2)) plot(dims, x.stress$mean, ylim=c(0, max(x.stress$max)), type="b", pch=19, lwd=2, xlab=xlab, ylab="Stress", xaxt="n", ...) axis(1, at=dims, labels=sprintf("%d", dims)) lines(dims, x.stress$min, type="l", lty=2) lines(dims, x.stress$max, type="l", lty=2) plot(dims, x.r2$mean, ylim=c(0, 1), type="b", pch=19, lwd=2, xlab=xlab, ylab=expression(r^2), xaxt="n", ...) axis(1, at=dims, labels=sprintf("%d", dims)) lines(dims, x.r2$min, type="l", lty=2) lines(dims, x.r2$max, type="l", lty=2) } invisible(list(stress=x.stress, r2=x.r2)) } ecodist/R/plot.vf.R0000644000176200001440000000114514474173300013624 0ustar liggesusersplot.vf <- function (x, pval = NULL, r = NULL, cex = 0.8, ascale = 0.9, ...) { plotlim <- par()$usr plotlim <- min((plotlim[2] - plotlim[1]), (plotlim[4] - plotlim[3])) ascale <- ascale * (plotlim/2) if(!is.null(pval)) { x <- x[x[, 4] < pval, , drop=FALSE] } if(!is.null(r)) { x <- x[x[, 3] >= r, , drop=FALSE] } for (i in 1:dim(x)[[1]]) { arrows(0, 0, x[i, 1] * x[i, 3] * ascale, x[i, 2] * x[i, 3] * ascale, ...) } text(x[, 1] * x[, 3] * (ascale * 1.1), x[, 2] * x[, 3] * (ascale * 1.1), dimnames(x)[[1]], cex = cex, ...) } ecodist/R/pco.R0000644000176200001440000000313714500175332013015 0ustar liggesuserspco <- function(x, negvals = "zero", dround=0) { # Principal coordinates analysis (classical scaling) # Sarah Goslee # x is a lower-triangular dissimilarity matrix. # negvals: if "zero" then negative eigenvalues are set to zero. # if "rm" then correction method 1 from Legendre & Anderson 1999 # dround is an attempt to correct for round-off error. n <- (1 + sqrt(1 + 8 * length(x)))/2 if(abs(n - round(n)) > 0.0000001) stop("Matrix not square.\n") n <- round(n) xlabels <- labels(x) x <- full(x) # note cmdscale does this in two steps # so dmat does not match cmdscale()$x dmat <- -0.5 * x * x # Double-center the dissimilarity matrix # Subtract row and column means and add the grand mean. dr <- matrix(apply(dmat, 1, mean), nrow=n, ncol=n) dmat <- dmat - (dr + t(dr)) + mean(dmat) deigen <- eigen(dmat) if(negvals == "rm") { c1 <- min(deigen$values) if(c1 < 0) { c1 <- abs(c1) x2 <- sqrt(x^2 + 2 * c1) diag(x2) <- 0 dmat <- -0.5 * x2 * x2 dr <- matrix(apply(dmat, 1, mean), nrow=n, ncol=n) dmat <- dmat - (dr + t(dr)) + mean(dmat) deigen <- eigen(dmat) } } else { deigen$values[deigen$values < 0] <- 0 } if(dround > 0) { deigen$values <- round(deigen$values, dround) deigen$vectors <- round(deigen$vectors, dround) } eigenscale <- deigen$values eigenscale[eigenscale > 0.000000001] <- sqrt(eigenscale[eigenscale > 0.000000001]) deigen$vectors <- sweep(deigen$vectors, 2, eigenscale, "*") deigen$vectors <- data.frame(deigen$vectors) rownames(deigen$vectors) <- xlabels colnames(deigen$vectors) <- paste0("X", seq_len(ncol(deigen$vectors))) deigen } ecodist/R/rotate2d.R0000644000176200001440000000312414475713346013772 0ustar liggesusersrotate2d <- function(ord, x) { # rotates a two-dimensional ordination configuration to match a vector x # so that x is along the horizontal axis to the right # facilitates display # get theta from coordinates of x # assumes first two values of x are the first two coordinates # this is correct for vf() output # if ord is a vector, also takes the first two values # # returns a matrix with ncol = 2 regardless of ord input type # extract configuration from pco() ordination output # does NOT preserve original, just rotated coordinates if(any(names(ord) == "vectors")) { ord <- ord$vectors } # extract configuration from vf() output # DOES preserve original, so vf.plot can still be used isvf <- FALSE if(inherits(ord, "vf")) { vf.orig <- ord isvf <- TRUE } # works for a vector of length 2 or a two-dimensional configuration if(!is.null(dim(ord))) { ord <- as.matrix(ord[, 1:2, drop = FALSE]) } else { # assumes first two values of x are the coordinates, as from vf() ord <- matrix(ord[1:2], ncol = 2) } # assumes first two values of x are the coordinates, as from vf() if(is.null(dim(x))) { x <- x[1:2] } else { x <- as.matrix(x)[1, 1:2] } ### theta <- - atan2(x[2], x[1]) ord.rot <- data.frame(X1 = ord[, 1] * cos(theta) - ord[, 2] * sin(theta), X2 = ord[, 1] * sin(theta) + ord[, 2] * cos(theta)) if(isvf) { vf.orig[, 1:2] <- as.matrix(ord.rot) ord.rot <- vf.orig } ord.rot } ecodist/R/dim.dist.R0000644000176200001440000000041414452055674013756 0ustar liggesusersdim.dist <- function(x) { # temporary workaround because # the spdep package changes the defintion of dim.dist() to # a non-standard result, over-writing base R # This puts it back within ecodist, until spdep is fixed # not exported! NULL } ecodist/R/crosstab.R0000644000176200001440000000654414452055674014075 0ustar liggesuserscrosstab <- function(rowlab, collab, values, type="sum", data, allrows, allcols, na.as.0 = TRUE, check.names=TRUE, ...) { # Converts field data in the form: # site, species, observation # into a site by species table # # By default, takes the sum of the data # Can also use "mean", "max" or "min" # Sarah C. Goslee # 24 Sept 2003 # ### # # if allrows or allcols exists, will expand the matrix to # include all of those elements into the rows or colums of # the results matrix # scg 20 Apr 2006 # # added data argument to simplify using data frames # added count option to type (length of matching data) # scg 2 Nov 2012 # # fixed bug with expanding single-row or single-column values using allrows or allcols # scg 17 Feb 2017 # added na.as.0 argument; scg 18 Apr 2017 # added check.names and data frame return 21 Jun 2017 if(!missing(data)) { if(mode(substitute(rowlab)) == "name") rowlab <- data[, deparse(substitute(rowlab))] if(mode(substitute(collab)) == "name") collab <- data[, deparse(substitute(collab))] if(!missing(values) & mode(substitute(values)) == "name") values <- data[, deparse(substitute(values))] } rowlab <- as.vector(rowlab) collab <- as.vector(collab) # if values are not provided, a count of combinations of rowlab and collab is returned # equivalent to table(rowlab, collab) if(missing(values)) { values <- rep(1, length(rowlab)) type <- "sum" } # if type is count and values are provided, combinations of unique values are counted if(type == "count") { values <- paste(rowlab, collab, values) values <- as.numeric(!duplicated(values)) type <- "sum" } values <- as.vector(values) results <- switch(type, mean = tapply(values, list(rowlab, collab), mean, ...), max = tapply(values, list(rowlab, collab), max, ...), min = tapply(values, list(rowlab, collab), min, ...), sum = tapply(values, list(rowlab, collab), sum, ...) ) if(!missing(allrows)) { allrows <- as.vector(allrows) allrows <- c(rownames(results), allrows) allrows <- sort(unique(allrows)) newrows <- allrows[!(allrows %in% rownames(results))] temp <- matrix(NA, ncol=ncol(results), nrow=length(newrows)) colnames(temp) <- colnames(results) rownames(temp) <- newrows results <- rbind(results, temp) if(is.numeric(rowlab)) { results <- results[order(as.numeric(rownames(results))), , drop=FALSE] } else { results <- results[order(rownames(results)), , drop = FALSE] } } if(!missing(allcols)) { allcols <- as.vector(allcols) allcols <- c(colnames(results), allcols) allcols <- sort(unique(allcols)) newcols <- allcols[!(allcols %in% colnames(results))] temp <- matrix(NA, nrow=nrow(results), ncol=length(newcols)) rownames(temp) <- rownames(results) colnames(temp) <- newcols results <- cbind(results, temp) if(is.numeric(collab)) { results <- results[, order(as.numeric(colnames(results))), drop=FALSE] } else { results <- results[, order(colnames(results)), drop = FALSE] } } if(na.as.0) results[is.na(results)] <- 0 data.frame(results, check.names=check.names) } ecodist/R/nmds.min.R0000644000176200001440000000204614500175272013760 0ustar liggesusersnmds.min <- function(x, dims=2) { # returns the minimum-stress configuration from nmds output. # (Results from nmds) # if dims==0, returns the overall lowest-stress configuration # Otherwise, returns the lowest-stress configuration of dimensionality dims # patched 2013-05-09 thanks to a bug report from Kellie Carim # superseded by min.nmds if(dims == 0) { x.min <- x$conf[x$stress == min(x$stress)] } else { x.dims <- sapply(x$conf, ncol) x$conf <- x$conf[x.dims == dims] x$stress <- x$stress[x.dims == dims] x$r2 <- x$r2[x.dims == dims] x.min <- x$conf[x$stress == min(x$stress)] } cat("Minimum stress for given dimensionality: ", x$stress[which.min(x$stress)], "\n") cat("r^2 for minimum stress configuration: ", x$r2[which.min(x$stress)], "\n") x.min <- x.min[[1]] x.min <- data.frame(x.min) colnames(x.min) <- paste0("X", seq_len(ncol(x.min))) attr(x.min, "stress") <- x$stress[which.min(x$stress)] attr(x.min, "r2") <- x$r2[which.min(x$stress)] x.min } ecodist/R/min.nmds.R0000644000176200001440000000215114500175311013747 0ustar liggesusersmin.nmds <- function(..., na.rm = FALSE, dims=2) { # returns the minimum-stress configuration from nmds output. # (Results from nmds) # if dims=0, returns the overall lowest-stress configuration # Otherwise, returns the lowest-stress configuration of dimensionality dims # patched 2013-05-09 thanks to a bug report from Kellie Carim # this function replaces nmds.min dots <- list(...) x <- dots[[1]] if(dims == 0) { x.min <- x$conf[x$stress == min(x$stress)] } else { x.dims <- sapply(x$conf, ncol) x$conf <- x$conf[x.dims == dims] x$stress <- x$stress[x.dims == dims] x$r2 <- x$r2[x.dims == dims] x.min <- x$conf[x$stress == min(x$stress)] } cat("Minimum stress for given dimensionality: ", x$stress[which.min(x$stress)], "\n") cat("r^2 for minimum stress configuration: ", x$r2[which.min(x$stress)], "\n") x.min <- x.min[[1]] x.min <- data.frame(x.min) colnames(x.min) <- paste0("X", seq_len(ncol(x.min))) attr(x.min, "stress") <- x$stress[which.min(x$stress)] attr(x.min, "r2") <- x$r2[which.min(x$stress)] x.min } ecodist/R/mgroup.R0000644000176200001440000000233314452056435013552 0ustar liggesusers# mgroup returns the Mantel correlations for group contrast # matrices computed from cluster groups across a range of # clustering levels. # The inputs are an ecological distance matrix # and a vector or matrix of cluster levels in any order. # # dlu # mgroup <- function(edist, groups, nperm = 1000, mrank = FALSE) { nl <- ncol(groups) if(is.null(nl)) { groups <- matrix(groups, ncol=1) nl <- 1 } if(mrank) { edist <- rank(edist) } outtable <- data.frame(nclust = rep(NA, nl), mantelr = rep(NA, nl), pval = rep(NA, nl)) for (i in seq_len(nl)) { # number of groups at this level: thisgroups <- groups[,i] if(is.factor(thisgroups)) { thisgroups <- as.numeric(thisgroups) } if(is.character(thisgroups)) { thisgroups <- as.numeric(factor(thisgroups)) } cl <- length(unique(groups[,i])) # create group contrast: gdist <- dist(thisgroups) gdist[gdist > 0] <- 1 # run mantel: m <- mantel(edist ~ gdist, nperm=nperm, nboot=0) outtable[["nclust"]][i] <- cl outtable[["mantelr"]][i] <- m[1] outtable[["pval"]][i] <- m[2] } outtable } ecodist/R/residuals.mgram.R0000644000176200001440000000012514452055674015337 0ustar liggesusersresiduals.mgram <- function(object, ...) { # for S3 "neatness" object$resids } ecodist/R/vf.R0000644000176200001440000000337214474176664012673 0ustar liggesusersvf <- function (ord, vars, nperm = 100) { vfcalc <- function(ord, vars) { lm.list <- apply(vars, 2, function(x, ord) lm(x ~ ord), ord = ord) coef.m <- sapply(lm.list, function(x) unlist(x$coefficients)) scores <- atan(coef.m[3, ]/coef.m[2, ]) scores <- t(rbind(cos(scores), sin(scores))) scores <- abs(scores) cor.m <- t(cor(ord, vars)) cor.m <- sign(cor.m) scores <- scores * cor.m coef.m <- lapply(lm.list, summary) r <- sapply(coef.m, function(x) sqrt(unlist(x$r.squared))) list(scores = scores, r = r) } ord <- as.matrix(ord) if(is.vector(vars)) { vars <- matrix(vars, ncol=1) colnames(vars) <- "var1" } else vars <- as.matrix(vars) nvars <- ncol(vars) if (any(is.na(vars))) { warning("NA values in variables will be removed\n") naindex <- apply(vars, 1, function(x) any(is.na(x))) ord <- ord[!naindex, ] vars <- vars[!naindex, ] } vf1 <- vfcalc(ord, vars) if (nperm > 0) { how.many <- rep(nrow(ord), nperm - 1) perm.ord <- lapply(how.many, function(x) sample(1:x)) r.list <- sapply(perm.ord, function(x, ord, vars, f) f(ord[x, ], vars)$r, ord = ord, vars = vars, f = vfcalc) if(nvars == 1) r.list <- matrix(r.list, nrow=1) r.list <- cbind(vf1$r, r.list) pval <- apply(r.list, 1, function(x, nperm) length(x[x >= x[1]])/nperm, nperm = nperm) } else pval <- rep(0, ncol(vars)) vfres <- data.frame(vf1$scores, vf1$r, pval) dimnames(vfres)[[1]] <- dimnames(vars)[[2]] dimnames(vfres)[[2]] <- c(paste0("X", 1:ncol(ord)), "r", "pval") class(vfres) <- c("vf", "data.frame") vfres } ecodist/R/addord.R0000644000176200001440000000645014452055674013506 0ustar liggesusersaddord <- function(origconf, fulldat, fulldist, isTrain, bfstep=10, maxit = 50, epsilon = 1e-12) { ## add new points to an ordination configuration ## by minimizing stress of new point location ## brute force, similar to PC-ORD method setgrid <- function(minvec, maxvec, nstep) { # find midpoints for each midlist <- vector(mode="list", length=length(minvec)) midlist <- lapply(seq_along(minvec), function(i){ thisstep <- (maxvec[i] - minvec[i])/nstep seq(minvec[i]+thisstep/2, maxvec[i]-thisstep/2, length=nstep) }) as.matrix(expand.grid(midlist)) } ########## if(missing(isTrain)) { isTrain <- c(rep(TRUE, nrow(origconf)), rep(FALSE, nrow(fulldat) - nrow(origconf))) } # set up extent to sample: +/- 1 sd osd <- apply(origconf, 2, sd) omin <- apply(origconf, 2, min) - osd omax <- apply(origconf, 2, max) + osd startgrid <- setgrid(omin, omax, bfstep) colnames(startgrid) <- colnames(origconf) # set up output objects fullfitconf <- data.frame(matrix(NA, nrow=nrow(fulldat), ncol=ncol(origconf))) colnames(fullfitconf) <- colnames(origconf) fullfitconf[isTrain, ] <- origconf stress.fullfit <- rep(NA, nrow(fullfitconf)) for(thispoint in seq_along(isTrain)) { if(!isTrain[thispoint]) { # fit a new point to the ordination configuration by brute force # 1. make a distance matrix that includes selected new point as the last row/col usethis <- isTrain + 0 usethis[thispoint] <- 2 # orig points are 1, focus point is 2, points to not use are 0 pointdist <- full(fulldist)[usethis > 0, usethis > 0] useord <- order(usethis[usethis > 0]) pointdist <- pointdist[useord, useord] pointdist <- lower(pointdist) # 2. which of the startgrid gives the lowest stress? pointstress <- apply(startgrid, 1, function(x) { pointconf <- rbind(origconf, x) sstress(pointdist, pointconf) }) conf <- startgrid[which.min(pointstress), ] stress2 <- min(pointstress) stress1 <- stress2 + 10 * epsilon # for stress, decreases thisstep <- (omax - omin) / (bfstep * 2) k <- 0 while(k < maxit && abs(stress1 - stress2) > epsilon) { # go finer and finer into the ordination space newmin <- as.vector(conf) - thisstep newmax <- as.vector(conf) + thisstep newgrid <- setgrid(newmin, newmax, bfstep) colnames(newgrid) <- colnames(origconf) # find stress for newgrid pointstress <- apply(newgrid, 1, function(x) { pointconf <- rbind(origconf, x) sstress(pointdist, pointconf) }) conf <- newgrid[which.min(pointstress), ] stress1 <- stress2 stress2 <- min(pointstress) thisstep <- (newmax - newmin) / (bfstep * 2) k <- k + 1 } fullfitconf[thispoint, ] <- conf stress.fullfit[thispoint] <- stress2 } } list(conf=fullfitconf, stress=stress.fullfit, isTrain=isTrain) } ecodist/MD50000644000176200001440000001115414517747122012230 0ustar liggesusers9314fe3cd07c09648e63947a7eb1b2fd *DESCRIPTION dd39642b27501ef8d59229b95cbe0fb0 *NAMESPACE 5f0ef9404bd7057eea29a96244297ae9 *R/MRM.R 46ede2c4d3401991a8ebb65990c90e87 *R/addord.R 6883e1f5939fa51fe387e47b2ea9751a *R/bcdist.R de02c50220be92a6c292a98e07d8db21 *R/cor2m.R a6ac5872408b8e3203c99014a5a99f1f *R/corgen.R ba9e2a92d06d4cddaf72aeed535ab7a2 *R/crosstab.R cc9fad3767cf1763f73a18067ed701ab *R/dim.dist.R b59534432afaa0f9a6f2b06b85336272 *R/distance.R 2c71a7ce644f23b66401b0939e0f8320 *R/fixdmat.R 305b662a275ddac44f45aa0c549b8260 *R/full.R 2bb91743927cc288ef6d315d27e35284 *R/lower.R e7f2b9d568dfbd6dc6e0594d3f2069a1 *R/mantel.R 2fd154a12bf2ae5df17a8cbe78bb7626 *R/mgram.R fdcf049138ee753cb86e46455a3f235f *R/mgroup.R 0635a58e46ab0428b3e2e6673078c850 *R/min.nmds.R 6bec67f7e042f9b71dc7969ce4b0550a *R/nmds.R d4be71920b2af530572b3f79b636ca0c *R/nmds.min.R 6be5287f13d5c9558a8c868e0b0cc3d7 *R/pathdist.R 5e7b1738060ded6ab6047d5d7b1ee87b *R/pco.R 5431a33e5ce0b188230e73bbbaf069ba *R/plot.mgram.R f311d96071e6968343c3532e31825508 *R/plot.nmds.R 2e511cd1e2ad802e9927f6aad4f02ae9 *R/plot.vf.R 6ba05de558d7ca5bb96262aace7237fd *R/pmgram.R 57cd8ab061ae26695f4c2616cbbe6fe5 *R/relrange.R 3edb216d47fc3f2394209d4ef7f40955 *R/residuals.mgram.R f003815de707b258a285a4edeb726c0a *R/rotate2d.R 5e1e277dcc7199bf0d3e0eba92b1dea3 *R/vf.R f3b0715cfd189a43f9d6bd58dd37e026 *R/xdistance.R 72025b2856dd48e51913caa3634d8594 *R/xmantel.R 9ddd02a9a66df9df3cf4c6d889d32dd4 *R/xmgram.R e0f68e75cce534e57eca36b2c9edfcc0 *README.md 40ef2d826449f98813eaf1a490862954 *build/partial.rdb a80ae37cc262b6488c2b53ee090f3a56 *build/vignette.rds 13c854d8d590fa79dc316628ab0b272a *data/bump.pmgram.rda 30d5b5d4e55edba01b24da1e0b460cba *data/bump.rda 6d3e215e51dab584c898839558991136 *data/graze.rda c6f3963d78b714e7184a7ea09ddf9814 *data/iris.fit.rda 487aff36b22f742501bd18d3054dfd18 *data/iris.nmds.rda cd86940eef6a822ecfd87569cb3ec77d *data/iris.vf.rda c8c954eb6921bedc8f9c24e833c08526 *data/iris.vfrot.rda b204771dff335c364aabb3a6e8f54be6 *data/z.no.rda 77a8d71949fae669d76c6a4ef95e66f5 *data/z.z1.rda 857d17c0a8711a04eeb6b64de8794927 *inst/CITATION ce8a258364528daf96312bcf6f96c75b *inst/doc/dissimilarity.Rmd 8a921b5fac578653754c9fb270d043d1 *inst/doc/dissimilarity.html 7424e92fb8ef9f4bd59fba261b571999 *man/MRM.Rd 697cee16af18f9cfc0888e1b49464c83 *man/addord.Rd 896281685766f866b18a647ca4686b05 *man/bcdist.Rd b5185d72e634620a362c362844dc8244 *man/bump.Rd ebb224fb20719ab6fab64031b0c12b14 *man/bump.pmgram.Rd e6b9ab94534537576561009f321d806c *man/cor2m.Rd 9b90d64da318102da8efc1de43e84f82 *man/corgen.Rd 400c1c34d4c579ed3e6c203d97a0757a *man/crosstab.Rd 461b2e9755ef40fb550978bd7a5d74c1 *man/dim.dist.Rd 52988ca389a8b078ff9a405ba9cc5c12 *man/distance.Rd 81a6795b0f5396ef52c22ec614b97fa4 *man/ecodist-package.Rd 599455d49118abd375c58788d9c6291f *man/fixdmat.Rd 754485899ec74a1f60f2531a8be37127 *man/full.Rd caa6d24b2d4bb1e7b1fc83c39ce89a6c *man/graze.Rd 6053fb0e92af994b3dca4c3274cb532c *man/iris.fit.Rd be2e2868917138b9b1b3d44f81967206 *man/iris.nmds.Rd e4b5951132e9c8860cb88a350ff85658 *man/iris.vf.Rd d9db0830bb5b84e9e48b94847cade17d *man/iris.vfrot.Rd 6218940b6fdc911a672e1718488fa724 *man/lower.Rd 9697035d6f5bfaeb69724c85c0b922eb *man/mantel.Rd 085badc9999530006495f40d1f5a711f *man/mgram.Rd 739341d1b001fdccfb48b0384e377a1e *man/mgroup.Rd 53043c4b5b64981c255a5d081b86142c *man/min.nmds.Rd 3ac4bd737c29520d4ef446118e369ca4 *man/nmds.Rd d10a12aa4d932b27a0bcc41daf459514 *man/pathdist.Rd ca53104c11c464ba211e5fb0b7ddf7ee *man/pco.Rd 3c6be74e70eb7dba3c710c1388a478ac *man/plot.mgram.Rd 9dfb72ca1556ab4b785b4c721777ae66 *man/plot.nmds.Rd c2e781a9a4c371da554359d83a771859 *man/plot.vf.Rd 8200e150f99d1e45413aa5774da88375 *man/pmgram.Rd 28b7b52846bc25eb57d162adfe43be75 *man/relrange.Rd c197b9e39d0d96512923ffad02742ef3 *man/residuals.mgram.Rd 2857dbda376b376f115a12ab60b6f02b *man/rotate2d.Rd 94a2f1d1204dc68ff911f76792c9aa1d *man/vf.Rd 586e31ea03a2da0b8cb83a68b893c211 *man/xdistance.Rd c61730782ee270d953df4a7594ec9d90 *man/xmantel.Rd 9c99f330b0efb10c082a603235b26d6a *man/xmgram.Rd d2c3e1dbf7218fe03c5224be0febb8d7 *man/z.no.Rd 3cf440ab38db7938ae6d2e130ab95a42 *man/z.z1.Rd 7ad45eea54b4e506438c8dd620473f96 *src/Makevars 45a4337aae018cf01482a72219abe977 *src/ecodist.c 41278d00a33cc545da4aebc4e8f7ab43 *src/init.c 9ddd5708c58d58e3550696f3119e87ed *tests/testthat.R 80c568577c3aae89c23492c1caeb9b7d *tests/testthat/test-MRM.R abfb26f46bd56ae9975457597f9b0dd6 *tests/testthat/test-crosstab.R 3ea6ed914e3d4cdd9fb9b8dc1a912dbb *tests/testthat/test-distance.R 8bdf878f30f5cac8a974890afca58fc9 *tests/testthat/test-mantel.R 0360a6ade8130399a6be6f6588a1f751 *tests/testthat/test-mgroup.R ce8a258364528daf96312bcf6f96c75b *vignettes/dissimilarity.Rmd ecodist/inst/0000755000176200001440000000000014517736751012701 5ustar liggesusersecodist/inst/doc/0000755000176200001440000000000014517736751013446 5ustar liggesusersecodist/inst/doc/dissimilarity.Rmd0000644000176200001440000000643714456245464017010 0ustar liggesusers--- title: "Dissimilarity Cheat Sheet" author: "Sarah Goslee" date: "2017-07-12" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Dissimilarity Cheat Sheet} %\VignetteEngine{knitr::rmarkdown} --- **Things to do with dissimilarity matrices** _(ecodist functions are marked in **bold**)_ _(untested ideas marked with ?)_ Description | Notation | Name | R function ------------|----------|------|----------- Relationship between two matrices | D1 ~ D2 | Mantel test | **mantel**(D1 ~ D2) Relationship between two matrices given more | D1 ~ D2 | D3 ... Dn | Partial Mantel test | **mantel**(D1 ~ D2 + D3 + ...) ||| Spatial structure in one matrix relative to all distance classes | D1 x S | Mantel correlogram | **mgram**(D1, S) Spatial structure in one matrix given more relative to all distance classes | D1 | D2 ... Dn x S | Partial Mantel correlogram | **?mgram**(residuals(lm(D1 ~ D2 + ...)), space) Spatial structuce in one matrix by distance class | D1 x S | Piecewise multivariate correlogram | **pmgram**(D1, S) Spatial structure in one matrix by distance class given more | D1 | D2 ... Dn x S | Piecewise partial multivariate correlogram | **pmgram**(D1, S, D2) ||| Spatial structure in the relationship between two matrices | D1 ~ D2 x S | Piecewise Mantel cross-correlogram | **pmgram**(cbind(lower(D1), lower(D2)), S) Spatial structure in the relationship between two matrices given more | D1 ~ D2 | D3 ... Dn x S | Piecewise partial Mantel cross-correlogram | **pmgram**(cbind(lower(D1), lower(D2)), S, D3) ||| Ordination of one matrix | | (N)MDS | **nmds**(y) or **pco**(y) Ordination of one matrix given more | | (Partial (N)MDS | **?nmds**(residuals(lm(y ~ z1 + ...))) ||| Grouping of items based on one matrix | | Cluster analysis | eg hclust(y) Grouping of items based on one matrix given more | | Partial cluster analysis | ?hclust(residuals(lm(y ~ z1 + ...))) Grouping of items given space | | Spatially-constrained cluster analysis | NA ||| Multiple regression | D1 ~ D2 | D3 ... Dn | Multiple regression on distance matrices | **MRM**(D1 ~ D2 + D3 + ...) **Ways to calculate dissimilarity matrices** Description | Result | R function ------------|--------|----------- From a site by sample matrix | Symmetric matrix with zero diagonals | dist(x) or **bcdist**(x) or **distance**(x) ----------------------------- **Things to do with cross-dissimilarity matrices** Description | Notation | Name | R function ------------|----------|------|----------- Relationship between two cross-dissimilarity matrices | D12 ~ D34 | Cross-Mantel test | **xmantel**(D12 ~ D34) Relationship between two cross-dissimilarity matrices given more | D12 ~ D34 | D56 ... Dn | Partial cross-Mantel test | **xmantel**(D12 ~ D34 + D56 + ...) ||| Spatial structure in one cross-dissimilarity matrix | D12 x S | Cross-Mantel correlogram | **xmgram**(D12, spaceX) Spatial structure in one cross-dissimilarity matrix given more | D12 | D34 ... Dn x S | Partial cross-Mantel correlogram | **?xmgram**(residuals(lm(D12 ~ D34 + ...)), spaceX) **Ways to calculate cross-dissimilarity matrices** Source | Result | R function -------|--------|----------- From 2 site by sample matrixes for the same sites and samples (e.g. different years) | nonsymmetric matrix with nonzero diagonals | **xdistance**(x, y) ecodist/inst/doc/dissimilarity.html0000644000176200001440000002416714517736751017234 0ustar liggesusers Dissimilarity Cheat Sheet

Dissimilarity Cheat Sheet

Sarah Goslee

2017-07-12

Things to do with dissimilarity matrices

(ecodist functions are marked in bold)

(untested ideas marked with ?)

Description Notation Name R function
Relationship between two matrices D1 ~ D2 Mantel test mantel(D1 ~ D2)
Relationship between two matrices given more D1 ~ D2 | D3 … Dn Partial Mantel test mantel(D1 ~ D2 + D3 + …)
Spatial structure in one matrix relative to all distance classes D1 x S Mantel correlogram mgram(D1, S)
Spatial structure in one matrix given more relative to all distance classes D1 | D2 … Dn x S Partial Mantel correlogram ?mgram(residuals(lm(D1 ~ D2 + …)), space)
Spatial structuce in one matrix by distance class D1 x S Piecewise multivariate correlogram pmgram(D1, S)
Spatial structure in one matrix by distance class given more D1 | D2 … Dn x S Piecewise partial multivariate correlogram pmgram(D1, S, D2)
Spatial structure in the relationship between two matrices D1 ~ D2 x S Piecewise Mantel cross-correlogram pmgram(cbind(lower(D1), lower(D2)), S)
Spatial structure in the relationship between two matrices given more D1 ~ D2 | D3 … Dn x S Piecewise partial Mantel cross-correlogram pmgram(cbind(lower(D1), lower(D2)), S, D3)
Ordination of one matrix (N)MDS nmds(y) or pco(y)
Ordination of one matrix given more (Partial (N)MDS ?nmds(residuals(lm(y ~ z1 + …)))
Grouping of items based on one matrix Cluster analysis eg hclust(y)
Grouping of items based on one matrix given more Partial cluster analysis ?hclust(residuals(lm(y ~ z1 + …)))
Grouping of items given space Spatially-constrained cluster analysis NA
Multiple regression D1 ~ D2 | D3 … Dn Multiple regression on distance matrices MRM(D1 ~ D2 + D3 + …)

Ways to calculate dissimilarity matrices

Description Result R function
From a site by sample matrix Symmetric matrix with zero diagonals dist(x) or bcdist(x) or distance(x)

Things to do with cross-dissimilarity matrices

Description Notation Name R function
Relationship between two cross-dissimilarity matrices D12 ~ D34 Cross-Mantel test xmantel(D12 ~ D34)
Relationship between two cross-dissimilarity matrices given more D12 ~ D34 | D56 … Dn Partial cross-Mantel test xmantel(D12 ~ D34 + D56 + …)
Spatial structure in one cross-dissimilarity matrix D12 x S Cross-Mantel correlogram xmgram(D12, spaceX)
Spatial structure in one cross-dissimilarity matrix given more D12 | D34 … Dn x S Partial cross-Mantel correlogram ?xmgram(residuals(lm(D12 ~ D34 + …)), spaceX)

Ways to calculate cross-dissimilarity matrices

Source Result R function
From 2 site by sample matrixes for the same sites and samples (e.g. different years) nonsymmetric matrix with nonzero diagonals xdistance(x, y)
ecodist/inst/CITATION0000644000176200001440000000107314476616743014041 0ustar liggesusersbibentry("Article", title = "The ecodist package for dissimilarity-based analysis of ecological data", author = c(person(c("Sarah", "C."), "Goslee"), person(c("Dean", "L."), "Urban")), journal = "Journal of Statistical Software", year = 2007, volume = 22, issue = 7, pages = "1-19", doi = "10.18637/jss.v022.i07", textVersion = paste("Goslee, S.C. and Urban, D.L. 2007.", "The ecodist package for dissimilarity-based analysis of ecological data.", "Journal of Statistical Software 22(7):1-19.", "DOI:10.18637/jss.v022.i07") )