Difference between revisions of "Module:Clade"
From Summertime Saga Wiki
(Created page with "--[[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;...") |
m |
||
(2 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | -- | + | --NOTE: this module contains functions for generating the table structure of the clade tree in two ways: |
− | + | -- (1) the original method was generated by a number of function calls from the template using {{invoke}} | |
− | + | -- function p.openTable(frame) - creates wikitext code to open the HTML table | |
− | + | -- function p.node(frame) - deals with the first node (|1,|label1) and creates wikitext for top row of the table | |
− | + | -- function p.nodeN(frame) - deals with a sister nodes (|2-17), adding a row each time it is called | |
− | + | -- function p.closeTable() - closes the HTML table | |
− | + | -- (2) the revised method is called by the template with one {{invoke}} instruction; it has three functions: | |
− | + | -- 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 | ||
local p = {} | local p = {} | ||
Line 13: | Line 14: | ||
− | -- | + | --============================== main function (for Method 2) =========================== |
− | -- main function, which will generate the table structure of the tree | + | -- main function, which will |
+ | --[[Main function to generate the table structure of the tree | ||
− | + | Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|main|style={{{STYLE}}} }} | |
− | Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|main|style={{{STYLE | + | Template: User:Jts1882/sandbox/templates/CladeN |
− | Template:CladeN | + | ]] |
− | |||
− | |||
− | |||
− | |||
function p.main(frame) | function p.main(frame) | ||
Line 30: | Line 28: | ||
local maxChildren = 20 -- currently 17 in the clade/cladex templates | local maxChildren = 20 -- currently 17 in the clade/cladex templates | ||
local childNumber = 0 | local childNumber = 0 | ||
− | + | local lastNode = 0 | |
− | + | local nodeCount = 0 -- total leafs plus new clade branches | |
− | + | local leafCount = 0 -- just the terminal leaves | |
− | + | local cladeCount = 0 -- new clade calls (each with a table) | |
local childCount = 0 -- number of leaves in the clade (can use to set bottom of bracket in addTaxon() | local childCount = 0 -- number of leaves in the clade (can use to set bottom of bracket in addTaxon() | ||
local totalCount = 0 | local totalCount = 0 | ||
− | + | --[[Note: 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 doesn’t affect the template depths; | |
− | + | it would probably be better to store the transcluded nodes in a table (a job for later) | |
− | + | ]] | |
− | + | --[[ disable proprocessing loop | |
− | + | while childNumber < maxChildren do -- preprocessing loop | |
− | + | childNumber = childNumber + 1 -- so we start with 1 | |
− | + | local nodeLeaf,data = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N= | |
− | + | ||
− | + | 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) | |
− | local | + | nodeCount = nodeCount + 1 |
− | cladeString = cladeString .. | + | end |
− | end | + | for i in string.gmatch(nodeLeaf, "{| cellspacing") do -- count number of tables started (transclusion) |
− | + | cladeCount = cladeCount + 1 | |
− | + | end | |
+ | -- _, cladeCount = string.gsub(nodeLeaf, "{| cellspacing", "") | ||
+ | --_, nodeCount = string.gsub(nodeLeaf, "|| rowspan", "") | ||
+ | |||
+ | --totalCount = totalCount + nodeCount | ||
+ | lastNode = childNumber | ||
+ | -- if data ~= nil then totalCount = totalCount + tonumber(data) else totalCount = totalCount + 1 end | ||
+ | end | ||
+ | |||
+ | |||
+ | --cladeString = cladeString .. '\n' .. ' count= ' .. totalCount | ||
+ | |||
+ | end | ||
+ | ]] | ||
+ | nodeCount = nodeCount + childCount --(elements passed down by transduction plus current child elements) | ||
+ | cladeCount = cladeCount + 1 --(elements passed down by transduction plus current clade) | ||
+ | leafCount = nodeCount-cladeCount+1 | ||
+ | totalCount =leafCount-- cladeCount --nodeCount | ||
+ | |||
+ | |||
+ | |||
+ | local testing = false | ||
+ | --testing = true -- COMMENT OUT TO GET MODULE RUNNING WITHOUT THE TEST | ||
+ | if testing then | ||
+ | local dataString = p.test(1) | ||
+ | cladeString = cladeString .. dataString | ||
+ | return cladeString | ||
+ | end | ||
+ | |||
local tableStyle = frame.args.style or "" | local tableStyle = frame.args.style or "" | ||
− | + | if tableStyle == '{{{style}}}' then tableStyle = "" end | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
local captionName =mw.getCurrentFrame():getParent().args['caption'] or "" | local captionName =mw.getCurrentFrame():getParent().args['caption'] or "" | ||
local captionStyle = mw.getCurrentFrame():getParent().args['captionstyle'] or "" | local captionStyle = mw.getCurrentFrame():getParent().args['captionstyle'] or "" | ||
− | |||
− | |||
− | |||
-- open table | -- open table | ||
− | + | --cladeString = cladeString .. '{| style="border-collapse:collapse;border-spacing:0;margin:0;' .. tableStyle .. '"' | |
− | + | cladeString = cladeString .. '{| style="border-spacing:0;margin:0;' .. tableStyle .. '"' | |
− | |||
-- add caption | -- add caption | ||
Line 90: | Line 104: | ||
local moreNeeded = true | local moreNeeded = true | ||
childNumber = 0 | childNumber = 0 | ||
− | + | lastNode = 0 | |
--[[get child elements (add more rows for each child of node; each child is two rows) | --[[get child elements (add more rows for each child of node; each child is two rows) | ||
Line 99: | Line 113: | ||
]] | ]] | ||
− | + | while childNumber < maxChildren do -- disable moreNeeded | |
− | while childNumber < | + | -- while childNumber < 17 and moreNeeded == true do |
− | |||
childNumber = childNumber + 1 -- so we start with 1 | childNumber = childNumber + 1 -- so we start with 1 | ||
local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N= | local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N= | ||
Line 112: | Line 125: | ||
nodeLabel = p.getNewickOuterterm(newickString) -- need to use terminal part of newick string for label | nodeLabel = p.getNewickOuterterm(newickString) -- need to use terminal part of newick string for label | ||
end | end | ||
− | cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, p.newick(0, newickString), nodeLabel | + | cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, p.newick(0, newickString), nodeLabel) |
− | + | lastNode = childNumber | |
elseif nodeLeaf ~= "" then -- if the node contains a leaf name or clade structue | elseif nodeLeaf ~= "" then -- if the node contains a leaf name or clade structue | ||
− | + | cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, nodeLeaf, nodeLabel) | |
− | + | lastNode = childNumber | |
− | + | else | |
− | + | moreNeeded = false -- no |N= so don’t look for more | |
− | -- | + | -- Note: this changes the behaviour. If there is no |2, it won’t look for |3 or |4, which clade does (is this desirable?) |
+ | -- this has been disabled to allow consistent behaviour with clade/cladex (it will check to the limit set) | ||
end | end | ||
end | end | ||
+ | --[[finish last row by adding cell with no left border | ||
+ | note: the row was started in addTaxon(), but the cell not added as left border yet to be determined; | ||
+ | here the cell is added to the last child node with no left border as it is below the bracket | ||
+ | this will be moved to addTaxon() when the number of the last child is known | ||
+ | ]] | ||
+ | local subLabel = mw.getCurrentFrame():getParent().args['sublabel'..tostring(lastNode)] or "" -- request in addLabel | ||
+ | |||
+ | --use subLabel for annotating the clade structues to use structure information (DEBUGGIING ONLY) | ||
+ | --subLabel= '(N=' .. totalCount .. ')' | ||
+ | |||
+ | --cladeString = cladeString .. '\n' .. '| style="border: 0; padding: 0; vertical-align: top;" | <br/> ' | ||
+ | cladeString = cladeString .. '\n' .. '|style="border:0;vertical-align:top;text-align:center;"|' .. p.addLabel(lastNode-1,subLabel) | ||
+ | |||
+ | --[[ footer description (add addition row spanning two columns at bottom of table) | ||
+ | this is designed to provide the description below the whole clade structure (mimicking cladogram); | ||
+ | however, it can also be used to add labels and spacing to the whole clade structre | ||
+ | ]] | ||
local footerText = mw.getCurrentFrame():getParent().args['footer'] or "" | local footerText = mw.getCurrentFrame():getParent().args['footer'] or "" | ||
local footerStyle = mw.getCurrentFrame():getParent().args['footerstyle'] or "" | local footerStyle = mw.getCurrentFrame():getParent().args['footerstyle'] or "" | ||
if footerText ~= "" then | if footerText ~= "" then | ||
+ | --cladeString = cladeString .. '<tr><td>Test <br/><br/><br/><br/><br/></td></tr>' | ||
cladeString = cladeString .. '\n|-style="' .. footerStyle .. '"\n|colspan="2"|<p>' .. footerText .. '</p>||' | cladeString = cladeString .. '\n|-style="' .. footerStyle .. '"\n|colspan="2"|<p>' .. footerText .. '</p>||' | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
Line 140: | Line 166: | ||
return cladeString | return cladeString | ||
− | |||
end | end | ||
Line 149: | Line 174: | ||
note that the first and last child nodes need to be handled differently from the middle elements | 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 middle elements (|2, |3 ...) use a left border to create the vertical line of the bracket | ||
− | the first child element | + | 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 | + | the last child doesn’t use a left border for the first cell in the second row (as it is above the bracket) |
+ | a complication is that the number of the last child node is not known; | ||
+ | as a result the cells will be added to the row on the next iteration or after the main loop finishes | ||
]] | ]] | ||
− | function p.addTaxon(childNumber, nodeLeaf, nodeLabel | + | function p.addTaxon(childNumber, nodeLeaf, nodeLabel) |
− | -- get | + | -- get leaf and labels |
+ | --local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- used passed variable to avoid redundancy | ||
+ | --local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or "" -- request in addLabel | ||
+ | |||
+ | -- get formating parameters for branch (default to global nodeParameters) | ||
-- - the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN | -- - the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN | ||
-- - the node parameters have no number, e.g. |color, |thickness, |state | -- - the node parameters have no number, e.g. |color, |thickness, |state | ||
Line 164: | Line 195: | ||
-- the left border takes node parameters, the bottom border takes branch parameters | -- the left border takes node parameters, the bottom border takes branch parameters | ||
− | |||
local bottomBorder = tostring(branchThickness) ..'px ' .. branchState .. (branchColor~="" and ' ' .. branchColor or '') | local bottomBorder = tostring(branchThickness) ..'px ' .. branchState .. (branchColor~="" and ' ' .. branchColor or '') | ||
local leftBorder = tostring(nodeThickness) ..'px ' .. nodeState .. (nodeColor~="" and ' ' .. nodeColor or '') | local leftBorder = tostring(nodeThickness) ..'px ' .. nodeState .. (nodeColor~="" and ' ' .. nodeColor or '') | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
-- variables for right hand bar or bracket | -- variables for right hand bar or bracket | ||
Line 193: | Line 213: | ||
if barTop ~= "0" then barTop = "2px solid " .. barTop end | if barTop ~= "0" then barTop = "2px solid " .. barTop end | ||
if barBottom ~= "0" then barBottom = "2px solid " .. barBottom end | if barBottom ~= "0" then barBottom = "2px solid " .. barBottom end | ||
− | |||
-- now construct wikitext | -- now construct wikitext | ||
+ | local styleString = '' | ||
local cladeString = '' | local cladeString = '' | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | -- (2) | + | --[[ first add cell to the spacing row (for 2-17); it completes the previous row |
− | + | why is this here rather than at the end of each row? | |
− | + | To allow left border (here while extending bracket) or not (end of bracket) | |
− | + | ]] | |
− | + | if childNumber ~= 1 then | |
− | + | local subLabel = mw.getCurrentFrame():getParent().args['sublabel'..tostring(childNumber-1)] or "" -- request in addLabel | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | --styleString = ' style="border-left:' .. leftBorder ..';border-top:0;border-right:0;border-bottom:0;vertical-align:top;text-align:center;"' | |
− | + | styleString = ' style="border:0;border-left:' .. leftBorder ..';vertical-align:top;text-align:center;"' | |
− | + | --cladeString = cladeString .. '| ' .. styleString .. ' | <br/> ' -- for sublabel ' | y<br/> ' | |
+ | cladeString = cladeString .. '|' .. styleString .. '|' .. p.addLabel(childNumber-1,subLabel) | ||
+ | end | ||
+ | |||
+ | -- new row | ||
+ | cladeString = cladeString .. '\n|-' | ||
+ | -- now add cell with label | ||
+ | styleString = '' | ||
if childNumber == 1 then | if childNumber == 1 then | ||
− | + | -- the width gives minimum spacing when all labels are empty (was 1.5em) | |
− | + | --styleString = ' style="width:1em;border-bottom:' .. bottomBorder .. ';border-left:0;border-top:0;border-right:0;padding:0 0.2em;vertical-align:bottom;text-align:center;' .. branchStyle .. '"' | |
− | + | styleString = ' style="width:1em;border:0;padding:0 0.2em;border-bottom:' .. bottomBorder .. ';vertical-align:bottom;text-align:center;' .. branchStyle .. '"' | |
− | + | else -- for 2-17 | |
+ | styleString = ' style="border:0;padding:0 0.2em;border-left:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';vertical-align:bottom;text-align:center;' .. branchStyle .. '"' | ||
+ | end | ||
+ | cladeString = cladeString .. '\n|' .. styleString .. '|' .. p.addLabel(childNumber,nodeLabel) -- p.addLabel(nodeLabel) | ||
− | + | -- add cell with leaf (which may be a table with transluded content) | |
− | + | --cladeString = cladeString .. '|| rowspan=2 style="border: 0; padding: 0; border-right: ' .. barRight .. ';border-bottom: ' .. barBottom .. ';border-top: ' .. barTop .. ';' .. branchStyle .. ' " | ' | |
− | + | styleString = '' | |
− | |||
− | |||
− | |||
− | |||
− | |||
if barRight ~= "0" then | if barRight ~= "0" then | ||
− | + | styleString = 'style="border:0;padding:0;border-right:' .. barRight .. ';border-bottom:' .. barBottom .. ';border-top:' .. barTop .. ';' .. branchStyle .. '"' | |
− | |||
− | |||
− | |||
− | |||
else | else | ||
− | + | styleString = 'style="border:0;padding:0;' .. branchStyle .. '"' | |
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | + | cladeString = cladeString .. '||rowspan=2 ' .. styleString .. '|' | |
− | + | -- note: this is where leading spaces can be added to labels and leaves. This was commented out in the clade template. Most trees seem to have added spaces, to would need to check for existing spaces; however, cladex uses it | |
− | + | -- or could use padding:0 0.2em in cell style as for labels | |
− | + | cladeString = cladeString .. '\n' .. nodeLeaf | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | -- | + | -- stuff for right-hand bar-bracket |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
if barRight ~= "0" then | if barRight ~= "0" then | ||
cladeString = cladeString .. ' ' -- add spaces between leaf text and bar | cladeString = cladeString .. ' ' -- add spaces between leaf text and bar | ||
if barLabel ~= "" then | if barLabel ~= "" then | ||
− | cladeString = cladeString .. '\n| | + | -- cladeString = cladeString .. '\n| ' .. barLabel end -- experiment for labeling the bar |
+ | cladeString = cladeString .. '<td style="vertical-align:middle;">' .. barLabel ..'</td>' | ||
end | end | ||
end | end | ||
− | + | if groupLabel ~= ""then | |
− | + | --cladeString = cladeString .. ' ' -- add spaces between leaf text and bar (could use padding) | |
− | + | cladeString = cladeString .. '<td style="'.. groupLabelStyle .. '">' .. groupLabel ..'</td>' | |
− | + | end | |
− | |||
− | |||
− | |||
− | -- | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | end | ||
− | |||
− | |||
− | + | -- add row (needed because of rowspan=2); | |
− | + | -- note: the cell will be added on the next iteration of addTaxon (with left border) or after the main loop (without left border) | |
− | |||
− | -- | ||
− | |||
local branchStyleString = 'style="' .. branchStyle .. '" ' | local branchStyleString = 'style="' .. branchStyle .. '" ' | ||
if branchStyle == '' then branchStyleString = '' end -- avoid empty style elements | if branchStyle == '' then branchStyleString = '' end -- avoid empty style elements | ||
cladeString = cladeString .. '\n|-' .. branchStyleString | cladeString = cladeString .. '\n|-' .. branchStyleString | ||
− | |||
− | |||
− | -- | + | -- TODO code to put whole row here instead of completing on next call to addTaxon() or after main loop |
− | + | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
return cladeString | return cladeString | ||
end | end | ||
− | |||
--[[ adds text for label or sublabel to a cell | --[[ adds text for label or sublabel to a cell | ||
Line 477: | Line 290: | ||
--local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or "" | --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 | + | --if nodeLabel ~= "{{{label1}}}" then |
− | + | if firstChars == "{{{" or nodeLabel == "" then | |
− | + | return '<br/>' --' <br/>' -- remove space to reduce post-expand include size (the width=1.5em handles spacing) | |
− | |||
− | |||
else | else | ||
-- spaces can cause wrapping and can break tree structure, hence use span with nowrap class | -- spaces can cause wrapping and can break tree structure, hence use span with nowrap class | ||
Line 497: | Line 308: | ||
else | else | ||
local nowrapString = string.gsub(nodeLabel," ", " ") -- replace spaces with non-breaking space | local nowrapString = string.gsub(nodeLabel," ", " ") -- replace spaces with non-breaking space | ||
− | |||
return nowrapString | return nowrapString | ||
end | end | ||
Line 510: | Line 320: | ||
return string.gsub(newickString, "%b()", "") -- delete parenthetic term | return string.gsub(newickString, "%b()", "") -- delete parenthetic term | ||
end | end | ||
− | |||
function p.newick(count,newickString) | function p.newick(count,newickString) | ||
− | |||
local cladeString = "" | local cladeString = "" | ||
count = count+1 | count = count+1 | ||
--start table | --start table | ||
− | + | cladeString = cladeString .. '{| style="border-collapse:collapse;border-spacing:0;border:0;margin:0;' | |
− | |||
local j,k | local j,k | ||
Line 533: | Line 340: | ||
--cladeString = cladeString .. '\n' .. p.addTaxon(1, innerTerm2, "") | --cladeString = cladeString .. '\n' .. p.addTaxon(1, innerTerm2, "") | ||
− | |||
local s = strsplit(innerTerm2, ",") | local s = strsplit(innerTerm2, ",") | ||
− | |||
− | |||
local i=1 | local i=1 | ||
while s[i] do | while s[i] do | ||
Line 544: | Line 348: | ||
if string.find(restoredString, '%(.*%)') then | if string.find(restoredString, '%(.*%)') then | ||
--cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "x") | --cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "x") | ||
− | cladeString = cladeString .. '\n' .. p.addTaxon(i, p.newick(count,restoredString), outerTerm | + | cladeString = cladeString .. '\n' .. p.addTaxon(i, p.newick(count,restoredString), outerTerm) |
-- p.addTaxon(2, p.newick(count,newickString2), "root") | -- p.addTaxon(2, p.newick(count,newickString2), "root") | ||
else | else | ||
− | cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "" | + | cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "") --count) |
end | end | ||
i=i+1 | i=i+1 | ||
end | end | ||
− | + | ||
− | |||
-- close table | -- close table | ||
− | + | cladeString = cladeString .. '\n' .. '| style="border: 0; padding: 0; vertical-align: top;" | <br/> \n|}' | |
− | + | ||
− | |||
return cladeString | return cladeString | ||
end | end | ||
Line 572: | Line 374: | ||
end | end | ||
+ | |||
+ | -- Bits from Peter Coxhead’s module | ||
+ | -- https://en.wikipedia.org/w/index.php?title=Module:Autotaxobox&action=edit | ||
+ | |||
+ | --[[ | ||
+ | Utility function primarily intended for use in checking and debugging. | ||
+ | Returns number of levels in a taxonomic hierarchy, starting from | ||
+ | the supplied taxon as level 1. | ||
+ | Usage: {{#invoke:Autotaxobox|nLevels|TAXON}} | ||
+ | ]] | ||
+ | function p.nLevels(frame) | ||
+ | local currTaxon = frame.args[1] | ||
+ | local i = 1 | ||
+ | local maxN = 2 | ||
+ | local searching = true | ||
+ | while searching and i < maxN do | ||
+ | --local parent = frame:expandTemplate{ title = 'Template:Taxonomy/' .. currTaxon, args = {['machine code'] = 'parent' } } | ||
+ | local parent = frame:expandTemplate{ title = currTaxon, args = {['machine code'] = 'parent' } } | ||
+ | if parent ~= '' then | ||
+ | currTaxon = parent | ||
+ | i = i + 1 | ||
+ | else | ||
+ | searching = false | ||
+ | end | ||
+ | end | ||
+ | if searching then return currTaxon --maxN .. '+' | ||
+ | else return i | ||
+ | end | ||
+ | end | ||
+ | |||
+ | --[[ | ||
+ | Utility function primarily intended for use in checking and debugging. | ||
+ | Returns a comma separated list of a taxonomic hierarchy, starting from | ||
+ | the supplied taxon. | ||
+ | Usage: {{#invoke:Autotaxobox|listAll|TAXON}} | ||
+ | ]] | ||
+ | function p.listAll(frame) | ||
+ | local currTaxon = frame.args[1] | ||
+ | local i = 1 | ||
+ | local searching = true | ||
+ | local maxN = 100 | ||
+ | local lst = currTaxon | ||
+ | while i < maxN and searching do | ||
+ | local currCall = 'Template:Taxonomy/' .. currTaxon | ||
+ | local parent = frame:expandTemplate{ title = currCall, args = {['machine code'] = 'parent' } } | ||
+ | if parent ~= '' then | ||
+ | currTaxon = parent | ||
+ | lst = lst .. ', ' .. currTaxon | ||
+ | i = i + 1 | ||
+ | else | ||
+ | searching = false | ||
+ | end | ||
+ | end | ||
+ | if searching then lst = lst .. '...' end | ||
+ | return lst .. ' (' .. i .. ')' | ||
+ | end | ||
-- =================== experimental Newick to clade parser function ============================= | -- =================== experimental Newick to clade parser function ============================= | ||
Line 612: | Line 470: | ||
end | end | ||
− | --[[ Parse one level of Newick | + | --[[ Parse one level of Newick sting |
− | This function | + | This function recieves a Newick string, which has two components |
1. the right hand term is a clade label: |labelN=labelname | 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 | 2. the left hand term in parenthesis has common delimited child nodes, each of which can be | ||
Line 686: | Line 544: | ||
------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | ||
+ | function p.test(dummy) | ||
+ | local dataString = "" | ||
+ | dataString = "NEWCLADE:" | ||
+ | |||
+ | local childNumber =0 | ||
+ | local lastNode = 0 | ||
+ | while childNumber < 17 do -- disable moreNeeded | ||
+ | |||
+ | childNumber = childNumber + 1 -- so we start with 1 | ||
+ | local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N= | ||
+ | --local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or "" -- get data from |labelN= | ||
+ | if nodeLeaf ~= "" then | ||
+ | dataString = dataString .. tostring(childNumber) | ||
+ | local firstChars = string.sub(nodeLeaf, 1,2) -- get first two characters | ||
+ | --if nodeLabel ~= "{{{label1}}}" then | ||
+ | if firstChars == "{{" then | ||
+ | dataString = dataString .. 'XXX' .. nodeLeaf | ||
+ | end | ||
+ | dataString = dataString .. 'LEAF:' .. nodeLeaf | ||
+ | |||
+ | lastNode = childNumber | ||
+ | end | ||
+ | end | ||
+ | local numClades=0 | ||
+ | local numBranches=0 | ||
+ | -- _, count = string.gsub(dataString, "NEWCLADE", "NEXT") | ||
+ | |||
+ | for i in string.gmatch(dataString, "NEWCLADE") do | ||
+ | numClades = numClades + 1 | ||
+ | end | ||
+ | dataString = dataString .. '<br/>(numClades=' .. numClades .. ')' | ||
+ | for i in string.gmatch(dataString, "LEAF") do | ||
+ | numBranches = numBranches + 1 | ||
+ | end | ||
+ | dataString = dataString .. '<br/>(numClades=' .. numClades .. ')' | ||
+ | dataString = dataString .. '<br/>(numBranches=' .. numBranches .. ')' | ||
+ | |||
+ | mw:log(numClades) | ||
+ | |||
+ | --return 'numClades=' .. numClades .. '; numBranches=' .. numBranches | ||
+ | return dataString | ||
+ | end | ||
function p.test2(target) | function p.test2(target) | ||
local target ="User:Jts1882/sandbox/templates/Template:Passeroidea" | local target ="User:Jts1882/sandbox/templates/Template:Passeroidea" | ||
Line 692: | Line 592: | ||
return result | return result | ||
end | end | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
function p.hidden(frame) | function p.hidden(frame) | ||
Line 754: | Line 625: | ||
local contentString = '<td style="padding:0;">' | local contentString = '<td style="padding:0;">' | ||
.. '<div class="mw-collapsible' .. contentState .. '" id="mw-customcollapsible-myClade' .. id .. '>' | .. '<div class="mw-collapsible' .. contentState .. '" id="mw-customcollapsible-myClade' .. id .. '>' | ||
− | .. '<div class="mw-collapsible-content mw-customtoggle-NOT_ON_CONTENT" >' -- | + | .. '<div class="mw-collapsible-content mw-customtoggle-NOT_ON_CONTENT" >' -- don’t toggle on the content |
.. '\n' .. p.main(frame) -- important to start wikitext tables on new line | .. '\n' .. p.main(frame) -- important to start wikitext tables on new line | ||
Line 787: | Line 658: | ||
return cladeString | return cladeString | ||
end | end | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | -- | + | -- this must be at end |
− | |||
− | |||
− | |||
− | |||
− | |||
− | end | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
return p | return p |
Latest revision as of 01:52, 11 July 2020
This module is designed to be used with the template {{clade}} to draw phylogenetic trees or cladograms. The new template‐module combination extends the feature available with {{clade}}
while replicating the behavior of the older templates written with the template language.
Additionally, the module has the code for a prototype template, which converts Newick strings into clade structure. This is not to be used in Wikipedia articles, but is a utility 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
{{#invoke:Clade|main|style={{{style}}}}}
--NOTE: this module contains functions for generating the table structure of the clade tree in two ways: -- (1) the original method was generated by a number of function calls from the template using {{invoke}} -- function p.openTable(frame) - creates wikitext code to open the HTML table -- function p.node(frame) - deals with the first node (|1,|label1) and creates wikitext for top row of the table -- function p.nodeN(frame) - deals with a sister nodes (|2-17), adding a row each time it is called -- function p.closeTable() - closes the HTML table -- (2) the revised method is called by the template with one {{invoke}} instruction; it has three functions: -- 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 local p = {} --============================== main function (for Method 2) =========================== -- main function, which will --[[Main function to generate the table structure of the tree Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|main|style={{{STYLE}}} }} Template: User:Jts1882/sandbox/templates/CladeN ]] function p.main(frame) local cladeString = "" local maxChildren = 20 -- currently 17 in the clade/cladex templates local childNumber = 0 local lastNode = 0 local nodeCount = 0 -- total leafs plus new clade branches local leafCount = 0 -- just the terminal leaves local cladeCount = 0 -- new clade calls (each with a table) local childCount = 0 -- number of leaves in the clade (can use to set bottom of bracket in addTaxon() local totalCount = 0 --[[Note: 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 doesn’t affect the template depths; it would probably be better to store the transcluded nodes in a table (a job for later) ]] --[[ disable proprocessing loop while childNumber < maxChildren do -- preprocessing loop childNumber = childNumber + 1 -- so we start with 1 local nodeLeaf,data = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N= 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, "{| cellspacing") do -- count number of tables started (transclusion) cladeCount = cladeCount + 1 end -- _, cladeCount = string.gsub(nodeLeaf, "{| cellspacing", "") --_, nodeCount = string.gsub(nodeLeaf, "|| rowspan", "") --totalCount = totalCount + nodeCount lastNode = childNumber -- if data ~= nil then totalCount = totalCount + tonumber(data) else totalCount = totalCount + 1 end end --cladeString = cladeString .. '\n' .. ' count= ' .. totalCount end ]] nodeCount = nodeCount + childCount --(elements passed down by transduction plus current child elements) cladeCount = cladeCount + 1 --(elements passed down by transduction plus current clade) leafCount = nodeCount-cladeCount+1 totalCount =leafCount-- cladeCount --nodeCount local testing = false --testing = true -- COMMENT OUT TO GET MODULE RUNNING WITHOUT THE TEST if testing then local dataString = p.test(1) cladeString = cladeString .. dataString return cladeString end local tableStyle = frame.args.style or "" if tableStyle == '{{{style}}}' then tableStyle = "" end local captionName =mw.getCurrentFrame():getParent().args['caption'] or "" local captionStyle = mw.getCurrentFrame():getParent().args['captionstyle'] or "" -- open table --cladeString = cladeString .. '{| style="border-collapse:collapse;border-spacing:0;margin:0;' .. tableStyle .. '"' cladeString = cladeString .. '{| style="border-spacing:0;margin:0;' .. tableStyle .. '"' -- add caption if captionName ~= "" then cladeString = cladeString .. '\n|+ style="' .. captionStyle .. '"|' .. captionName end -- global nodeParameters (unnumber, i.e. color, thickness, state) apply to whole node bracket, -- but can be overrriden by branchParameters (numbered, e.g. color2, thickness2, state2) nodeColor = mw.getCurrentFrame():getParent().args['color'] or "" nodeThickness = tonumber(mw.getCurrentFrame():getParent().args['thickness']) or 1 nodeState = mw.getCurrentFrame():getParent().args['state'] or "solid" local moreNeeded = 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 ]] while childNumber < maxChildren do -- disable moreNeeded -- while childNumber < 17 and moreNeeded == true do childNumber = childNumber + 1 -- so we start with 1 local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N= local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or "" -- get data from |labelN= local newickString = mw.getCurrentFrame():getParent().args['newick'..tostring(childNumber)] or "" -- get data from |labelN= if newickString ~= "" then -- if using a newick string instead of a clade structure if nodeLabel == "" 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 = childNumber elseif nodeLeaf ~= "" then -- if the node contains a leaf name or clade structue cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, nodeLeaf, nodeLabel) lastNode = childNumber else moreNeeded = false -- no |N= so don’t look for more -- Note: this changes the behaviour. If there is no |2, it won’t look for |3 or |4, which clade does (is this desirable?) -- this has been disabled to allow consistent behaviour with clade/cladex (it will check to the limit set) end end --[[finish last row by adding cell with no left border note: the row was started in addTaxon(), but the cell not added as left border yet to be determined; here the cell is added to the last child node with no left border as it is below the bracket this will be moved to addTaxon() when the number of the last child is known ]] local subLabel = mw.getCurrentFrame():getParent().args['sublabel'..tostring(lastNode)] or "" -- request in addLabel --use subLabel for annotating the clade structues to use structure information (DEBUGGIING ONLY) --subLabel= '(N=' .. totalCount .. ')' --cladeString = cladeString .. '\n' .. '| style="border: 0; padding: 0; vertical-align: top;" | <br/> ' cladeString = cladeString .. '\n' .. '|style="border:0;vertical-align:top;text-align:center;"|' .. p.addLabel(lastNode-1,subLabel) --[[ footer description (add addition row spanning two columns at bottom of table) this is designed to provide the description below the whole clade structure (mimicking cladogram); however, it can also be used to add labels and spacing to the whole clade structre ]] local footerText = mw.getCurrentFrame():getParent().args['footer'] or "" local footerStyle = mw.getCurrentFrame():getParent().args['footerstyle'] or "" if footerText ~= "" then --cladeString = cladeString .. '<tr><td>Test <br/><br/><br/><br/><br/></td></tr>' cladeString = cladeString .. '\n|-style="' .. footerStyle .. '"\n|colspan="2"|<p>' .. footerText .. '</p>||' end -- close table (wikitext to close table) cladeString = cladeString .. '\n|}' return cladeString end --[[ 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 above the bracket) a complication is that the number of the last child node is not known; as a result the cells will be added to the row on the next iteration or after the main loop finishes ]] function p.addTaxon(childNumber, nodeLeaf, nodeLabel) -- get leaf and labels --local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- used passed variable to avoid redundancy --local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or "" -- request in addLabel -- get formating parameters for branch (default to global nodeParameters) -- - the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN -- - the node parameters have no number, e.g. |color, |thickness, |state local branchThickness = tonumber(mw.getCurrentFrame():getParent().args['thickness'..tostring(childNumber)]) or nodeThickness local branchColor = mw.getCurrentFrame():getParent().args['color'..tostring(childNumber)] or nodeColor local branchStyle = mw.getCurrentFrame():getParent().args['style'..tostring(childNumber)] or "" local branchState = mw.getCurrentFrame():getParent().args['state'..tostring(childNumber)] or nodeState -- "solid" if branchState == 'double' then if branchThickness < 2 then branchThickness = 3 end end -- need thick line for double -- the left border takes node parameters, the bottom border takes branch parameters local bottomBorder = tostring(branchThickness) ..'px ' .. branchState .. (branchColor~="" and ' ' .. branchColor or '') local leftBorder = tostring(nodeThickness) ..'px ' .. nodeState .. (nodeColor~="" and ' ' .. nodeColor or '') -- variables for right hand bar or bracket --local barColor = "" local barRight = mw.getCurrentFrame():getParent().args['bar'..tostring(childNumber)] or "0" local barBottom = mw.getCurrentFrame():getParent().args['barend'..tostring(childNumber)] or "0" local barTop = mw.getCurrentFrame():getParent().args['barbegin'..tostring(childNumber)] or "0" local barLabel = mw.getCurrentFrame():getParent().args['barlabel'..tostring(childNumber)] or "" local groupLabel = mw.getCurrentFrame():getParent().args['grouplabel'..tostring(childNumber)] or "" local groupLabelStyle = mw.getCurrentFrame():getParent().args['labelstyle'..tostring(childNumber)] or "" --replace colours with format string; need right bar for all three options if barRight ~= "0" then barRight = "2px solid " .. barRight end if barTop ~= "0" then barRight = "2px solid " .. barTop end if barBottom ~= "0" then barRight = "2px solid " .. barBottom end if barTop ~= "0" then barTop = "2px solid " .. barTop end if barBottom ~= "0" then barBottom = "2px solid " .. barBottom end -- now construct wikitext local styleString = '' local cladeString = '' --[[ first add cell to the spacing row (for 2-17); it completes the previous row why is this here rather than at the end of each row? To allow left border (here while extending bracket) or not (end of bracket) ]] if childNumber ~= 1 then local subLabel = mw.getCurrentFrame():getParent().args['sublabel'..tostring(childNumber-1)] or "" -- request in addLabel --styleString = ' style="border-left:' .. leftBorder ..';border-top:0;border-right:0;border-bottom:0;vertical-align:top;text-align:center;"' styleString = ' style="border:0;border-left:' .. leftBorder ..';vertical-align:top;text-align:center;"' --cladeString = cladeString .. '| ' .. styleString .. ' | <br/> ' -- for sublabel ' | y<br/> ' cladeString = cladeString .. '|' .. styleString .. '|' .. p.addLabel(childNumber-1,subLabel) end -- new row cladeString = cladeString .. '\n|-' -- now add cell with label styleString = '' if childNumber == 1 then -- the width gives minimum spacing when all labels are empty (was 1.5em) --styleString = ' style="width:1em;border-bottom:' .. bottomBorder .. ';border-left:0;border-top:0;border-right:0;padding:0 0.2em;vertical-align:bottom;text-align:center;' .. branchStyle .. '"' styleString = ' style="width:1em;border:0;padding:0 0.2em;border-bottom:' .. bottomBorder .. ';vertical-align:bottom;text-align:center;' .. branchStyle .. '"' else -- for 2-17 styleString = ' style="border:0;padding:0 0.2em;border-left:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';vertical-align:bottom;text-align:center;' .. branchStyle .. '"' end cladeString = cladeString .. '\n|' .. styleString .. '|' .. p.addLabel(childNumber,nodeLabel) -- p.addLabel(nodeLabel) -- add cell with leaf (which may be a table with transluded content) --cladeString = cladeString .. '|| rowspan=2 style="border: 0; padding: 0; border-right: ' .. barRight .. ';border-bottom: ' .. barBottom .. ';border-top: ' .. barTop .. ';' .. branchStyle .. ' " | ' styleString = '' if barRight ~= "0" then styleString = 'style="border:0;padding:0;border-right:' .. barRight .. ';border-bottom:' .. barBottom .. ';border-top:' .. barTop .. ';' .. branchStyle .. '"' else styleString = 'style="border:0;padding:0;' .. branchStyle .. '"' end cladeString = cladeString .. '||rowspan=2 ' .. styleString .. '|' -- note: this is where leading spaces can be added to labels and leaves. This was commented out in the clade template. Most trees seem to have added spaces, to would need to check for existing spaces; however, cladex uses it -- or could use padding:0 0.2em in cell style as for labels cladeString = cladeString .. '\n' .. nodeLeaf -- stuff for right-hand bar-bracket if barRight ~= "0" then cladeString = cladeString .. ' ' -- add spaces between leaf text and bar if barLabel ~= "" then -- cladeString = cladeString .. '\n| ' .. barLabel end -- experiment for labeling the bar cladeString = cladeString .. '<td style="vertical-align:middle;">' .. barLabel ..'</td>' end end if groupLabel ~= ""then --cladeString = cladeString .. ' ' -- add spaces between leaf text and bar (could use padding) cladeString = cladeString .. '<td style="'.. groupLabelStyle .. '">' .. groupLabel ..'</td>' end -- add row (needed because of rowspan=2); -- note: the cell will be added on the next iteration of addTaxon (with left border) or after the main loop (without left border) local branchStyleString = 'style="' .. branchStyle .. '" ' if branchStyle == '' then branchStyleString = '' end -- avoid empty style elements cladeString = cladeString .. '\n|-' .. branchStyleString -- TODO code to put whole row here instead of completing on next call to addTaxon() or after main loop return cladeString end --[[ adds text for label or sublabel to a cell ]] function p.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 nodeLabel ~= "{{{label1}}}" then if firstChars == "{{{" or nodeLabel == "" then return '<br/>' --' <br/>' -- remove space to reduce post-expand include size (the width=1.5em handles spacing) 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= ...) local stylingElementDetected = false if string.find(nodeLabel, "span ") ~= nil then stylingElementDetected = true end if string.find(nodeLabel, " style") ~= nil then stylingElementDetected = true end if stylingElementDetected == true then return '<span class="nowrap">' .. nodeLabel .. '</span>' else local nowrapString = string.gsub(nodeLabel," ", " ") -- replace spaces with non-breaking space return nowrapString end end end --[[=================== Newick string handling function ============================= ]] function p.getNewickOuterterm(newickString) return string.gsub(newickString, "%b()", "") -- delete parenthetic term end function p.newick(count,newickString) local cladeString = "" count = count+1 --start table cladeString = cladeString .. '{| style="border-collapse:collapse;border-spacing:0;border:0;margin:0;' local j,k j,k = string.find(newickString, '%(.*%)') -- find location of outer parenthesised term local innerTerm = string.sub(newickString, j+1, k-1) -- select content in parenthesis local outerTerm = string.gsub(newickString, "%b()", "") -- delete parenthetic term if outerTerm == 'panthera' then outerTerm = "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 local innerTerm2 = string.gsub(innerTerm, "%b()", function (n) return string.gsub(n, ",%s*", "XXX") -- also strip spaces after commas here end) --cladeString = cladeString .. '\n' .. p.addTaxon(1, innerTerm2, "") local s = strsplit(innerTerm2, ",") local i=1 while s[i] do restoredString = string.gsub(s[i],"XXX", ",") -- convert back to commas --restoredString = s[i] local outerTerm = string.gsub(restoredString, "%b()", "") if string.find(restoredString, '%(.*%)') then --cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "x") cladeString = cladeString .. '\n' .. p.addTaxon(i, p.newick(count,restoredString), outerTerm) -- p.addTaxon(2, p.newick(count,newickString2), "root") else cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "") --count) end i=i+1 end -- close table cladeString = cladeString .. '\n' .. '| style="border: 0; padding: 0; vertical-align: top;" | <br/> \n|}' return cladeString end -- emulate a standard split string function function strsplit(inputstr, sep) if sep == nil then sep = "%s" end local t={} ; i=1 for str in string.gmatch(inputstr, "([^"..sep.."]+)") do t[i] = str i = i + 1 end return t end -- Bits from Peter Coxhead’s module -- https://en.wikipedia.org/w/index.php?title=Module:Autotaxobox&action=edit --[[ Utility function primarily intended for use in checking and debugging. Returns number of levels in a taxonomic hierarchy, starting from the supplied taxon as level 1. Usage: {{#invoke:Autotaxobox|nLevels|TAXON}} ]] function p.nLevels(frame) local currTaxon = frame.args[1] local i = 1 local maxN = 2 local searching = true while searching and i < maxN do --local parent = frame:expandTemplate{ title = 'Template:Taxonomy/' .. currTaxon, args = {['machine code'] = 'parent' } } local parent = frame:expandTemplate{ title = currTaxon, args = {['machine code'] = 'parent' } } if parent ~= '' then currTaxon = parent i = i + 1 else searching = false end end if searching then return currTaxon --maxN .. '+' else return i end end --[[ Utility function primarily intended for use in checking and debugging. Returns a comma separated list of a taxonomic hierarchy, starting from the supplied taxon. Usage: {{#invoke:Autotaxobox|listAll|TAXON}} ]] function p.listAll(frame) local currTaxon = frame.args[1] local i = 1 local searching = true local maxN = 100 local lst = currTaxon while i < maxN and searching do local currCall = 'Template:Taxonomy/' .. currTaxon local parent = frame:expandTemplate{ title = currCall, args = {['machine code'] = 'parent' } } if parent ~= '' then currTaxon = parent lst = lst .. ', ' .. currTaxon i = i + 1 else searching = false end end if searching then lst = lst .. '...' end return lst .. ' (' .. i .. ')' 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}}} }} ]] function p.newickConverter(frame) local newickString = frame.args['newickstring'] if newickString == '{{{newickstring}}}' then return newickString end -- show the Newick string local cladeString = '' local levelNumber = 1 -- for depth of iteration local childNumber = 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}}' local resultString = '' local option = mw.getCurrentFrame():getParent().args['option'] or '' if option == '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) } return resultString end --[[ Parse one level of Newick sting This function recieves 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 ]] function p.newickParseLevel(newickString,levelNumber,childNumber) local cladeString = "" local indent = p.getIndent(levelNumber) --levelNumber=levelNumber+1 local j=0 local k=0 j,k = string.find(newickString, '%(.*%)') -- find location of outer parenthesised term local innerTerm = string.sub(newickString, j+1, k-1) -- select content in parenthesis local outerTerm = 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 local innerTerm2 = string.gsub(innerTerm, "%b()", function (n) return string.gsub(n, ",%s*", "XXX") -- also strip spaces after commas here end) local s = strsplit(innerTerm2, ",") local i=1 while s[i] do restoredString = string.gsub(s[i],"XXX", ",") -- convert back to commas local outerTerm = string.gsub(restoredString, "%b()", "") if string.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 .. '}}' return cladeString end function p.getIndent(levelNumber) local indent = "\r" local extraIndent = mw.getCurrentFrame():getParent().args['indent'] or 0 while tonumber(extraIndent) > 0 do indent = indent .. " " -- an extra indent to make aligining compound trees easier extraIndent = extraIndent - 1 end while levelNumber > 1 do indent = indent .. " " levelNumber = levelNumber-1 end return indent end function p.newickstuff(newickString) end ------------------------------------------------------------------------------------------ function p.test(dummy) local dataString = "" dataString = "NEWCLADE:" local childNumber =0 local lastNode = 0 while childNumber < 17 do -- disable moreNeeded childNumber = childNumber + 1 -- so we start with 1 local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N= --local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or "" -- get data from |labelN= if nodeLeaf ~= "" then dataString = dataString .. tostring(childNumber) local firstChars = string.sub(nodeLeaf, 1,2) -- get first two characters --if nodeLabel ~= "{{{label1}}}" then if firstChars == "{{" then dataString = dataString .. 'XXX' .. nodeLeaf end dataString = dataString .. 'LEAF:' .. nodeLeaf lastNode = childNumber end end local numClades=0 local numBranches=0 -- _, count = string.gsub(dataString, "NEWCLADE", "NEXT") for i in string.gmatch(dataString, "NEWCLADE") do numClades = numClades + 1 end dataString = dataString .. '<br/>(numClades=' .. numClades .. ')' for i in string.gmatch(dataString, "LEAF") do numBranches = numBranches + 1 end dataString = dataString .. '<br/>(numClades=' .. numClades .. ')' dataString = dataString .. '<br/>(numBranches=' .. numBranches .. ')' mw:log(numClades) --return 'numClades=' .. numClades .. '; numBranches=' .. numBranches return dataString end function p.test2(target) local target ="User:Jts1882/sandbox/templates/Template:Passeroidea" local result = mw.getCurrentFrame():expandTemplate{ title = target, args = {['style'] = '' } } return result end function p.hidden(frame) local id = mw.getCurrentFrame():getParent().args['id'] or "" local mode = mw.getCurrentFrame():getParent().args['mode'] or "right" local expandSymbol = mw.getCurrentFrame():getParent().args['expand-symbol'] or "⊞" local collapseSymbol = mw.getCurrentFrame():getParent().args['collapse-symbol'] or "⊟" local initialState = mw.getCurrentFrame():getParent().args['expanded'] -- default is content collapsed local contentState = " mw-collapsed" -- class to collapse content at start local collapseSymbolState = " mw-collapsed" local expandSymbolState = "" if initialState then contentState = "" collapseSymbolState = "" expandSymbolState = " mw-collapsed" end -- collapsible element containing the expand sympol and/or text local expandSymbolString = '<td style="padding:0 0 0.25em 0;">' .. '<div class="mw-collapsible' .. expandSymbolState .. '" id="mw-customcollapsible-expandSymbol' .. id .. '">' .. '<div class="mw-collapsible-content mw-customtoggle-expandSymbol' .. id .. '">' .. '<span class="mw-customtoggle-myClade' .. id .. ' mw-customtoggle-collapseSymbol' .. id .. ' mw-customtoggle-expandSymbol' .. id .. '" style="font-size:100%;">' .. expandSymbol .. '</span>' .. '</div></div></td>' -- collapsible element containing the clade content local contentString = '<td style="padding:0;">' .. '<div class="mw-collapsible' .. contentState .. '" id="mw-customcollapsible-myClade' .. id .. '>' .. '<div class="mw-collapsible-content mw-customtoggle-NOT_ON_CONTENT" >' -- don’t toggle on the content .. '\n' .. p.main(frame) -- important to start wikitext tables on new line .. '</div></div></td>' -- collapsible element containing the collapse sympol and/or text local collapseSymbolString = '<td style="padding:0 0 0.4em 0;">' .. '<div class="mw-collapsible' .. collapseSymbolState .. '" id="mw-customcollapsible-collapseSymbol' .. id .. '">' .. '<div class="mw-collapsible-content mw-customtoggle-collapseSymbol' .. id .. '" >' .. '<span class="mw-customtoggle-expandSymbol' .. id .. ' mw-customtoggle-myClade' .. id .. ' mw-customtoggle-collapseSymbol' .. id .. ' " style="font-size:100%;" >' .. collapseSymbol .. '</span>' .. '</div></div></td>' local tableStyle = frame.args.style or "" if tableStyle == '{{{style}}}' then tableStyle = "" end local cladeString = '<table style="border-spacing:0;margin:0;'..tableStyle ..'"><tr>' cladeString = cladeString .. expandSymbolString if mode == "left" then cladeString = cladeString .. collapseSymbolString end cladeString = cladeString .. contentString if mode == "right" then cladeString = cladeString .. collapseSymbolString end -- Note: if we want collapse string left and right it needs an extra element with a different id cladeString = cladeString .. '</tr></table>' return cladeString end -- this must be at end return p