Class | SVG::Graph::Pie |
In: |
lib/SVG/Graph/Pie.rb
|
Parent: | Graph |
require 'SVG/Graph/Pie' fields = %w(Jan Feb Mar) data_sales_02 = [12, 45, 21] graph = SVG::Graph::Pie.new({ :height => 500, :width => 300, :fields => fields, }) graph.add_data({ :data => data_sales_02, :title => 'Sales 2002', }) print "Content-type: image/svg+xml\r\n\r\n" print graph.burn();
This object aims to allow you to easily create high quality SVG pie graphs. You can either use the default style sheet or supply your own. Either way there are many options which can be configured to give you control over how the graph is generated - with or without a key, display percent on pie chart, title, subtitle etc.
www.germane-software/repositories/public/SVG/test/single.rb
Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
Copyright 2004 Sean E. Russell This software is available under the Ruby license
RADIANS | = | Math::PI/180 |
datapoint_font_size | [RW] | The font size of the data point labels |
expand_gap | [RW] | The amount of space between expanded wedges |
expand_greatest | [RW] | If true, expand the largest pie wedge |
expanded | [RW] | If true, "explode" the pie (put space between the wedges) |
shadow_offset | [RW] | Sets the offset of the shadow from the pie chart |
show_actual_values | [RW] | If true, display the actual field values in the data labels |
show_data_labels | [RW] | If true, display the data labels on the chart |
show_key_actual_values | [RW] | If true, display the actual value of the field in the key |
show_key_data_labels | [RW] | If true, display the labels in the key |
show_key_percent | [RW] | If true, display the percentage value of the wedges in the key |
show_percent | [RW] | If true, display the percentage value of each pie wedge in the data labels |
show_shadow | [RW] | If true, displays a drop shadow for the chart |
Adds a data set to the graph.
graph.add_data( { :data => [1,2,3,4] } )
Note that the :title is not necessary. If multiple data sets are added to the graph, the pie chart will display the sums of the data. EG:
graph.add_data( { :data => [1,2,3,4] } ) graph.add_data( { :data => [2,3,5,9] } )
is the same as:
graph.add_data( { :data => [3,5,8,13] } )
# File lib/SVG/Graph/Pie.rb, line 111 111: def add_data arg 112: arg[:data].each_index {|idx| 113: @data[idx] = 0 unless @data[idx] 114: @data[idx] += arg[:data][idx] 115: } 116: end
Defaults are those set by Graph::initialize, and
# File lib/SVG/Graph/Pie.rb, line 73 73: def set_defaults 74: init_with( 75: :show_shadow => true, 76: :shadow_offset => 10, 77: 78: :show_data_labels => false, 79: :show_actual_values => false, 80: :show_percent => true, 81: 82: :show_key_data_labels => true, 83: :show_key_actual_values => true, 84: :show_key_percent => false, 85: 86: :expanded => false, 87: :expand_greatest => false, 88: :expand_gap => 10, 89: 90: :show_x_labels => false, 91: :show_y_labels => false, 92: :datapoint_font_size => 12 93: ) 94: @data = [] 95: end
# File lib/SVG/Graph/Pie.rb, line 147 147: def add_defs defs 148: gradient = defs.add_element( "filter", { 149: "id"=>"dropshadow", 150: "width" => "1.2", 151: "height" => "1.2", 152: } ) 153: gradient.add_element( "feGaussianBlur", { 154: "stdDeviation" => "4", 155: "result" => "blur" 156: }) 157: end
# File lib/SVG/Graph/Pie.rb, line 187 187: def draw_data 188: @graph = @root.add_element( "g" ) 189: background = @graph.add_element("g") 190: midground = @graph.add_element("g") 191: 192: diameter = @graph_height > @graph_width ? @graph_width : @graph_height 193: diameter -= expand_gap if expanded or expand_greatest 194: diameter -= datapoint_font_size if show_data_labels 195: diameter -= 10 if show_shadow 196: radius = diameter / 2.0 197: 198: xoff = (width - diameter) / 2 199: yoff = (height - @border_bottom - diameter) 200: yoff -= 10 if show_shadow 201: @graph.attributes['transform'] = "translate( #{xoff} #{yoff} )" 202: 203: wedge_text_pad = 5 204: wedge_text_pad = 20 if show_percent and show_data_labels 205: 206: total = 0 207: max_value = 0 208: @data.each {|x| 209: max_value = max_value < x ? x : max_value 210: total += x 211: } 212: percent_scale = 100.0 / total 213: 214: prev_percent = 0 215: rad_mult = 3.6 * RADIANS 216: @config[:fields].each_index { |count| 217: value = @data[count] 218: percent = percent_scale * value 219: 220: radians = prev_percent * rad_mult 221: x_start = radius+(Math.sin(radians) * radius) 222: y_start = radius-(Math.cos(radians) * radius) 223: radians = (prev_percent+percent) * rad_mult 224: x_end = radius+(Math.sin(radians) * radius) 225: x_end -= 0.00001 if @data.length == 1 226: y_end = radius-(Math.cos(radians) * radius) 227: path = "M#{radius},#{radius} L#{x_start},#{y_start} "+ 228: "A#{radius},#{radius} "+ 229: "0, #{percent >= 50 ? '1' : '0'},1, "+ 230: "#{x_end} #{y_end} Z" 231: 232: 233: wedge = @foreground.add_element( "path", { 234: "d" => path, 235: "class" => "fill#{count+1}" 236: }) 237: 238: translate = nil 239: tx = 0 240: ty = 0 241: half_percent = prev_percent + percent / 2 242: radians = half_percent * rad_mult 243: 244: if show_shadow 245: shadow = background.add_element( "path", { 246: "d" => path, 247: "filter" => "url(#dropshadow)", 248: "style" => "fill: #ccc; stroke: none;" 249: }) 250: clear = midground.add_element( "path", { 251: "d" => path, 252: "style" => "fill: #fff; stroke: none;" 253: }) 254: end 255: 256: if expanded or (expand_greatest && value == max_value) 257: tx = (Math.sin(radians) * expand_gap) 258: ty = -(Math.cos(radians) * expand_gap) 259: translate = "translate( #{tx} #{ty} )" 260: wedge.attributes["transform"] = translate 261: clear.attributes["transform"] = translate if clear 262: end 263: 264: if show_shadow 265: shadow.attributes["transform"] = 266: "translate( #{tx+shadow_offset} #{ty+shadow_offset} )" 267: end 268: 269: if show_data_labels and value != 0 270: label = "" 271: label += @config[:fields][count] if show_key_data_labels 272: label += " ["+value.to_s+"]" if show_actual_values 273: label += " "+percent.round.to_s+"%" if show_percent 274: 275: msr = Math.sin(radians) 276: mcr = Math.cos(radians) 277: tx = radius + (msr * radius) 278: ty = radius - (mcr * radius) 279: 280: if expanded or (expand_greatest && value == max_value) 281: tx += (msr * expand_gap) 282: ty -= (mcr * expand_gap) 283: end 284: @foreground.add_element( "text", { 285: "x" => tx.to_s, 286: "y" => ty.to_s, 287: "class" => "dataPointLabel", 288: "style" => "stroke: #fff; stroke-width: 2;" 289: }).text = label.to_s 290: @foreground.add_element( "text", { 291: "x" => tx.to_s, 292: "y" => ty.to_s, 293: "class" => "dataPointLabel", 294: }).text = label.to_s 295: end 296: 297: prev_percent += percent 298: } 299: end
# File lib/SVG/Graph/Pie.rb, line 308 308: def get_css 309: return ".dataPointLabel{\n fill: #000000;\n text-anchor:middle;\n font-size: \#{datapoint_font_size}px;\n font-family: \"Arial\", sans-serif;\n font-weight: normal;\n}\n\n/* key - MUST match fill styles */\n.key1,.fill1{\n fill: #ff0000;\n fill-opacity: 0.7;\n stroke: none;\n stroke-width: 1px; \n}\n.key2,.fill2{\n fill: #0000ff;\n fill-opacity: 0.7;\n stroke: none;\n stroke-width: 1px; \n}\n.key3,.fill3{\n fill-opacity: 0.7;\n fill: #00ff00;\n stroke: none;\n stroke-width: 1px; \n}\n.key4,.fill4{\n fill-opacity: 0.7;\n fill: #ffcc00;\n stroke: none;\n stroke-width: 1px; \n}\n.key5,.fill5{\n fill-opacity: 0.7;\n fill: #00ccff;\n stroke: none;\n stroke-width: 1px; \n}\n.key6,.fill6{\n fill-opacity: 0.7;\n fill: #ff00ff;\n stroke: none;\n stroke-width: 1px; \n}\n.key7,.fill7{\n fill-opacity: 0.7;\n fill: #00ff99;\n stroke: none;\n stroke-width: 1px; \n}\n.key8,.fill8{\n fill-opacity: 0.7;\n fill: #ffff00;\n stroke: none;\n stroke-width: 1px; \n}\n.key9,.fill9{\n fill-opacity: 0.7;\n fill: #cc6666;\n stroke: none;\n stroke-width: 1px; \n}\n.key10,.fill10{\n fill-opacity: 0.7;\n fill: #663399;\n stroke: none;\n stroke-width: 1px; \n}\n.key11,.fill11{\n fill-opacity: 0.7;\n fill: #339900;\n stroke: none;\n stroke-width: 1px; \n}\n.key12,.fill12{\n fill-opacity: 0.7;\n fill: #9966FF;\n stroke: none;\n stroke-width: 1px; \n}\n" 310: end
# File lib/SVG/Graph/Pie.rb, line 171 171: def keys 172: total = 0 173: #max_value = 0 174: @data.each {|x| total += x } 175: percent_scale = 100.0 / total 176: count = -1 177: @config[:fields].collect{ |x| 178: count += 1 179: v = @data[count] 180: perc = show_key_percent ? " "+(v * percent_scale).round.to_s+"%" : "" 181: x + " [" + v.to_s + "]" + perc 182: } 183: end