lib/sparklines.rb in sparklines-0.4.0 vs lib/sparklines.rb in sparklines-0.4.1
- old
+ new
@@ -1,9 +1,8 @@
require 'rubygems'
require 'RMagick'
-require 'mathn'
=begin rdoc
A library for generating small unmarked graphs (sparklines).
@@ -54,10 +53,11 @@
area
discrete
pie
smooth
bar
+ whisker
General Defaults:
:type => 'smooth'
:height => 14px
@@ -72,11 +72,11 @@
Licensed under the MIT license.
=end
class Sparklines
- VERSION = '0.4.0'
+ VERSION = '0.4.1'
@@label_margin = 5.0
@@pointsize = 10.0
class << self
@@ -107,21 +107,21 @@
:has_last => false,
:label => nil
}
- # Hack for HashWithIndifferentAccess
+ # HACK for HashWithIndifferentAccess
options_sym = Hash.new
options.keys.each do |key|
options_sym[key.to_sym] = options[key]
end
options_sym = defaults.merge(options_sym)
# Call the appropriate method for actual plotting.
sparkline = self.new(data, options_sym)
- if %w(area bar pie smooth discrete).include? options_sym[:type]
+ if %w(area bar pie smooth discrete whisker).include? options_sym[:type]
sparkline.send options_sym[:type]
else
sparkline.plot_error options_sym
end
end
@@ -131,18 +131,19 @@
File.open( filename, 'wb' ) do |png|
png << self.plot( data, options)
end
end
- end
+ end # class methods
def initialize(data=[], options={})
@data = Array(data)
@options = options
normalize_data
end
+ ##
# Creates a continuous area sparkline. Relevant options.
#
# :step - An integer that determines the distance between each point on the sparkline. Defaults to 2.
#
# :height - An integer that determines what the height of the sparkline will be. Defaults to 14
@@ -162,10 +163,11 @@
# :last_color - A string or color code representing the color that the dot drawn at the last value will be displayed as. Defaults to red.
#
# :above_color - A string or color code representing the color to draw values above or equal the upper value. Defaults to red.
#
# :below_color - A string or color code representing the color to draw values below the upper value. Defaults to gray.
+
def area
step = @options[:step].to_i
height = @options[:height].to_i
background_color = @options[:background_color]
@@ -229,13 +231,13 @@
@draw.draw(@canvas)
@canvas.to_blob
end
+ ##
+ # A bar graph.
- # Draws a bar graph.
- #
def bar
step = @options[:step].to_i
height = @options[:height].to_f
background_color = @options[:background_color]
@@ -258,19 +260,21 @@
@draw.draw(@canvas)
@canvas.to_blob
end
+ ##
# Creates a discretized sparkline
#
# :height - An integer that determines what the height of the sparkline will be. Defaults to 14
#
# :upper - An integer that determines the threshold for colorization purposes. Any value less than upper will be colored using below_color, anything above and equal to upper will use above_color. Defaults to 50.
#
# :above_color - A string or color code representing the color to draw values above or equal the upper value. Defaults to red.
#
# :below_color - A string or color code representing the color to draw values below the upper value. Defaults to gray.
+
def discrete
height = @options[:height].to_i
upper = @options[:upper].to_i
background_color = @options[:background_color]
@@ -293,19 +297,20 @@
@draw.draw(@canvas)
@canvas.to_blob
end
+ ##
# Creates a pie-chart sparkline
#
# :diameter - An integer that determines what the size of the sparkline will be. Defaults to 20
#
# :share_color - A string or color code representing the color to draw the share of the pie represented by percent. Defaults to red.
#
# :remain_color - A string or color code representing the color to draw the pie not taken by the share color. Defaults to lightgrey.
- def pie
+ def pie
diameter = @options[:diameter].to_i
background_color = @options[:background_color]
create_canvas(diameter, diameter, background_color)
@@ -360,10 +365,11 @@
@draw.draw(@canvas)
@canvas.to_blob
end
+ ##
# Creates a smooth sparkline.
#
# :step - An integer that determines the distance between each point on the sparkline. Defaults to 2.
#
# :height - An integer that determines what the height of the sparkline will be. Defaults to 14
@@ -377,10 +383,11 @@
# :min_color - A string or color code representing the color that the dot drawn at the smallest value will be displayed as. Defaults to blue.
#
# :max_color - A string or color code representing the color that the dot drawn at the largest value will be displayed as. Defaults to green.
#
# :last_color - A string or color code representing the color that the dot drawn at the last value will be displayed as. Defaults to red.
+
def smooth
step = @options[:step].to_i
height = @options[:height].to_i
background_color = @options[:background_color]
@@ -414,11 +421,69 @@
@draw.draw(@canvas)
@canvas.to_blob
end
+ ##
+ # Creates a whisker sparkline to track on/off type data. There are five states:
+ # on, off, no value, exceptional on, exceptional off. On values create an up
+ # whisker and off values create a down whisker. Exceptional values may be
+ # colored differently than regular values to indicate, for example, a shut out.
+ # No value produces an empty row to indicate a tie.
+ #
+ # * results - an array of integer values between -2 and 2. -2 is exceptional
+ # down, 1 is regular down, 0 is no value, 1 is up, and 2 is exceptional up.
+ # * options - a hash that takes parameters
+ #
+ # :height - height of the sparkline
+ #
+ # :whisker_color - the color of regular whiskers; defaults to black
+ #
+ # :exception_color - the color of exceptional whiskers; defaults to red
+
+ def whisker
+
+ # step = @options[:step].to_i
+ height = @options[:height].to_i
+ background_color = @options[:background_color]
+
+ create_canvas((@data.size - 1) * 2, height, background_color)
+
+ whisker_color = @options[:whisker_color] || 'black'
+ exception_color = @options[:exception_color] || 'red'
+
+ i = 0
+ @data.each do |r|
+ color = whisker_color
+
+ if ( (r == 2 || r == -2) && exception_color )
+ color = exception_color
+ end
+
+ y_mid_point = (r >= 1) ? (@canvas.rows/2.0 - 1).ceil : (@canvas.rows/2.0).floor
+
+ y_end_point = y_mid_point
+ if ( r > 0)
+ y_end_point = 0
+ end
+
+ if ( r < 0 )
+ y_end_point = @canvas.rows
+ end
+
+ @draw.stroke( color )
+ @draw.line( i, y_mid_point, i, y_end_point )
+ i += 2
+ end
+
+ @draw.draw(@canvas)
+ @canvas.to_blob
+ end
+
+ ##
# Draw the error Sparkline.
+
def plot_error(options={})
create_canvas(40, 15, 'white')
@draw.fill('red')
@draw.line(0,0,40,15)
@@ -437,65 +502,71 @@
else
@norm_data = @data.map { |value| value = (value.to_f / @maximum_value) * 100.0 }
end
end
- # * arr - an array of points (represented as two element arrays)
+ ##
+ # * :arr - an array of points (represented as two element arrays)
+
def open_ended_polyline(arr)
0.upto(arr.length - 2) { |i|
@draw.line(arr[i][0], arr[i][1], arr[i+1][0], arr[i+1][1])
}
end
+ ##
# Create an image to draw on and a drawable to do the drawing with.
#
- # TODO Refactor into smaller functions
+ # TODO Refactor into smaller methods
+
def create_canvas(w, h, bkg_col)
@draw = Magick::Draw.new
@draw.pointsize = @@pointsize # TODO Use height
@canvas = Magick::Image.new(w , h) { self.background_color = bkg_col }
-
+
# Make room for label and last value
- if !@options[:label].nil?
+ unless @options[:label].nil?
@options[:has_last] = true
@label_width = calculate_width(@options[:label])
@data_last_width = calculate_width(@data.last)
# HACK The 7.0 is a severe hack. Must figure out correct spacing
@label_and_data_last_width = @label_width + @data_last_width + @@label_margin * 7.0
w += @label_and_data_last_width
end
-
+
@canvas = Magick::Image.new(w , h) { self.background_color = bkg_col }
@canvas.format = "PNG"
-
+
# Draw label and last value
- if !@options[:label].nil?
+ unless @options[:label].nil?
if ENV.has_key?('MAGICK_FONT_PATH')
vera_font_path = File.expand_path('Vera.ttf', ENV['MAGICK_FONT_PATH'])
@font = File.exists?(vera_font_path) ? vera_font_path : nil
else
@font = nil
end
-
+
@draw.fill = 'black'
@draw.font = @font if @font
@draw.gravity = Magick::WestGravity
@draw.annotate( @canvas,
@label_width, 1.0,
w - @label_and_data_last_width + @@label_margin, h - calculate_caps_height/2.0,
@options[:label])
-
+
@draw.fill = 'red'
@draw.annotate( @canvas,
@data_last_width, 1.0,
w - @data_last_width - @@label_margin * 2.0, h - calculate_caps_height/2.0,
@data.last.to_s)
end
end
-
+
+ ##
# Utility to draw a coloured box
# Centred on pt, offset off in each direction, fill color is col
+
def drawbox(pt, offset, color)
@draw.stroke 'transparent'
@draw.fill(color)
@draw.rectangle(pt[0]-offset, pt[1]-offset, pt[0]+offset, pt[1]+offset)
end
@@ -505,8 +576,7 @@
end
def calculate_caps_height
@draw.get_type_metrics(@canvas, 'X').height
end
-
end