Method: Statsample::Graph::Boxplot#rubyvis_panel

Defined in:
lib/statsample/graph/boxplot.rb

#rubyvis_panelObject

Returns a Rubyvis panel with scatterplot

[View source] [View on GitHub]

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/statsample/graph/boxplot.rb', line 80

def rubyvis_panel # :nodoc:
  that=self
  
  min,max=@minimum, @maximum
  
  min||=@vectors.map {|v| v.min}.min
  max||=@vectors.map {|v| v.max}.max
  
  margin_hor=margin_left + margin_right
  margin_vert=margin_top  + margin_bottom
  x_scale = pv.Scale.ordinal(@vectors.size.times.map.to_a).split_banded(0, width-margin_hor, 4.0/5)
  y_scale=Rubyvis::Scale.linear(min,max).range(0,height-margin_vert)
  y_scale.nice
  # cache data
  
  colors=Rubyvis::Colors.category10
  
  data=@vectors.map {|v|
    out={:percentil_25=>v.percentil(25), :median=>v.median, :percentil_75=>v.percentil(75), :name=>v.name}
    out[:iqr]=out[:percentil_75] - out[:percentil_25]
    
    irq_max=out[:percentil_75] + out[:iqr]
    irq_min=out[:percentil_25] - out[:iqr]
    
    # Find the last data inside the margin
    min = out[:percentil_25]
    max = out[:percentil_75]
    
    v.each {|d|
      min=d if d < min and d > irq_min
      max=d if d > max and d < irq_max
    }
    # Whiskers!
    out[:low_whisker]=min
    out[:high_whisker]=max
    # And now, data outside whiskers
    out[:outliers]=v.to_a.find_all {|d| d < min or d > max }
    out
  }
         
  vis=Rubyvis::Panel.new do |pan| 
    pan.width  width  - margin_hor
    pan.height height - margin_vert
    pan.bottom margin_bottom
    pan.left   margin_left
    pan.right  margin_right
    pan.top    margin_top
     # Y axis
    pan.rule do
      data y_scale.ticks
      bottom y_scale
      stroke_style {|d| d!=0 ? "#eee" : "#000"}
      label(:anchor=>'left') do
        text y_scale.tick_format
      end
    end
    pan.rule do
      bottom 0
      stroke_style 'black'
    end
    
    # Labels
    
    pan.label  do |l|
      l.data data
      l.text_angle that.label_angle
      l.left  {|v| x_scale[index] }
      l.bottom(-15)
      l.text {|v,x| v[:name]}
    end
    
    pan.panel do |bp|
      bp.data data
      bp.left {|v|  x_scale[index]}
      bp.width x_scale.range_band
      
      # Bar
      bp.bar do |b|
        b.bottom {|v| y_scale[v[:percentil_25]]}
        b.height {|v| y_scale[v[:percentil_75]] - y_scale[v[:percentil_25]] }
        b.line_width 1
        b.stroke_style  {|v| 
          if that.groups
            colors.scale(that.groups[parent.index]).darker
          else
            colors.scale(index).darker
          end  
        }
        b.fill_style {|v| 
          if that.groups
            colors.scale(that.groups[parent.index])
          else
            colors.scale(index)
          end
        }
      end
      # Median
      bp.rule do |r|
        r.bottom {|v| y_scale[v[:median]]}
        r.width x_scale.range_band
        r.line_width 2
      end
      ##
      # Whiskeys
      ##
      # Low whiskey
      bp.rule do |r|
        r.visible {|v| v[:percentil_25] > v[:low_whisker]}
        r.bottom {|v| y_scale[v[:low_whisker]]}              
      end
      
      bp.rule do |r|
        r.visible {|v| v[:percentil_25] > v[:low_whisker]}
        r.bottom {|v| y_scale[v[:low_whisker]]}              
        r.left {|v| x_scale.range_band / 2.0}
        r.height {|v| y_scale.scale(v[:percentil_25]) - y_scale.scale(v[:low_whisker])}
      end
      # High whiskey

      bp.rule do |r|
        r.visible {|v| v[:percentil_75] < v[:high_whisker]}
        r.bottom {|v| y_scale.scale(v[:high_whisker])}              
      end
      
       bp.rule do |r|
        r.visible {|v| v[:percentil_75] < v[:high_whisker]}
        r.bottom {|v| y_scale.scale(v[:percentil_75])}              
        r.left {|v| x_scale.range_band / 2.0}
        r.height {|v| y_scale.scale(v[:high_whisker]) - y_scale.scale(v[:percentil_75])}
      end
      # Outliers
      bp.dot do |dot|
        dot.shape_size 4
        dot.data {|v| v[:outliers]}
        dot.left {|v| x_scale.range_band / 2.0}
        dot.bottom {|v| y_scale.scale(v)}
        dot.title {|v| v}
      end
    end
  end
  vis
end