Module:CCI stats
Appearance
local TableTools = require("Module:TableTools");
local getArgs = require("Module:Arguments").getArgs;
local p = {}
--- Extracts case open and close dates from wikitext.
-- @param opens The table to append open dates to.
-- @param opens The table to append close dates to.
-- @param wikitext The wikitext to parse.
function p._extractCaseDates(opens, closes, wikitext)
for openDate in mw.ustring.gmatch(wikitext, "data%-cci%-open=['\"](.-)['\"]") do
table.insert(opens, tonumber(openDate))
end
for closeDate in mw.ustring.gmatch(wikitext, "data%-cci%-close=['\"](.-)['\"]") do
table.insert(closes, tonumber(closeDate))
end
return opens, closes, wikitext
end
--- Returns a tuple containing case dates, the first being all the dates where a
-- case was opened, the second being all the dates where a case was closed. All
-- dates are in stats format (i.e. days since the first day of the UNIX epoch,
-- January 1, 1970).
-- @param noArchive `true` to exclude counting archives. `closes` will be empty.
function p._getCaseDates(noArchive)
local frame = mw.getCurrentFrame()
local opens = {}
local closes = {}
p._extractCaseDates(
opens, closes, frame:expandTemplate{ title = "CCIlist" }
)
if not noArchive then
p._extractCaseDates(
opens, closes, frame:expandTemplate{ title = "Wikipedia:Contributor copyright investigations/Archive" }
)
end
table.sort(opens)
table.sort(closes)
return opens, closes
end
--- Transforms a table of case opening and closing dates and returns a table
-- of overall case count change for each day. This function will does not return
-- any duplicate keys.
function p._caseDatesToCaseNet(opens, closes)
local caseNet = {}
for _, date in ipairs(opens) do
if not caseNet[date] then
caseNet[date] = 1
else
caseNet[date] = caseNet[date] + 1
end
end
for _, date in ipairs(closes) do
if not caseNet[date] then
caseNet[date] = -1
else
caseNet[date] = caseNet[date] - 1
end
end
return caseNet
end
--- Transforms a table of case net dates and returns a table with date:caseCount
-- pairs.
function p._caseNetToDateCaseCounts(caseNet)
local dateCaseCounts = {}
local lastValue = 0
for date, net in TableTools.sortedPairs(caseNet) do
dateCaseCounts[date] = lastValue + net
lastValue = lastValue + net
end
return dateCaseCounts
end
--- Transforms date case counts to Vega data.
function p._dateCaseCountsToVega(dateCaseCounts)
local values = {}
for date, caseCount in TableTools.sortedPairs(dateCaseCounts) do
table.insert(values, {
-- Multiply by seconds in a day to get UNIX timestamp.
x = date * 86400,
y = caseCount
})
end
return {
data = {
{
name = "cases",
values = values
}
},
scales = {
{
name = "Date",
type = "time",
range = "width",
domain = { data = "cases", field = "x" }
},
{
name = "Open cases",
range = "height",
nice = true,
domain = { data = "cases", field = "y" }
}
},
axes = {
{ type = "x", scale = "Date" },
{ type = "y", scale = "Open cases" }
},
marks = {
{
type = "line",
from = { data = "cases" },
properties = {
enter = {
x = { scale = "Date", field = "x" },
y = { scale = "Open cases", field = "y" },
stroke = { value = "#000" }
}
}
}
}
}
end
--- Build a graph with the relevant data.
local function buildGraph(frame, args, settings)
local graphSettings = {
version = "2",
width = args.width or 600,
height = args.height or 300,
padding = {
top = args.paddingTop or 10,
right = args.paddingTop or 10,
bottom = args.paddingTop or 30,
left = args.paddingTop or 30
}
}
local graphContent = TableTools.deepCopy(graphSettings)
for k,v in TableTools.sortedPairs(settings) do graphContent[k] = v end
return frame:extensionTag{
name = "graph",
content = mw.text.jsonEncode(
graphContent,
mw.text.JSON_PRETTY
)
}
end
function p._graphCases(args)
local opens, closes = p._getCaseDates(args.noArchive)
local caseNet = p._caseDatesToCaseNet(opens, closes)
local dateCaseCounts = p._caseNetToDateCaseCounts(caseNet)
local vegaData = p._dateCaseCountsToVega(dateCaseCounts)
return buildGraph(args.frame, args.args, vegaData)
end
function p.graphCases(frame)
local args = getArgs(frame, {
trim = true,
removeBlanks = false
})
return p._graphCases{
frame = frame,
args = args,
from = args.from,
upto = args.upto
}
end
return p