Class: Rubyvis::Layout::Horizon

Inherits:
Rubyvis::Layout show all
Defined in:
lib/rubyvis/layout/horizon.rb

Overview

Implements a horizon layout, which is a variation of a single-series area chart where the area is folded into multiple bands. Color is used to encode band, allowing the size of the chart to be reduced significantly without impeding readability. This layout algorithm is based on the work of

  1. Heer, N. Kong and M. Agrawala in

the Horizon: The Effects of Chart Size and Layering on the Graphical Perception of Time Series Visualizations[hci.stanford.edu/publications/2009/heer-horizon-chi09.pdf], CHI 2009.

<p>This layout exports a single band mark prototype, which is intended to be used with an area mark. The band mark is contained in a panel which is replicated per band (and for negative/positive bands). For example, to create a simple horizon graph given an array of numbers:

vis.add(Rubyvis::Layout::Horizon)
  .bands(n)
.band.add(Rubyvis::Area)
  .data(data)
  .left(lambda { index * 35})
  .height(lambda {|d| d * 40})

The layout can be further customized by changing the number of bands, and toggling whether the negative bands are mirrored or offset. (See the above-referenced paper for guidance.)

<p>The fill_style of the area can be overridden, though typically it is easier to customize the layout's behavior through the custom background_style, positive_style and negative_style properties. By default, the background is white, positive bands are blue, and negative bands are red. For the most accurate presentation, use fully-opaque colors of equal intensity for the negative and positive bands.

Instance Attribute Summary collapse

Attributes inherited from Panel

#_canvas, #children, #root

Attributes inherited from Mark

#_properties, #binds, #child_index, #parent, #proto, #root, #scale, #scene, #target

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Rubyvis::Layout

Arc, Cluster, Grid, Hierarchy, Horizon, Indent, Matrix, Network, Pack, Partition, Stack, Tree, Treemap, attr_accessor_dsl, #build_properties, #layout_build_implied, #layout_build_properties

Methods inherited from Panel

#add, #anchor, #bind, #build_instance, #children_inspect, #panel_build_implied, #to_svg, #type

Methods inherited from Bar

#type, #width

Methods inherited from Mark

#add, #anchor, #area, attr_accessor_dsl, #bar, #bind, #build, #build_instance, #build_properties, #context, #context_apply, #context_clear, #cousin, #delete_index, #dot, #event, #execute, #first, #image, #index, index, #index=, index=, #index_defined?, #instance, #instances, #label, #last, #layout_arc, #layout_cluster, #layout_grid, #layout_horizon, #layout_indent, #layout_matrix, #layout_pack, #layout_partition, #layout_partition_fill, #layout_stack, #layout_tree, #layout_treemap, #line, #margin, #mark_anchor, #mark_bind, #mark_build_implied, #mark_build_instance, #mark_build_properties, #mark_extend, mark_method, #panel, #properties, properties, property_method, #property_value, #render, #rule, scene, scene=, #sibling, stack, stack=, #type, #wedge

Constructor Details

#initializeHorizon

Returns a new instance of Horizon.


44
45
46
47
48
49
50
51
52
53
54
# File 'lib/rubyvis/layout/horizon.rb', line 44

def initialize
  super
  @_bands=nil
  @_mode=nil # cached mode
  @_size=nil # cached height
  @_fill=nil # cached background style
  @_red=nil # cached negative color (ramp)
  @_blue=nil # cached positive color (ramp)
  @_bands_panel=_bands_panel
  @band=_band
end

Instance Attribute Details

#_bandsObject

Returns the value of attribute _bands


43
44
45
# File 'lib/rubyvis/layout/horizon.rb', line 43

def _bands
  @_bands
end

#_blueObject

Returns the value of attribute _blue


43
44
45
# File 'lib/rubyvis/layout/horizon.rb', line 43

def _blue
  @_blue
end

#_fillObject

Returns the value of attribute _fill


43
44
45
# File 'lib/rubyvis/layout/horizon.rb', line 43

def _fill
  @_fill
end

#_modeObject

Returns the value of attribute _mode


43
44
45
# File 'lib/rubyvis/layout/horizon.rb', line 43

def _mode
  @_mode
end

#_redObject

Returns the value of attribute _red


43
44
45
# File 'lib/rubyvis/layout/horizon.rb', line 43

def _red
  @_red
end

#_sizeObject

Returns the value of attribute _size


43
44
45
# File 'lib/rubyvis/layout/horizon.rb', line 43

def _size
  @_size
end

#bandObject

The band prototype. This prototype is intended to be used with an Area mark to render the horizon bands.


42
43
44
# File 'lib/rubyvis/layout/horizon.rb', line 42

def band
  @band
end

Class Method Details

.defaultsObject

Default properties for horizon layouts. By default, there are two bands, the mode is “offset”, the background style is “white”, the positive style is blue, negative style is red.


142
143
144
145
146
147
148
149
# File 'lib/rubyvis/layout/horizon.rb', line 142

def self.defaults
  Horizon.new.mark_extend(Layout.defaults).
    bands(2).
    mode('offset').
    background_style('white').
    positive_style('#1f77b4').
    negative_style('#d62728')
end

Instance Method Details

#_bandObject


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/rubyvis/layout/horizon.rb', line 75

def _band
  that=self
  m=Rubyvis::Mark.new().
  top(lambda  {|d,i|
    (that._mode == "mirror" and (i & 1)!=0) ? (i + 1 >> 1) * that._size : nil
  }).
  bottom(lambda {|d,i|
      crit= (i & 1)!= 0 ? i & 1 : -1
    (that._mode == "mirror") ? ((i & 1)!=0 ? nil : (i + 1 >> 1) * -that._size) : (crit * (i + 1 >> 1) * that._size)
  }).
  fill_style(lambda {|d,i|
      ((i & 1)!=0 ? that._red : that._blue).scale((i >> 1) + 1)
  })
  
  class << m # :nodoc:
    def that_and_bands(that,bands)
      @that = that
      @bands=bands
    end
    def add(type)
      bands=@bands
      that = @that
      that.add( Rubyvis.Panel ).mark_extend(bands). add(type). mark_extend(self)
    end
  end
  
  m.that_and_bands(self, @_bands_panel)
  m
end

#_bands_panelObject


65
66
67
68
69
70
71
72
73
# File 'lib/rubyvis/layout/horizon.rb', line 65

def _bands_panel
  that=self
  Rubyvis::Panel.new().
    data(lambda {Rubyvis.range(that._bands.to_f * 2)}).
    overflow("hidden").
    height(lambda {that._size}).
    top(lambda {|i| that._mode=='color' ? (i & 1) * that._size : 0 }).
    fill_style(lambda {|i| i!=0 ? nil : that._fill})
end

#bandsObject

:attr: background_style The background color. The panel background is filled with the specified color, and the negative and positive bands are filled with an interpolated color between this color and the respective band color. The default value of this property is white. For accurate blending, this color should be fully opaque.


137
# File 'lib/rubyvis/layout/horizon.rb', line 137

attr_accessor_dsl :bands, :mode, :background_style, [:background_style, lambda {|d| Rubyvis.color(d)}], [:positive_style, lambda {|d| Rubyvis.color(d)}], [:negative_style, lambda {|d| Rubyvis.color(d)}]

#build_implied(s) ⇒ Object


55
56
57
58
59
60
61
62
63
64
# File 'lib/rubyvis/layout/horizon.rb', line 55

def build_implied(s)
  layout_build_implied(s) 
  @_bands=s.bands
  @_mode=s.mode
  @_size=((@_mode == "color" ? 0.5 : 1) * s.height).round
  @_fill=s.background_style
  @_red=Rubyvis.ramp(@_fill, s.negative_style).domain(0,@_bands)
  @_blue=Rubyvis.ramp(@_fill, s.positive_style).domain(0,@_bands)
  
end