rubyvis 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.txt +3 -0
  3. data/Manifest.txt +44 -0
  4. data/README.txt +64 -0
  5. data/Rakefile +16 -0
  6. data/examples/crimea-line.rb +64 -0
  7. data/examples/first.rb +17 -0
  8. data/examples/second.rb +14 -0
  9. data/lib/rubyvis.rb +43 -0
  10. data/lib/rubyvis/color/color.rb +241 -0
  11. data/lib/rubyvis/color/colors.rb +40 -0
  12. data/lib/rubyvis/color/ramp.rb +0 -0
  13. data/lib/rubyvis/format.rb +19 -0
  14. data/lib/rubyvis/format/date.rb +18 -0
  15. data/lib/rubyvis/format/number.rb +31 -0
  16. data/lib/rubyvis/internals.rb +215 -0
  17. data/lib/rubyvis/javascript_behaviour.rb +64 -0
  18. data/lib/rubyvis/label.rb +0 -0
  19. data/lib/rubyvis/mark.rb +528 -0
  20. data/lib/rubyvis/mark/anchor.rb +22 -0
  21. data/lib/rubyvis/mark/area.rb +34 -0
  22. data/lib/rubyvis/mark/bar.rb +23 -0
  23. data/lib/rubyvis/mark/label.rb +17 -0
  24. data/lib/rubyvis/mark/line.rb +14 -0
  25. data/lib/rubyvis/mark/panel.rb +87 -0
  26. data/lib/rubyvis/mark/rule.rb +28 -0
  27. data/lib/rubyvis/scale.rb +34 -0
  28. data/lib/rubyvis/scale/linear.rb +5 -0
  29. data/lib/rubyvis/scale/ordinal.rb +52 -0
  30. data/lib/rubyvis/scale/quantitative.rb +263 -0
  31. data/lib/rubyvis/scene/svg_bar.rb +31 -0
  32. data/lib/rubyvis/scene/svg_label.rb +51 -0
  33. data/lib/rubyvis/scene/svg_panel.rb +117 -0
  34. data/lib/rubyvis/scene/svg_rule.rb +29 -0
  35. data/lib/rubyvis/scene/svg_scene.rb +118 -0
  36. data/lib/rubyvis/sceneelement.rb +44 -0
  37. data/lib/rubyvis/transform.rb +25 -0
  38. data/spec/internal_spec.rb +146 -0
  39. data/spec/javascript_behaviour_spec.rb +64 -0
  40. data/spec/panel_spec.rb +8 -0
  41. data/spec/scale_linear_spec.rb +121 -0
  42. data/spec/scale_spec.rb +8 -0
  43. data/spec/spec.opts +3 -0
  44. data/spec/spec_helper.rb +27 -0
  45. metadata +160 -0
  46. metadata.gz.sig +2 -0
@@ -0,0 +1,22 @@
1
+ module Rubyvis
2
+ def self.Anchor(target)
3
+ Rubyvis::Anchor.new(target)
4
+ end
5
+
6
+ class Anchor < Mark
7
+ @properties=Mark.properties
8
+ attr_accessor_dsl :name, :text_baseline, :text_align
9
+ def type
10
+ 'area'
11
+ end
12
+ def initialize(target)
13
+ super()
14
+ self.target=target
15
+ self.parent=target.parent
16
+ end
17
+ def _extend(proto)
18
+ self.proto=proto
19
+ return self
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,34 @@
1
+ module Rubyvis
2
+ def self.Area
3
+ Rubyvis::Area
4
+ end
5
+
6
+ class Area < Mark
7
+ @properties=Mark.properties
8
+ attr_accessor_dsl :width, :height, :line_width, :stroke_style, :fill_style, :segmented, :interpolate, :tension
9
+ def type
10
+ 'area'
11
+ end
12
+ def defaults
13
+ sd=super
14
+ return sd.merge({:line_width=>1.5, :fill_style=>pv.Colors.category20.by(pv.parent), :interpolate=>'linear', :tension=>0.7})
15
+ end
16
+ def build_implied(s)
17
+ s.heigth=0 if s.height.nil?
18
+ s.width=0 if s.width.nil?
19
+ super(s)
20
+ end
21
+ def self.anchor(name)
22
+ Mark.anchor(name).interpolate(lambda {
23
+ self.scene.target[self.index].interpolate
24
+ }).eccentricity(lambda {
25
+ self.scene.target[self.index].eccentricity
26
+ }).tension(lambda {
27
+ self.scene.target[self.index].tension
28
+ })
29
+ end
30
+ def anchor
31
+ (self.class).anchor(name)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,23 @@
1
+ module Rubyvis
2
+ def self.Bar
3
+ Rubyvis::Bar
4
+ end
5
+ class Bar < Mark
6
+ def type
7
+ "bar"
8
+ end
9
+
10
+ @properties=Mark.properties
11
+ attr_accessor_dsl :width, :height, :line_width, :stroke_style, :fill_style
12
+ def defaults
13
+ sd=super
14
+ return sd.merge({:line_width=>1.5, :fill_style=>Rubyvis.Colors.category20().by(Rubyvis.parent)})
15
+ end
16
+ def svg_render_pre
17
+ "<rect fill='#{pr_svg(:fill_style)}' height='#{pr_svg(:height)}' width='#{pr_svg(:width)}' x='#{pr_svg(:left)}' y='#{pr_svg(:top)}'>"
18
+ end
19
+ def svg_render_post
20
+ "</rect>"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ module Rubyvis
2
+ def self.Label
3
+ Rubyvis::Label
4
+ end
5
+
6
+ class Label < Mark
7
+ @properties=Mark.properties
8
+ attr_accessor_dsl :text, :font, :text_angle, :text_style, :text_align, :text_baseline, :text_margin, :text_decoration, :text_shadow
9
+ def type
10
+ 'label'
11
+ end
12
+ def defaults
13
+ sd=super
14
+ return sd.merge({:events=>'none', :text=>lambda{|x| puts "->#{x}"; x}, :font=>"10px sans-serif", :text_angle=>0, :text_style=>pv.color('black'), :text_align=>'left', :text_baseline=>'bottom', :text_margin=>3})
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ module Rubyvis
2
+ def self.Line
3
+ Rubyvis::Line
4
+ end
5
+
6
+ class Line < Mark
7
+ @properties=Mark.properties
8
+ attr_accessor_dsl :line_width, :line_join, :stroke_style, :fill_style, :segmented, :interporale, :eccentricity, :tension
9
+ def defaults
10
+ sd=super
11
+ return sd.merge({:line_join=>'miter', :line_width=>1.5, :stroke_style=>RubyVis::Color.category10().by(pv.parent), :interpolate=>'linear', :eccentricity=>0, :tension=>7})
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,87 @@
1
+ module Rubyvis
2
+ def self.Panel
3
+ Rubyvis::Panel
4
+ end
5
+ class Panel < Bar
6
+ def type
7
+ "panel"
8
+ end
9
+
10
+ @properties=Bar.properties
11
+ attr_accessor_dsl :transform, :overflow, :canvas
12
+ attr_accessor :children, :root
13
+ def initialize
14
+ super
15
+ @children=[]
16
+ @root=self
17
+ end
18
+ def defaults
19
+ sd=super
20
+ return sd.merge({:fill_style=>nil, :overflow=>'visible', :canvas=>Rubyvis.document.add_element("canvas")})
21
+ end
22
+ def add(type)
23
+ child=type.new
24
+ child.parent=self
25
+ child.root=root
26
+ child.child_index=children.size
27
+ children.push(child)
28
+ child
29
+ end
30
+
31
+ attr_reader :_canvas
32
+ def bind
33
+ super
34
+ children.each {|c|
35
+ c.bind()
36
+ }
37
+ end
38
+ def build_instance(s)
39
+ super(s)
40
+ return if !s.visible
41
+ s.children=[] if !s.children
42
+ scale=self.scale*s.transform.k
43
+ n=self.children.size
44
+ Mark.index=-1
45
+ n.times {|i|
46
+ child=children[i]
47
+ child.scene=s.children[i]
48
+ child.scale=scale
49
+ child.build()
50
+ }
51
+ n.times {|i|
52
+ child=children[i]
53
+ s.children[i]=child.scene
54
+ child.scene=nil
55
+ child.scale=nil
56
+ }
57
+ s.children=s.children[0,n]
58
+ end
59
+ def build_implied(s)
60
+ if(!self.parent)
61
+ c=s.canvas
62
+ if(c)
63
+ if s.width.nil?
64
+ w=Rubyvis.css(c,'width')
65
+ s.width=w-s.left-s.right
66
+ end
67
+ if s.height.nil?
68
+ w=Rubyvis.css(c,'height')
69
+ s.height=h-s.top-s.bottom
70
+ end
71
+ else
72
+ @_canvas||={}
73
+ cache=@_canvas
74
+ if(!(c=cache[self.index]))
75
+ c=cache[this.index]=Rubyvis.add_element('span')
76
+ end
77
+ end
78
+ s.canvas=c
79
+ end
80
+
81
+ s.transform=Rubyvis.Transform.identity if (s.transform.nil?)
82
+ super(s)
83
+
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,28 @@
1
+ module Rubyvis
2
+ def self.Rule
3
+ Rubyvis::Rule
4
+ end
5
+ class Rule < Mark
6
+ @properties=Mark.properties
7
+ attr_accessor_dsl :width, :height, :line_width, :stroke_style
8
+ def defaults
9
+ sd=super
10
+ return sd.merge({:line_width=>1,:stroke_style=>pv.color('black'),:antialias=>false})
11
+ end
12
+ def type
13
+ 'rule'
14
+ end
15
+ def build_implied(s)
16
+ l=s.left
17
+ r=s.right
18
+ t=s.top
19
+ b=s.bottom
20
+ if((!s.width.nil?) or ((l.nil?) and (r.nil?)) or ((!r.nil?) or (!l.nil?)))
21
+ s.height=0
22
+ else
23
+ s.width=0
24
+ end
25
+ super(s)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,34 @@
1
+ module Rubyvis
2
+ def self.Scale
3
+ Rubyvis::Scale
4
+ end
5
+ module Scale
6
+ def self.quantitative(*args)
7
+ Quantitative.new(*args)
8
+ end
9
+ def self.linear(*args)
10
+ Linear.new(*args)
11
+ end
12
+ def self.ordinal(*args)
13
+ Ordinal.new(*args)
14
+ end
15
+ def self.interpolator(start,_end)
16
+ if start.is_a? Numeric
17
+ return lambda {|t| t*(_end-start)+start}
18
+ end
19
+ start=Rubyvis.color(start).rgb()
20
+ _end = Rubyvis.color(_end).rgb()
21
+ return lambda {|t|
22
+ a=start.a*(1-t)+_end.a*t
23
+ a=0 if a<1e-5
24
+ return (start.a == 0) ? Rubyvis.rgb(_end.r, _end.g, _end.b, a) : ((_end.a == 0) ? pv.rgb(start.r, start.g, start.b, a) : Rubyvis.rgb(
25
+ (start.r * (1 - t) + _end.r * t).round,
26
+ (start.g * (1 - t) + _end.g * t).round,
27
+ (start.b * (1 - t) + _end.b * t).round, a))
28
+ }
29
+ end
30
+ end
31
+ end
32
+ require 'rubyvis/scale/quantitative.rb'
33
+ require 'rubyvis/scale/linear.rb'
34
+ require 'rubyvis/scale/ordinal.rb'
@@ -0,0 +1,5 @@
1
+ module Rubyvis
2
+
3
+ class Scale::Linear < Rubyvis::Scale::Quantitative
4
+ end
5
+ end
@@ -0,0 +1,52 @@
1
+ module Rubyvis
2
+ class Scale::Ordinal
3
+ include Rubyvis::Scale
4
+
5
+ def initialize(*args)
6
+ @d=[] # domain
7
+ @i={}
8
+ @r=[]
9
+ @band=0
10
+ domain(*args)
11
+ end
12
+ def scale(x)
13
+ if @i[x].nil?
14
+ @d.push(x)
15
+ @i[x]=@d.size-1
16
+ end
17
+ @r[@i[x] % @r.size]
18
+ end
19
+ def domain(*arguments)
20
+ array,f=arguments[0],arguments[1]
21
+ if(arguments.size>0)
22
+ array= (array.is_a? Array) ? ((arguments.size>1) ? array.map(&f) : array) : arguments.dup
23
+ @d=array.uniq
24
+ i=pv.numerate(d)
25
+ return self
26
+ end
27
+ @d
28
+ end
29
+ def range(*arguments)
30
+ array, f = arguments[0],arguments[1]
31
+ if(arguments.size>0)
32
+ @r=(array.is_a? Array) ? ((arguments.size>1) ? array.map(&f) : array) : arguments.dup
33
+ if @r[0].is_a? String
34
+ @r=@r.map {|i| pv.color(i)}
35
+ end
36
+ self
37
+ end
38
+ @r
39
+ end
40
+ def split(min,max)
41
+ step=(max-min).quo(domain().size)
42
+ @r=pv.range(min+step.quo(2),max,step)
43
+ self
44
+ end
45
+ def by(*arguments)
46
+ f,dummy=arguments
47
+ t=self
48
+ by=lambda { t.scale(f.js_apply(self,arguments))}
49
+ by
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,263 @@
1
+ module Rubyvis
2
+ class Scale::Quantitative
3
+ include Rubyvis::Scale
4
+ attr_reader :l
5
+ def initialize(*args)
6
+ @d=[0,1] # domain
7
+ @l=[0,1] # transformed domain
8
+ @r=[0,1] # default range
9
+ @i=[Rubyvis.identity] # default interpolator
10
+ @type=:to_f # default type
11
+ @n=false
12
+ @f=Rubyvis.identity # default forward transformation
13
+ @g=Rubyvis.identity
14
+ @tick_format=lambda {|x| x.to_f}
15
+ domain(*args)
16
+ end
17
+ def new_date(x=nil)
18
+ x.nil? ? Date.today : DateTime.civil(x)
19
+ end
20
+
21
+ def scale(x)
22
+ j=Rubyvis.search(@d,x)
23
+ j=-j-2 if (j<0)
24
+ j=[0,[@i.size-1,j].min].max
25
+ # p @l
26
+ # puts "Primero #{j}: #{@f.call(x) - @l[j]}"
27
+ # puts "Segundo #{(@l[j + 1] - @l[j])}"
28
+ @i[j].call((@f.call(x) - @l[j]) .quo(@l[j + 1] - @l[j]));
29
+ end
30
+ def [](x)
31
+ scale(x)
32
+ end
33
+ def transform(forward, inverse)
34
+ @f=lambda {|x| @n ? -forward.call(-x) : forward.call(x); }
35
+ @g=lambda {|y| @n ? -inverse.call(-y) : inverse.call(y); }
36
+ @l=@d.map{|v| @f.call(v)}
37
+ self
38
+ end
39
+
40
+
41
+ def domain(*arguments)
42
+ array,min,max=arguments
43
+ if (arguments.size>0)
44
+ if array.is_a? Array
45
+ min = pv.identity if (arguments.size < 2)
46
+ max = min if (arguments.size < 3)
47
+ o = array.size>0 && [array[0]].min
48
+ @d = array.size ? [Rubyvis.min(array, min), Rubyvis.max(array, max)] : [];
49
+ else
50
+ o = array;
51
+ @d = arguments.map {|i| i.to_f}
52
+ end
53
+ if !@d.size
54
+ @d = [-Infinity, Infinity];
55
+ elsif (@d.size == 1)
56
+ @d = [@d.first, @d.first]
57
+ end
58
+ @n = (@d.first<0 or @d.last<0)
59
+ @l=@d.map{|v| @f.call(v)}
60
+ @type = (o.is_a? Date) ? new_date : :to_f;
61
+ return self
62
+ end
63
+ # TODO: Fix this.
64
+ @d.map{|v|
65
+ case @type
66
+ when :to_f
67
+ v.to_f
68
+ when :to_date
69
+ Date.new(v)
70
+ else
71
+ v
72
+ end
73
+ }
74
+ end
75
+
76
+
77
+ def range(*arguments)
78
+ if (arguments.size>0)
79
+ @r = arguments.dup
80
+ if (@r.size==0)
81
+ @r = [-Infinity, Infinity];
82
+ elsif (@r.size == 1)
83
+ @r = [@r[0], @r[0]]
84
+ end
85
+ @i=(@r.size-1).times.map do |j|
86
+ Rubyvis::Scale.interpolator(@r[j], @r[j + 1]);
87
+ end
88
+ return self
89
+ end
90
+ @r
91
+ end
92
+
93
+ def invert(y)
94
+ j=Rubyvis.search(@r, y)
95
+ j=-j-2 if j<0
96
+ j = [0, [@i.size - 1, j].min].max
97
+
98
+ @g.call(@l[j] + (y - @r[j]).quo(@r[j + 1] - @r[j]) * (@l[j + 1] - @l[j]));
99
+ end
100
+
101
+ def type(v=nil)
102
+ return @type if v.nil?
103
+ case @type
104
+ when Numeric
105
+ v.to_f
106
+ when Date
107
+ raise "Not implemented yet"
108
+ end
109
+ end
110
+ # TODO: FIX this func
111
+ def ticks(*arguments)
112
+ m = arguments[0]
113
+ start = @d.first
114
+ _end = @d.last
115
+ reverse = _end < start
116
+ min = reverse ? _end : start
117
+ max = reverse ? start : _end
118
+ span = max - min
119
+
120
+ # Special case: empty, invalid or infinite span.
121
+ if (!span or (span.is_a? Float and span.infinite?))
122
+ @tick_format= Rubyvis.Format.date("%x") if (@type == newDate)
123
+ return [type(min)];
124
+ end
125
+ # From here, �chaos!
126
+ #/* Special case: dates. */
127
+ if (@type == new_date)
128
+ #/* Floor the date d given the precision p. */
129
+ lambda do |d,p|
130
+ case(p)
131
+ when 31536e6
132
+ d.setMonth(0);
133
+ when 2592e6
134
+ d.setDate(1);
135
+ when 6048e5
136
+ if (p == 6048e5)
137
+ d.setDate(d.getDate() - d.getDay());
138
+ end
139
+ when 864e5
140
+ d.setHours(0);
141
+ when 36e5
142
+ d.setMinutes(0);
143
+ when 6e4
144
+ d.setSeconds(0);
145
+ when 1e3
146
+ d.setMilliseconds(0);
147
+ end
148
+ end
149
+
150
+ precision, format, increment, step = 1,1,1,1
151
+ if (span >= 3 * 31536e6)
152
+ precision = 31536e6;
153
+ format = "%Y";
154
+ increment = lambda {|d| d.setFullYear(d.getFullYear() + step); };
155
+ elsif (span >= 3 * 2592e6)
156
+ precision = 2592e6;
157
+ format = "%m/%Y";
158
+ increment = lambda {|d| d.setMonth(d.getMonth() + step); };
159
+ elsif (span >= 3 * 6048e5)
160
+ precision = 6048e5;
161
+ format = "%m/%d";
162
+ increment = lambda {|d| d.setDate(d.getDate() + 7 * step); };
163
+ elsif (span >= 3 * 864e5)
164
+ precision = 864e5;
165
+ format = "%m/%d";
166
+ increment = lambda {|d| d.setDate(d.getDate() + step); };
167
+ elsif (span >= 3 * 36e5)
168
+ precision = 36e5;
169
+ format = "%I:%M %p";
170
+ increment = lambda {|d| d.setHours(d.getHours() + step); };
171
+ elsif (span >= 3 * 6e4)
172
+ precision = 6e4;
173
+ format = "%I:%M %p";
174
+ increment = lambda {|d| d.setMinutes(d.getMinutes() + step); };
175
+ elsif (span >= 3 * 1e3)
176
+ precision = 1e3;
177
+ format = "%I:%M:%S";
178
+ increment = lambda {|d| d.setSeconds(d.getSeconds() + step); };
179
+ else
180
+ precision = 1;
181
+ format = "%S.%Qs";
182
+ increment = lambda {|d| d.setTime(d.getTime() + step); };
183
+ end
184
+ @tick_format = pv.Format.date(format);
185
+
186
+ date = Date.new(min)
187
+ dates = []
188
+ #floor(date, precision);
189
+
190
+ # If we'd generate too many ticks, skip some!.
191
+ n = span.quo(precision)
192
+ if (n > 10)
193
+ case (precision)
194
+ when 36e5
195
+ step = (n > 20) ? 6 : 3;
196
+ date.setHours(Math.floor(date.getHours() / step) * step);
197
+ when 2592e6
198
+ step = 3; # seasons
199
+ date.setMonth(Math.floor(date.getMonth() / step) * step);
200
+ when 6e4
201
+ step = (n > 30) ? 15 : ((n > 15) ? 10 : 5);
202
+ date.setMinutes(Math.floor(date.getMinutes() / step) * step);
203
+ when 1e3
204
+ step = (n > 90) ? 15 : ((n > 60) ? 10 : 5);
205
+ date.setSeconds(Math.floor(date.getSeconds() / step) * step);
206
+ when 1
207
+ step = (n > 1000) ? 250 : ((n > 200) ? 100 : ((n > 100) ? 50 : ((n > 50) ? 25 : 5)));
208
+ date.setMilliseconds(Math.floor(date.getMilliseconds() / step) * step);
209
+ else
210
+ step = pv.logCeil(n / 15, 10);
211
+ if (n / step < 2)
212
+ step =step.quo(5)
213
+ elsif (n / step < 5)
214
+ step = step.quo(2)
215
+ end
216
+ date.setFullYear((date.getFullYear().quo(step)).floor * step);
217
+ end
218
+ end
219
+
220
+ while (true)
221
+ increment(date);
222
+ break if (date > max)
223
+ dates.push(Date.new(date));
224
+ end
225
+ return reverse ? dates.reverse() : dates;
226
+ end
227
+
228
+ # Normal case: numbers.
229
+ m = 10 if (arguments.size==0)
230
+
231
+ step = pv.log_floor(span.quo(m), 10)
232
+ err = m.quo(span.quo(step))
233
+ if (err <= 0.15)
234
+ step = step*10
235
+ elsif (err <= 0.35)
236
+ step = step*5
237
+ elsif (err <= 0.75)
238
+ step = step*2
239
+ end
240
+ start = (min.quo(step)).ceil * step
241
+ _end = (max.quo(step)).floor * step
242
+ @tick_format= pv.Format.number().fraction_digits([0, -(pv.log(step, 10) + 0.01).floor].max);
243
+ ticks = pv.range(start, _end + step, step);
244
+ return reverse ? ticks.reverse() : ticks;
245
+ end
246
+ def nice
247
+ if (@d.size!=2)
248
+ return self;
249
+ end
250
+ start=@d.first
251
+ _end=@d[@d.size-1]
252
+ reverse=_end<start
253
+ min=reverse ? _end : start
254
+ max = reverse ? start : _end
255
+ span=max-min
256
+ return self if(!span or span.infinite?)
257
+ step=10**((Math::log(span).quo(Math::log(10))).round-1)
258
+ @d=[(min.quo(step)).floor*step, (max.quo(step)).ceil*step]
259
+ @d.reverse if reverse
260
+ @l=@d.map {|v| @f.call(v)}
261
+ end
262
+ end
263
+ end