Module: Utilities::Heatmap

Defined in:
lib/utilities/heatmap.rb

Constant Summary collapse

CURVES =

Written with CLAUDE code

Curve types for different emphasis patterns

{
  # Linear curve - equal emphasis across range
  linear: ->(x) { x },

  # Logarithmic curve - emphasizes higher values more
  # Good for data where high values should stand out
  logarithmic: ->(x) {
    return 0 if x <= 0
    Math.log(1 + x * 99) / Math.log(100)
  },

  # Citation emphasis curve - designed for citation counts
  # No color for 1, strong differentiation at low end (2-10), moderate at high end
  citation_count: ->(x, count: nil) {
    return 0 if x <= 0

    # If actual count is provided and it's 1, return 0 (no color)
    return 0 if count && count <= 1

    # Use a power curve with very strong differentiation at low end
    # Optimized for max values around 50-200
    if x < 0.0125    # ~2 records when max is 160
      0.15           # Start with visible color for 2
    elsif x < 0.019  # ~3 records
      0.15 + (x - 0.0125) * 15.0
    elsif x < 0.025  # ~4 records
      0.25 + (x - 0.019) * 12.0
    elsif x < 0.0375 # ~5-6 records
      0.32 + (x - 0.025) * 8.0
    elsif x < 0.0625 # ~7-10 records
      0.42 + (x - 0.0375) * 4.0
    elsif x < 0.125  # ~11-20 records
      0.52 + (x - 0.0625) * 2.0
    elsif x < 0.31   # ~21-50 records
      0.645 + (x - 0.125) * 1.0
    elsif x < 1.0    # ~51+ records
      0.83 + (x - 0.31) * 0.5
    else
      0.975 + (x - 1.0) * 0.025  # Extreme emphasis above max
    end
  },

  # Exponential curve - emphasizes higher values extremely
  exponential: ->(x) {
    (Math.exp(x * 2) - 1) / (Math.exp(2) - 1)
  },

  # Square root curve - de-emphasizes very high values
  sqrt: ->(x) {
    Math.sqrt(x)
  }
}.freeze

Class Method Summary collapse

Class Method Details

.color_from_hash(hash) ⇒ Object



86
87
88
89
90
91
92
93
# File 'lib/utilities/heatmap.rb', line 86

def self.color_from_hash(hash)
  j = hash[0, 1]
  substr = j.hex

  hash << hash

  '#' + hash[substr..(substr + 5)]
end

.heatmap_color_for(value, curve: :linear, count: nil) ⇒ String

0,1

Parameters:

  • value (Float)

    normalized value between 0 and 1

  • curve (Symbol, Proc) (defaults to: :linear)

    curve type from CURVES or custom proc

Returns:

  • (String)

    HSL color string



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/utilities/heatmap.rb', line 63

def self.heatmap_color_for(value, curve: :linear, count: nil)
  curve_fn = curve.is_a?(Proc) ? curve : CURVES[curve] || CURVES[:linear]

  # Apply the curve transformation, passing count if the curve accepts it
  transformed_value = if curve == :citation_count && count
    curve_fn.call(value, count: count)
  else
    curve_fn.call(value)
  end

  # Clamp between 0 and 1
  transformed_value = [[transformed_value, 0].max, 1].min

  # Map to hue (red=0, yellow=60, green=120, cyan=180, blue=240)
  # We want: low values = blue/cyan (cool), high values = red/orange (hot)
  # So we reverse: 1 - transformed_value
  h = (1 - transformed_value) * 240  # 240=blue to 0=red
  s = 100
  l = 30 + (transformed_value * 30)  # Vary lightness from 30% to 60%

  "hsl(#{h.round(2)},#{s.round(2)}%,#{l.round(2)}%)"
end

.hex_color_from_string(text) ⇒ Object



110
111
112
# File 'lib/utilities/heatmap.rb', line 110

def self.hex_color_from_string(text)
  color_from_hash(text_to_hash(text))
end

.text_to_hash(text) ⇒ Object

llama-3-8b-instruct and function colorFromHash(hash) (internall)



97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/utilities/heatmap.rb', line 97

def self.text_to_hash(text)
  hash = 0
  if text.empty?
    return hash.to_s(16)
  end

  text.each_char do |char|
    hash = ((hash << 5) - hash + char.ord).abs
  end

  hash.to_s(16)
end