mtah-ruby-treemap 0.0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile ADDED
@@ -0,0 +1,72 @@
1
+ # -*- coding: undecided -*-
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'rake/clean'
5
+ require 'rake/testtask'
6
+ require 'rake/rdoctask'
7
+ require 'rake/packagetask'
8
+ require 'rake/gempackagetask'
9
+
10
+ $:.unshift(File.dirname(__FILE__) + "/lib")
11
+ require 'treemap'
12
+
13
+ CLEAN.include FileList['test/*.html', 'test/*.png', 'test/*.svg']
14
+ CLEAN.include 'docs'
15
+
16
+ PKG_NAME = 'mtah-ruby-treemap'
17
+ PKG_VERSION = Treemap::VERSION
18
+
19
+ desc 'list available tasks'
20
+ task :default do
21
+ puts "Run 'rake --tasks' for the list of available tasks"
22
+ end
23
+
24
+ Rake::RDocTask.new do |rdoc|
25
+ rdoc.rdoc_dir = 'docs'
26
+ rdoc.title = "RubyTreemap"
27
+ rdoc.options << "--all"
28
+ rdoc.options << "-S"
29
+ rdoc.options << "-N"
30
+ rdoc.options << "--main=README"
31
+ rdoc.rdoc_files.include("README", "EXAMPLES", "TODO", "ChangeLog", "lib/*.rb", "lib/**/*.rb")
32
+ end
33
+
34
+ desc "Run unit tests"
35
+ Rake::TestTask.new do |t|
36
+ t.libs << "test"
37
+ begin
38
+ require 'RMagick'
39
+ t.pattern = 'test/tc_*.rb'
40
+ rescue LoadError
41
+ t.test_files = ['tc_color.rb','tc_html.rb']
42
+ end
43
+ t.verbose = true
44
+ end
45
+
46
+ spec = Gem::Specification.new do |s|
47
+ s.platform = Gem::Platform::RUBY
48
+
49
+ s.name = PKG_NAME
50
+ s.summary = "Treemap visualization in ruby"
51
+ s.description = %q{Treemap visualization in ruby}
52
+ s.version = PKG_VERSION
53
+ s.author = "Martin Häger"
54
+ s.email = "martin.haeger@gmail.com"
55
+ s.homepage = "http://github.com/mtah/ruby-treemap"
56
+
57
+ s.has_rdoc = true
58
+ s.extra_rdoc_files = [ "README", "EXAMPLES" ]
59
+ s.rdoc_options = [ "--main", "README" ]
60
+ s.requirements << 'none'
61
+
62
+ s.require_path = 'lib'
63
+ s.autorequire = 'treemap'
64
+
65
+ s.files = [ "Rakefile", "TODO", "EXAMPLES", "README", "ChangeLog", "COPYING"]
66
+ s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
67
+ s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
68
+ end
69
+
70
+ Rake::GemPackageTask.new(spec) do |p|
71
+ p.need_tar = true
72
+ end
data/TODO ADDED
@@ -0,0 +1,6 @@
1
+ = RubyTreemap - TODO
2
+
3
+ * Lots of testing. Need to create solid unit tests.
4
+ * HTML output seems to be a few pixels off when drawing treemap squares.
5
+ * Better image output support. Need to add the ability to draw labels.
6
+ * Add option to pad squares in treemap.
data/lib/treemap.rb ADDED
@@ -0,0 +1,66 @@
1
+ #
2
+ # treemap.rb - RubyTreemap
3
+ #
4
+ # Copyright (c) 2006 by Andrew Bruno <aeb@qnot.org>
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ #
12
+
13
+ require File.dirname(__FILE__) + '/treemap/node'
14
+ require File.dirname(__FILE__) + '/treemap/layout_base'
15
+ require File.dirname(__FILE__) + '/treemap/output_base'
16
+ require File.dirname(__FILE__) + '/treemap/color_base'
17
+ require File.dirname(__FILE__) + '/treemap/slice_layout'
18
+ require File.dirname(__FILE__) + '/treemap/squarified_layout'
19
+ require File.dirname(__FILE__) + '/treemap/html_output'
20
+ require File.dirname(__FILE__) + '/treemap/rectangle'
21
+ require File.dirname(__FILE__) + '/treemap/gradient_color'
22
+ require File.dirname(__FILE__) + '/treemap/svg_output'
23
+
24
+ # XXX these are still expirmental. Requires RMagick
25
+ # require File.dirname(__FILE__) + '/treemap/image_output'
26
+
27
+ module Treemap
28
+ VERSION = "0.0.3.1"
29
+
30
+ def Treemap::dump_tree(node)
31
+ puts "#{node.label}: #{node.bounds.to_s}"
32
+ node.children.each do |c|
33
+ dump_tree(c)
34
+ end
35
+ end
36
+
37
+ def Treemap::tree_from_xml(file)
38
+ doc = REXML::Document.new(file)
39
+ node_from_xml(doc.root)
40
+ end
41
+
42
+ def Treemap::node_from_xml(xmlnode)
43
+ node = Treemap::Node.new
44
+
45
+ node.label = xmlnode.attributes["label"]
46
+ id = xmlnode.attributes["id"]
47
+ if(!id.nil?)
48
+ node.id = id.to_s
49
+ end
50
+
51
+ node.size = xmlnode.attributes["size"]
52
+ node.size = node.size.to_f unless node.size.nil?
53
+
54
+ node.color = xmlnode.attributes["change"]
55
+ node.color = node.color.to_f unless node.color.nil?
56
+
57
+
58
+ xmlnode.elements.each do |c|
59
+ child = node_from_xml(c)
60
+ node.add_child(child) if !child.nil?
61
+ end
62
+
63
+ return nil if node.size < 5
64
+ node
65
+ end
66
+ end
@@ -0,0 +1,61 @@
1
+ #
2
+ # color_base.rb - RubyTreemap
3
+ #
4
+ # Copyright (c) 2006 by Andrew Bruno <aeb@qnot.org>
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ #
12
+
13
+ module Treemap
14
+ class ColorBase
15
+ def get_hex_color(value)
16
+ # base classes override
17
+ end
18
+
19
+ def get_rgb_color(value)
20
+ # base classes override
21
+ end
22
+
23
+ def red(color)
24
+ color.sub!(/^#/, "")
25
+ color[0,2].hex
26
+ end
27
+
28
+ def green(color)
29
+ color.sub!(/^#/, "")
30
+ color[2,2].hex
31
+ end
32
+
33
+ def blue(color)
34
+ color.sub!(/^#/, "")
35
+ color[4,2].hex
36
+ end
37
+
38
+ def to_rgb(color)
39
+ [red(color), green(color), blue(color)]
40
+ end
41
+
42
+ def to_html(width=1, height=20)
43
+ html = "<div>"
44
+ index = @min
45
+
46
+ while(index <= @max)
47
+ html += "<span style=\"display: block; float: left;"
48
+ html += "width: " + width.to_s + "px;"
49
+ html += "height: " + height.to_s + "px;"
50
+ html += "background-color: #" + get_hex_color(index) + ";"
51
+ html += "\">"
52
+ html += "<img width=\"1\" height=\"1\" />"
53
+ html += "</span>"
54
+ index += @increment
55
+ end
56
+
57
+ html += "</div>"
58
+ html
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,71 @@
1
+ #
2
+ # gradient_color.rb - RubyTreemap
3
+ #
4
+ # Copyright (c) 2006 by Andrew Bruno <aeb@qnot.org>
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ #
12
+
13
+ require File.dirname(__FILE__) + "/color_base"
14
+
15
+ class Treemap::GradientColor < Treemap::ColorBase
16
+ attr_accessor(:min, :max, :min_color, :mean_color, :max_color, :increment)
17
+
18
+ def initialize
19
+ @min = -100
20
+ @max = 100
21
+ @min_color = "FF0000" # red
22
+ @mean_color = "000000" # black
23
+ @max_color = "00FF00" # green
24
+ @increment = 1
25
+
26
+ yield self if block_given?
27
+
28
+ # XXX add in error checking. if min >= max, if colors aren't hex, etc.
29
+ @min = @min.to_f
30
+ @max = @max.to_f
31
+ @mean = (@min + @max) / 2.to_f
32
+ @slices = (1.to_f / @increment.to_f) * (@max - @mean).to_f
33
+ end
34
+
35
+ def get_hex_color(value)
36
+ value = @max if(value > @max)
37
+ vaue = @min if(value < @min)
38
+
39
+
40
+ r1, g1, b1 = to_rgb(@mean_color)
41
+ r2, g2, b2 = to_rgb(@min_color)
42
+ if(value >= @mean)
43
+ r2, g2, b2 = to_rgb(@max_color)
44
+ end
45
+
46
+ rfactor = ((r1 -r2).abs.to_f / @slices) * value.abs
47
+ gfactor = ((g1 -g2).abs.to_f / @slices) * value.abs
48
+ bfactor = ((b1 -b2).abs.to_f / @slices) * value.abs
49
+
50
+ newr = r1 + rfactor
51
+ if(r1 > r2)
52
+ newr = r1 - rfactor
53
+ end
54
+
55
+ newg = g1 + gfactor
56
+ if(g1 > g2)
57
+ newg = g1 - gfactor
58
+ end
59
+
60
+ newb = b1 + bfactor
61
+ if(b1 > b2)
62
+ newb = b1 - bfactor
63
+ end
64
+
65
+ sprintf("%02X", newr.round) + sprintf("%02X", newg.round) + sprintf("%02X", newb.round)
66
+ end
67
+
68
+ def get_rgb_color(value)
69
+ to_rgb(get_hex_color(value))
70
+ end
71
+ end
@@ -0,0 +1,173 @@
1
+ #
2
+ # html_output.rb - RubyTreemap
3
+ #
4
+ # Copyright (c) 2006 by Andrew Bruno <aeb@qnot.org>
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ #
12
+
13
+ require 'cgi'
14
+ require File.dirname(__FILE__) + "/output_base"
15
+ require File.dirname(__FILE__) + "/slice_layout"
16
+
17
+ class Treemap::HtmlOutput < Treemap::OutputBase
18
+ attr_accessor(:full_html, :base_font_size, :center_labels_at_depth, :center_labels_at_z, :stylesheets, :javascripts, :metadata)
19
+
20
+ def initialize
21
+ super
22
+
23
+ # default options for HtmlOutput
24
+ @full_html = true
25
+ @center_labels_at_depth = nil
26
+ @center_labels_at_z = 100
27
+ @stylesheets = ""
28
+ @javascripts = ""
29
+ @base_font_size = 14
30
+
31
+ yield self if block_given?
32
+
33
+ @layout.position = :absolute
34
+ end
35
+
36
+ def default_css
37
+ css = <<CSS
38
+ .node {
39
+ border: 1px solid black;
40
+ }
41
+ .label {
42
+ color: #FFFFFF;
43
+ font-size: 11px;
44
+ }
45
+ .label-heading {
46
+ color: #FFFFFF;
47
+ font-size: 14pt;
48
+ font-weight: bold;
49
+ text-decoration: underline;
50
+ }
51
+ CSS
52
+ end
53
+
54
+ def node_label(node)
55
+ CGI.escapeHTML(node.label)
56
+ end
57
+
58
+ def node_color(node)
59
+ color = "#CCCCCC"
60
+
61
+ if(!node.color.nil?)
62
+ if(not Numeric === node.color)
63
+ color = node.color
64
+ else
65
+ color = "#" + @color.get_hex_color(node.color)
66
+ end
67
+ end
68
+
69
+ color
70
+ end
71
+
72
+ def to_html(node)
73
+ @bounds = self.bounds
74
+
75
+ @layout.process(node, @bounds)
76
+
77
+ draw_map(node)
78
+ end
79
+
80
+ def draw_map(node)
81
+ html = ""
82
+
83
+ if(@full_html)
84
+ html += "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
85
+ html += "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
86
+ html += "<html><head>"
87
+ html += "<title>Treemap - #{node_label(node)}</title>"
88
+ html += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"
89
+ html += "<style type=\"text/css\">" + default_css + "</style>"
90
+ html += self.stylesheets
91
+ html += self.javascripts
92
+ html += "</head><body>"
93
+ end
94
+
95
+ html += draw_node(node)
96
+
97
+ if(@full_html)
98
+ html += "</body></html>"
99
+ end
100
+
101
+ html
102
+ end
103
+
104
+ def draw_label(node)
105
+ label= "<span"
106
+ if(!@center_labels_at_depth.nil? and @center_labels_at_depth == node.depth)
107
+ px_per_point = 20
108
+ label_size = node.label.length * px_per_point
109
+
110
+ label += " style=\""
111
+ label += "overflow: hidden; position: absolute;"
112
+ label += "margin-top: " + (node.bounds.height/2 - node.font_size(@base_font_size)/2).to_s + "px;"
113
+
114
+ label += "left: 0px; top: 0px; width: 100%; height: 100%; line-height: 100%; text-align: center;"
115
+ label += "z-index: #{@center_labels_at_z};"
116
+ label += "font-size:#{node.font_size(@base_font_size)}px;"
117
+ label += "\""
118
+ label += " class=\"label-heading\""
119
+ else
120
+ label += " class=\"label\""
121
+ label += " style=\"font-size:#{node.font_size(@base_font_size)}px\""
122
+ end
123
+ label += ">"
124
+ label += node_label(node)
125
+ label += "</span>"
126
+
127
+ label
128
+ end
129
+
130
+ # Subclass can override to add more html inside <div/> of node
131
+ def draw_node_body(node)
132
+ draw_label(node)
133
+ end
134
+
135
+ def draw_node(node)
136
+ return "" if node.bounds.nil?
137
+
138
+ root_class = node.depth == 0 ? " treemap-root" : ""
139
+
140
+ html = "<div id=\"node-#{node.id}\""
141
+ html += " style=\""
142
+ html += "overflow: hidden; position: absolute; display: inline;"
143
+ html += "left: #{node.bounds.x1}px; top: #{node.bounds.y1}px;"
144
+ html += "width: #{node.bounds.width}px; height: #{node.bounds.height}px;"
145
+ html += "background-color: " + node_color(node) + ";"
146
+ if(!@center_labels_at_depth.nil? and @center_labels_at_depth == node.depth)
147
+ html += "border: 1px solid black;"
148
+ end
149
+ html += "\" class=\"#{metadata(node)}node#{root_class}\""
150
+ html += ">"
151
+
152
+ html += draw_node_body(node)
153
+
154
+ if(!node.children.nil? and node.children.size > 0)
155
+ node.children.each do |c|
156
+ html += draw_node(c)
157
+ end
158
+ end
159
+
160
+ html += "</div>"
161
+ end
162
+
163
+ private
164
+ def metadata(node)
165
+ if node.object && @metadata
166
+ metadata = @metadata.map { |c| "'#{c}': '#{node.object.send(c).to_s}'" } || []
167
+
168
+ return "" if metadata.empty?
169
+
170
+ return "{#{metadata.join(',')}} "
171
+ end
172
+ end
173
+ end