Module:Sandbox/Ajuanca/GraphIt
Usage
Place the following snippet on the wiki page, replacing function_name with the name of the function to be used, and giving the parameters separated with |
. Specific parameters, the ones with a specific name, like avgs
, are assigned with the =
sign: |avgs=2,3,4|
.
For all the examples shown below, the file Data:COVID-19 cases in Asturias.tab is going to be used.
{{#invoke:Sandbox/Ajuanca|function_name|param1|param2|param name = param value}}
Incidence proportion
This function calculates the incidence proportion of a specific event for all the available dates.
I.e.: The daily confirmed cases of flu per 10.000 inhabitants in Asturias.
Parameters
The possible parameters are:
src=
or the first param: The name of the Tabular file. These files are hosted on Wikimedia Commons, inside the Data namespace ("Data:name of tabular file.tab"). The files in this section must end with the suffix ("Data: name of tabular file.tab"). I.e. The file itself, "COVID-19 cases in Asturias.tab
"column_name=
or the second param: The name of the column where the data of the event is stored. I.e. The column with the total confirmed cases of COVID-19 in Asturias, called "total_cases
".date_name=
or the third param: The name of the column where the date of the data of the event is stored. I.e. The column with the date (in a String format YYYY-MM-DD), called "date
".inhabitants=
or the fourth param: The population size of the given region. I.e. 1,018,775 total inhabitants living in Asturias, according to the INE as a temporarly data for January 1st, 2020.nth=
or the fifth param: The power of 10 for the generated output (the power of ten to the nth, 10n). This value normally will be 4 or 5, althought can be changed for smaller or bigger population sizes. I.e. 5, which causes the output to be given per 105 inhabitants (100,000).graph=
param: A Boolean (true or false) specifiying if a graph should be generated as an output. Default is false. I.e.true
(showing a graph as an output).ltable=
param: A Boolean (true or false) specifiying if the Lua variable should be generated as an output. Default is false. I.e.false
(no returning the variable itself). This is a extrange value to be requested.wtable=
param: A Boolean (true or false) specifiying if a Wikitable table should be generated as an output. Default is false. I.e.false
(no returning a wikitable). This options is still NOT AVAILABLE.
Note 1: Instead of the column_name
parameter, column_title
can be used intead. Alike, date_title
can be given. It is unusual, but two or more columns could have the same title (but not the same name), so this approach is less safe than column_name
and date_name
.
Note 2: If graph=true
is requested, all parameters available at the Module:Graph can be given. They will be passed to this moduled without any kind of modification.
As a recap, the snippet to include will loke like this:
{{#insert:Sandbox/Ajuanca/GraphIt|get_all_incidence|src|colum_name|date_name|inhabitants|nth|graph=true}}
Examples
local p = {}
--[[
------------------
---| EPIDEMICS MODULE |---
------------------
~~ A specialized module to work with epidemics data. ~~
In order to use it:
- Data should be stored in Wikimedia Commons, as a Tabular file.
- The module is added to any wiki with: {{#invoke:path|param1|param2|...}}
- All the functions that don't begin with an underscore are thought
to be invoked. The remaining functions are "internal" functions.
- Make sure you give the correct params. All functions include an
explication.
Please consider writing to my discussion page (User_talk:Ajuanca)
for any problem, question, critic or anything.
ToDo list:
[ ] Generate wikitable
[ ] Add positive rate
Some ideas that maybe are implemented:
* Divide functions (graph, wikitable) instead of booleans??
* Join functions (get_avg_incidence + get_all_incidence = get_incidences)
* Get rid of internal join_tables function.
]]--
mgraph = require("Module:Graph")
-- Join two tables.
-- Number index are added over the first table.
-- Other type of keys are added "as they are".
function p.join_tables(_table1, _table2)
for k, arg in pairs(_table2) do
if not tonumber(k) then
_table1[k] = arg
else
table.insert(_table1, arg)
end
end
return _table1
end
-- Converts table data type to String.
-- Keys should be int numbers.
-- Values are concatenated with ", "
function p.table2string(_table)
original_table = _table
wrapped = ""
for i=1, #original_table do
wrapped = wrapped .. original_table[i] .. ", "
end
return wrapped:sub(0, -3)
end
-- Graph the given data.
-- All Moduule:Graph parameters are given.
function p._graph(args)
local ret = mgraph.chart {args=args}
local graph = mw.getCurrentFrame():extensionTag('graph', ret)
return graph
end
function p._get_avg_incidence(args)
local incidences = args.incidences or args[1]
local dates = args.dates or args[2]
local avg_period = args.period or 3
local periods_avg = {}
local periods_dates = {}
local period_cases = {}
for i, sincidence in ipairs(incidences) do
table.insert(period_cases, sincidence)
if #period_cases == avg_period then
local total = 0
for i = 1, #period_cases do
total = total + tonumber(period_cases[i])
end
table.insert(periods_avg, total/#period_cases)
period_cases = {}
end
end
for i, sdate in ipairs(dates) do
if i%avg_period == 0 then
table.insert(periods_dates, sdate)
end
end
return {periods_avg, periods_dates}
end
-- Get an average for the incidence proportion of a specific event.
-- ie. The week average of the daily confirmed cases of flu.
-- The given parameters are:
-- [1] or src: The tabular data, ie: "example.tab"
-- [2] or column_name: The name of the column.
-- [3] or date_name: The name of the date column.
-- [4] or inhabitants: The population size of the given region.
-- [5] or nth: The power of 10 in which the result is given.
-- column_title: The column title of the data to work with.
-- date_title: The column title of the date.
-- period: The number of values to perform the average with.
-- Default is 3 (ie: 3 days).
function p.get_avg_incidence(frame)
return_graph = frame.args.graph == "true"
return_table = frame.args.ltable == "true"
return_wikitable = frame.args.wtable == "true"
all_incidence = p.join_tables(p._get_all_incidence(frame.args), frame.args)
avg_incidence = p._get_avg_incidence(all_incidence)
to_return = {}
if return_table then
table.insert(to_return, avg_incidence)
end
avg_incidence = p.join_tables(avg_incidence, frame.args)
if return_graph then
avg_incidence.x = p.table2string(table.remove(avg_incidence, 2))
avg_incidence.y = p.table2string(table.remove(avg_incidence, 1))
table.insert(to_return, p._graph(avg_incidence))
end
if return_wikitable then
mw.log("in progress")
end
if #to_return == 1 then
to_return = to_return[1]
end
return to_return
end
function p._get_all_incidence(args)
local data_page = args.src or args[1]
local data = mw.ext.data.get(data_page)
local column_name = args.column_name or args[2]
local date_name = args.date_name or args[3]
local total_residents = tonumber(args.inhabitants) or tonumber(args[4])
local n = tonumber(args.nth) or tonumber(args[5])
local column_title = args.column_title or nil
local date_title = args.date_title or nil
local ci = nil
local di = nil
local column_values = {}
local date_values = {}
for j, field in ipairs(data.schema.fields) do
if field.name == column_name or field.title == column_title then
ci = j
elseif field.name == date_name or field.title == date_title then
di = j
end
if ci and di then
break
end
end
for j, record in ipairs(data.data) do
row_value = (tonumber(record[ci])*10^tonumber(n))/tonumber(total_residents)
table.insert(column_values, row_value)
table.insert(date_values, record[di])
end
return {column_values, date_values}
end
-- Get the incidence proportion of a specific event for all the available dates.
-- Def: "Number of new cases of disease during specified time interval"
-- ie. The daily confirmed cases of flu per 10.000 inhabitants.
-- The given parameters are:
-- [1] or src: The tabular data, ie: "example.tab"
-- [2] or column_name: The name of the column.
-- [3] or date_name: The name of the date column.
-- [4] or inhabitants: The population size of the given region.
-- [5] or nth: The power of 10 in which the result is given.
-- column_title: The column title of the data to work with.
-- date_title: The column title of the date.
function p.get_all_incidence(frame)
all_incidence = p._get_all_incidence(frame.args)
return_graph = frame.args.graph == "true"
return_table = frame.args.ltable == "true"
return_wikitable = frame.args.wtable == "true"
to_return = {}
if return_table then
table.insert(to_return, all_incidence)
end
all_incidence = p.join_tables(all_incidence, frame.args)
if return_graph then
all_incidence.x = p.table2string(table.remove(all_incidence, 2))
all_incidence.y = p.table2string(table.remove(all_incidence, 1))
table.insert(to_return, p._graph(all_incidence))
end
if return_wikitable then
mw.log("in progress")
end
if #to_return == 1 then
to_return = to_return[1]
end
return to_return
end
function p.string2table(_string)
stable = {}
for value in _string:gmatch("[^,]+") do
table.insert(stable, value)
end
return stable
end
-- Get the incidence proportion of a specific event for the specific intervals.
-- Various events and averages can be given. If no averages are specified,
-- daily info is given.
-- ie. The daily confirmed cases of flu per 10.000 inhabitants and the week
-- average of hospital occupation due to flu per 10.000 inhabitants.
-- The given parameters are:
-- [1] or src: The tabular data, ie: "example.tab"
-- [2] or column_names: The names of the columns for the different events.
-- [3] or date_name: The name of the columnthat contains the date information.
-- [4] or inhabitants: The population size of the given region.
-- [5] or nth: The power of 10 in which the result is given.
-- avgs: The averages of the events to be calculated.
-- ie: 3 (days)
function p.get_incidences(frame)
columns = nil
incidences = {}
dates = {}
avgs = nil
if frame.args.column_names then
columns = p.string2table(frame.args.column_names)
else
columns = p.string2table(table.remove(frame.args, 2))
end
if frame.args.avgs then
avgs = p.string2table(frame.args.avgs)
end
if not avgs then
for i, incidence in ipairs(columns) do
frame.args.column_name = incidence
incidence = p._get_all_incidence(frame.args)
table.insert(incidences, incidence[1])
table.insert(dates, incidence[2])
end
else
for i, incidence in ipairs(columns) do
frame.args.column_name = incidence
local all_incidence = p._get_all_incidence(frame.args)
local all_args = p.join_tables(all_incidence, frame.args)
all_args.period = tonumber(avgs[i])
incidence = p._get_avg_incidence(all_args)
table.insert(incidences, incidence[1])
table.insert(dates, incidence[2])
end
end
return_graph = frame.args.graph == "true"
return_table = frame.args.ltable == "true"
return_wikitable = frame.args.wtable == "true"
to_return = {}
if return_table then
table.insert(to_return, {incidences, dates})
end
if return_graph or true then
to_graph = {}
for i, incidence in ipairs(incidences) do
key = "y" .. tostring(i)
to_graph[key] = p.table2string(incidence)
-- xnth values are not inserted due to Module:Graph limitations.
end
to_graph.x = p.table2string(dates[1])
to_graph = p.join_tables(to_graph, frame.args)
table.insert(to_return, p._graph(to_graph))
end
if return_wikitable then
mw.log("in progress")
end
if #to_return == 1 then
to_return = to_return[1]
end
return to_return
end
return p