Class: Rubyvis::Flatten

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

Overview

Represents a flatten operator for the specified array. Flattening allows hierarchical maps to be flattened into an array. The levels in the input tree are specified by key functions.

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

<pre>{ 1931: {

  Manchuria: {
    "University Farm": 27.00,
    "Waseca": 48.87,
    "Morris": 27.43,
    ... },
  Glabron: {
    "University Farm": 43.07,
    "Waseca": 55.20,
    ... } },
1932: {
  ... } }</pre>

To facilitate visualization, it may be useful to flatten the tree into a tabular array:

<pre>var array = pv.flatten(yields)

.key("year")
.key("variety")
.key("site")
.key("yield")
.array();</pre>

This returns an array of object elements. Each element in the array has attributes corresponding to this flatten operator's keys:

<pre>{ site: “University Farm”, variety: “Manchuria”, year: 1931, yield: 27 }, { site: “Waseca”, variety: “Manchuria”, year: 1931, yield: 48.87 }, { site: “Morris”, variety: “Manchuria”, year: 1931, yield: 27.43 }, { site: “University Farm”, variety: “Glabron”, year: 1931, yield: 43.07 }, { site: “Waseca”, variety: “Glabron”, year: 1931, yield: 55.2 }, …</pre>

<p>The flatten operator is roughly the inverse of the pv.Nest and pv.Tree operators.

Instance Method Summary collapse

Constructor Details

#initialize(map) ⇒ Flatten

Returns a new instance of Flatten.


50
51
52
53
54
# File 'lib/rubyvis/flatten.rb', line 50

def initialize(map)
  @map=map
  @keys=[]
  @leaf=nil
end

Instance Method Details

#arrayObject Also known as: to_a

Returns the flattened array. Each entry in the array is an object; each object has attributes corresponding to this flatten operator's keys.


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/rubyvis/flatten.rb', line 107

def array
  @entries=[]
  @stack=[]
  if @leaf
    recurse(@map,0)
    return @entries
  end
  visit(@map,0)
  @entries.map {|stack|
    m={}
    @keys.each_with_index {|k,i|
      v=stack[i]
      m[k.name]=k.value ? k.value.js_call(self,v) : v
    }
    m
  }
end

#key(k, f = nil) ⇒ Object

Flattens using the specified key function. Multiple keys may be added to the flatten; the tiers of the underlying tree must correspond to the specified keys, in order. The order of the returned array is undefined; however, you can easily sort it.

Parameters:

  • key (string)

    the key name.

  • [f] (function)

    an optional value map function.


64
65
66
67
68
# File 'lib/rubyvis/flatten.rb', line 64

def key(k, f=nil)
  @keys.push(OpenStruct.new({:name=>k, :value=>f}))
  @leaf=nil
  self
end

#leaf(f) ⇒ Object

Flattens using the specified leaf function. This is an alternative to specifying an explicit set of keys; the tiers of the underlying tree will be determined dynamically by recursing on the values, and the resulting keys will be stored in the entries :keys attribute. The leaf function must return true for leaves, and false for internal nodes.

Parameters:

  • f (function)

    a leaf function.


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

def leaf(f)
  @keys.clear
  @leaf=f
  self
end

#recurse(value, i) ⇒ Object


81
82
83
84
85
86
87
88
89
90
91
# File 'lib/rubyvis/flatten.rb', line 81

def recurse(value,i)
  if @leaf.call(value)
    @entries.push({:keys=>@stack.dup, :value=>value})
  else
    value.each {|key,v|
      @stack.push(key)
      recurse(v, i+1)
      @stack.pop
    }
  end
end

#visit(value, i) ⇒ Object


92
93
94
95
96
97
98
99
100
101
102
# File 'lib/rubyvis/flatten.rb', line 92

def visit(value,i)
  if (i < @keys.size - 1)
    value.each {|key,v|
      @stack.push(key)
      visit(v,i+1)
      @stack.pop
    }
  else 
    @entries.push(@stack+[value])
  end
end