rubyvis 0.1.2 → 0.1.3

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.
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
+