class SVG::Graph::Pie
Create presentation quality SVG
pie graphs easily¶ ↑
Synopsis¶ ↑
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();
Description¶ ↑
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.
Examples¶ ↑
www.germane-software/repositories/public/SVG/test/single.rb
See also¶ ↑
Author¶ ↑
Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
Copyright 2004 Sean E. Russell This software is available under the Ruby license
Constants
- RADIANS
Attributes
The font size of the data point labels
The amount of space between expanded wedges
If true, expand the largest pie wedge
If true, “explode” the pie (put space between the wedges)
Sets the offset of the shadow from the pie chart
If true, display the actual field values in the data labels
If true, display the data labels on the chart
If true, display the actual value of the field in the key
If true, display the labels in the key
If true, display the percentage value of the wedges in the key
If true, display the percentage value of each pie wedge in the data labels
If true, displays a drop shadow for the chart
Public Instance Methods
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 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
show_shadow
-
true
shadow_offset
-
10
show_data_labels
-
false
show_actual_values
-
false
show_percent
-
true
show_key_data_labels
-
true
show_key_actual_values
-
true
show_key_percent
-
false
- expanded
-
false
expand_greatest
-
false
expand_gap
-
10
- show_x_labels
-
false
- show_y_labels
-
false
datapoint_font_size
-
12
# File lib/SVG/Graph/Pie.rb 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
Protected Instance Methods
# File lib/SVG/Graph/Pie.rb 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 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
We don't need the graph
# File lib/SVG/Graph/Pie.rb 160 def draw_graph 161 end
# File lib/SVG/Graph/Pie.rb 308 def get_css 309 return <<EOL 310 .dataPointLabel{ 311 fill: #000000; 312 text-anchor:middle; 313 font-size: #{datapoint_font_size}px; 314 font-family: "Arial", sans-serif; 315 font-weight: normal; 316 } 317 318 /* key - MUST match fill styles */ 319 .key1,.fill1{ 320 fill: #ff0000; 321 fill-opacity: 0.7; 322 stroke: none; 323 stroke-width: 1px; 324 } 325 .key2,.fill2{ 326 fill: #0000ff; 327 fill-opacity: 0.7; 328 stroke: none; 329 stroke-width: 1px; 330 } 331 .key3,.fill3{ 332 fill-opacity: 0.7; 333 fill: #00ff00; 334 stroke: none; 335 stroke-width: 1px; 336 } 337 .key4,.fill4{ 338 fill-opacity: 0.7; 339 fill: #ffcc00; 340 stroke: none; 341 stroke-width: 1px; 342 } 343 .key5,.fill5{ 344 fill-opacity: 0.7; 345 fill: #00ccff; 346 stroke: none; 347 stroke-width: 1px; 348 } 349 .key6,.fill6{ 350 fill-opacity: 0.7; 351 fill: #ff00ff; 352 stroke: none; 353 stroke-width: 1px; 354 } 355 .key7,.fill7{ 356 fill-opacity: 0.7; 357 fill: #00ff99; 358 stroke: none; 359 stroke-width: 1px; 360 } 361 .key8,.fill8{ 362 fill-opacity: 0.7; 363 fill: #ffff00; 364 stroke: none; 365 stroke-width: 1px; 366 } 367 .key9,.fill9{ 368 fill-opacity: 0.7; 369 fill: #cc6666; 370 stroke: none; 371 stroke-width: 1px; 372 } 373 .key10,.fill10{ 374 fill-opacity: 0.7; 375 fill: #663399; 376 stroke: none; 377 stroke-width: 1px; 378 } 379 .key11,.fill11{ 380 fill-opacity: 0.7; 381 fill: #339900; 382 stroke: none; 383 stroke-width: 1px; 384 } 385 .key12,.fill12{ 386 fill-opacity: 0.7; 387 fill: #9966FF; 388 stroke: none; 389 stroke-width: 1px; 390 } 391 EOL 392 end
# File lib/SVG/Graph/Pie.rb 167 def get_x_labels 168 [""] 169 end
# File lib/SVG/Graph/Pie.rb 163 def get_y_labels 164 [""] 165 end
# File lib/SVG/Graph/Pie.rb 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
# File lib/SVG/Graph/Pie.rb 302 def round val, to 303 up = 10**to.to_f 304 (val * up).to_i / up 305 end