Skip to content

Instantly share code, notes, and snippets.

@alesya-h
Created December 2, 2012 20:05
Show Gist options
  • Save alesya-h/4190765 to your computer and use it in GitHub Desktop.
Save alesya-h/4190765 to your computer and use it in GitHub Desktop.
Стаааарый тримапер
#!/usr/bin/env ruby
require 'rmagick'
class Array
alias :head :first
def tail
self[1..-1]
end
end
module Treemap
attr_accessor :x,:y,:w,:h,:children
class Rectangle
def initialize(x,y,w,h)
@x,@y,@w,@h = x,y,w,h
@children = []
end
def add_child(c)
@children.push c
end
def flatten
if @children.empty?
return [self]
else
return @children.map(&:flatten).inject(&:+)
end
end
end
module Treemapper
def draw(canvas,x,y,w,h,root)
v_w = Math.sqrt(w*root.size/h)
v_h = root.size / v_w
picture = squarify(0,0,v_w,v_h,root.children)
# make picture translation and visualisation here
drawing = Magick::Draw.new
drawing.stroke('black')
drawing.fill_opacity(0)
drawing.stroke_width(1)
drawing.stroke_opacity(1)
picture.flatten.each do |r|
drawing.rectangle(x+r.x*w/v_w,
y+r.y*h/v_h,
x+r.x*w/v_w + r.w*w/v_w,
y+r.y*h/v_h + r.h*h/v_h)
end
drawing.draw(canvas)
end
def tall(row,side)
row.map(&:size).inject(&:+)/side
end
def worst(row,w)
s=row.map(&:size).inject(&:+)
x = [(w*w*row.max.size)/(s*s),(s*s)/(w*w*row.min.size)]
x.max
end
def squarify(x,y,w,h,children)
if children.empty?
return Rectangle.new(x,y,w,h)
elsif children.size == 1
return squarify(x,y,w,h,children.first.children)
else
row_orientation = (h<w) ? :vert : :horiz
picture = Rectangle.new(x,y,w,h)
small_side = (h < w) ? h : w
row = children.shift(1)
while worst(row,small_side) >= worst(row+[children.first],small_side)
row += children.shift(1)
end
delta = 0.0
t=tall(row,small_side)
case row_orientation
when :vert
row.each do |elem|
picture.add_child squarify(x, y+delta, t, elem.size/t,
[elem])
delta += elem.size/t
end
picture.add_child squarify(x+t,y,w-t,h,children)
when :horiz
row.each do |elem|
picture.add_child squarify(x+delta, y, elem.size/t, t,
[elem])
delta += elem.size/t
end
picture.add_child squarify(x,y+t,w,h-t,children)
end
end
end
end
class Node
attr_accessor :size
attr_accessor :children
attr_accessor :path
attr_accessor :name
def initialize
@children = []
@size = 0.0
@path = nil
@name = nil
end
def inspect
"{#{@size}}"
end
def <=>(n)
return @size <=> n.size
end
end
end
def process_directory(path,name)
n = Node.new
n.path = path
n.name = name
if path
full_name = path+"/"+name
else
full_name = name
end
if FileTest.symlink?(full_name)
return nil
end
unless FileTest.directory?(full_name)
n.size = File.size(full_name)
n.children=[]
if n.size != 0
return n
else
return nil
end
else FileTest.readable?(full_name)
begin
d = Dir.open(full_name)
d.select{|x| x!="." and x!=".."}.each do |entry|
if child = process_directory(full_name,entry)
n.size += child.size
n.children.push child
end
end
rescue e
n.size = 0
ensure
d.close unless d.nil?
end
if n.size == 0
return nil
end
n.children.sort!.reverse!
return n
end
end
puts "Usage: ./treemap.rb [dir] [width] [height] [outfile]"
path = ARGV[0] || "."
w = ARGV[1] || "1024"
h = ARGV[2] || "768"
filename = ARGV[3] || "out.png"
include Treemap
print "Processing directory structure..."
root = process_directory(nil,path)
puts " finished."
root.children.each do |node|
puts node.path + "/" + node.name + " : " + node.size.to_s
end
canvas = Magick::ImageList.new
canvas.new_image(1366,768,Magick::HatchFill.new('white'))
include Treemapper
print "Building treemap... "
draw(canvas,0,0,1366,768,root)
puts " finished."
print "Writing treemap to "+filename
canvas.write("out.png")
puts " finished."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment