sankey 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Jan Stępień
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,11 @@
1
+ = Sankey
2
+
3
+ A small tool which generates Sankey diagrams.
4
+
5
+ = Dependencies
6
+
7
+ * {rmagick}[http://rmagick.rubyforge.org/]
8
+
9
+ = Usage
10
+
11
+ See +examples/coffee.rb+.
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ require 'rake'
3
+
4
+ desc "Run rdoc"
5
+ task :rdoc do
6
+ print `rdoc -a -S -N -w 2 -U -o doc/rdoc README.rdoc lib`
7
+ end
8
+
9
+ begin
10
+ require 'jeweler'
11
+ Jeweler::Tasks.new do |gemspec|
12
+ gemspec.name = 'sankey'
13
+ gemspec.summary = 'Sankey diagrams generator'
14
+ gemspec.description = 'A small tool which generates Sankey diagrams.'
15
+ gemspec.email = 'jstepien@users.sourceforge.net'
16
+ gemspec.homepage = "http://github.com/jstepien/sankey"
17
+ gemspec.authors = ['Jan Stępień']
18
+ gemspec.files.exclude '.gitignore'
19
+ gemspec.add_dependency 'rmagick'
20
+ end
21
+ rescue LoadError
22
+ puts "Jeweler not available. Install it with: gem install jeweler"
23
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/ruby -I../lib
2
+ require 'sankey'
3
+ require 'renderers/rvg'
4
+
5
+ g = Sankey::Generator.new
6
+ beans = Sankey::Reagent.new 100
7
+ ground_coffee = Sankey::Reagent.new 100
8
+ water = Sankey::Reagent.new 200
9
+ beverage = Sankey::Reagent.new 280
10
+ crema = Sankey::Reagent.new 20
11
+ espresso_machine = Sankey::Process.new
12
+ grinder = Sankey::Process.new
13
+ beans.drain = grinder
14
+ water.drain = espresso_machine
15
+ ground_coffee.drain = espresso_machine
16
+ ground_coffee.source = grinder
17
+ beverage.source = espresso_machine
18
+ crema.source = espresso_machine
19
+ g.processes.push espresso_machine
20
+ g.processes.push grinder
21
+ g.go!
22
+ p = Sankey::Renderers::RVG.new g.data, "espresso.png"
23
+ p.render
@@ -0,0 +1,233 @@
1
+ require 'processvertex'
2
+ require 'point'
3
+ require 'imagedata'
4
+
5
+ module Sankey
6
+ class Generator
7
+ attr_reader :processes, :data
8
+
9
+ ProcessWidth = 40
10
+ ProcessLayerStep = 100
11
+ ProcessSideStep = 50
12
+ Margin = 5
13
+ InputReagentsStep = 20
14
+ OutputReagentsStep = 20
15
+
16
+ def initialize
17
+ @processes = []
18
+ end
19
+
20
+ def go!
21
+ @processes_vertices = {}
22
+ @drawn_reagents = []
23
+ @vertices = []
24
+ @input_reagent_offset = Margin
25
+ @below_next_process_offset = {}
26
+ @process_input_offset = {}
27
+ @process_output_left_offset = {}
28
+ @process_output_right_offset = {}
29
+ get_max_distances_to_processes
30
+ to_be_drawn = []
31
+ input_reagents.each { |r| to_be_drawn.push r }
32
+ until to_be_drawn.empty? do
33
+ STDERR.puts "to draw"
34
+ to_be_drawn.each { |r| STDERR.puts " " + r.to_s + " " + r.name }
35
+ not_drawn = []
36
+ to_be_drawn.each { |r| not_drawn += recursively_draw r }
37
+ to_be_drawn = not_drawn.uniq
38
+ end
39
+ make_coordinates_positive
40
+ w, h = get_size
41
+ @data = ImageData.new @vertices, w, h
42
+ end
43
+
44
+ private
45
+
46
+ # Moves all vertices so that there are no negative coordinates.
47
+ def make_coordinates_positive
48
+ min_y = @vertices[0].points[0].y
49
+ min_x = @vertices[0].points[0].x
50
+ @vertices.each do |v|
51
+ v.points.each do |p|
52
+ min_y = [min_y, p.y].min
53
+ min_x = [min_x, p.x].min
54
+ end
55
+ end
56
+ min_x -= Margin
57
+ STDERR.puts "Vector: #{-min_x} -#{-min_y}."
58
+ vector = [-min_x, -min_y]
59
+ @vertices.each do |v|
60
+ v.points.map! do |p|
61
+ p + vector
62
+ end
63
+ end
64
+ end
65
+
66
+ def get_max_distances_to_processes(reagent = nil, level = 0)
67
+ if reagent.nil?
68
+ @max_distances_to_processes = {}
69
+ input_reagents.each { |r| get_max_distances_to_processes r }
70
+ elsif !reagent.drain.nil?
71
+ new_level = level + 1
72
+ if @max_distances_to_processes[reagent.drain].nil? or
73
+ @max_distances_to_processes[reagent.drain] < new_level
74
+ @max_distances_to_processes[reagent.drain] = new_level
75
+ end
76
+ reagent.drain.output.each do |r|
77
+ get_max_distances_to_processes r, new_level
78
+ end
79
+ end
80
+ end
81
+
82
+ def draw_process(process)
83
+ layer = @max_distances_to_processes[process] - 1
84
+ height = process.total_reagents_mass
85
+ corner = Point.new (layer+1)*(ProcessLayerStep+ProcessWidth) + Margin,
86
+ Margin
87
+ v = ProcessVertex.new corner, corner + [0, height],
88
+ corner + [ProcessWidth, height], corner + [ProcessWidth, 0]
89
+ @vertices.push v
90
+ @processes_vertices[process] = v
91
+ # Initialize @below_next_process_offset
92
+ process.input.each do |r|
93
+ unless r.source.nil?
94
+ @below_next_process_offset[r.source] = Margin + height
95
+ break
96
+ end
97
+ end
98
+ end
99
+
100
+ def recursively_draw(reagent)
101
+ return [] if @drawn_reagents.include? reagent
102
+ STDERR.puts " drawing " + reagent.name if reagent.name != ""
103
+ if reagent.drain.nil?
104
+ if reagent.source.is_first_in_output_queue reagent
105
+ draw_output_reagent reagent
106
+ reagent.source.remove_from_output_queue reagent
107
+ else
108
+ STDERR.puts " later"
109
+ return [reagent]
110
+ end
111
+ elsif reagent.source.nil?
112
+ if reagent.drain.is_first_in_input_queue reagent
113
+ draw_input_reagent reagent
114
+ reagent.drain.remove_from_input_queue reagent
115
+ else
116
+ STDERR.puts " later"
117
+ return [reagent]
118
+ end
119
+ else
120
+ if reagent.drain.is_first_in_input_queue(reagent) and
121
+ reagent.source.is_first_in_output_queue(reagent)
122
+ draw_middle_reagent reagent
123
+ reagent.source.remove_from_output_queue reagent
124
+ reagent.drain.remove_from_input_queue reagent
125
+ else
126
+ #STDERR.puts reagent.drain.is_first_in_input_queue(reagent)
127
+ #STDERR.puts reagent.source.is_first_in_output_queue(reagent)
128
+ STDERR.puts " later"
129
+ return [reagent]
130
+ end
131
+ end
132
+ @drawn_reagents.push reagent
133
+ to_draw_later = []
134
+ unless reagent.drain.nil?
135
+ reagent.drain.output.each { |r| to_draw_later += recursively_draw r }
136
+ end
137
+ to_draw_later
138
+ end
139
+
140
+ def draw_middle_reagent(reagent)
141
+ left_height = reagent.source.total_reagents_mass *
142
+ reagent.source.fraction(reagent)
143
+ right_height = reagent.drain.total_reagents_mass *
144
+ reagent.drain.fraction(reagent)
145
+ [reagent.source, reagent.drain].each do |p|
146
+ draw_process p unless @processes_vertices.include? p
147
+ end
148
+ @process_input_offset[reagent.drain] ||= 0
149
+ @process_output_left_offset[reagent.source] ||= 0
150
+ left_corner = @processes_vertices[reagent.source].output_edge[:top] +
151
+ [0, @process_output_left_offset[reagent.source]]
152
+ right_corner = @processes_vertices[reagent.drain].input_edge[:top] +
153
+ [0, @process_input_offset[reagent.drain]]
154
+ v = Vertex.new
155
+ v.points.push left_corner
156
+ v.points.push left_corner + [0, left_height]
157
+ v.points.push right_corner + [0, right_height]
158
+ v.points.push right_corner
159
+ @vertices.push v
160
+ @process_input_offset[reagent.drain] += right_height
161
+ @process_output_left_offset[reagent.source] += left_height
162
+ end
163
+
164
+ def draw_input_reagent(reagent)
165
+ draw_process reagent.drain unless @processes_vertices.include? reagent.drain
166
+ height = reagent.drain.total_reagents_mass * reagent.drain.fraction(reagent)
167
+ @process_input_offset[reagent.drain] ||= 0
168
+ v = Vertex.new
169
+ if @process_input_offset[reagent.drain] == 0 and reagent.joins_later
170
+ left_corner = @processes_vertices[reagent.drain].input_edge[:top] +
171
+ [-ProcessSideStep, -height]
172
+ else
173
+ left_corner = Point.new Margin, @input_reagent_offset
174
+ end
175
+ v.points.push left_corner
176
+ v.points.push left_corner + [5, height / 2]
177
+ v.points.push left_corner + [0, height]
178
+ v.points.push @processes_vertices[reagent.drain].input_edge[:top] +
179
+ [0, @process_input_offset[reagent.drain] + height]
180
+ v.points.push @processes_vertices[reagent.drain].input_edge[:top] +
181
+ [0, @process_input_offset[reagent.drain]]
182
+ @vertices.push v
183
+ @input_reagent_offset += height + InputReagentsStep
184
+ @process_input_offset[reagent.drain] += height
185
+ end
186
+
187
+ def draw_output_reagent(reagent)
188
+ height = reagent.source.total_reagents_mass *
189
+ reagent.source.fraction(reagent)
190
+ @process_output_left_offset[reagent.source] ||= 0
191
+ @process_output_right_offset[reagent.source] ||= 0
192
+ right_offset = @process_output_right_offset[reagent.source] +
193
+ (@below_next_process_offset[reagent.source] ||= 0)
194
+ left_corner = @processes_vertices[reagent.source].output_edge[:top] +
195
+ [0, @process_output_left_offset[reagent.source]]
196
+ v = Vertex.new
197
+ v.points.push left_corner
198
+ v.points.push left_corner + [0, height]
199
+ v.points.push left_corner +
200
+ [ProcessLayerStep, right_offset + height]
201
+ v.points.push left_corner +
202
+ [ProcessLayerStep + 5, right_offset + height / 2]
203
+ v.points.push left_corner +
204
+ [ProcessLayerStep, right_offset]
205
+ @vertices.push v
206
+ @process_output_left_offset[reagent.source] += height
207
+ @process_output_right_offset[reagent.source] += height + InputReagentsStep
208
+ end
209
+
210
+ def input_reagents
211
+ return @input_reagents if defined? @input_reagents
212
+ @input_reagents = []
213
+ @processes.each do |process|
214
+ process.input.each do |reagent|
215
+ @input_reagents.push reagent if reagent.source.nil?
216
+ end
217
+ end
218
+ @input_reagents.uniq!
219
+ @input_reagents
220
+ end
221
+
222
+ def get_size
223
+ w = h = 0
224
+ @vertices.each do |vertex|
225
+ vertex.points.each do |point|
226
+ w = point.x + Margin if point.x + Margin > w
227
+ h = point.y + Margin if point.y + Margin > h
228
+ end
229
+ end
230
+ return w, h
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,11 @@
1
+ module Sankey
2
+ class ImageData
3
+ attr_reader :vertices, :width, :height
4
+
5
+ def initialize(vertices, width, height)
6
+ @vertices = vertices
7
+ @width = width
8
+ @height = height
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ module Sankey
2
+ class Point
3
+ attr_reader :x, :y
4
+
5
+ def initialize(x, y)
6
+ @x = x
7
+ @y = y
8
+ end
9
+
10
+ def +(val)
11
+ if val.is_a? Array and 2 == val.count
12
+ x = val[0]
13
+ y = val[1]
14
+ else
15
+ throw "Invalid argument"
16
+ end
17
+ Point.new @x + x, @y + y
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,83 @@
1
+ module Sankey
2
+ class Process
3
+ attr_reader :input, :output
4
+
5
+ def initialize
6
+ @input = []
7
+ @output = []
8
+ @input_reagents_queue = {}
9
+ @output_reagents_queue = {}
10
+ end
11
+
12
+ def fraction(reagent)
13
+ side = nil
14
+ [@output, @input].each { |io| side = io if io.include? reagent }
15
+ throw "Reagent isn't present in this process" if side.nil?
16
+ sum = 0
17
+ side.each { |r| sum += r.size }
18
+ reagent.size * 1.0 / sum
19
+ end
20
+
21
+ def total_reagents_mass
22
+ check_conservation_of_mass
23
+ end
24
+
25
+ def add_output(reagent, order = nil)
26
+ @output.push reagent
27
+ @output_reagents_queue[order] = reagent unless order.nil?
28
+ end
29
+
30
+ def add_input(reagent, order = nil)
31
+ @input.push reagent
32
+ @input_reagents_queue[order] = reagent unless order.nil?
33
+ end
34
+
35
+ def remove_from_input_queue(reagent)
36
+ key_to_be_removed = nil
37
+ @input_reagents_queue.each do |key, val|
38
+ key_to_be_removed = key if val == reagent
39
+ end
40
+ @input_reagents_queue.delete key_to_be_removed
41
+ end
42
+
43
+ def remove_from_output_queue(reagent)
44
+ key_to_be_removed = nil
45
+ @output_reagents_queue.each do |key, val|
46
+ key_to_be_removed = key if val == reagent
47
+ end
48
+ @output_reagents_queue.delete key_to_be_removed
49
+ end
50
+
51
+ def is_first_in_input_queue(reagent)
52
+ min_key = nil
53
+ return true unless @input_reagents_queue.values.include? reagent
54
+ @input_reagents_queue.each do |key, val|
55
+ #STDERR.puts "#{key} -> #{val.name}"
56
+ min_key ||= key
57
+ min_key = [min_key, key].min
58
+ end
59
+ @input_reagents_queue[min_key] == reagent
60
+ end
61
+
62
+ def is_first_in_output_queue(reagent)
63
+ min_key = nil
64
+ return true unless @output_reagents_queue.values.include? reagent
65
+ @output_reagents_queue.each do |key, val|
66
+ min_key ||= key
67
+ min_key = [min_key, key].min
68
+ end
69
+ @output_reagents_queue[min_key] == reagent
70
+ end
71
+
72
+ private
73
+
74
+ def check_conservation_of_mass
75
+ input_sum = output_sum = 0
76
+ @input.each { |r| input_sum += r.size }
77
+ @output.each { |r| output_sum += r.size }
78
+ throw 'Conservation of mass constraint failed: ' +
79
+ "#{input_sum} != #{output_sum}" if input_sum != output_sum
80
+ input_sum
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,18 @@
1
+ require 'vertex'
2
+
3
+ module Sankey
4
+ class ProcessVertex < Vertex
5
+ def initialize(a, b, c, d)
6
+ super()
7
+ [a, b, c, d].each { |x| @points.push x }
8
+ end
9
+
10
+ def input_edge
11
+ {:bottom => @points[1], :top => @points[0]}
12
+ end
13
+
14
+ def output_edge
15
+ {:bottom => @points[2], :top => @points[3]}
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,40 @@
1
+ module Sankey
2
+ class Reagent
3
+ attr_reader :size, :source, :drain, :name
4
+
5
+ def initialize(size, name = '')
6
+ @size = size
7
+ @name = name
8
+ end
9
+
10
+ def source=(process)
11
+ process.add_output self
12
+ @source = process
13
+ end
14
+
15
+ def drain=(process)
16
+ process.add_input self
17
+ @drain = process
18
+ end
19
+
20
+ def add_drain(process, order = nil)
21
+ process.add_input self, order
22
+ @drain = process
23
+ end
24
+
25
+ def add_source(process, order = nil)
26
+ process.add_output self, order
27
+ @source= process
28
+ end
29
+
30
+ def joins_later
31
+ drain.input.each do |r|
32
+ next if r == self
33
+ if r.source != nil
34
+ return true
35
+ end
36
+ end
37
+ false
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,7 @@
1
+ module Sankey::Renderers
2
+ module Renderer
3
+ def render
4
+ throw 'Not implemented'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,65 @@
1
+ require 'renderers/renderer'
2
+ require 'rvg/rvg'
3
+ require 'imagedata'
4
+
5
+ module Sankey::Renderers
6
+ class RVG
7
+ include Renderer
8
+ include Sankey
9
+
10
+ def initialize(data, filename = nil, args = {})
11
+ throw "data isn't ImageData" unless data.is_a? ImageData
12
+ @grid = args[:grid] || false
13
+ @vertices = data.vertices
14
+ @filename = filename
15
+ @width = args[:width] || data.width
16
+ @height = args[:height] || data.height
17
+ @width_ratio = 1.0 * @width / data.width
18
+ @height_ratio = 1.0 * @height / data.height
19
+ end
20
+
21
+ def render
22
+ canvas = Magick::ImageList.new
23
+ canvas.new_image(@width, @height)
24
+ draw_grid canvas if @grid
25
+ @vertices.each { |v| draw_vertex canvas, v }
26
+ if @filename.nil?
27
+ return canvas.to_blob { self.format = 'PNG' }
28
+ else
29
+ canvas.write @filename
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def draw_grid(canvas)
36
+ grid = Magick::Draw.new
37
+ grid.stroke = 'lightgray'
38
+ grid.stroke_width = 1
39
+ 0.upto @width/@grid/@width_ratio do |x|
40
+ grid.line @width_ratio*(x*@grid+@grid-1), 0,
41
+ (x*@grid+@grid-1)*@width_ratio, @height
42
+ end
43
+ 0.upto @height/@grid/@height_ratio do |x|
44
+ grid.line 0, (x*@grid+@grid-1)*@height_ratio, @width,
45
+ (x*@grid+@grid-1)*@height_ratio
46
+ end
47
+ grid.draw canvas
48
+ end
49
+
50
+ def draw_vertex(canvas, v)
51
+ vertex = Magick::Draw.new
52
+ vertex.stroke = 'black'
53
+ vertex.stroke_width = 1
54
+ first_x = prev_x = v.points.first.x * @width_ratio
55
+ first_y = prev_y = v.points.first.y * @height_ratio
56
+ v.points.each do |p|
57
+ vertex.line prev_x, prev_y, p.x * @width_ratio, p.y * @height_ratio
58
+ prev_x = p.x * @width_ratio
59
+ prev_y = p.y * @height_ratio
60
+ end
61
+ vertex.line prev_x, prev_y, first_x, first_y
62
+ vertex.draw canvas
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ require 'process'
2
+ require 'reagent'
3
+ require 'generator'
@@ -0,0 +1,9 @@
1
+ module Sankey
2
+ class Vertex
3
+ attr_reader :points
4
+
5
+ def initialize
6
+ @points = []
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{sankey}
8
+ s.version = "0.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jan Stępień"]
12
+ s.date = %q{2010-02-18}
13
+ s.description = %q{A small tool which generates Sankey diagrams.}
14
+ s.email = %q{jstepien@users.sourceforge.net}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ "LICENSE",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "examples/coffee.rb",
25
+ "lib/generator.rb",
26
+ "lib/imagedata.rb",
27
+ "lib/point.rb",
28
+ "lib/process.rb",
29
+ "lib/processvertex.rb",
30
+ "lib/reagent.rb",
31
+ "lib/renderers/renderer.rb",
32
+ "lib/renderers/rvg.rb",
33
+ "lib/sankey.rb",
34
+ "lib/vertex.rb",
35
+ "sankey.gemspec"
36
+ ]
37
+ s.homepage = %q{http://github.com/jstepien/sankey}
38
+ s.rdoc_options = ["--charset=UTF-8"]
39
+ s.require_paths = ["lib"]
40
+ s.rubygems_version = %q{1.3.5}
41
+ s.summary = %q{Sankey diagrams generator}
42
+ s.test_files = [
43
+ "examples/coffee.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<rmagick>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<rmagick>, [">= 0"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<rmagick>, [">= 0"])
57
+ end
58
+ end
59
+
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sankey
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - "Jan St\xC4\x99pie\xC5\x84"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-18 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rmagick
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: A small tool which generates Sankey diagrams.
26
+ email: jstepien@users.sourceforge.net
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ files:
35
+ - LICENSE
36
+ - README.rdoc
37
+ - Rakefile
38
+ - VERSION
39
+ - examples/coffee.rb
40
+ - lib/generator.rb
41
+ - lib/imagedata.rb
42
+ - lib/point.rb
43
+ - lib/process.rb
44
+ - lib/processvertex.rb
45
+ - lib/reagent.rb
46
+ - lib/renderers/renderer.rb
47
+ - lib/renderers/rvg.rb
48
+ - lib/sankey.rb
49
+ - lib/vertex.rb
50
+ - sankey.gemspec
51
+ has_rdoc: true
52
+ homepage: http://github.com/jstepien/sankey
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --charset=UTF-8
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.5
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Sankey diagrams generator
79
+ test_files:
80
+ - examples/coffee.rb