rubyvis 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -1
- data/Manifest.txt +9 -4
- data/README.txt +59 -8
- data/examples/antibiotics/antibiotics.rb +16 -8
- data/examples/area.rb +6 -49
- data/examples/bar_column_chart.rb +4 -0
- data/examples/crimea/{crimea.rb → crimea_data.rb} +0 -0
- data/examples/crimea/crimea_grouped_bar.rb +2 -2
- data/examples/crimea/crimea_line.rb +1 -1
- data/examples/dot.rb +7 -8
- data/examples/first.rb +4 -0
- data/examples/grouped_charts.rb +3 -0
- data/examples/line.rb +19 -61
- data/examples/line_and_step.rb +4 -0
- data/examples/nested_grid.rb +53 -0
- data/examples/scatterplot.rb +2 -0
- data/examples/second.rb +14 -2
- data/examples/third.rb +9 -6
- data/lib/rubyvis/color/color.rb +8 -6
- data/lib/rubyvis/color/colors.rb +4 -6
- data/lib/rubyvis/format/number.rb +2 -2
- data/lib/rubyvis/internals.rb +15 -3
- data/lib/rubyvis/javascript_behaviour.rb +20 -8
- data/lib/rubyvis/layout/stack.rb +13 -16
- data/lib/rubyvis/mark/anchor.rb +64 -2
- data/lib/rubyvis/mark/area.rb +4 -3
- data/lib/rubyvis/mark/bar.rb +51 -2
- data/lib/rubyvis/mark/dot.rb +88 -5
- data/lib/rubyvis/mark/label.rb +94 -3
- data/lib/rubyvis/mark/line.rb +3 -2
- data/lib/rubyvis/mark/panel.rb +1 -0
- data/lib/rubyvis/mark/rule.rb +2 -1
- data/lib/rubyvis/mark/wedge.rb +2 -1
- data/lib/rubyvis/mark.rb +419 -54
- data/lib/rubyvis/nest.rb +20 -20
- data/lib/rubyvis/scale/linear.rb +1 -1
- data/lib/rubyvis/scale/log.rb +1 -1
- data/lib/rubyvis/scale/ordinal.rb +120 -8
- data/lib/rubyvis/scale/quantitative.rb +159 -15
- data/lib/rubyvis/scale.rb +1 -1
- data/lib/rubyvis/scene/svg_area.rb +12 -12
- data/lib/rubyvis/scene/svg_line.rb +5 -5
- data/lib/rubyvis/scene/svg_panel.rb +1 -1
- data/lib/rubyvis/scene/svg_scene.rb +1 -1
- data/lib/rubyvis.rb +35 -6
- data/spec/anchor_spec.rb +15 -15
- data/web/Rakefile +34 -0
- data/web/build_site.rb +86 -0
- data/web/examples.haml +26 -0
- data/web/index.haml +97 -0
- data/web/style.css +82 -0
- data.tar.gz.sig +0 -0
- metadata +14 -9
- metadata.gz.sig +0 -0
- data/lib/rubyvis/label.rb +0 -1
- data/web/first.svg +0 -1
- data/web/index.html +0 -48
data/lib/rubyvis/nest.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
module Rubyvis
|
2
2
|
##
|
3
|
-
# Returns a
|
4
|
-
# convenience factory method, equivalent to <tt>new
|
3
|
+
# Returns a Nest operator for the specified array. This is a
|
4
|
+
# convenience factory method, equivalent to <tt>Nest.new(array)</tt>.
|
5
5
|
#
|
6
|
-
# @see
|
6
|
+
# @see Rubyvis::Nest
|
7
7
|
# @param {array} array an array of elements to nest.
|
8
8
|
# @returns {Nest} a nest operator for the specified array.
|
9
9
|
##
|
10
10
|
def self.nest(array)
|
11
11
|
Nest.new(array)
|
12
12
|
end
|
13
|
+
# :stopdoc:
|
13
14
|
class NestedArray
|
14
15
|
attr_accessor :key, :values
|
15
16
|
def initialize(opts)
|
@@ -20,20 +21,18 @@ module Rubyvis
|
|
20
21
|
key==var.key and values=var.values
|
21
22
|
end
|
22
23
|
end
|
23
|
-
|
24
|
-
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# @class Represents a {@link Nest} operator for the specified array. Nesting
|
24
|
+
# :startdoc:
|
25
|
+
|
26
|
+
# Represents a Nest operator for the specified array. Nesting
|
28
27
|
# allows elements in an array to be grouped into a hierarchical tree
|
29
28
|
# structure. The levels in the tree are specified by <i>key</i> functions. The
|
30
29
|
# leaf nodes of the tree can be sorted by value, while the internal nodes can
|
31
30
|
# be sorted by key. Finally, the tree can be returned either has a
|
32
|
-
# multidimensional array via
|
33
|
-
#
|
31
|
+
# multidimensional array via Nest.entries, or as a hierarchical map via
|
32
|
+
# Nest.map. The Nest.rollup routine similarly returns a map, collapsing
|
34
33
|
# the elements in each leaf node using a summary function.
|
35
34
|
#
|
36
|
-
#
|
35
|
+
# For example, consider the following tabular data structure of Barley
|
37
36
|
# yields, from various sites in Minnesota during 1931-2:
|
38
37
|
#
|
39
38
|
# { yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm" },
|
@@ -43,10 +42,10 @@ module Rubyvis
|
|
43
42
|
# To facilitate visualization, it may be useful to nest the elements first by
|
44
43
|
# year, and then by variety, as follows:
|
45
44
|
#
|
46
|
-
#
|
47
|
-
# .key(
|
48
|
-
# .key(
|
49
|
-
# .entries()
|
45
|
+
# var nest = Rubyvis.nest(yields)
|
46
|
+
# .key(lambda {|d| d.year})
|
47
|
+
# .key(lambda {|d| d.variety})
|
48
|
+
# .entries();
|
50
49
|
#
|
51
50
|
# This returns a nested array. Each element of the outer array is a key-values
|
52
51
|
# pair, listing the values for each distinct key:
|
@@ -68,11 +67,12 @@ module Rubyvis
|
|
68
67
|
#
|
69
68
|
# Further details, including sorting and rollup, is provided below on the
|
70
69
|
# corresponding methods.
|
71
|
-
#
|
72
|
-
# @param {array} array an array of elements to nest.
|
73
|
-
#/
|
74
70
|
class Nest
|
75
71
|
attr_accessor :array, :keys, :order
|
72
|
+
##
|
73
|
+
# Constructs a nest operator for the specified array. This constructor should
|
74
|
+
# not be invoked directly; use Rubyvis.nest instead.
|
75
|
+
|
76
76
|
def initialize(array)
|
77
77
|
@array=array
|
78
78
|
@keys=[]
|
@@ -83,11 +83,11 @@ module Rubyvis
|
|
83
83
|
return self
|
84
84
|
end
|
85
85
|
def sort_keys(order=nil)
|
86
|
-
keys[keys.size-1].order = order.nil? ?
|
86
|
+
keys[keys.size-1].order = order.nil? ? Rubyvis.natural_order : order
|
87
87
|
return self
|
88
88
|
end
|
89
89
|
def sort_values(order=nil)
|
90
|
-
@order = order.nil? ?
|
90
|
+
@order = order.nil? ? Rubyvis.natural_order : order
|
91
91
|
return self
|
92
92
|
end
|
93
93
|
def map
|
data/lib/rubyvis/scale/linear.rb
CHANGED
data/lib/rubyvis/scale/log.rb
CHANGED
@@ -1,7 +1,60 @@
|
|
1
1
|
module Rubyvis
|
2
|
+
# Represents an ordinal scale. <style
|
3
|
+
# type="text/css">sub{line-height:0}</style> An ordinal scale represents a
|
4
|
+
# pairwise mapping from <i>n</i> discrete values in the input domain to
|
5
|
+
# <i>n</i> discrete values in the output range. For example, an ordinal scale
|
6
|
+
# might map a domain of species ["setosa", "versicolor", "virginica"] to colors
|
7
|
+
# ["red", "green", "blue"]. Thus, saying
|
8
|
+
#
|
9
|
+
# .fill_style(lambda {|d|
|
10
|
+
# case (d.species)
|
11
|
+
# when "setosa"
|
12
|
+
# "red"
|
13
|
+
# when "versicolor"
|
14
|
+
# "green"
|
15
|
+
# when "virginica"
|
16
|
+
# "blue"
|
17
|
+
# }
|
18
|
+
# )
|
19
|
+
#
|
20
|
+
# is equivalent to
|
21
|
+
#
|
22
|
+
# .fill_style(Rubyvis::Scale.ordinal("setosa", "versicolor", "virginica")
|
23
|
+
# .range("red", "green", "blue")
|
24
|
+
# .by(lambda {|d| d.species}))</pre>
|
25
|
+
#
|
26
|
+
# If the mapping from species to color does not need to be specified
|
27
|
+
# explicitly, the domain can be omitted. In this case it will be inferred
|
28
|
+
# lazily from the data:
|
29
|
+
#
|
30
|
+
# .fill_style(Rubyvis.colors("red", "green", "blue")
|
31
|
+
# .by(lambda {|d| d.species}))</pre>
|
32
|
+
#
|
33
|
+
# When the domain is inferred, the first time the scale is invoked, the first
|
34
|
+
# element from the range will be returned. Subsequent calls with unique values
|
35
|
+
# will return subsequent elements from the range. If the inferred domain grows
|
36
|
+
# larger than the range, range values will be reused. However, it is strongly
|
37
|
+
# recommended that the domain and the range contain the same number of
|
38
|
+
# elements.
|
39
|
+
#
|
40
|
+
# A range can be discretized from a continuous interval (e.g., for pixel
|
41
|
+
# positioning) by using split, split_flush or
|
42
|
+
# split_banded after the domain has been set. For example, if
|
43
|
+
# <tt>states</tt> is an array of the fifty U.S. state names, the state name can
|
44
|
+
# be encoded in the left position:
|
45
|
+
#
|
46
|
+
# .left(Rubyvis::Scale.ordinal(states)
|
47
|
+
# .split(0, 640)
|
48
|
+
# .by(lambda {|d| d.state}))
|
49
|
+
#
|
50
|
+
# N.B.: ordinal scales are not invertible (at least not yet), since the
|
51
|
+
# domain and range and discontinuous. A workaround is to use a linear scale.
|
2
52
|
class Scale::Ordinal
|
3
|
-
#
|
53
|
+
# range band, after use split_banded
|
54
|
+
# equivalen to protovis scale.range().band
|
4
55
|
attr_reader :range_band
|
56
|
+
# Returns an ordinal scale for the specified domain. The arguments to this
|
57
|
+
# constructor are optional, and equivalent to calling domain
|
5
58
|
def initialize(*args)
|
6
59
|
@d=[] # domain
|
7
60
|
@i={}
|
@@ -10,6 +63,14 @@ module Rubyvis
|
|
10
63
|
@band=0
|
11
64
|
domain(*args)
|
12
65
|
end
|
66
|
+
|
67
|
+
# Return
|
68
|
+
# lambda {|d| scale_object.scale(d)}
|
69
|
+
# Useful as value on dynamic properties
|
70
|
+
# scale=Rubyvis.ordinal("red","blue","green")
|
71
|
+
# bar.fill_style(scale)
|
72
|
+
# is the same as
|
73
|
+
# bar.fill_style(lambda {|x| scale.scale(x)})
|
13
74
|
def to_proc
|
14
75
|
that=self
|
15
76
|
lambda {|*args| args[0] ? that.scale(args[0]) : nil }
|
@@ -21,17 +82,60 @@ module Rubyvis
|
|
21
82
|
end
|
22
83
|
@r[@i[x] % @r.size]
|
23
84
|
end
|
85
|
+
# Sets or gets the input domain. This method can be invoked several ways:
|
86
|
+
#
|
87
|
+
# <p>1. <tt>domain(values...)</tt>
|
88
|
+
#
|
89
|
+
# <p>Specifying the domain as a series of values is the most explicit and
|
90
|
+
# recommended approach. However, if the domain values are derived from data,
|
91
|
+
# you may find the second method more appropriate.
|
92
|
+
#
|
93
|
+
# <p>2. <tt>domain(array, f)</tt>
|
94
|
+
#
|
95
|
+
# <p>Rather than enumerating the domain values as explicit arguments to this
|
96
|
+
# method, you can specify a single argument of an array. In addition, you can
|
97
|
+
# specify an optional accessor function to extract the domain values from the
|
98
|
+
# array.
|
99
|
+
#
|
100
|
+
# <p>3. <tt>domain()</tt>
|
101
|
+
#
|
102
|
+
# <p>Invoking the <tt>domain</tt> method with no arguments returns the
|
103
|
+
# current domain as an array.
|
24
104
|
def domain(*arguments)
|
25
105
|
array, f=arguments[0],arguments[1]
|
26
106
|
if(arguments.size>0)
|
27
|
-
array= (array.is_a? Array) ? ((arguments.size>1) ?
|
107
|
+
array= (array.is_a? Array) ? ((arguments.size>1) ? Rubyvis.map(array,f) : array) : arguments.dup
|
28
108
|
@d=array.uniq
|
29
|
-
@i=
|
109
|
+
@i=Rubyvis.numerate(@d)
|
30
110
|
return self
|
31
111
|
end
|
32
112
|
@d
|
33
113
|
end
|
34
|
-
|
114
|
+
|
115
|
+
# Sets the range from the given continuous interval. The interval [<i>
|
116
|
+
# min</i>, <i>max</i>] is subdivided into <i>n</i> equispaced bands,
|
117
|
+
# where <i>n</i> is the number of (unique) values in the domain. The first
|
118
|
+
# and last band are offset from the edge of the range by the distance between
|
119
|
+
# bands.
|
120
|
+
#
|
121
|
+
# <p>The band width argument, <tt>band</tt>, is typically in the range [0, 1]
|
122
|
+
# and defaults to 1. This fraction corresponds to the amount of space in the
|
123
|
+
# range to allocate to the bands, as opposed to padding. A value of 0.5 means
|
124
|
+
# that the band width will be equal to the padding width. The computed
|
125
|
+
# absolute band width can be retrieved from the range as
|
126
|
+
# <tt>scale.range_band</tt>.
|
127
|
+
#
|
128
|
+
# <p>If the band width argument is negative, this method will allocate bands
|
129
|
+
# of a <i>fixed</i> width <tt>-band</tt>, rather than a relative fraction of
|
130
|
+
# the available space.
|
131
|
+
#
|
132
|
+
# <p>Tip: to inset the bands by a fixed amount <tt>p</tt>, specify a minimum
|
133
|
+
# value of <tt>min + p</tt> (or simply <tt>p</tt>, if <tt>min</tt> is
|
134
|
+
# 0). Then set the mark width to <tt>scale.range_band - p</tt>.
|
135
|
+
#
|
136
|
+
# <p>This method must be called <i>after</i> the domain is set.
|
137
|
+
|
138
|
+
def split_banded(*arguments) # :args: (min,max,band=1)
|
35
139
|
min,max,band=arguments
|
36
140
|
band=1 if (arguments.size < 3)
|
37
141
|
if (band < 0)
|
@@ -40,11 +144,11 @@ module Rubyvis
|
|
40
144
|
total = -band * n
|
41
145
|
remaining = max - min - total
|
42
146
|
padding = remaining / (n + 1).to_f
|
43
|
-
@r =
|
147
|
+
@r = Rubyvis.range(min + padding, max, padding - band);
|
44
148
|
@range_band = -band;
|
45
149
|
else
|
46
150
|
step = (max - min) / (self.domain().size + (1 - band))
|
47
|
-
@r =
|
151
|
+
@r = Rubyvis.range(min + step * (1 - band), max, step);
|
48
152
|
@range_band = step * band;
|
49
153
|
end
|
50
154
|
return self
|
@@ -54,15 +158,23 @@ module Rubyvis
|
|
54
158
|
if(arguments.size>0)
|
55
159
|
@r=(array.is_a? Array) ? ((arguments.size>1) ? array.map(&f) : array) : arguments.dup
|
56
160
|
if @r[0].is_a? String
|
57
|
-
@r=@r.map {|i|
|
161
|
+
@r=@r.map {|i| Rubyvis.color(i)}
|
58
162
|
end
|
59
163
|
return self
|
60
164
|
end
|
61
165
|
@r
|
62
166
|
end
|
167
|
+
|
168
|
+
# Sets the range from the given continuous interval. The interval [<i>
|
169
|
+
# min</i>, <i>max</i>] is subdivided into <i>n</i> equispaced points,
|
170
|
+
# where <i>n</i> is the number of (unique) values in the domain. The first
|
171
|
+
# and last point are offset from the edge of the range by half the distance
|
172
|
+
# between points.
|
173
|
+
#
|
174
|
+
# <p>This method must be called <i>after</i> the domain is set.
|
63
175
|
def split(min,max)
|
64
176
|
step=(max-min).quo(domain().size)
|
65
|
-
@r=
|
177
|
+
@r=Rubyvis.range(min+step.quo(2),max,step)
|
66
178
|
self
|
67
179
|
end
|
68
180
|
def by(f)
|
@@ -1,7 +1,61 @@
|
|
1
1
|
module Rubyvis
|
2
|
+
# Represents an abstract quantitative scale; a function that performs a
|
3
|
+
# numeric transformation. This class is typically not used directly; see one of
|
4
|
+
# the quantitative scale implementations (linear, log, root, etc.)
|
5
|
+
# instead. <style type="text/css">sub{line-height:0}</style> A quantitative
|
6
|
+
# scale represents a 1-dimensional transformation from a numeric domain of
|
7
|
+
# input data [<i>d<sub>0</sub></i>, <i>d<sub>1</sub></i>] to a numeric range of
|
8
|
+
# pixels [<i>r<sub>0</sub></i>, <i>r<sub>1</sub></i>]. In addition to
|
9
|
+
# readability, scales offer several useful features:
|
10
|
+
#
|
11
|
+
# <p>1. The range can be expressed in colors, rather than pixels. For example:
|
12
|
+
#
|
13
|
+
# .fill_style(Scale.linear(0, 100).range("red", "green"))
|
14
|
+
#
|
15
|
+
# will fill the marks "red" on an input value of 0, "green" on an input value
|
16
|
+
# of 100, and some color in-between for intermediate values.
|
17
|
+
#
|
18
|
+
# <p>2. The domain and range can be subdivided for a non-uniform
|
19
|
+
# transformation. For example, you may want a diverging color scale that is
|
20
|
+
# increasingly red for negative values, and increasingly green for positive
|
21
|
+
# values:
|
22
|
+
#
|
23
|
+
# .fill_style(Scale.linear(-1, 0, 1).range("red", "white", "green"))</pre>
|
24
|
+
#
|
25
|
+
# The domain can be specified as a series of <i>n</i> monotonically-increasing
|
26
|
+
# values; the range must also be specified as <i>n</i> values, resulting in
|
27
|
+
# <i>n - 1</i> contiguous linear scales.
|
28
|
+
#
|
29
|
+
# <p>3. Quantitative scales can be inverted for interaction. The
|
30
|
+
# invert() method takes a value in the output range, and returns the
|
31
|
+
# corresponding value in the input domain. This is frequently used to convert
|
32
|
+
# the mouse location (see Mark#mouse) to a value in the input
|
33
|
+
# domain. Note that inversion is only supported for numeric ranges, and not
|
34
|
+
# colors.
|
35
|
+
#
|
36
|
+
# <p>4. A scale can be queried for reasonable "tick" values. The ticks()
|
37
|
+
# method provides a convenient way to get a series of evenly-spaced rounded
|
38
|
+
# values in the input domain. Frequently these are used in conjunction with
|
39
|
+
# Rule to display tick marks or grid lines.
|
40
|
+
#
|
41
|
+
# <p>5. A scale can be "niced" to extend the domain to suitable rounded
|
42
|
+
# numbers. If the minimum and maximum of the domain are messy because they are
|
43
|
+
# derived from data, you can use nice() to round these values down and
|
44
|
+
# up to even numbers.
|
45
|
+
#
|
46
|
+
# @see Scale.linear
|
47
|
+
# @see Scale.log
|
48
|
+
# @see Scale.root
|
2
49
|
class Scale::Quantitative
|
3
50
|
include Rubyvis::Scale
|
4
51
|
attr_reader :l
|
52
|
+
# Returns a default quantitative, linear, scale for the specified domain. The
|
53
|
+
# arguments to this constructor are optional, and equivalent to calling
|
54
|
+
# domain. The default domain and range are [0,1].
|
55
|
+
#
|
56
|
+
# This constructor is typically not used directly; see one of the
|
57
|
+
# quantitative scale implementations instead.
|
58
|
+
# @param {number...} domain... optional domain values.
|
5
59
|
def initialize(*args)
|
6
60
|
@d=[0,1] # domain
|
7
61
|
@l=[0,1] # transformed domain
|
@@ -20,13 +74,23 @@ module Rubyvis
|
|
20
74
|
}
|
21
75
|
domain(*args)
|
22
76
|
end
|
23
|
-
|
77
|
+
|
78
|
+
# Deprecated
|
79
|
+
def new_date(x=nil) # :nodoc:
|
24
80
|
x.nil? ? Time.new() : Time.at(x)
|
25
81
|
end
|
82
|
+
# Return
|
83
|
+
# lambda {|d| scale_object.scale(d)}
|
84
|
+
# Useful as value on dynamic properties
|
85
|
+
# scale=Rubyvis.linear(0,1000)
|
86
|
+
# bar.width(scale)
|
87
|
+
# is the same as
|
88
|
+
# bar.width(lambda {|x| scale.scale(x)})
|
26
89
|
def to_proc
|
27
90
|
that=self
|
28
91
|
lambda {|*args| args[0] ? that.scale(args[0]) : nil }
|
29
92
|
end
|
93
|
+
# Transform value +x+ according to domain and range
|
30
94
|
def scale(x)
|
31
95
|
x=x.to_f
|
32
96
|
j=Rubyvis.search(@d, x)
|
@@ -37,6 +101,7 @@ module Rubyvis
|
|
37
101
|
# puts "Segundo #{(@l[j + 1] - @l[j])}"
|
38
102
|
@i[j].call((@f.call(x) - @l[j]) .quo(@l[j + 1] - @l[j]));
|
39
103
|
end
|
104
|
+
# Alias for scale(x)
|
40
105
|
def [](x)
|
41
106
|
scale(x)
|
42
107
|
end
|
@@ -46,14 +111,51 @@ module Rubyvis
|
|
46
111
|
@l=@d.map{|v| @f.call(v)}
|
47
112
|
self
|
48
113
|
end
|
49
|
-
|
50
|
-
|
114
|
+
private :transform
|
115
|
+
# Sets or gets the input domain. This method can be invoked several ways:
|
116
|
+
#
|
117
|
+
# <p>1. <tt>domain(min, ..., max)</tt>
|
118
|
+
#
|
119
|
+
# <p>Specifying the domain as a series of numbers is the most explicit and
|
120
|
+
# recommended approach. Most commonly, two numbers are specified: the minimum
|
121
|
+
# and maximum value. However, for a diverging scale, or other subdivided
|
122
|
+
# non-uniform scales, multiple values can be specified. Values can be derived
|
123
|
+
# from data using Rubyvis.min and Rubyvis.max. For example:
|
124
|
+
#
|
125
|
+
# .domain(0, Rubyvis.max(array))
|
126
|
+
#
|
127
|
+
# An alternative method for deriving minimum and maximum values from data
|
128
|
+
# follows.
|
129
|
+
#
|
130
|
+
# <p>2. <tt>domain(array, minf, maxf)</tt>
|
131
|
+
#
|
132
|
+
# <p>When both the minimum and maximum value are derived from data, the
|
133
|
+
# arguments to the <tt>domain</tt> method can be specified as the array of
|
134
|
+
# data, followed by zero, one or two accessor functions. For example, if the
|
135
|
+
# array of data is just an array of numbers:
|
136
|
+
#
|
137
|
+
# .domain(array)
|
138
|
+
#
|
139
|
+
# On the other hand, if the array elements are objects representing stock
|
140
|
+
# values per day, and the domain should consider the stock's daily low and
|
141
|
+
# daily high:
|
142
|
+
#
|
143
|
+
# .domain(array, lambda {|d| d.low}, lambda {|d| d.high})
|
144
|
+
#
|
145
|
+
# The first method of setting the domain is preferred because it is more
|
146
|
+
# explicit; setting the domain using this second method should be used only
|
147
|
+
# if brevity is required.
|
148
|
+
#
|
149
|
+
# <p>3. <tt>domain()</tt>
|
150
|
+
#
|
151
|
+
# <p>Invoking the <tt>domain</tt> method with no arguments returns the
|
152
|
+
# current domain as an array of numbers.
|
51
153
|
def domain(*arguments)
|
52
154
|
array,min,max=arguments
|
53
155
|
o=nil
|
54
156
|
if (arguments.size>0)
|
55
157
|
if array.is_a? Array
|
56
|
-
min =
|
158
|
+
min = Rubyvis.identity if (arguments.size < 2)
|
57
159
|
max = min if (arguments.size < 3)
|
58
160
|
o = [array[0]].min if array.size>0
|
59
161
|
@d = array.size>0 ? [Rubyvis.min(array, min), Rubyvis.max(array, max)] : []
|
@@ -87,7 +189,29 @@ module Rubyvis
|
|
87
189
|
}
|
88
190
|
end
|
89
191
|
|
90
|
-
|
192
|
+
# Sets or gets the output range. This method can be invoked several ways:
|
193
|
+
#
|
194
|
+
# <p>1. <tt>range(min, ..., max)</tt>
|
195
|
+
#
|
196
|
+
# <p>The range may be specified as a series of numbers or colors. Most
|
197
|
+
# commonly, two numbers are specified: the minimum and maximum pixel values.
|
198
|
+
# For a color scale, values may be specified as {@link Rubyvis.Color}s or
|
199
|
+
# equivalent strings. For a diverging scale, or other subdivided non-uniform
|
200
|
+
# scales, multiple values can be specified. For example:
|
201
|
+
#
|
202
|
+
# .range("red", "white", "green")
|
203
|
+
#
|
204
|
+
# <p>Currently, only numbers and colors are supported as range values. The
|
205
|
+
# number of range values must exactly match the number of domain values, or
|
206
|
+
# the behavior of the scale is undefined.
|
207
|
+
#
|
208
|
+
# <p>2. <tt>range()</tt>
|
209
|
+
#
|
210
|
+
# <p>Invoking the <tt>range</tt> method with no arguments returns the current
|
211
|
+
# range as an array of numbers or colors.
|
212
|
+
# :call-seq:
|
213
|
+
# range(min,...,max)
|
214
|
+
# range()
|
91
215
|
def range(*arguments)
|
92
216
|
if (arguments.size>0)
|
93
217
|
@r = arguments.dup
|
@@ -122,7 +246,7 @@ module Rubyvis
|
|
122
246
|
raise "Not implemented yet"
|
123
247
|
end
|
124
248
|
end
|
125
|
-
def ticks_floor(d,prec)
|
249
|
+
def ticks_floor(d,prec) # :nodoc:
|
126
250
|
ar=d.to_a
|
127
251
|
#p ar
|
128
252
|
# [ sec, min, hour, day, month, year, wday, yday, isdst, zone ]
|
@@ -145,12 +269,19 @@ module Rubyvis
|
|
145
269
|
to_date(ar)
|
146
270
|
end
|
147
271
|
|
148
|
-
|
272
|
+
private :ticks_floor
|
273
|
+
|
274
|
+
def to_date(d) # :nodoc:
|
149
275
|
|
150
276
|
Time.utc(*d)
|
151
277
|
end
|
152
|
-
#
|
153
|
-
|
278
|
+
# Returns an array of evenly-spaced, suitably-rounded values in the input
|
279
|
+
# domain. This method attempts to return between 5 and 10 tick values. These
|
280
|
+
# values are frequently used in conjunction with Rule to display
|
281
|
+
# tick marks or grid lines.
|
282
|
+
#
|
283
|
+
# @todo: fix for dates and n>10
|
284
|
+
def ticks(*arguments) # :args: (number_of_ticks=nil)
|
154
285
|
m = arguments[0]
|
155
286
|
start = @d.first
|
156
287
|
_end = @d.last
|
@@ -163,7 +294,7 @@ module Rubyvis
|
|
163
294
|
@tick_format= Rubyvis.Format.date("%x") if (@type == newDate)
|
164
295
|
return [type(min)];
|
165
296
|
end
|
166
|
-
|
297
|
+
|
167
298
|
#/* Special case: dates. */
|
168
299
|
if (@type == :time)
|
169
300
|
#/* Floor the date d given the precision p. */
|
@@ -202,12 +333,13 @@ module Rubyvis
|
|
202
333
|
increment = lambda {|d| Time.at(d.to_f+(step/1000.0)) }
|
203
334
|
end
|
204
335
|
|
205
|
-
@tick_format =
|
336
|
+
@tick_format = Rubyvis.Format.date(format);
|
206
337
|
date = Time.at(min.to_f)
|
207
338
|
dates = []
|
208
339
|
date = ticks_floor(date,precision)
|
209
340
|
# If we'd generate too many ticks, skip some!.
|
210
341
|
n = span / (precision/1000.0)
|
342
|
+
# FIX FROM HERE
|
211
343
|
if (n > 10)
|
212
344
|
case (precision)
|
213
345
|
when 36e5
|
@@ -228,7 +360,7 @@ module Rubyvis
|
|
228
360
|
step = (n > 1000) ? 250 : ((n > 200) ? 100 : ((n > 100) ? 50 : ((n > 50) ? 25 : 5)));
|
229
361
|
date.setMilliseconds(Math.floor(date.getMilliseconds() / step) * step);
|
230
362
|
else
|
231
|
-
step =
|
363
|
+
step = Rubyvis.logCeil(n / 15, 10);
|
232
364
|
if (n / step < 2)
|
233
365
|
step =step.quo(5)
|
234
366
|
elsif (n / step < 5)
|
@@ -249,7 +381,7 @@ module Rubyvis
|
|
249
381
|
# Normal case: numbers.
|
250
382
|
m = 10 if (arguments.size==0)
|
251
383
|
|
252
|
-
step =
|
384
|
+
step = Rubyvis.log_floor(span.quo(m), 10)
|
253
385
|
err = m.quo(span.quo(step))
|
254
386
|
if (err <= 0.15)
|
255
387
|
step = step*10
|
@@ -260,15 +392,27 @@ module Rubyvis
|
|
260
392
|
end
|
261
393
|
start = (min.quo(step)).ceil * step
|
262
394
|
_end = (max.quo(step)).floor * step
|
263
|
-
@tick_format=
|
264
|
-
ticks =
|
395
|
+
@tick_format= Rubyvis.Format.number.fraction_digits([0, -(Rubyvis.log(step, 10) + 0.01).floor].max)
|
396
|
+
ticks = Rubyvis.range(start, _end + step, step);
|
265
397
|
return reverse ? ticks.reverse() : ticks;
|
266
398
|
end
|
267
399
|
|
400
|
+
# Returns a Proc that formats the specified tick value using the appropriate precision, based on
|
401
|
+
# the step interval between tick marks. If ticks() has not been called,
|
402
|
+
# the argument is converted to a string, but no formatting is applied.
|
403
|
+
# scale.tick_format.call(value)
|
404
|
+
#
|
268
405
|
def tick_format
|
269
406
|
@tick_format
|
270
407
|
end
|
271
408
|
|
409
|
+
# "Nices" this scale, extending the bounds of the input domain to
|
410
|
+
# evenly-rounded values. Nicing is useful if the domain is computed
|
411
|
+
# dynamically from data, and may be irregular. For example, given a domain of
|
412
|
+
# [0.20147987687960267, 0.996679553296417], a call to <tt>nice()</tt> might
|
413
|
+
# extend the domain to [0.2, 1].
|
414
|
+
#
|
415
|
+
# This method must be invoked each time after setting the domain.
|
272
416
|
def nice
|
273
417
|
if (@d.size!=2)
|
274
418
|
return self;
|
data/lib/rubyvis/scale.rb
CHANGED
@@ -24,7 +24,7 @@ module Rubyvis
|
|
24
24
|
return lambda {|t|
|
25
25
|
a=start.a*(1-t)+_end.a*t
|
26
26
|
a=0 if a<1e-5
|
27
|
-
return (start.a == 0) ? Rubyvis.rgb(_end.r, _end.g, _end.b, a) : ((_end.a == 0) ?
|
27
|
+
return (start.a == 0) ? Rubyvis.rgb(_end.r, _end.g, _end.b, a) : ((_end.a == 0) ? Rubyvis.rgb(start.r, start.g, start.b, a) : Rubyvis.rgb(
|
28
28
|
(start.r * (1 - t) + _end.r * t).round,
|
29
29
|
(start.g * (1 - t) + _end.g * t).round,
|
30
30
|
(start.b * (1 - t) + _end.b * t).round, a))
|
@@ -64,14 +64,14 @@ module Rubyvis
|
|
64
64
|
}
|
65
65
|
|
66
66
|
if (s.interpolate == "basis")
|
67
|
-
pathT =
|
68
|
-
pathB =
|
67
|
+
pathT = Rubyvis.SvgScene.curve_basis(pointsT);
|
68
|
+
pathB = Rubyvis.SvgScene.curve_basis(pointsB);
|
69
69
|
elsif (s.interpolate == "cardinal")
|
70
|
-
pathT =
|
71
|
-
pathB =
|
70
|
+
pathT = Rubyvis.SvgScene.curve_cardinal(pointsT, s.tension);
|
71
|
+
pathB = Rubyvis.SvgScene.curve_cardinal(pointsB, s.tension);
|
72
72
|
elsif # monotone
|
73
|
-
pathT =
|
74
|
-
pathB =
|
73
|
+
pathT = Rubyvis.SvgScene.curve_monotone(pointsT);
|
74
|
+
pathB = Rubyvis.SvgScene.curve_monotone(pointsB);
|
75
75
|
end
|
76
76
|
|
77
77
|
"#{pointsT[0].left },#{ pointsT[0].top }#{ pathT }L#{ pointsB[0].left},#{pointsB[0].top}#{pathB}"
|
@@ -132,14 +132,14 @@ module Rubyvis
|
|
132
132
|
}
|
133
133
|
|
134
134
|
if (s.interpolate == "basis")
|
135
|
-
pathT =
|
136
|
-
pathB =
|
135
|
+
pathT = Rubyvis.SvgScene.curve_basis_segments(pointsT);
|
136
|
+
pathB = Rubyvis.SvgScene.curve_basis_segments(pointsB);
|
137
137
|
elsif (s.interpolate == "cardinal")
|
138
|
-
pathT =
|
139
|
-
pathB =
|
138
|
+
pathT = Rubyvis.SvgScene.curve_cardinal_segments(pointsT, s.tension);
|
139
|
+
pathB = Rubyvis.SvgScene.curve_cardinal_segments(pointsB, s.tension);
|
140
140
|
elsif # monotone
|
141
|
-
pathT =
|
142
|
-
pathB =
|
141
|
+
pathT = Rubyvis.SvgScene.curve_monotone_segments(pointsT);
|
142
|
+
pathB = Rubyvis.SvgScene.curve_monotone_segments(pointsB);
|
143
143
|
end
|
144
144
|
end
|
145
145
|
n=scenes.size-1
|
@@ -72,7 +72,7 @@ module Rubyvis
|
|
72
72
|
next if (!s1.visible and !s2.visible)
|
73
73
|
|
74
74
|
stroke = s1.stroke_style
|
75
|
-
fill =
|
75
|
+
fill = Rubyvis.Color.transparent
|
76
76
|
|
77
77
|
next if stroke.opacity==0.0
|
78
78
|
|
@@ -80,7 +80,7 @@ module Rubyvis
|
|
80
80
|
d=nil
|
81
81
|
if ((s1.interpolate == "linear") and (s1.lineJoin == "miter"))
|
82
82
|
fill = stroke;
|
83
|
-
stroke =
|
83
|
+
stroke = Rubyvis.Color.transparent;
|
84
84
|
d = path_join(scenes[i - 1], s1, s2, scenes[i + 2]);
|
85
85
|
elsif(paths)
|
86
86
|
d = paths[i];
|
@@ -142,9 +142,9 @@ module Rubyvis
|
|
142
142
|
# no joins).
|
143
143
|
#
|
144
144
|
|
145
|
-
p1 =
|
145
|
+
p1 = Rubyvis.vector(s1.left, s1.top)
|
146
146
|
|
147
|
-
p2 =
|
147
|
+
p2 = Rubyvis.vector(s2.left, s2.top)
|
148
148
|
|
149
149
|
p = p2.minus(p1)
|
150
150
|
|
@@ -172,7 +172,7 @@ module Rubyvis
|
|
172
172
|
|
173
173
|
#/* Similarly, for end join. */
|
174
174
|
if (s3 && s3.visible)
|
175
|
-
v2 =
|
175
|
+
v2 = Rubyvis.vector(s3.left, s3.top).minus(p2).perp().norm().plus(v);
|
176
176
|
c = line_intersect(p2, v2, c, p);
|
177
177
|
b = line_intersect(p2, v2, b, p);
|
178
178
|
end
|
@@ -110,7 +110,7 @@ module Rubyvis
|
|
110
110
|
"y"=> s.top,
|
111
111
|
"width"=> [1E-10, s.width].max,
|
112
112
|
"height"=>[1E-10, s.height].max,
|
113
|
-
"fill"=>
|
113
|
+
"fill"=>"none",
|
114
114
|
"stroke"=> stroke.color,
|
115
115
|
"stroke-opacity"=> stroke.opacity,
|
116
116
|
"stroke-width"=> s.line_width / self.scale.to_f
|