
(*==============================================================================

     plot.tl

     This file is part of the TREEFINDER software.

                                    COPYRIGHT (C) 1997-2008 BY GANGOLF JOBB
==============================================================================*)

PreparePlotXYOptions:=<<
 opts:=
  {
   If[!IsVoid[PSFile],PSFile->PSFile],
   If[!IsVoid[Header],Header->Header],
   If[!IsVoid[Description],Description->Description],
   If[!IsVoid[PaperWidth],PaperWidth->PaperWidth],
   If[!IsVoid[PaperHeight],PaperHeight->PaperHeight],
   If[!IsVoid[DiagramWidth],DiagramWidth->DiagramWidth],
   If[!IsVoid[DiagramHeight],DiagramHeight->DiagramHeight],
   If[!IsVoid[XRange],XRange->XRange],
   If[!IsVoid[YRange],YRange->YRange],
   If[!IsVoid[XDivision],XDivision->XDivision],
   If[!IsVoid[XLabel],XLabel->XLabel],
   If[!IsVoid[YLabel],YLabel->YLabel],
   If[!IsVoid[BarLabels],BarLabels->BarLabels],
   If[!IsVoid[AsBarGraph],AsBarGraph->AsBarGraph],
   If[!IsVoid[Joined],Joined->Joined],
   If[!IsVoid[Grid],Grid->Grid],
   If[!IsVoid[Isometric],Isometric->Isometric],
   If[!IsVoid[DotSize],DotSize->DotSize],
   If[!IsVoid[DotSymbol],DotSymbol->DotSymbol],
   If[!IsVoid[LineWidth],LineWidth->LineWidth],
   If[!IsVoid[Color],Color->Color]
  },
 Append[
  opts,
  PSComment->
   "%> "<>Build[Put[Prepend[opts,data],0,symb],'Hold]<>"\n%.\n"
   <>If[!IsVoid[Header],"%Header: "<>ToString[Header]<>"\n",""]
   <>If[!IsVoid[Description],"%Description: "<>ToString[Description]<>"\n",""]
   <>If[!IsVoid[PaperWidth],"%PaperWidth: "<>ToString[PaperWidth]<>"\n",""]
   <>If[!IsVoid[PaperHeight],"%PaperHeight: "<>ToString[PaperHeight]<>"\n",""]
   <>If[!IsVoid[Joined],"%Joined: "<>ToString[Joined]<>"\n",""]
   <>If[!IsVoid[AsBarGraph],"%AsBarGraph: "<>ToString[AsBarGraph]<>"\n",""]
   <>If[!IsVoid[Grid],"%Grid: "<>ToString[Grid]<>"\n",""]
   <>If[!IsVoid[Isometric],"%Isometric: "<>ToString[Isometric]<>"\n",""]
   <>If[!IsVoid[XLabel],"%XLabel: "<>ToString[XLabel]<>"\n",""]
   <>If[!IsVoid[YLabel],"%YLabel: "<>ToString[YLabel]<>"\n",""]
   <>If[!IsVoid[XRange]&&XRange==(_:_),"%XRange: "<>ToString[XRange|1]<>" "<>ToString[XRange|2]<>"\n",""]
   <>If[!IsVoid[YRange]&&YRange==(_:_),"%YRange: "<>ToString[YRange|1]<>" "<>ToString[YRange|2]<>"\n",""]
   <>If[!IsVoid[XDivision],"%XDivision: "<>ToString[XDivision]<>"\n",""]
   <>If[!IsVoid[DiagramWidth],"%DiagramWidth: "<>ToString[DiagramWidth]<>"\n",""]
   <>If[!IsVoid[DiagramHeight],"%DiagramHeight: "<>ToString[DiagramHeight]<>"\n",""]
 ],
 Forget[opts]
>>,
Protect[PreparePlotXYOptions],

(*............................................................................*)

PlotPoints[
 data,
 PSFile->~Void~,
 Header->~Void~,
 Description->~Void~,
 PaperWidth->~Void~,
 PaperHeight->~Void~,
 DiagramWidth->~Void~,
 DiagramHeight->~Void~,
 XRange->~Void~,
 YRange->~Void~,
 XDivision->~Void~,
 XLabel->~Void~,
 YLabel->~Void~,
 BarLabels->~Void~,
 AsBarGraph->~Void~,
 Joined->~Void~,
 Grid->~Void~,
 Isometric->~Void~,
 DotSize->~Void~,
 DotSymbol->~Void~,
 LineWidth->~Void~,
 Color->~Void~
][
 symb:='PlotPoints
]:=<<
 If[Rank[data]==2,
  data={data};
  If[!IsVoid[DotSymbol],DotSymbol={DotSymbol}];
  If[!IsVoid[Color],Color={Color}]
 ];
 Eval[`Put[Prepend[PreparePlotXYOptions,data],0,'PlotXY]]
>>,
SetMask[PlotPoints,"1."], Protect[PlotPoints],

(*............................................................................*)

PlotValues[
 data,
 StartIndex->1,
 PSFile->~Void~,
 Header->~Void~,
 Description->~Void~,
 PaperWidth->~Void~,
 PaperHeight->~Void~,
 DiagramWidth->~Void~,
 DiagramHeight->~Void~,
 XRange->~Void~,
 YRange->~Void~,
 XDivision->~Void~,
 XLabel->~Void~,
 YLabel->~Void~,
 BarLabels->~Void~,
 AsBarGraph->~Void~,
 Joined->~Void~,
 Grid->~Void~,
 Isometric->~Void~,
 DotSize->~Void~,
 DotSymbol->~Void~,
 LineWidth->~Void~,
 Color->~Void~
][
 symb:='PlotValues,
 wrap[l]:=<<Table[{x,y},(=x,StartIndex:Length[l]+StartIndex-1,y,l=)]>>
]:=<<
 If[Rank[data]==1,
  data={data};
  If[!IsVoid[DotSymbol],DotSymbol={DotSymbol}];
  If[!IsVoid[Color],Color={Color}]
 ];
 Eval[`Put[Prepend[PreparePlotXYOptions,data#wrap],0,'PlotXY]]
>>,
SetMask[PlotValues,"1."], Protect[PlotValues],
Create[StartIndex], Protect[StartIndex],

(*============================================================================*)

Col2str[c]:=<<
 Scope[
  {n:=Max[c#Length],
   maxwidth:=<<'StringLength,Map,0,Prepend,Max>>,
   w1:=maxwidth[c|1],w3:=maxwidth[c|3],w5:=maxwidth[c|5]
  },
  Alternate[
   Extend[{},"\n     ",n], Extend[c|1,"",n]#<<w1,PadRight>>,
   Extend[{},  " "    ,n], Extend[c|2,"",n]#<<12,PadRight>>,
   Extend[{},  "    " ,n], Extend[c|3,"",n]#<<w3,PadRight>>,
   Extend[{},  " "    ,n], Extend[c|4,"",n]#<<12,PadRight>>,
   Extend[{},  "    " ,n], Extend[c|5,"",n]#<<w5,PadRight>>,
   Extend[{},  " "    ,n], Extend[c|6,"",n]#<<12,PadRight>>
  ]@JoinStrings
 ]
>>,
Protect[Col2str],

(*............................................................................*)

SubstitutionParameterLabels[l]:=<<
 Scope[{n:=Length[l]},Flatten[Table[l|i<>l|j<>":",(=i,1:n-1=),(=j,i+1:n=)]]]
>>,
Protect[SubstitutionParameterLabels],

(*............................................................................*)

Subst2col:=<<
 '{

   _[{__tr},{_t,_c,_a,_g}]=>
    {
     SubstitutionParameterLabels[{"T","C","A","G"}],{__tr},
     {"T:","C:","A:","G:"},{_t,_c,_a,_g}
    },

   GTR3[{__tr},{_t,_a,_g}]=>
    {
     SubstitutionParameterLabels[{"T","A","G"}],{__tr},
     {"T:","A:","G:"},{_t,_a,_g}
    },

   GTR2[_,{_t,_a}]->
    {
     {},{},
     {"T:","A:"},{_t,_a}
    },

   DG[{__tr},{_a,_c,_d,_f,_h,_i}]=>
    {
     SubstitutionParameterLabels[{"A","C","D","F","H","I"}],{__tr},
     {"A:","C:","D:","F:","H:","I:"},{_a,_c,_d,_f,_h,_i}
    },

   MAP[__st][{__tr},{__fr}]=>
    {
     SubstitutionParameterLabels[{__st}#<<{1,1},CutString>>],{__tr},
     {__st}#<<{1,1},CutString,":",JoinStrings>>,{__fr}
    },

   GTR20[{__tr},{_a,_c,_d,_e,_f,_g,_h,_i,_k,_l,_m,_n,_p,_q,_r,_s,_t,_v,_w,_y}]=>
    {
     SubstitutionParameterLabels[{"A","C","D","E","F","G","H","I","K","L","M","N","P","Q","R","S","T","V","W","Y"}],{__tr},
     {"A:","C:","D:","E:","F:","G:","H:","I:","K:","L:","M:","N:","P:","Q:","R:","S:","T:","V:","W:","Y:"},{_a,_c,_d,_e,_f,_g,_h,_i,_k,_l,_m,_n,_p,_q,_r,_s,_t,_v,_w,_y}
    },

   MIX[__sy][_wei,{_a,_c,_d,_e,_f,_g,_h,_i,_k,_l,_m,_n,_p,_q,_r,_s,_t,_v,_w,_y}]=>
    {
     {__sy}#<<":",JoinStrings>>,_wei,
     {"A:","C:","D:","E:","F:","G:","H:","I:","K:","L:","M:","N:","P:","Q:","R:","S:","T:","V:","W:","Y:"},{_a,_c,_d,_e,_f,_g,_h,_i,_k,_l,_m,_n,_p,_q,_r,_s,_t,_v,_w,_y}
    },

   MIX[__sy][_wei,_fr]=>
    {
     {__sy}#<<":",JoinStrings>>,_wei,
     {},{}
    },

   _[_,{_a,_c,_d,_e,_f,_g,_h,_i,_k,_l,_m,_n,_p,_q,_r,_s,_t,_v,_w,_y}]->
    {
     {},{},
     {"A:","C:","D:","E:","F:","G:","H:","I:","K:","L:","M:","N:","P:","Q:","R:","S:","T:","V:","W:","Y:"},{_a,_c,_d,_e,_f,_g,_h,_i,_k,_l,_m,_n,_p,_q,_r,_s,_t,_v,_w,_y}
    },

   _[_tr,_fr]->
    {
     {},{},
     {},{}
    }

  },
 Replace
>>,
Protect[Subst2col],

(*............................................................................*)

Sy2str[x]:=<<(x=='Optimum)?"o"?(x=='Empirical)?"e"?"f">>,
Protect[Sy2str],

(*............................................................................*)

Opti2str:=<<
 '{
   _s[_r,_f]:_h[_a]:_n => Sy2str[_r]<>Sy2str[_f]<>"+"<>Sy2str[_a],
   _s[_r,_f]:_h[_a]    => Sy2str[_r]<>Sy2str[_f]<>"+"<>Sy2str[_a],
   _s[_r,_f]           => Sy2str[_r]<>Sy2str[_f]
  },
 Replace
>>,
Protect[Opti2str],

(*............................................................................*)

SubstitutionModelToString[id,model,optim]:=<<
 If[IsSymbol[id],id=""],
 If[IsNumber[id],id="#"<>id<>":"],
 If[IsSymbol[optim],optim=model],
 If[IsList[model]&&!IsList[optim],optim=id#<<Drop,optim>>],
 model-|{

  {__l}=>id#{__l}#optim#SubstitutionModelToString@JoinStrings,

  _s[_r,_f]:G[_a]:_rc=>
   "\n "<>id<>"  "<>(_s-|{MIX[__]->MIX})<>"+G ("<>_rc<>")  /"<>Opti2str[optim]<>"\n"
   <>Col2str[Join[Subst2col[_s[_r,_f]],{{"ALPHA:"},_a}]]<>"\n",

  _s[_r,_f]:GI[_a]:_rc=>
   "\n "<>id<>"  "<>(_s-|{MIX[__]->MIX})<>"+I+G ("<>_rc<>")  /"<>Opti2str[optim]<>"\n"
   <>Col2str[Join[Subst2col[_s[_r,_f]],{{"ALPHA:","THETA:"},_a}]]<>"\n",

  _s[_r,_f]:I[_a]=>
   "\n "<>id<>"  "<>(_s-|{MIX[__]->MIX})<>"+I  /"<>Opti2str[optim]<>"\n"
   <>Col2str[Join[Subst2col[_s[_r,_f]],{{"THETA:"},_a}]]<>"\n",

  _s[_r,_f]=>
   "\n "<>id<>"  "<>(_s-|{MIX[__]->MIX})<>"  /"<>Opti2str[optim]<>"\n"
   <>Col2str[Join[Subst2col[_s[_r,_f]],{{},{}}]]<>"\n"

 }
>>,
Protect[SubstitutionModelToString],

(*............................................................................*)

AddReconstructionComments[hyp]:=<<
 Scope[{com,edgeoff,nsit,npar,aic,aicc,hq,bic,pscrit},
  edgeoff=hyp|OEdgeOptimizationOff, If[!IsBoolean[edgeoff],edgeoff=False],
  nsit=hyp|NSites, If[!IsNumber[nsit],nsit="-"],
  npar=hyp|NParameters, If[!IsNumber[npar],npar="-"],
  aic=hyp|AIC, If[!IsNumber[aic],aic="-"],
  aicc=hyp|AICc, If[!IsNumber[aicc],aicc="-"],
  hq=hyp|HQ, If[!IsNumber[hq],hq="-"],
  bic=hyp|BIC, If[!IsNumber[bic],bic="-"],
  pscrit=hyp|PairedSitesCriterion,
  pscrit=IsString[pscrit]&&pscrit!="Likelihood"?"+"<>pscrit?"",
  Oprec[7,
   hyp^|{
    (Meaning->_m)=>"\n\n"<>_m<>"\n",
    (Weight->_w)=>"\n\nWeight: "<>_w<>"\n",
    (PairedSitesSupport->{_elw,_bp,_kh,_sh,_wsh,_au})=>
      "\n\nPaired Sites Tests:\n\n"
      <>"   ELW"<>pscrit<>": "<>_elw<>"\n"
      <>"   BP"<>pscrit<>":  "<>_bp <>"\n"
      <>"   KH"<>pscrit<>":  "<>_kh <>"\n"
      <>"   SH"<>pscrit<>":  "<>_sh <>"\n"
      <>"   WSH"<>pscrit<>": "<>_wsh<>"\n"
      <>"   AU"<>pscrit<>":  "<>_au <>"\n",
    (SimIC->_l)=>
     "\n\nSimIC: "<>_l<>"\n\n"
      <>"   Eff. #Param.: "<>hyp|NEffParameters<>"\n",
    (Likelihood->_l)=>
     "\n\nLikelihood: "<>_l<>"  /"<>(edgeoff?"f"?"o")<>"\n\n"
      <>"   AIC:  "<>PadRight[aic ,12]<>"    BIC: "<>PadRight[bic,12]<>"    #Sites:  "<>nsit<>"\n"
      <>"   AICc: "<>PadRight[aicc,12]<>"    HQ:  "<>PadRight[hq ,12]<>"    #Param.: "<>npar<>"\n",
    (SubstitutionModel->_m)=>"\n\nSubstitution Model:\n"<>SubstitutionModelToString[hyp|PartitionKeys,_m,hyp|OSubstitutionModel],
    (PartitionRates->{__l})=>"\n\nPartition Rates:  /"<>Sy2str[hyp|OPartitionRates]<>"\n                       "<>(hyp|FilterNames#<<" ",Swap," ">>@JoinStrings)<>Alternate[{__l}#<<Drop,"\n #">>,hyp|PartitionKeys,{__l}#<<Drop,": ">>,{__l}]@JoinStrings<>"\n",
    _->()
   },
   'JoinStrings,Apply,
   'com,Sto,
   Append[hyp^|{(Comment->_)->()},Comment->com]
  ]
 ]
>>,
Protect[AddReconstructionComments],

(*............................................................................*)

PlotTreeRaw:=Lookup[PlotTree], Protect[PlotTreeRaw],

PlotTree[
 report,
 Header->~Void~,
 Description->~Void~,
 PaperWidth->~Void~,
 PaperHeight->~Void~,
 TreeWidth->~Void~,
 PSFile->~Void~
]:=<<
 Scope[{opts,call},
  report=AsReport[report];
  opts=
   {
    If[!IsVoid[Header],Header->Header],
    If[!IsVoid[Description],Description->Description],
    If[!IsVoid[PaperWidth],PaperWidth->PaperWidth],
    If[!IsVoid[PaperHeight],PaperHeight->PaperHeight],
    If[!IsVoid[TreeWidth],TreeWidth->TreeWidth],
    If[!IsVoid[PSFile],PSFile->PSFile]
   };
  call=Put[Prepend[opts,report],0,'PlotTree];
  call=
   Append[
    call,
    PSComment->
     "%> "<>Build[call,'Hold]<>"\n%.\n"
     <>If[!IsVoid[Header],"%Header: "<>ToString[Header]<>"\n",""]
     <>If[!IsVoid[Description],"%Description: "<>ToString[Description]<>"\n",""]
     <>If[!IsVoid[PaperWidth],"%PaperWidth: "<>ToString[PaperWidth]<>"\n",""]
     <>If[!IsVoid[PaperHeight],"%PaperHeight: "<>ToString[PaperHeight]<>"\n",""]
     <>If[!IsVoid[TreeWidth],"%TreeWidth: "<>ToString[TreeWidth]<>"\n",""]
     <>Table["%Tip: "<>ToString[i]<>"\n",(=i,GetTipNames[report]=)]@JoinStrings
   ];
  call=Put[call,0,'PlotTreeRaw];
  call=Put[call,1,report#AddReconstructionComments];
  Eval[`call]
 ]
>>,
SetMask[PlotTree,"1."], Protect[PlotTree],

(*============================================================================*)

RedrawPlot[
 call,
 XRange->~Void~,
 YRange->~Void~,
 XDivision->~Void~,
 DiagramWidth->~Void~,
 DiagramHeight->~Void~,
 XLabel->~Void~,
 YLabel->~Void~,
 Joined->~Void~,
 AsBarGraph->~Void~,
 Grid->~Void~,
 Isometric->~Void~,
 Header->~Void~,
 Description->~Void~,
 PaperWidth->~Void~,
 PaperHeight->~Void~,
 PSFile->~Void~
]:=<<
 Scope[{oldopts,newopts,dlgopts},
  oldopts=Put[Remove[call,1],0,'List];
  dlgopts='{XRange,YRange,XDivision,DiagramWidth,DiagramHeight,XLabel,YLabel,
            Joined,AsBarGraph,Grid,Isometric,Header,Description,PaperWidth,PaperHeight,PSFile};
  newopts=dlgopts^|{_s=>If[!IsVoid[_s],_s->_s]};
  For[If[!IsMember[dlgopts,o|1],AppendR[newopts,o]],(=o,oldopts=)];
  call=Put[Prepend[newopts,call|1],0,call|0];
  Eval[`call]
 ]
>>,
SetMask[RedrawPlot,"1."], Protect[RedrawPlot],

(*============================================================================*)

RedrawTree[
 call,
 Midrooted->~Void~,
 FirstBranchRemoved->~Void~,
 FirstBranchIsolated->~Void~,
 MinimumEdgeLength->~Void~,
 Outgroup->~Void~,
 GroupsToSwap->~Void~,
 TipsToRemove->~Void~,
 SortedBy->~Void~,
 Selected->~Void~,
 Header->~Void~,
 Description->~Void~,
 PaperWidth->~Void~,
 PaperHeight->~Void~,
 TreeWidth->~Void~,
 PSFile->~Void~
]:=<<
 Scope[{trees,oldopts,newopts,dlgopts},
  trees=call|1;
  If[ !IsVoid[Midrooted],
   If[ Midrooted , trees=Midroot[trees] ]
  ];
  If[ !IsVoid[FirstBranchRemoved],
   If[ FirstBranchRemoved , trees=RemoveFirstBranch[trees] ]
  ];
  If[ !IsVoid[FirstBranchIsolated],
   If[ FirstBranchIsolated , trees=IsolateFirstBranch[trees] ]
  ];
  If[ !IsVoid[MinimumEdgeLength],
   trees=Collapse[trees,MinimumEdgeLength]
  ];
  If[ !IsVoid[Outgroup],
   trees=StandardizeTree[Reroot[trees,Outgroup],HoldFirst->True]
  ];
  If[ !IsVoid[GroupsToSwap],
   trees=StandardizeTree[SwapBranches[trees,GroupsToSwap|1,GroupsToSwap|2]]
  ];
  If[ !IsVoid[TipsToRemove],
   trees=StandardizeTree[RemoveTips[trees,TipsToRemove]]
  ];
  If[ !IsVoid[SortedBy],
   trees=SortHypotheses[trees,SortedBy]
  ];
  If[ !IsVoid[Selected],
   trees=Table[trees|i,(=i,Selected=)]
  ];
  oldopts=Put[Remove[call,1],0,'List];
  dlgopts='{Header,Description,PaperWidth,PaperHeight,TreeWidth,PSFile};
  newopts=dlgopts^|{_s=>If[!IsVoid[_s],_s->_s]};
  For[If[!IsMember[dlgopts,o|1],AppendR[newopts,o]],(=o,oldopts=)];
  call=Put[Prepend[newopts,trees],0,call|0];
  Eval[`call]
 ]
>>,
SetMask[RedrawTree,"1."], Protect[RedrawTree]
