-----------
-- Generating Flot plots from Lua scripts
local flot = {}
flot.path = ''
-- can set it to absolute URL of directory containing flot subdir, or to a remote URI
--flot.path = 'file:///c:/users/steve/utils/web/'
local prefix = [[
Lua Flot
]]
local div = [[
]]
local coda = [[
]]
local script = [[
$.plot($("#placeholder%d"),
%s,
%s);
]]
local concat,append = table.concat,table.insert
local as_js
flot.null = setmetatable({},{
__tostring = function(self) return "null" end
})
-- you can of course use any available Lua JSON library here - this is good
-- enough for our purposes.
function as_js (t)
local mt = getmetatable(t)
if type(t) ~= 'table' or (mt and mt.__tostring) then
return type(t) == 'string' and '"'..t..'"' or tostring(t)
elseif #t > 0 then -- it's an array!
local res = {}
for i = 1,#t do
res[i] = as_js(t[i])
end
return '['..concat(res,',')..']'
else
local res = {}
for k,v in pairs(t) do
append(res,k..':'..as_js(v))
end
return '{'..concat(res,',')..'}'
end
end
local function interleave (xv,yv)
local res = {}
for i = 1,#xv do
res[i] = {xv[i],yv[i]}
end
return res
end
function flot.range (x1,x2,incr)
local res, i = {}, 1
for x = x1,x2,incr do
res[i] = x
i = i + 1
end
return res
end
local kount = 0
function flot.Plot (opts)
local plot = {}
if _G.FLOT_PLACEHOLDER then
plot.idx = _G.FLOT_PLACEHOLDER
else
kount = kount + 1
plot.idx = kount
end
opts = opts or {}
plot.width = opts.width or 600
plot.height = opts.height or 400
plot.xvalues = opts.xvalues
opts.width = nil -- no harm, but they're not valid options.
opts.height = nil
opts.xvalues = nil
local dataset, append = {}, table.insert
function plot:add_series(label,data,kind)
kind = kind or { lines = { show = true }}
kind.label = label
if data.x then
data = interleave(data.x,data.y)
elseif plot.xvalues and type(data[1]) ~= 'table' then
data = interleave(plot.xvalues,data)
end
kind.data = data
append(dataset,kind)
end
function plot:script ()
return script:format(self.idx,as_js(dataset),as_js(opts))
end
return plot
end
function flot.render (plot)
local p = flot.path
local header = prefix:format(p,p,p)
local div = div:format(plot.idx,plot.width,plot.height,plot:script())
local name
if arg then -- not interactive
name = arg[0]:match('([%w_%-]+)%.lua')
end
-- hack for suppressing headers and forcing dump to stdout
if _G.FLOT_PLACEHOLDER then name = nil end
if name then
local d = header .. div .. coda
local f = io.open(name..'.html','w')
f:write(d)
f:close()
else
io.write(div)
end
end
return flot