jagthedrummer-scruffy 0.2.9 → 0.2.10

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/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