Moduł:Demografia
Moduł do generowania tabelki z danymi demograficznymi.
Raport
[edytuj kod]
Funkcja do generowania wierszy tabelki z danymi demograficznymi.
Uwaga funkcja nie generuje początku ani końca tabelki. W szczególności nagłówek tabelki trzeba podawać przed każdym wywołaniem funkcji.
parametry[edytuj kod]
Pole | Do czego służy? | Jak wypełnić? |
---|---|---|
liczba-kolumn | Liczba kolumn podawanych danych demograficznych z przedziału od 2 do 99. Wartość domyślna to 2. | np. 4 |
liczba-grup | Liczba nadrzędnych grup z przedziału 1 do 99. Wartość domyślna to 1. Uwaga! liczba kolumn musi być podzielna przez liczbę grup. |
np. 2 |
populacja | Nazwa dla wiersza podsumowującego wszystkie dane. Wartość domyślna to Populacja. | np. nie podawać |
miejsce-populacji | Pozycja wiersza podsumowującego wszystkie dane w tabelce.
Wartość domyślna to przed. |
np. nie podawać |
miejsce-ogółem | Pozycja kolumn podsumowujących wiersz.
Wartość domyślna to przed. |
np. nie podawać |
styl-ogółem-wartość | Styl dla komórki z sumą danych. Jeśli nie podano to zwykła komórka tabeli. Jeśli podano ! to komórka nagłówka tabeli. Jeśli podano inną wartość to styl CSS zaaplikowany do zwykłej komórki tabeli.
|
|
styl-ogółem-procent | Styl dla komórki z procentową sumą danych. Jeśli nie podano to zwykła komórka tabeli. Jeśli podano ! to komórka nagłówka tabeli. Jeśli podano inną wartość to styl CSS zaaplikowany do zwykłej komórki tabeli.
|
|
styl-dana-wartość | Styl dla komórki ze źródłową wartością absolutną. Jeśli nie podano to zwykła komórka tabeli. Jeśli podano ! to komórka nagłówka tabeli. Jeśli podano inną wartość to styl CSS zaaplikowany do zwykłej komórki tabeli.
|
|
styl-data-procent | Styl dla komórki ze źródłową wartością procentową. Jeśli nie podano to zwykła komórka tabeli. Jeśli podano ! to komórka nagłówka tabeli. Jeśli podano inną wartość to styl CSS zaaplikowany do zwykłej komórki tabeli.
|
|
styl-opisu | Styl komórki opisu wiersza. Jeśli nie podano to zwykła komórka tabeli. Jeśli podano ! to komórka nagłówka tabeli. Jeśli podano inną wartość to styl CSS zaaplikowany do zwykłej komórki tabeli.
|
|
ogółem-szczegóły | Stopień szczegółów sum cząstkowych
Jeśli parametru nie podano to szczegóły nie są dodawane do wynikowej tabeli. |
|
typ-procentu | Sposób wyznaczania wartości procentowych:
Jeśli parametru nie podano to wartości procentowe obliczane są metodą globalną. |
|
1..N | Dane dla raportu. Należy podawać kolejno dane dla wszystkich wierszy. Pierwszy parametr wiersza to jego opis. Za nim podaje się tyle liczb ile kolumn zostało zadeklarowanych w parametrze liczba-kolumn . Kolejne wiersze podaje się analogicznie. Parametry można podać bezpośrednio w wywołaniu funkcji. Jeśli lista parametrów indeksowanych jest pusta, to funkcja przegląda parametry indeksowane wywołanego szablonu.
|
przykłady[edytuj kod]
Wywołanie:
{| border="1" cellpadding="4" cellspacing="0" style="margin: 0 0 1em 1em; background: #f9f9f9; border: 1px #aaaaaa solid; border-collapse: collapse; text-align:center;" ! rowspan=3 | opis ! rowspan=2 colspan=2 | ogółem ! colspan=4 | grupa A ! colspan=4 | grupa B |- ! colspan=2 | K ! colspan=2 | M ! colspan=2 | K ! colspan=2 | M |- ! osób ! % ! osób ! % ! osób ! % ! osób ! % ! osób ! % {{#invoke:Demografia|Raport|liczba-kolumn=4|liczba-grup=2|styl-ogółem-wartość=font-weight:bold;text-align:right;|styl-ogółem-procent=font-weight:bold;|styl-dana-wartość=text-align:right;|styl-dana-procent=font-weight:bold;|test|10|20|30|40|dane|100|200|300|400|x|a|b|c|d|duże|10000|20000|30000|40000}} |}
Efekt:
opis | ogółem | grupa A | grupa B | |||||||
---|---|---|---|---|---|---|---|---|---|---|
K | M | K | M | |||||||
osób | % | osób | % | osób | % | osób | % | osób | % | |
Populacja | 101 100 | 100 | 10 110 | 10,00 | 20 220 | 20,00 | 30 330 | 30,00 | 40 440 | 40,00 |
test | 100 | 0,10 | 10 | 0,01 | 20 | 0,02 | 30 | 0,03 | 40 | 0,04 |
dane | 1000 | 0,99 | 100 | 0,10 | 200 | 0,20 | 300 | 0,30 | 400 | 0,40 |
x | 0 | 0 | a | — | b | — | c | — | d | — |
duże | 100 000 | 98,91 | 10 000 | 9,89 | 20 000 | 19,78 | 30 000 | 29,67 | 40 000 | 39,56 |
Wywołanie 2:
{| border="1" cellpadding="4" cellspacing="0" style="margin: 0 0 1em 1em; background: #f9f9f9; border: 1px #aaaaaa solid; border-collapse: collapse; text-align:center;" ! rowspan=3 | opis ! colspan=6 | ogółem ! colspan=6 | grupa A ! colspan=6 | grupa B |- ! colspan=2 | Razem ! colspan=2 | K ! colspan=2 | M ! colspan=2 | Razem ! colspan=2 | K ! colspan=2 | M ! colspan=2 | Razem ! colspan=2 | K ! colspan=2 | M |- ! osób ! % ! osób ! % ! osób ! % ! osób ! % ! osób ! % ! osób ! % ! osób ! % ! osób ! % ! osób ! % {{#invoke:Demografia|Raport|liczba-kolumn=4|liczba-grup=2|ogółem-szczegóły=kolumny i grupy|styl-ogółem-wartość=font-weight:bold;text-align:right;|styl-ogółem-procent=font-weight:bold;|styl-dana-wartość=text-align:right;|styl-dana-procent=font-weight:bold;|test|10|20|30|40|dane|100|200|300|400|x|a|b|c|d|duże|10000|20000|30000|40000}} |}
Efekt
opis | ogółem | grupa A | grupa B | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Razem | K | M | Razem | K | M | Razem | K | M | ||||||||||
osób | % | osób | % | osób | % | osób | % | osób | % | osób | % | osób | % | osób | % | osób | % | |
Populacja | 101 100 | 100 | 40 440 | 40,00 | 60 660 | 60,00 | 30 330 | 30,00 | 10 110 | 10,00 | 20 220 | 20,00 | 70 770 | 70,00 | 30 330 | 30,00 | 40 440 | 40,00 |
test | 100 | 0,10 | 40 | 0,04 | 60 | 0,06 | 30 | 0,03 | 10 | 0,01 | 20 | 0,02 | 70 | 0,07 | 30 | 0,03 | 40 | 0,04 |
dane | 1000 | 0,99 | 400 | 0,40 | 600 | 0,59 | 300 | 0,30 | 100 | 0,10 | 200 | 0,20 | 700 | 0,69 | 300 | 0,30 | 400 | 0,40 |
x | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | a | — | b | — | 0 | 0 | c | — | d | — |
duże | 100 000 | 98,91 | 40 000 | 39,56 | 60 000 | 59,35 | 30 000 | 29,67 | 10 000 | 9,89 | 20 000 | 19,78 | 70 000 | 69,24 | 30 000 | 29,67 | 40 000 | 39,56 |
Powyższy opis jest dołączany ze strony Moduł:Demografia/opis. (edytuj | historia)
Zobacz podstrony tego modułu. |
local m = {}
local demographicsData = {
apiName = "Raport",
argNumberOfDataColumns = "liczba-kolumn",
argNumberOfGroups = "liczba-grup",
argSummaryRowTitle = "populacja",
argSummaryRowLocation = "miejsce-populacji",
argSummaryColumnLocation = "miejsce-ogółem",
argSummaryValueStyle = "styl-ogółem-wartość",
argSummaryPercentStyle = "styl-ogółem-procent",
argDataValueStyle = "styl-dana-wartość",
argDataPercentStyle = "styl-dana-procent",
argTitleStyle = "styl-opisu",
argSummaryDetails = "ogółem-szczegóły",
argPercentMode = "typ-procentu",
defaultSummaryTitle = "Populacja",
locationBefore = "przed",
locationAfter = "za",
summaryDetailsNone = "brak",
summaryDetailsColumns = "kolumny",
summaryDetailsGroups = "grupy",
summaryDetailsBoth = "kolumny i grupy",
percentGlobal = "globalny",
percentLocal = "lokalny",
}
local function loadDemographicControlData(frame)
local result = {}
local numberOfDataColumns = frame.args[demographicsData.argNumberOfDataColumns] or "2"
local numberOfGroups = frame.args[demographicsData.argNumberOfGroups] or "1"
if numberOfDataColumns:match"^%d%d?$" then
result.numberOfDataColumns = tonumber(numberOfDataColumns)
else
return nil -- invalid argument
end
if numberOfGroups:match"^%d%d?$" then
result.numberOfGroups = tonumber(numberOfGroups)
else
return nil -- invalid argument
end
if (result.numberOfDataColumns < 2) or (result.numberOfGroups < 1) then
return nil -- invalid arguments
end
local numberOfColumnsInGroup = result.numberOfDataColumns / result.numberOfGroups
if (numberOfColumnsInGroup < 2) or (math.floor(numberOfColumnsInGroup) ~= numberOfColumnsInGroup) then
return nil -- invalid arguments
end
result.numberOfColumnsInGroup = numberOfColumnsInGroup
result.summaryRowTitle = frame.args[demographicsData.argSummaryRowTitle] or demographicsData.defaultSummaryTitle
local location = frame.args[demographicsData.argSummaryRowLocation]
if location then
if location == demographicsData.locationBefore then
result.summaryRowLocation = false
elseif location == demographicsData.locationAfter then
result.summaryRowLocation = true
else
return nil
end
else
result.summaryRowLocation = false
end
location = frame.args[demographicsData.argSummaryColumnLocation]
if location then
if location == demographicsData.locationBefore then
result.summaryColumnLocation = false
elseif location == demographicsData.locationAfter then
result.summaryColumnLocation = true
else
return nil
end
else
result.summaryColumnLocation = false
end
local style = frame.args[demographicsData.argTitleStyle]
if style and #style > 0 then
if style:match'"' then
return nil
else
result.titleStyle = style
end
end
style = frame.args[demographicsData.argSummaryValueStyle]
if style and #style > 0 then
if style:match'"' then
return nil
else
result.summaryValueStyle = style
end
end
style = frame.args[demographicsData.argSummaryPercentStyle]
if style and #style > 0 then
if style:match'"' then
return nil
else
result.summaryPercentStyle = style
end
end
local style = frame.args[demographicsData.argDataValueStyle]
if style and #style > 0 then
if style:match'"' then
return nil
else
result.dataValueStyle = style
end
end
local style = frame.args[demographicsData.argDataPercentStyle]
if style and #style > 0 then
if style:match'"' then
return nil
else
result.dataPercentStyle = style
end
end
local summaryDetails = frame.args[demographicsData.argSummaryDetails]
if summaryDetails then
if summaryDetails == demographicsData.summaryDetailsColumns then
result.showColumnsSummary = true
elseif summaryDetails == demographicsData.summaryDetailsGroups then
result.showGroupsSummary = true
elseif summaryDetails == demographicsData.summaryDetailsBoth then
result.showColumnsSummary = true
result.showGroupsSummary = true
else
return nil
end
end
local percentMode = frame.args[demographicsData.argPercentMode]
if percentMode then
if percentMode == demographicsData.percentGlobal then
result.localPercent = false
elseif percentMode == demographicsData.percentLocal then
result.localPercent = true
else
return nil
end
else
result.localPercent = false
end
return result
end
local function trim(s)
return s:match'^()%s*$' and '' or s:match'^%s*(.*%S)'
end
local function loadIndexedArguments(frame)
local args = {}
for i, v in ipairs(frame.args) do
-- copy direct arguments available by index
-- they overrides template arguments
table.insert(args, trim(v))
end
if #args == 0 then
-- if no indexed arguments are provided
-- use arguments from called template
local parentFrame = frame:getParent()
if parentFrame then
for i, v in ipairs(parentFrame.args) do
-- copy template arguments available by index
table.insert(args, trim(v))
end
end
end
return args
end
local function createReportRow(control)
local function createGroup(columns)
local result = {
total = 0,
}
for i = 1, columns do
result[i] = 0
end
return result
end
local result = {
total = createGroup(control.numberOfColumnsInGroup)
}
for i = 1, control.numberOfGroups do
result[i] = createGroup(control.numberOfColumnsInGroup)
end
return result
end
local function prepareReportData(control, data, rows)
local totalRow = createReportRow(control)
totalRow.title = control.summaryRowTitle
local result = {
total = totalRow,
}
for row = 1, rows do
local baseIndex = (row - 1) * (control.numberOfDataColumns + 1) + 1
local currentRow = createReportRow(control)
table.insert(result, currentRow)
currentRow.title = data[baseIndex]
for column = 1, control.numberOfDataColumns do
local groupNo = math.floor((column - 1) / control.numberOfColumnsInGroup) + 1
local colInGroup = ((column - 1) % control.numberOfColumnsInGroup) + 1
local valueText = data[baseIndex+column]
if valueText:match"^%d%d?%d?%d?%d?%d?%d?%d?%d?%d?%d?$" then
local value = tonumber(data[baseIndex+column])
currentRow[groupNo][colInGroup] = value
-- calculate aggregated values
currentRow[groupNo].total = currentRow[groupNo].total + value
currentRow.total[colInGroup] = currentRow.total[colInGroup] + value
currentRow.total.total = currentRow.total.total + value
totalRow[groupNo][colInGroup] = totalRow[groupNo][colInGroup] + value
totalRow[groupNo].total = totalRow[groupNo].total + value
totalRow.total[colInGroup] = totalRow.total[colInGroup] + value
totalRow.total.total = totalRow.total.total + value
else
currentRow[groupNo][colInGroup] = valueText
end
end
end
return result
end
local function printReportData(control, data, numberOfRows)
local total = data.total.total.total
local lang = mw.getContentLanguage()
local percent = function(value)
if (total <= 0) or (value < 0) then
return " "
elseif value == 0 then
return "0"
elseif value == total then
return "100"
else
local textValue = string.format("%02.2f", 100 * value/total)
local result, _ = string.gsub(textValue,"%.",",",1)
return result
end
end
local function cellFormat(style, value)
if style == "!" then
return "! " .. value
elseif style then
return "|style=\"" .. style .. "\"| " .. value
else
return "| " .. value
end
end
local function printRow(result, control, rawData)
-- new table row with title in first column
table.insert(result, "|-")
table.insert(result, cellFormat(control.titleStyle, rawData.title))
-- leading summary columns
if not control.summaryColumnLocation then
table.insert(result, cellFormat(control.summaryValueStyle, lang:formatNum(rawData.total.total)))
table.insert(result, cellFormat(control.summaryPercentStyle, percent(rawData.total.total)))
if control.showColumnsSummary and (control.numberOfGroups > 1) then
for i = 1, control.numberOfColumnsInGroup do
table.insert(result, cellFormat(control.summaryValueStyle, lang:formatNum(rawData.total[i])))
table.insert(result, cellFormat(control.summaryPercentStyle, percent(rawData.total[i])))
end
end
end
-- data groups
for i = 1, control.numberOfGroups do
local groupData = rawData[i]
-- leading summary in group
if control.showGroupsSummary and (control.numberOfGroups > 1) and not control.summaryColumnLocation then
table.insert(result, cellFormat(control.summaryValueStyle, lang:formatNum(groupData.total)))
table.insert(result, cellFormat(control.summaryPercentStyle, percent(groupData.total)))
end
-- actual data
for j = 1, control.numberOfColumnsInGroup do
local value = groupData[j]
if type(value) == "number" then
table.insert(result, cellFormat(control.dataValueStyle, lang:formatNum(value)))
table.insert(result, cellFormat(control.dataPercentStyle, percent(value)))
else
table.insert(result, cellFormat(control.dataValueStyle, value))
table.insert(result, cellFormat(control.dataPercentStyle, "—"))
end
end
-- remaining summary in group
if control.showGroupsSummary and (control.numberOfGroups > 1) and control.summaryColumnLocation then
table.insert(result, cellFormat(control.summaryValueStyle, lang:formatNum(groupData.total)))
table.insert(result, cellFormat(control.summaryPercentStyle, percent(groupData.total)))
end
end
-- remaining summary columns
if control.summaryColumnLocation then
if control.showColumnsSummary and (control.numberOfGroups > 1) then
for i = 1, control.numberOfColumnsInGroup do
table.insert(result, cellFormat(control.summaryValueStyle, lang:formatNum(rawData.total[i])))
table.insert(result, cellFormat(control.summaryPercentStyle, percent(rawData.total[i])))
end
end
table.insert(result, cellFormat(control.summaryValueStyle, lang:formatNum(rawData.total.total)))
table.insert(result, cellFormat(control.summaryPercentStyle, percent(rawData.total.total)))
end
end
local result = {}
if numberOfRows > 1 and not control.summaryRowLocation then
if control.localPercent then
total = data.total.total.total
end
printRow(result, control, data.total )
end
for i = 1, numberOfRows do
if control.localPercent then
total = data[i].total.total
end
printRow(result, control, data[i])
end
if numberOfRows > 1 and control.summaryRowLocation then
if control.localPercent then
total = data.total.total.total
end
printRow(result, control, data.total )
end
return table.concat(result,"\n")
end
local function DemographicsReport(frame)
local controlData = loadDemographicControlData(frame)
if controlData == nil then
return nil
end
local actualData = loadIndexedArguments(frame)
local numberOfRows = #actualData / (controlData.numberOfDataColumns + 1)
if (numberOfRows < 1) or (math.floor(numberOfRows) ~= numberOfRows) then
return nil -- invalid number of expected data arguments
end
local reportData = prepareReportData(controlData, actualData, numberOfRows)
return printReportData(controlData, reportData, numberOfRows)
end
m[demographicsData.apiName] = DemographicsReport
return m