gruff 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
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