gnuplotrb 0.2.0 → 0.3.0
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/README.rdoc +79 -13
- data/Rakefile +2 -2
- data/lib/gnuplotrb/animation.rb +102 -0
- data/lib/gnuplotrb/external_classes/array.rb +2 -0
- data/lib/gnuplotrb/external_classes/daru.rb +15 -5
- data/lib/gnuplotrb/external_classes/string.rb +2 -0
- data/lib/gnuplotrb/fit.rb +176 -0
- data/lib/gnuplotrb/mixins/error_handling.rb +12 -8
- data/lib/gnuplotrb/mixins/option_handling.rb +20 -13
- data/lib/gnuplotrb/mixins/plottable.rb +56 -33
- data/lib/gnuplotrb/multiplot.rb +77 -37
- data/lib/gnuplotrb/plot.rb +81 -37
- data/lib/gnuplotrb/staff/dataset.rb +85 -94
- data/lib/gnuplotrb/staff/settings.rb +61 -49
- data/lib/gnuplotrb/staff/terminal.rb +14 -17
- data/lib/gnuplotrb/version.rb +1 -1
- data/lib/gnuplotrb.rb +6 -6
- metadata +4 -3
- data/lib/gnuplotrb/external_classes/iruby.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 636e6f8b249ca52a3dc09d4034cb7596ba650e42
|
4
|
+
data.tar.gz: d8eea39c386a7cc6513b2992b126fc15412318f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d331f099e12185d350a4b1fe6908a658cfdcc977c3d4657bd621efe510fb854fe1a86fdd780b8f32e1ea69146934e513e8b1de16ead04e8a43c11da093d23eb
|
7
|
+
data.tar.gz: 26c483e4a645ac3b2ef9a680ba8a30cc3975fd68f0ad329e3cf22fae53a26cec5fd8b8743bd57850025c351bae77988dccf40d436c3f49b7a4c8c4344b222e4d
|
data/README.rdoc
CHANGED
@@ -1,34 +1,100 @@
|
|
1
1
|
= GnuplotRB
|
2
2
|
|
3
|
-
|
3
|
+
GnuplotRB is a plot generator for Ruby based on {Gnuplot}[http://www.gnuplot.info].
|
4
|
+
|
5
|
+
This software has been developed as a product in Google Summer of Code 2015 (GSoC2015). Its progress may be saw in {SciRuby mailing list}[https://groups.google.com/forum/?fromgroups#!topic/sciruby-dev/lhWvb5hWc3k] or in {project's blog}[http://dilcom.github.io/gnuplotrb/].
|
6
|
+
|
7
|
+
{<img src="https://badge.fury.io/rb/gnuplotrb.svg" alt="Gem Version" />}[https://rubygems.org/gems/gnuplotrb]
|
4
8
|
|
5
9
|
{<img src="https://travis-ci.org/dilcom/gnuplotrb.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/dilcom/gnuplotrb]
|
6
10
|
{<img src="https://codeclimate.com/github/dilcom/gnuplotrb/badges/gpa.svg" alt="Code quality" />}[https://codeclimate.com/github/dilcom/gnuplotrb]
|
7
11
|
{<img src="https://codeclimate.com/github/dilcom/gnuplotrb/badges/coverage.svg" alt="Test coverage" />}[https://codeclimate.com/github/dilcom/gnuplotrb]
|
8
12
|
|
13
|
+
== Table of contents
|
14
|
+
* {Installation}[https://github.com/dilcom/gnuplotrb#installation]
|
15
|
+
* {Examples}[https://github.com/dilcom/gnuplotrb#examples]
|
16
|
+
* {Notebooks}[https://github.com/dilcom/gnuplotrb#notebooks]
|
17
|
+
* {Plain examples}[https://github.com/dilcom/gnuplotrb#plain-examples]
|
18
|
+
* {Contributing}[https://github.com/dilcom/gnuplotrb#contributing]
|
9
19
|
|
10
20
|
== Installation
|
11
|
-
While gem isn't on rubygems, it may be installed from source.
|
12
21
|
=== Dependencies
|
13
22
|
* Ruby 2.0+
|
14
23
|
* It is required to install {gnuplot 5.0}[http://www.gnuplot.info/download.html] to use that gem.
|
15
24
|
=== Gem installation
|
16
|
-
==== Install latest version from
|
17
|
-
git clone https://github.com/dilcom/gnuplotrb.git
|
18
|
-
cd gnuplotrb
|
19
|
-
bundle install
|
20
|
-
rake install
|
21
|
-
==== Install latest stable vrsion
|
25
|
+
==== Install latest stable version from Rubygems
|
22
26
|
gem install gnuplotrb
|
23
|
-
==== Install latest stable
|
27
|
+
==== Install latest stable version using bundler
|
24
28
|
* add
|
25
29
|
gem 'gnuplotrb'
|
26
30
|
to your Gemfile
|
27
31
|
* run
|
28
32
|
bundle install
|
33
|
+
==== Install latest version from source (may be unstable)
|
34
|
+
git clone https://github.com/dilcom/gnuplotrb.git
|
35
|
+
cd gnuplotrb
|
36
|
+
bundle install
|
37
|
+
rake install
|
38
|
+
|
39
|
+
== Examples
|
40
|
+
=== Notebooks
|
41
|
+
|
42
|
+
This notebooks are powered by {Ruby kernel}[https://github.com/SciRuby/iruby/] for {IPython/Jupyter}[https://jupyter.org/].
|
43
|
+
I placed them here to show some GnuplotRB's capabilities and ways of using it together with iRuby.
|
44
|
+
|
45
|
+
To use GnuplotRB gem with iRuby you need to install them both.
|
46
|
+
|
47
|
+
* iRuby installation is covered in its {README}[https://github.com/SciRuby/iruby/blob/master/README.md].
|
48
|
+
It also covers installation of iPython and other dependecies.
|
49
|
+
* GnuplotRB gem installation covered in {README}[https://github.com/dilcom/gnuplotrb#installation] too.
|
50
|
+
|
51
|
+
==== Embedding plots into iRuby
|
52
|
+
Using GnuplotRB inside iRuby notebooks is covered in:
|
53
|
+
|
54
|
+
* {Basic usage notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/basic_usage.ipynb].
|
55
|
+
|
56
|
+
==== 2D and 3D plots
|
57
|
+
GnuplotRB is capable to plot vast range of plots from histograms to 3D heatmaps. Gem's repository contains examples of several plot types:
|
58
|
+
|
59
|
+
* {Heatmaps}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/heatmaps.ipynb]
|
60
|
+
* {Vector field}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/vector_field.ipynb] (Thanks, {Alexej}[https://github.com/agisga])
|
61
|
+
* {Math equations}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/math_plots.ipynb]
|
62
|
+
* {3D visualizations}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/3d_plot.ipynb]
|
63
|
+
* {Histogram}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/histogram.ipynb]
|
64
|
+
|
65
|
+
==== Possible datasources
|
66
|
+
GnuplotRB may take data in Ruby container or in a file. Supported containers for now are Arrays, Daru::Vector and Daru::DataFrame.
|
67
|
+
When data given in file, GnuplotRB pass filename to Gnuplot *without* reading the file into memory.
|
68
|
+
|
69
|
+
Examples of using different datasources:
|
70
|
+
|
71
|
+
* {Data given in file or Ruby Array}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/points_from_different_sources.ipynb]
|
72
|
+
* {Data given in Daru containers}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/plotting_from_daru.ipynb]
|
73
|
+
* {Data given in Daru containers (with timeseries)}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/time_series_from_daru.ipynb]
|
74
|
+
* {Updating plots with new data}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/updating_data.ipynb]
|
75
|
+
|
76
|
+
==== Multiplot
|
77
|
+
You can not only plot several datasets in single coordinate system but place several coordinate systems on a canvas.
|
78
|
+
|
79
|
+
* {Multiplot example notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/multiplot_layout.ipynb].
|
80
|
+
|
81
|
+
==== Animation
|
82
|
+
It's possible to use several plots (Plot, Splot or Multiplot objects) to create gif animation.
|
83
|
+
|
84
|
+
* {Animation example notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/animated_plots.ipynb].
|
85
|
+
|
86
|
+
==== Fitting data with formula
|
87
|
+
GnuplotRB also may be used to fit some data with given math formula.
|
88
|
+
|
89
|
+
* {Fitting data}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/fitting_data.ipynb]
|
90
|
+
|
91
|
+
=== Plain examples
|
92
|
+
You may find several examples in {examples directory}[https://github.com/dilcom/gnuplotrb/tree/master/examples].
|
29
93
|
|
30
|
-
==
|
31
|
-
You may find several examples in {examples directory}[https://github.com/dilcom/gnuplotrb/tree/master/examples]
|
94
|
+
== Contributing
|
32
95
|
|
33
|
-
|
34
|
-
|
96
|
+
1. {Fork repository}[https://github.com/dilcom/gnuplotrb/fork]
|
97
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
98
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
99
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
100
|
+
5. Create a new Pull Request
|
data/Rakefile
CHANGED
@@ -9,9 +9,9 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
9
9
|
spec.rspec_opts = '--format documentation'
|
10
10
|
end
|
11
11
|
|
12
|
-
RDoc::Task.new do |rdoc|
|
12
|
+
RDoc::Task.new(:doc) do |rdoc|
|
13
13
|
rdoc.main = 'README.rdoc'
|
14
14
|
rdoc.rdoc_files.include %w(README.rdoc lib)
|
15
15
|
end
|
16
16
|
|
17
|
-
RuboCop::RakeTask.new
|
17
|
+
RuboCop::RakeTask.new(:cop)
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module GnuplotRB
|
2
|
+
##
|
3
|
+
# === Overview
|
4
|
+
# Animation allows to create gif animation with given plots
|
5
|
+
# as frames. Possible frames: Plot, Splot, Multiplot.
|
6
|
+
# More about its usage in {animation notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/animated_plots.ipynb].
|
7
|
+
class Animation < Multiplot
|
8
|
+
##
|
9
|
+
# *Plot* here is also named as *frame*
|
10
|
+
alias_method :frames, :plots
|
11
|
+
alias_method :update_frame, :update_plot
|
12
|
+
alias_method :replace_frame, :replace_plot
|
13
|
+
alias_method :add_frame, :add_plot
|
14
|
+
alias_method :add_frames, :add_plots
|
15
|
+
alias_method :remove_frame, :remove_plot
|
16
|
+
|
17
|
+
##
|
18
|
+
# ====== Overview
|
19
|
+
# This method creates a gif animation where frames are plots
|
20
|
+
# already contained by Animation object.
|
21
|
+
# ====== Arguments
|
22
|
+
# * *term* - Terminal to plot to
|
23
|
+
# * *options* - will be considered as 'settable' options of gnuplot
|
24
|
+
# ('set xrange [1:10]', 'set title 'plot'' etc)
|
25
|
+
# Options passed here have priority over already existing.
|
26
|
+
# Inner options of Plots have the highest priority (except
|
27
|
+
# :term and :output which are ignored).
|
28
|
+
def plot(path = nil, **options)
|
29
|
+
options[:output] ||= path
|
30
|
+
plot_options = mix_options(options) do |plot_opts, anim_opts|
|
31
|
+
plot_opts.merge(term: ['gif', anim_opts])
|
32
|
+
end.to_h
|
33
|
+
need_output = plot_options[:output].nil?
|
34
|
+
plot_options[:output] = Dir::Tmpname.make_tmpname('anim', 0) if need_output
|
35
|
+
terminal = Terminal.new
|
36
|
+
multiplot(terminal, plot_options)
|
37
|
+
# guaranteed wait for plotting to finish
|
38
|
+
terminal.close
|
39
|
+
if need_output
|
40
|
+
result = File.binread(plot_options[:output])
|
41
|
+
File.delete(plot_options[:output])
|
42
|
+
else
|
43
|
+
result = nil
|
44
|
+
end
|
45
|
+
result
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# #to_<term_name> methods are not supported by animation
|
50
|
+
def to_specific_term(*_)
|
51
|
+
fail 'Specific terminals are not supported by Animation'
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# This method is used to embed gif animations
|
56
|
+
# into iRuby notebooks.
|
57
|
+
def to_iruby
|
58
|
+
gif_base64 = Base64.encode64(plot)
|
59
|
+
['text/html', "<img src=\"data:image/gif;base64, #{gif_base64}\">"]
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
##
|
65
|
+
# Dafault options to be used for that plot
|
66
|
+
def default_options
|
67
|
+
{
|
68
|
+
animate: {
|
69
|
+
delay: 10,
|
70
|
+
loop: 0,
|
71
|
+
optimize: true
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# This plot have some specific options which
|
78
|
+
# should be handled different way than others.
|
79
|
+
# Here are keys of this options.
|
80
|
+
def specific_keys
|
81
|
+
%w(
|
82
|
+
animate
|
83
|
+
size
|
84
|
+
background
|
85
|
+
transparent
|
86
|
+
enhanced
|
87
|
+
rounded
|
88
|
+
butt
|
89
|
+
linewidth
|
90
|
+
dashlength
|
91
|
+
tiny
|
92
|
+
small
|
93
|
+
medium
|
94
|
+
large
|
95
|
+
giant
|
96
|
+
font
|
97
|
+
fontscale
|
98
|
+
crop
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -1,10 +1,16 @@
|
|
1
1
|
if defined? Daru
|
2
|
+
##
|
3
|
+
# See {daru}[https://github.com/v0dro/daru] and
|
4
|
+
# {plotting from daru}[https://github.com/dilcom/gnuplotrb/blob/master/notebooks/plotting_from_daru.ipynb]
|
2
5
|
module Daru
|
6
|
+
##
|
7
|
+
# Methods to take data for GnuplotRB plots.
|
3
8
|
class DataFrame
|
4
9
|
def to_gnuplot_points
|
5
10
|
result = ''
|
6
|
-
|
7
|
-
|
11
|
+
each_row_with_index do |row, index|
|
12
|
+
quoted = index.is_a?(String) || index.is_a?(Symbol)
|
13
|
+
result += quoted ? "\"#{index}\" " : "#{index} "
|
8
14
|
result += row.to_a.join(' ')
|
9
15
|
result += "\n"
|
10
16
|
end
|
@@ -12,14 +18,18 @@ if defined? Daru
|
|
12
18
|
end
|
13
19
|
end
|
14
20
|
|
21
|
+
##
|
22
|
+
# Methods to take data for GnuplotRB plots.
|
15
23
|
class Vector
|
16
24
|
def to_gnuplot_points
|
17
25
|
result = ''
|
18
|
-
|
19
|
-
|
26
|
+
each_with_index do |value, index|
|
27
|
+
quoted = index.is_a?(String) || index.is_a?(Symbol)
|
28
|
+
result += quoted ? "\"#{index}\" " : "#{index} "
|
29
|
+
result += "#{value}\n"
|
20
30
|
end
|
21
31
|
result
|
22
32
|
end
|
23
33
|
end
|
24
34
|
end
|
25
|
-
end
|
35
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module GnuplotRB
|
2
|
+
##
|
3
|
+
# ====== Overview
|
4
|
+
# Fit given data with function. Covered in {fit notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/fitting_data.ipynb].
|
5
|
+
# ====== Arguments
|
6
|
+
# * *data* - method accepts the same sources as Dataset.new
|
7
|
+
# and Dataset object
|
8
|
+
# * *:function* - function to fit data with. Default 'a2*x*x+a1*x+a0'
|
9
|
+
# * *:initials* - initial values for coefficients used in fitting.
|
10
|
+
# Default: {a2: 1, a1: 1, a0: 1}
|
11
|
+
# * *:via* - coefficients that Gnuplot should change during fitting.
|
12
|
+
# Default: initials#keys
|
13
|
+
# * *:term_options* - terminal options that should be setted to terminal before fit.
|
14
|
+
# For example *xrange*, *yrange* etc
|
15
|
+
# * *options* - options passed to Gnuplot's fit such as *using*
|
16
|
+
# ====== Return value
|
17
|
+
# Fit returns hash of 4 elements:
|
18
|
+
# * *:formula_ds* - dataset with best fit curve as data
|
19
|
+
# * *:coefficients* - hash of calculated coefficients. So if you gave {via: [:a, :b, :c]} or
|
20
|
+
# {initials: {a: 1, b: 1, c: 1} } it will return hash with keys :a, :b, :c and its values
|
21
|
+
# * *:deltas* - Gnuplot calculates possible deltas for coefficients during fitting and
|
22
|
+
# *deltas* hash contains this deltas
|
23
|
+
# * *:data* - pointer to Datablock with given data
|
24
|
+
# ====== Examples
|
25
|
+
# fit(some_data, function: 'exp(a/x)', initials: {a: 10}, term_option: { xrange: 1..100 })
|
26
|
+
# fit(some_dataset, using: '1:2:3')
|
27
|
+
def fit(data, function: 'a2*x*x+a1*x+a0', initials: { a2: 1, a1: 1, a0: 1 }, term_options: {}, **options)
|
28
|
+
dataset = data.is_a?(Dataset) ? Dataset.new(data.data) : Dataset.new(data)
|
29
|
+
opts_str = OptionHandling.ruby_class_to_gnuplot(options)
|
30
|
+
output = gnuplot_fit(function, dataset, opts_str, initials, term_options)
|
31
|
+
res = parse_output(initials.keys, function, output)
|
32
|
+
{
|
33
|
+
formula_ds: Dataset.new(res[2], title: 'Fit formula'),
|
34
|
+
coefficients: res[0],
|
35
|
+
deltas: res[1],
|
36
|
+
data: dataset
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# ====== Overview
|
42
|
+
# Shortcut for fit with polynomial. Degree here is max power of *x* in polynomial.
|
43
|
+
# ====== Arguments
|
44
|
+
# * *data* - method accepts the same sources as Dataset.new and Dataset object
|
45
|
+
# * *:degree* - degree of polynomial
|
46
|
+
# * *options* - all of this options will be passed to *#fit* so you
|
47
|
+
# can set here any *term_options*. If you pass here *:initials* hash, it
|
48
|
+
# will be merged into default initals hash (all values are 1).
|
49
|
+
# ====== Return value
|
50
|
+
# See the same section for #fit.
|
51
|
+
# ====== Examples
|
52
|
+
# fit_poly(some_data, degree: 5, initials: { a4: 10, a2: -1 }, term_option: { xrange: 1..100 })
|
53
|
+
# #=> The same as:
|
54
|
+
# #=> fit(
|
55
|
+
# #=> some_data,
|
56
|
+
# #=> function: 'a5*x**5 + a4*x**4 + ... + a0*x**0',
|
57
|
+
# #=> initals: {a5: 1, a4: 10, a3: 1, a2: -1, a1: 1, a0: 1},
|
58
|
+
# #=> term_option: { xrange: 1..100 }
|
59
|
+
# #=> )
|
60
|
+
def fit_poly(data, degree: 2, **options)
|
61
|
+
sum_count = degree + 1
|
62
|
+
initials = {}
|
63
|
+
sum_count.times { |i| initials["a#{i}".to_sym] = 1 }
|
64
|
+
options[:initials] = initials.merge(options[:initials] || {})
|
65
|
+
function = sum_count.times.map { |i| "a#{i}*x**#{i}" }.join(' + ')
|
66
|
+
fit(data, **options, function: function)
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# :method: fit_<function>
|
71
|
+
# :call-seq:
|
72
|
+
# fit_exp(data, **options) -> Hash
|
73
|
+
# fit_log(data, **options) -> Hash
|
74
|
+
# fit_sin(data, **options) -> Hash
|
75
|
+
#
|
76
|
+
# ====== Overview
|
77
|
+
# Shortcuts for fitting with several math functions (exp, log, sin).
|
78
|
+
# ====== Arguments
|
79
|
+
# * *data* - method accepts the same sources as Dataset.new and Dataset object
|
80
|
+
# * *options* - all of this options will be passed to *#fit* so you
|
81
|
+
# can set here any *term_options*. If you pass here *:initials* hash, it
|
82
|
+
# will be merged into default initals hash { yoffset: 0.1, xoffset: 0.1, yscale: 1, xscale: 1 }
|
83
|
+
# ====== Return value
|
84
|
+
# See the same section for #fit.
|
85
|
+
# ====== Examples
|
86
|
+
# fit_exp(some_data, initials: { yoffset: -11 }, term_option: { xrange: 1..100 })
|
87
|
+
# #=> The same as:
|
88
|
+
# #=> fit(
|
89
|
+
# #=> some_data,
|
90
|
+
# #=> function: 'yscale * (yoffset + exp((x - xoffset) / xscale))',
|
91
|
+
# #=> initals: { yoffset: -11, xoffset: 0.1, yscale: 1, xscale: 1 },
|
92
|
+
# #=> term_option: { xrange: 1..100 }
|
93
|
+
# #=> )
|
94
|
+
# fit_log(...)
|
95
|
+
# fit_sin(...)
|
96
|
+
%w(exp log sin).map do |fname|
|
97
|
+
define_method("fit_#{fname}".to_sym) do |data, **options|
|
98
|
+
options[:initials] = {
|
99
|
+
yoffset: 0.1,
|
100
|
+
xoffset: 0.1,
|
101
|
+
yscale: 1,
|
102
|
+
xscale: 1
|
103
|
+
}.merge(options[:initials] || {})
|
104
|
+
function = "yscale * (yoffset + #{fname} ((x - xoffset) / xscale))"
|
105
|
+
fit(data, **options, function: function)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
##
|
112
|
+
# It takes some time to produce output so here we need
|
113
|
+
# to wait for it.
|
114
|
+
def wait_for_output(term, variables)
|
115
|
+
# now we should catch 'error' from terminal: it will contain approximation data
|
116
|
+
# but we can get a real error instead of output, so lets wait for limited time
|
117
|
+
start = Time.now
|
118
|
+
output = ''
|
119
|
+
until output_ready?(output, variables)
|
120
|
+
begin
|
121
|
+
term.check_errors
|
122
|
+
rescue GnuplotRB::GnuplotError => e
|
123
|
+
output += e.message
|
124
|
+
end
|
125
|
+
if Time.now - start > Settings.max_fit_delay
|
126
|
+
fail GnuplotError, "Seems like there is an error in gnuplotrb: #{output}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
output
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# Check if current output contains all the
|
134
|
+
# variables given to fit.
|
135
|
+
def output_ready?(output, variables)
|
136
|
+
output =~ /Final set .*#{variables.join('.*')}/
|
137
|
+
end
|
138
|
+
|
139
|
+
##
|
140
|
+
# Parse Gnuplot's output to get coefficients and their deltas
|
141
|
+
# from it. Also replaces coefficients in given function with
|
142
|
+
# exact values.
|
143
|
+
def parse_output(variables, function, output)
|
144
|
+
plottable_function = " #{function.clone} "
|
145
|
+
coefficients = {}
|
146
|
+
deltas = {}
|
147
|
+
variables.each do |var|
|
148
|
+
value, error = output.scan(%r{#{var} *= ([^ ]+) *\+/\- ([^ ]+)})[0]
|
149
|
+
plottable_function.gsub!(/#{var}([^0-9a-zA-Z])/) { value + Regexp.last_match(1) }
|
150
|
+
coefficients[var] = value.to_f
|
151
|
+
deltas[var] = error.to_f
|
152
|
+
end
|
153
|
+
[coefficients, deltas, plottable_function]
|
154
|
+
end
|
155
|
+
|
156
|
+
##
|
157
|
+
# Make fit command and send it to gnuplot
|
158
|
+
def gnuplot_fit(function, data, options, initials, term_options)
|
159
|
+
variables = initials.keys
|
160
|
+
term = Terminal.new
|
161
|
+
term.set(term_options)
|
162
|
+
initials.each { |var_name, value| term.stream_puts "#{var_name} = #{value}" }
|
163
|
+
command = "fit #{function} #{data.to_s(term)} #{options} via #{variables.join(',')}"
|
164
|
+
term.stream_puts(command)
|
165
|
+
output = wait_for_output(term, variables)
|
166
|
+
begin
|
167
|
+
term.close
|
168
|
+
rescue GnuplotError
|
169
|
+
# Nothing interesting here.
|
170
|
+
# If we had an error, we never reach this line.
|
171
|
+
# Error here may be only additional information
|
172
|
+
# such as correlation matrix.
|
173
|
+
end
|
174
|
+
output
|
175
|
+
end
|
176
|
+
end
|
@@ -13,30 +13,34 @@ module GnuplotRB
|
|
13
13
|
# Check if there were errors in previous commands.
|
14
14
|
# Throws GnuplotError in case of any errors.
|
15
15
|
def check_errors
|
16
|
-
|
16
|
+
return if @err_array.empty?
|
17
|
+
command = ''
|
18
|
+
rest = ''
|
19
|
+
@semaphore.synchronize do
|
17
20
|
command = @err_array.first
|
18
21
|
rest = @err_array[1..-1].join('; ')
|
19
|
-
message = "Error in previous command (\"#{command}\"): \"#{rest}\""
|
20
22
|
@err_array.clear
|
21
|
-
fail GnuplotError, message
|
22
23
|
end
|
24
|
+
message = "Error in previous command (\"#{command}\"): \"#{rest}\""
|
25
|
+
fail GnuplotError, message
|
23
26
|
end
|
24
27
|
|
28
|
+
private
|
29
|
+
|
25
30
|
##
|
26
31
|
# ====== Overview
|
27
32
|
# Start new thread that will read stderr given as stream
|
28
33
|
# and add errors into @err_array.
|
29
34
|
def handle_stderr(stream)
|
30
35
|
@err_array = []
|
36
|
+
# synchronize access to @err_array
|
37
|
+
@semaphore = Mutex.new
|
31
38
|
Thread.new do
|
32
|
-
until (line = stream.gets).nil?
|
39
|
+
until (line = stream.gets).nil?
|
33
40
|
line.strip!
|
34
|
-
@err_array << line if line.size > 3
|
41
|
+
@semaphore.synchronize { @err_array << line if line.size > 3 }
|
35
42
|
end
|
36
43
|
end
|
37
44
|
end
|
38
|
-
|
39
|
-
private :check_errors,
|
40
|
-
:handle_stderr
|
41
45
|
end
|
42
46
|
end
|
@@ -20,10 +20,19 @@ module GnuplotRB
|
|
20
20
|
zlabel
|
21
21
|
rgb
|
22
22
|
font
|
23
|
+
background
|
24
|
+
format
|
25
|
+
format_x
|
26
|
+
format_y
|
27
|
+
format_xy
|
28
|
+
format_x2
|
29
|
+
format_y2
|
30
|
+
format_z
|
31
|
+
format_cb
|
32
|
+
timefmt
|
23
33
|
)
|
24
34
|
|
25
35
|
##
|
26
|
-
# For inner use!
|
27
36
|
# Replacement '_' with ' ' is made to allow passing several options
|
28
37
|
# with the same first word of key.
|
29
38
|
# See issue #7 for more info.
|
@@ -89,26 +98,25 @@ module GnuplotRB
|
|
89
98
|
# Now checks only terminal name.
|
90
99
|
def validate_terminal_options(options)
|
91
100
|
terminal = options[:term]
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
end
|
101
|
+
return unless terminal
|
102
|
+
terminal = terminal[0] if terminal.is_a?(Array)
|
103
|
+
message = 'Seems like your Gnuplot does not ' \
|
104
|
+
'support that terminal, please see supported ' \
|
105
|
+
'terminals with Settings::available_terminals'
|
106
|
+
fail(ArgumentError, message) unless valid_terminal?(terminal)
|
99
107
|
end
|
100
108
|
end
|
101
109
|
|
102
110
|
##
|
103
111
|
# You should implement #initialize in classes that use OptionsHelper
|
104
|
-
def initialize(*
|
112
|
+
def initialize(*_)
|
105
113
|
fail NotImplementedError, 'You should implement #initialize' \
|
106
114
|
' in classes that use OptionsHelper!'
|
107
115
|
end
|
108
116
|
|
109
117
|
##
|
110
118
|
# You should implement #new_with_options in classes that use OptionsHelper
|
111
|
-
def new_with_options(*
|
119
|
+
def new_with_options(*_)
|
112
120
|
fail NotImplementedError, 'You should implement #new_with_options' \
|
113
121
|
' in classes that use OptionsHelper!'
|
114
122
|
end
|
@@ -137,8 +145,9 @@ module GnuplotRB
|
|
137
145
|
end
|
138
146
|
end
|
139
147
|
|
148
|
+
private
|
149
|
+
|
140
150
|
##
|
141
|
-
# Method for inner use.
|
142
151
|
# ====== Arguments
|
143
152
|
# * *key* - [Symbol] - option key
|
144
153
|
# * *value* - anything treated as options value in gnuplot gem
|
@@ -151,7 +160,5 @@ module GnuplotRB
|
|
151
160
|
options(key => value)
|
152
161
|
end
|
153
162
|
end
|
154
|
-
|
155
|
-
private :option
|
156
163
|
end
|
157
164
|
end
|