Class: PDF::Charts::StdDev
- Inherits:
-
Object
- Object
- PDF::Charts::StdDev
- Defined in:
- lib/pdf/charts/stddev.rb
Overview
Creates a standard deviation chart. This is a type of chart that is effective for the display of survey results or other data that can easily be measured in terms of the average and the standard deviation from that average.
The scale of responses is the vertical scale; the average data points and standard deviation values are the horizontal scale.
Defined Under Namespace
Classes: DataPoint, Label, Marker, Scale
Instance Attribute Summary collapse
-
#bar ⇒ Object
The standard deviation bar.
-
#data ⇒ Object
readonly
The data used to generate the standard deviation chart.
-
#datapoint_width ⇒ Object
The width of a single datapoint.
-
#dot ⇒ Object
The dot marker.
-
#height ⇒ Object
The height of the chart in PDF user units.
-
#inner_borders ⇒ Object
The inner border style.
-
#label ⇒ Object
The label style of the labels if they are displayed.
-
#leading_gap ⇒ Object
The minimum gap between the chart and the bottom of the page, in PDF user units.
-
#lower_crossbar ⇒ Object
The lower crossbar.
-
#maximum_width ⇒ Object
The maximum width of the chart in PDF user units.
-
#outer_borders ⇒ Object
The outer border style.
-
#scale ⇒ Object
The scale of the chart.
-
#show_labels ⇒ Object
This will be
true
if labels are to be displayed. -
#upper_crossbar ⇒ Object
The upper crossbar.
Instance Method Summary collapse
-
#initialize {|_self| ... } ⇒ StdDev
constructor
A new instance of StdDev.
-
#render_on(pdf) ⇒ Object
Draw the standard deviation chart on the supplied PDF document.
Constructor Details
#initialize {|_self| ... } ⇒ StdDev
Returns a new instance of StdDev.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/pdf/charts/stddev.rb', line 109 def initialize @data = [] @scale = Scale.new do |scale| scale.range = 0..6 scale.step = 1 scale.style = PDF::Writer::StrokeStyle.new(0.25) scale.show_labels = false scale.label = Label.new do |label| label.text_size = 8 label.text_color = Color::RGB::Black label.pad = 2 label.decimal_precision = 1 end end @leading_gap = 10 @show_labels = true @label = Label.new do |label| label.height = 25 label.background_color = Color::RGB::Black label.text_color = Color::RGB::White label.text_size = 12 end @outer_borders = Marker.new do |marker| marker.style = PDF::Writer::StrokeStyle.new(1.5) marker.color = Color::RGB::Black end @inner_borders = nil @dot = Marker.new do |marker| marker.style = PDF::Writer::StrokeStyle.new(5) marker.color = Color::RGB::Black end @bar = Marker.new do |marker| marker.style = PDF::Writer::StrokeStyle.new(0.5) marker.color = Color::RGB::Black end @upper_crossbar = Marker.new do |marker| marker.style = PDF::Writer::StrokeStyle.new(1) marker.color = Color::RGB::Black end @lower_crossbar = Marker.new do |marker| marker.style = PDF::Writer::StrokeStyle.new(1) marker.color = Color::RGB::Black end @height = 200 @maximum_width = 500 @datapoint_width = 35 yield self if block_given? end |
Instance Attribute Details
#bar ⇒ Object
The standard deviation bar. A line will be drawn through the dot marker (if drawn) from the upper to lower standard deviation. If nil
, the line will not be drawn. This is a PDF::Charts::StdDev::Marker object.
197 198 199 |
# File 'lib/pdf/charts/stddev.rb', line 197 def @bar end |
#data ⇒ Object (readonly)
The data used to generate the standard deviation chart. This is an array of DataPoint objects, each containing a label
, an average
, and the stddev
(standard deviation) from that average.
166 167 168 |
# File 'lib/pdf/charts/stddev.rb', line 166 def data @data end |
#datapoint_width ⇒ Object
The width of a single datapoint.
216 217 218 |
# File 'lib/pdf/charts/stddev.rb', line 216 def datapoint_width @datapoint_width end |
#dot ⇒ Object
The dot marker. A filled circle will be drawn with this information. If nil
, the dot will not be drawn. This is a PDF::Charts::StdDev::Marker object.
192 193 194 |
# File 'lib/pdf/charts/stddev.rb', line 192 def dot @dot end |
#height ⇒ Object
The height of the chart in PDF user units. Default 200 units.
212 213 214 |
# File 'lib/pdf/charts/stddev.rb', line 212 def height @height end |
#inner_borders ⇒ Object
The inner border style. If nil
, no inner borders are drawn. This is a PDF::Charts::StdDev::Marker object.
184 185 186 |
# File 'lib/pdf/charts/stddev.rb', line 184 def inner_borders @inner_borders end |
#label ⇒ Object
The label style of the labels if they are displayed. This must be a PDF::Charts::StdDev::Label object.
180 181 182 |
# File 'lib/pdf/charts/stddev.rb', line 180 def label @label end |
#leading_gap ⇒ Object
The minimum gap between the chart and the bottom of the page, in PDF user units.
174 175 176 |
# File 'lib/pdf/charts/stddev.rb', line 174 def leading_gap @leading_gap end |
#lower_crossbar ⇒ Object
The lower crossbar. A line will be drawn across the bottom of the standard deviation bar to the width of the dot marker. If #dot is nil
, then the line will be twice as wide as it is thick. If nil
, the lower crossbar will not be drawn. This is a PDF::Charts::StdDev::Marker object.
209 210 211 |
# File 'lib/pdf/charts/stddev.rb', line 209 def @lower_crossbar end |
#maximum_width ⇒ Object
The maximum width of the chart in PDF user units. Default 500 units.
214 215 216 |
# File 'lib/pdf/charts/stddev.rb', line 214 def maximum_width @maximum_width end |
#outer_borders ⇒ Object
The outer border style. If nil
, no inner borders are drawn. This is a PDF::Charts::StdDev::Marker object.
187 188 189 |
# File 'lib/pdf/charts/stddev.rb', line 187 def outer_borders @outer_borders end |
#scale ⇒ Object
The scale of the chart. All values must be within this range. This will be a Scale object. It defaults to a scale of 0..6 with a step of 1.
170 171 172 |
# File 'lib/pdf/charts/stddev.rb', line 170 def scale @scale end |
#show_labels ⇒ Object
This will be true
if labels are to be displayed.
177 178 179 |
# File 'lib/pdf/charts/stddev.rb', line 177 def show_labels @show_labels end |
#upper_crossbar ⇒ Object
The upper crossbar. A line will be drawn across the top of the standard deviation bar to the width of the dot marker. If #dot is nil
, then the line will be twice as wide as it is thick. If nil
, the upper crossbar will not be drawn. This is a PDF::Charts::StdDev::Marker object.
203 204 205 |
# File 'lib/pdf/charts/stddev.rb', line 203 def @upper_crossbar end |
Instance Method Details
#render_on(pdf) ⇒ Object
Draw the standard deviation chart on the supplied PDF document.
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'lib/pdf/charts/stddev.rb', line 219 def render_on(pdf) raise TypeError, PDF::Writer::Lang[:charts_stddev_data_empty] if @data.empty? data = @data.dup leftover_data = nil loop do # Set up the scale information. scale = [] (@scale.first + @scale.step).step(@scale.last, @scale.step) do |ii| scale << "%01.#{@scale.label.decimal_precision}f" % ii end scales = PDF::Writer::OHash.new scale.each_with_index do |gg, ii| scales[ii] = OpenStruct.new scales[ii].value = gg end # Add information about the scales' locations to the scales # hash. Note that the count is one smaller than it should be, so we're # increasing it. The first scale is the bottom of the chart. scale_count = scale.size + 1 label_height_adjuster = 0 label_height_adjuster = @label.height if @show_labels chart_area_height = @height - label_height_adjuster scale_height = chart_area_height / scale_count.to_f scales.each_key do |index| this_height = scale_height * (index + 1) + @label.height scales[index].line_height = this_height if @scale.show_labels scales[index].label_height = this_height - (@scale.label.text_size / 3.0) end end # How many sections do we need in this chart, and how wide will it # need to be? chunk_width = @datapoint_width num_chunks = data.size widest_scale_label = 0 if @scale.show_labels scales.each_value do |scale| this_width = pdf.text_width(scale.value, @scale.label.text_size) widest_scale_label = this_width if this_width > widest_scale_label end end chart_width = chunk_width * num_chunks total_width = chart_width + widest_scale_label + @scale.label.pad # What happens if the projected width of the chart is too big? # Figure out how to break the chart in pieces. if total_width > @maximum_width max_column_count = 0 base_width = widest_scale_label + @scale.label.pad (1..(num_chunks + 1)).each do |ii| if (base_width + (ii * chunk_width)) > @maximum_width break else max_column_count += 1 end end leftover_data = data.slice!(max_column_count, -1) num_chunks = data.size chart_width = chunk_width * num_chunks total_width = chart_width + widest_scale_label + @scale.label.pad end chart_y = pdf.y - @height + @leading_gap chart_y += (@outer_borders.style.width * 2.0) if @outer_borders if chart_y < pdf.bottom_margin pdf.start_new_page chart_y = pdf.y - @height chart_y += (@outer_borders.style.width * 2.0) if @outer_borders end chart_x = pdf.absolute_x_middle - (total_width / 2.0) + widest_scale_label # Add labels, if needed. if @show_labels pdf.save_state pdf.fill_color! @label.background_color # Draw a rectangle for each label num_chunks.times do |ii| this_x = chart_x + ii * chunk_width pdf.rectangle(this_x, chart_y, chunk_width, @label.height).fill end # Add a border above the label rectangle. if @outer_borders pdf.stroke_style! @outer_borders.style pdf.line(chart_x, chart_y + @label.height, chart_x + chart_width, chart_y + @label.height).stroke end pdf.fill_color! @label.text_color data.each_with_index do |datum, ii| label = datum.label.to_s label_width = pdf.text_width(label, @label.text_size) this_x = chart_x + (ii * chunk_width) + (chunk_width / 2.0) - (label_width / 2.0) this_y = chart_y + (@label.height / 2.0) - (@label.text_size / 3.0) pdf.add_text(this_x, this_y, label, @label.text_size) end pdf.restore_state end if @inner_borders pdf.save_state pdf.stroke_color! @inner_borders.color pdf.stroke_style! @inner_borders.style (num_chunks - 1).times do |ii| this_x = chart_x + (ii * chunk_width) + chunk_width pdf.line(this_x, chart_y, this_x, chart_y + @height).stroke end pdf.restore_state end pdf.save_state if @outer_borders pdf.stroke_color! @outer_borders.color pdf.stroke_style! @outer_borders.style pdf.rectangle(chart_x, chart_y, chart_width, @height).stroke end if @scale.style pdf.save_state pdf.stroke_style! @scale.style scales.each_value do |scale| this_y = chart_y + scale.line_height pdf.line(chart_x, this_y, chart_x + chart_width, this_y).stroke end pdf.restore_state end if @scale.show_labels pdf.save_state scales.each_value do |scale| this_y = chart_y + scale.label_height label_width = pdf.text_width(scale.value, @scale.label.text_size) this_x = chart_x - label_width - @scale.label.pad pdf.fill_color! @scale.label.text_color pdf.add_text(this_x, this_y, scale.value, @scale.label.text_size) end pdf.restore_state end data.each_with_index do |datum, ii| avg_height = datum.average * scale_height stddev_height = datum.stddev * scale_height this_y = chart_y + label_height_adjuster + avg_height this_x = chart_x + (ii * chunk_width) + (chunk_width / 2.0) line_top_y = this_y + (stddev_height / 2.0) line_bot_y = this_y - (stddev_height / 2.0) # Plot the dot if @dot pdf.stroke_color! @dot.color pdf.stroke_style! @dot.style pdf.circle_at(this_x, this_y, (@dot.style.width / 2.0)).fill end # Plot the bar if @bar pdf.stroke_color! @bar.color pdf.stroke_style! @bar.style pdf.line(this_x, line_top_y, this_x, line_bot_y).stroke end # Plot the crossbars if @upper_crossbar if @dot cb_width = @dot.style.width else cb_width = @upper_crossbar.style.width end pdf.stroke_color! @upper_crossbar.color pdf.stroke_style! @upper_crossbar.style pdf.line(this_x - cb_width, line_top_y, this_x + cb_width, line_top_y).stroke end if @lower_crossbar if @dot cb_width = @dot.style.width else cb_width = @lower_crossbar.style.width end pdf.stroke_color! @lower_crossbar.color pdf.stroke_style! @lower_crossbar.style pdf.line(this_x - cb_width, line_bot_y, this_x + cb_width, line_bot_y).stroke end end pdf.restore_state pdf.y = chart_y break if leftover_data.nil? data = leftover_data leftover_data = nil end pdf.y end |