Class: CycletimeHistogram
- Includes:
- GroupableIssueChart
- Defined in:
- lib/jirametrics/cycletime_histogram.rb
Instance Attribute Summary collapse
-
#possible_statuses ⇒ Object
Returns the value of attribute possible_statuses.
-
#show_stats ⇒ Object
readonly
Returns the value of attribute show_stats.
Attributes inherited from ChartBase
#aggregated_project, #all_boards, #atlassian_document_format, #board_id, #canvas_height, #canvas_width, #data_quality, #date_range, #file_system, #holiday_dates, #issues, #settings, #time_range, #timezone_offset
Instance Method Summary collapse
- #data_set_for(histogram_data:, label:, color:) ⇒ Object
- #disable_stats ⇒ Object
- #histogram_data_for(issues:) ⇒ Object
-
#initialize(block) ⇒ CycletimeHistogram
constructor
A new instance of CycletimeHistogram.
- #percentiles(percs = nil) ⇒ Object
- #run ⇒ Object
- #stats_for(histogram_data:, percentiles:) ⇒ Object
Methods included from GroupableIssueChart
#group_issues, #grouping_rules, #init_configuration_block
Methods inherited from ChartBase
#aggregated_project?, #canvas, #canvas_responsive?, #chart_format, #collapsible_issues_panel, #color_block, #color_for, #completed_issues_in_range, #current_board, #daily_chart_dataset, #describe_non_working_days, #description_text, #format_integer, #format_status, #header_text, #holidays, #html_directory, #icon_span, #label_days, #label_issues, #link_to_issue, #next_id, #random_color, #render, #render_top_text, #status_category_color, #working_days_annotation, #wrap_and_render
Constructor Details
#initialize(block) ⇒ CycletimeHistogram
Returns a new instance of CycletimeHistogram.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/jirametrics/cycletime_histogram.rb', line 10 def initialize block super() percentiles [50, 85, 98] @show_stats = true header_text 'Cycletime Histogram' description_text <<-HTML <p> The Cycletime Histogram shows how many items completed in a certain timeframe. This can be useful for determining how many different types of work are flowing through, based on the lengths of time they take. </p> HTML init_configuration_block(block) do grouping_rules do |issue, rule| rule.label = issue.type rule.color = color_for type: issue.type end end end |
Instance Attribute Details
#possible_statuses ⇒ Object
Returns the value of attribute possible_statuses.
7 8 9 |
# File 'lib/jirametrics/cycletime_histogram.rb', line 7 def possible_statuses @possible_statuses end |
#show_stats ⇒ Object (readonly)
Returns the value of attribute show_stats.
8 9 10 |
# File 'lib/jirametrics/cycletime_histogram.rb', line 8 def show_stats @show_stats end |
Instance Method Details
#data_set_for(histogram_data:, label:, color:) ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/jirametrics/cycletime_histogram.rb', line 123 def data_set_for histogram_data:, label:, color: keys = histogram_data.keys.sort { type: 'bar', label: label, data: keys.sort.filter_map do |key| next if histogram_data[key].zero? { x: key, y: histogram_data[key], title: "#{histogram_data[key]} items completed in #{label_days key}" } end, backgroundColor: color, borderRadius: 0 } end |
#disable_stats ⇒ Object
38 39 40 |
# File 'lib/jirametrics/cycletime_histogram.rb', line 38 def disable_stats @show_stats = false end |
#histogram_data_for(issues:) ⇒ Object
72 73 74 75 76 77 78 79 |
# File 'lib/jirametrics/cycletime_histogram.rb', line 72 def histogram_data_for issues: count_hash = {} issues.each do |issue| days = issue.board.cycletime.cycletime(issue) count_hash[days] = (count_hash[days] || 0) + 1 if days.positive? end count_hash end |
#percentiles(percs = nil) ⇒ Object
33 34 35 36 |
# File 'lib/jirametrics/cycletime_histogram.rb', line 33 def percentiles percs = nil @percentiles = percs unless percs.nil? @percentiles end |
#run ⇒ Object
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 |
# File 'lib/jirametrics/cycletime_histogram.rb', line 42 def run stopped_issues = completed_issues_in_range include_unstarted: true # For the histogram, we only want to consider items that have both a start and a stop time. histogram_issues = stopped_issues.select { |issue| issue.board.cycletime.started_stopped_times(issue).first } rules_to_issues = group_issues histogram_issues the_stats = {} overall_stats = stats_for histogram_data: histogram_data_for(issues: histogram_issues), percentiles: @percentiles the_stats[:all] = overall_stats data_sets = rules_to_issues.keys.collect do |rules| the_issue_type = rules.label the_histogram = histogram_data_for(issues: rules_to_issues[rules]) the_stats[the_issue_type] = stats_for histogram_data: the_histogram, percentiles: @percentiles if @show_stats data_set_for( histogram_data: the_histogram, label: the_issue_type, color: rules.color ) end if data_sets.empty? return "<h1 class='foldable'>#{@header_text}</h1><div>No data matched the selected criteria. Nothing to show.</div>" end wrap_and_render(binding, __FILE__) end |
#stats_for(histogram_data:, percentiles:) ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/jirametrics/cycletime_histogram.rb', line 81 def stats_for histogram_data:, percentiles: return {} if histogram_data.empty? total_values = histogram_data.values.sum # Calculate the average weighted_sum = histogram_data.reduce(0) { |sum, (value, frequency)| sum + (value * frequency) } average = total_values.zero? ? 0 : weighted_sum.to_f / total_values # Find the mode (or modes!) and the spread of the distribution sorted_histogram = histogram_data.sort_by { |_value, frequency| frequency } max_freq = sorted_histogram[-1][1] mode = sorted_histogram.select { |_v, f| f == max_freq } minmax = histogram_data.keys.minmax # Calculate percentiles sorted_values = histogram_data.keys.sort cumulative_counts = {} cumulative_sum = 0 sorted_values.each do |value| cumulative_sum += histogram_data[value] cumulative_counts[value] = cumulative_sum end percentile_results = {} percentiles.each do |percentile| rank = (percentile / 100.0) * total_values percentile_value = sorted_values.find { |value| cumulative_counts[value] >= rank } percentile_results[percentile] = percentile_value end { average: average, mode: mode.collect(&:first).sort, min: minmax[0], max: minmax[1], percentiles: percentile_results } end |