gnuplotrb 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 636e6f8b249ca52a3dc09d4034cb7596ba650e42
4
- data.tar.gz: d8eea39c386a7cc6513b2992b126fc15412318f4
3
+ metadata.gz: cec6373d3af74267f75b7e627201944401affe70
4
+ data.tar.gz: cc9e9d26c4ab999b708b797a4feb2d6d643705d9
5
5
  SHA512:
6
- metadata.gz: 2d331f099e12185d350a4b1fe6908a658cfdcc977c3d4657bd621efe510fb854fe1a86fdd780b8f32e1ea69146934e513e8b1de16ead04e8a43c11da093d23eb
7
- data.tar.gz: 26c483e4a645ac3b2ef9a680ba8a30cc3975fd68f0ad329e3cf22fae53a26cec5fd8b8743bd57850025c351bae77988dccf40d436c3f49b7a4c8c4344b222e4d
6
+ metadata.gz: 13b66a6ebf312632d79e5f6ab3578fb00e7fa02060855f04ca8c24c680766146bfef1c8f7be038f601e8064e3d1e361b80e727605be6386ed112554e73ff57f1
7
+ data.tar.gz: 663aee900352e69d581a0fa2830b878441de4a81515d1901b252c647a96eff64c36b166f66326368747d72947d004a8ea18d6a1ccd3130b8c349c2ff242506bd
@@ -2,17 +2,20 @@
2
2
 
3
3
  GnuplotRB is a plot generator for Ruby based on {Gnuplot}[http://www.gnuplot.info].
4
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/].
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://www.evgrafov.work/gnuplotrb/].
6
6
 
7
7
  {<img src="https://badge.fury.io/rb/gnuplotrb.svg" alt="Gem Version" />}[https://rubygems.org/gems/gnuplotrb]
8
8
 
9
+ {<img src="https://gemnasium.com/dilcom/gnuplotrb.svg" alt="Dependency Status" />}[https://gemnasium.com/dilcom/gnuplotrb]
10
+
9
11
  {<img src="https://travis-ci.org/dilcom/gnuplotrb.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/dilcom/gnuplotrb]
10
12
  {<img src="https://codeclimate.com/github/dilcom/gnuplotrb/badges/gpa.svg" alt="Code quality" />}[https://codeclimate.com/github/dilcom/gnuplotrb]
11
13
  {<img src="https://codeclimate.com/github/dilcom/gnuplotrb/badges/coverage.svg" alt="Test coverage" />}[https://codeclimate.com/github/dilcom/gnuplotrb]
12
14
 
13
15
  == Table of contents
14
16
  * {Installation}[https://github.com/dilcom/gnuplotrb#installation]
15
- * {Examples}[https://github.com/dilcom/gnuplotrb#examples]
17
+ * {Getting started}[https://github.com/dilcom/gnuplotrb#getting-started]
18
+ * {Plottable classes}[https://github.com/dilcom/gnuplotrb#plottable-classes]
16
19
  * {Notebooks}[https://github.com/dilcom/gnuplotrb#notebooks]
17
20
  * {Plain examples}[https://github.com/dilcom/gnuplotrb#plain-examples]
18
21
  * {Contributing}[https://github.com/dilcom/gnuplotrb#contributing]
@@ -36,7 +39,67 @@ This software has been developed as a product in Google Summer of Code 2015 (GSo
36
39
  bundle install
37
40
  rake install
38
41
 
39
- == Examples
42
+ == Getting started
43
+
44
+ GnuplotRB gem is based on {Gnuplot}[http://www.gnuplot.info/] so I would recommend to use {Gnuplot doc}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] and {GnuplotRB doc at Rubydoc}[https://rubygems.org/gems/gnuplotrb] in cases when docs and examples (as notebooks and plain examples) present here are not enough to explain how to plot something.
45
+
46
+ === Plottable classes
47
+
48
+ Each of plottable classes may be outputted to image file using ```#to_png```, ```#to_svg```, ```#to_gif``` and so on methods. You can read more about it in {GnuplotRB doc}[https://rubygems.org/gems/gnuplotrb] related to Plottable module or see examples in {beginners notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/basic_usage.ipynb].
49
+
50
+ ==== Dataset
51
+ Single dataset may be created with math formula ('sin(x)') or some data. If your data is stored in a file you can just pass a filename (e.g. 'gnuplotrb.data'). Dataset may also be constructed out of data contained in Ruby classes (Array, Daru containers), see {example notebooks}[https://github.com/dilcom/gnuplotrb#possible-datasources].
52
+
53
+ Dataset have several possible options which are explained in {gnuplot doc}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] (pp. 80-102). Options are passed to Dataset.new as hash and are tranlated into gnuplot format before plotting:
54
+ Dataset.new(data, with: 'lines', using: '1:2')
55
+ Examples of option translation (nested containers allowed):
56
+ * Hash:
57
+ { key1: "value1", key2: { nested_key1: "nested_value1" } }
58
+ # =>
59
+ "key1 value1 key2 nested key1 nested_value1"
60
+ * Hashes with underscored keys (see {#7}[https://github.com/dilcom/gnuplotrb/issues/7]):
61
+ { style_data: 'histograms' }
62
+ #=>
63
+ "style data histograms"
64
+ * Range:
65
+ { xrange: 0..100 }
66
+ # =>
67
+ "xrange [0:100]"
68
+ * Array (often used with nested hashes) and Array of Numeric
69
+ ['png', { size: [400, 500] }]
70
+ # =>
71
+ "png size 400,500"
72
+ * Others
73
+ some_object
74
+ # =>
75
+ some_object.to_s
76
+
77
+ Once Dataset created, it may be updated with new data or options. Methods related to updating are explained in {a notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/updating_data.ipynb].
78
+
79
+ Just as other Plottable object Dataset has several plotting methods which are desribed in {beginners notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/basic_usage.ipynb].
80
+
81
+ ==== Plot
82
+ Plot is a container for several datasets and layout options:
83
+ Plot.new(ds1, ds2, ds2, xrange: 1..10)
84
+
85
+ Datasets contained bu Plot are outputted on single xy plain.
86
+
87
+ Plot's options are explained in {gnuplot doc}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] (pp. 105-181). Plot options are translated into gnuplot format the same way as Dataset's (except adding 'set' before each option). Plot's datasets and Plot itself may be updated with almost the same methods as desribed in Dataset section above.
88
+
89
+ ==== Splot
90
+ Almost the same as Plot but for 3-D plots. See Plot section.
91
+
92
+ ==== Multiplot
93
+
94
+ Container for several Plot or Splot objects, each of them is plotted in its own xy(z) space. So Multiplot offers single layout (image file\window) for several plots. It's grid is tuned by :layout option, and you can also set layout's title:
95
+ Multiplot.new(plot1, plot2, splot1, layout: [3, 1], title: 'Three plots on a layout')
96
+
97
+ Updating methods for Multiplot are almost the same as Plot's and Dataset's and are covered in Multiplot's docs and {multiplot notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/multiplot_layout.ipynb]. See examples there.
98
+
99
+ ==== Animation
100
+
101
+ Animation is a container for several Plot, Splot or Multiplot objects. Each of contained items is considered as frame in gif animation which is creating by ```#plot``` call. Animation's frames and options may be modifyed or updated just as other classes above. Animation does not support methods like ```#to_png``` and may be plotted only with ```#plot``` method. Please see {related notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/animated_plots.ipynb] and docs at RubyDoc for examples.
102
+
40
103
  === Notebooks
41
104
 
42
105
  This notebooks are powered by {Ruby kernel}[https://github.com/SciRuby/iruby/] for {IPython/Jupyter}[https://jupyter.org/].
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
3
  require 'rspec/core'
4
- require 'rdoc/task'
4
+ require 'yard'
5
5
  require 'rubocop/rake_task'
6
6
 
7
7
  RSpec::Core::RakeTask.new(:spec) do |spec|
@@ -9,9 +9,8 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
9
9
  spec.rspec_opts = '--format documentation'
10
10
  end
11
11
 
12
- RDoc::Task.new(:doc) do |rdoc|
13
- rdoc.main = 'README.rdoc'
14
- rdoc.rdoc_files.include %w(README.rdoc lib)
12
+ YARD::Rake::YardocTask.new(:doc) do |t|
13
+ t.files = %w(README.rdoc lib) # optional
15
14
  end
16
15
 
17
16
  RuboCop::RakeTask.new(:cop)
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency 'bundler', '~> 1.7'
23
23
  spec.add_development_dependency 'rake', '~> 10.0'
24
24
  spec.add_development_dependency 'rspec', '~> 3.2'
25
- spec.add_development_dependency 'rdoc', '~> 4.2'
25
+ spec.add_development_dependency 'yard', '~> 0.8'
26
26
  spec.add_development_dependency 'rubocop', '~> 0.29'
27
27
  spec.add_development_dependency 'codeclimate-test-reporter'
28
28
  spec.add_development_dependency 'chunky_png'
@@ -3,6 +3,11 @@ require 'hamster'
3
3
  require 'open3'
4
4
  require 'base64'
5
5
 
6
+ ##
7
+ # Require gem if it's available in current gemspace.
8
+ #
9
+ # @param name [String] gem name
10
+ # @return [Boolean] true if gem was loaded, false otherwise
6
11
  def require_if_available(name)
7
12
  require name
8
13
  rescue LoadError
@@ -1,9 +1,29 @@
1
1
  module GnuplotRB
2
2
  ##
3
- # === Overview
4
3
  # Animation allows to create gif animation with given plots
5
4
  # 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].
5
+ # More about its usage in
6
+ # {animation notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/animated_plots.ipynb].
7
+ #
8
+ # == Options
9
+ # Animations has several specific options:
10
+ # * animate - allows to get animated gif's. Possible values are true (just turn on animation),
11
+ # ot hash with suboptions (:loop - count of loops, default 0 - infinity$;
12
+ # :delay - delay between frames; :optimize - boolean, reduces file size).
13
+ # * size - size of gif file in pixels (size: [500, 500]) or (size: 500)
14
+ # * background - background color
15
+ # * transparent
16
+ # * enhanced
17
+ # * font
18
+ # * fontscale
19
+ # * crop
20
+ #
21
+ # Animation ignores :term option and does not have methods like #to_png or #to_svg.
22
+ # One can also set animation any options related to Plot and they will be considered
23
+ # by all nested plots (if they does not override it with their own values).
24
+ #
25
+ # Animation inherits all plot array handling methods from Multiplot
26
+ # and adds aliases for them (#plots -> #frames; #update_frame! -> #update_plot!; etc).
7
27
  class Animation < Multiplot
8
28
  ##
9
29
  # *Plot* here is also named as *frame*
@@ -13,18 +33,25 @@ module GnuplotRB
13
33
  alias_method :add_frame, :add_plot
14
34
  alias_method :add_frames, :add_plots
15
35
  alias_method :remove_frame, :remove_plot
36
+ alias_method :update_frame!, :update_plot!
37
+ alias_method :replace_frame!, :replace_plot!
38
+ alias_method :add_frame!, :add_plot!
39
+ alias_method :add_frames!, :add_plots!
40
+ alias_method :remove_frame!, :remove_plot!
16
41
 
17
42
  ##
18
- # ====== Overview
19
43
  # This method creates a gif animation where frames are plots
20
44
  # 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.
45
+ #
46
+ # Options passed in #plot have priority over those which were set before.
47
+ #
26
48
  # Inner options of Plots have the highest priority (except
27
49
  # :term and :output which are ignored).
50
+ #
51
+ # @param path [String] path to new gif file that will be created as a result
52
+ # @param options [Hash] see note about available options in top class documentation
53
+ # @return [nil] if path to output file given
54
+ # @return [String] gif file contents if no path to output file given
28
55
  def plot(path = nil, **options)
29
56
  options[:output] ||= path
30
57
  plot_options = mix_options(options) do |plot_opts, anim_opts|
@@ -46,7 +73,7 @@ module GnuplotRB
46
73
  end
47
74
 
48
75
  ##
49
- # #to_<term_name> methods are not supported by animation
76
+ # #to_|term_name| methods are not supported by animation
50
77
  def to_specific_term(*_)
51
78
  fail 'Specific terminals are not supported by Animation'
52
79
  end
@@ -2,6 +2,7 @@
2
2
  # Methods to take data for GnuplotRB plots.
3
3
  class Array
4
4
  # taken for example from current gnuplot bindings
5
+ # @return [String] array converted to Gnuplot format
5
6
  def to_gnuplot_points
6
7
  return '' if self.empty?
7
8
  case self[0]
@@ -6,6 +6,10 @@ if defined? Daru
6
6
  ##
7
7
  # Methods to take data for GnuplotRB plots.
8
8
  class DataFrame
9
+ ##
10
+ # Convert DataFrame to Gnuplot format.
11
+ #
12
+ # @return [String] data converted to Gnuplot format
9
13
  def to_gnuplot_points
10
14
  result = ''
11
15
  each_row_with_index do |row, index|
@@ -21,6 +25,10 @@ if defined? Daru
21
25
  ##
22
26
  # Methods to take data for GnuplotRB plots.
23
27
  class Vector
28
+ ##
29
+ # Convert Vector to Gnuplot format.
30
+ #
31
+ # @return [String] data converted to Gnuplot format
24
32
  def to_gnuplot_points
25
33
  result = ''
26
34
  each_with_index do |value, index|
@@ -1,7 +1,6 @@
1
1
  ##
2
2
  # Methods to take data for GnuplotRB plots.
3
3
  class String
4
- def to_gnuplot_points
5
- clone
6
- end
4
+ # @return [String] data converted to Gnuplot format
5
+ alias_method :to_gnuplot_points, :clone
7
6
  end
@@ -1,176 +1,204 @@
1
1
  module GnuplotRB
2
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
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].
75
5
  #
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)
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
+ }
106
47
  end
107
- end
108
48
 
109
- private
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
110
84
 
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
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)
124
129
  end
125
- if Time.now - start > Settings.max_fit_delay
126
- fail GnuplotError, "Seems like there is an error in gnuplotrb: #{output}"
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
127
154
  end
155
+ output
128
156
  end
129
- output
130
- end
131
157
 
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
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
138
164
 
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
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]
152
180
  end
153
- [coefficients, deltas, plottable_function]
154
- end
155
181
 
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.
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
173
202
  end
174
- output
175
203
  end
176
204
  end