gruff 0.2.8 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/gruff/line.rb CHANGED
@@ -1,6 +1,17 @@
1
1
 
2
2
  require File.dirname(__FILE__) + '/base'
3
3
 
4
+ ##
5
+ # Here's how to make a Line graph:
6
+ #
7
+ # g = Gruff::Line.new
8
+ # g.title = "A Line Graph"
9
+ # g.data 'Fries', [20, 23, 19, 8]
10
+ # g.data 'Hamburgers', [50, 19, 99, 29]
11
+ # g.write("test/output/line.png")
12
+ #
13
+ # There are also other options described below, such as #baseline_value, #baseline_color, #hide_dots, and #hide_lines.
14
+
4
15
  class Gruff::Line < Gruff::Base
5
16
 
6
17
  # Draw a dashed line at the given value
@@ -20,14 +20,14 @@ module Gruff
20
20
 
21
21
  legend_square_width = 40.0 # small square with color of this item
22
22
  legend_square_margin = 10.0
23
- @legend_left_margin = 40.0
23
+ @legend_left_margin = 100.0
24
24
  legend_top_margin = 40.0
25
25
 
26
26
  # May fix legend drawing problem at small sizes
27
27
  @d.font = @font if @font
28
28
  @d.pointsize = @legend_font_size
29
29
 
30
- current_x_offset = @graph_left + @legend_left_margin
30
+ current_x_offset = @legend_left_margin
31
31
  current_y_offset = @original_rows + legend_top_margin
32
32
 
33
33
  debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset }
@@ -66,7 +66,7 @@ module Gruff
66
66
 
67
67
  def truncate_legend_label(label)
68
68
  truncated_label = label.to_s
69
- while calculate_width(scale_fontsize(@legend_font_size), truncated_label) > (@columns - @legend_left_margin - Gruff::Base::RIGHT_MARGIN) && (truncated_label.length > 1)
69
+ while calculate_width(scale_fontsize(@legend_font_size), truncated_label) > (@columns - @legend_left_margin - @right_margin) && (truncated_label.length > 1)
70
70
  truncated_label = truncated_label[0..truncated_label.length-2]
71
71
  end
72
72
  truncated_label + (truncated_label.length < label.to_s.length ? "…" : '')
@@ -7,6 +7,8 @@ module Gruff
7
7
 
8
8
  class SideBar < Gruff::SideBar
9
9
 
10
+ include Gruff::Mini::Legend
11
+
10
12
  def initialize_ivars
11
13
  super
12
14
  @hide_legend = true
@@ -14,6 +16,17 @@ module Gruff
14
16
  @hide_line_numbers = true
15
17
 
16
18
  @marker_font_size = 50.0
19
+ @legend_font_size = 50.0
20
+ end
21
+
22
+ def draw
23
+ expand_canvas_for_vertical_legend
24
+
25
+ super
26
+
27
+ draw_vertical_legend
28
+
29
+ @d.draw(@base_image)
17
30
  end
18
31
 
19
32
  end
data/lib/gruff/pie.rb CHANGED
@@ -1,6 +1,16 @@
1
-
2
1
  require File.dirname(__FILE__) + '/base'
3
2
 
3
+ ##
4
+ # Here's how to make a Pie graph:
5
+ #
6
+ # g = Gruff::Pie.new
7
+ # g.title = "Visual Pie Graph Test"
8
+ # g.data 'Fries', 20
9
+ # g.data 'Hamburgers', 50
10
+ # g.write("test/output/pie_keynote.png")
11
+ #
12
+ # To control where the pie chart starts creating slices, use #zero_degree.
13
+
4
14
  class Gruff::Pie < Gruff::Base
5
15
 
6
16
  TEXT_OFFSET_PERCENTAGE = 0.15
@@ -8,7 +18,7 @@ class Gruff::Pie < Gruff::Base
8
18
  # Can be used to make the pie start cutting slices at the top (-90.0)
9
19
  # or at another angle. Default is 0.0, which starts at 3 o'clock.
10
20
  attr_accessor :zero_degree
11
-
21
+
12
22
  def initialize_ivars
13
23
  super
14
24
  @zero_degree = 0.0
@@ -30,7 +40,8 @@ class Gruff::Pie < Gruff::Base
30
40
  prev_degrees = @zero_degree
31
41
 
32
42
  # Use full data since we can easily calculate percentages
33
- @data.sort{ |a, b| a[DATA_VALUES_INDEX][0] <=> b[DATA_VALUES_INDEX][0] }.each do |data_row|
43
+ data = (@sort ? @data.sort{ |a, b| a[DATA_VALUES_INDEX][0] <=> b[DATA_VALUES_INDEX][0] } : @data)
44
+ data.each do |data_row|
34
45
  if data_row[DATA_VALUES_INDEX][0] > 0
35
46
  @d = @d.stroke data_row[DATA_COLOR_INDEX]
36
47
  @d = @d.fill 'transparent'
@@ -47,13 +58,16 @@ class Gruff::Pie < Gruff::Base
47
58
 
48
59
  half_angle = prev_degrees + ((prev_degrees + current_degrees) - prev_degrees) / 2
49
60
 
50
- # End the string with %% to escape the single %.
51
- # RMagick must use sprintf with the string and % has special significance.
52
- label_string = ((data_row[DATA_VALUES_INDEX][0] / total_sum) * 100.0).round.to_s + '%%'
53
- @d = draw_label(center_x,center_y,
54
- half_angle, radius + (radius * TEXT_OFFSET_PERCENTAGE),
55
- label_string)
56
-
61
+ unless @hide_line_markers then
62
+ # End the string with %% to escape the single %.
63
+ # RMagick must use sprintf with the string and % has special significance.
64
+ label_string = ((data_row[DATA_VALUES_INDEX][0] / total_sum) *
65
+ 100.0).round.to_s + '%%'
66
+ @d = draw_label(center_x,center_y, half_angle,
67
+ radius + (radius * TEXT_OFFSET_PERCENTAGE),
68
+ label_string)
69
+ end
70
+
57
71
  prev_degrees += current_degrees
58
72
  end
59
73
  end
@@ -99,10 +113,10 @@ private
99
113
 
100
114
  end
101
115
 
102
-
103
116
  class Float
104
117
  # Used for degree => radian conversions
105
118
  def deg2rad
106
119
  self * (Math::PI/180.0)
107
120
  end
108
121
  end
122
+
data/lib/gruff/scene.rb CHANGED
@@ -14,19 +14,31 @@ require File.dirname(__FILE__) + '/base'
14
14
  #
15
15
  # Usage:
16
16
  #
17
- # g = Gruff::Scene.new("500x100", "artwork/city_scene")
17
+ # g = Gruff::Scene.new("500x100", "path/to/city_scene_directory")
18
+ #
19
+ # # Define order of layers, back to front
18
20
  # g.layers = %w(background haze sky clouds)
21
+ #
22
+ # # Define groups that will be controlled by the same input
19
23
  # g.weather_group = %w(clouds)
20
24
  # g.time_group = %w(background sky)
25
+ #
26
+ # # Set values for the layers or groups
21
27
  # g.weather = "cloudy"
22
28
  # g.time = Time.now
23
29
  # g.haze = true
24
- # g.write "hazy_daytime_city_scene.png"
25
30
  #
31
+ # # Write the final graph to disk
32
+ # g.write "hazy_daytime_city_scene.png"
26
33
  #
27
34
  #
28
- # If there is a file named 'default.png', it will be selected (unless other values are provided to override it).
35
+ # There are several rules that will magically select a layer when possible.
29
36
  #
37
+ # * Numbered files will be selected according to the closest value that is less than the input value.
38
+ # * 'true.png' and 'false.png' will be used as booleans.
39
+ # * Other named files will be used if the input matches the filename (without the filetype extension).
40
+ # * If there is a file named 'default.png', it will be used unless other input values are set for the corresponding layer.
41
+
30
42
  class Gruff::Scene < Gruff::Base
31
43
 
32
44
  # An array listing the foldernames that will be rendered, from back to front.
@@ -1,21 +1,66 @@
1
1
  require File.dirname(__FILE__) + '/base'
2
2
 
3
3
  ##
4
- # EXPERIMENTAL
5
- #
6
- # Graph with horizontal bars instead of vertical.
7
- #
8
- # TODO SideStackedBar should probably inherit from this
9
- # to consolidate the line marker drawing.
4
+ # Graph with individual horizontal bars instead of vertical bars.
5
+
10
6
  class Gruff::SideBar < Gruff::Base
11
7
 
8
+ def draw
9
+ @has_left_labels = true
10
+ super
11
+
12
+ return unless @has_data
13
+
14
+ # Setup spacing.
15
+ #
16
+ spacing_factor = 0.9
17
+
18
+ @bars_width = @graph_height / @column_count.to_f
19
+ @bar_width = @bars_width * spacing_factor / @norm_data.size
20
+ @d = @d.stroke_opacity 0.0
21
+ height = Array.new(@column_count, 0)
22
+ length = Array.new(@column_count, @graph_left)
23
+
24
+ @norm_data.each_with_index do |data_row, row_index|
25
+ @d = @d.fill data_row[DATA_COLOR_INDEX]
26
+
27
+ data_row[1].each_with_index do |data_point, point_index|
28
+
29
+ # Using the original calcs from the stacked bar chart
30
+ # to get the difference between
31
+ # part of the bart chart we wish to stack.
32
+ temp1 = @graph_left + (@graph_width - data_point * @graph_width - height[point_index])
33
+ temp2 = @graph_left + @graph_width - height[point_index]
34
+ difference = temp2 - temp1
35
+
36
+ left_x = length[point_index] - 1
37
+ left_y = @graph_top + (@bars_width * point_index) + (@bar_width * row_index)
38
+ right_x = left_x + difference
39
+ right_y = left_y + @bar_width
40
+
41
+ height[point_index] += (data_point * @graph_width)
42
+
43
+ @d = @d.rectangle(left_x, left_y, right_x, right_y)
44
+
45
+ # Calculate center based on bar_width and current row
46
+ label_center = @graph_top + (@bars_width * point_index + @bars_width / 2)
47
+ draw_label(label_center, point_index)
48
+ end
49
+
50
+ end
51
+
52
+ @d.draw(@base_image)
53
+ end
54
+
55
+ protected
56
+
12
57
  # Instead of base class version, draws vertical background lines and label
13
58
  def draw_line_markers
14
59
 
15
60
  return if @hide_line_markers
16
61
 
17
62
  @d = @d.stroke_antialias false
18
-
63
+
19
64
  # Draw horizontal line markers and annotate with numbers
20
65
  @d = @d.stroke(@marker_color)
21
66
  @d = @d.stroke_width 1
@@ -36,10 +81,11 @@ class Gruff::SideBar < Gruff::Base
36
81
  @d.font = @font if @font
37
82
  @d.stroke = 'transparent'
38
83
  @d.pointsize = scale_fontsize(@marker_font_size)
39
- # @d.gravity = NorthGravity
40
- @d = @d.annotate_scaled( @base_image,
41
- 100, 20,
42
- x - (@marker_font_size/1.5), @graph_bottom + 40,
84
+ @d.gravity = CenterGravity
85
+ # TODO Center text over line
86
+ @d = @d.annotate_scaled( @base_image,
87
+ 0, 0, # Width of box to draw text in
88
+ x, @graph_bottom + (LABEL_MARGIN * 2.0), # Coordinates of text
43
89
  marker_label.to_s, @scale)
44
90
  end # unless
45
91
  @d = @d.stroke_antialias true
@@ -48,7 +94,7 @@ class Gruff::SideBar < Gruff::Base
48
94
 
49
95
  ##
50
96
  # Draw on the Y axis instead of the X
51
-
97
+
52
98
  def draw_label(y_offset, index)
53
99
  if !@labels[index].nil? && @labels_seen[index].nil?
54
100
  @d.fill = @font_color
@@ -65,53 +111,4 @@ class Gruff::SideBar < Gruff::Base
65
111
  end
66
112
  end
67
113
 
68
- def draw
69
- @has_left_labels = true
70
- super
71
-
72
- return unless @has_data
73
-
74
- # Setup spacing.
75
- #
76
- # Columns sit stacked.
77
- spacing_factor = 0.9
78
-
79
- @bar_width = @graph_height / @column_count.to_f
80
- @d = @d.stroke_opacity 0.0
81
- height = Array.new(@column_count, 0)
82
- length = Array.new(@column_count, @graph_left)
83
-
84
- @norm_data.each_with_index do |data_row, row_index|
85
- @d = @d.fill data_row[DATA_COLOR_INDEX]
86
-
87
- data_row[1].each_with_index do |data_point, point_index|
88
-
89
- # Using the original calcs from the stacked bar chart
90
- # to get the difference between
91
- # part of the bart chart we wish to stack.
92
- temp1 = @graph_left + (@graph_width -
93
- data_point * @graph_width -
94
- height[point_index]) + 1
95
- temp2 = @graph_left + @graph_width - height[point_index] - 1
96
- difference = temp2 - temp1
97
-
98
- left_x = length[point_index] #+ 1
99
- left_y = @graph_top + (@bar_width * point_index)
100
- right_x = left_x + difference
101
- right_y = left_y + @bar_width * spacing_factor
102
- length[point_index] += difference
103
- height[point_index] += (data_point * @graph_width - 2)
104
-
105
- @d = @d.rectangle(left_x, left_y, right_x, right_y)
106
-
107
- # Calculate center based on bar_width and current row
108
- label_center = @graph_top + (@bar_width * point_index) + (@bar_width * spacing_factor / 2.0)
109
- draw_label(label_center, point_index)
110
- end
111
-
112
- end
113
-
114
- @d.draw(@base_image)
115
- end
116
-
117
114
  end
@@ -1,121 +1,73 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+ require File.dirname(__FILE__) + '/side_bar'
3
+ require File.dirname(__FILE__) + '/stacked_mixin'
4
+
1
5
  ##
2
- # New gruff graph type added to enable sideways stacking bar charts (basically looks like a x/y
3
- # flip of a standard stacking bar chart)
6
+ # New gruff graph type added to enable sideways stacking bar charts
7
+ # (basically looks like a x/y flip of a standard stacking bar chart)
4
8
  #
5
9
  # alun.eyre@googlemail.com
6
- #
7
- require File.dirname(__FILE__) + '/base'
8
-
9
- class Gruff::SideStackedBar < Gruff::Base
10
-
11
- # instead of base class version, draws vertical background lines and label
12
- def draw_line_markers
13
10
 
14
- return if @hide_line_markers
11
+ class Gruff::SideStackedBar < Gruff::SideBar
12
+ include StackedMixin
15
13
 
16
- # Draw horizontal line markers and annotate with numbers
17
- @d = @d.stroke(@marker_color)
18
- @d = @d.stroke_width 1
19
- number_of_lines = 5
14
+ def draw
15
+ @has_left_labels = true
16
+ get_maximum_by_stack
17
+ super
20
18
 
21
- # TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
22
- increment = significant(@maximum_value.to_f / number_of_lines)
23
- (0..number_of_lines).each do |index|
19
+ return unless @has_data
24
20
 
25
- line_diff = (@graph_right - @graph_left) / number_of_lines
26
- x = @graph_right - (line_diff * index) - 1
27
- @d = @d.line(x, @graph_bottom, x, @graph_top)
21
+ # Setup spacing.
22
+ #
23
+ # Columns sit stacked.
24
+ spacing_factor = 0.9
28
25
 
29
- diff = index - number_of_lines
30
- marker_label = diff.abs * increment
26
+ @bar_width = @graph_height / @column_count.to_f
27
+ @d = @d.stroke_opacity 0.0
28
+ height = Array.new(@column_count, 0)
29
+ length = Array.new(@column_count, @graph_left)
31
30
 
32
- @d.fill = @marker_color
33
- @d.font = @font if @font
34
- @d.stroke = 'transparent'
35
- @d.pointsize = scale_fontsize(@marker_font_size)
36
- # @d.gravity = NorthGravity
37
- @d = @d.annotate_scaled( @base_image,
38
- 100, 20,
39
- x - (@marker_font_size/1.5), @graph_bottom + 40,
40
- marker_label.to_s, @scale)
31
+ @norm_data.each_with_index do |data_row, row_index|
32
+ @d = @d.fill data_row[DATA_COLOR_INDEX]
41
33
 
42
- end
43
- end
44
-
45
- # instead of base class version, modified to enable us to draw on the Y axis instead of X
46
- def draw_label(y_offset, index)
47
- if !@labels[index].nil? && @labels_seen[index].nil?
48
- @d.fill = @marker_color
49
- @d.font = @font if @font
50
- @d.stroke = 'transparent'
51
- @d.font_weight = NormalWeight
52
- @d.pointsize = scale_fontsize(@marker_font_size)
53
- @d.gravity = CenterGravity
54
- @d = @d.annotate_scaled(@base_image,
55
- 1, 1,
56
- @graph_left / 2, y_offset,
57
- @labels[index], @scale)
58
- @labels_seen[index] = 1
59
- end
60
- end
34
+ data_row[1].each_with_index do |data_point, point_index|
61
35
 
62
- def draw
63
- @has_left_labels = true
64
- get_maximum_by_stack
65
- super
36
+ ## using the original calcs from the stacked bar chart to get the difference between
37
+ ## part of the bart chart we wish to stack.
38
+ temp1 = @graph_left + (@graph_width -
39
+ data_point * @graph_width -
40
+ height[point_index]) + 1
41
+ temp2 = @graph_left + @graph_width - height[point_index] - 1
42
+ difference = temp2 - temp1
66
43
 
67
- return unless @has_data
44
+ left_x = length[point_index] #+ 1
45
+ left_y = @graph_top + (@bar_width * point_index)
46
+ right_x = left_x + difference
47
+ right_y = left_y + @bar_width * spacing_factor
48
+ length[point_index] += difference
49
+ height[point_index] += (data_point * @graph_width - 2)
68
50
 
69
- # Setup spacing.
70
- #
71
- # Columns sit stacked.
72
- spacing_factor = 0.9
73
-
74
- @bar_width = @graph_height / @column_count.to_f
75
- @d = @d.stroke_opacity 0.0
76
- height = Array.new(@column_count, 0)
77
- length = Array.new(@column_count, @graph_left)
78
-
79
- @norm_data.each_with_index do |data_row, row_index|
80
- @d = @d.fill data_row[DATA_COLOR_INDEX]
81
-
82
- data_row[1].each_with_index do |data_point, point_index|
83
-
84
- ## using the original calcs from the stacked bar chart to get the difference between
85
- ## part of the bart chart we wish to stack.
86
- temp1 = @graph_left + (@graph_width -
87
- data_point * @graph_width -
88
- height[point_index]) + 1
89
- temp2 = @graph_left + @graph_width - height[point_index] - 1
90
- difference = temp2 - temp1
91
-
92
- left_x = length[point_index] #+ 1
93
- left_y = @graph_top + (@bar_width * point_index)
94
- right_x = left_x + difference
95
- right_y = left_y + @bar_width * spacing_factor
96
- length[point_index] += difference
97
- height[point_index] += (data_point * @graph_width - 2)
98
-
99
- @d = @d.rectangle(left_x, left_y, right_x, right_y)
100
-
101
- # Calculate center based on bar_width and current row
102
- label_center = @graph_top + (@bar_width * point_index) + (@bar_width * spacing_factor / 2.0)
103
- draw_label(label_center, point_index)
104
- end
51
+ @d = @d.rectangle(left_x, left_y, right_x, right_y)
105
52
 
53
+ # Calculate center based on bar_width and current row
54
+ label_center = @graph_top + (@bar_width * point_index) + (@bar_width * spacing_factor / 2.0)
55
+ draw_label(label_center, point_index)
106
56
  end
107
57
 
108
- @d.draw(@base_image)
109
58
  end
110
59
 
111
- protected
60
+ @d.draw(@base_image)
61
+ end
112
62
 
113
- def larger_than_max?(data_point, index=0)
114
- max(data_point, index) > @maximum_value
115
- end
63
+ protected
116
64
 
117
- def max(data_point, index)
118
- @data.inject(0) {|sum, item| sum + item[1][index]}
119
- end
65
+ def larger_than_max?(data_point, index=0)
66
+ max(data_point, index) > @maximum_value
67
+ end
68
+
69
+ def max(data_point, index)
70
+ @data.inject(0) {|sum, item| sum + item[1][index]}
71
+ end
120
72
 
121
73
  end