hill-noise/demo/histogram.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