71 lines
2.1 KiB
Lua
71 lines
2.1 KiB
Lua
local Histogram = setmetatable({}, {__call=function(self,options)
|
|
local h = setmetatable({},{__index=self})
|
|
h:init(options)
|
|
return h
|
|
end})
|
|
|
|
function Histogram:init(options)
|
|
self.pos = options.pos
|
|
self.size = options.size
|
|
local total = 0
|
|
for _,entry in ipairs(options.data) do
|
|
local x, count = unpack(entry)
|
|
total = total + count
|
|
end
|
|
local t = 0
|
|
local iqrMin, iqrMax
|
|
for _,entry in ipairs(options.data) do
|
|
local x, count = unpack(entry)
|
|
t = t + count
|
|
if not iqrMin and t >= .25*total then iqrMin = x end
|
|
if not iqrMax and t >= .75*total then iqrMax = x end
|
|
end
|
|
local h = 2*(iqrMax-iqrMin)*total^(1/3)
|
|
local xmin, xmax = options.xmin or options.data[1][1], options.xmax or options.data[#options.data][1]
|
|
local numBuckets = options.numBuckets or math.max(3, math.min(options.size.x/10, math.ceil((xmax - xmin) * total / h)))
|
|
local buckets = {}
|
|
for i=1,numBuckets do
|
|
buckets[i] = 0
|
|
end
|
|
local ymax = 0
|
|
for _,entry in ipairs(options.data) do
|
|
local x, count = unpack(entry)
|
|
local b = 1 + math.floor((x - xmin)/(xmax - xmin) * (numBuckets-1))
|
|
buckets[b] = (buckets[b] or 0) + count
|
|
ymax = math.max(buckets[b], ymax)
|
|
end
|
|
self.ymax = ymax
|
|
self.xmax = xmax
|
|
self.buckets = buckets
|
|
function self:getX(x)
|
|
return self.pos.x + self.size.x * (x-xmin)/(xmax-xmin)
|
|
end
|
|
end
|
|
|
|
function Histogram:fromList(list, options)
|
|
table.sort(list)
|
|
local data = {}
|
|
for _,x in ipairs(list) do
|
|
if not data[#data] or data[#data][1] ~= x then
|
|
table.insert(data, {x,1})
|
|
else
|
|
data[#data][2] = data[#data][2] + 1
|
|
end
|
|
end
|
|
options.data = data
|
|
return Histogram(options)
|
|
end
|
|
|
|
function Histogram:draw()
|
|
local height = self.size.y / (#self.buckets-1)
|
|
for i,count in ipairs(self.buckets) do
|
|
if count > 0 then
|
|
local width = count/self.ymax * self.size.x
|
|
love.graphics.rectangle('fill', self.pos.x,
|
|
self.pos.y+(#self.buckets-i-1)*height, width, height)
|
|
end
|
|
end
|
|
end
|
|
|
|
return Histogram
|