jagthedrummer-scruffy 0.2.9 → 0.2.10

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt CHANGED
@@ -24,6 +24,7 @@ lib/scruffy/graph_state.rb
24
24
  lib/scruffy/helpers.rb
25
25
  lib/scruffy/helpers/canvas.rb
26
26
  lib/scruffy/helpers/layer_container.rb
27
+ lib/scruffy/helpers/marker_helper.rb
27
28
  lib/scruffy/helpers/meta.rb
28
29
  lib/scruffy/helpers/point_container.rb
29
30
  lib/scruffy/layers.rb
@@ -31,8 +32,11 @@ lib/scruffy/layers/all_smiles.rb
31
32
  lib/scruffy/layers/area.rb
32
33
  lib/scruffy/layers/average.rb
33
34
  lib/scruffy/layers/bar.rb
35
+ lib/scruffy/layers/box.rb
34
36
  lib/scruffy/layers/base.rb
35
37
  lib/scruffy/layers/line.rb
38
+ lib/scruffy/layers/multi.rb
39
+ lib/scruffy/layers/multi_bar.rb
36
40
  lib/scruffy/layers/pie.rb
37
41
  lib/scruffy/layers/pie_slice.rb
38
42
  lib/scruffy/layers/scatter.rb
@@ -51,6 +55,7 @@ lib/scruffy/renderers/reversed.rb
51
55
  lib/scruffy/renderers/sparkline.rb
52
56
  lib/scruffy/renderers/split.rb
53
57
  lib/scruffy/renderers/standard.rb
58
+ lib/scruffy/renderers/axis_legend.rb
54
59
  lib/scruffy/themes.rb
55
60
  lib/scruffy/version.rb
56
61
  script/console
@@ -16,15 +16,20 @@ module Scruffy
16
16
  end
17
17
  end
18
18
  unless options[:point_markers].nil?
19
- point_distance = bounds[:width] / (options[:point_markers].size - 1).to_f
20
-
19
+ # Updated to set the label in line with the point.
20
+ point_distance = bounds[:width] / (options[:point_markers].size).to_f
21
21
  (0...options[:point_markers].size).map do |idx|
22
- x_coord = point_distance * idx
22
+ x_coord = point_distance * idx + point_distance/2
23
+ if options[:point_markers_ticks]
24
+ svg.line(:x1 => x_coord, :y1 => 0, :x2 => x_coord, :y2 => -2, :style => "stroke:#{(options[:theme].marker || 'white').to_s}, stroke-width:1")
25
+ end
26
+
23
27
  svg.text(options[:point_markers][idx],
24
- :x => x_coord,
25
- :y => bounds[:height],
26
- 'font-size' => relative(90),
28
+ :x => 0,
29
+ :y => 0,
30
+ 'font-size' => options[:theme].marker_font_size || relative(90),
27
31
  'font-family' => options[:theme].font_family,
32
+ :transform => "translate(#{x_coord},#{bounds[:height]}) rotate(#{options[:point_markers_rotation] || 0})",
28
33
  :fill => (options[:theme].marker || 'white').to_s,
29
34
  'text-anchor' => 'middle') unless options[:point_markers][idx].nil?
30
35
  end
@@ -31,6 +31,7 @@ module Scruffy
31
31
  layer_options[:complexity] = options[:complexity]
32
32
  layer_options[:size] = [bounds[:width], bounds[:height]]
33
33
  layer_options[:color] = layer.preferred_color || layer.color || options[:theme].next_color
34
+ layer_options[:outline] = layer.preferred_outline || layer.outline || options[:theme].next_outline
34
35
  layer_options[:opacity] = opacity_for(idx)
35
36
  layer_options[:theme] = options[:theme]
36
37
 
@@ -13,6 +13,11 @@ module Scruffy
13
13
  each_marker(markers, options[:min_value], options[:max_value], bounds[:height], options, :value_formatter) do |label, y|
14
14
  svg.line(:x1 => 0, :y1 => y, :x2 => bounds[:width], :y2 => y, :style => "stroke: #{options[:theme].marker.to_s}; stroke-width: #{stroke_width};")
15
15
  end
16
+
17
+ #add a 0 line
18
+ y = (options[:max_value] * bounds[:height])/(options[:max_value] - options[:min_value])
19
+ svg.line(:x1 => 0, :y1 => y, :x2 => bounds[:width], :y2 => y, :style => "stroke: #{options[:theme].marker.to_s}; stroke-width: #{stroke_width};")
20
+
16
21
  end
17
22
  end
18
23
 
@@ -22,12 +27,25 @@ module Scruffy
22
27
  include Scruffy::Helpers::Marker
23
28
 
24
29
  def draw(svg, bounds, options={})
25
- markers = (options[:key_markers] || self.markers) || 5
26
-
27
- stroke_width = options[:stroke_width]
28
30
 
29
- each_marker(markers, options[:min_key], options[:max_key], bounds[:width], options, :key_formatter) do |label, x|
30
- svg.line(:x1 => x, :y1 => 0, :x2 => x, :y2 => bounds[:height], :style => "stroke: #{options[:theme].marker.to_s}; stroke-width: #{stroke_width};")
31
+ if options[:graph].point_markers #get vertical grid lines up with points if there are labels for them
32
+ point_distance = bounds[:width] / (options[:graph].point_markers.size).to_f
33
+ stroke_width = options[:stroke_width]
34
+ (0...options[:graph].point_markers.size).map do |idx|
35
+ x = point_distance * idx + point_distance/2
36
+ svg.line(:x1 => x, :y1 => 0, :x2 => x, :y2 => bounds[:height], :style => "stroke: #{options[:theme].marker.to_s}; stroke-width: #{stroke_width};")
37
+ end
38
+ #add the far right and far left lines
39
+ svg.line(:x1 => 0, :y1 => 0, :x2 => 0, :y2 => bounds[:height], :style => "stroke: #{options[:theme].marker.to_s}; stroke-width: #{stroke_width};")
40
+ svg.line(:x1 => bounds[:width], :y1 => 0, :x2 => bounds[:width], :y2 => bounds[:height], :style => "stroke: #{options[:theme].marker.to_s}; stroke-width: #{stroke_width};")
41
+ else
42
+
43
+ markers = (options[:key_markers] || self.markers) || 5 #options[:point_markers].size#
44
+ stroke_width = options[:stroke_width]
45
+ each_marker(markers, options[:min_key], options[:max_key], bounds[:width], options, :key_formatter) do |label, x|
46
+ svg.line(:x1 => x, :y1 => 0, :x2 => x, :y2 => bounds[:height], :style => "stroke: #{options[:theme].marker.to_s}; stroke-width: #{stroke_width};")
47
+ end
48
+
31
49
  end
32
50
  end
33
51
  end
@@ -1,5 +1,47 @@
1
1
  module Scruffy::Components
2
-
2
+
3
+ class XLegend < Base
4
+ def draw(svg, bounds, options={})
5
+ if options[:title]
6
+ svg.text(options[:x_legend],
7
+ :class => 'title',
8
+ :x => (bounds[:width] / 2),
9
+ :y => bounds[:height],
10
+ 'font-size' => options[:theme].legend_font_size || relative(100),
11
+ 'font-family' => options[:theme].font_family,
12
+ :fill => options[:theme].marker,
13
+ :stroke => 'none', 'stroke-width' => '0',
14
+ 'text-anchor' => (@options[:text_anchor] || 'middle'))
15
+ end
16
+ end
17
+ end #XLegend
18
+
19
+
20
+
21
+ class YLegend < Base
22
+ def draw(svg, bounds, options={})
23
+ if options[:title]
24
+ svg.text(options[:y_legend],
25
+ :class => 'title',
26
+ :x => (0),
27
+ :y => 0,
28
+ 'font-size' => options[:theme].legend_font_size || relative(100),
29
+ 'font-family' => options[:theme].font_family,
30
+ :transform => "translate(#{bounds[:width] / 2},#{bounds[:height]/2}) rotate(#{-90})",
31
+ :fill => options[:theme].marker,
32
+ :stroke => 'none', 'stroke-width' => '0',
33
+ 'text-anchor' => (@options[:text_anchor] || 'middle'))
34
+ end
35
+ end
36
+ end #YLegend
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
3
45
  class Legend < Base
4
46
  FONT_SIZE = 80
5
47
 
@@ -11,18 +53,18 @@ module Scruffy::Components
11
53
  set_line_height = 0.08 * bounds[:height]
12
54
  @line_height = bounds[:height] / legend_info.length
13
55
  @line_height = set_line_height if @line_height >
14
- set_line_height
56
+ set_line_height
15
57
  else
16
58
  set_line_height = 0.90 * bounds[:height]
17
59
  @line_height = set_line_height
18
60
  end
19
-
61
+
20
62
  text_height = @line_height * FONT_SIZE / 100
21
63
  # #TODO how does this related to @points?
22
64
  active_width, points = layout(legend_info, vertical)
23
-
65
+
24
66
  offset = (bounds[:width] - active_width) / 2 # Nudge over a bit for true centering
25
-
67
+
26
68
  # Render Legend
27
69
  points.each_with_index do |point, idx|
28
70
  if vertical
@@ -38,18 +80,18 @@ module Scruffy::Components
38
80
  # "#{x} #{y} #{@line_height} #{size}"
39
81
 
40
82
  svg.rect(:x => x,
41
- :y => y,
42
- :width => size,
43
- :height => size,
44
- :fill => legend_info[idx][:color])
45
-
83
+ :y => y,
84
+ :width => size,
85
+ :height => size,
86
+ :fill => legend_info[idx][:color])
87
+
46
88
  svg.text(legend_info[idx][:title],
47
- :x => x + @line_height,
48
- :y => y + text_height * 0.75,
89
+ :x => x + @line_height,
90
+ :y => y + text_height * 0.75,
49
91
  'font-size' => text_height,
50
92
  'font-family' => options[:theme].font_family,
51
- :style => "color: #{options[:theme].marker || 'white'}",
52
- :fill => (options[:theme].marker || 'white'))
93
+ :style => "color: #{options[:theme].marker || 'white'}",
94
+ :fill => (options[:theme].marker || 'white'))
53
95
  end
54
96
  end # draw
55
97
 
@@ -60,9 +102,9 @@ module Scruffy::Components
60
102
  def relevant_legend_info(layers, categories=(@options[:category] ? [@options[:category]] : @options[:categories]))
61
103
  legend_info = layers.inject([]) do |arr, layer|
62
104
  if categories.nil? ||
63
- (categories.include?(layer.options[:category]) ||
64
- (layer.options[:categories] && (categories & layer.options[:categories]).size > 0) )
65
-
105
+ (categories.include?(layer.options[:category]) ||
106
+ (layer.options[:categories] && (categories & layer.options[:categories]).size > 0) )
107
+
66
108
  data = layer.legend_data
67
109
  arr << data if data.is_a?(Hash)
68
110
  arr = arr + data if data.is_a?(Array)
@@ -70,7 +112,7 @@ module Scruffy::Components
70
112
  arr
71
113
  end
72
114
  end # relevant_legend_info
73
-
115
+
74
116
  # Returns an array consisting of the total width needed by the legend
75
117
  # information, as well as an array of @x-coords for each element. If
76
118
  # vertical, then these are @y-coords, and @x is 0
@@ -84,7 +126,7 @@ module Scruffy::Components
84
126
  longest = longest < cur_length ? cur_length : longest
85
127
  }
86
128
  y_positions = []
87
- (0..legend_info_array.length - 1).each {|y|
129
+ (0..legend_info_array.length - 1).each {|y|
88
130
  y_positions << y * @line_height
89
131
  }
90
132
  [longest, y_positions]
@@ -94,12 +136,12 @@ module Scruffy::Components
94
136
  enum[1] << enum.first # Add location to points
95
137
  enum[0] += relative(50) # Add room for color box
96
138
  enum[0] += (relative(50) * elem[:title].length) # Add room for text
97
-
139
+
98
140
  [enum.first, enum.last]
99
141
  end
100
142
  end
101
143
  end
102
-
144
+
103
145
  end # class Legend
104
146
 
105
147
  end # Scruffy::Components
@@ -7,7 +7,7 @@ module Scruffy
7
7
  :class => 'title',
8
8
  :x => (bounds[:width] / 2),
9
9
  :y => bounds[:height],
10
- 'font-size' => relative(100),
10
+ 'font-size' => options[:theme].title_font_size || relative(100),
11
11
  'font-family' => options[:theme].font_family,
12
12
  :fill => options[:theme].marker,
13
13
  :stroke => 'none', 'stroke-width' => '0',
@@ -10,10 +10,11 @@ module Scruffy
10
10
  markers = (options[:markers] || self.markers) || 5
11
11
 
12
12
  each_marker(markers, options[:min_value], options[:max_value], bounds[:height], options, :value_formatter) do |label, y|
13
+
13
14
  svg.text( label,
14
15
  :x => bounds[:width],
15
16
  :y => (bounds[:height] - y),
16
- 'font-size' => relative(8),
17
+ 'font-size' => options[:theme].marker_font_size || relative(8),
17
18
  'font-family' => options[:theme].font_family,
18
19
  :fill => ((options.delete(:marker_color_override) || options[:theme].marker) || 'white').to_s,
19
20
  'text-anchor' => 'end')
data/lib/scruffy/graph.rb CHANGED
@@ -79,12 +79,12 @@ module Scruffy
79
79
  include Scruffy::Helpers::LayerContainer
80
80
 
81
81
  # Delegating these getters to the internal state object.
82
- def_delegators :internal_state, :title, :theme, :default_type,
83
- :point_markers, :value_formatter, :rasterizer,
82
+ def_delegators :internal_state, :title,:x_legend,:y_legend, :theme, :default_type,
83
+ :point_markers,:point_markers_rotation,:point_markers_ticks, :value_formatter, :rasterizer,
84
84
  :key_formatter
85
85
 
86
- def_delegators :internal_state, :title=, :theme=, :default_type=,
87
- :point_markers=, :value_formatter=, :rasterizer=,
86
+ def_delegators :internal_state, :title=, :theme=,:x_legend=,:y_legend=, :default_type=,
87
+ :point_markers=,:point_markers_rotation=,:point_markers_ticks=, :value_formatter=, :rasterizer=,
88
88
  :key_formatter=
89
89
 
90
90
  attr_reader :renderer # Writer defined below
@@ -98,11 +98,15 @@ module Scruffy
98
98
  # Options:
99
99
  #
100
100
  # title:: Graph's title
101
+ # x_legend :: Title for X Axis
102
+ # y_legend :: Title for Y Axis
101
103
  # theme:: A theme object to use when rendering graph
102
104
  # layers:: An array of Layers for this graph to use
103
105
  # default_type:: A symbol indicating the default type of Layer for this graph
104
106
  # value_formatter:: Sets a formatter used to modify marker values prior to rendering
105
107
  # point_markers:: Sets the x-axis marker values
108
+ # point_markers_rotation:: Sets the angle of rotation for x-axis marker values
109
+ # point_markers_ticks:: Sets a small tick mark above each marker value. Helful when used with rotation.
106
110
  # rasterizer:: Sets the rasterizer to use when rendering to an image format. Defaults to RMagick.
107
111
  def initialize(*args)
108
112
  self.default_type = args.shift if args.first.is_a?(Symbol)
@@ -110,13 +114,15 @@ module Scruffy
110
114
  raise ArgumentError, "The arguments provided are not supported." if args.size > 0
111
115
 
112
116
  options ||= {}
117
+
118
+
113
119
  self.theme = Scruffy::Themes::Standard.new
114
120
  self.renderer = Scruffy::Renderers::Standard.new
115
121
  self.rasterizer = Scruffy::Rasterizers::RMagickRasterizer.new
116
122
  self.value_formatter = Scruffy::Formatters::Number.new
117
123
  self.key_formatter = Scruffy::Formatters::Number.new
118
124
 
119
- %w(title theme layers default_type value_formatter point_markers rasterizer key_formatter).each do |arg|
125
+ %w(title x_legend y_legend theme layers default_type value_formatter point_markers point_markers_rotation point_markers_ticks rasterizer key_formatter).each do |arg|
120
126
  self.send("#{arg}=".to_sym, options.delete(arg.to_sym)) unless options[arg.to_sym].nil?
121
127
  end
122
128
 
@@ -141,11 +147,15 @@ module Scruffy
141
147
  options[:value_formatter] ||= value_formatter
142
148
  options[:key_formatter] ||= key_formatter
143
149
  options[:point_markers] ||= point_markers
150
+ options[:point_markers_rotation] ||= point_markers_rotation
151
+ options[:point_markers_ticks] ||= point_markers_ticks
144
152
  options[:size] ||= (options[:width] ? [options[:width], (options.delete(:width) * 0.6).to_i] : [600, 360])
145
153
  options[:title] ||= title
154
+ options[:x_legend] ||= x_legend
155
+ options[:y_legend] ||= y_legend
146
156
  options[:layers] ||= layers
147
- options[:min_value] ||= bottom_value #(:padded)
148
- options[:max_value] ||= top_value
157
+ options[:min_value] ||= bottom_value(options[:padding] ? options[:padding] : nil)
158
+ options[:max_value] ||= top_value(options[:padding] ? options[:padding] : nil)
149
159
  options[:min_key] ||= bottom_key
150
160
  options[:max_key] ||= top_key
151
161
  options[:graph] ||= self
@@ -11,9 +11,13 @@ module Scruffy
11
11
  class GraphState
12
12
 
13
13
  attr_accessor :title
14
+ attr_accessor :x_legend
15
+ attr_accessor :y_legend
14
16
  attr_accessor :theme
15
17
  attr_accessor :default_type
16
18
  attr_accessor :point_markers
19
+ attr_accessor :point_markers_rotation
20
+ attr_accessor :point_markers_ticks
17
21
  attr_accessor :value_formatter
18
22
  attr_accessor :key_formatter
19
23
  attr_accessor :rasterizer
@@ -67,7 +67,9 @@ module Scruffy::Helpers
67
67
  # If padding is set to :padded, a 15% padding is added to the highest value.
68
68
  def top_value(padding=nil) # :nodoc:
69
69
  topval = layers.inject(0) { |max, layer| (max = ((max < layer.top_value) ? layer.top_value : max)) unless layer.top_value.nil?; max }
70
- padding == :padded ? (topval - ((topval - bottom_value) * 0.15)) : topval
70
+ below_zero = (topval <= 0)
71
+ topval = padding == :padded ? (topval + ((topval - bottom_value) * 0.15)) : topval
72
+ (below_zero && topval > 0) ? 0 : topval
71
73
  end
72
74
 
73
75
  # Returns the lowest value in any of this container's layers.
@@ -80,7 +82,7 @@ module Scruffy::Helpers
80
82
  (min = ((min > layer.bottom_value) ? layer.bottom_value : min)) unless layer.bottom_value.nil?
81
83
  min
82
84
  end
83
- above_zero = (botval > 0)
85
+ above_zero = (botval >= 0)
84
86
  botval = (botval - ((top_value - botval) * 0.15)) if padding == :padded
85
87
 
86
88
  # Don't introduce negative values solely due to padding.
@@ -11,7 +11,9 @@ module Scruffy::Helpers
11
11
  end
12
12
 
13
13
  all_values.size.times do |idx|
14
- location = idx.to_f * width/(markers-1)
14
+ dx = width/(markers - 1)
15
+
16
+ location = idx.to_f * dx #+ dx/2
15
17
  marker_value = all_values[idx]
16
18
  marker_value = options[format_key].route_format(marker_value, idx, options.merge({:all_values => all_values})) if options[format_key]
17
19
 
@@ -8,10 +8,22 @@ module Scruffy::Layers
8
8
  class Bar < Base
9
9
 
10
10
  # Draw bar graph.
11
+ # Now handles positive and negative values gracefully.
11
12
  def draw(svg, coords, options = {})
12
- coords.each do |coord|
13
- x, y, bar_height = (coord.first-(@bar_width * 0.5)), coord.last, (height - coord.last)
14
-
13
+ coords.each_with_index do |coord,idx|
14
+ x, y, bar_height = (coord.first), coord.last, 1#(height - coord.last)
15
+
16
+ valh = max_value + min_value * -1 #value_height
17
+ maxh = max_value * height / valh #positive area height
18
+ minh = min_value * height / valh #negative area height
19
+ #puts "height = #{height} and max_value = #{max_value} and min_value = #{min_value} and y = #{y} and point = #{points[idx]}"
20
+ if points[idx] > 0
21
+ bar_height = points[idx]*maxh/max_value
22
+ else
23
+ bar_height = points[idx]*minh/min_value
24
+ end
25
+
26
+ #puts " y = #{y} and point = #{points[idx]}"
15
27
  svg.g(:transform => "translate(-#{relative(0.5)}, -#{relative(0.5)})") {
16
28
  svg.rect( :x => x, :y => y, :width => @bar_width + relative(1), :height => bar_height + relative(1),
17
29
  :style => "fill: black; fill-opacity: 0.15; stroke: none;" )
@@ -34,13 +46,17 @@ module Scruffy::Layers
34
46
  # Unfortunately this just mean that bar-graphs and most other graphs
35
47
  # end up on different points. Maybe adding a padding to the coordinates
36
48
  # should be a graph-wide thing?
49
+ #
50
+ # Update : x-axis coords for lines and area charts should now line
51
+ # up with the center of bar charts.
52
+
37
53
  def generate_coordinates(options = {})
38
54
  @bar_width = (width / points.size) * 0.9
39
55
  options[:point_distance] = (width - (width / points.size)) / (points.size - 1).to_f
40
56
 
41
57
  #TODO more array work with index, try to rework to be accepting of hashes
42
58
  coords = (0...points.size).map do |idx|
43
- x_coord = (options[:point_distance] * idx) + (width / points.size * 0.5)
59
+ x_coord = (options[:point_distance] * idx) + (width / points.size * 0.5) - (@bar_width * 0.5)
44
60
 
45
61
  relative_percent = ((points[idx] == min_value) ? 0 : ((points[idx] - min_value) / (max_value - min_value).to_f))
46
62
  y_coord = (height - (height * relative_percent))
@@ -26,6 +26,7 @@ module Scruffy::Layers
26
26
  attr_accessor :points
27
27
  attr_accessor :relevant_data
28
28
  attr_accessor :preferred_color
29
+ attr_accessor :preferred_outline
29
30
  attr_accessor :options # On-the-fly values for easy customization / acts as attributes.
30
31
 
31
32
  # The following attributes are set during the layer's render process,
@@ -34,6 +35,7 @@ module Scruffy::Layers
34
35
  attr_reader :height, :width
35
36
  attr_reader :min_value, :max_value
36
37
  attr_reader :color
38
+ attr_reader :outline
37
39
  attr_reader :opacity
38
40
  attr_reader :complexity
39
41
 
@@ -47,6 +49,7 @@ module Scruffy::Layers
47
49
  # title:: Name/title of data group
48
50
  # points:: Array of data points
49
51
  # preferred_color:: Color used to render this graph, overrides theme color.
52
+ # preferred_outline:: Color used to render this graph outline, overrides theme outline.
50
53
  # relevant_data:: Rarely used - indicates the data on this graph should not
51
54
  # included in any graph data aggregations, such as averaging data points.
52
55
  # style:: SVG polyline style. (default: 'fill-opacity: 0; stroke-opacity: 0.35')
@@ -57,6 +60,7 @@ module Scruffy::Layers
57
60
  def initialize(options = {})
58
61
  @title = options.delete(:title) || ''
59
62
  @preferred_color = options.delete(:color)
63
+ @preferred_outline = options.delete(:outline)
60
64
  @relevant_data = options.delete(:relevant_data) || true
61
65
  @points = options.delete(:points) || []
62
66
  @points.extend Scruffy::Helpers::PointContainer unless @points.kind_of? Scruffy::Helpers::PointContainer
@@ -145,6 +149,7 @@ module Scruffy::Layers
145
149
  # itself.
146
150
  def setup_variables(options = {})
147
151
  @color = (preferred_color || options.delete(:color))
152
+ @outline = (preferred_outline || options.delete(:outline))
148
153
  @width, @height = options.delete(:size)
149
154
  @min_value, @max_value = options[:min_value], options[:max_value]
150
155
  @opacity = options[:opacity] || 1.0
@@ -154,15 +159,19 @@ module Scruffy::Layers
154
159
  # Optimistic generation of coordinates for layer to use. These coordinates are
155
160
  # just a best guess, and can be overridden or thrown away (for example, this is overridden
156
161
  # in pie charting and bar charts).
162
+
163
+ # Updated : Assuming n number of points, the graph is divided into n rectangles
164
+ # and the points are plotted in the middle of each rectangle. This allows bars to
165
+ # play nice with lines.
157
166
  def generate_coordinates(options = {})
158
167
 
159
- dy = height.to_f / (options[:max_value] - options[:min_value])
160
- dx = width.to_f / (options[:max_key] - options[:min_key])
168
+ dy = height.to_f / (options[:max_value] - options[:min_value])
169
+ dx = width.to_f / (options[:max_key] - options[:min_key] + 1)
161
170
 
162
171
  ret = []
163
172
  points.each_point do |x, y|
164
173
  if y
165
- x_coord = dx * (x - options[:min_key])
174
+ x_coord = dx * (x - options[:min_key]) + dx/2
166
175
  y_coord = dy * (y - options[:min_value])
167
176
 
168
177
  ret << [x_coord, height - y_coord]
@@ -17,9 +17,12 @@ require 'scruffy/layers/base'
17
17
  require 'scruffy/layers/area'
18
18
  require 'scruffy/layers/all_smiles'
19
19
  require 'scruffy/layers/bar'
20
+ require 'scruffy/layers/box'
20
21
  require 'scruffy/layers/line'
21
22
  require 'scruffy/layers/average'
22
23
  require 'scruffy/layers/stacked'
24
+ require 'scruffy/layers/multi'
25
+ require 'scruffy/layers/multi_bar'
23
26
  require 'scruffy/layers/pie'
24
27
  require 'scruffy/layers/pie_slice'
25
28
  require 'scruffy/layers/scatter'
@@ -4,12 +4,12 @@ module Scruffy::Renderers
4
4
  def define_layout
5
5
  super do |components|
6
6
  components << Scruffy::Components::Title.new(:title, :position => [5, 2], :size => [90, 7])
7
- components << Scruffy::Components::Viewport.new(:view, :position => [2, 26], :size => [89, 66]) do |graph|
8
- graph << Scruffy::Components::ValueMarkers.new(:values, :position => [0, 2], :size => [18, 89])
9
- graph << Scruffy::Components::Grid.new(:grid, :position => [20, 0], :size => [80, 89], :stroke_width => 1)
10
- graph << Scruffy::Components::VGrid.new(:vgrid, :position => [20, 0], :size => [80, 89], :stroke_width => 1)
11
- graph << Scruffy::Components::DataMarkers.new(:labels, :position => [20, 92], :size => [80, 8])
12
- graph << Scruffy::Components::Graphs.new(:graphs, :position => [20, 0], :size => [80, 89])
7
+ components << Scruffy::Components::Viewport.new(:view, :position => [2, 26], :size => [90, 66]) do |graph|
8
+ graph << Scruffy::Components::ValueMarkers.new(:values, :position => [0, 2], :size => [8, 89])
9
+ graph << Scruffy::Components::Grid.new(:grid, :position => [10, 0], :size => [90, 89], :stroke_width => 1)
10
+ graph << Scruffy::Components::VGrid.new(:vgrid, :position => [10, 0], :size => [90, 89], :stroke_width => 1)
11
+ graph << Scruffy::Components::DataMarkers.new(:labels, :position => [10, 92], :size => [90, 8])
12
+ graph << Scruffy::Components::Graphs.new(:graphs, :position => [10, 0], :size => [90, 89])
13
13
  end
14
14
  components << Scruffy::Components::Legend.new(:legend, :position => [5, 13], :size => [90, 6])
15
15
  end
@@ -15,6 +15,7 @@ module Scruffy::Renderers; end
15
15
  require 'scruffy/renderers/base'
16
16
  require 'scruffy/renderers/empty'
17
17
  require 'scruffy/renderers/standard'
18
+ require 'scruffy/renderers/axis_legend'
18
19
  require 'scruffy/renderers/reversed'
19
20
  require 'scruffy/renderers/cubed'
20
21
  require 'scruffy/renderers/split'
@@ -19,8 +19,12 @@ module Scruffy::Themes
19
19
  class Base
20
20
  attr_accessor :background # Background color or array of two colors
21
21
  attr_accessor :colors # Array of colors for data graphs
22
+ attr_accessor :outlines # Array of colors for outlines of elements for data graphs
22
23
  attr_accessor :marker # Marker color for grid lines, values, etc.
23
24
  attr_accessor :font_family # Font family: Not really supported. Maybe in the future.
25
+ attr_accessor :marker_font_size # Marker Font Size:
26
+ attr_accessor :title_font_size # Title Font Size:
27
+ attr_accessor :legend_font_size # Legend Font Size:
24
28
 
25
29
  # Returns a new Scruffy::Themes::Base object.
26
30
  #
@@ -34,8 +38,12 @@ module Scruffy::Themes
34
38
  def initialize(descriptor)
35
39
  self.background = descriptor[:background]
36
40
  self.colors = descriptor[:colors]
41
+ self.outlines = descriptor[:outlines]
37
42
  self.marker = descriptor[:marker]
38
43
  self.font_family = descriptor[:font_family]
44
+ self.marker_font_size = descriptor[:marker_font_size]
45
+ self.title_font_size = descriptor[:title_font_size]
46
+ self.legend_font_size = descriptor[:legend_font_size]
39
47
  end
40
48
 
41
49
  # Returns the next available color in the color array.
@@ -45,6 +53,17 @@ module Scruffy::Themes
45
53
 
46
54
  self.colors[(@previous_color-1) % self.colors.size]
47
55
  end
56
+
57
+
58
+ # Returns the next available outline in the outline array.
59
+ def next_outline
60
+ @previous_outline = 0 if @previous_outline.nil?
61
+ @previous_outline += 1
62
+ if self.outlines.nil?
63
+ return "#000000"
64
+ end
65
+ self.outlines[(@previous_outline-1) % self.outlines.size]
66
+ end
48
67
 
49
68
  # todo: Implement darken function.
50
69
  def darken(color, shift=20); end
@@ -49,6 +49,43 @@ class GraphCreationTest < Test::Unit::TestCase
49
49
  graph.render :to => "#{WEBSITE_DIR}/line_test.svg"
50
50
  graph.render :width => 400, :to => "#{WEBSITE_DIR}/line_test.png", :as => 'png' if $make_png
51
51
  end
52
+
53
+
54
+ def test_create_line_with_negatives
55
+ graph = Scruffy::Graph.new
56
+ graph.title = "Sample Line Graph"
57
+ graph.renderer = Scruffy::Renderers::Standard.new
58
+
59
+ graph.add :line, 'Example', [-20, 100, -70, -30, 106]
60
+ theme = Scruffy::Themes::Base.new :background=>"#ffffff", :marker=>"#444444",
61
+ :colors=>["#4f83bf","#be514e","#a1ba5e","#82649a"],
62
+ :title_font_size => 30, :marker_font_size=>10
63
+ graph.render :to => "#{WEBSITE_DIR}/line_test_with_negatives.svg",:theme=>theme
64
+ graph.render :width => 400, :to => "#{WEBSITE_DIR}/line_test_with_negatives.png",:theme=>theme, :as => 'png' if $make_png
65
+ end
66
+
67
+
68
+ def test_create_negative_line
69
+ graph = Scruffy::Graph.new
70
+ graph.title = "Sample Line Graph"
71
+ graph.renderer = Scruffy::Renderers::Standard.new
72
+
73
+ graph.add :line, 'Example', [-20, -100, -70, -30, -106]
74
+ theme = Scruffy::Themes::Apples.new
75
+ graph.render :to => "#{WEBSITE_DIR}/negative_line_test.svg",:theme=>theme
76
+ graph.render :width => 600,:theme=>theme, :to => "#{WEBSITE_DIR}/negative_line_test.png", :as => 'png' if $make_png
77
+ end
78
+
79
+ def test_create_small_value_line
80
+ graph = Scruffy::Graph.new
81
+ graph.title = "Sample Line Graph"
82
+ graph.renderer = Scruffy::Renderers::Standard.new
83
+ graph.value_formatter = Scruffy::Formatters::Number.new(:precision => 1)
84
+ graph.add :line, 'Example', [0.2,0.5,0.1,0.9,0.8,1.2,0.05,1]
85
+
86
+ graph.render :to => "#{WEBSITE_DIR}/small_value_line_test.svg"
87
+ graph.render :width => 400, :to => "#{WEBSITE_DIR}/small_value_line_test.png", :as => 'png' if $make_png
88
+ end
52
89
 
53
90
 
54
91
  def test_create_bar
@@ -60,6 +97,34 @@ class GraphCreationTest < Test::Unit::TestCase
60
97
  graph.render :width => 400, :to => "#{WEBSITE_DIR}/bar_test.png", :as => 'png' if $make_png
61
98
  end
62
99
 
100
+
101
+
102
+
103
+ def test_create_bar_with_negatives
104
+ graph = Scruffy::Graph.new
105
+ graph.title = "Sample Bar Graph"
106
+ graph.renderer = Scruffy::Renderers::Standard.new
107
+ graph.add :bar, 'Example', [20, 100,-10, 70, 30, -40, 106]
108
+ graph.render :to => "#{WEBSITE_DIR}/negative_bar_test.svg"
109
+ graph.render :width => 400, :to => "#{WEBSITE_DIR}/negative_bar_test.png", :as => 'png' if $make_png
110
+ end
111
+
112
+
113
+ def test_create_bar_with_all_negatives
114
+ graph = Scruffy::Graph.new
115
+ graph.title = "Sample Bar Graph"
116
+ graph.renderer = Scruffy::Renderers::Standard.new
117
+ graph.add :bar, 'Example', [-20, -100,-10, -70, -30, -40, -106]
118
+
119
+ theme = Scruffy::Themes::Base.new :background=>"#ffffff", :marker=>"#444444",
120
+ :colors=>["#ff0000","#00ff00","#0000ff","#cccccc"],
121
+ :title_font_size => 30, :marker_font_size=>10
122
+
123
+ graph.render :to => "#{WEBSITE_DIR}/all_negative_bar_test.svg",:theme=>theme
124
+ graph.render :width => 400,:theme=>theme, :to => "#{WEBSITE_DIR}/all_negative_bar_test.png", :as => 'png' if $make_png
125
+ end
126
+
127
+
63
128
  def test_split
64
129
  graph = Scruffy::Graph.new
65
130
  graph.title = "Long-term Comparisons"
@@ -91,6 +156,93 @@ class GraphCreationTest < Test::Unit::TestCase
91
156
  graph.render :width => 500, :to => "#{WEBSITE_DIR}/stacking_test.png", :as => 'png' if $make_png
92
157
  end
93
158
 
159
+
160
+ def test_reg_multi_bar
161
+ graph = Scruffy::Graph.new
162
+ graph.title = "Comparative Agent Performance"
163
+ graph.value_formatter = Scruffy::Formatters::Percentage.new(:precision => 0)
164
+ #graph.add :multi do |multi|
165
+ graph.add :bar, 'Jack', [30, 60, 49, 29, 100, 120]
166
+ graph.add :bar, 'Jill', [120, 240, 0, 100, 140, 20]
167
+ graph.add :bar, 'Hill', [10, 10, 90, 20, 40, 10]
168
+ #end
169
+ graph.point_markers = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
170
+ graph.render :to => "#{WEBSITE_DIR}/reg_multi_bar_test.svg"
171
+ graph.render :width => 500, :to => "#{WEBSITE_DIR}/reg_multi_bar_test.png", :as => 'png' if $make_png
172
+ end
173
+
174
+ def test_multi_bar
175
+ graph = Scruffy::Graph.new
176
+ graph.title = "Comparative Agent Performance"
177
+ graph.value_formatter = Scruffy::Formatters::Percentage.new(:precision => 0)
178
+ graph.add :multi do |multi|
179
+ multi.add :multi_bar, 'Jack', [30, 60, 49, 29, 100, 120]
180
+ multi.add :multi_bar, 'Jill', [120, 240, 0, 100, 140, 20]
181
+ multi.add :multi_bar, 'Hill', [10, 10, 90, 20, 40, 10]
182
+ multi.add :multi_bar, 'Bob', [-10, -20, -30, -40, -50, -60]
183
+ end
184
+ graph.point_markers = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
185
+ graph.point_markers_ticks = true
186
+ theme = Scruffy::Themes::Base.new :background=>"#ffffff", :marker=>"#444444",
187
+ :colors=>["#cccccc","#ff0000","#00ff00","#0000ff"],
188
+ :title_font_size => 30, :marker_font_size=>10
189
+
190
+ graph.render :to => "#{WEBSITE_DIR}/multi_bar_test.svg",:theme=>theme
191
+
192
+ graph.render :width => 900,:theme=>theme, :to => "#{WEBSITE_DIR}/multi_bar_test.png", :as => 'png' if $make_png
193
+ end
194
+
195
+
196
+ def test_box_plot
197
+ graph = Scruffy::Graph.new()
198
+ graph.title = "Box Plot Test"
199
+ graph.x_legend = "Time in Seconds"
200
+ graph.y_legend = "Inces of Rain"
201
+ graph.value_formatter = Scruffy::Formatters::Percentage.new(:precision => 0)
202
+ graph.add :box, "Test Data", [
203
+ [10,8,6.2,4,2],
204
+ [12,9,8.2,4.2,3.5],
205
+ [10,8,5.3,4,2],
206
+ [12,9,8.2,4.2,3.5],
207
+ [10,8,6.6,4,2],
208
+ [12,9,8.2,4.2,3.5]
209
+ ]
210
+
211
+ graph.point_markers = ['Jan', 'Feb','Jan', 'Feb','Jan', 'Feb']
212
+ graph.point_markers_ticks = true
213
+ graph.renderer = Scruffy::Renderers::AxisLegend.new
214
+
215
+ theme = Scruffy::Themes::Base.new :background=>"#ffffff", :marker=>"#aaaaaa",
216
+ :colors=>["#4f83bf","#be514e","#a1ba5e","#82649a"],
217
+ :legend_font_size=>30,
218
+ :title_font_size=>40,
219
+ :marker_font_size=>20,
220
+ :outlines=>["#be514e","#a1ba5e","#82649a","#4f83bf"]
221
+ graph.render :to => "#{WEBSITE_DIR}/box_plot_test.svg",:padding=>:padded,:theme=>theme,:key_markers=>8
222
+ graph.render :size => [600,540],:theme=>theme,:key_markers=>7, :to => "#{WEBSITE_DIR}/box_plot_test.png", :as => 'png',:padding=>:padded if $make_png
223
+ end
224
+
225
+
226
+
227
+ def test_rotated_point_markers
228
+ graph = Scruffy::Graph.new({:point_markers_rotation=>30}) #
229
+ graph.title = "Comparative Agent Performance"
230
+ graph.value_formatter = Scruffy::Formatters::Percentage.new(:precision => 0)
231
+ graph.add :stacked do |stacked|
232
+ stacked.add :bar, 'Jack', [30, 60, 49, 29, 100, 120]
233
+ stacked.add :bar, 'Jill', [120, 240, 0, 100, 140, 20]
234
+ stacked.add :bar, 'Hill', [10, 10, 90, 20, 40, 10]
235
+ end
236
+ graph.point_markers = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
237
+ graph.point_markers_ticks = true
238
+ #Rotation was set when the graph was created
239
+ #You can also do something like this
240
+ #graph.point_markers_rotation = 90
241
+ graph.render :to => "#{WEBSITE_DIR}/rotated_point_markers_test.svg"
242
+ graph.render :width => 500, :to => "#{WEBSITE_DIR}/rotated_point_markers_test.png", :as => 'png' if $make_png
243
+ end
244
+
245
+
94
246
  def test_multi_layered
95
247
  graph = Scruffy::Graph.new
96
248
  graph.title = "Some Kind of Information"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jagthedrummer-scruffy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.9
4
+ version: 0.2.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brasten Sager