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.
- checksums.yaml +4 -4
- data/Gemfile +4 -4
- data/LICENSE +20 -20
- data/README.rdoc +163 -163
- data/Rakefile +16 -16
- data/gnuplotrb.gemspec +30 -30
- data/lib/gnuplotrb.rb +35 -35
- data/lib/gnuplotrb/animation.rb +129 -129
- data/lib/gnuplotrb/external_classes/array.rb +17 -17
- data/lib/gnuplotrb/external_classes/daru.rb +43 -43
- data/lib/gnuplotrb/external_classes/string.rb +6 -6
- data/lib/gnuplotrb/fit.rb +204 -204
- data/lib/gnuplotrb/mixins/error_handling.rb +48 -48
- data/lib/gnuplotrb/mixins/option_handling.rb +190 -190
- data/lib/gnuplotrb/mixins/plottable.rb +208 -208
- data/lib/gnuplotrb/multiplot.rb +269 -269
- data/lib/gnuplotrb/plot.rb +299 -299
- data/lib/gnuplotrb/splot.rb +18 -18
- data/lib/gnuplotrb/staff/datablock.rb +112 -112
- data/lib/gnuplotrb/staff/dataset.rb +294 -294
- data/lib/gnuplotrb/staff/settings.rb +89 -80
- data/lib/gnuplotrb/staff/terminal.rb +202 -202
- data/lib/gnuplotrb/version.rb +8 -8
- metadata +3 -4
data/lib/gnuplotrb/plot.rb
CHANGED
@@ -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
|