Test Wikimedia Commons testcommonswiki https://test-commons.wikimedia.org/wiki/Main_Page MediaWiki 1.45.0-wmf.6 first-letter Media Special Talk User User talk Commons Commons talk File File talk MediaWiki MediaWiki talk Template Template talk Help Help talk Category Category talk Creator Creator talk TimedText TimedText talk Sequence Sequence talk Institution Institution talk Data Data talk TimedText TimedText talk Module Module talk Translations Translations talk Module:TabUtils 828 2434 5025 5024 2025-06-16T20:06:00Z Brooke Vibber (WMF) 1355 drop the inline, it's cute but not the best way to do that i fwe want to support it ;) 5025 Scribunto text/plain -- -- Experimental tabular data utilities for Chart transforms -- See https://www.mediawiki.org/wiki/Extension:Chart/Transforms -- local p = {} -- -- build a map of column names -> indexes -- @internal -- function colmap( tab ) local cols = {} for i, field in ipairs( tab.schema.fields ) do cols[field.name] = i end return cols end -- -- select: subset a data set by column reference or comparison on row values -- -- Arguments: -- * cols: comma-separated list of column names to keep, otherwise returns all cols -- * where: column name to match on, otherwise returns all rows -- * eq, ne, gt, lt, gte, lte: value to compare against to keep rows -- * sort: column name to sort on -- * order: sort order "asc" or "desc", defaults to "asc" -- function p.select( tab, args ) local map = colmap( tab ) local where = nil if args.where then local index = map[args.where] local field = tab.schema.fields[index] local function convert( val ) if field.type == "number" then return tonumber( val ) elseif field.type == "localized" then error( "todo: support localized fields" ) else return val end end local comparator if args.eq then local against = convert( args.eq ) comparator = function ( val ) return val == against end elseif args.ne then local against = convert( args.ne ) comparator = function ( val ) return val ~= against end elseif args.gt then local against = convert( args.gt ) comparator = function ( val ) return val > against end elseif args.lt then local against = convert( args.lt ) comparator = function ( val ) return val < against end elseif args.gte then local against = convert( args.gte ) comparator = function ( val ) return val >= against end elseif args.lte then local against = convert( args.lte ) comparator = function ( val ) return val <= against end else error( "'where' must provide argument for 'eq', 'ne', 'gt', 'lt', 'gte', or 'lte'" ) end local newdata = {} for _, row in ipairs( tab.data ) do if comparator( row[index] ) then table.insert( newdata, row ) end end tab.data = newdata end if args.cols then local cols = mw.text.split( args.cols, ",", true ) local newfields = {} local newdata = {} for i, name in ipairs( cols ) do table.insert( newfields, tab.schema.fields[map[name]] ) end for n, row in ipairs( tab.data ) do local newrow = {} for i, name in ipairs( cols ) do table.insert( newrow, row[map[name]] ) end table.insert( newdata, newrow ) end tab.schema.fields = newfields tab.data = newdata map = colmap( tab ) end if args.sort then local index = map[args.sort] if not index then error("Missing sort column: " .. args.sort) end local comparator if args.order == "desc" then comparator = function ( a, b ) return a[index] > b[index] end elseif args.order == "asc" or not args.order then comparator = function ( a, b ) return a[index] < b[index] end else error("Invalid sort order: " .. args.order) end table.sort( tab.data, comparator ) end return tab end -- -- Convenience function for testing/debugging, run from console -- while editing this module. -- function p.demo() local tab = mw.ext.data.get( "Sample_weekly_temperature_dataset.tab", "_" ) mw.logObject( p.select( tab, { ["cols"] = "month,high", ["where"] = "high", ["lt"] = "25" } ) ) end function p.demoSort(order) local tab = mw.ext.data.get( "Sample_weekly_temperature_dataset.tab", "_" ) mw.logObject( p.select( tab, { ["cols"] = "month,high", ["sort"] = "high", ["order"] = order } ) ) end return p a0e1xganwuwhra3ddbh66vkx5sgctjg 5026 5025 2025-06-16T20:28:28Z Brooke Vibber (WMF) 1355 decimate option 5026 Scribunto text/plain -- -- Experimental tabular data utilities for Chart transforms -- See https://www.mediawiki.org/wiki/Extension:Chart/Transforms -- local p = {} -- -- build a map of column names -> indexes -- @internal -- function colmap( tab ) local cols = {} for i, field in ipairs( tab.schema.fields ) do cols[field.name] = i end return cols end -- -- select: subset a data set by column reference or comparison on row values -- -- Arguments: -- * cols: comma-separated list of column names to keep, otherwise returns all cols -- * where: column name to match on, otherwise returns all rows -- * eq, ne, gt, lt, gte, lte: value to compare against to keep rows -- * sort: column name to sort on -- * order: sort order "asc" or "desc", defaults to "asc" -- * decimate: keep only every nth row -- function p.select( tab, args ) local map = colmap( tab ) if args.decimate then local n = tonumber( args.decimate ) local newdata = {} for i, row in ipairs( tab.data ) do if i % n == 0 then table.insert(newdata, row) end end tab.data = newdata end local where = nil if args.where then local index = map[args.where] local field = tab.schema.fields[index] local function convert( val ) if field.type == "number" then return tonumber( val ) elseif field.type == "localized" then error( "todo: support localized fields" ) else return val end end local comparator if args.eq then local against = convert( args.eq ) comparator = function ( val ) return val == against end elseif args.ne then local against = convert( args.ne ) comparator = function ( val ) return val ~= against end elseif args.gt then local against = convert( args.gt ) comparator = function ( val ) return val > against end elseif args.lt then local against = convert( args.lt ) comparator = function ( val ) return val < against end elseif args.gte then local against = convert( args.gte ) comparator = function ( val ) return val >= against end elseif args.lte then local against = convert( args.lte ) comparator = function ( val ) return val <= against end else error( "'where' must provide argument for 'eq', 'ne', 'gt', 'lt', 'gte', or 'lte'" ) end local newdata = {} for _, row in ipairs( tab.data ) do if comparator( row[index] ) then table.insert( newdata, row ) end end tab.data = newdata end if args.cols then local cols = mw.text.split( args.cols, ",", true ) local newfields = {} local newdata = {} for i, name in ipairs( cols ) do table.insert( newfields, tab.schema.fields[map[name]] ) end for n, row in ipairs( tab.data ) do local newrow = {} for i, name in ipairs( cols ) do table.insert( newrow, row[map[name]] ) end table.insert( newdata, newrow ) end tab.schema.fields = newfields tab.data = newdata map = colmap( tab ) end if args.sort then local index = map[args.sort] if not index then error("Missing sort column: " .. args.sort) end local comparator if args.order == "desc" then comparator = function ( a, b ) return a[index] > b[index] end elseif args.order == "asc" or not args.order then comparator = function ( a, b ) return a[index] < b[index] end else error("Invalid sort order: " .. args.order) end table.sort( tab.data, comparator ) end return tab end -- -- Convenience function for testing/debugging, run from console -- while editing this module. -- function p.demo() local tab = mw.ext.data.get( "Sample_weekly_temperature_dataset.tab", "_" ) mw.logObject( p.select( tab, { ["cols"] = "month,high", ["where"] = "high", ["lt"] = "25" } ) ) end function p.demoSort(order) local tab = mw.ext.data.get( "Sample_weekly_temperature_dataset.tab", "_" ) mw.logObject( p.select( tab, { ["cols"] = "month,high", ["sort"] = "high", ["order"] = order } ) ) end return p 3p58jcioul6t8knsya8tqf0yvzu10gn