Module: PredictabilityEngine::MermaidVisualizer

Defined in:
lib/predictability_engine/mermaid_visualizer.rb

Class Method Summary collapse

Class Method Details

.aging_wip(items, **_opts) ⇒ Object



43
44
45
46
47
# File 'lib/predictability_engine/mermaid_visualizer.rb', line 43

def self.aging_wip(items, **_opts)
  data = Calculators::Aging.item_age_data(items)
  format_mermaid_xy('Aging Work In Progress', data.map { |d| d[:id] }, 'Age (days)',
                    [data.map { |d| d[:age] }], labels: ['Age'], type: 'bar')
end

.build_vertical_rule(data, percentile, hist_size) ⇒ Object



35
36
37
38
39
40
41
# File 'lib/predictability_engine/mermaid_visualizer.rb', line 35

def self.build_vertical_rule(data, percentile, hist_size)
  days = data[:summary][:"p#{percentile}"]
  index = hist_size - 1 + days
  res = Array.new(data[:dates].size, nil)
  res[index] = data[:summary][:total_items] if index < res.size
  res
end

.cfd_plot(items, **_opts) ⇒ Object



7
8
9
10
11
12
13
# File 'lib/predictability_engine/mermaid_visualizer.rb', line 7

def self.cfd_plot(items, **_opts)
  data = Calculators::Cfd.calculate(items).last(20)
  dates = data.map { |d| d[:date].to_s }
  format_mermaid_xy("Cumulative Flow Diagram (Last #{dates.size} days)", dates, 'Items',
                    [data.map { |d| d[:arrived] }, data.map { |d| d[:departed] }],
                    labels: %w[Arrivals Departures])
end

.cycle_time_scatter(items, percentiles: PredictabilityEngine::DEFAULT_PERCENTILES, **_opts) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
# File 'lib/predictability_engine/mermaid_visualizer.rb', line 55

def self.cycle_time_scatter(items, percentiles: PredictabilityEngine::DEFAULT_PERCENTILES, **_opts)
  completed = Calculators::CycleTime.completed_sorted(items)
  return '' if completed.empty?

  dates = completed.map { |i| i.end_date.to_s }.uniq.last(20)
  series = percentiles.map { |p| dates.map { |d| pct_at(completed, d, p) } }
  labels = percentiles.map { |p| "#{p}th Percentile" }

  format_mermaid_xy("Cycle Time Trend (Last #{dates.size} days)", dates, 'Cycle Time (days)',
                    series, labels: labels, thin: true)
end

.forecasted_cfd_plot(items, percentiles: PredictabilityEngine::DEFAULT_PERCENTILES, **_opts) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/predictability_engine/mermaid_visualizer.rb', line 15

def self.forecasted_cfd_plot(items, percentiles: PredictabilityEngine::DEFAULT_PERCENTILES, **_opts)
  data = Calculators::Cfd.forecast_series(items, percentiles: percentiles)
  return cfd_plot(items) unless data

  series = [data[:arrivals]]
  labels = ['Arrivals']
  hist_size = data[:departed].size
  series << (data[:departed] + Array.new(data[:dates].size - hist_size, nil))
  labels << 'Departures'
  percentiles.each do |p|
    series << data[:forecasts][p]
    labels << "#{p}% Confidence"
    series << build_vertical_rule(data, p, hist_size)
    labels << "#{p}% Deadline"
  end

  format_mermaid_xy('Forecasted Cumulative Flow Diagram', data[:dates].map(&:to_s), 'Items',
                    series, labels: labels, thin: true)
end

.format_mermaid_xy(title, x_axis, y_label, series, opts = {}) ⇒ Object



71
72
73
74
# File 'lib/predictability_engine/mermaid_visualizer.rb', line 71

def self.format_mermaid_xy(title, x_axis, y_label, series, opts = {})
  ['xychart-beta', "    title \"#{title}\"", "    x-axis [\"#{format_x_axis(x_axis, opts).join('", "')}\"]",
   "    y-axis \"#{y_label}\"", *format_series(series, opts)].join("\n")
end

.pct_at(items, date, pct) ⇒ Object



67
68
69
# File 'lib/predictability_engine/mermaid_visualizer.rb', line 67

def self.pct_at(items, date, pct)
  PredictabilityEngine.cycle_time_percentile(items.select { |i| i.end_date <= Date.parse(date) }, pct)
end

.throughput_histogram(items, **_opts) ⇒ Object



49
50
51
52
53
# File 'lib/predictability_engine/mermaid_visualizer.rb', line 49

def self.throughput_histogram(items, **_opts)
  counts = Calculators::Throughput.histogram_data(items)
  format_mermaid_xy('Throughput Histogram', counts.map { |c| c[0] }, 'Frequency',
                    [counts.map { |c| c[1] }], labels: ['Frequency'], type: 'bar')
end