Class: TrendLineCalculator

Inherits:
Object show all
Defined in:
lib/jirametrics/trend_line_calculator.rb

Instance Method Summary collapse

Constructor Details

#initialize(points) ⇒ TrendLineCalculator



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/jirametrics/trend_line_calculator.rb', line 6

def initialize points
  # We can't do trend calculations with less than two data points
  @valid = points.size >= 2
  return unless valid?

  sum_of_x = points.sum { |x, _y| x }
  sum_of_y = points.sum { |_x, y| y }
  sum_of_xy = points.sum { |x, y| x * y }
  sum_of_x2 = points.sum { |x, _y| x * x }
  n = points.size.to_f

  @slope = ((n * sum_of_xy) - (sum_of_x * sum_of_y)) / ((n * sum_of_x2) - (sum_of_x * sum_of_x))
  @offset = (sum_of_y - (@slope * sum_of_x)) / n

  @valid = false if vertical?
end

Instance Method Details

#calc_y(x:) ⇒ Object

rubocop:disable Naming/MethodParameterName



27
28
29
# File 'lib/jirametrics/trend_line_calculator.rb', line 27

def calc_y x: # rubocop:disable Naming/MethodParameterName
  ((x * @slope) + @offset).to_i
end

#chart_datapoints(range:, max_y:, min_y: 0) ⇒ Object

If the trend line can’t be calculated then return an empty array. Otherwise, return an array with two (x,y) points, with which you can draw the trend line.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/jirametrics/trend_line_calculator.rb', line 39

def chart_datapoints range:, max_y:, min_y: 0
  raise 'max_y is nil' if max_y.nil?
  return [] unless valid?

  data_points = []
  x_start = range.begin
  y_start = calc_y(x: range.begin).to_i
  x_end = range.end
  y_end = calc_y(x: range.end).to_i

  if y_start < min_y
    x_start = line_crosses_at y: 0
    y_start = 0
  end

  if y_start > max_y
    x_start = line_crosses_at y: max_y
    y_start = max_y
  end

  if y_end < min_y
    x_end = line_crosses_at y: 0
    y_end = 0
  end

  if y_end > max_y
    x_end = line_crosses_at y: max_y
    y_end = max_y
  end

  data_points << { x: x_start, y: y_start }
  data_points << { x: x_end, y: y_end }

  data_points
end

#horizontal?Boolean

Returns:

  • (Boolean)


24
# File 'lib/jirametrics/trend_line_calculator.rb', line 24

def horizontal? = @slope.zero?

#line_crosses_at(y:) ⇒ Object

rubocop:disable Naming/MethodParameterName



31
32
33
34
35
# File 'lib/jirametrics/trend_line_calculator.rb', line 31

def line_crosses_at y: # rubocop:disable Naming/MethodParameterName
  raise "line will never cross #{y}. Trend is perfectly horizontal" if horizontal?

  ((y.to_f - @offset) / @slope).to_i
end

#valid?Boolean

Returns:

  • (Boolean)


23
# File 'lib/jirametrics/trend_line_calculator.rb', line 23

def valid? = @valid

#vertical?Boolean

Returns:

  • (Boolean)


25
# File 'lib/jirametrics/trend_line_calculator.rb', line 25

def vertical? = @slope.nan? || @slope.infinite?