technical_graph 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,374 @@
1
+ h1. How to use it
2
+
3
+ p. All this examples are generated in test/test_technical_readme.rb.
4
+
5
+
6
+
7
+
8
+
9
+ h2. Simple graph
10
+
11
+ p. First thing we need to have data to show on graph, for example something like:
12
+
13
+ <pre>
14
+ <code>
15
+ @simple_data_array = [
16
+ { :x => 0, :y => 0 },
17
+ { :x => 1, :y => 1 },
18
+ { :x => 2, :y => 2 },
19
+ { :x => 3, :y => 2 },
20
+ { :x => 4, :y => 1 },
21
+ { :x => 5, :y => 0 },
22
+ ]
23
+ </code>
24
+ </pre>
25
+
26
+ p. If you want to put this data on graph you need to create TechnicalGraph object
27
+
28
+ <pre>
29
+ <code>
30
+ @tg = TechnicalGraph.new
31
+ </code>
32
+ </pre>
33
+
34
+ p. and add a layer.
35
+
36
+ <pre>
37
+ <code>
38
+ @tg.add_layer(@simple_data_array)
39
+ </code>
40
+ </pre>
41
+
42
+ p. We added data but we don't see anything. Now we have to render graph and save it to file.
43
+
44
+ <pre>
45
+ <code>
46
+ @tg.render
47
+ file_name = 'samples/readme/01_simplest.png'
48
+ @tg.image_drawer.save_to_file(file_name)
49
+ </code>
50
+ </pre>
51
+
52
+ p. And we got our first graph with one layer without any options changes, a bit raw.
53
+
54
+ !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/01_simplest.png((01) simple graph)!
55
+
56
+
57
+
58
+
59
+
60
+ h2. More layers
61
+
62
+ p. Maybe example with two layers?
63
+
64
+ <pre>
65
+ <code>
66
+ @simple_data_array = [
67
+ { :x => 0, :y => 0 },
68
+ { :x => 1, :y => 1 },
69
+ { :x => 2, :y => 2 },
70
+ { :x => 3, :y => 2 },
71
+ { :x => 4, :y => 1 },
72
+ { :x => 5, :y => 0 },
73
+ ]
74
+
75
+ @simple_data_array_b = [
76
+ { :x => 0.5, :y => 0.5 },
77
+ { :x => 1.5, :y => 0.5 },
78
+ { :x => 2.5, :y => 1.5 },
79
+ { :x => 3.5, :y => 1.0 },
80
+ { :x => 4.5, :y => 1.5 },
81
+ { :x => 5.5, :y => 1.5 },
82
+ ]
83
+
84
+ @tg = TechnicalGraph.new
85
+ @tg.add_layer(@simple_data_array)
86
+ @tg.add_layer(@simple_data_array_b)
87
+ @tg.render
88
+ file_name = 'samples/readme/02_two_layers.png'
89
+ @tg.image_drawer.save_to_file(file_name)
90
+ </code>
91
+ </pre>
92
+
93
+
94
+ !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/02_two_layers.png((02) simple graph)!
95
+
96
+
97
+
98
+
99
+ h2. Ranges
100
+
101
+ p. On default ranges are calculated automatically so all points are visible. You can override ranges setting.
102
+
103
+ <pre>
104
+ <code>
105
+ @simple_data_array = [
106
+ { :x => 0, :y => 0 },
107
+ { :x => 1, :y => 1 },
108
+ { :x => 2, :y => 2 },
109
+ { :x => 3, :y => 2 },
110
+ { :x => 4, :y => 1 },
111
+ { :x => 5, :y => 0 },
112
+ ]
113
+
114
+ @tg = TechnicalGraph.new(
115
+ {
116
+ :x_min => -2,
117
+ :x_max => 10,
118
+ :y_min => -1,
119
+ :y_max => 10,
120
+ })
121
+
122
+ @tg.add_layer(@simple_data_array)
123
+ @tg.render
124
+ file_name = 'samples/readme/03_changed_ranges.png'
125
+ @tg.image_drawer.save_to_file(file_name)
126
+ </code>
127
+ </pre>
128
+
129
+ !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/03_changed_ranges.png((03) changed ranges)!
130
+
131
+
132
+ p. Keep in mind that ranges will be changed but any point of graph can enlarge ranges that all points will be visible, unless...
133
+
134
+
135
+
136
+
137
+
138
+ h2. Fixed ranges
139
+
140
+ p. You can turn off automatic range enlargement algorithm by using:
141
+
142
+ <pre>
143
+ <code>
144
+ options[:xy_behaviour] = :fixed
145
+ </code>
146
+ </pre>
147
+
148
+ Example:
149
+
150
+ <pre>
151
+ <code>
152
+ @simple_data_array = [
153
+ { :x => 0, :y => 0 },
154
+ { :x => 1, :y => 1 },
155
+ { :x => 2, :y => 2 },
156
+ { :x => 3, :y => 2 },
157
+ { :x => 4, :y => 1 },
158
+ { :x => 5, :y => 0 },
159
+ ]
160
+
161
+ @tg = TechnicalGraph.new(
162
+ {
163
+ :x_min => 1,
164
+ :x_max => 2,
165
+ :y_min => 1,
166
+ :y_max => 2,
167
+ :xy_behaviour => :fixed,
168
+ })
169
+
170
+ @tg.add_layer(@simple_data_array)
171
+ @tg.render
172
+ file_name = 'samples/readme/04_changed_ranges_fixed.png'
173
+ @tg.image_drawer.save_to_file(file_name)
174
+ </code>
175
+ </pre>
176
+
177
+ !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/04_changed_ranges_fixed.png((04) changed ranges)!
178
+
179
+
180
+
181
+
182
+ h2. Axis interval - fixed count
183
+
184
+ p. Axis can be calculated using two algorithms:
185
+
186
+ # fixed interval - axis is every some distance,
187
+ # fixed count - there is fixed amount of axis on graph.
188
+
189
+ p. Keep in mind that where is X (parameter) and Y (value) axis. If you want to set fixed amount you should set
190
+ options[:x_axis_fixed_interval] and/or options[:y_axis_fixed_interval] to false, like in the example below.
191
+
192
+ <pre>
193
+ <code>
194
+ @simple_data_array = [
195
+ { :x => 0, :y => 0 },
196
+ { :x => 1, :y => 1 },
197
+ { :x => 2, :y => 2 },
198
+ { :x => 3, :y => 2 },
199
+ { :x => 4, :y => 1 },
200
+ { :x => 5, :y => 0 },
201
+ ]
202
+
203
+ @tg = TechnicalGraph.new(
204
+ {
205
+ :x_axis_fixed_interval => false,
206
+ :y_axis_fixed_interval => false,
207
+ :y_axis_count => 20,
208
+ :x_axis_count => 20,
209
+ })
210
+
211
+ @tg.add_layer(@simple_data_array)
212
+ @tg.render
213
+ file_name = 'samples/readme/05_axis_fixed_amount.png'
214
+ @tg.image_drawer.save_to_file(file_name)
215
+ </code>
216
+ </pre>
217
+
218
+ !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/05_axis_fixed_amount.png((05) fixed axis count)!
219
+
220
+
221
+
222
+
223
+ h2. Axis interval - fixed interval
224
+
225
+ p. Axis can be calculated using two algorithms:
226
+
227
+ # fixed interval - axis is every some distance,
228
+ # fixed count - there is fixed amount of axis on graph.
229
+
230
+ p. Keep in mind that where is X (parameter) and Y (value) axis. If you want to set fixed amount you should set
231
+ options[:x_axis_fixed_interval] and/or options[:y_axis_fixed_interval] to false, like in the example below.
232
+
233
+ <pre>
234
+ <code>
235
+ @simple_data_array = [
236
+ { :x => 0, :y => 0 },
237
+ { :x => 1, :y => 1 },
238
+ { :x => 2, :y => 2 },
239
+ { :x => 3, :y => 2 },
240
+ { :x => 4, :y => 1 },
241
+ { :x => 5, :y => 0 },
242
+ ]
243
+
244
+ @tg = TechnicalGraph.new(
245
+ {
246
+ :x_axis_fixed_interval => true,
247
+ :y_axis_fixed_interval => true,
248
+ :y_axis_interval => 0.8,
249
+ :x_axis_interval => 0.6,
250
+ })
251
+ @tg.add_layer(@simple_data_array)
252
+ @tg.render
253
+ file_name = 'samples/readme/06_axis_fixed_interval.png'
254
+ @tg.image_drawer.save_to_file(file_name)
255
+ </code>
256
+ </pre>
257
+
258
+ !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/06_axis_fixed_interval.png((06) fixed axis interval)!
259
+
260
+
261
+
262
+
263
+
264
+
265
+ h2. Axis labels
266
+
267
+ p. You can add label to X and Y axis. using options[:x_axis_label] and options[:y_axis_label], and you can choose font
268
+ size using options[:axis_label_font_size].
269
+
270
+ <pre>
271
+ <code>
272
+ @simple_data_array = [
273
+ { :x => 0, :y => 0 },
274
+ { :x => 1, :y => 1 },
275
+ { :x => 2, :y => 2 },
276
+ { :x => 3, :y => 2 },
277
+ { :x => 4, :y => 1 },
278
+ { :x => 5, :y => 0 },
279
+ ]
280
+
281
+ @tg = TechnicalGraph.new(
282
+ {
283
+ :x_axis_label => 'parameter',
284
+ :y_axis_label => 'value',
285
+ :axis_label_font_size => 36
286
+ })
287
+ @@tg.add_layer(@simple_data_array)
288
+ @tg.render
289
+ file_name = 'samples/readme/07_axis_label.png'
290
+ @tg.image_drawer.save_to_file(file_name)
291
+ </code>
292
+ </pre>
293
+
294
+ !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/07_axis_label.png((07) axis labels)!
295
+
296
+
297
+
298
+ h2. Float numbers and value labels
299
+
300
+ p. On default all float number are shown using 2 digits after dot. You can override it using options[:truncate_string]
301
+ like in example below. If you want have values near graph points you can use proper layer options.
302
+
303
+ p. Layers have also options, and it is useful for this example to turn on value labels.
304
+
305
+ layer_options[:value_labels]
306
+
307
+ <pre>
308
+ <code>
309
+ @float_data_array = [
310
+ { :x => 0, :y => 0 },
311
+ { :x => 0.111, :y => 0.123 },
312
+ { :x => 0.222, :y => 1.456 },
313
+ { :x => 0.333, :y => 2.8756 },
314
+ { :x => 0.555, :y => 1.042 },
315
+ { :x => 0.888, :y => 0.988 },
316
+ ]
317
+
318
+ @tg = TechnicalGraph.new(
319
+ {
320
+ :truncate_string => "%.3f"
321
+ })
322
+ @layer_params = {
323
+ :value_labels => true
324
+ }
325
+ @tg.add_layer(@float_data_array, @layer_params)
326
+ @tg.render
327
+ file_name = 'samples/readme/08a_truncate_string.png'
328
+ @tg.image_drawer.save_to_file(file_name)
329
+ </code>
330
+ </pre>
331
+
332
+ !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/08a_truncate_string.png((08a) displaying float numbers)!
333
+
334
+ <pre>
335
+ <code>
336
+ @float_data_array = [
337
+ { :x => 0, :y => 0 },
338
+ { :x => 0.111, :y => 0.123 },
339
+ { :x => 0.222, :y => 1.456 },
340
+ { :x => 0.333, :y => 2.8756 },
341
+ { :x => 0.555, :y => 1.042 },
342
+ { :x => 0.888, :y => 0.988 },
343
+ ]
344
+
345
+ @tg = TechnicalGraph.new(
346
+ {
347
+ :truncate_string => "%.1f"
348
+ })
349
+ @layer_params = {
350
+ :value_labels => true
351
+ }
352
+ @tg.add_layer(@float_data_array, @layer_params)
353
+ @tg.render
354
+ file_name = 'samples/readme/08b_truncate_string.png'
355
+ @tg.image_drawer.save_to_file(file_name)
356
+ </code>
357
+ </pre>
358
+
359
+ !https://github.com/akwiatkowski/technical_graph/raw/master/samples/readme/08b_truncate_string.png((08b) displaying float numbers)!
360
+
361
+
362
+ h2. TODO
363
+
364
+ # Graph image size
365
+ # Graph colors: background, hatch (option to turn it off?), axis
366
+ # Anti-aliasing: image size comparison, layer antialiases
367
+ # Font sizes
368
+ # Axis density checking algorithm: sample when it us useful
369
+ # Layer labels: used in legend
370
+ # Layer colors, random colors
371
+ # Legend with set position
372
+ # Legend with auto position
373
+ # Smoother:
374
+ # Noise removal
data/README.md CHANGED
@@ -1,11 +1,38 @@
1
- technical-graph
1
+ technical_graph
2
2
  ===============
3
3
 
4
- Create neat graphs.
4
+ Purpose of this gem is to create neat, meaningful, linear graphs for large amount of data.
5
5
 
6
+ If you want to:
6
7
 
7
- Usage
8
- -----
8
+ * create big graphs using large amount of data,
9
+ * do it offline,
10
+ * minimize needed code,
11
+ * use only linear graph,
12
+ * speed is not essential,
13
+ * RMagick / ImageMagick is ok for you,
14
+ * tired of forgotten gems/libraries...
15
+
16
+ then you should try this gem.
17
+
18
+ I created it because there were not available and maintained gems for that I needed. Now I use it to create hourly
19
+ temperature and wind graphs for vast period of time (months, years), visualize measurements for [HomeIO](https://github.com/akwiatkowski/HomeIO).
20
+
21
+ If you want to create candy, ultra fast, web graphs it maybe not the best tool. If you want other graph types than linear it
22
+ is definitely not the right tool for you. It is also not SVG ready yet, but it should be within a few months.
23
+ You can find my competitors [here](https://www.ruby-toolbox.com/categories/graphing).
24
+
25
+
26
+ Future
27
+ ------
28
+
29
+ 1. Finish data processors: smoothing (nearly done), noise removal (50%), interpolation or curved graphs (planned).
30
+ 2. Fix export to SVG.
31
+ 3. Optimization, and if needed find or write something faster for creating SVGs.
32
+
33
+
34
+ Quick start
35
+ -----------
9
36
 
10
37
  Check currents test when documentation is not enough :)
11
38
 
@@ -32,7 +59,7 @@ or
32
59
  where:
33
60
 
34
61
  * layer_data - Array of Hashes, like [{:x => 0, :y => 0}, {:x => 1, :y => 1}, ...]
35
- * layer_params - Hash of other parameters, all parameters will be described later.
62
+ * layer_params - Hash of other parameters, all parameters are described later.
36
63
 
37
64
  3. Render graph
38
65
 
@@ -46,101 +73,13 @@ or get image binary content.
46
73
 
47
74
  > tg.image_drawer.to_format(format)
48
75
 
49
- where format is image format, ex. 'png', 'jpeg', ...
76
+ where format is image format, ex. 'png', 'jpeg', ... Of course I prefer 'png'.
50
77
 
51
78
 
52
- Options Hash
79
+ Documentation
53
80
  -------------
54
81
 
55
- Default ranges:
56
-
57
- * options[:x_min]
58
- * options[:x_max]
59
- * options[:y_min]
60
- * options[:y_max]
61
-
62
- Ranges calculation mode:
63
-
64
- * options[:xy_behaviour] = :default - ranges can be enlarged
65
- * options[:xy_behaviour] = :fixed - fixed ranges
66
-
67
- Axis can be calculated using fixed interval or fixed count per graph.
68
-
69
- * options[:x_axis_fixed_interval] = true
70
- * options[:y_axis_fixed_interval] = true
71
-
72
- If fixed interval is set you should specify interval:
73
-
74
- * options[:y_axis_interval] = 1.0
75
- * options[:x_axis_interval] = 1.0
76
-
77
- ...else, count of axis:
78
-
79
- * options[:y_axis_count] = 10
80
- * options[:x_axis_count] = 10
81
-
82
- Axis labels:
83
-
84
- * options[:x_axis_label] = 'x'
85
- * options[:y_axis_label] = 'y'
86
-
87
-
88
- Labels has truncate string to define precision. Default it is "%.2f".
89
-
90
- * options[:truncate_string] = "%.2f"
91
-
92
- Graph image size:
93
-
94
- * options[:width]
95
- * options[:height]
96
-
97
- Colors:
98
-
99
- Possible #RRGGBB or color names (ex. 'white').
100
-
101
- * options[:background_color] - background color of image
102
- * options[:background_hatch_color] - background hatch color
103
- * options[:axis_color] - color of axis
104
-
105
- Anti-aliasing:
106
-
107
- * options[:axis_antialias] - use anti-aliasing for axis, default false
108
- * options[:layers_antialias] - use anti-aliasing for data layers, default false, can be override using layer option
109
- * options[:font_antialias] - use anti-aliasing for all fonts, default false
110
-
111
- Font size:
112
-
113
- * options[:layers_font_size] - size of font used for values in graph
114
- * options[:axis_font_size] - size of font used in axis
115
- * options[:axis_label_font_size] - size of font used in options[:x_axis_label] and options[:y_axis_label]
116
-
117
- Sometime because of axis options and large amount of data, axis can be put densely on graph. Turning this option graph
118
- size will be enlarged to maintain set distanced between axis.
119
-
120
- * options[:axis_density_enlarge_image] - turn this options on
121
- * options[:x_axis_min_distance] - minimum distance between X axis, default 30 pixels
122
- * options[:y_axis_min_distance] - minimum distance between X axis, default 50 pixels
123
-
124
- Legend options:
125
-
126
- * options[:legend] - do you want to draw legend?, default false
127
- * options[:legend_auto] - let legend position to be chosen by algorithm, default true
128
- * options[:legend_width] - width used for setting proper distance while drawing on right, default 100, legend height is calculated
129
- * options[:legend_margin] - graph margin used not to draw legend on border, default 50
130
- * options[:legend_x] - legend X position, used when options[:legend_auto] is false, default 50
131
- * options[:legend_y] - legend Y position, used when options[:legend_auto] is false, default 50
132
-
133
-
134
- Layer options Hash
135
- ------------------
136
-
137
- * layer_options[:label] - label used in legend
138
- * layer_options[:color] - color of graph layer, ex.: 'red', 'green', '#FFFF00'
139
- * layer_options[:antialias] - use anti-aliasing for this, default false, override options[:layers_antialias]
140
- * layer_options[:value_labels] - write values near 'dots', default true
141
- * layer_options[:simple_smoother] - 'smooth' data, default false
142
- * layer_options[:simple_smoother_level] - strength of smoothing, this is level of window used for processing, default 3
143
- * layer_options[:simple_smoother_strategy] - strategy used for smoothing data, you can choose between :rectangular or :gauss, default :rectangular
82
+ Documentation is moved [here](https://github.com/akwiatkowski/technical_graph/blob/master/DOCUMENTATION.textile)
144
83
 
145
84
 
146
85
  Contributing to technical-graph
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.3.1
@@ -0,0 +1,14 @@
1
+ #encoding: utf-8
2
+
3
+ # Additional methods for array
4
+ # http://stackoverflow.com/questions/1341271/average-from-a-ruby-array
5
+
6
+ class Array
7
+ def sum
8
+ inject(0.0) { |result, el| result + el }
9
+ end
10
+
11
+ def mean
12
+ sum / size
13
+ end
14
+ end
@@ -1,5 +1,6 @@
1
1
  #encoding: utf-8
2
2
 
3
+ require 'technical_graph/data_point'
3
4
  require 'technical_graph/graph_color_library'
4
5
  require 'technical_graph/data_layer_processor'
5
6
 
@@ -20,8 +21,9 @@ class DataLayer
20
21
  # smoothing parameters
21
22
  # by default it is false
22
23
  @data_params[:simple_smoother] = true if options[:simple_smoother] == true
24
+ @data_params[:simple_smoother_x] = true if options[:simple_smoother_x] == true
23
25
  @data_params[:simple_smoother_level] ||= 3
24
- @data_params[:simple_smoother_strategy] ||= DataLayerProcessor::DEFAULT_STRATEGY
26
+ @data_params[:simple_smoother_strategy] ||= DataLayerProcessor::DEFAULT_SIMPLE_SMOOTHER_STRATEGY
25
27
  # was already done
26
28
  @data_params[:processor_finished] = false
27
29
 
@@ -36,29 +38,42 @@ class DataLayer
36
38
  attr_reader :processor
37
39
 
38
40
  # Accessor for setting chart data for layer to draw
39
- def append_data(d)
40
- if d.kind_of? Array
41
- @data += d
41
+ def append_data(data_array)
42
+ if data_array.kind_of? Array
43
+ # append as DataPoint
44
+ # convert to DataPoints, which has more specialized methods
45
+ data_array.each do |d|
46
+ @data << DataPoint.new(d)
47
+ end
48
+
42
49
  # sort, clean bad records
43
- process_data
50
+ process_data_internal
51
+
52
+ # @raw_data is dirty, deleting @processed_data
53
+ @processed_data = nil
44
54
  else
45
55
  raise 'Data not an Array'
46
56
  end
47
57
  end
48
58
 
49
- # Array of {:x =>, :y =>}
50
- attr_reader :data
59
+ # Array of DataPoints, not processed
60
+ def raw_data
61
+ @data
62
+ end
51
63
 
52
- # Run external processor (smoothing, ...)
53
- def process
54
- if simple_smoother and not processor_finished?
55
- @processor.strategy = simple_smoother_strategy
56
- @processor.level = simple_smoother_level
57
- @processor.generate_vector
58
- @data = @processor.process
59
-
60
- processor_finished!
64
+ # Array of DataPoints, after external processing
65
+ def processed_data
66
+ if @processed_data.nil?
67
+ process!
61
68
  end
69
+
70
+ @processed_data
71
+ end
72
+
73
+ # Run external processor (smoothing, ...)
74
+ def process!
75
+ @processed_data = @data.clone
76
+ @processed_data = @processor.process
62
77
  end
63
78
 
64
79
  # Additional parameters
@@ -97,14 +112,8 @@ class DataLayer
97
112
  return @data_params[:simple_smoother_strategy]
98
113
  end
99
114
 
100
- # Was already processed?
101
- def processor_finished?
102
- @data_params[:processor_finished]
103
- end
104
-
105
- # Mark as processed
106
- def processor_finished!
107
- @data_params[:processor_finished] = true
115
+ def simple_smoother_x
116
+ return @data_params[:simple_smoother_x]
108
117
  end
109
118
 
110
119
  # Clear data
@@ -113,24 +122,23 @@ class DataLayer
113
122
  end
114
123
 
115
124
  # Clean and process data used for drawing current data layer
116
- def process_data
125
+ def process_data_internal
117
126
  # delete duplicates
118
- @data = @data.inject([]) { |result, d| result << d unless result.select { |r| r[:x] == d[:x] }.size > 0; result }
127
+ @data = @data.inject([]) { |result, d| result << d unless result.select { |r| r.x == d.x }.size > 0; result }
119
128
 
120
- @data.delete_if { |d| d[:x].nil? or d[:y].nil? }
121
- @data.sort! { |d, e| d[:x] <=> e[:x] }
129
+ @data.delete_if { |d| d.x.nil? or d.y.nil? }
130
+ @data.sort! { |d, e| d.x <=> e.x }
122
131
 
123
132
  # default X values, if data is not empty
124
133
  if @data.size > 0
125
- @data_params[:x_min] = @data.first[:x] || @options[:default_x_min]
126
- @data_params[:x_max] = @data.last[:x] || @options[:default_x_max]
134
+ @data_params[:x_min] = @data.first.x || @options[:default_x_min]
135
+ @data_params[:x_max] = @data.last.x || @options[:default_x_max]
127
136
 
128
137
  # default Y values
129
- y_sort = @data.sort { |a, b| a[:y] <=> b[:y] }
130
- @data_params[:y_min] = y_sort.first[:y] || @options[:default_y_min]
131
- @data_params[:y_max] = y_sort.last[:y] || @options[:@default_y_max]
138
+ y_sort = @data.sort { |a, b| a.y <=> b.y }
139
+ @data_params[:y_min] = y_sort.first.y || @options[:default_y_min]
140
+ @data_params[:y_max] = y_sort.last.y || @options[:@default_y_max]
132
141
  end
133
-
134
142
  end
135
143
 
136
144
  def x_min