##// END OF EJS Templates
fix incorrect min_x_value of lib/SVG/Graph/TimeSeries.rb by r10439 (#12711, #11290)...
Toshi MARUYAMA -
r10861:2ba7228b065b
parent child
Show More
@@ -1,238 +1,238
1 1 require 'SVG/Graph/Plot'
2 2
3 3 module SVG
4 4 module Graph
5 5 # === For creating SVG plots of scalar temporal data
6 6 #
7 7 # = Synopsis
8 8 #
9 9 # require 'SVG/Graph/TimeSeriess'
10 10 #
11 11 # # Data sets are x,y pairs
12 12 # data1 = ["6/17/72", 11, "1/11/72", 7, "4/13/04 17:31", 11,
13 13 # "9/11/01", 9, "9/1/85", 2, "9/1/88", 1, "1/15/95", 13]
14 14 # data2 = ["8/1/73", 18, "3/1/77", 15, "10/1/98", 4,
15 15 # "5/1/02", 14, "3/1/95", 6, "8/1/91", 12, "12/1/87", 6,
16 16 # "5/1/84", 17, "10/1/80", 12]
17 17 #
18 18 # graph = SVG::Graph::TimeSeries.new( {
19 19 # :width => 640,
20 20 # :height => 480,
21 21 # :graph_title => title,
22 22 # :show_graph_title => true,
23 23 # :no_css => true,
24 24 # :key => true,
25 25 # :scale_x_integers => true,
26 26 # :scale_y_integers => true,
27 27 # :min_x_value => 0,
28 28 # :min_y_value => 0,
29 29 # :show_data_labels => true,
30 30 # :show_x_guidelines => true,
31 31 # :show_x_title => true,
32 32 # :x_title => "Time",
33 33 # :show_y_title => true,
34 34 # :y_title => "Ice Cream Cones",
35 35 # :y_title_text_direction => :bt,
36 36 # :stagger_x_labels => true,
37 37 # :x_label_format => "%m/%d/%y",
38 38 # })
39 39 #
40 40 # graph.add_data({
41 41 # :data => projection
42 42 # :title => 'Projected',
43 43 # })
44 44 #
45 45 # graph.add_data({
46 46 # :data => actual,
47 47 # :title => 'Actual',
48 48 # })
49 49 #
50 50 # print graph.burn()
51 51 #
52 52 # = Description
53 53 #
54 54 # Produces a graph of temporal scalar data.
55 55 #
56 56 # = Examples
57 57 #
58 58 # http://www.germane-software/repositories/public/SVG/test/timeseries.rb
59 59 #
60 60 # = Notes
61 61 #
62 62 # The default stylesheet handles upto 10 data sets, if you
63 63 # use more you must create your own stylesheet and add the
64 64 # additional settings for the extra data sets. You will know
65 65 # if you go over 10 data sets as they will have no style and
66 66 # be in black.
67 67 #
68 68 # Unlike the other types of charts, data sets must contain x,y pairs:
69 69 #
70 70 # [ "12:30", 2 ] # A data set with 1 point: ("12:30",2)
71 71 # [ "01:00",2, "14:20",6] # A data set with 2 points: ("01:00",2) and
72 72 # # ("14:20",6)
73 73 #
74 74 # Note that multiple data sets within the same chart can differ in length,
75 75 # and that the data in the datasets needn't be in order; they will be ordered
76 76 # by the plot along the X-axis.
77 77 #
78 78 # The dates must be parseable by ParseDate, but otherwise can be
79 79 # any order of magnitude (seconds within the hour, or years)
80 80 #
81 81 # = See also
82 82 #
83 83 # * SVG::Graph::Graph
84 84 # * SVG::Graph::BarHorizontal
85 85 # * SVG::Graph::Bar
86 86 # * SVG::Graph::Line
87 87 # * SVG::Graph::Pie
88 88 # * SVG::Graph::Plot
89 89 #
90 90 # == Author
91 91 #
92 92 # Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
93 93 #
94 94 # Copyright 2004 Sean E. Russell
95 95 # This software is available under the Ruby license[LICENSE.txt]
96 96 #
97 97 class TimeSeries < Plot
98 98 # In addition to the defaults set by Graph::initialize and
99 99 # Plot::set_defaults, sets:
100 100 # [x_label_format] '%Y-%m-%d %H:%M:%S'
101 101 # [popup_format] '%Y-%m-%d %H:%M:%S'
102 102 def set_defaults
103 103 super
104 104 init_with(
105 105 #:max_time_span => '',
106 106 :x_label_format => '%Y-%m-%d %H:%M:%S',
107 107 :popup_format => '%Y-%m-%d %H:%M:%S'
108 108 )
109 109 end
110 110
111 111 # The format string use do format the X axis labels.
112 112 # See Time::strformat
113 113 attr_accessor :x_label_format
114 114 # Use this to set the spacing between dates on the axis. The value
115 115 # must be of the form
116 116 # "\d+ ?(days|weeks|months|years|hours|minutes|seconds)?"
117 117 #
118 118 # EG:
119 119 #
120 120 # graph.timescale_divisions = "2 weeks"
121 121 #
122 122 # will cause the chart to try to divide the X axis up into segments of
123 123 # two week periods.
124 124 attr_accessor :timescale_divisions
125 125 # The formatting used for the popups. See x_label_format
126 126 attr_accessor :popup_format
127 127
128 128 # Add data to the plot.
129 129 #
130 130 # d1 = [ "12:30", 2 ] # A data set with 1 point: ("12:30",2)
131 131 # d2 = [ "01:00",2, "14:20",6] # A data set with 2 points: ("01:00",2) and
132 132 # # ("14:20",6)
133 133 # graph.add_data(
134 134 # :data => d1,
135 135 # :title => 'One'
136 136 # )
137 137 # graph.add_data(
138 138 # :data => d2,
139 139 # :title => 'Two'
140 140 # )
141 141 #
142 142 # Note that the data must be in time,value pairs, and that the date format
143 143 # may be any date that is parseable by ParseDate.
144 144 def add_data data
145 145 @data = [] unless @data
146 146
147 147 raise "No data provided by #{@data.inspect}" unless data[:data] and
148 148 data[:data].kind_of? Array
149 149 raise "Data supplied must be x,y pairs! "+
150 150 "The data provided contained an odd set of "+
151 151 "data points" unless data[:data].length % 2 == 0
152 152 return if data[:data].length == 0
153 153
154 154
155 155 x = []
156 156 y = []
157 157 data[:data].each_index {|i|
158 158 if i%2 == 0
159 159 t = DateTime.parse( data[:data][i] ).to_time
160 160 x << t.to_i
161 161 else
162 162 y << data[:data][i]
163 163 end
164 164 }
165 165 sort( x, y )
166 166 data[:data] = [x,y]
167 167 @data << data
168 168 end
169 169
170 170
171 171 protected
172 172
173 173 def min_x_value=(value)
174 @min_x_value = DateTime.parse( data[:data][i] ).to_time
174 @min_x_value = DateTime.parse( value ).to_time
175 175 end
176 176
177 177
178 178 def format x, y
179 179 Time.at( x ).strftime( popup_format )
180 180 end
181 181
182 182 def get_x_labels
183 183 get_x_values.collect { |v| Time.at(v).strftime( x_label_format ) }
184 184 end
185 185
186 186 private
187 187 def get_x_values
188 188 rv = []
189 189 min, max, scale_division = x_range
190 190 if timescale_divisions
191 191 timescale_divisions =~ /(\d+) ?(day|week|month|year|hour|minute|second)?/
192 192 division_units = $2 ? $2 : "day"
193 193 amount = $1.to_i
194 194 if amount
195 195 step = nil
196 196 case division_units
197 197 when "month"
198 198 cur = min
199 199 while cur < max
200 200 rv << cur
201 201 arr = Time.at( cur ).to_a
202 202 arr[4] += amount
203 203 if arr[4] > 12
204 204 arr[5] += (arr[4] / 12).to_i
205 205 arr[4] = (arr[4] % 12)
206 206 end
207 207 cur = Time.local(*arr).to_i
208 208 end
209 209 when "year"
210 210 cur = min
211 211 while cur < max
212 212 rv << cur
213 213 arr = Time.at( cur ).to_a
214 214 arr[5] += amount
215 215 cur = Time.local(*arr).to_i
216 216 end
217 217 when "week"
218 218 step = 7 * 24 * 60 * 60 * amount
219 219 when "day"
220 220 step = 24 * 60 * 60 * amount
221 221 when "hour"
222 222 step = 60 * 60 * amount
223 223 when "minute"
224 224 step = 60 * amount
225 225 when "second"
226 226 step = amount
227 227 end
228 228 min.step( max, step ) {|v| rv << v} if step
229 229
230 230 return rv
231 231 end
232 232 end
233 233 min.step( max, scale_division ) {|v| rv << v}
234 234 return rv
235 235 end
236 236 end
237 237 end
238 238 end
General Comments 0
You need to be logged in to leave comments. Login now