rubyvis 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.txt +13 -1
  3. data/Manifest.txt +19 -0
  4. data/examples/antibiotics/antibiotics.rb +96 -0
  5. data/examples/antibiotics/antibiotics_data.rb +20 -0
  6. data/examples/area.rb +103 -0
  7. data/examples/bar_column_chart.rb +55 -0
  8. data/examples/barley/barley.rb +29 -19
  9. data/examples/barley/barley_data.rb +122 -0
  10. data/examples/crimea/crimea_grouped_bar.rb +59 -0
  11. data/examples/dot.rb +19 -0
  12. data/examples/first.rb +1 -6
  13. data/examples/line.rb +84 -0
  14. data/examples/pie_and_donut.rb +38 -0
  15. data/examples/scatterplot.rb +55 -0
  16. data/examples/second.rb +3 -4
  17. data/examples/third.rb +1 -1
  18. data/lib/rubyvis.rb +3 -1
  19. data/lib/rubyvis/color/color.rb +31 -3
  20. data/lib/rubyvis/color/colors.rb +3 -3
  21. data/lib/rubyvis/format/number.rb +80 -10
  22. data/lib/rubyvis/internals.rb +11 -5
  23. data/lib/rubyvis/javascript_behaviour.rb +1 -0
  24. data/lib/rubyvis/mark.rb +43 -20
  25. data/lib/rubyvis/mark/anchor.rb +1 -1
  26. data/lib/rubyvis/mark/area.rb +15 -13
  27. data/lib/rubyvis/mark/bar.rb +2 -2
  28. data/lib/rubyvis/mark/dot.rb +85 -0
  29. data/lib/rubyvis/mark/label.rb +1 -1
  30. data/lib/rubyvis/mark/line.rb +7 -6
  31. data/lib/rubyvis/mark/panel.rb +0 -1
  32. data/lib/rubyvis/mark/rule.rb +5 -4
  33. data/lib/rubyvis/mark/wedge.rb +124 -0
  34. data/lib/rubyvis/nest.rb +158 -0
  35. data/lib/rubyvis/scale.rb +4 -0
  36. data/lib/rubyvis/scale/log.rb +55 -0
  37. data/lib/rubyvis/scale/ordinal.rb +34 -11
  38. data/lib/rubyvis/scale/quantitative.rb +17 -3
  39. data/lib/rubyvis/scene/svg_area.rb +197 -0
  40. data/lib/rubyvis/scene/svg_dot.rb +67 -0
  41. data/lib/rubyvis/scene/svg_label.rb +17 -15
  42. data/lib/rubyvis/scene/svg_line.rb +0 -2
  43. data/lib/rubyvis/scene/svg_rule.rb +2 -2
  44. data/lib/rubyvis/scene/svg_scene.rb +8 -1
  45. data/lib/rubyvis/scene/svg_wedge.rb +56 -0
  46. data/lib/rubyvis/sceneelement.rb +2 -1
  47. data/spec/bar_spec.rb +27 -3
  48. data/spec/label_spec.rb +1 -1
  49. data/spec/nest_spec.rb +41 -0
  50. data/spec/panel_spec.rb +1 -1
  51. data/spec/scale_linear_spec.rb +2 -2
  52. data/spec/scale_ordinal_spec.rb +81 -0
  53. data/spec/spec.opts +0 -1
  54. metadata +24 -3
  55. metadata.gz.sig +0 -0
data/lib/rubyvis/scale.rb CHANGED
@@ -12,6 +12,9 @@ module Rubyvis
12
12
  def self.ordinal(*args)
13
13
  Ordinal.new(*args)
14
14
  end
15
+ def self.log(*args)
16
+ Log.new(*args)
17
+ end
15
18
  def self.interpolator(start,_end)
16
19
  if start.is_a? Numeric
17
20
  return lambda {|t| t*(_end-start)+start}
@@ -32,3 +35,4 @@ end
32
35
  require 'rubyvis/scale/quantitative.rb'
33
36
  require 'rubyvis/scale/linear.rb'
34
37
  require 'rubyvis/scale/ordinal.rb'
38
+ require 'rubyvis/scale/log.rb'
@@ -0,0 +1,55 @@
1
+ module Rubyvis
2
+
3
+ class Scale::Log < Rubyvis::Scale::Quantitative
4
+ def initialize(*args)
5
+ super(*args)
6
+ @b=nil
7
+ @_p=nil
8
+
9
+ base(10)
10
+ end
11
+ def log(x)
12
+
13
+ Math.log(x+1e15) / @_p
14
+ end
15
+ def pow(y)
16
+ @b**y
17
+ end
18
+ def base(v=nil)
19
+ if v
20
+ @b=v
21
+ @_p=Math.log(@b)
22
+ transform(lambda {|x| log(x)}, lambda {|x| pow(x)})
23
+ return self
24
+ end
25
+ return @b
26
+ end
27
+ def ticks
28
+ d = domain
29
+ n = d[0] < 0,
30
+ i = (n ? -log(-d[0]) : log(d[0])).floor
31
+ j = (n ? -log(-d[1]) : log(d[1])).ceil
32
+ ticks = [];
33
+ if n
34
+ ticks.push(-pow(-i))
35
+ (i..j).each {|ii|
36
+ ((b-1)...0).each {|k|
37
+ ticks.push(-pow(-ii) * k)
38
+ }
39
+ }
40
+ else
41
+ (i...j).each {|ii|
42
+ (1...b).each {|k|
43
+ ticks.push(pow(i) * k)
44
+ }
45
+ }
46
+ ticks.push(pow(i));
47
+ end
48
+
49
+ #for (i = 0; ticks[i] < d[0]; i++); // strip small values
50
+ #for (j = ticks.length; ticks[j - 1] > d[1]; j--); // strip big values
51
+ #return ticks.slice(i, j);
52
+ ticks
53
+ end
54
+ end
55
+ end
@@ -1,14 +1,19 @@
1
1
  module Rubyvis
2
2
  class Scale::Ordinal
3
- include Rubyvis::Scale
4
-
3
+ #include Rubyvis::Scale
4
+ attr_reader :range_band
5
5
  def initialize(*args)
6
6
  @d=[] # domain
7
7
  @i={}
8
8
  @r=[]
9
+ @range_band=nil
9
10
  @band=0
10
11
  domain(*args)
11
12
  end
13
+ def to_proc
14
+ that=self
15
+ lambda {|*args| args[0] ? that.scale(args[0]) : nil }
16
+ end
12
17
  def scale(x)
13
18
  if @i[x].nil?
14
19
  @d.push(x)
@@ -17,15 +22,33 @@ module Rubyvis
17
22
  @r[@i[x] % @r.size]
18
23
  end
19
24
  def domain(*arguments)
20
- array,f=arguments[0],arguments[1]
25
+ array, f=arguments[0],arguments[1]
21
26
  if(arguments.size>0)
22
- array= (array.is_a? Array) ? ((arguments.size>1) ? array.map(&f) : array) : arguments.dup
27
+ array= (array.is_a? Array) ? ((arguments.size>1) ? pv.map(array,f) : array) : arguments.dup
23
28
  @d=array.uniq
24
- i=pv.numerate(d)
29
+ @i=pv.numerate(@d)
25
30
  return self
26
31
  end
27
32
  @d
28
33
  end
34
+ def split_banded(*arguments)
35
+ min,max,band=arguments
36
+ band=1 if (arguments.size < 3)
37
+ if (band < 0)
38
+
39
+ n = self.domain().size
40
+ total = -band * n
41
+ remaining = max - min - total
42
+ padding = remaining / (n + 1).to_f
43
+ @r = pv.range(min + padding, max, padding - band);
44
+ @range_band = -band;
45
+ else
46
+ step = (max - min) / (self.domain().size + (1 - band))
47
+ @r = pv.range(min + step * (1 - band), max, step);
48
+ @range_band = step * band;
49
+ end
50
+ return self
51
+ end
29
52
  def range(*arguments)
30
53
  array, f = arguments[0],arguments[1]
31
54
  if(arguments.size>0)
@@ -33,7 +56,7 @@ module Rubyvis
33
56
  if @r[0].is_a? String
34
57
  @r=@r.map {|i| pv.color(i)}
35
58
  end
36
- self
59
+ return self
37
60
  end
38
61
  @r
39
62
  end
@@ -42,11 +65,11 @@ module Rubyvis
42
65
  @r=pv.range(min+step.quo(2),max,step)
43
66
  self
44
67
  end
45
- def by(*arguments)
46
- f,dummy=arguments
47
- t=self
48
- by=lambda {t.scale(f.js_apply(self,arguments))}
49
- by
68
+ def by(f)
69
+ that=self
70
+ lambda {|*args|
71
+ that.scale(f.js_apply(self,args))
72
+ }
50
73
  end
51
74
  end
52
75
  end
@@ -11,13 +11,22 @@ module Rubyvis
11
11
  @n=false
12
12
  @f=Rubyvis.identity # default forward transformation
13
13
  @g=Rubyvis.identity
14
- @tick_format=lambda {|x| x.to_f}
14
+ @tick_format=lambda {|x|
15
+ if x.is_a? Numeric
16
+ (x.to_f-x.to_i==0) ? x.to_i : x.to_f
17
+ else
18
+ ""
19
+ end
20
+ }
15
21
  domain(*args)
16
22
  end
17
23
  def new_date(x=nil)
18
24
  x.nil? ? Time.new() : Time.at(x)
19
25
  end
20
-
26
+ def to_proc
27
+ that=self
28
+ lambda {|*args| args[0] ? that.scale(args[0]) : nil }
29
+ end
21
30
  def scale(x)
22
31
  x=x.to_f
23
32
  j=Rubyvis.search(@d, x)
@@ -251,10 +260,15 @@ module Rubyvis
251
260
  end
252
261
  start = (min.quo(step)).ceil * step
253
262
  _end = (max.quo(step)).floor * step
254
- @tick_format= pv.Format.number().fraction_digits([0, -(pv.log(step, 10) + 0.01).floor].max);
263
+ @tick_format= pv.Format.number.fraction_digits([0, -(pv.log(step, 10) + 0.01).floor].max)
255
264
  ticks = pv.range(start, _end + step, step);
256
265
  return reverse ? ticks.reverse() : ticks;
257
266
  end
267
+
268
+ def tick_format
269
+ @tick_format
270
+ end
271
+
258
272
  def nice
259
273
  if (@d.size!=2)
260
274
  return self;
@@ -0,0 +1,197 @@
1
+ module Rubyvis
2
+ module SvgScene
3
+ def self.area(scenes)
4
+ e = scenes._g.elements[1]
5
+ return e if scenes.size==0
6
+ s=scenes[0]
7
+ # segmented */
8
+ return self.area_segment(scenes) if (s.segmented)
9
+ # visible
10
+ #
11
+ return e if (!s.visible)
12
+
13
+ fill = s.fill_style
14
+ stroke = s.stroke_style
15
+
16
+ return e if (fill.opacity==0 and stroke.opacity==0)
17
+ # /** @private Computes the straight path for the range [i, j]. */
18
+ path=lambda {|i,j|
19
+ p1 = []
20
+ p2 = [];
21
+ k=j
22
+ (i..k).each {|i|
23
+ si = scenes[i]
24
+ sj = scenes[j]
25
+ pi = "#{si.left},#{si.top}"
26
+ pj = "#{(sj.left + sj.width)},#{(sj.top + sj.height)}"
27
+
28
+ #/* interpolate */
29
+ if (i < k)
30
+ sk = scenes[i + 1]
31
+ sl = scenes[j - 1]
32
+ case (s.interpolate)
33
+ when "step-before"
34
+ pi = pi+"V#{sk.top}"
35
+ pj = pj+"H#{sl.left + sl.width}"
36
+
37
+ when "step-after"
38
+ pi = pi+"H#{sk.left}"
39
+ pj = pj+"V#{sl.top + sl.height}"
40
+ end
41
+ end
42
+
43
+ p1.push(pi);
44
+ p2.push(pj);
45
+ j=j-1
46
+ }
47
+ (p1+p2).join("L");
48
+ }
49
+
50
+ # @private Computes the curved path for the range [i, j]. */
51
+ path_curve=lambda {|i, j|
52
+ pointsT = []
53
+ pointsB = []
54
+ pathT=nil
55
+ pathB=nil
56
+
57
+
58
+ k=j
59
+ (i..k).each {|i|
60
+ sj = scenes[j];
61
+ pointsT.push(scenes[i])
62
+ pointsB.push(OpenStruct.new({:left=> sj.left + sj.width, :top=> sj.top + sj.height}))
63
+ j=j-1
64
+ }
65
+
66
+ if (s.interpolate == "basis")
67
+ pathT = pv.SvgScene.curve_basis(pointsT);
68
+ pathB = pv.SvgScene.curve_basis(pointsB);
69
+ elsif (s.interpolate == "cardinal")
70
+ pathT = pv.SvgScene.curve_cardinal(pointsT, s.tension);
71
+ pathB = pv.SvgScene.curve_cardinal(pointsB, s.tension);
72
+ elsif # monotone
73
+ pathT = pv.SvgScene.curve_monotone(pointsT);
74
+ pathB = pv.SvgScene.curve_monotone(pointsB);
75
+ end
76
+
77
+ "#{pointsT[0].left },#{ pointsT[0].top }#{ pathT }L#{ pointsB[0].left},#{pointsB[0].top}#{pathB}"
78
+ }
79
+
80
+ #/* points */
81
+ d = []
82
+ si=nil
83
+ sj=nil
84
+ i=0
85
+ while(i<scenes.size)
86
+ si = scenes[i]
87
+ continue if (si.width==0 and si.height==0)
88
+ j=0
89
+ (i+1).upto(scenes.size-1) {|jj|
90
+ j=jj; sj = scenes[jj];
91
+ break if (si.width==0 and si.height==0)
92
+ }
93
+
94
+ i=i-1 if (i!=0 and (s.interpolate != "step-after"))
95
+ j=j+1 if ((j < scenes.size) and (s.interpolate != "step-before"))
96
+ d.push(((j - i > 2 and (s.interpolate == "basis" or s.interpolate == "cardinal" or s.interpolate == "monotone")) ? path_curve : path).call(i, j - 1))
97
+ i = j - 1
98
+ i+=1
99
+ end
100
+
101
+ return e if d.size==0
102
+
103
+ e = self.expect(e, "path", {
104
+ "shape-rendering"=> s.antialias ? nil : "crispEdges",
105
+ "pointer-events"=> s.events,
106
+ "cursor"=> s.cursor,
107
+ "d"=> "M" + d.join("ZM") + "Z",
108
+ "fill"=> fill.color,
109
+ "fill-opacity"=> fill.opacity==0 ? nil : fill.opacity,
110
+ "stroke"=> stroke.color,
111
+ "stroke-opacity"=> stroke.opacity==0 ? nil : stroke.opacity,
112
+ "stroke-width"=> stroke.opacity!=0 ? s.line_width / self.scale : nil
113
+ });
114
+ return self.append(e, scenes, 0);
115
+ end
116
+
117
+ def self.area_segment(scenes)
118
+
119
+ e = scenes._g.elements[1]
120
+ s = scenes[0]
121
+ pathsT=[]
122
+ pathsB=[]
123
+
124
+ if (s.interpolate == "basis" or s.interpolate == "cardinal" or s.interpolate == "monotone")
125
+ pointsT = []
126
+ pointsB = []
127
+ n=scenes.size
128
+ n.times {|i|
129
+ sj = scenes[n - i - 1]
130
+ pointsT.push(scenes[i])
131
+ pointsB.push(OpenStruct.new({:left=> sj.left + sj.width, :top=> sj.top + sj.height}));
132
+ }
133
+
134
+ if (s.interpolate == "basis")
135
+ pathT = pv.SvgScene.curve_basis_segments(pointsT);
136
+ pathB = pv.SvgScene.curve_basis_segments(pointsB);
137
+ elsif (s.interpolate == "cardinal")
138
+ pathT = pv.SvgScene.curve_cardinal_segments(pointsT, s.tension);
139
+ pathB = pv.SvgScene.curve_cardinal_segments(pointsB, s.tension);
140
+ elsif # monotone
141
+ pathT = pv.SvgScene.curve_monotone_segments(pointsT);
142
+ pathB = pv.SvgScene.curve_monotone_segments(pointsB);
143
+ end
144
+ end
145
+ n=scenes.size-1
146
+ n.times {|i|
147
+
148
+ s1 = scenes[i]
149
+ s2 = scenes[i + 1]
150
+
151
+ # /* visible */
152
+ next if (!s1.visible or !s2.visible)
153
+
154
+ fill = s.fill_style
155
+ stroke = s.stroke_style
156
+ next e if (fill.opacity==0 and stroke.opacity==0)
157
+ d=nil
158
+ if (pathsT)
159
+ pathT = pathsT[i]
160
+ pb=pathsB[n - i - 1]
161
+ pathB = "L" + pb[1,pb.size-1]
162
+ d = pathT + pathB + "Z";
163
+ else
164
+ #/* interpolate */
165
+ si = s1
166
+ sj = s2
167
+
168
+ case (s1.interpolate)
169
+ when "step-before"
170
+ si = s2
171
+ when "step-after"
172
+ sj = s1
173
+ end
174
+
175
+
176
+ #/* path */
177
+ d = "M#{s1.left},#{si.top}L#{s2.left},#{sj.top }L#{s2.left + s2.width},#{sj.top + sj.height}L#{s1.left + s1.width},#{si.top + si.height}Z"
178
+ end
179
+
180
+ e = self.expect(e, "path", {
181
+ "shape-rendering"=> s1.antialias ? null : "crispEdges",
182
+ "pointer-events"=> s1.events,
183
+ "cursor"=> s1.cursor,
184
+ "d"=> d,
185
+ "fill"=> fill.color,
186
+ "fill-opacity"=> fill.opacity==0 ? nil : fill.opacity,
187
+ "stroke"=> stroke.color,
188
+ "stroke-opacity"=> stroke.opacity==0 ? nil : stroke.opacity,
189
+ "stroke-width"=> stroke.opacity!=0 ? s1.line_width / self.scale : nil
190
+ });
191
+ e = self.append(e, scenes, i);
192
+ }
193
+ return e;
194
+ end
195
+ end
196
+ end
197
+
@@ -0,0 +1,67 @@
1
+ module Rubyvis
2
+ module SvgScene
3
+ def self.dot(scenes)
4
+ e = scenes._g.elements[1]
5
+ scenes.each_with_index {|s,i|
6
+ s = scenes[i];
7
+
8
+ # visible */
9
+ next if !s.visible
10
+ fill = s.fill_style
11
+ stroke = s.stroke_style
12
+ next if (fill.opacity==0 and stroke.opacity==0)
13
+
14
+ #/* points */
15
+ radius = s.shape_radius
16
+ path = nil
17
+ case s.shape
18
+ when 'cross'
19
+ path = "M#{-radius},#{-radius}L#{radius},#{radius}M#{radius},#{ -radius}L#{ -radius},#{radius}"
20
+ when "triangle"
21
+ h = radius
22
+ w = radius * 1.1547; # // 2 / Math.sqrt(3)
23
+ path = "M0,#{h}L#{w},#{-h} #{-w},#{-h}Z"
24
+ when "diamond"
25
+ radius=radius* Math::sqrt(2)
26
+ path = "M0,#{-radius}L#{radius},0 0,#{radius} #{-radius},0Z";
27
+ when "square"
28
+ path = "M#{-radius},#{-radius}L#{radius},#{-radius} #{radius},#{radius} #{-radius},#{radius}Z"
29
+ when "tick"
30
+ path = "M0,0L0,#{-s.shapeSize}"
31
+ when "bar"
32
+ path = "M0,#{s.shape_size / 2.0}L0,#{-(s.shapeSize / 2.0)}"
33
+
34
+ end
35
+
36
+ #/* Use <circle> for circles, <path> for everything else. */
37
+ svg = {
38
+ "shape-rendering"=> s.antialias ? nil : "crispEdges",
39
+ "pointer-events"=> s.events,
40
+ "cursor"=> s.cursor,
41
+ "fill"=> fill.color,
42
+ "fill-opacity"=> (fill.opacity==0) ? nil :fill.opacity,
43
+ "stroke"=> stroke.color,
44
+ "stroke-opacity"=> (stroke.opacity==0) ? nil : stroke.opacity,
45
+ "stroke-width"=> (stroke.opacity!=0) ? s.line_width / self.scale : nil
46
+ }
47
+
48
+ if (path)
49
+ svg["transform"] = "translate(#{s.left},#{s.top})"
50
+ if (s.shape_angle)
51
+ svg["transform"] += " rotate(#{180 * s.shape_angle / Math.PI})";
52
+ end
53
+ svg["d"] = path
54
+ e = self.expect(e, "path", svg);
55
+ else
56
+ svg["cx"] = s.left;
57
+ svg["cy"] = s.top;
58
+ svg["r"] = radius;
59
+ e = self.expect(e, "circle", svg);
60
+ end
61
+ e = self.append(e, scenes, i);
62
+ }
63
+ return e
64
+ end
65
+ end
66
+ end
67
+