Class: Rubyvis::Nest

Inherits:
Object show all
Defined in:
lib/rubyvis/nest.rb

Overview

Represents a Nest operator for the specified array. Nesting allows elements in an array to be grouped into a hierarchical tree structure. The levels in the tree are specified by key functions. The leaf nodes of the tree can be sorted by value, while the internal nodes can be sorted by key. Finally, the tree can be returned either has a multidimensional array via Nest.entries, or as a hierarchical map via Nest.map. The Nest.rollup routine similarly returns a map, collapsing the elements in each leaf node using a summary function.

For example, consider the following tabular data structure of Barley yields, from various sites in Minnesota during 1931-2:

{ yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm" },
{ yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca" },
{ yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris" }

To facilitate visualization, it may be useful to nest the elements first by year, and then by variety, as follows:

var nest = Rubyvis.nest(yields)
.key(lambda {|d|  d.year})
.key(lambda {|d| d.variety})
.entries();

This returns a nested array. Each element of the outer array is a key-values pair, listing the values for each distinct key:

<pre>{ key: 1931, values: [

{ key: "Manchuria", values: [
    { yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm" },
    { yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca" },
    { yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris" },
    ...
  ] },
{ key: "Glabron", values: [
    { yield: 43.07, variety: "Glabron", year: 1931, site: "University Farm" },
    { yield: 55.20, variety: "Glabron", year: 1931, site: "Waseca" },
    ...
  ] },
] },

{ key: 1932, values: … }</pre>

Further details, including sorting and rollup, is provided below on the corresponding methods.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(array) ⇒ Nest

Constructs a nest operator for the specified array. This constructor should not be invoked directly; use Rubyvis.nest instead.



76
77
78
79
80
# File 'lib/rubyvis/nest.rb', line 76

def initialize(array)
  @array=array
  @keys=[]
  @order=nil
end

Instance Attribute Details

#arrayObject

Returns the value of attribute array.



71
72
73
# File 'lib/rubyvis/nest.rb', line 71

def array
  @array
end

#keysObject

Returns the value of attribute keys.



71
72
73
# File 'lib/rubyvis/nest.rb', line 71

def keys
  @keys
end

#orderObject

Returns the value of attribute order.



71
72
73
# File 'lib/rubyvis/nest.rb', line 71

def order
  @order
end

Instance Method Details

#entriesObject

Returns a hierarchical nested array. This method is similar to pv.entries, but works recursively on the entire hierarchy. Rather than returning a map like #map, this method returns a nested array. Each element of the array has a key and values field. For leaf nodes, the values array will be a subset of the underlying elements array; for non-leaf nodes, the values array will contain more key-values pairs.

<p>For an example usage, see the Nest constructor.



148
149
150
# File 'lib/rubyvis/nest.rb', line 148

def entries()
  entries_sort(entries_entries(map),0)
end

#entries_entries(map) ⇒ Object



151
152
153
154
155
156
157
# File 'lib/rubyvis/nest.rb', line 151

def entries_entries(map)
  array=[]
  map.each_pair {|k,v|
    array.push(NestedArray.new({:key=>k, :values=>(v.is_a? Array) ? v: entries_entries(v)}))
  }
  array
end

#entries_sort(array, i) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/rubyvis/nest.rb', line 158

def entries_sort(array,i)
  o=keys[i].order
  if o
    array.sort! {|a,b| o.call(a.key, b.key)}
  end
  i+=1
  if (i<keys.size)
    array.each {|v|
      entries_sort(v, i)
    }
  end
  array
  
end

#key(k) ⇒ Object



81
82
83
84
# File 'lib/rubyvis/nest.rb', line 81

def key(k)
  @keys.push(k)
  return self
end

#mapObject

Returns a hierarchical map of values. Each key adds one level to the hierarchy. With only a single key, the returned map will have a key for each distinct value of the key function; the correspond value with be an array of elements with that key value. If a second key is added, this will be a nested map. For example:

<pre>Rubyvis.nest(yields)

.key(function(d) d.variety)
.key(function(d) d.site)
.map()</pre>

returns a map m such that m[variety][site] is an array, a subset of yields, with each element having the given variety and site.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/rubyvis/nest.rb', line 109

def map
  #i=0
  map={} 
  values=[]
  @array.each_with_index {|x,j|
    m=map
    (@keys.size-1).times {|i|
      k=@keys[i].call(x)
      m[k]={} if (!m[k])
      m=m[k]
    }
    k=@keys.last.call(x)
    if(!m[k])
      a=[]
      values.push(a)
      m[k]=a
    end
    m[k].push(x)
  }
  if(self.order)
    values.each_with_index {|v,vi|
      values[vi].sort!(&self.order)
    }
  end
  map
end

#rollup(f) ⇒ Object



199
200
201
# File 'lib/rubyvis/nest.rb', line 199

def rollup(f)
  rollup_rollup(self.map, f)
end

#rollup_rollup(map, f) ⇒ Object



172
173
174
175
176
177
178
179
180
181
# File 'lib/rubyvis/nest.rb', line 172

def rollup_rollup(map,f)
  map.each_pair {|key,value|
    if value.is_a? Array
      map[key]=f.call(value)
    else
      rollup_rollup(value,f)
    end
  }
  return map;
end

#sort_keys(order = nil) ⇒ Object



85
86
87
88
# File 'lib/rubyvis/nest.rb', line 85

def sort_keys(order=nil)
  keys[keys.size-1].order = order.nil? ? Rubyvis.natural_order : order
  return self
end

#sort_values(order = nil) ⇒ Object



89
90
91
92
# File 'lib/rubyvis/nest.rb', line 89

def sort_values(order=nil)
  @order = order.nil? ? Rubyvis.natural_order : order
  return self
end