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.

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

{ 1931: {
    Manchuria: {
      "University Farm": 27.00,
      "Waseca": 48.87,
      "Morris": 27.43,
      ... },
    Glabron: {
      "University Farm": 43.07,
      "Waseca": 55.20,
      ... } },
  1932: {
    ... } }

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

var array = pv.flatten(yields)
    .key("year")
    .key("variety")
    .key("site")
    .key("yield")
    .array();

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

{ 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 }, ...

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