Module:Sports attendance/sandbox
Appearance
| This is the module sandbox page for Module:Sports attendance (diff). |
| This module is rated as alpha. It is ready for limited use and third-party feedback. It may be used on a small number of pages, but should be monitored closely. Suggestions for new features or adjustments to input and output are welcome. |
Module:Sports attendance is meant to build attendance tables for sports leagues from lists of individual match attendance for each team. If only aggregate data is available, please consider using Template:Fb a header, Template:Fb a team, and Template:Fb a footer instead.
Wikitext test cases are at Module:Sports attendance/testcases wikitext.
Usage
[edit]In article
[edit]| What you type | {{#invoke:Sports attendance|main
|team_VAN = [[Vancouver Rise]]
|attendance_VAN = 4650,3526,3723,3451,3430,3655
|previous_VAN = 4245
|note_VAN = The attendance for Vancouver Rise FC – AFC Toronto (June 28) has not been announced.
|team_MTL = [[Montreal Roses]]
|attendance_MTL = 3304,2457,2068,1792,1891,2565,2348
|previous_MTL = 3221
|note_MTL = The attendance for Montreal Roses FC – Vancouver Rise FC (July 4) has not been announced.
|team_TOR = [[AFC Toronto]]
|attendance_TOR = 6577,3153,2554,2519,2118,2682
|previous_TOR = 4058
|note_TOR =
|team_HFX = [[Halifax Tides]]
|attendance_HFX = 4030,3440,3501,3735,5516,3913,3682
|previous_HFX = 3915
|note_HFX =
|team_CGY = [[Calgary Wild]]
|attendance_CGY = 3219,2342,2847,2718,3164,2398,2292,2210,2232
|previous_CGY = 3366
|note_CGY =
|team_OTT = [[Ottawa Rapid]]
|attendance_OTT = 2855,1321,1295,1877,3069,2631,2405
|previous_OTT = 3042
|note_OTT =
|previous_league = 3633
|note_league = League total note.
|source=[https://www.nsl.ca/schedule NSL]
|updated=August 7, 2026
}}
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| What it looks like |
Updated to games played on August 7, 2026. Source: NSL
|
The main command is {{#invoke:Sports attendance|main}} statement. Teams will be ranked based on average attendance and team name.
-- Module to build tables for attendance in Sports
-- See documentation for details
require('strict')
local p = {}
-- Main function
function p.main(frame)
-- Declare locals
local getArgs = require('Module:Arguments').getArgs
local Args = getArgs(frame, {parentFirst = true})
local team_list = {['league'] = {name = 'League total', attendance = {}}}
local sorted_teams = {}
local t = {}
local lang = mw.language.getContentLanguage()
local templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = 'Module:Sports attendance/styles.css' }
}
-- Load modules
local yesno = require('Module:Yesno')
local mm = require('Module:Math')
-- Form list of teams, stored under key of string following 'team_'
for arg, value in pairs(Args) do
local tname = string.match(arg, '^team_(.+)')
if yesno(tname, true) then
-- Initialise team in team_list
team_list[tname] = {}
table.insert(sorted_teams, tname)
-- Set team's name, with link stripped
local stripped_brackets = mw.ustring.gsub(value, '[%[%]]', '')
team_list[tname]['name'] = mw.ustring.gsub(stripped_brackets, '.-|', '') -- strip original page name
-- Transform team's match attendances into numbers
local attendance = mw.text.split(Args['attendance_' .. tname] or '', '%s*[;,]%s*')
for i, att in ipairs(attendance) do
if i == 1 then team_list[tname]['attendance'] = {} end -- Initialise team's attendance array
local att_num = tonumber(att)
team_list[tname]['attendance'][i] = att_num
table.insert(team_list['league']['attendance'], att_num)
end
-- Compute team's average attendance for ranking
team_list[tname]['average'] = mm._round(mm._average(unpack(attendance)), 0)
end
end
-- Compute league total average
team_list['league']['average'] = mm._round(mm._average(unpack(team_list['league'].attendance)), 0)
-- Rank teams by average attendance
table.sort(sorted_teams, function(a, b)
-- Compare names if both teams do not have any attendance, or if their averages are identical
if (not yesno(#team_list[a].attendance, true) and not yesno(#team_list[b].attendance, true)) or team_list[a].average == team_list[b].average then return team_list[a].name < team_list[b].name end -- sort by alphabetical order
-- The team with no attendance is placed lower
if not yesno(#team_list[a].attendance, true) then return false end
if not yesno(#team_list[b].attendance, true) then return true end
-- Compare average attendance
return team_list[a].average > team_list[b].average
end)
-- Add 'League total' to end of sorted_teams
table.insert(sorted_teams, 'league')
-- Create table header
table.insert(t, '{| class="wikitable sortable" style="text-align:right;"\n')
table.insert(t, '!width=25|<abbr title="Position">Pos</abbr>\n')
table.insert(t, '!width=185|Team\n')
table.insert(t, '!width=25|<abbr title="Home matches played">Pld</abbr>\n')
table.insert(t, '!width=65|<abbr title="Total season attendance">Total</abbr>\n')
table.insert(t, '!width=55|<abbr title="Highest season attendance">High</abbr>\n')
table.insert(t, '!width=55|<abbr title="Lowest season attendance">Low</abbr>\n')
table.insert(t, '!width=55|<abbr title="Median season attendance">Median</abbr>\n')
table.insert(t, '!width=55|<abbr title="Average season attendance">Average</abbr>\n')
table.insert(t, '!width=55|<abbr title="Change in average attendance in comparison with the previous season">Change</abbr>\n')
-- Create data rows
for pos, tname in ipairs(sorted_teams) do
local any = yesno(#team_list[tname].attendance, true) -- Check if any attendance data is available for the team
local total = tname == 'league'
if total then
-- Total row formatting
table.insert(t, '|-class="sortbottom" style="background-color:#d8edf3; font-weight:bold;"\n')
else
-- Team row formatting
table.insert(t, '|-\n')
end
table.insert(t, '| style="text-align:center;" |'..(any and not total and pos or '')..'\n')
table.insert(t, '| style="text-align:left;" |'..(Args['team_'..tname] or team_list[tname].name)..'\n') -- Team name or table footer row name
table.insert(t, '| style="text-align:center;" |'..(any and #team_list[tname].attendance or '')..'\n')
table.insert(t, '| '..(any and lang:formatNum(mm._sum(unpack(team_list[tname].attendance))) or '')..'\n')
table.insert(t, '| '..(any and lang:formatNum(mm._max(unpack(team_list[tname].attendance))) or '')..'\n')
table.insert(t, '| '..(any and lang:formatNum(mm._min(unpack(team_list[tname].attendance))) or '')..'\n')
table.insert(t, '| '..(any and lang:formatNum(mm._median(unpack(team_list[tname].attendance))) or '')..'\n')
table.insert(t, '| style="font-weight:bold" | '..(any and lang:formatNum(team_list[tname].average) or '')..'\n')
-- No newline at end of {{change}} for note to be tacked on
if yesno(Args['previous_'..tname], true) then
if yesno(#team_list[tname].attendance, true) then -- Checking attendance list instead of average since 0 attendance with matches is possible
table.insert(t, '| '..(any and frame:expandTemplate{title='change', args={Args['previous_'..tname], team_list[tname].average, disp='out', dec=1}}))
else
table.insert(t, '| style="text-align:center" | ')
end
else
table.insert(t, '| style="text-align:center" | n/a')
end
if yesno(Args['note_'..tname], true) then
table.insert(t, frame:expandTemplate{title='efn', args={group='lower-alpha', Args['note_'..tname]}})
end
table.insert(t, '\n') -- end change cell
end
-- Close table
table.insert(t, '|}')
-- Create footer
local note_list = {}
if yesno(Args['updated'], true) then
table.insert(note_list, 'Updated to games played on '..Args['updated']..'.')
end
if yesno(Args['source'], true) then
table.insert(note_list, 'Source: '..Args['source'])
else
table.insert(note_list, 'Source: '..frame:expandTemplate{title='Citation needed', args={date=lang:formatDate('F Y')}}..'\n')
end
local t_footer = '<div class="sports-attendance-notes">'..table.concat(note_list, ' ')..'</div>'..frame:expandTemplate{title='notelist', args={group='lower-alpha'}}
return templatestyles..'\n'..table.concat(t)..t_footer
end
return p