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
@@ -1,6 +1,6 @@
|
|
1
|
-
##
|
2
|
-
# Methods to take data for GnuplotRB plots.
|
3
|
-
class String
|
4
|
-
# @return [String] data converted to Gnuplot format
|
5
|
-
alias_method :to_gnuplot_points, :clone
|
6
|
-
end
|
1
|
+
##
|
2
|
+
# Methods to take data for GnuplotRB plots.
|
3
|
+
class String
|
4
|
+
# @return [String] data converted to Gnuplot format
|
5
|
+
alias_method :to_gnuplot_points, :clone
|
6
|
+
end
|
data/lib/gnuplotrb/fit.rb
CHANGED
@@ -1,204 +1,204 @@
|
|
1
|
-
module GnuplotRB
|
2
|
-
##
|
3
|
-
# Contains methods relating to Gnuplot's fit function. Covered in
|
4
|
-
# {fit notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/fitting_data.ipynb].
|
5
|
-
#
|
6
|
-
# You can also see original gnuplot's fit in
|
7
|
-
# {gnuplot doc}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] p. 122.
|
8
|
-
module Fit
|
9
|
-
##
|
10
|
-
# Fit given data with function.
|
11
|
-
#
|
12
|
-
# Fit waits for output from gnuplot Settings.max_fit_delay and throw exception if gets nothing.
|
13
|
-
# One can change this value in order to wait longer (if huge datasets is fitted).
|
14
|
-
#
|
15
|
-
# @param data [#to_gnuplot_points] method accepts the same sources as Dataset.new
|
16
|
-
# and Dataset object
|
17
|
-
# @param :function [String] function to fit data with
|
18
|
-
# @param :initials [Hash] initial values for coefficients used in fitting
|
19
|
-
# @param :term_options [Hash] terminal options that should be setted to terminal before fit.
|
20
|
-
# You can see them in Plot's documentation (or even better in gnuplot doc)
|
21
|
-
# Most useful here are ranges (xrange, yrange etc) and fit option which tunes fit parameters
|
22
|
-
# (see {gnuplot doc}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] p. 122)
|
23
|
-
# @param options [Hash] options passed to Gnuplot's fit such as *using*. They are covered in
|
24
|
-
# {gnuplot doc}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] (pp. 69-74)
|
25
|
-
#
|
26
|
-
# @return [Hash] hash with four elements:
|
27
|
-
# - :formula_ds - dataset with best fit curve as data
|
28
|
-
# - :coefficients - hash of calculated coefficients. So if you gave
|
29
|
-
# ``{ initials: {a: 1, b: 1, c: 1} }`` it will return hash with keys :a, :b, :c and its values
|
30
|
-
# - :deltas - Gnuplot calculates possible deltas for coefficients during fitting and
|
31
|
-
# deltas hash contains this deltas
|
32
|
-
# - :data - pointer to Datablock with given data
|
33
|
-
# @example
|
34
|
-
# fit(some_data, function: 'exp(a/x)', initials: {a: 10}, term_option: { xrange: 1..100 })
|
35
|
-
# fit(some_dataset, using: '1:2:3')
|
36
|
-
def fit(data, function: 'a2*x*x+a1*x+a0', initials: { a2: 1, a1: 1, a0: 1 }, term_options: {}, **options)
|
37
|
-
dataset = data.is_a?(Dataset) ? Dataset.new(data.data) : Dataset.new(data)
|
38
|
-
opts_str = OptionHandling.ruby_class_to_gnuplot(options)
|
39
|
-
output = gnuplot_fit(function, dataset, opts_str, initials, term_options)
|
40
|
-
res = parse_output(initials.keys, function, output)
|
41
|
-
{
|
42
|
-
formula_ds: Dataset.new(res[2], title: 'Fit formula'),
|
43
|
-
coefficients: res[0],
|
44
|
-
deltas: res[1],
|
45
|
-
data: dataset
|
46
|
-
}
|
47
|
-
end
|
48
|
-
|
49
|
-
##
|
50
|
-
# Shortcut for fit with polynomial. Degree here is max power of *x* in polynomial.
|
51
|
-
#
|
52
|
-
# @param data [#to_gnuplot_points] method accepts the same sources as Dataset.new
|
53
|
-
# and Dataset object
|
54
|
-
# @param :degree [Integer] degree of polynomial
|
55
|
-
# @param options [Hash] all of this options will be passed to #fit so you
|
56
|
-
# can set here any options listed in its docs. If you pass here :initials hash, it
|
57
|
-
# will be merged into default initals hash. Formula by default is
|
58
|
-
# "xn*x**n + ... + x0*x**0", initials by default "{ an: 1, ..., a0: 1 }"
|
59
|
-
#
|
60
|
-
# @return [Hash] hash with four elements:
|
61
|
-
# - :formula_ds - dataset with best fit curve as data
|
62
|
-
# - :coefficients - hash of calculated coefficients. So for degree = 3
|
63
|
-
# it will return hash with keys :a3, :a2, :a1, :a0 and calculated values
|
64
|
-
# - :deltas - Gnuplot calculates possible deltas for coefficients during fitting and
|
65
|
-
# deltas hash contains this deltas
|
66
|
-
# - :data - pointer to Datablock with given data
|
67
|
-
# @example
|
68
|
-
# fit_poly(some_data, degree: 5, initials: { a4: 10, a2: -1 }, term_option: { xrange: 1..100 })
|
69
|
-
# #=> The same as:
|
70
|
-
# #=> fit(
|
71
|
-
# #=> some_data,
|
72
|
-
# #=> function: 'a5*x**5 + a4*x**4 + ... + a0*x**0',
|
73
|
-
# #=> initals: {a5: 1, a4: 10, a3: 1, a2: -1, a1: 1, a0: 1},
|
74
|
-
# #=> term_option: { xrange: 1..100 }
|
75
|
-
# #=> )
|
76
|
-
def fit_poly(data, degree: 2, **options)
|
77
|
-
sum_count = degree + 1
|
78
|
-
initials = {}
|
79
|
-
sum_count.times { |i| initials["a#{i}".to_sym] = 1 }
|
80
|
-
options[:initials] = initials.merge(options[:initials] || {})
|
81
|
-
function = sum_count.times.map { |i| "a#{i}*x**#{i}" }.join(' + ')
|
82
|
-
fit(data, **options, function: function)
|
83
|
-
end
|
84
|
-
|
85
|
-
##
|
86
|
-
# @!method fit_exp(data, **options)
|
87
|
-
# @!method fit_log(data, **options)
|
88
|
-
# @!method fit_sin(data, **options)
|
89
|
-
#
|
90
|
-
# Shortcuts for fitting with several math functions (exp, log, sin).
|
91
|
-
#
|
92
|
-
# @param data [#to_gnuplot_points] method accepts the same sources as Dataset.new
|
93
|
-
# and Dataset object
|
94
|
-
# @param options [Hash] all of this options will be passed to #fit so you
|
95
|
-
# can set here any options listed in its docs. If you pass here :initials hash, it
|
96
|
-
# will be merged into default initals hash. Formula by default is
|
97
|
-
# "yscale * (yoffset + #{function name}((x - xoffset) / xscale))", initials by default
|
98
|
-
# "{ yoffset: 0.1, xoffset: 0.1, yscale: 1, xscale: 1 }"
|
99
|
-
#
|
100
|
-
# @return [Hash] hash with four elements:
|
101
|
-
# - :formula_ds - dataset with best fit curve as data
|
102
|
-
# - :coefficients - hash of calculated coefficients. So for this case
|
103
|
-
# it will return hash with keys :yoffset, :xoffset, :yscale, :xscale and calculated values
|
104
|
-
# - :deltas - Gnuplot calculates possible deltas for coefficients during fitting and
|
105
|
-
# deltas hash contains this deltas
|
106
|
-
# - :data - pointer to Datablock with given data
|
107
|
-
#
|
108
|
-
# @example
|
109
|
-
# fit_exp(some_data, initials: { yoffset: -11 }, term_option: { xrange: 1..100 })
|
110
|
-
# #=> The same as:
|
111
|
-
# #=> fit(
|
112
|
-
# #=> some_data,
|
113
|
-
# #=> function: 'yscale * (yoffset + exp((x - xoffset) / xscale))',
|
114
|
-
# #=> initals: { yoffset: -11, xoffset: 0.1, yscale: 1, xscale: 1 },
|
115
|
-
# #=> term_option: { xrange: 1..100 }
|
116
|
-
# #=> )
|
117
|
-
# fit_log(...)
|
118
|
-
# fit_sin(...)
|
119
|
-
%w(exp log sin).map do |fname|
|
120
|
-
define_method("fit_#{fname}".to_sym) do |data, **options|
|
121
|
-
options[:initials] = {
|
122
|
-
yoffset: 0.1,
|
123
|
-
xoffset: 0.1,
|
124
|
-
yscale: 1,
|
125
|
-
xscale: 1
|
126
|
-
}.merge(options[:initials] || {})
|
127
|
-
function = "yscale * (yoffset + #{fname} ((x - xoffset) / xscale))"
|
128
|
-
fit(data, **options, function: function)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
private
|
133
|
-
|
134
|
-
##
|
135
|
-
# It takes some time to produce output so here we need
|
136
|
-
# to wait for it.
|
137
|
-
#
|
138
|
-
# Max time to wait is stored in Settings.max_fit_delay, so one
|
139
|
-
# can change it in order to wait longer.
|
140
|
-
def wait_for_output(term, variables)
|
141
|
-
# now we should catch 'error' from terminal: it will contain approximation data
|
142
|
-
# but we can get a real error instead of output, so lets wait for limited time
|
143
|
-
start = Time.now
|
144
|
-
output = ''
|
145
|
-
until output_ready?(output, variables)
|
146
|
-
begin
|
147
|
-
term.check_errors(raw: true)
|
148
|
-
rescue GnuplotRB::GnuplotError => e
|
149
|
-
output += e.message
|
150
|
-
end
|
151
|
-
if Time.now - start > Settings.max_fit_delay
|
152
|
-
fail GnuplotError, "Seems like there is an error in gnuplotrb: #{output}"
|
153
|
-
end
|
154
|
-
end
|
155
|
-
output
|
156
|
-
end
|
157
|
-
|
158
|
-
##
|
159
|
-
# Check if current output contains all the
|
160
|
-
# variables given to fit.
|
161
|
-
def output_ready?(output, variables)
|
162
|
-
output =~ /Final set .*#{variables.join('.*')}/
|
163
|
-
end
|
164
|
-
|
165
|
-
##
|
166
|
-
# Parse Gnuplot's output to get coefficients and their deltas
|
167
|
-
# from it. Also replaces coefficients in given function with
|
168
|
-
# exact values.
|
169
|
-
def parse_output(variables, function, output)
|
170
|
-
plottable_function = " #{function.clone} "
|
171
|
-
coefficients = {}
|
172
|
-
deltas = {}
|
173
|
-
variables.each do |var|
|
174
|
-
value, error = output.scan(%r{#{var} *= ([^ ]+) *\+/\- ([^ ]+)})[0]
|
175
|
-
plottable_function.gsub!(/#{var}([^0-9a-zA-Z])/) { value + Regexp.last_match(1) }
|
176
|
-
coefficients[var] = value.to_f
|
177
|
-
deltas[var] = error.to_f
|
178
|
-
end
|
179
|
-
[coefficients, deltas, plottable_function]
|
180
|
-
end
|
181
|
-
|
182
|
-
##
|
183
|
-
# Make fit command and send it to gnuplot
|
184
|
-
def gnuplot_fit(function, data, options, initials, term_options)
|
185
|
-
variables = initials.keys
|
186
|
-
term = Terminal.new
|
187
|
-
term.set(term_options)
|
188
|
-
initials.each { |var_name, value| term.stream_puts "#{var_name} = #{value}" }
|
189
|
-
command = "fit #{function} #{data.to_s(term, without_options: true)} " \
|
190
|
-
"#{options} via #{variables.join(',')}"
|
191
|
-
term.stream_puts(command)
|
192
|
-
output = wait_for_output(term, variables)
|
193
|
-
begin
|
194
|
-
term.close
|
195
|
-
rescue GnuplotError
|
196
|
-
# Nothing interesting here.
|
197
|
-
# If we had an error, we never reach this line.
|
198
|
-
# Error here may be only additional information
|
199
|
-
# such as correlation matrix.
|
200
|
-
end
|
201
|
-
output
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
1
|
+
module GnuplotRB
|
2
|
+
##
|
3
|
+
# Contains methods relating to Gnuplot's fit function. Covered in
|
4
|
+
# {fit notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/fitting_data.ipynb].
|
5
|
+
#
|
6
|
+
# You can also see original gnuplot's fit in
|
7
|
+
# {gnuplot doc}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] p. 122.
|
8
|
+
module Fit
|
9
|
+
##
|
10
|
+
# Fit given data with function.
|
11
|
+
#
|
12
|
+
# Fit waits for output from gnuplot Settings.max_fit_delay and throw exception if gets nothing.
|
13
|
+
# One can change this value in order to wait longer (if huge datasets is fitted).
|
14
|
+
#
|
15
|
+
# @param data [#to_gnuplot_points] method accepts the same sources as Dataset.new
|
16
|
+
# and Dataset object
|
17
|
+
# @param :function [String] function to fit data with
|
18
|
+
# @param :initials [Hash] initial values for coefficients used in fitting
|
19
|
+
# @param :term_options [Hash] terminal options that should be setted to terminal before fit.
|
20
|
+
# You can see them in Plot's documentation (or even better in gnuplot doc)
|
21
|
+
# Most useful here are ranges (xrange, yrange etc) and fit option which tunes fit parameters
|
22
|
+
# (see {gnuplot doc}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] p. 122)
|
23
|
+
# @param options [Hash] options passed to Gnuplot's fit such as *using*. They are covered in
|
24
|
+
# {gnuplot doc}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] (pp. 69-74)
|
25
|
+
#
|
26
|
+
# @return [Hash] hash with four elements:
|
27
|
+
# - :formula_ds - dataset with best fit curve as data
|
28
|
+
# - :coefficients - hash of calculated coefficients. So if you gave
|
29
|
+
# ``{ initials: {a: 1, b: 1, c: 1} }`` it will return hash with keys :a, :b, :c and its values
|
30
|
+
# - :deltas - Gnuplot calculates possible deltas for coefficients during fitting and
|
31
|
+
# deltas hash contains this deltas
|
32
|
+
# - :data - pointer to Datablock with given data
|
33
|
+
# @example
|
34
|
+
# fit(some_data, function: 'exp(a/x)', initials: {a: 10}, term_option: { xrange: 1..100 })
|
35
|
+
# fit(some_dataset, using: '1:2:3')
|
36
|
+
def fit(data, function: 'a2*x*x+a1*x+a0', initials: { a2: 1, a1: 1, a0: 1 }, term_options: {}, **options)
|
37
|
+
dataset = data.is_a?(Dataset) ? Dataset.new(data.data) : Dataset.new(data)
|
38
|
+
opts_str = OptionHandling.ruby_class_to_gnuplot(options)
|
39
|
+
output = gnuplot_fit(function, dataset, opts_str, initials, term_options)
|
40
|
+
res = parse_output(initials.keys, function, output)
|
41
|
+
{
|
42
|
+
formula_ds: Dataset.new(res[2], title: 'Fit formula'),
|
43
|
+
coefficients: res[0],
|
44
|
+
deltas: res[1],
|
45
|
+
data: dataset
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Shortcut for fit with polynomial. Degree here is max power of *x* in polynomial.
|
51
|
+
#
|
52
|
+
# @param data [#to_gnuplot_points] method accepts the same sources as Dataset.new
|
53
|
+
# and Dataset object
|
54
|
+
# @param :degree [Integer] degree of polynomial
|
55
|
+
# @param options [Hash] all of this options will be passed to #fit so you
|
56
|
+
# can set here any options listed in its docs. If you pass here :initials hash, it
|
57
|
+
# will be merged into default initals hash. Formula by default is
|
58
|
+
# "xn*x**n + ... + x0*x**0", initials by default "{ an: 1, ..., a0: 1 }"
|
59
|
+
#
|
60
|
+
# @return [Hash] hash with four elements:
|
61
|
+
# - :formula_ds - dataset with best fit curve as data
|
62
|
+
# - :coefficients - hash of calculated coefficients. So for degree = 3
|
63
|
+
# it will return hash with keys :a3, :a2, :a1, :a0 and calculated values
|
64
|
+
# - :deltas - Gnuplot calculates possible deltas for coefficients during fitting and
|
65
|
+
# deltas hash contains this deltas
|
66
|
+
# - :data - pointer to Datablock with given data
|
67
|
+
# @example
|
68
|
+
# fit_poly(some_data, degree: 5, initials: { a4: 10, a2: -1 }, term_option: { xrange: 1..100 })
|
69
|
+
# #=> The same as:
|
70
|
+
# #=> fit(
|
71
|
+
# #=> some_data,
|
72
|
+
# #=> function: 'a5*x**5 + a4*x**4 + ... + a0*x**0',
|
73
|
+
# #=> initals: {a5: 1, a4: 10, a3: 1, a2: -1, a1: 1, a0: 1},
|
74
|
+
# #=> term_option: { xrange: 1..100 }
|
75
|
+
# #=> )
|
76
|
+
def fit_poly(data, degree: 2, **options)
|
77
|
+
sum_count = degree + 1
|
78
|
+
initials = {}
|
79
|
+
sum_count.times { |i| initials["a#{i}".to_sym] = 1 }
|
80
|
+
options[:initials] = initials.merge(options[:initials] || {})
|
81
|
+
function = sum_count.times.map { |i| "a#{i}*x**#{i}" }.join(' + ')
|
82
|
+
fit(data, **options, function: function)
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# @!method fit_exp(data, **options)
|
87
|
+
# @!method fit_log(data, **options)
|
88
|
+
# @!method fit_sin(data, **options)
|
89
|
+
#
|
90
|
+
# Shortcuts for fitting with several math functions (exp, log, sin).
|
91
|
+
#
|
92
|
+
# @param data [#to_gnuplot_points] method accepts the same sources as Dataset.new
|
93
|
+
# and Dataset object
|
94
|
+
# @param options [Hash] all of this options will be passed to #fit so you
|
95
|
+
# can set here any options listed in its docs. If you pass here :initials hash, it
|
96
|
+
# will be merged into default initals hash. Formula by default is
|
97
|
+
# "yscale * (yoffset + #{function name}((x - xoffset) / xscale))", initials by default
|
98
|
+
# "{ yoffset: 0.1, xoffset: 0.1, yscale: 1, xscale: 1 }"
|
99
|
+
#
|
100
|
+
# @return [Hash] hash with four elements:
|
101
|
+
# - :formula_ds - dataset with best fit curve as data
|
102
|
+
# - :coefficients - hash of calculated coefficients. So for this case
|
103
|
+
# it will return hash with keys :yoffset, :xoffset, :yscale, :xscale and calculated values
|
104
|
+
# - :deltas - Gnuplot calculates possible deltas for coefficients during fitting and
|
105
|
+
# deltas hash contains this deltas
|
106
|
+
# - :data - pointer to Datablock with given data
|
107
|
+
#
|
108
|
+
# @example
|
109
|
+
# fit_exp(some_data, initials: { yoffset: -11 }, term_option: { xrange: 1..100 })
|
110
|
+
# #=> The same as:
|
111
|
+
# #=> fit(
|
112
|
+
# #=> some_data,
|
113
|
+
# #=> function: 'yscale * (yoffset + exp((x - xoffset) / xscale))',
|
114
|
+
# #=> initals: { yoffset: -11, xoffset: 0.1, yscale: 1, xscale: 1 },
|
115
|
+
# #=> term_option: { xrange: 1..100 }
|
116
|
+
# #=> )
|
117
|
+
# fit_log(...)
|
118
|
+
# fit_sin(...)
|
119
|
+
%w(exp log sin).map do |fname|
|
120
|
+
define_method("fit_#{fname}".to_sym) do |data, **options|
|
121
|
+
options[:initials] = {
|
122
|
+
yoffset: 0.1,
|
123
|
+
xoffset: 0.1,
|
124
|
+
yscale: 1,
|
125
|
+
xscale: 1
|
126
|
+
}.merge(options[:initials] || {})
|
127
|
+
function = "yscale * (yoffset + #{fname} ((x - xoffset) / xscale))"
|
128
|
+
fit(data, **options, function: function)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
##
|
135
|
+
# It takes some time to produce output so here we need
|
136
|
+
# to wait for it.
|
137
|
+
#
|
138
|
+
# Max time to wait is stored in Settings.max_fit_delay, so one
|
139
|
+
# can change it in order to wait longer.
|
140
|
+
def wait_for_output(term, variables)
|
141
|
+
# now we should catch 'error' from terminal: it will contain approximation data
|
142
|
+
# but we can get a real error instead of output, so lets wait for limited time
|
143
|
+
start = Time.now
|
144
|
+
output = ''
|
145
|
+
until output_ready?(output, variables)
|
146
|
+
begin
|
147
|
+
term.check_errors(raw: true)
|
148
|
+
rescue GnuplotRB::GnuplotError => e
|
149
|
+
output += e.message
|
150
|
+
end
|
151
|
+
if Time.now - start > Settings.max_fit_delay
|
152
|
+
fail GnuplotError, "Seems like there is an error in gnuplotrb: #{output}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
output
|
156
|
+
end
|
157
|
+
|
158
|
+
##
|
159
|
+
# Check if current output contains all the
|
160
|
+
# variables given to fit.
|
161
|
+
def output_ready?(output, variables)
|
162
|
+
output =~ /Final set .*#{variables.join('.*')}/
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Parse Gnuplot's output to get coefficients and their deltas
|
167
|
+
# from it. Also replaces coefficients in given function with
|
168
|
+
# exact values.
|
169
|
+
def parse_output(variables, function, output)
|
170
|
+
plottable_function = " #{function.clone} "
|
171
|
+
coefficients = {}
|
172
|
+
deltas = {}
|
173
|
+
variables.each do |var|
|
174
|
+
value, error = output.scan(%r{#{var} *= ([^ ]+) *\+/\- ([^ ]+)})[0]
|
175
|
+
plottable_function.gsub!(/#{var}([^0-9a-zA-Z])/) { value + Regexp.last_match(1) }
|
176
|
+
coefficients[var] = value.to_f
|
177
|
+
deltas[var] = error.to_f
|
178
|
+
end
|
179
|
+
[coefficients, deltas, plottable_function]
|
180
|
+
end
|
181
|
+
|
182
|
+
##
|
183
|
+
# Make fit command and send it to gnuplot
|
184
|
+
def gnuplot_fit(function, data, options, initials, term_options)
|
185
|
+
variables = initials.keys
|
186
|
+
term = Terminal.new
|
187
|
+
term.set(term_options)
|
188
|
+
initials.each { |var_name, value| term.stream_puts "#{var_name} = #{value}" }
|
189
|
+
command = "fit #{function} #{data.to_s(term, without_options: true)} " \
|
190
|
+
"#{options} via #{variables.join(',')}"
|
191
|
+
term.stream_puts(command)
|
192
|
+
output = wait_for_output(term, variables)
|
193
|
+
begin
|
194
|
+
term.close
|
195
|
+
rescue GnuplotError
|
196
|
+
# Nothing interesting here.
|
197
|
+
# If we had an error, we never reach this line.
|
198
|
+
# Error here may be only additional information
|
199
|
+
# such as correlation matrix.
|
200
|
+
end
|
201
|
+
output
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
@@ -1,48 +1,48 @@
|
|
1
|
-
module GnuplotRB
|
2
|
-
##
|
3
|
-
# Just a new error name
|
4
|
-
class GnuplotError < ArgumentError
|
5
|
-
end
|
6
|
-
|
7
|
-
##
|
8
|
-
# Mixin for classes that need to run subprocess and
|
9
|
-
# handle errors from its stderr.
|
10
|
-
module ErrorHandling
|
11
|
-
##
|
12
|
-
# Check if there were errors in previous commands.
|
13
|
-
# Throws GnuplotError in case of any errors.
|
14
|
-
def check_errors(raw: false)
|
15
|
-
return if @err_array.empty?
|
16
|
-
command = ''
|
17
|
-
rest = ''
|
18
|
-
@semaphore.synchronize do
|
19
|
-
command = @err_array.first
|
20
|
-
rest = @err_array[1..-1].join('; ')
|
21
|
-
@err_array.clear
|
22
|
-
end
|
23
|
-
message = if raw
|
24
|
-
"#{command};#{rest}}"
|
25
|
-
else
|
26
|
-
"Error in previous command (\"#{command}\"): \"#{rest}\""
|
27
|
-
end
|
28
|
-
fail GnuplotError, message
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
##
|
34
|
-
# Start new thread that will read stderr given as stream
|
35
|
-
# and add errors into @err_array.
|
36
|
-
def handle_stderr(stream)
|
37
|
-
@err_array = []
|
38
|
-
# synchronize access to @err_array
|
39
|
-
@semaphore = Mutex.new
|
40
|
-
Thread.new do
|
41
|
-
until (line = stream.gets).nil?
|
42
|
-
line.strip!
|
43
|
-
@semaphore.synchronize { @err_array << line if line.size > 3 }
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
1
|
+
module GnuplotRB
|
2
|
+
##
|
3
|
+
# Just a new error name
|
4
|
+
class GnuplotError < ArgumentError
|
5
|
+
end
|
6
|
+
|
7
|
+
##
|
8
|
+
# Mixin for classes that need to run subprocess and
|
9
|
+
# handle errors from its stderr.
|
10
|
+
module ErrorHandling
|
11
|
+
##
|
12
|
+
# Check if there were errors in previous commands.
|
13
|
+
# Throws GnuplotError in case of any errors.
|
14
|
+
def check_errors(raw: false)
|
15
|
+
return if @err_array.empty?
|
16
|
+
command = ''
|
17
|
+
rest = ''
|
18
|
+
@semaphore.synchronize do
|
19
|
+
command = @err_array.first
|
20
|
+
rest = @err_array[1..-1].join('; ')
|
21
|
+
@err_array.clear
|
22
|
+
end
|
23
|
+
message = if raw
|
24
|
+
"#{command};#{rest}}"
|
25
|
+
else
|
26
|
+
"Error in previous command (\"#{command}\"): \"#{rest}\""
|
27
|
+
end
|
28
|
+
fail GnuplotError, message
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
##
|
34
|
+
# Start new thread that will read stderr given as stream
|
35
|
+
# and add errors into @err_array.
|
36
|
+
def handle_stderr(stream)
|
37
|
+
@err_array = []
|
38
|
+
# synchronize access to @err_array
|
39
|
+
@semaphore = Mutex.new
|
40
|
+
Thread.new do
|
41
|
+
until (line = stream.gets).nil?
|
42
|
+
line.strip!
|
43
|
+
@semaphore.synchronize { @err_array << line if line.size > 3 }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|