class Friends::Graph

Constants

COLORS

Originally generated by executing the code in Minitest's Pride plugin (the PrideLOL class), and then pulling the unique values out and doubling them to create a more even distribution of colors.

DATE_FORMAT
SCALED_SIZE

Public Class Methods

new(filtered_activities:, all_activities:, unscaled:) click to toggle source

@param filtered_activities [Array<Friends::Activity>] a list of activities to highlight in

the graph (may be the same as `all_activities`)

@param all_activities [Array<Friends::Activity>] a list of activities to graph @param unscaled [Boolean] true iff we should show the absolute size of bars in the graph

rather than a scaled version
# File lib/friends/graph.rb, line 15
def initialize(filtered_activities:, all_activities:, unscaled:)
  @filtered_activities = filtered_activities
  @all_activities = all_activities
  @unscaled = unscaled

  return if @all_activities.empty?

  @start_date = @all_activities.last.date
  @end_date = @all_activities.first.date
end

Public Instance Methods

output() click to toggle source

@return [Array<String>] the output to print, with colors

# File lib/friends/graph.rb, line 27
def output
  hash = to_h
  global_total = hash.max_by { |_, (_, val)| val }.last.last unless @unscaled || hash.empty?

  hash.map do |month, (filtered_count, total_count)|
    unless @unscaled
      # We want to use rationals for math so we can round up as well
      # as down (instead of int division), for more accurate graphing.
      # Floats are less trustworthy and could give results < 0 or > total_count
      filtered_count = Rational(filtered_count * SCALED_SIZE, global_total).round
      total_count = SCALED_SIZE
    end

    str = "#{month} |"
    str += Array.new(filtered_count) do |count|
      Paint["█", color(count)]
    end.join
    if total_count > filtered_count
      str += Array.new(total_count - filtered_count) do |count|
        Paint["∙", color(filtered_count + count)]
      end.join + Paint["|", color(total_count + 1)]
    end

    str
  end.reverse!
end

Private Instance Methods

color(x_coord) click to toggle source

@param x_coord [Integer] the x coordinate we want to color; x >= 0 @return [Array<Integer>] the color we should use to paint

a point on the graph at the given x coordinate
# File lib/friends/graph.rb, line 101
def color(x_coord)
  COLORS[x_coord % COLORS.size]
end
empty_graph() click to toggle source

Render an empty graph as a hash in the format:

{
  "Jan 2015" => [0, 0] # [# filtered activities, # total activities]
  "Feb 2015" => [0, 0]
  "Mar 2015" => [0, 0]
}

@return [Hash{String => Integer}]

# File lib/friends/graph.rb, line 85
def empty_graph
  Hash[(@start_date && @end_date ? (@start_date..@end_date) : []).map do |date|
    [format_date(date), [0, 0]]
  end]
end
format_date(date) click to toggle source

Format a date for use in the graph label @param date [Date] the date to format @return [String]

# File lib/friends/graph.rb, line 94
def format_date(date)
  date.strftime(DATE_FORMAT)
end
to_h() click to toggle source

Render the graph as a hash in the format:

{
  "Jan 2015" => [3, 4], # [# filtered activities, # total activities]
  "Feb 2015" => [0, 0],
  "Mar 2015" => [0, 9]
}

@return [Hash{String => Integer}]

# File lib/friends/graph.rb, line 65
def to_h
  empty_graph.tap do |graph|
    @filtered_activities.each do |activity|
      graph[format_date(activity.date)][0] += 1
    end
    @all_activities.each do |activity|
      graph[format_date(activity.date)][1] += 1
    end
  end
end