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
@@ -8,9 +8,9 @@ module Rubyvis
8
8
  end
9
9
 
10
10
  @properties=Mark.properties.dup
11
- attr_accessor_dsl :width, :height, :line_width, :stroke_style, :fill_style
11
+ attr_accessor_dsl :width, :height, :line_width, [:stroke_style, lambda {|d| pv.color(d)}], [:fill_style, lambda {|d| pv.color(d)}]
12
12
  def self.defaults
13
- Bar.new.extend(Mark.defaults).line_width(1.5).fill_style(Rubyvis.Colors.category20().by(Rubyvis.parent))
13
+ Bar.new.extend(Mark.defaults).line_width(1.5).fill_style( lambda {Rubyvis.Colors.category20().scale(self.parent.index)})
14
14
  end
15
15
  end
16
16
  end
@@ -0,0 +1,85 @@
1
+ module Rubyvis
2
+ def self.Dot
3
+ Rubyvis::Dot
4
+ end
5
+ class Dot < Mark
6
+ def type
7
+ "dot"
8
+ end
9
+
10
+ @properties=Mark.properties.dup
11
+
12
+ attr_accessor_dsl :shape, :shape_angle, :shape_radius, :shape_size, :line_width, [:stroke_style, lambda {|d| pv.color(d)}], [:fill_style, lambda {|d| pv.color(d)}]
13
+
14
+ def self.defaults()
15
+ Dot.new().extend(Mark.defaults).shape("circle"). line_width(1.5). stroke_style(lambda {pv.Colors.category10().scale(self.parent.index)})
16
+ end
17
+
18
+ def anchor(name)
19
+
20
+
21
+ mark_anchor(name).left(lambda {
22
+ s=scene.target[self.index]
23
+ case self.name
24
+ when 'bottom' then s.left;
25
+ when 'top' then s.left;
26
+ when 'center' then s.left;
27
+ when 'left' then nil;
28
+ else
29
+ s.left+s.shape_radius
30
+ end
31
+ }).right(lambda {
32
+ s=scene.target[self.index]
33
+ self.name()=='left' ? s.right+s.shape_radius : nil
34
+
35
+ }).top(lambda {
36
+ s=scene.target[self.index]
37
+ case self.name
38
+ when 'left' then s.top;
39
+ when 'right' then s.top;
40
+ when 'center' then s.top;
41
+ when 'top' then nil;
42
+ else
43
+ s.top+s.shape_radius
44
+ end
45
+ }).bottom(lambda {
46
+ s=scene.target[self.index]
47
+ self.name()=='top' ? s.bottom+s.shape_radius : nil
48
+ }).text_align(lambda {
49
+ case self.name
50
+ when 'left' then 'right';
51
+ when 'bottom' then 'center';
52
+ when 'top' then 'center';
53
+ when 'center' then 'center';
54
+ else
55
+ 'left'
56
+ end
57
+ }).text_baseline( lambda {
58
+ case self.name
59
+ when 'right' then 'middle';
60
+ when 'left' then 'middle';
61
+ when 'center' then 'middle';
62
+ when 'bottom' then 'top';
63
+ else
64
+ 'bottom'
65
+ end
66
+
67
+ })
68
+ end
69
+ def build_implied(s)
70
+ r = s.shape_radius
71
+ z = s.shape_size
72
+ if (r.nil?)
73
+ if (z.nil?)
74
+ s.shape_size = 20.25;
75
+ s.shape_radius = 4.5;
76
+ else
77
+ s.shape_radius = Math.sqrt(z)
78
+ end
79
+ elsif (z.nil?)
80
+ s.shape_size = r * r;
81
+ end
82
+ mark_build_implied(s)
83
+ end
84
+ end
85
+ end
@@ -5,7 +5,7 @@ module Rubyvis
5
5
 
6
6
  class Label < Mark
7
7
  @properties=Mark.properties.dup
8
- attr_accessor_dsl :text, :font, :text_angle, :text_style, :text_align, :text_baseline, :text_margin, :text_decoration, :text_shadow
8
+ attr_accessor_dsl :text, :font, :text_angle, [:text_style, lambda {|d| pv.color(d)}], :text_align, :text_baseline, :text_margin, :text_decoration, :text_shadow
9
9
  def type
10
10
  'label'
11
11
  end
@@ -5,18 +5,19 @@ module Rubyvis
5
5
  module LinePrototype
6
6
  include AreaPrototype
7
7
  def line_anchor(name)
8
- area_anchor(name).text_align(lambda {|d|
9
- {'left'=>'right','bottom'=>'center', 'top'=>'center','center'=>'center','right'=>'left'}[d]
8
+ anchor=area_anchor(name).text_align(lambda {|d|
9
+ {'left'=>'right','bottom'=>'center', 'top'=>'center','center'=>'center','right'=>'left'}[self.name]
10
10
  }).text_baseline(lambda{|d|
11
- {'top'=>'bottom','right'=>'middle', 'left'=>'middle','center'=>'middle','bottom'=>'top'}[d]
11
+ {'top'=>'bottom', 'right'=>'middle', 'left'=>'middle','center'=>'middle','bottom'=>'top'}[self.name]
12
12
  })
13
+ return anchor
13
14
  end
14
15
  end
15
16
  class Line < Mark
16
17
  include AreaPrototype
17
18
  include LinePrototype
18
19
  @properties=Mark.properties.dup
19
- attr_accessor_dsl :line_width, :line_join, :stroke_style, :fill_style, :segmented, :interpolate, :eccentricity, :tension
20
+ attr_accessor_dsl :line_width, :line_join, [:stroke_style, lambda {|d| pv.color(d)}], [:fill_style, lambda {|d| pv.color(d)}], :segmented, :interpolate, :eccentricity, :tension
20
21
  def type
21
22
  "line"
22
23
  end
@@ -29,8 +30,8 @@ module Rubyvis
29
30
  def build_instance(*args)
30
31
  area_build_instance(*args)
31
32
  end
32
- def defaults
33
- Line.new.extend(Rubyvis::Mark).line_join('miter').line_width(1.5).stroke_style(RubyVis::Color.category10().by(pv.parent)).interpolate('linear').eccentricity(0).tension(7)
33
+ def self.defaults
34
+ Line.new.extend(Mark.defaults).line_join('miter').line_width(1.5).stroke_style( lambda {return Rubyvis::Colors.category10().scale(self.parent.index)}).interpolate('linear').eccentricity(0).tension(7)
34
35
  end
35
36
  end
36
37
  end
@@ -74,7 +74,6 @@ module Rubyvis
74
74
  bar = REXML::Formatters::Default.new
75
75
  out = String.new
76
76
  bar.write(v[1].elements[1], out)
77
- out
78
77
  }.join
79
78
  end
80
79
  def build_implied(s)
@@ -5,9 +5,9 @@ module Rubyvis
5
5
  class Rule < Mark
6
6
  include LinePrototype
7
7
  @properties=Mark.properties.dup
8
- attr_accessor_dsl :width, :height, :line_width, :stroke_style
8
+ attr_accessor_dsl :width, :height, :line_width, [:stroke_style, lambda {|d| pv.color(d)}]
9
9
  def self.defaults
10
- Rule.new.extend(Mark.defaults).line_width(1).stroke_style(pv.color('black')).antialias(false)
10
+ Rule.new.extend(Mark.defaults).line_width(1).stroke_style('black').antialias(false)
11
11
  end
12
12
  def type
13
13
  'rule'
@@ -21,12 +21,13 @@ module Rubyvis
21
21
  r=s.right
22
22
  t=s.top
23
23
  b=s.bottom
24
- if((!s.width.nil?) or ((l.nil?) and (r.nil?)) or ((!r.nil?) or (!l.nil?)))
24
+
25
+ if((!s.width.nil?) or ((l.nil?) and (r.nil?)) or ((!r.nil?) and (!l.nil?)))
25
26
  s.height=0
26
27
  else
27
28
  s.width=0
28
29
  end
29
- super(s)
30
+ mark_build_implied(s)
30
31
  end
31
32
  end
32
33
  end
@@ -0,0 +1,124 @@
1
+ module Rubyvis
2
+ def self.Wedge
3
+ Rubyvis::Wedge
4
+ end
5
+ class Wedge < Mark
6
+ def type
7
+ "wedge"
8
+ end
9
+ @properties=Mark.properties.dup
10
+ attr_accessor_dsl :start_angle, :end_angle, :angle, :inner_radius, :outer_radius, :line_width, [:stroke_style, lambda {|d| pv.color(d)}], [:fill_style, lambda {|d| pv.color(d)}]
11
+ def self.defaults
12
+ Wedge.new.extend(Mark.defaults).start_angle(lambda {s=self.sibling; s ? s.end_angle: -Math::PI.quo(2) } ).inner_radius( 0 ).line_width( 1.5 ).stroke_style( nil ).fill_style( lambda {Rubyvis.Colors.category20().scale(self.parent.index)})
13
+ end
14
+ def mid_radius
15
+ (inner_radius+outer_radius) / 2.0
16
+ end
17
+ def mid_angle
18
+ (start_angle+end_angle) / 2.0
19
+ end
20
+
21
+ def anchor(name)
22
+ partial=lambda {|s| s.inner_radius!=0 ? true : s.angle<2*Math.PI}
23
+ mid_radius=lambda {|s| (s.inner_radius+s.outer_radius) / 2.0}
24
+ mid_angle=lambda {|s| (s.start_angle+s.end_angle) / 2.0 }
25
+
26
+ mark_anchor(name).left(lambda {
27
+ s = self.scene.target[self.index];
28
+ if (partial.call(s))
29
+
30
+ case (self.name())
31
+ when "outer"
32
+ return s.left + s.outer_radius * Math.cos(mid_angle.call(s))
33
+ when "inner"
34
+ return s.left + s.inner_radius * Math.cos(mid_angle.call(s))
35
+ when "start"
36
+ return s.left + mid_radius.call(s) * Math.cos(s.start_angle)
37
+ when "center"
38
+ return s.left + mid_radius.call(s) * Math.cos(mid_angle.call(s))
39
+ when "end"
40
+ return s.left + mid_radius.call(s) * Math.cos(s.end_angle)
41
+ end
42
+ end
43
+ return s.left;
44
+ }).top(lambda {
45
+ s = self.scene.target[self.index];
46
+ if (partial.call(s))
47
+ case (self.name())
48
+ when "outer"
49
+ return s.top + s.outer_radius * Math.sin(mid_angle.call(s))
50
+ when "inner"
51
+ return s.top + s.inner_radius * Math.sin(mid_angle.call(s))
52
+ when "start"
53
+ return s.top + mid_radius.call(s) * Math.sin(s.start_angle)
54
+ when "center"
55
+ return s.top + mid_radius.call(s) * Math.sin(mid_angle.call(s))
56
+ when "end"
57
+ return s.top + mid_radius.call(s) * Math.sin(s.end_angle)
58
+ end
59
+ end
60
+ return s.top;
61
+
62
+ }).text_align(lambda {
63
+ s = self.scene.target[self.index];
64
+ if (partial.call(s))
65
+ case (self.name())
66
+ when 'outer'
67
+ return self.upright(mid_angle.call(s)) ? 'right':'left'
68
+ when 'inner'
69
+ return self.upright(mid_angle.call(s)) ? 'left':'right'
70
+
71
+ end
72
+ end
73
+ return 'center'
74
+ }).text_baseline(lambda {
75
+ s = self.scene.target[self.index];
76
+ if (partial.call(s))
77
+ case (self.name())
78
+ when 'start'
79
+ return self.upright(s.start_angle) ? 'top':'bottom'
80
+ when 'end'
81
+ return self.upright(s.end_angle) ? 'bottom':'top'
82
+
83
+ end
84
+ end
85
+ return 'middle'
86
+ }).text_angle(lambda {
87
+ s = self.scene.target[self.index];
88
+ a=0
89
+ if (partial.call(s))
90
+ case (self.name())
91
+ when 'center'
92
+ a=mid_angle.call(s)
93
+ when 'inner'
94
+ a=mid_angle.call(s)
95
+ when 'outer'
96
+ a=mid_angle.call(s)
97
+ when 'start'
98
+ a=s.start_angle
99
+ when 'end'
100
+ a=s.end_angle
101
+ end
102
+ end
103
+ self.upright(a) ? a: (a+Math::PI)
104
+ })
105
+
106
+ end
107
+
108
+
109
+ def self.upright(angle)
110
+ angle=angle % (2*Math::PI)
111
+ angle=(angle<0) ? (2*Math::PI+angle) : angle
112
+ (angle < Math::PI/2.0) or (angle>=3*Math::PI / 2.0)
113
+
114
+ end
115
+ def build_implied(s)
116
+ if (s.angle.nil?)
117
+ s.angle= s.end_angle-s.start_angle
118
+ elsif s.end_angle.nil?
119
+ s.end_angle=s.start_angle+s.angle
120
+ end
121
+ mark_build_implied(s)
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,158 @@
1
+ module Rubyvis
2
+ ##
3
+ # Returns a {@link pv.Nest} operator for the specified array. This is a
4
+ # convenience factory method, equivalent to <tt>new pv.Nest(array)</tt>.
5
+ #
6
+ # @see pv.Nest
7
+ # @param {array} array an array of elements to nest.
8
+ # @returns {Nest} a nest operator for the specified array.
9
+ ##
10
+ def self.nest(array)
11
+ Nest.new(array)
12
+ end
13
+ class NestedArray
14
+ attr_accessor :key, :values
15
+ def initialize(opts)
16
+ @key=opts[:key]
17
+ @values=opts[:values]
18
+ end
19
+ def ==(var)
20
+ key==var.key and values=var.values
21
+ end
22
+ end
23
+ ##
24
+ # Constructs a nest operator for the specified array. This constructor should
25
+ # not be invoked directly; use {@link pv.nest} instead.
26
+ #
27
+ # @class Represents a {@link Nest} operator for the specified array. Nesting
28
+ # allows elements in an array to be grouped into a hierarchical tree
29
+ # structure. The levels in the tree are specified by <i>key</i> functions. The
30
+ # leaf nodes of the tree can be sorted by value, while the internal nodes can
31
+ # be sorted by key. Finally, the tree can be returned either has a
32
+ # multidimensional array via {@link #entries}, or as a hierarchical map via
33
+ # {@link #map}. The {@link #rollup} routine similarly returns a map, collapsing
34
+ # the elements in each leaf node using a summary function.
35
+ #
36
+ # <p>For example, consider the following tabular data structure of Barley
37
+ # yields, from various sites in Minnesota during 1931-2:
38
+ #
39
+ # { yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm" },
40
+ # { yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca" },
41
+ # { yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris" }
42
+ #
43
+ # To facilitate visualization, it may be useful to nest the elements first by
44
+ # year, and then by variety, as follows:
45
+ #
46
+ # <pre>var nest = pv.nest(yields)
47
+ # .key(function(d) d.year)
48
+ # .key(function(d) d.variety)
49
+ # .entries();</pre>
50
+ #
51
+ # This returns a nested array. Each element of the outer array is a key-values
52
+ # pair, listing the values for each distinct key:
53
+ #
54
+ # <pre>{ key: 1931, values: [
55
+ # { key: "Manchuria", values: [
56
+ # { yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm" },
57
+ # { yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca" },
58
+ # { yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris" },
59
+ # ...
60
+ # ] },
61
+ # { key: "Glabron", values: [
62
+ # { yield: 43.07, variety: "Glabron", year: 1931, site: "University Farm" },
63
+ # { yield: 55.20, variety: "Glabron", year: 1931, site: "Waseca" },
64
+ # ...
65
+ # ] },
66
+ # ] },
67
+ # { key: 1932, values: ... }</pre>
68
+ #
69
+ # Further details, including sorting and rollup, is provided below on the
70
+ # corresponding methods.
71
+ #
72
+ # @param {array} array an array of elements to nest.
73
+ #/
74
+ class Nest
75
+ attr_accessor :array, :keys, :order
76
+ def initialize(array)
77
+ @array=array
78
+ @keys=[]
79
+ @order=nil
80
+ end
81
+ def key(k)
82
+ @keys.push(k)
83
+ return self
84
+ end
85
+ def sort_keys(order=nil)
86
+ #keys[keys.size-1].order = order.nil? ? pv.natural_order : order
87
+ return self
88
+ end
89
+ def sort_values(order=nil)
90
+ @order = order.nil? ? pv.natural_order : order
91
+ return self
92
+ end
93
+ def map
94
+ i=0
95
+ map={}
96
+ values=[]
97
+ @array.each_with_index {|x,j|
98
+ m=map
99
+ (@keys.size-1).times {|i|
100
+ k=@keys[i].call(x)
101
+ m[k]={} if (!m[k])
102
+ m=m[k]
103
+ }
104
+ k=@keys.last.call(x)
105
+ if(!m[k])
106
+ a=[]
107
+ values.push(a)
108
+ m[k]=a
109
+ end
110
+ m[k].push(x)
111
+ }
112
+ if(self.order)
113
+ values.each_with_index {|v,vi|
114
+ values[vi].sort(&self.order)
115
+ }
116
+ end
117
+ map
118
+ end
119
+ def entries()
120
+ entries_sort(entries_entries(map),0)
121
+ end
122
+ def entries_entries(map)
123
+ array=[]
124
+ map.each_pair {|k,v|
125
+ array.push(NestedArray.new({:key=>k, :values=>(v.is_a? Array) ? v: entries_entries(v)}))
126
+ }
127
+ array
128
+ end
129
+ def entries_sort(array,i)
130
+ o=keys[i].order
131
+ if o
132
+ array.sort {|a,b| o(a.key, b.key)}
133
+ end
134
+ i+=1
135
+ if (i<keys.size)
136
+ array.each {|v|
137
+ entries_sort(v, i)
138
+ }
139
+
140
+ end
141
+ return array
142
+
143
+ end
144
+ def rollup_rollup(map,f)
145
+ map.each_pair {|key,value|
146
+ if value.is_a? Array
147
+ map[key]=f.call(value)
148
+ else
149
+ rollup_rollup(value)
150
+ end
151
+ }
152
+ return map;
153
+ end
154
+ def rollup(f)
155
+ rollup_rollup(self.map,f)
156
+ end
157
+ end
158
+ end