lib/sparklines.rb in sparklines-0.4.8 vs lib/sparklines.rb in sparklines-0.5.0

- old
+ new

@@ -53,10 +53,11 @@ area discrete pie smooth bar + bullet whisker General Defaults: :type => 'smooth' @@ -72,21 +73,21 @@ Licensed under the MIT license. =end class Sparklines - VERSION = '0.4.8' + VERSION = '0.5.0' @@label_margin = 5.0 @@pointsize = 10.0 class << self - # Does the actual plotting of the graph. - # Calls the appropriate subclass based on the :type argument. - # Defaults to 'smooth' - def plot(data=[], options={}) + ## + # Plots a sparkline and returns a Magic::Image object. + + def plot_to_image(data=[], options={}) defaults = { :type => 'smooth', :height => 14, :upper => 50, :diameter => 20, @@ -126,11 +127,24 @@ else sparkline.plot_error options_sym end end - # Writes a graph to disk with the specified filename, or "sparklines.png" + ## + # Does the actual plotting of the graph. + # Calls the appropriate subclass based on the :type argument. + # Defaults to 'smooth'. + # + # Returns a blob. + + def plot(data=[], options={}) + plot_to_image(data, options).to_blob + end + + ## + # Writes a graph to disk with the specified filename, or "sparklines.png". + def plot_to_file(filename="sparklines.png", data=[], options={}) File.open( filename, 'wb' ) do |png| png << self.plot( data, options) end end @@ -230,11 +244,11 @@ drawbox(coords[@norm_data.index(@norm_data.max)+1], 1, max_color) if has_max == true drawbox(coords[-2], 1, last_color) if has_last == true @draw.draw(@canvas) - @canvas.to_blob + @canvas end ## # A bar graph. @@ -258,11 +272,11 @@ i + step - 2, @canvas.rows - ( (r / @maximum_value) * @canvas.rows) ) i += step end @draw.draw(@canvas) - @canvas.to_blob + @canvas end ## # Creates a discretized sparkline @@ -300,11 +314,11 @@ i, (@canvas.rows - r/(101.0/(height-4))).to_f) i += step end @draw.draw(@canvas) - @canvas.to_blob + @canvas end ## # Creates a pie-chart sparkline @@ -333,16 +347,16 @@ # Special exceptions if percent == 0 # For 0% return blank @draw.draw(@canvas) - return @canvas.to_blob + return @canvas elsif percent == 100 # For 100% just draw a full circle @draw.ellipse(r + 2, r + 2, r , r , 0, 360) @draw.draw(@canvas) - return @canvas.to_blob + return @canvas end # Okay, this part is as confusing as hell, so pay attention: # This line determines the horizontal portion of the point on the circle where the X-Axis # should end. It's caculated by taking the center of the on-image circle and adding that @@ -368,15 +382,15 @@ # More info on the SVG path string format at: http://www.w3.org/TR/SVG/paths.html path = "M#{r + 2},#{r + 2} h#{r} A#{r},#{r} 0 #{large_arc_flag},1 #{arc_end_x},#{arc_end_y} z" @draw.path(path) @draw.draw(@canvas) - @canvas.to_blob + @canvas end ## - # Creates a smooth sparkline. + # Creates a smooth line graph 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 # @@ -395,10 +409,15 @@ # :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. # # :std_dev_color - A string or color code representing the color that the standard deviation bar behind the smooth graph will be displayed as. Defaults to #efefef # # :underneath_color - A string or color code representing the color that will be used to fill in the area underneath the line. Optional. + # + # :target - A 1px horizontal line will be drawn at this value. Useful for showing an average. + # + # :target_color - Color of the target line. Defaults to white. + def smooth step = @options[:step].to_f height = @options[:height].to_f width = ((@norm_data.size - 1) * step).to_f @@ -414,10 +433,13 @@ has_last = @options[:has_last] line_color = @options[:line_color] has_std_dev = @options[:has_std_dev] std_dev_color = @options[:std_dev_color] + target = @options.has_key?(:target) ? @options[:target].to_f : nil + target_color = @options[:target_color] || 'white' + drawstddevbox(width,height,std_dev_color) if has_std_dev == true @draw.stroke(line_color) coords = [] i=0 @@ -430,16 +452,23 @@ closed_polygon(height, width, coords) else open_ended_polyline(coords) end + unless target.nil? + normalized_target_value = ((target.to_f - @minimum_value)/(@maximum_value - @minimum_value)) * 100.0 + adjusted_target_value = (height - 3 - normalized_target_value/(101.0/(height-4))).to_i + @draw.stroke(target_color) + open_ended_polyline([[-5, adjusted_target_value], [width + 5, adjusted_target_value]]) + end + drawbox(coords[@norm_data.index(@norm_data.min)], 2, min_color) if has_min == true drawbox(coords[@norm_data.index(@norm_data.max)], 2, max_color) if has_max == true drawbox(coords[-1], 2, last_color) if has_last == true @draw.draw(@canvas) - @canvas.to_blob + @canvas 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 @@ -457,15 +486,15 @@ # # :exception_color - the color of exceptional whiskers; defaults to red def whisker - # step = @options[:step].to_f + step = @options[:step].to_i height = @options[:height].to_f background_color = @options[:background_color] - create_canvas(@data.size * 2 - 1, height, background_color) + create_canvas(@data.size * step - 1, height, background_color) whisker_color = @options[:whisker_color] || 'black' exception_color = @options[:exception_color] || 'red' on_row = (@canvas.rows/2.0 - 1).ceil @@ -489,52 +518,80 @@ y_end_point = @canvas.rows end @draw.stroke( color ) @draw.line( i, y_mid_point, i, y_end_point ) - i += 2 + i += step end @draw.draw(@canvas) - @canvas.to_blob + @canvas end + ## + # A bullet graph, a la Stephen Few in "Information Dashboard Design." + # + # * data - A single value for the thermometer part of the bullet. + # Represents the current value. + # * options - a hash + # + # :good - Numeric. Maximum value that will be shown on the graph. Required. + # + # :height - Numeric. Defaults to 15. Should be a multiple of three. + # + # :width - This graph expands to any specified width. Defaults to 100. + # + # :bad - Numeric. A darker shade background will be drawn up to this point. + # + # :satisfactory - Numeric. A medium background will be drawn up to this point. + # + # :target - Numeric value. A thin vertical bar will be drawn. + # + # :good_color - Color for the rightmost section of the bullet. + # + # :satisfactory_color - Color for the middle background of the bullet. + # + # :bad_color - Color for the lowest, leftmost section. + def bullet height = @options[:height].to_f - @graph_width = @options.has_key?(:width) ? @options[:width].to_f : 100.0 - background_color = '#eeeeee' # @options[:background_color] + @graph_width = @options.has_key?(:width) ? @options[:width].to_f : 100.0 + good_color = @options.has_key?(:good_color) ? @options[:good_color] : '#eeeeee' + satisfactory_color = @options.has_key?(:satisfactory_color) ? @options[:satisfactory_color] : '#bbbbbb' + bad_color = @options.has_key?(:bad_color) ? @options[:bad_color] : '#999999' + bullet_color = @options.has_key?(:bullet_color) ? @options[:bullet_color] : 'black' @thickness = height/3.0 - create_canvas(@graph_width, height, background_color) + create_canvas(@graph_width, height, good_color) @value = @norm_data @good_value = @options[:good].to_f - + @graph_height = @options[:height] - qualitative_range_colors = ['#bbbbbb', '#999999'] + qualitative_range_colors = [satisfactory_color, bad_color] [:satisfactory, :bad].each_with_index do |indicator, index| next unless @options.has_key?(indicator) @draw = @draw.fill(qualitative_range_colors[index]) indicator_width_x = @graph_width * (@options[indicator].to_f / @good_value) @draw = @draw.rectangle(0, 0, indicator_width_x.to_i, @graph_height) end if @options.has_key?(:target) - @draw = @draw.fill 'black' + @draw = @draw.fill(bullet_color) target_x = @graph_width * (@options[:target].to_f / @good_value) half_thickness = (@thickness / 2.0).to_i bar_width = 1.0 @draw = @draw.rectangle(target_x.to_i, half_thickness, (target_x + bar_width).to_i, @thickness * 2 + half_thickness) end # Value - @draw = @draw.fill 'black' + @draw = @draw.fill(bullet_color) @draw = @draw.rectangle(0, @thickness.to_i, @graph_width * (@data.first.to_f / @good_value), (@thickness * 2.0).to_i) @draw.draw(@canvas) - @canvas.to_blob + @canvas end ## # Draw the error Sparkline. @@ -544,10 +601,10 @@ @draw.fill('red') @draw.line(0,0,40,15) @draw.line(0,15,40,0) @draw.draw(@canvas) - @canvas.to_blob + @canvas end private def normalize_data