public
Rubygem
Description: Gruff graphing library for Ruby
Homepage: http://gruff.rubyforge.org
Clone URL: git://github.com/topfunky/gruff.git
XY Graph option for line graph
topfunky (author)
Mon Mar 24 09:59:12 -0700 2008
commit  864d8e33118d55962d908c8dfff5f575b06f4a83
tree    08569f6dbb50c216352b668acb904901d7d26158
parent  3bd90836f56a2c49cbdd92f043a7bcf77f44ac39
...
32
33
34
 
35
36
37
...
32
33
34
35
36
37
38
0
@@ -32,6 +32,7 @@ module Gruff
0
     DATA_LABEL_INDEX = 0
0
     DATA_VALUES_INDEX = 1
0
     DATA_COLOR_INDEX = 2
0
+ DATA_VALUES_X_INDEX = 3
0
 
0
     # Space around text elements. Mostly used for vertical spacing
0
     LEGEND_MARGIN = TITLE_MARGIN = LABEL_MARGIN = 10.0
...
22
23
24
 
 
 
 
25
26
27
...
43
44
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
47
48
...
50
51
52
53
54
55
 
 
 
 
 
 
 
 
 
 
 
 
 
56
57
58
...
64
65
66
67
 
68
69
70
71
 
 
 
 
 
 
 
 
 
 
 
72
73
74
...
102
103
104
 
 
 
 
105
...
22
23
24
25
26
27
28
29
30
31
...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
113
114
115
 
116
 
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
...
138
139
140
 
141
142
143
 
 
144
145
146
147
148
149
150
151
152
153
154
155
156
157
...
185
186
187
188
189
190
191
192
0
@@ -22,6 +22,10 @@ class Gruff::Line < Gruff::Base
0
   
0
   # Hide parts of the graph to fit more datapoints, or for a different appearance.
0
   attr_accessor :hide_dots, :hide_lines
0
+
0
+ #accessors for support of xy data
0
+ attr_accessor :minimum_x_value
0
+ attr_accessor :maximum_x_value
0
 
0
   # Call with target pixel width of graph (800, 400, 300), and/or 'false' to omit lines (points only).
0
   #
0
@@ -43,6 +47,65 @@ class Gruff::Line < Gruff::Base
0
     @hide_dots = @hide_lines = false
0
     @baseline_color = 'red'
0
     @baseline_value = nil
0
+ @maximum_x_value = nil
0
+ @minimum_x_value = nil
0
+ end
0
+
0
+ # This method allows one to plot a dataset with both X and Y data.
0
+ #
0
+ # Parameters are as follows:
0
+ # name: string, the title of the dataset
0
+ # x_data_points: an array containing the x data points for the graph
0
+ # y_data_points: an array containing the y data points for the graph
0
+ # color: hex number indicating the line color as an RGB triplet
0
+ #
0
+ # Notes:
0
+ # -if (x_data_points.length != y_data_points.length) an error is
0
+ # returned.
0
+ # -if the color argument is nil, the next color from the default theme will
0
+ # be used.
0
+ # -if you want to use a preset theme, you must set it before calling
0
+ # dataxy().
0
+ #
0
+ # Example:
0
+ # g = Gruff::Line.new
0
+ # g.title = "X/Y Dataset"
0
+ # g.dataxy("Apples", [1,3,4,5,6,10], [1, 2, 3, 4, 4, 3])
0
+ # g.dataxy("Bapples", [1,3,4,5,7,9], [1, 1, 2, 2, 3, 3])
0
+ # #you can still use the old data method too if you want:
0
+ # g.data("Capples", [1, 1, 2, 2, 3, 3])
0
+ # #labels will be drawn at the x locations of the 1st dataset that you
0
+ # #passed in. In this example the lables are drawn at x locations 1,4,6
0
+ # g.labels = {0 => '2003', 2 => '2004', 4 => '2005'} #labels
0
+
0
+ def dataxy(name, x_data_points=[], y_data_points=[], color=nil)
0
+
0
+ raise ArgumentError, "x_data_points is nil!" if x_data_points.length == 0
0
+ raise ArgumentError, "x_data_points.length != y_data_points.length!" if x_data_points.length != y_data_points.length
0
+
0
+ #call the existing data routine for the y data.
0
+ self.data(name, y_data_points, color)
0
+
0
+ x_data_points = Array(x_data_points) # make sure it's an array
0
+ #append the x data to the last entry that was just added in the @data member
0
+ lastElem = @data.length()-1
0
+ @data[lastElem] << x_data_points
0
+
0
+ # Update the global min/max values for the x data
0
+ x_data_points.each_with_index do |x_data_point, index|
0
+ next if x_data_point.nil?
0
+
0
+ # Setup max/min so spread starts at the low end of the data points
0
+ if @maximum_x_value.nil? && @minimum_x_value.nil?
0
+ @maximum_x_value = @minimum_x_value = x_data_point
0
+ end
0
+
0
+ @maximum_x_value = (x_data_point > @maximum_x_value) ?
0
+ x_data_point : @maximum_x_value
0
+ @minimum_x_value = (x_data_point < @minimum_x_value) ?
0
+ x_data_point : @minimum_x_value
0
+ end
0
+
0
   end
0
 
0
   def draw
0
@@ -50,9 +113,20 @@ class Gruff::Line < Gruff::Base
0
 
0
     return unless @has_data
0
     
0
- # Check to see if more than one datapoint was given. NaN can result otherwise.
0
     @x_increment = (@column_count > 1) ? (@graph_width / (@column_count - 1).to_f) : @graph_width
0
-
0
+
0
+ #normalize the x data if it is specified
0
+ @data.each_with_index do |data_row, index|
0
+ norm_x_data_points = []
0
+ if (data_row[DATA_VALUES_X_INDEX] != nil)
0
+ data_row[DATA_VALUES_X_INDEX].each do |x_data_point|
0
+ norm_x_data_points << ( (x_data_point.to_f - @minimum_x_value.to_f ) /
0
+ (@maximum_x_value.to_f - @minimum_x_value.to_f) )
0
+ end
0
+ @norm_data[index] << norm_x_data_points
0
+ end
0
+ end
0
+
0
     if (defined?(@norm_baseline)) then
0
       level = @graph_top + (@graph_height - @norm_baseline * @graph_height)
0
       @d = @d.push
0
@@ -64,11 +138,20 @@ class Gruff::Line < Gruff::Base
0
       @d = @d.pop
0
     end
0
 
0
- @norm_data.each do |data_row|
0
+ @norm_data.each_with_index do |data_row, dr_index|
0
       prev_x = prev_y = nil
0
 
0
- data_row[1].each_with_index do |data_point, index|
0
- new_x = @graph_left + (@x_increment * index)
0
+ data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
0
+ x_data = data_row[DATA_VALUES_X_INDEX]
0
+ if (x_data == nil)
0
+ #use the old method: equally spaced points along the x-axis
0
+ new_x = @graph_left + (@x_increment * index)
0
+ else
0
+ x_data_row = data_row[DATA_VALUES_X_INDEX]
0
+ x_data_point = x_data_row[index]
0
+ new_x = getXCoord(x_data_point, @graph_width, @graph_left)
0
+ end
0
+
0
         next if data_point.nil?
0
 
0
         draw_label(new_x, index)
0
@@ -102,4 +185,8 @@ class Gruff::Line < Gruff::Base
0
     @norm_baseline = (@baseline_value.to_f / @maximum_value.to_f) if @baseline_value
0
   end
0
   
0
+ def getXCoord(x_data_point, width, offset)
0
+ return(x_data_point * width + offset)
0
+ end
0
+
0
 end
...
436
437
438
 
 
 
 
 
 
 
 
 
 
439
440
441
...
509
510
511
512
 
513
...
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
...
519
520
521
 
522
523
0
@@ -436,6 +436,16 @@ class TestGruffLine < GruffTestCase
0
     g.write('test/output/line_no_hide.png')
0
   end
0
 
0
+ def test_xy_data
0
+ g = Gruff::Line.new
0
+ g.title = "X/Y Dataset"
0
+ g.dataxy("Apples", [1,3,4,5,6,10], [1, 2, 3, 4, 4, 3])
0
+ g.dataxy("Bapples", [1,3,4,5,7,9], [1, 1, 2, 2, 3, 3])
0
+ g.data("Capples", [1, 1, 2, 2, 3, 3])
0
+ g.labels = {0 => '2003', 2 => '2004', 4 => '2005'}
0
+ g.write('test/output/data_xy.png')
0
+ end
0
+
0
 protected
0
 
0
   # TODO Reset data after each theme
0
@@ -509,5 +519,5 @@ protected
0
     g.data(:peaches, [-10, -8, -6, -3])
0
     g
0
   end
0
-
0
+
0
 end

Comments

    No one has commented yet.