gnuplotrb 0.3.1 → 0.3.2

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.
@@ -1,299 +1,299 @@
1
- module GnuplotRB
2
- ##
3
- # Class corresponding to simple 2D visualisation.
4
- #
5
- # == Notebooks
6
- #
7
- # * {Heatmaps}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/heatmaps.ipynb]
8
- # * {Vector field}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/vector_field.ipynb]
9
- # * {Math equations}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/math_plots.ipynb]
10
- # * {Histogram}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/histogram.ipynb]
11
- # * {Updating plots with new data}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/updating_data.ipynb]
12
- #
13
- # == Options
14
- # All possible options are exaplained in
15
- # {gnuplot docs}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] (pp. 105-190).
16
- #
17
- # Several common ones:
18
- #
19
- # * xrange(yrange, zrange, urange, vrange) - set range for a variable. Takes
20
- # Range (xrange: 0..100), or String (yrange: '[0:100]').
21
- # * title - plot's title. Takes String (title: 'Some new plot').
22
- # * polar (parametric) - plot in polar or parametric space. Takes boolean (true).
23
- # * style_data - set style for plotting data. Takes string, possible values: histogram,
24
- # points, lines, linespoints, boxes etc. See gnuplot docs for more.
25
- # * term - select terminal used by gnuplot. Examples: { term: 'png' },
26
- # { term: ['svg', size: [600, 600]] }. Deprecated due to existance of #to_<term_name> methods.
27
- # One can use #to_png and #to_svg(size: [600, 600]) instead of passing previous options.
28
- # * output - select filename to output plot to. Should be used together with term. Deprecated
29
- # due to existance of #to_<term_name> methods. One should use #to_png('file.png') instead of
30
- # passing { term: 'png', output: 'file.png' }.
31
- # Every option may be passed to constructor in order to create plot with it.
32
- #
33
- # Methods #options(several: options, ...) and bunch of #option_name(only_an: option) such as
34
- # #xrange, #using, #polar etc create new Plot object based on existing but with a new options.
35
- #
36
- # Methods with the same names ending with '!' or '=' ('plot.xrange!(1..3)',
37
- # 'plot.title = "New title"') are destructive and modify state of existing object just as
38
- # "Array#sort!" do with Array object. See notebooks for examples.
39
- class Plot
40
- include Plottable
41
- ##
42
- # Array of datasets which are plotted by this object.
43
- attr_reader :datasets
44
- ##
45
- # @param *datasets [Sequence of Dataset or Array] either instances of Dataset class or
46
- # "[data, **dataset_options]"" arrays
47
- # @param options [Hash] see Plot top level doc for options examples
48
- def initialize(*datasets)
49
- # had to relace **options arg with this because in some cases
50
- # Daru::DataFrame was mentioned as hash and added to options
51
- # instead of plots
52
- @options = Hamster.hash
53
- if datasets[-1].is_a?(Hamster::Hash) || datasets[-1].is_a?(Hash)
54
- @options = Hamster.hash(datasets[-1])
55
- datasets = datasets[0..-2]
56
- end
57
- @datasets = parse_datasets_array(datasets)
58
- @cmd = 'plot '
59
- OptionHandling.validate_terminal_options(@options)
60
- yield(self) if block_given?
61
- end
62
-
63
- ##
64
- # Output plot to term (if given) or to this plot's own terminal.
65
- #
66
- # @param term [Terminal] Terminal object to plot to
67
- # @param :multiplot_part [Boolean] true if this plot is part of a multiplot. For inner use!
68
- # @param options [Hash] see options in Plot top level doc.
69
- # Options passed here have priority over already existing.
70
- # @return [Plot] self
71
- def plot(term = nil, multiplot_part: false, **options)
72
- fail ArgumentError, 'Empty plots are not supported!' if @datasets.empty?
73
- inner_opts = if multiplot_part
74
- @options.merge(options).reject { |key, _| [:term, :output].include?(key) }
75
- else
76
- @options.merge(options)
77
- end
78
- terminal = term || (inner_opts[:output] ? Terminal.new : own_terminal)
79
- ds_string = @datasets.map { |dataset| dataset.to_s(terminal) }.join(' , ')
80
- full_command = @cmd + ds_string
81
- terminal.set(inner_opts).stream_puts(full_command).unset(inner_opts.keys)
82
- if inner_opts[:output]
83
- # guaranteed wait for plotting to finish
84
- terminal.close unless term
85
- # not guaranteed wait for plotting to finish
86
- # work bad with terminals like svg and html
87
- sleep 0.01 until File.size?(inner_opts[:output])
88
- end
89
- self
90
- end
91
-
92
- alias_method :replot, :plot
93
-
94
- ##
95
- # Create new Plot object where dataset at *position* will
96
- # be replaced with the new one created from it by updating.
97
- #
98
- # @param position [Integer] position of dataset which you need to update
99
- # (by default first dataset is updated)
100
- # @param data [#to_gnuplot_points] data to update dataset with
101
- # @param options [Hash] options to update dataset with, see Dataset top level doc
102
- #
103
- # @example
104
- # updated_plot = plot.update_dataset(data: [x1,y1], title: 'After update')
105
- # # plot IS NOT affected (if dataset did not store data in a file)
106
- def update_dataset(position = 0, data: nil, **options)
107
- old_ds = @datasets[position]
108
- new_ds = old_ds.update(data, options)
109
- new_ds.equal?(old_ds) ? self : replace_dataset(position, new_ds)
110
- end
111
-
112
- ##
113
- # Updates existing Plot object by replacing dataset at *position*
114
- # with the new one created from it by updating.
115
- #
116
- # @param position [Integer] position of dataset which you need to update
117
- # (by default first dataset is updated)
118
- # @param data [#to_gnuplot_points] data to update dataset with
119
- # @param options [Hash] options to update dataset with, see Dataset top level doc
120
- #
121
- # @example
122
- # plot.update_dataset!(data: [x1,y1], title: 'After update')
123
- # # plot IS affected anyway
124
- def update_dataset!(position = 0, data: nil, **options)
125
- @datasets[position].update!(data, options)
126
- self
127
- end
128
-
129
- ##
130
- # Create new Plot object where dataset at *position* will
131
- # be replaced with the given one.
132
- #
133
- # @param position [Integer] position of dataset which you need to replace
134
- # (by default first dataset is replaced)
135
- # @param dataset [Dataset, Array] dataset to replace the old one. You can also
136
- # give here "[data, **dataset_options]"" array from which Dataset may be created.
137
- # @example
138
- # sinx = Plot.new('sin(x)')
139
- # cosx = sinx.replace_dataset(['cos(x)'])
140
- # # sinx IS NOT affected
141
- def replace_dataset(position = 0, dataset)
142
- self.class.new(@datasets.set(position, dataset_from_any(dataset)), @options)
143
- end
144
-
145
- ##
146
- # Updates existing Plot object by replacing dataset at *position*
147
- # with the given one.
148
- #
149
- # @param position [Integer] position of dataset which you need to replace
150
- # (by default first dataset is replaced)
151
- # @param dataset [Dataset, Array] dataset to replace the old one. You can also
152
- # give here "[data, **dataset_options]"" array from which Dataset may be created.
153
- # @example
154
- # sinx = Plot.new('sin(x)')
155
- # sinx.replace_dataset!(['cos(x)'])
156
- # # sinx IS affected
157
- def replace_dataset!(position = 0, dataset)
158
- @datasets = @datasets.set(position, dataset_from_any(dataset))
159
- self
160
- end
161
-
162
- alias_method :[]=, :replace_dataset!
163
-
164
- ##
165
- # Create new Plot object where given datasets will
166
- # be inserted into dataset list before given position
167
- # (position = 0 by default).
168
- #
169
- # @param position [Integer] position of dataset BEFORE which datasets will be placed.
170
- # 0 by default.
171
- # @param *datasets [ Sequence of Dataset or Array] datasets to insert
172
- # @example
173
- # sinx = Plot.new('sin(x)')
174
- # sinx_and_cosx_with_expx = sinx.add(['cos(x)'], ['exp(x)'])
175
- #
176
- # cosx_and_sinx = sinx << ['cos(x)']
177
- # # sinx IS NOT affected in both cases
178
- def add_datasets(*datasets)
179
- datasets.map! { |ds| ds.is_a?(Numeric) ? ds : dataset_from_any(ds) }
180
- # first element is position where to add datasets
181
- datasets.unshift(0) unless datasets[0].is_a?(Numeric)
182
- self.class.new(@datasets.insert(*datasets), @options)
183
- end
184
-
185
- alias_method :add_dataset, :add_datasets
186
- alias_method :<<, :add_datasets
187
-
188
- ##
189
- # Updates existing Plot object by inserting given datasets
190
- # into dataset list before given position (position = 0 by default).
191
- #
192
- # @param position [Integer] position of dataset BEFORE which datasets will be placed.
193
- # 0 by default.
194
- # @param *datasets [ Sequence of Dataset or Array] datasets to insert
195
- # @example
196
- # sinx = Plot.new('sin(x)')
197
- # sinx.add!(['cos(x)'], ['exp(x)'])
198
- # # sinx IS affected
199
- def add_datasets!(*datasets)
200
- datasets.map! { |ds| ds.is_a?(Numeric) ? ds : dataset_from_any(ds) }
201
- # first element is position where to add datasets
202
- datasets.unshift(0) unless datasets[0].is_a?(Numeric)
203
- @datasets = @datasets.insert(*datasets)
204
- self
205
- end
206
-
207
- alias_method :add_dataset!, :add_datasets!
208
-
209
- ##
210
- # Create new Plot object where dataset at given position
211
- # will be removed from dataset list.
212
- #
213
- # @param position [Integer] position of dataset that should be
214
- # removed (by default last dataset is removed)
215
- # @example
216
- # sinx_and_cosx = Plot.new('sin(x)', 'cos(x)')
217
- # sinx = sinx_and_cosx.remove_dataset
218
- # cosx = sinx_and_cosx.remove_dataset(0)
219
- # # sinx_and_cosx IS NOT affected in both cases
220
- def remove_dataset(position = -1)
221
- self.class.new(@datasets.delete_at(position), @options)
222
- end
223
-
224
- ##
225
- # Updates existing Plot object by removing dataset at given position.
226
- #
227
- # @param position [Integer] position of dataset that should be
228
- # removed (by default last dataset is removed)
229
- # @example
230
- # sinx_and_cosx = Plot.new('sin(x)', 'cos(x)')
231
- # sinx_and_cosx!.remove_dataset
232
- # sinx_and_cosx!.remove_dataset
233
- # # sinx_and_cosx IS affected and now is empty
234
- def remove_dataset!(position = -1)
235
- @datasets = @datasets.delete_at(position)
236
- self
237
- end
238
-
239
- ##
240
- # The same as #datasets[*args]
241
- def [](*args)
242
- @datasets[*args]
243
- end
244
-
245
- private
246
-
247
- ##
248
- # Checks several conditions and set options needed
249
- # to handle DateTime indexes properly.
250
- def provide_with_datetime_format(data, using)
251
- return unless defined?(Daru)
252
- return unless data.is_a?(Daru::DataFrame) || data.is_a?(Daru::Vector)
253
- return unless data.index.first.is_a?(DateTime)
254
- return if using[0..1] != '1:'
255
- @options = Hamster::Hash.new(
256
- xdata: 'time',
257
- timefmt: '%Y-%m-%dT%H:%M:%S',
258
- format_x: '%d\n%b\n%Y'
259
- ).merge(@options)
260
- end
261
-
262
- ##
263
- # Check if given args is a dataset and returns it. Creates
264
- # new dataset from given args otherwise.
265
- def dataset_from_any(source)
266
- ds = case source
267
- # when initialized with dataframe (it passes here several vectors)
268
- when (defined?(Daru) ? Daru::Vector : nil)
269
- Dataset.new(source)
270
- when Dataset
271
- source.clone
272
- else
273
- Dataset.new(*source)
274
- end
275
- data = source.is_a?(Array) ? source[0] : source
276
- provide_with_datetime_format(data, ds.using)
277
- ds
278
- end
279
-
280
- ##
281
- # Parses given array and returns Hamster::Vector of Datasets
282
- def parse_datasets_array(datasets)
283
- case datasets[0]
284
- when Hamster::Vector
285
- datasets[0]
286
- when (defined?(Daru) ? Daru::DataFrame : nil)
287
- Hamster::Vector.new(datasets[0].map { |ds| dataset_from_any(ds) })
288
- else
289
- Hamster::Vector.new(datasets.map { |ds| dataset_from_any(ds) })
290
- end
291
- end
292
-
293
- ##
294
- # Creates new Plot with existing data and given options.
295
- def new_with_options(options)
296
- self.class.new(@datasets, options)
297
- end
298
- end
299
- end
1
+ module GnuplotRB
2
+ ##
3
+ # Class corresponding to simple 2D visualisation.
4
+ #
5
+ # == Notebooks
6
+ #
7
+ # * {Heatmaps}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/heatmaps.ipynb]
8
+ # * {Vector field}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/vector_field.ipynb]
9
+ # * {Math equations}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/math_plots.ipynb]
10
+ # * {Histogram}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/histogram.ipynb]
11
+ # * {Updating plots with new data}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/updating_data.ipynb]
12
+ #
13
+ # == Options
14
+ # All possible options are exaplained in
15
+ # {gnuplot docs}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] (pp. 105-190).
16
+ #
17
+ # Several common ones:
18
+ #
19
+ # * xrange(yrange, zrange, urange, vrange) - set range for a variable. Takes
20
+ # Range (xrange: 0..100), or String (yrange: '[0:100]').
21
+ # * title - plot's title. Takes String (title: 'Some new plot').
22
+ # * polar (parametric) - plot in polar or parametric space. Takes boolean (true).
23
+ # * style_data - set style for plotting data. Takes string, possible values: histogram,
24
+ # points, lines, linespoints, boxes etc. See gnuplot docs for more.
25
+ # * term - select terminal used by gnuplot. Examples: { term: 'png' },
26
+ # { term: ['svg', size: [600, 600]] }. Deprecated due to existance of #to_<term_name> methods.
27
+ # One can use #to_png and #to_svg(size: [600, 600]) instead of passing previous options.
28
+ # * output - select filename to output plot to. Should be used together with term. Deprecated
29
+ # due to existance of #to_<term_name> methods. One should use #to_png('file.png') instead of
30
+ # passing { term: 'png', output: 'file.png' }.
31
+ # Every option may be passed to constructor in order to create plot with it.
32
+ #
33
+ # Methods #options(several: options, ...) and bunch of #option_name(only_an: option) such as
34
+ # #xrange, #using, #polar etc create new Plot object based on existing but with a new options.
35
+ #
36
+ # Methods with the same names ending with '!' or '=' ('plot.xrange!(1..3)',
37
+ # 'plot.title = "New title"') are destructive and modify state of existing object just as
38
+ # "Array#sort!" do with Array object. See notebooks for examples.
39
+ class Plot
40
+ include Plottable
41
+ ##
42
+ # Array of datasets which are plotted by this object.
43
+ attr_reader :datasets
44
+ ##
45
+ # @param *datasets [Sequence of Dataset or Array] either instances of Dataset class or
46
+ # "[data, **dataset_options]"" arrays
47
+ # @param options [Hash] see Plot top level doc for options examples
48
+ def initialize(*datasets)
49
+ # had to relace **options arg with this because in some cases
50
+ # Daru::DataFrame was mentioned as hash and added to options
51
+ # instead of plots
52
+ @options = Hamster.hash
53
+ if datasets[-1].is_a?(Hamster::Hash) || datasets[-1].is_a?(Hash)
54
+ @options = Hamster.hash(datasets[-1])
55
+ datasets = datasets[0..-2]
56
+ end
57
+ @datasets = parse_datasets_array(datasets)
58
+ @cmd = 'plot '
59
+ OptionHandling.validate_terminal_options(@options)
60
+ yield(self) if block_given?
61
+ end
62
+
63
+ ##
64
+ # Output plot to term (if given) or to this plot's own terminal.
65
+ #
66
+ # @param term [Terminal] Terminal object to plot to
67
+ # @param :multiplot_part [Boolean] true if this plot is part of a multiplot. For inner use!
68
+ # @param options [Hash] see options in Plot top level doc.
69
+ # Options passed here have priority over already existing.
70
+ # @return [Plot] self
71
+ def plot(term = nil, multiplot_part: false, **options)
72
+ fail ArgumentError, 'Empty plots are not supported!' if @datasets.empty?
73
+ inner_opts = if multiplot_part
74
+ @options.merge(options).reject { |key, _| [:term, :output].include?(key) }
75
+ else
76
+ @options.merge(options)
77
+ end
78
+ terminal = term || (inner_opts[:output] ? Terminal.new : own_terminal)
79
+ ds_string = @datasets.map { |dataset| dataset.to_s(terminal) }.join(' , ')
80
+ full_command = @cmd + ds_string
81
+ terminal.set(inner_opts).stream_puts(full_command).unset(inner_opts.keys)
82
+ if inner_opts[:output]
83
+ # guaranteed wait for plotting to finish
84
+ terminal.close unless term
85
+ # not guaranteed wait for plotting to finish
86
+ # work bad with terminals like svg and html
87
+ sleep 0.01 until File.size?(inner_opts[:output])
88
+ end
89
+ self
90
+ end
91
+
92
+ alias_method :replot, :plot
93
+
94
+ ##
95
+ # Create new Plot object where dataset at *position* will
96
+ # be replaced with the new one created from it by updating.
97
+ #
98
+ # @param position [Integer] position of dataset which you need to update
99
+ # (by default first dataset is updated)
100
+ # @param data [#to_gnuplot_points] data to update dataset with
101
+ # @param options [Hash] options to update dataset with, see Dataset top level doc
102
+ #
103
+ # @example
104
+ # updated_plot = plot.update_dataset(data: [x1,y1], title: 'After update')
105
+ # # plot IS NOT affected (if dataset did not store data in a file)
106
+ def update_dataset(position = 0, data: nil, **options)
107
+ old_ds = @datasets[position]
108
+ new_ds = old_ds.update(data, options)
109
+ new_ds.equal?(old_ds) ? self : replace_dataset(position, new_ds)
110
+ end
111
+
112
+ ##
113
+ # Updates existing Plot object by replacing dataset at *position*
114
+ # with the new one created from it by updating.
115
+ #
116
+ # @param position [Integer] position of dataset which you need to update
117
+ # (by default first dataset is updated)
118
+ # @param data [#to_gnuplot_points] data to update dataset with
119
+ # @param options [Hash] options to update dataset with, see Dataset top level doc
120
+ #
121
+ # @example
122
+ # plot.update_dataset!(data: [x1,y1], title: 'After update')
123
+ # # plot IS affected anyway
124
+ def update_dataset!(position = 0, data: nil, **options)
125
+ @datasets[position].update!(data, options)
126
+ self
127
+ end
128
+
129
+ ##
130
+ # Create new Plot object where dataset at *position* will
131
+ # be replaced with the given one.
132
+ #
133
+ # @param position [Integer] position of dataset which you need to replace
134
+ # (by default first dataset is replaced)
135
+ # @param dataset [Dataset, Array] dataset to replace the old one. You can also
136
+ # give here "[data, **dataset_options]"" array from which Dataset may be created.
137
+ # @example
138
+ # sinx = Plot.new('sin(x)')
139
+ # cosx = sinx.replace_dataset(['cos(x)'])
140
+ # # sinx IS NOT affected
141
+ def replace_dataset(position = 0, dataset)
142
+ self.class.new(@datasets.set(position, dataset_from_any(dataset)), @options)
143
+ end
144
+
145
+ ##
146
+ # Updates existing Plot object by replacing dataset at *position*
147
+ # with the given one.
148
+ #
149
+ # @param position [Integer] position of dataset which you need to replace
150
+ # (by default first dataset is replaced)
151
+ # @param dataset [Dataset, Array] dataset to replace the old one. You can also
152
+ # give here "[data, **dataset_options]"" array from which Dataset may be created.
153
+ # @example
154
+ # sinx = Plot.new('sin(x)')
155
+ # sinx.replace_dataset!(['cos(x)'])
156
+ # # sinx IS affected
157
+ def replace_dataset!(position = 0, dataset)
158
+ @datasets = @datasets.set(position, dataset_from_any(dataset))
159
+ self
160
+ end
161
+
162
+ alias_method :[]=, :replace_dataset!
163
+
164
+ ##
165
+ # Create new Plot object where given datasets will
166
+ # be inserted into dataset list before given position
167
+ # (position = 0 by default).
168
+ #
169
+ # @param position [Integer] position of dataset BEFORE which datasets will be placed.
170
+ # 0 by default.
171
+ # @param *datasets [ Sequence of Dataset or Array] datasets to insert
172
+ # @example
173
+ # sinx = Plot.new('sin(x)')
174
+ # sinx_and_cosx_with_expx = sinx.add(['cos(x)'], ['exp(x)'])
175
+ #
176
+ # cosx_and_sinx = sinx << ['cos(x)']
177
+ # # sinx IS NOT affected in both cases
178
+ def add_datasets(*datasets)
179
+ datasets.map! { |ds| ds.is_a?(Numeric) ? ds : dataset_from_any(ds) }
180
+ # first element is position where to add datasets
181
+ datasets.unshift(0) unless datasets[0].is_a?(Numeric)
182
+ self.class.new(@datasets.insert(*datasets), @options)
183
+ end
184
+
185
+ alias_method :add_dataset, :add_datasets
186
+ alias_method :<<, :add_datasets
187
+
188
+ ##
189
+ # Updates existing Plot object by inserting given datasets
190
+ # into dataset list before given position (position = 0 by default).
191
+ #
192
+ # @param position [Integer] position of dataset BEFORE which datasets will be placed.
193
+ # 0 by default.
194
+ # @param *datasets [ Sequence of Dataset or Array] datasets to insert
195
+ # @example
196
+ # sinx = Plot.new('sin(x)')
197
+ # sinx.add!(['cos(x)'], ['exp(x)'])
198
+ # # sinx IS affected
199
+ def add_datasets!(*datasets)
200
+ datasets.map! { |ds| ds.is_a?(Numeric) ? ds : dataset_from_any(ds) }
201
+ # first element is position where to add datasets
202
+ datasets.unshift(0) unless datasets[0].is_a?(Numeric)
203
+ @datasets = @datasets.insert(*datasets)
204
+ self
205
+ end
206
+
207
+ alias_method :add_dataset!, :add_datasets!
208
+
209
+ ##
210
+ # Create new Plot object where dataset at given position
211
+ # will be removed from dataset list.
212
+ #
213
+ # @param position [Integer] position of dataset that should be
214
+ # removed (by default last dataset is removed)
215
+ # @example
216
+ # sinx_and_cosx = Plot.new('sin(x)', 'cos(x)')
217
+ # sinx = sinx_and_cosx.remove_dataset
218
+ # cosx = sinx_and_cosx.remove_dataset(0)
219
+ # # sinx_and_cosx IS NOT affected in both cases
220
+ def remove_dataset(position = -1)
221
+ self.class.new(@datasets.delete_at(position), @options)
222
+ end
223
+
224
+ ##
225
+ # Updates existing Plot object by removing dataset at given position.
226
+ #
227
+ # @param position [Integer] position of dataset that should be
228
+ # removed (by default last dataset is removed)
229
+ # @example
230
+ # sinx_and_cosx = Plot.new('sin(x)', 'cos(x)')
231
+ # sinx_and_cosx!.remove_dataset
232
+ # sinx_and_cosx!.remove_dataset
233
+ # # sinx_and_cosx IS affected and now is empty
234
+ def remove_dataset!(position = -1)
235
+ @datasets = @datasets.delete_at(position)
236
+ self
237
+ end
238
+
239
+ ##
240
+ # The same as #datasets[*args]
241
+ def [](*args)
242
+ @datasets[*args]
243
+ end
244
+
245
+ private
246
+
247
+ ##
248
+ # Checks several conditions and set options needed
249
+ # to handle DateTime indexes properly.
250
+ def provide_with_datetime_format(data, using)
251
+ return unless defined?(Daru)
252
+ return unless data.is_a?(Daru::DataFrame) || data.is_a?(Daru::Vector)
253
+ return unless data.index.first.is_a?(DateTime)
254
+ return if using[0..1] != '1:'
255
+ @options = Hamster::Hash.new(
256
+ xdata: 'time',
257
+ timefmt: '%Y-%m-%dT%H:%M:%S',
258
+ format_x: '%d\n%b\n%Y'
259
+ ).merge(@options)
260
+ end
261
+
262
+ ##
263
+ # Check if given args is a dataset and returns it. Creates
264
+ # new dataset from given args otherwise.
265
+ def dataset_from_any(source)
266
+ ds = case source
267
+ # when initialized with dataframe (it passes here several vectors)
268
+ when (defined?(Daru) ? Daru::Vector : nil)
269
+ Dataset.new(source)
270
+ when Dataset
271
+ source.clone
272
+ else
273
+ Dataset.new(*source)
274
+ end
275
+ data = source.is_a?(Array) ? source[0] : source
276
+ provide_with_datetime_format(data, ds.using)
277
+ ds
278
+ end
279
+
280
+ ##
281
+ # Parses given array and returns Hamster::Vector of Datasets
282
+ def parse_datasets_array(datasets)
283
+ case datasets[0]
284
+ when Hamster::Vector
285
+ datasets[0]
286
+ when (defined?(Daru) ? Daru::DataFrame : nil)
287
+ Hamster::Vector.new(datasets[0].map { |ds| dataset_from_any(ds) })
288
+ else
289
+ Hamster::Vector.new(datasets.map { |ds| dataset_from_any(ds) })
290
+ end
291
+ end
292
+
293
+ ##
294
+ # Creates new Plot with existing data and given options.
295
+ def new_with_options(options)
296
+ self.class.new(@datasets, options)
297
+ end
298
+ end
299
+ end