class Charma::ViolinChart

Public Class Methods

new(opts) click to toggle source
Calls superclass method Charma::Chart::new
# File lib/charma/violin_chart.rb, line 5
def initialize(opts)
  super(opts)
end

Public Instance Methods

calc_range(sym) click to toggle source

TODO: LineChart に同じようなメソッドがあるのでなんとかする

# File lib/charma/violin_chart.rb, line 10
def calc_range(sym)
  r0 = @opts[:series].map{ |e| e[sym] }.flatten.minmax
  dist = r0[1] - r0[0]
  delta = dist==0 ? 1 : dist*0.1
  raw_range =
    if 0<=r0[0]
      [[r0[0]-delta, 0].max, r0[1]+delta]
    else
      [r0[0]-delta, r0[1]+delta]
    end
  raw_range.map{ |e| unscale_value( sym, e ) }
end
draw_violin(pdf, rect, yrange, hists, cols) click to toggle source
# File lib/charma/violin_chart.rb, line 31
def draw_violin(pdf, rect, yrange, hists, cols)
  ratio = 0.75
  _, violins, = rect.hsplit( (1-ratio)/2, ratio, (1-ratio)/2 )
  v_rects = violins.hsplit(*Array.new(hists.size,1))
  v_rects.zip(hists, cols) do |rc, hist, col|
    cx = rc.x + rc.w/2
    h = rc.h / hist.size.to_f
    hist.each.with_index do |f, ix|
      next if f==0
      w = rc.w * f
      top = rc.bottom + h*(ix+1)
      edge = 1e-1 # バーの隙間を埋める
      fill_rect( pdf, Rect.new( cx-w/2, top + edge, w, h + edge*2 ), col )
    end
  end
end
make_histograms( vals, range ) click to toggle source
# File lib/charma/violin_chart.rb, line 60
def make_histograms( vals, range )
  hist_size = @opts[:bins] || [10,Math.sqrt( meansize(vals) ).round].max
  min = range.min
  step = (range.max - min).to_f / hist_size
  bottoms = Array.new(hist_size){ |ix| min + (ix+1)*step }
  raw_h = vals.map{ |vvv|
    vvv.map{ |vv|
      vv.each.with_object([0]*hist_size){ |v,o|
        ix = bottoms.index{ |b| v<b }
        o[ix]+=1
      }
    }
  }
  ratio = 1.0 / raw_h.flatten.max
  raw_h.map{ |vvv|
    vvv.map{ |vv|
      vv.map{ |e| e*ratio }
    }
  }
end
meansize( vals ) click to toggle source
# File lib/charma/violin_chart.rb, line 48
def meansize( vals )
  sum=0.0
  count=0
  vals.each do |vvv|
    vvv.each do |vv|
      sum += vv.size
      count+=1
    end
  end
  sum / count
end
render( pdf, rect ) click to toggle source

BarChart の render とほぼ同じなのでなんとかする

# File lib/charma/violin_chart.rb, line 97
def render( pdf, rect )
  title_text = @opts[:title]
  title, main, ticks, bottom = rect.vsplit(
    (title_text ? 1 : 0),
    7,
    (@opts[:x_ticks] ? 0.5 : 0),
    (bottom_legend? ? 0.5 : 0))
  draw_text( pdf, title, title_text ) if title_text
  hratio = [(@opts[:y_label] ? 1 : 0), 1, 10]
  ylabel, yticks, chart = main.hsplit(*hratio)
  yrange = @opts[:y_range] || calc_range(:y)
  render_chart(pdf, chart, yrange)
  if @opts[:y_label]
    render_rottext(pdf, ylabel, @opts[:y_label] )
  end
  if @opts[:x_ticks]
    _, _, xticks = ticks.hsplit(*hratio)
    render_xticks(pdf, xticks)
  end
  yvalues = tick_values(:y, yrange)
  render_yticks(pdf, yticks, yrange, yvalues)
  render_y_grid(pdf, chart, yrange, yvalues)
  render_legend(pdf, bottom) if bottom_legend?
end
render_chart(pdf, rect, yrange) click to toggle source
# File lib/charma/violin_chart.rb, line 81
def render_chart(pdf, rect, yrange)
  stroke_rect(pdf, rect)
  y_values = @opts[:series].map{ |s| s[:y] }.transpose
  bar_areas = rect.hsplit(*Array.new(y_values.size,1))
  cols = if y_values.first.size==1
    colors(y_values.size).map{ |e| [e] }
  else
    [colors(y_values.first.size)] * y_values.size
  end
  hists = make_histograms(y_values, yrange)
  hists.zip(bar_areas, cols).each do |h, rc, c|
    draw_violin(pdf, rc, yrange, h, c)
  end
end
render_xticks(pdf, area) click to toggle source

TODO: BarChart に同じメソッドがあるのでなんとかする

# File lib/charma/violin_chart.rb, line 24
def render_xticks(pdf, area)
  rects = area.hsplit(*Array.new(@opts[:x_ticks].size){ 1 }).map{ |rc0|
    rc0.hsplit(1,8,1)[1]
  }
  draw_samesize_texts( pdf, rects, @opts[:x_ticks], valign: :top )
end