Modul:Table
Utseende
Dokumentationen för denna modul kan skapas på Modul:Table/dok
local tab = {}
local lang = mw.getContentLanguage()
local chart = require("Modul:Chart")
require("Modul:Debug")
local defColors = require "Module:Plotter/DefaultColors"
local function addTitlesToChart(htmlContent, xTitle, yTitle, chartWidth, chartHeight,iColumns)
-- Create the HTML for the x-axis title with centered alignment
local xTitleHtml
if (iColumns==1) then
xTitleHtml= '<div style="text-align:center;font-weight:bold;position:relative;top:-50px;width:' .. chartWidth .. 'px;">' .. xTitle .. '</div>'
else
xTitleHtml = '<div style="text-align:center;font-weight:bold;margin-top:20px;width:' .. chartWidth .. 'px;">' .. xTitle .. '</div>'
end
-- Create the HTML for the y-axis title with adjusted positioning
lengthYtitle = string.len(yTitle)*8 --length in pixels, about 8 pixels per char
local yTitleHtml = '<div style="transform: rotate(-90deg);transform-origin: left top 0;position:absolute;font-weight:bold;margin-top:' .. ((chartHeight-lengthYtitle)/2) .. 'px;">' .. yTitle .. '</div>'
-- local yTitleHtml = '<div style="transform: rotate(-90deg);transform-origin: left top 0;position:absolute;font-weight:bold;top:50%;">' .. yTitle .. '</div>'
-- Find the position to insert the y-axis title (after the opening div of the chart container)
local chartDivStart = string.find(htmlContent, 'class="chart noresize"', 1, true)
if chartDivStart then
-- Find the end of the opening div tag
local divEnd = string.find(htmlContent, '>', chartDivStart)
if divEnd then
-- Insert the y-axis title right after the opening div tag
htmlContent = string.sub(htmlContent, 1, divEnd) .. yTitleHtml .. string.sub(htmlContent, divEnd + 1)
else
print("End of opening div tag not found. Cannot insert y-axis title.")
end
else
print("Chart div not found. Cannot insert y-axis title.")
end
-- Find the position to insert the x-axis title (before the closing div of the chart container)
local chartDivEnd = string.find(htmlContent, '</div>', -20, true)
if chartDivEnd then
-- Insert the x-axis title right before the closing div tag
htmlContent = string.sub(htmlContent, 1, chartDivEnd) .. xTitleHtml .. string.sub(htmlContent, chartDivEnd)
htmlContent = string.gsub(htmlContent,"<<","<")
else
print("Chart div not found. Cannot insert x-axis title.")
end
return htmlContent
end
--Function that reads data and put it into a structure that other functions use to present the data
tab.data=function(myframe)
local step = tonumber(myframe.args['step'])
if (not step) then step = 1 end
tab.step=step
columns = mw.text.split(myframe.args['columns'],"%s*,%s*")
iTitles=(#columns)
tab.columntypes = mw.text.split(myframe.args['columntypes'],"%s*,%s*")
if not (#columns==#tab.columntypes) then
error("Number of columns and their types not matching")
end
local xmin = tonumber(myframe.args['xmin'])
local xmax = tonumber(myframe.args['xmax'])
local factor = tonumber(myframe.args['factor'])
if (not factor) then factor = 1 end
tab.factor=factor
local combination = myframe.args['combination']
local files=mw.text.split(myframe.args['file'],",")
local iPages=#files
local filelabels
if (iPages>1) then
local strfilelabels=myframe.args['filelabels']
if (strfilelabels) then
filelabels= mw.text.split(strfilelabels,",")
else
error("Multiple files use, but no 'filelabels' used as argument to give them labels")
end
if not (#filelabels==#files) then
error("Number of files and their labels not matching")
end
tab.iColumns=(iTitles-1)*iPages
else
tab.iColumns=(iTitles-1)*iPages
end
local jsonFileContent
tab.values={}
tab.xvalues={}
tab.iTiles=0
tab.titles={}
for i, page in ipairs(files) do
mw.log("i: " .. i)
jsonFileContent = mw.ext.data.get(page)
if jsonFileContent then
if next(jsonFileContent) then
tab.fields=jsonFileContent.fields;
data=jsonFileContent.data;
schema=jsonFileContent.schema;
indices={}
tab.xtitle=tab.titles[1]
for j=1,iTitles do
local index,selecteddata=tab.filter(schema,"fields","name",columns[j],false)
table.insert(indices,index)
if (j>1) then
if (iPages==1) then
table.insert(tab.titles,selecteddata.title)
else
if (iTitles==2) then
table.insert(tab.titles,filelabels[i])
else
if (combination=="filefirst") then
table.insert(tab.titles,filelabels[i] .. " (" .. selecteddata.title .. ")" )
end
if (combination=="columnfirst") then
table.insert(tab.titles,selecteddata.title .. " (" .. filelabels[i] .. ")")
end
end
end
end
end
-- table.remove(tab.titles,1)
local dataitems=#data/tab.step
local jRowWrite=0
for jRow=1,dataitems do
mw.log("jRow: " .. jRow)
local jRowRead=1+(jRow-1)*tab.step
xvalue=data[jRowRead][1]
minok=(not xmin) or (xvalue>=xmin)
maxok=(not xmax) or (xvalue<=xmax)
if (minok and maxok) then
jRowWrite=jRowWrite+1
if (i==1) then
tab.values[jRowWrite]={}
table.insert(tab.xvalues,xvalue)
end
for k=2,iTitles do
index=indices[k]
table.insert(tab.values[jRowWrite],data[jRowRead][index]*factor)
end
end
end
tab.iDataitems=#tab.xvalues
else
error("The page '" .. page .. "' contains no data")
end
else
error("The page '" .. page .. "' does not exist")
end
end
mw.log(tprint(tab))
return tprint(tab)
end
tab.showBarChart=function(frame)
local myframe=frame
local width=myframe.args["width"]
local height=myframe.args["height"]
local xtitle=myframe.args["xtitle"]
local ytitle=myframe.args["ytitle"]
local stack=myframe.args["stack"]
local xtick=myframe.args["xtick"]
if (not xtick) then xtick = 1 end
myframe.args={}
myframe.args=frame.args
local indices={}
local titles={}
local types={}
if height then
myframe.args["height"]=height
end
if stack then
myframe.args["stack"]=stack
end
if not width then width="1400" end
myframe.args["width"]=width
myframe.args["group names"]=table.concat(tab.titles,":")
myframe.args["colors"]=defColors[1]
for ii=1,20,2 do
table.remove(defColors,ii)
end
table.remove(defColors,1)
local count = 1
for k, v in pairs(defColors) do
if count < (tab.iColumns) then
myframe.args["colors"]=myframe.args["colors"] .. ":" .. v
count = count + 1
else
break
end
end
jfirst=true
tab.step=2
for j=1,tab.iDataitems do
thisvalue=""
if (((j-1) % xtick) == 0) then
thisvalue=tab.xvalues[j]
end
if (jfirst==true) then
myframe.args["x legends"]=thisvalue
jfirst=false
else
myframe.args["x legends"]=myframe.args["x legends"] .. ":" .. thisvalue
end
for i=1,tab.iColumns do
txtTarget="group " .. i
value=tab.values[j][i]
if (j==1) then
myframe.args[txtTarget]=value
else
myframe.args[txtTarget]=myframe.args[txtTarget] .. ":" .. value
end
end
end
mw.log(tprint(myframe))
-- local html=tprint(myframe)
local html=chart["bar chart"](myframe)
if (xtitle or ytitle) then
html = addTitlesToChart(html, xtitle, ytitle,width,600,1)
---- html = addTitlesToChart(html, "xtitle", "ytitle")
end
return html
end
tab.showColumnTable=function(frame)
local types={}
local tblTxt={}
table.insert(tblTxt,"<table class='wikitable'>")
table.insert(tblTxt,"<tr>")
table.insert(tblTxt,"<th>")
table.insert(tblTxt,tab.xtitle)
table.insert(tblTxt,"</th>")
for i=1,tab.iColumns do
table.insert(tblTxt,"<th>")
table.insert(tblTxt,tab.titles[i])
table.insert(tblTxt,"</th>")
end
table.insert(tblTxt,"</tr>")
-- Data
for j=1,tab.iDataitems do
table.insert(tblTxt,"<tr>")
value=tab.xvalues[j]
if (tab.columntypes[1]=="value") then
table.insert(tblTxt,"<td align='right'>")
table.insert(tblTxt,lang:formatNum( value ))
else
table.insert(tblTxt,"<td>")
table.insert(tblTxt,value)
end
table.insert(tblTxt,"</td>")
for i=1,tab.iColumns do
value=tab.values[j][i]
if (tab.columntypes[i+1]=="value") then
table.insert(tblTxt,"<td align='right'>")
table.insert(tblTxt,lang:formatNum( value ))
else
table.insert(tblTxt,"<td>")
table.insert(tblTxt,value)
end
table.insert(tblTxt,"</td>")
end
table.insert(tblTxt,"</tr>")
end
table.insert(tblTxt,"</tr>")
table.insert(tblTxt,"</table>")
return table.concat(tblTxt)
end
tab.showColumn=function(frame)
tabdata=tab.data(frame)
if (frame.args["output"]=="table") then
return tab.showColumnTable(frame)
end
if (frame.args["output"]=="chart") then
return tab.showBarChart(frame)
end
end
tab.showRow=function(frame)
local pageName = frame.args['file']
local data = mw.ext.data.get(pageName)
if (frame.args["output"]=="table") then
return tab.showRowTable(frame,data)
end
if (frame.args["output"]=="chart") then
return tab.showPieChart(frame,data)
end
return tprint(data.schema.fields)
-- return tprint(myframe)
end
tab.showRowTable=function(frame,data)
local category = frame.args['category']
local row = frame.args['row']
local unit = frame.args['unit']
local xlabel = frame.args['xlabel']
local ylabel = frame.args['ylabel']
local index,selecteddata=tab.filter(data.schema,"fields","name",category,false)
local index2,selecteddata2=tab.filter(data,"data",index,row,true)
local tblTxt={}
table.insert(tblTxt,"<table class='wikitable sortable'>")
table.insert(tblTxt,"<tr>")
table.insert(tblTxt,"<th>" .. xlabel .. "</td>")
table.insert(tblTxt,"<th data-sort-type='number'>" .. ylabel .. " (" .. unit .. ")</td>")
table.insert(tblTxt,"</tr>")
local first=true
for i=1,#data.schema.fields do
if not (i==index) then
local value=data.data[index2][i]
table.insert(tblTxt,"<tr>")
table.insert(tblTxt,"<td>" .. data.schema.fields[i].title .. "</td>")
table.insert(tblTxt,"<td align='right'>" .. data.data[index2][i] .. "</td>") --lang:formatNum()
table.insert(tblTxt,"</tr>")
end
end
table.insert(tblTxt,"</table>")
return table.concat(tblTxt)
end
function tochartstring(input)
return string.gsub(input, ",", ":")
end
tab.showPieChart=function(frame,data)
local category = frame.args['category']
local row = frame.args['row']
local unit = frame.args['unit']
local radius=frame.args["radius"]
local minimum=tonumber(frame.args["minimum"])
local index,selecteddata=tab.filter(data.schema,"fields","name",category,false)
local index2,selecteddata2=tab.filter(data,"data",index,row,true)
local myframe=frame
myframe.args={}
myframe.args=frame.args
myframe.args["slices"]=''
if not radius then radius="150" end
myframe.args["radius"]=radius
others=0
txtOthers="Övriga"
local first=true
for i=1,#data.schema.fields do
if not (i==index) then
local value=data.data[index2][i]
if (not minimum or value>minimum) then -- either not asking for values to be above a minimum value, or the values are above the minimum value
myframe.args["slices"]=myframe.args["slices"] .. '(' .. value .. ' : ' .. data.schema.fields[i].title .. ')'
else
others=others+tonumber(value)
end
end
end
if (others>0) then
myframe.args["slices"]=myframe.args["slices"] .. '(' .. others .. ' : ' .. txtOthers .. ')'
end
myframe.args['percent']=true
myframe.args['units suffix']="_" .. unit
return chart["pie chart"](myframe)
end
local function decodeHtmlEntities(htmlContent)
-- Decode common HTML entities
htmlContent = string.gsub(htmlContent, "<", "<")
htmlContent = string.gsub(htmlContent, ">", ">")
htmlContent = string.gsub(htmlContent, "&", "&")
htmlContent = string.gsub(htmlContent, """, '"')
htmlContent = string.gsub(htmlContent, "'", "'")
return htmlContent
end
tab.filter=function(tblIn,txtProperty,txtVariable,selectedvalue,bIsnumber)
local tblProperty=tblIn[txtProperty] -- Get chosen property
local iItems=#tblProperty -- Count number of items
local tblOut={} -- Empty table that will be filled by the results of the filter query
local indices={}
for i=1,iItems do -- Loop through all items
if (not bIsnumber and (tblProperty[i][txtVariable]==selectedvalue)) or (bIsnumber and ((tblProperty[i][txtVariable]==selectedvalue) or (tonumber(tblProperty[i][txtVariable])==tonumber(selectedvalue)))) then -- If the data value for the chosen variable of this item is the same as the selected value (for the filter) ...
return i,tblProperty[i] -- Return the out table
end
end
end
-- Funktion från https://stackoverflow.com/questions/41942289/display-contents-of-tables-in-lua
function tprint (tbl, indent)
if not indent then indent = 0 end
local toprint = string.rep(" ", indent) .. "{\r\n"
indent = indent + 2
for k, v in pairs(tbl) do
toprint = toprint .. string.rep(" ", indent)
if (type(k) == "number") then
toprint = toprint .. "[" .. k .. "] = "
elseif (type(k) == "string") then
toprint = toprint .. k .. "= "
end
if (type(v) == "number") then
toprint = toprint .. v .. ",\r\n"
elseif (type(v) == "string") then
toprint = toprint .. "\"" .. v .. "\",\r\n"
elseif (type(v) == "table") then
toprint = toprint .. tprint(v, indent + 2) .. ",\r\n"
else
toprint = toprint .. "\"" .. tostring(v) .. "\",\r\n"
end
end
toprint = toprint .. string.rep(" ", indent-2) .. "}"
return toprint
end
return tab