module DYI::Chart::AxisUtil
@since 0.0.0
Private Instance Methods
base_value(a, b, allow_under=true, allow_over=true)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 78 def base_value(a, b, allow_under=true, allow_over=true) return 0 if a * b <= 0 || a == b a, b = -a, -b if negative = (a < 0) a, b = b, a if a > b return 0 if ((negative && allow_over) || (!negative && allow_under)) && a < b * 0.3 suitable_value_positive(a, b) * (negative ? -1 : 1) end
chart_range(data, min=nil, max=nil)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 248 def chart_range(data, min=nil, max=nil) data = data.compact.flatten if min.nil? && max.nil? data_min, data_max = data.inject([nil, nil]) do |(_min, _max), value| [value < (_min ||= value) ? value : _min, (_max ||= value) < value ? value : _max] end elsif min && max && max < min data_min, data_max = max, min else data_min = min || [data.min, max].min data_max = max || [data.max, min].max end if data_min == data_max if data_min > 0 data_min = 0 elsif data_max < 0 data_max = 0 else data_min = 0 data_max = 100 end end [data_min, data_max] end
figures_count(num)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 74 def figures_count(num) Math.log10(num).floor end
min_scale_value(max, min, scale_interval)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 297 def min_scale_value(max, min, scale_interval) return scale_interval if min == 0 if (max_digit = Math.log10(max).to_i) != Math.log10(min).to_i base_value = 10 ** max_digit elsif max.div(10 ** max_digit) != min.div(10 ** max_digit) base_value = 9 * 10 ** max_digit else range_digit = Math.log10(max - min).floor base_value = max.div(10 ** range_digit) * (10 ** range_digit) end base_value - ((base_value - min).quo(scale_interval).ceil - 1) * scale_interval end
moderate_axis(data, axis_length, min=nil, max=nil, scale_count_limit=nil)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 31 def moderate_axis(data, axis_length, min=nil, max=nil, scale_count_limit=nil) raise ArgumentError, 'no data' if (data = data.flatten.compact).empty? axis_length = Length.new(axis_length) data_min, data_max = chart_range(data, min, max) base_value = base_value(data_min, data_max, min.nil?, max.nil?) scale_count_limit ||= (axis_length / Length.new(30)).to_i scale_count_limit = 10 if 10 < scale_count_limit scale_count_limit = 2 if scale_count_limit < 2 scale_interval = scale_interval(base_value, data_min, data_max, scale_count_limit) min_scale_value = nil (base_value + scale_interval).step(data_min, -scale_interval) {|n| min_scale_value = n} min ||= (min_scale_value.nil? ? base_value : min_scale_value - scale_interval) min_scale_value ||= min + scale_interval unless max base_value.step(data_max, scale_interval) {|n| max = n} max += scale_interval if max < data_max end { :min => min || min_scale_value - scale_interval, :max => max, :axis_length => axis_length, :min_scale_value => min_scale_value, :scale_interval => scale_interval } end
moderate_sub_axis(data, main_axis_settings, min=nil, max=nil)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 203 def moderate_sub_axis(data, main_axis_settings, min=nil, max=nil) if min && max axis_ratio = (max - min).quo(main_axis_settings[:max] - main_axis_settings[:min]) return { :max => max, :min => min, :min_scale_value => min + (main_axis_settings[:min_scale_value] - main_axis_settings[:min]) * axis_ratio, :axis_length => main_axis_settings[:axis_length], :scale_interval => main_axis_settings[:scale_interval] * axis_ratio } end scale_count = (main_axis_settings[:max] - main_axis_settings[:min_scale_value]).div(main_axis_settings[:scale_interval]) + (main_axis_settings[:min_scale_value] == main_axis_settings[:min] ? 0 : 1) data_min, data_max = chart_range(data, min, max) base_value = base_value(data_min, data_max, min.nil?, max.nil?) scale_interval = scale_interval(base_value, data_min, data_max, scale_count) scale_ratio = scale_interval.quo(main_axis_settings[:scale_interval]) if min min_scale_value = scale_ratio * (main_axis_settings[:min_scale_value] - main_axis_settings[:min]) + min max = scale_ratio * (main_axis_settings[:max] - main_axis_settings[:min_scale_value]) + min_scale_value elsif max min_scale_value = max - scale_ratio * (main_axis_settings[:max] - main_axis_settings[:min_scale_value]) min = min_scale_value - scale_ratio * (main_axis_settings[:min_scale_value] - main_axis_settings[:min]) else min_scale_value = nil (base_value + scale_interval).step(data_min, -scale_interval) {|n| min_scale_value = n} min_scale_value ||= base_value + scale_interval min = min_scale_value - scale_ratio * (main_axis_settings[:min_scale_value] - main_axis_settings[:min]) if data_min < min min_scale_value -= scale_interval min -= scale_interval end max = scale_ratio * (main_axis_settings[:max] - main_axis_settings[:min_scale_value]) + min_scale_value end { :min => min || min_scale_value - scale_interval, :max => max, :axis_length => main_axis_settings[:axis_length], :min_scale_value => min_scale_value, :scale_interval => scale_interval } end
order_position_on_chart(chart_margin, axis_length, count, index, type=:point, renge_width_ratio=0, reverse_direction=false)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 281 def order_position_on_chart(chart_margin, axis_length, count, index, type=:point, renge_width_ratio=0, reverse_direction=false) chart_margin = Length.new(chart_margin) pos = case type when :point then index.to_f / (count - 1) when :range then (index + 0.5 - renge_width_ratio.to_f / 2) / count else raise ArgumentError, "\"#{type}\" is invalid type" end axis_length * pos + chart_margin end
round_top_2_digit(max, min)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 292 def round_top_2_digit(max, min) digit = Math.log10([max.abs, min.abs].max).floor - 1 [max.quo(10 ** digit).ceil * (10 ** digit), min.quo(10 ** digit).floor * (10 ** digit)] end
scale_interval(base_value, data_min, data_max, scale_count_limit)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 95 def scale_interval(base_value, data_min, data_max, scale_count_limit) if base_value - data_min < data_max - base_value allocate_scale_count = (data_max - base_value).div((data_max - data_min).quo(scale_count_limit)) scale_interval_base2edge(base_value, data_max, allocate_scale_count) else allocate_scale_count = (base_value - data_min).div((data_max - data_min).quo(scale_count_limit)) scale_interval_base2edge(base_value, data_min, allocate_scale_count) end end
scale_interval_base2edge(base_value, edge_value, scale_count_limit)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 105 def scale_interval_base2edge(base_value, edge_value, scale_count_limit) raise ArgumentError, 'base_value should not equal edge_value' if edge_value == base_value range = (base_value - edge_value).abs top_2_digits = top_digit(range, 2) case scale_count_limit.to_i when 1 case top_2_digits when 10 then label_range = 10 when 11..20 then label_range = 20 when 21..40 then label_range = 40 when 41..50 then label_range = 50 when 51..99 then label_range = 100 end when 2 case top_2_digits when 10 then label_range = 5 when 11..20 then label_range = 10 when 21..40 then label_range = 20 when 41..50 then label_range = 25 when 51..99 then label_range = 50 end when 3 case top_2_digits when 10 then label_range = 4 when 11..15 then label_range = 5 when 16..30 then label_range = 10 when 31..60 then label_range = 20 when 61..75 then label_range = 25 when 76..99 then label_range = 40 end when 4 case top_2_digits when 10 then label_range = 2.5 when 11..15 then label_range = 4 when 16..20 then label_range = 5 when 21..40 then label_range = 10 when 41..80 then label_range = 20 when 81..99 then label_range = 25 end when 5 case top_2_digits when 10 then label_range = 2 when 11..12 then label_range = 2.5 when 13..15 then label_range = 4 when 16..25 then label_range = 5 when 26..50 then label_range = 10 when 51..99 then label_range = 20 end when 6 case top_2_digits when 10..12 then label_range = 2 when 13..15 then label_range = 2.5 when 16..20 then label_range = 4 when 21..30 then label_range = 5 when 31..60 then label_range = 10 when 61..99 then label_range = 20 end when 7 case top_2_digits when 10..14 then label_range = 2 when 15..17 then label_range = 2.5 when 18..20 then label_range = 4 when 21..35 then label_range = 5 when 35..70 then label_range = 10 when 71..99 then label_range = 20 end when 8 case top_2_digits when 10..16 then label_range = 2 when 17..20 then label_range = 2.5 when 21..25 then label_range = 4 when 26..40 then label_range = 5 when 41..80 then label_range = 10 when 81..99 then label_range = 20 end when 9 case top_2_digits when 10..18 then label_range = 2 when 19..22 then label_range = 2.5 when 23..30 then label_range = 4 when 31..45 then label_range = 5 when 46..90 then label_range = 10 when 91..99 then label_range = 20 end else case top_2_digits when 10 then label_range = 1 when 11..20 then label_range = 2 when 21..25 then label_range = 2.5 when 26..30 then label_range = 4 when 31..50 then label_range = 5 when 51..99 then label_range = 10 end end label_range * (10 ** (figures_count(range) - 1)) end
suitable_1digit_value(a, b)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 63 def suitable_1digit_value(a, b) return a if a == b a, b = b, a if a > b return 0 if a == 0 return 5 if a <= 5 && 5 <= b return 2 if a <= 2 && 2 <= b return 4 if a <= 4 && 4 <= b return 6 if a <= 6 && 6 <= b 8 end
suitable_value_positive(a, b)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 86 def suitable_value_positive(a, b) if figures_count(a) != (dig = figures_count(b)) return 10 ** dig end n = 1 n += 1 while (dig_a = top_digit(a, n)) == (dig_b = top_digit(b, n)) (suitable_1digit_value(dig_a - dig_a.div(10) * 10 + (dig_a == dig_a.div(10) * 10 ? 0 : 1), dig_b - dig_b.div(10) * 10) + dig_a.div(10) * 10) * (10 ** (dig - figures_count(dig_a))) end
top_digit(num, n=1)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 59 def top_digit(num, n=1) num.div(10 ** (figures_count(num) - n + 1)) end
value_position_on_chart(chart_margin, axis_settings, value, reverse_direction = false)
click to toggle source
# File lib/dyi/chart/axis_util.rb, line 275 def value_position_on_chart(chart_margin, axis_settings, value, reverse_direction = false) axis_settings[:axis_length] * ((reverse_direction ? (axis_settings[:max] - value) : (value - axis_settings[:min])).to_f / (axis_settings[:max] - axis_settings[:min])) + Length.new(chart_margin) end