class SVG::Graph::Schedule

For creating SVG plots of scalar temporal data

Synopsis

require 'SVG/Graph/Schedule'

# Data sets are label, start, end tripples.
data1 = [
  "Housesitting", "6/17/04", "6/19/04", 
  "Summer Session", "6/15/04", "8/15/04",
]

graph = SVG::Graph::Schedule.new( {
  :width => 640,
  :height => 480,
  :graph_title => title,
  :show_graph_title => true,
  :no_css => true,
  :scale_x_integers => true,
  :scale_y_integers => true,
  :min_x_value => 0,
  :min_y_value => 0,
  :show_data_labels => true,
  :show_x_guidelines => true,
  :show_x_title => true,
  :x_title => "Time",
  :stagger_x_labels => true,
  :stagger_y_labels => true,
  :x_label_format => "%m/%d/%y",
})

graph.add_data({
        :data => data1,
  :title => 'Data',
})

print graph.burn()

Description

Produces a graph of temporal scalar data.

Examples

www.germane-software/repositories/public/SVG/test/schedule.rb

Notes

The default stylesheet handles upto 10 data sets, if you use more you must create your own stylesheet and add the additional settings for the extra data sets. You will know if you go over 10 data sets as they will have no style and be in black.

Note that multiple data sets within the same chart can differ in length, and that the data in the datasets needn't be in order; they will be ordered by the plot along the X-axis.

The dates must be parseable by ParseDate, but otherwise can be any order of magnitude (seconds within the hour, or years)

See also

Author

Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>

Copyright 2004 Sean E. Russell This software is available under the Ruby license

Attributes

bar_gap[RW]
min_x_value[RW]
popup_format[RW]

The formatting used for the popups. See x_label_format

scale_x_divisions[RW]
scale_x_integers[RW]
timescale_divisions[RW]

Use this to set the spacing between dates on the axis. The value must be of the form “d+ ?(days|weeks|months|years|hours|minutes|seconds)?”

EG:

graph.timescale_divisions = "2 weeks"

will cause the chart to try to divide the X axis up into segments of two week periods.

x_label_format[RW]

The format string use do format the X axis labels. See Time::strformat

Public Instance Methods

add_data(data) click to toggle source

Add data to the plot.

# A data set with 1 point: Lunch from 12:30 to 14:00
d1 = [ "Lunch", "12:30", "14:00" ] 
# A data set with 2 points: "Cats" runs from 5/11/03 to 7/15/04, and
#                           "Henry V" runs from 6/12/03 to 8/20/03
d2 = [ "Cats", "5/11/03", "7/15/04",
       "Henry V", "6/12/03", "8/20/03" ]

graph.add_data( 
  :data => d1,
  :title => 'Meetings'
)
graph.add_data(
  :data => d2,
  :title => 'Plays'
)

Note that the data must be in time,value pairs, and that the date format may be any date that is parseable by ParseDate. Also note that, in this example, we're mixing scales; the data from d1 will probably not be discernable if both data sets are plotted on the same graph, since d1 is too granular.

    # File lib/SVG/Graph/Schedule.rb
141 def add_data data
142   @data = [] unless @data
143  
144   raise "No data provided by #{conf.inspect}" unless data[:data] and
145                                               data[:data].kind_of? Array
146   raise "Data supplied must be title,from,to tripples!  "+
147     "The data provided contained an odd set of "+
148     "data points" unless data[:data].length % 3 == 0
149   return if data[:data].length == 0
150 
151 
152   y = []
153   x_start = []
154   x_end = []
155   data[:data].each_index {|i|
156     im3 = i%3
157     if im3 == 0
158       y << data[:data][i]
159     else
160       t = DateTime.parse( data[:data][i] ).to_time
161       (im3 == 1 ? x_start : x_end) << t.to_i
162     end
163   }
164   sort( x_start, x_end, y )
165   @data = [x_start, x_end, y ]
166 end
set_defaults() click to toggle source

In addition to the defaults set by Graph::initialize and Plot::set_defaults, sets:

x_label_format

'%Y-%m-%d %H:%M:%S'

popup_format

'%Y-%m-%d %H:%M:%S'

   # File lib/SVG/Graph/Schedule.rb
87 def set_defaults
88   init_with(
89     :x_label_format     => '%Y-%m-%d %H:%M:%S',
90     :popup_format       => '%Y-%m-%d %H:%M:%S',
91     :scale_x_divisions  => false,
92     :scale_x_integers   => false,
93     :bar_gap            => true
94   )
95 end

Protected Instance Methods

draw_data() click to toggle source
    # File lib/SVG/Graph/Schedule.rb
192 def draw_data
193   fieldheight = field_height
194   fieldwidth = field_width
195 
196   bargap = bar_gap ? (fieldheight < 10 ? fieldheight / 2 : 10) : 0
197   subbar_height = fieldheight - bargap
198   
199   field_count = 1
200   y_mod = (subbar_height / 2) + (font_size / 2)
201   min,max,div = x_range
202   scale = (@graph_width.to_f - font_size*2) / (max-min)
203   @data[0].each_index { |i|
204     x_start = @data[0][i]
205     x_end = @data[1][i]
206     y = @graph_height - (fieldheight * field_count)
207     bar_width = (x_end-x_start) * scale
208     bar_start = x_start * scale - (min * scale)
209   
210     @graph.add_element( "rect", {
211       "x" => bar_start.to_s,
212       "y" => y.to_s,
213       "width" => bar_width.to_s,
214       "height" => subbar_height.to_s,
215       "class" => "fill#{field_count+1}"
216     })
217     field_count += 1
218   }
219 end
format(x, y) click to toggle source
    # File lib/SVG/Graph/Schedule.rb
176 def format x, y
177   Time.at( x ).strftime( popup_format )
178 end
get_css() click to toggle source
    # File lib/SVG/Graph/Schedule.rb
221       def get_css
222         return <<EOL
223 /* default fill styles for multiple datasets (probably only use a single dataset on this graph though) */
224 .key1,.fill1{
225         fill: #ff0000;
226         fill-opacity: 0.5;
227         stroke: none;
228         stroke-width: 0.5px;   
229 }
230 .key2,.fill2{
231         fill: #0000ff;
232         fill-opacity: 0.5;
233         stroke: none;
234         stroke-width: 1px;     
235 }
236 .key3,.fill3{
237         fill: #00ff00;
238         fill-opacity: 0.5;
239         stroke: none;
240         stroke-width: 1px;     
241 }
242 .key4,.fill4{
243         fill: #ffcc00;
244         fill-opacity: 0.5;
245         stroke: none;
246         stroke-width: 1px;     
247 }
248 .key5,.fill5{
249         fill: #00ccff;
250         fill-opacity: 0.5;
251         stroke: none;
252         stroke-width: 1px;     
253 }
254 .key6,.fill6{
255         fill: #ff00ff;
256         fill-opacity: 0.5;
257         stroke: none;
258         stroke-width: 1px;     
259 }
260 .key7,.fill7{
261         fill: #00ffff;
262         fill-opacity: 0.5;
263         stroke: none;
264         stroke-width: 1px;     
265 }
266 .key8,.fill8{
267         fill: #ffff00;
268         fill-opacity: 0.5;
269         stroke: none;
270         stroke-width: 1px;     
271 }
272 .key9,.fill9{
273         fill: #cc6666;
274         fill-opacity: 0.5;
275         stroke: none;
276         stroke-width: 1px;     
277 }
278 .key10,.fill10{
279         fill: #663399;
280         fill-opacity: 0.5;
281         stroke: none;
282         stroke-width: 1px;     
283 }
284 .key11,.fill11{
285         fill: #339900;
286         fill-opacity: 0.5;
287         stroke: none;
288         stroke-width: 1px;     
289 }
290 .key12,.fill12{
291         fill: #9966FF;
292         fill-opacity: 0.5;
293         stroke: none;
294         stroke-width: 1px;     
295 }
296 EOL
297       end
get_x_labels() click to toggle source
    # File lib/SVG/Graph/Schedule.rb
180 def get_x_labels
181   rv = get_x_values.collect { |v| Time.at(v).strftime( x_label_format ) }
182 end
get_y_labels() click to toggle source
    # File lib/SVG/Graph/Schedule.rb
188 def get_y_labels
189   @data[2]
190 end
min_x_value=(value) click to toggle source
    # File lib/SVG/Graph/Schedule.rb
171 def min_x_value=(value)
172   @min_x_value = DateTime.parse( value ).to_time.to_i
173 end
y_label_offset( height ) click to toggle source
    # File lib/SVG/Graph/Schedule.rb
184 def y_label_offset( height )
185   height / -2.0
186 end