Jump to content
Wikipedia The Free Encyclopedia

Module:Clade/sandbox

From Wikipedia, the free encyclopedia
This is the module sandbox page for Module:Clade (diff).
Module documentation[view] [edit] [history] [purge]
Warning This Lua module is used on approximately 9,600 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them.
This module is rated as ready for general use. It has reached a mature state, is considered relatively stable and bug-free, and may be used wherever appropriate. It can be mentioned on help pages and other Wikipedia resources as an option for new users. To minimise server load and avoid disruptive output, improvements should be developed through sandbox testing rather than repeated trial-and-error editing.

This module is designed to be used with the clade template to draw phylogenetic trees or cladograms. The new template-module combination extends the feature available with the clade and cladex templates, while replicating the behaviour of the older templates written with the template language. This module is copied from the test version Module:Sandbox/Jts1882/CladeN, which was used with the template Template:CladeN to test the features during development.

Additionally, the module has the code for template {{clade newick converter }}, which is a basic utility to convert Newick strings into nested clade structures. This is not to be used in wikipedia articles, but is a tool to help construct cladograms for inclusion in articles.

The diagram below gives an overview of the features. See the template documentation for a more detailed description of how to use the templates.

Usage

[edit ]

{{#invoke:Clade|main|style={{{style}}}}}

Examples

[edit ]

Simple examples mimicking the clade template:

Example demonstrating more advanced features of cladeN:

Example demonstrating features available:

Template:Clade
Node structure
label1

leaf 1

label2
label A

leaf A

label B

leaf B

 leaf 2 is a nested clade structure
label3

leaf 3

sublabel3
|label1=Node structure |sublabel1=(brackets)
|style1=background-color:#ffdddd;
|1={{Clade
 |label1=label1 
 |1=leaf 1 
 |label2=label2
 |grouplabel2= leaf 2 is a nested clade structure 
 |2={{Clade |style=background-color:#ffaaaa;
 |label1=label A
 |1=leaf A
 |label2=label B
 |2=leaf B
 |bar1=purple |bar2=purple 
 }}
 |label3=label3 |sublabel3=sublabel3
 |3=leaf 3 
 }}
(brackets)

 

Leaf styling
thicknessN

1 (default)

2

 line thickness

3

colorN

black (default)

red

blue

 #00ff00

stateN

solid (default)

dotted

dashed

 line styles

none

double

|label3=Leaf styling |sublabel3=(branches)
|style3=background-color:#eeeeee;
|3={{Clade
 |label1=thicknessN
 |1={{Clade
 |1=1 (default) |thickness1=1 |barbegin1=blue 
 |2=2 |thickness2=2 |bar2=blue |barlabel2= line thickness
 |3=3 |thickness3=3 |barend3=blue 
 }}
 |label2=colorN
 |2={{Clade
 |1=black (default) |color1=black 
 |2=red |color2=red 
 |3=blue |color3=blue 
 |4= #00ff00 |color4=#00ff00 
 }}
 |label3=stateN
 |3={{Clade
 |1=solid (default) |state1=solid |barbegin1=purple 
 |2=dotted |state2=dotted |bar2=purple 
 |3=dashed |state3=dashed |bar3=purple |barlabel3= line styles
 |4=none |state4=none |bar4=purple
 |5=double |state5=double |barend5=purple 
 }}
 }}
(branches)
node styling
thickness

I

J

K

color

A

B

C

state

X

Y

Z

|label4=node styling |sublabel4=(brackets)
|style4=background-color:#ffffee;
|4={{Clade
 |label1=thickness
 |1={{Clade |thickness=3
 |1=I 
 |2=J 
 |3=K 
 }}
 |label2=color
 |2={{Clade |color=red 
 |1=A
 |2=B 
 |3=C 
 }}
 |label3=state
 |3={{Clade |state=dashed
 |1=X 
 |2=Y 
 |3=Z 
 }} }}
(brackets)

 

newick
string

((lion,jaguar,leopard),((siberian,bengal)tiger,snow leopard))panthera

subtree
panthera

lion

jaguar

leopard

tiger

siberian

bengal

snow leopard

 expanded Newick string
|label6=newick 
|style6=background-color:#ddffdd;
|6={{Clade
 |label1=string
 |1=((lion,jaguar,leopard),((siberian,bengal)tiger,snow leopard))panthera 
 |label2=subtree 
 |grouplabel2= expanded Newick string 
 |grouplabelstyle2=vertical-align: middle;
 |2={{Clade |style=background-color:#ccffcc;
 |newick1=((lion,jaguar,leopard),((siberian,bengal)tiger,snow leopard))panthera
 |1=Leaf1 (redundant if newick1 set) 
 }}
 }}
paraphyly example 
clade  label a paraphyletic group within a clade
|label7=paraphyly example  |style7=background-color:#ffeeff;
|7={{Clade
 |1={{Clade
 |1=[[Geraniales]] 
 |2=[[Myrtales]] 
 }}
 |grouplabel2= label a paraphyletic group within a clade 
 |label2=clade
 |style2=background-color:#ffddff;
 |2={{Clade
 |1=[[Crossosomatales]] |barbegin1=purple
 |2={{Clade
 |1=[[Picramniales]] |bar1=purple
 |2={{Clade
 |1=[[Sapindales]] |bar1=purple 
 |2={{Clade
 |1=[[Huerteales]] |bar1=purple
 |2={{Clade
 |1=[[Brassicales]] |barend1=purple
 |2=[[Malvales]] |style2=background-color:#ff99ff;
 }} }} }} }} }} }}

A cladogram illustrating clade features.


Subpages

[edit ]
The above documentation is transcluded from Module:Clade/doc. (edit | history)
Editors can experiment in this module's sandbox (edit | diff) and testcases (create) pages.
Add categories to the /doc subpage. Subpages of this module.
 --[[NOTE: this module contains functions for generating the table structure of the clade tree: 

 The main function is called by the template using the {{invoke}} instruction; the three main functions are:
 		p.main(frame) - opens and closes table, loops through the children of node, main is invoked once and controls the rest, calling ...
 		p.addTaxon(childNumber, nodeLeaf) - the nuts and bolts; code dealing with each child node
 		p.addLabel(childNumber) - adds the label text

 		now uses templatestyles
 ]]
 require('strict')
 localp={}
 localpargs={}-- parent arguments
 locallastNode=0
 localnodeCount=0
 localcladeCount=0
 localleafCount=0
 localtemplateStylesCount=0
 localinfoOutput
 localreverseClade=false

 --[[============================== main function ===========================
 -- main function, which will generate the table structure of the tree

 Test version:
 Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|main|style={{{STYLE|}}} }}
 Template:CladeN

 Release version:
 Usage: {{#invoke:Clade|main|style={{{STYLE|}}} }}
 Template:Clade
 ]]

 functionp.main(frame)

 localcladeString=""
 localmaxChildren=20-- was 17 in the clade/cladex templates
 localchildNumber=0
 localchildCount=0-- number of leaves in the clade (can use to set bottom of bracket in addTaxon()
 localtotalCount=0

 pargs=frame:getParent().args-- parent arguments

 infoOutput=p.getCladeTreeInfo()-- get info about clade structure, e.g. lastNode (last |N= child number)

 --[[ add the templatestyles tag conditionally to reduce expansion size (currently diabled)
 		when added to every clade table, it increases post‐expand include size significantly
 		 e.g. the Neosuchia page (or test version) is increase by about 8% (672 bytes each)
 				if template styles added to all pages there are 133 stripmarkers 
 				with cladeCount==1 condition, this is reduced to 34
 		however cladeCount==1 condition interfers with fix for additional line due to parser bug T18700
 		killing the strip markers also removes backlinks to references using citation templates 
 	--]]
 --cladeString =mw.text.killMarkers( cladeString ) -- also kills off strip markers using citation templates
 --cladeString = mw.text.unstrip(cladeString)
 --if cladeCount==1 then
 cladeString=cladeString..frame:extensionTag('templatestyles','',
 {src="Template:Clade/sandbox/styles.css"})..'\n'
 --end	

 localtableStyle=frame.args.styleor""

 iftableStyle~=""then
 tableStyle=' style="'..tableStyle..'"'-- include style= in string to suppress empty style elements
 end

 reverseClade=frame.args.reverseorpargs.reverseorfalse-- a global
 --ENFORCE GLOBAL FOR DEVELOPMENT
 --reverseClade = true

 localcaptionName=pargs['caption']or""
 localcaptionStyle=pargs['captionstyle']or""

 -- add an element to mimick nowiki WORKS BUT DISABLE FOR DEMO PURPOSES
 --cladeString = '<p class="mw-empty-elt"></p>\n'

 -- open table	
 -- (border-collapse causes problems (see talk) -- cladeString = cladeString .. '{| style="border-collapse:collapse;border-spacing:0;margin:0;' .. tableStyle .. '"'
 -- (before CSS styling) -- cladeString = cladeString .. '{| style="border-spacing:0;margin:0;' .. tableStyle .. '"'
 cladeString=cladeString..'{|class="clade"'..tableStyle

 -- add caption
 ifcaptionName~=""then
 cladeString=cladeString..'\n|+ style="'..captionStyle..'"|'..captionName
 end


 localmoreNeeded=true
 childNumber=0
 --lastNode = 0

 --[[get child elements (add more rows for each child of node; each child is two rows)
 		the function addTaxon is called to add the rows for each child element;
 		each child add two rows: the first cell of each row contains the label or sublabel (below the line label), respectively;
 		the second cell spans both rows and contains the leaf name or a new clade structure
 		a third cell on the top row is sometimes added to contain a group to the right
 	]]

 -- main loop
 whilechildNumber<lastNodedo-- use the last number determined in the preprocessing

 childNumber=childNumber+1-- so we start with 1
 localnodeLeaf=pargs[tostring(childNumber)]or""-- get data from |N=
 localnodeLabel=pargs['label'..tostring(childNumber)]or""-- get data from |labelN=


 localnewickString=pargs['newick'..tostring(childNumber)]or""-- get data from |labelN=
 locallistString=pargs['list'..tostring(childNumber)]or""

 iflistString~=""then
 cladeString=cladeString..'\n'..p.addTaxon(childNumber,p.list(0,listString),nodeLabel,lastNode)
 elseifnewickString~=""then-- if using a newick string instead of a clade structure
 newickString=p.processNewickString(newickString,childNumber)
 ifnodeLabel==""then-- use labelN by default, otherwise use root name from Newick string
 nodeLabel=p.getNewickOuterterm(newickString)-- need to use terminal part of newick string for label
 end
 cladeString=cladeString..'\n'..p.addTaxon(childNumber,p.newick(0,newickString),nodeLabel,lastNode)
 --lastNode=lastNode+1 -- there is a counting problem with the newickstring
 elseifnodeLeaf~=""then-- if the node contains a leaf name or clade structue
 --if reverseClade2 then
 --	cladeString = cladeString .. '\n' .. p.addTaxonReverse(childNumber, nodeLeaf, nodeLabel, lastNode)
 --else
 cladeString=cladeString..'\n'..p.addTaxon(childNumber,nodeLeaf,nodeLabel,lastNode)
 --end
 end
 end

 localfooterText=pargs['footer']or""
 localfooterStyle=pargs['footerstyle']or""

 iffooterText~=""then
 cladeString=cladeString..'\n|-style="'..footerStyle..'"\n|colspan="2"|<p>'..footerText..'</p>||'
 -- note the footer causes a problem with tr:last-child so need either
 -- (1) use <tfoot> but it is not allowed or incompatable
 --		 cladeString = cladeString .. '<tfoot><tr style="' .. footerStyle .. '"><td colspan="2"><p>' .. footerText .. '</p></td></tr></tfoot>'
 -- (2) always add footer and use nth:last-child(2) but is this backwards compatible
 -- (3) if footer= set the style inline for the last sublabel row (more a temp fix)
 -- (4) set class for first and last element (DONE. Also works well with reverse class)
 end

 -- close table (wikitext to close table)
 cladeString=cladeString..'\n|}'

 cladeString=p.addSubTrees(cladeString)-- add subtrees

 returncladeString
 --return '<div style="width:auto;">\n' .. cladeString .. '</div>'
 end

 --[[ =============================function to add subtrees ========================================== ]]

 functionp.addSubTrees(cladeString)

 --local pargs = mw.getCurrentFrame():getParent().args 

 localsuffix={[1]="A",[2]="B",[3]="C",[4]="D",[5]="E",[6]="F",[7]="G",[8]="H",[9]="I",[10]="J",
 [11]="K",[12]="L",[13]="M",[14]="N",[15]="O",[16]="P",[17]="Q",[18]="R",[19]="S",[20]="T",
 [21]="U",[22]="V",[23]="W",[24]="X",[25]="Y",[26]="Z"}
 fori=1,26,1do
 localsubclade=pargs['subclade'..suffix[i]]
 localtarget=pargs['target'..suffix[i]]or"SUBCLADE_"..suffix[i]
 ifsubcladethen
 ifstring.find(cladeString,target)then
 cladeString=string.gsub(cladeString,target,subclade)
 end
 end
 end
 returncladeString
 end
 --[[ -------------------------------------- p.addTaxon() ------------------------------------------
 	 function to add child elements
 	 adds wikitext for two rows of the table for each child node, 
 	 	the first cell in each is used for the label and sublabel; the bottom border forms the horizonal branch of the bracket
 	 	the second cell is used for the leafname or a transcluded clade structure and spans both rows
 	 note that the first and last child nodes need to be handled differently from the middle elements
 		 the middle elements (|2, |3 ...) use a left border to create the vertical line of the bracket
 		 the first child element doesn't use a left border for the first cell in the top row (as it is above the bracket)
 		 the last child doesn't use a left border for the first cell in the second row (as it is below the bracket)
 ]]
 functionp.addTaxon(childNumber,nodeLeaf,nodeLabel,lastNode)

 --[[ get border formating parameters (i.e. color, thickness, state)
 			nodeParameters for whole bracket (unnumbered, i.e. color, thickness, state) apply to whole node bracket, 
 			branchParameters apply to individual branches
 			the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN
 			the node parameters have no number, e.g. |color, |thickness, |state
 	]]
 localnodeColor=pargs['color']or""-- don't set default to allow green on black gadget
 localnodeThickness=tonumber(pargs['thickness'])or1
 localnodeState=pargs['state']or"solid"
 -- get border formating parameters for branch (default to global nodeParameters)
 localbranchColor=pargs['color'..tostring(childNumber)]ornodeColor
 localbranchThickness=tonumber(pargs['thickness'..tostring(childNumber)])ornodeThickness
 localbranchState=pargs['state'..tostring(childNumber)]ornodeState
 ifbranchState=='double'then
 ifbranchThickness<2thenbranchThickness=3end-- need thick line for double
 end

 localbranchStyle=pargs['style'..tostring(childNumber)]or""
 localbranchLength=pargs['length']orpargs['length'..tostring(childNumber)]or""

 -- the left border takes node parameters, the bottom border takes branch parameters
 -- this has coding on the colours for green on black
 localbottomBorder=tostring(branchThickness)..'px '..branchState..(branchColor~=""and' '..branchColoror'')
 localleftBorder=tostring(nodeThickness)..'px '..nodeState..(nodeColor~=""and' '..nodeColoror'')

 --The default border styles are in the CSS (styles.css)
 --	the inline styling is applied when thickness, color or state are change

 localuseInlineStyle=false
 -- use inline styling non-default color, line thickness or state have been set
 ifbranchColor~=""orbranchThickness~=1orbranchState~="solid"then
 useInlineStyle=true
 end


 -- variables for right hand bar or bracket
 --local barColor = "" 
 localbarRight=pargs['bar'..tostring(childNumber)]or"0"
 localbarBottom=pargs['barend'..tostring(childNumber)]or"0"
 localbarTop=pargs['barbegin'..tostring(childNumber)]or"0"
 localbarLabel=pargs['barlabel'..tostring(childNumber)]or""
 localgroupLabel=pargs['grouplabel'..tostring(childNumber)]or""
 localgroupLabelStyle=pargs['grouplabelstyle'..tostring(childNumber)]or""
 locallabelStyle=pargs['labelstyle'..tostring(childNumber)]or""
 localsublabelStyle=pargs['sublabelstyle'..tostring(childNumber)]or""

 --replace colours with format string; need right bar for all three options
 ifbarRight~="0"thenbarRight="2px solid "..barRightend
 ifbarTop~="0"thenbarRight="2px solid "..barTopend
 ifbarBottom~="0"thenbarRight="2px solid "..barBottomend
 ifbarTop~="0"thenbarTop="2px solid "..barTopend
 ifbarBottom~="0"thenbarBottom="2px solid "..barBottomend


 -- now construct wikitext 
 localcladeString=''
 localstyleString=''
 localborderStyle=''-- will be used if border color, thickness or state is to be changed
 localclassString=''
 localreverseClass=''
 localwidthClass=''

 -- class to add if using reverse (rtl) cladogram; 
 ifreverseCladethenreverseClass=' reverse'end

 -- (1) wikitext for new row
 --cladeString = cladeString .. '\n|-'

 -- (2) now add cell with label

 ifuseInlineStylethen
 ifchildNumber==1then
 borderStyle='border-left:none;border-right:none;border-bottom:'..bottomBorder..';'
 --borderStyle = 'border-bottom:' .. bottomBorder .. ';' 
 else-- for 2-17
 ifreverseCladethen
 borderStyle='border-left:none;border-right:'..leftBorder..';border-bottom:'..bottomBorder..';'
 else
 borderStyle='border-left:'..leftBorder..';border-bottom:'..bottomBorder..';'
 end
 end
 end

 ifuseInlineStyleorbranchStyle~=''orbranchLength~=""orlabelStyle~=""then
 localbranchLengthStyle=""
 ifbranchLength~=""then
 ifchildNumber==1then
 branchLengthStyle='width:'..branchLength..';'-- add width to first element
 end
 --if childNumber > 1 then prefix = 'max-' end
 branchLengthStyle=branchLengthStyle--= prefix .. 'width:' .. branchLength .. ';' 
 ..'max-width:'..branchLength..';'
 ..'padding:0em;'-- remove padding to make calculation easier
 -- following moved to styles.css
 --				.. 'white-space:nowrap'
 --				.. 'overflow:hidden;'	-- clip labels longer than the max-width
 --				.. 'text-overflow:clip;' -- ellipsis;'
 widthClass=" clade-fixed-width"
 end
 styleString='style="'..borderStyle..branchLengthStyle..branchStyle..labelStyle..'"'
 end

 ifchildNumber==1then
 classString='class="clade-label first'..widthClass..'" '-- add class "first" for top row
 else
 classString='class="clade-label'..reverseClass..widthClass..'" '-- add "reverse" class if ltr cladogram
 end

 -- wikitext for cell with label
 locallabelCellString='\n|'..classString..styleString..'|'..p.addLabel(childNumber,nodeLabel)-- p.addLabel(nodeLabel)

 --cladeString = cladeString .. labelCellString

 ---------------------------------------------------------------------------------
 -- (3) add cell with leaf (which may be a table with transluded clade content)

 ifbarRight~="0"then
 ifreverseCladethen-- we want the bar on the left
 styleString=' style="border-left:'..barRight..';border-bottom:'..barBottom..';border-top:'..barTop..';'..branchStyle..'"'
 else
 styleString=' style="border-right:'..barRight..';border-bottom:'..barBottom..';border-top:'..barTop..';'..branchStyle..'"'
 end
 elseif(branchStyle~='')then
 styleString=' style="'..branchStyle..'"'
 else
 styleString=''-- use defaults in styles.css
 end

 classString='class="clade-leaf'..reverseClass..'"'

 --[[note: the \n causes plain leaf elements get wrapped in <p> with style="margin:0.4em 0 0.5em 0;" 
 			 this adds spacing to rows, but is set by defaults rather than the clade template
 			 it also means there are two newlines when it is a clade structure (which might explain some past issues)
 	]]
 localcontent='\n'..nodeLeaf-- the newline is not necessary, but keep for backward compatibility

 -- test using image parameter
 localimage=pargs['image'..tostring(childNumber)]or""

 ifimage~=""then
 --content = content .. image -- basic version
 content='\n{|class=clade style=width:auto'--defaults to width:100% because of class "clade"
 ..'\n|class=clade-leaf|\n'..nodeLeaf
 ..'\n|class=clade-leaf|\n'..image
 ..'\n|}'
 -- note: the classes interfere with the node counter, so try simpler version with style
 content='\n{|style=width:100%;border-spacing:0'--width:auto is "tight"; 100% needed for image alignment
 ..'\n|style=border:0;padding:0|\n'..nodeLeaf
 ..'\n|style=border:0;padding:0|\n'..image
 ..'\n|}'
 end


 -- wikitext for leaf cell (note: nodeLeaf needs to be on newline if new wikitable)
 --						 but that is no longer the case (newline is now forced)
 --						 the newline wraps plain leaf terminals in <P> with vertical padding (see above)

 --local leafCellString = '\n|rowspan=2 ' .. classString .. styleString .. ' |\n' .. content -- the new line causes <p> wrapping for plain leaf terminals
 localleafCellString='\n|rowspan=2 '..classString..styleString..' |'..content

 --cladeString = cladeString .. leafCellString


 -------------------------------------------
 -- (4) stuff for right-hand bracket labels

 classString='class="clade-bar'..reverseClass..'"'

 localbarLabelCellString=''
 ifbarRight~="0"andbarLabel~=""then
 barLabelCellString='\n|rowspan=2 '..classString..' |'..barLabel
 else-- uncomment following line to see the cell structure
 --barLabelCellString = '\n|rowspan=2 ' .. classString .. ' |' .. 'BL'
 end

 ifgroupLabel~=""then
 barLabelCellString=barLabelCellString..'\n|rowspan=2 '..classString..' style="'..groupLabelStyle..'" |'..groupLabel
 else-- uncomment following line to see the cell structure
 --barLabelCellString = barLabelCellString .. '\n|rowspan=2 ' .. classString .. '" |' .. 'GL' 
 end

 --cladeString = cladeString .. barLabelCellString

 -------------------------------------------------------------------------------------
 -- (5) add second row (only one cell needed for sublabel because of rowspan=2); 
 --	 note: earlier versions applied branch style to row rather than cell
 --		 for consistency, it is applied to the sublabel cell as with the label cell

 --cladeString = cladeString .. '\n|-' 

 -----------------------------------
 -- (6) add cell containing sublabel

 localsubLabel=pargs['sublabel'..tostring(childNumber)]or""-- request in addLabel

 -- FOR TESTING: use subLabel for annotating the clade structues to use structure information (DEBUGGIING ONLY)
 --if childNumber==lastNode then subLabel= infoOutput end
 -- END TESTING

 borderStyle=''
 styleString=''
 ifuseInlineStylethen
 ifchildNumber==lastNodethen-- if childNumber==lastNode we don't want left border, otherwise we do
 borderStyle='border-right:none;border-left:none;'
 elseifreverseCladethen
 borderStyle='border-left:none;border-right:'..leftBorder..';'
 else
 borderStyle='border-right:none;border-left:'..leftBorder..';'
 end
 end
 ifborderStyle~=''orbranchStyle~=''orbranchLength~=''orsublabelStyle~=""then
 localbranchLengthStyle=""
 ifbranchLength~=""then
 ifchildNumber==1then
 branchLengthStyle='width:'..branchLength..';'-- add width to first element
 end
 --if childNumber > 1 then prefix = 'max-' end
 branchLengthStyle=branchLengthStyle--= prefix .. 'width:' .. branchLength .. ';' 
 ..'max-width:'..branchLength..';'
 ..'padding:0em;'-- remove padding to make calculation easier
 end
 styleString='style="'..borderStyle..branchLengthStyle..branchStyle..sublabelStyle..'"'
 --styleString = ' style="' .. borderStyle .. branchStyle .. sublabelStyle .. '"'
 end

 --local sublabel = p.addLabel(childNumber,subLabel)

 ifchildNumber==lastNodethen
 classString='class="clade-slabel last'..widthClass..'" '
 else
 classString='class="clade-slabel'..reverseClass..widthClass..'" '
 end
 localsublabelCellString='\n|'..classString..styleString..'|'..p.addLabel(childNumber,subLabel)

 --cladeString = cladeString .. sublabelCellString

 -- constuct child element wikitext
 ifreverseCladethen
 cladeString=cladeString..'\n|-'
 cladeString=cladeString..barLabelCellString
 cladeString=cladeString..leafCellString
 cladeString=cladeString..labelCellString
 cladeString=cladeString..'\n|-'
 cladeString=cladeString..sublabelCellString
 else
 cladeString=cladeString..'\n|-'
 cladeString=cladeString..labelCellString
 cladeString=cladeString..leafCellString
 cladeString=cladeString..barLabelCellString
 cladeString=cladeString..'\n|-'-- add second row (only one cell needed for sublabel because of rowspan=2);
 cladeString=cladeString..sublabelCellString
 end

 returncladeString
 end



 --[[ adds text for label or sublabel to a cell
 ]]
 functionp.addLabel(childNumber,nodeLabel)

 --local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or ""

 --local firstChars = string.sub(nodeLabel, 1,2) -- get first two characters; will be {{ if no parameter (for Old method?)
 --if firstChars == "{{{" or nodeLabel == "" then
 ifnodeLabel==""then
 -- Has to be some content for layout, but can use CSS to add it instead.
 return''
 else
 -- spaces can cause wrapping and can break tree structure, hence use span with nowrap class
 --return '<span class="nowrap">' .. nodeLabel .. '</span>'

 -- a better method for template expansion size is to replace spaces with nonbreaking spaces
 -- however, there is a problem if labels have a styling element (e.g. <span style= ..., <span title= ...)
 localstylingElementDetected=false
 ifnodeLabel:find("span ")ornodeLabel:find(" style")then
 stylingElementDetected=true
 end
 --TODO test following alternative
 --if nodeLabel:find( "%b<>") then stylingElementDetected = true end 

 ifstylingElementDetected==truethen
 return'<div style=display:inline class=nowrap>'..nodeLabel..'</div>'
 else
 localnowrapString=string.gsub(nodeLabel," ","&nbsp;")-- replace spaces with non-breaking space
 ifnotnowrapString:find("UNIQ.-QINU")andnotnowrapString:find("%[%[.-%]%]")then-- unless a strip marker
 nowrapString=string.gsub(nowrapString,"-","&#8209;")-- replace hyphen with non-breaking hyphen (&#8209;)
 end
 returnnowrapString
 end
 end
 end



 --[[=================== Newick string handling function =============================
 ]]
 functionp.getNewickOuterterm(newickString)
 returnstring.gsub(newickString,"%b()","")-- delete parenthetic term
 end

 functionp.newick(count,newickString)
 --start table
 --'{| style="border-collapse:collapse;border-spacing:0;border:0;margin:0;'
 localcladeString='{|class=clade '
 count=count+1

 localj,k
 j,k=string.find(newickString,'%(.*%)')-- find location of outer parenthesised term
 localinnerTerm=string.sub(newickString,j+1,k-1)-- select content in parenthesis
 localouterTerm=string.gsub(newickString,"%b()","")-- delete parenthetic term
 ifouterTerm=='panthera'thenouterTerm="x"end-- how is this set in local variable for inner nodes?

 outerTerm=tostring(count)

 -- need to remove commas in bracket terms before split, so temporarily replace commas between brackets
 localinnerTerm2=string.gsub(innerTerm,"%b()",function(n)
 returnstring.gsub(n,",%s*","XXX")-- also strip spaces after commas here
 end)
 --cladeString = cladeString .. '\n' .. p.addTaxon(1, innerTerm2, "")

 -- this needs a lastNode variable
 locals=p.strsplit(innerTerm2,",")
 --oldLastNode=lastNode
 locallastNode=table.getn(s)-- number of child branches
 locali=1
 whiles[i]do
 localrestoredString=string.gsub(s[i],"XXX",",")-- convert back to commas
 --restoredString = s[i]
 localouterTerm=string.gsub(restoredString,"%b()","")
 ifstring.find(restoredString,'%(.*%)')then
 --cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "x")
 cladeString=cladeString..'\n'..p.addTaxon(i,p.newick(count,restoredString),outerTerm,lastNode)
 -- p.addTaxon(2, p.newick(count,newickString2), "root")
 else
 cladeString=cladeString..'\n'..p.addTaxon(i,restoredString,"",lastNode)--count)
 end
 i=i+1
 end
 -- lastNode=oldLastNode

 -- close table
 --cladeString = cladeString .. '\n' .. '| style="border: 0; padding: 0; vertical-align: top;" | <br/> \n|}'
 --cladeString = cladeString .. '\n| <br/> \n|}' -- is this legacy for extra sublabel?
 cladeString=cladeString..'\n|}'
 returncladeString
 end
 -- emulate a standard split string function
 -- why not use mw.text.split(s, sep)?
 functionp.strsplit(inputstr,sep)
 ifsep==nilthen
 sep="%s"
 end
 localt={}
 locali=1
 forstrinstring.gmatch(inputstr,"([^"..sep.."]+)")do
 t[i]=str
 i=i+1
 end
 returnt
 end


 -- =================== experimental Newick to clade parser function =============================

 --[[Function of convert Newick strings to clade format

 Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|newickConverter|newickstring={{{NEWICK_STRING}}} }}
 ]]
 functionp.newickConverter(frame)

 localnewickString=frame.args['newickstring']orframe.args['newick']orpargs['newickstring']orpargs['newick']

 --if newickString == '{{{newickstring}}}' then return newickString end

 newickString=p.processNewickString(newickString,"")-- "childNumber")


 -- show the Newick string
 localcladeString=''
 locallevelNumber=1-- for depth of iteration
 localchildNumber=1-- number of sister elements on node (always one for root)

 -- converted the newick string to the clade structure
 cladeString=cladeString..'{{clade'
 cladeString=cladeString..p.newickParseLevel(newickString,levelNumber,childNumber)
 cladeString=cladeString..'\r}}'

 localresultString=''
 localoption=pargs['option']or''
 ifoption=='tree'then
 --show the transcluded clade diagram
 resultString=cladeString
 else
 -- show the Newick string
 resultString='<pre>'..newickString..'</pre>'
 -- show the converted clade structure
 resultString=resultString..'<pre>'..cladeString..'</pre>'
 end
 --resultString = frame:expandTemplate{ title = 'clade', frame:preprocess(cladeString) }

 returnresultString
 end

 --[[ Parse one level of Newick string
 	 This function receives a Newick string, which has two components
 	 1. the right hand term is a clade label: |labelN=labelname
 	 2. the left hand term in parenthesis has common delimited child nodes, each of which can be
 		 i. a taxon name which just needs: |N=leafname 
 		 ii. a Newick string which needs further processing through reiteration
 ]]
 functionp.newickParseLevel(newickString,levelNumber,childNumber)


 localcladeString=""
 localindent=p.getIndent(levelNumber)
 --levelNumber=levelNumber+1

 localj=0
 localk=0
 j,k=string.find(newickString,'%(.*%)')-- find location of outer parenthesised term
 localinnerTerm=string.sub(newickString,j+1,k-1)-- select content in parenthesis
 localouterTerm=string.gsub(newickString,"%b()","")-- delete parenthetic term

 cladeString=cladeString..indent..'|label'..childNumber..'='..outerTerm
 cladeString=cladeString..indent..'|'..childNumber..'='..'{{clade'

 levelNumber=levelNumber+1
 indent=p.getIndent(levelNumber)

 -- protect commas in inner parentheses from split; temporarily replace commas between parentheses
 localinnerTerm2=string.gsub(innerTerm,"%b()",function(n)
 returnstring.gsub(n,",%s*","XXX")-- also strip spaces after commas here
 end)

 locals=p.strsplit(innerTerm2,",")
 locali=1
 whiles[i]do
 localrestoredString=string.gsub(s[i],"XXX",",")-- convert back to commas

 localouterTerm=string.gsub(restoredString,"%b()","")
 ifstring.find(restoredString,'%(.*%)')then
 --cladeString = cladeString .. indent .. '|y' .. i .. '=' .. p.newickParseLevel(restoredString,levelNumber+1,i) 
 cladeString=cladeString..p.newickParseLevel(restoredString,levelNumber,i)
 else
 cladeString=cladeString..indent..'|'..i..'='..restoredString--.. '(level=' .. levelNumber .. ')'
 end
 i=i+1
 end
 --	end -- end splitting of strings

 cladeString=cladeString..indent..'}}'
 returncladeString
 end

 functionp.getIndent(levelNumber)
 localindent="\r"
 localextraIndent=pargs['indent']ormw.getCurrentFrame().args['indent']or0

 indent=indent..string.rep(" ",extraIndent)..string.rep(" ",levelNumber-1)-- extra indent to make aligning compound trees easier

 returnindent
 end

 functionp.newickstuff(newickString)


 end
 functionp.processNewickString(newickString,childNumber)

 localmaxPatterns=5
 locali=0
 localpargs=pargs
 localpattern=pargs['newick'..tostring(childNumber)..'-pattern']-- unnumbered option for i = 1
 localreplace=pargs['newick'..tostring(childNumber)..'-replace']

 whilei<maxPatternsdo
 i=i+1
 pattern=patternorpargs['newick'..tostring(childNumber)..'-pattern'..tostring(i)]
 replace=replaceorpargs['newick'..tostring(childNumber)..'-replace'..tostring(i)]or""

 ifpatternthen
 newickString=string.gsub(newickString,pattern,replace)
 end
 pattern=nil;replace=nil
 end
 newickString=string.gsub(newickString,"_"," ")-- replace underscore with space
 returnnewickString
 end
 ------------------------------------------------------------------------------------------


 functionp.test2(target)
 localtarget="User:Jts1882/sandbox/templates/Template:Passeroidea"
 localresult=mw.getCurrentFrame():expandTemplate{title=target,args={['style']=''}}
 returnresult
 end
 -------------------------------------------------------------------------------------------

 -----------------------------------------------------------------------------------------------

 --[[function getCladeTreeInfo()
 		this preprocessing loop gets information about the whole structure (number of nodes, leaves etc)
 		it makes a redundant calls to the templates through transclusion, but doen't affect the template depths; 
 		it provides the global lastNode that is used to limit the main while loop
 --]]
 functionp.getCladeTreeInfo()

 -- enable proprocessing loop
 localchildNumber=0
 localchildCount=0
 localmaxChildren=20

 --info veriables (these are global for now)
 nodeCount=0
 cladeCount=0
 leafCount=0

 whilechildNumber<maxChildrendo-- preprocessing loop
 childNumber=childNumber+1-- so we start with 1
 localnodeLeaf,data=pargs[tostring(childNumber)]or""-- get data from |N=
 localnewickString=pargs['newick'..tostring(childNumber)]or""-- get data from |labelN=
 locallistString=pargs['list'..tostring(childNumber)]or""-- get data from |labelN=
 ifnewickString~=""ornodeLeaf~=""orlistString~=""then
 --if nodeLeaf ~= "" then 
 childCount=childCount+1-- this counts child elements in this clade 
 --[[]
 			for i in string.gmatch(nodeLeaf, "||rowspan") do -- count number of rows started (transclusion)
  				nodeCount = nodeCount + 1
 	 		end
 			for i in string.gmatch(nodeLeaf, '{|class="clade"') do -- count number of tables started (transclusion)
  				cladeCount = cladeCount + 1
 	 		end
 	 		]]
 -- count occurences of clade structure using number of classes used and add to counters
 local_,nClades=string.gsub(nodeLeaf,'class="clade"',"")
 local_,nNodes=string.gsub(nodeLeaf,'class="clade%-leaf"',"")
 cladeCount=cladeCount+nClades
 nodeCount=nodeCount+nNodes

 lastNode=childNumber-- this gets the last node with a valid entry, even when missing numbers
 end
 end
 --]]	
 -- nodes can be either terminal leaves or a clade structure (table)
 --	note: should change class clade-leaf to clade-node to reflect this
 nodeCount=nodeCount-- number of nodes (class clade-leaf) passed down by transduction 
 +childCount+1-- plus one for current clade and one for each of its child element
 cladeCount=cladeCount+1-- number of clade structure tables passed down by transduction (plus one for current clade)
 leafCount=nodeCount-cladeCount-- number of terminal leaves (equals height of cladogram)

 -- output for testing: number of clades / total nodes / terminal nodes (=leaves)
 --					 (internal nodes)				 (cladogram height)
 infoOutput='<small>['..cladeCount..'/'..nodeCount..'/'..leafCount..']</small>'

 returninfoOutput

 end

 functionp.showClade(frame)
 --local code = frame.args.code or ""
 localcode=frame:getParent().args['code2']or""

 --return code 
 --return mw.text.unstrip(code)

 --local test = "<pre>Hello</pre>"
 --return string.sub(test,6,-7)

 localo1=frame:getParent():getArgument('code2')
 returno1:expand()

 --return string.sub(code,2,-1)			 -- strip marker 127円'"`UNIQ--tagname-8 hex digits-QINU`"'127円
 --return frame:preprocess(string.sub(code,3))
 end


 functionp.firstToUpper(str)
 return(str:gsub("^%l",string.upper))
 end
 --[[ function to generate cladogram from a wikitext-like list
 		 - uses @ instead of * because we don't want wikitext processed and nowiki elements are passed as stripmarkers (?)
 ]]
 functionp.list(count,listString)

 localcladeString=""
 --count = count+1
 locali=1
 localchild=1
 locallastNode=0--table.getn(list) -- number of child branches (potential)
 locallistChar="@"

 iflistString:find("UNIQ.-QINU")then-- if wrapped in nowiki
 mw.addWarning("Stripping content in nowiki tags")
 listString=mw.text.trim(mw.text.unstripNoWiki(listString))
 end
 ifstring.match(listString,"^*",1)then
 listChar="*"
 end

 locallist=mw.text.split(listString,"\n")

 cladeString=cladeString..'{| class="clade" '

 whilelist[i]do
 list[i]=list[i]:gsub("^"..listChar,"")-- strip the first @ or *
 list[i]=mw.text.trim(list[i])-- trim 

 ifnotstring.match(list[i],"^"..listChar,1)then-- count children at this level (not beginning wiht @/*)
 lastNode=lastNode+1
 end
 i=i+1
 end

 i=1
 whilelist[i]do

 --[[ pseudocode: 
 			 if next value begins with @ we have a subtree, 
 				which must be recombined and past iteratively
 			 else we have a simple leaf
 		]]

 -- if the next value begins with @, we have a subtree which should be recombined
 iflist[i+1]andstring.match(list[i+1],"^"..listChar,1)then

 locallabel=list[i]
 i=i+1
 localrecombined=list[i]
 whilelist[i+1]andstring.match(list[i+1],"^"..listChar,1)do
 recombined=recombined.."\n"..list[i+1]
 i=i+1
 end
 --cladeString = cladeString .. '\n' .. p.addTaxon(child, recombined, label, lastNode) 
 cladeString=cladeString..'\n'..p.addTaxon(child,p.list(count,recombined),label,lastNode)
 else
 cladeString=cladeString..'\n'..p.addTaxon(child,list[i],"",lastNode)
 end
 i=i+1
 child=child+1
 end


 cladeString=cladeString..'\n|}'

 mw.addWarning("WARNING. This is a test feature only.")
 returncladeString
 end
 -- =================== experimental wikitext list to clade parser function =============================

 --[[Function of convert wikitext lists to clade format

 Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|listConverter|list={{{WIKITEXT_LIST}}} }}
 ]]
 functionp.cladeConverter(frame)
 pargs=frame:getParent().args

 ifframe.args['list']orpargs['list']then
 returnp.listConverter(frame)
 elseifframe.args['newickstring']orframe.args['newick']orpargs['newickstring']orpargs['newick']then
 returnp.newickConverter(frame)
 else
 localmessage="Conversion needs wikitext list or newick string in parameters ''list'' or ''newick'' respectively"
 mw.addWarning(message)
 returnmessage
 end
 end
 functionp.listConverter(frame)

 locallistString=frame.args['list']orpargs['list']

 -- show the list string
 localcladeString=''
 locallevelNumber=1-- for depth of iteration
 localchildNumber=1-- number of sister elements on node (always one for root)
 localindent=p.getIndent(levelNumber)
 -- converted the newick string to the clade structure
 cladeString=cladeString..indent..'{{clade'
 cladeString=cladeString..p.listParseLevel(listString,levelNumber,childNumber)
 --cladeString = cladeString .. '\r}}' 

 localresultString=''
 localoption=pargs['option']or''
 ifoption=='tree'then
 --show the transcluded clade diagram
 resultString=cladeString
 else
 -- show the wikitext list string
 resultString='<pre>'..listString..'</pre>'
 -- show the converted clade structure
 resultString=resultString..'<pre>'..cladeString..'</pre>'
 end
 --resultString = frame:expandTemplate{ title = 'clade', frame:preprocess(cladeString) }

 returnresultString
 end

 functionp.listParseLevel(listString,levelNumber,childNumber)

 localcladeString=""
 localindent=p.getIndent(levelNumber)
 levelNumber=levelNumber+1

 localnowiki=false
 iflistString:find("UNIQ.-QINU")then-- if wrapped in nowiki
 mw.addWarning("Stripping content in nowiki tags")
 listString=mw.text.trim(mw.text.unstripNoWiki(listString))
 nowiki=true
 end
 locallistChar="@"
 ifstring.match(listString,"^*",1)then
 listChar="*"
 end

 locallist=mw.text.split(listString,"\n")
 locali=1
 localchild=1
 locallastNode=0

 whilelist[i]do
 list[i]=list[i]:gsub("^"..listChar,"")-- strip the first @

 ifnotstring.match(list[i],"^"..listChar,1)then-- count children at this level (not beginning wiht @)
 lastNode=lastNode+1
 end
 i=i+1
 end
 i=1

 whilelist[i]do

 --[[ pseudocode: 
 			 if next value begins with @ we have a subtree, 
 				which must be recombined and past iteratively
 			 else we have a simple leaf
 		]]

 -- if the next value begins with @, we have a subtree which should be recombined
 iflist[i+1]andstring.match(list[i+1],"^"..listChar,1)then

 locallabel=list[i]
 i=i+1
 localrecombined=list[i]
 whilelist[i+1]andstring.match(list[i+1],"^"..listChar,1)do
 recombined=recombined.."\n"..list[i+1]
 i=i+1
 end
 cladeString=cladeString..indent..'|label'..child..'='..label
 cladeString=cladeString..indent..'|'..child..'='..'{{clade'
 ..p.listParseLevel(recombined,levelNumber,i)
 else
 cladeString=cladeString..indent..'|'..child..'='..list[i]
 end
 i=i+1
 child=child+1
 end

 cladeString=cladeString..indent..'}}'

 ifnowikithen
 returnmw.getCurrentFrame():preprocess('<nowiki>'..cladeString..'</nowiki>')--return wrapped in nowiki
 else
 returncladeString
 end
 end



 -- this must be at end
 returnp

AltStyle によって変換されたページ (->オリジナル) /