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
@@ -6,44 +6,12 @@ module GnuplotRB
|
|
6
6
|
module Plottable
|
7
7
|
include OptionHandling
|
8
8
|
|
9
|
-
##
|
10
|
-
# Terminal object used by this Plottable to pipe data to gnuplot.
|
11
|
-
attr_reader :terminal
|
12
|
-
|
13
9
|
##
|
14
10
|
# You should implement #plot in classes that are Plottable
|
15
|
-
def plot(*
|
11
|
+
def plot(*_)
|
16
12
|
fail NotImplementedError, 'You should implement #plot in classes that are Plottable!'
|
17
13
|
end
|
18
14
|
|
19
|
-
##
|
20
|
-
# Method for inner use.
|
21
|
-
# ====== Overview
|
22
|
-
# Method which outputs plot to specific terminal (possibly some file).
|
23
|
-
# Explicit use should be avoided. This method is called from #method_missing
|
24
|
-
# when it handles method names like #to_png(options).
|
25
|
-
# ====== Arguments
|
26
|
-
# * *terminal* - string corresponding to terminal type (png, html, jpeg etc)
|
27
|
-
# * *path* - path to output file, if none given it will output to temp file
|
28
|
-
# and then read it and return binary contents of file
|
29
|
-
# * *options* - used in 'set term <term type> <options here>'
|
30
|
-
# ====== Examples
|
31
|
-
# ## plot here may be Plot, Splot, Multiplot or any other plottable class
|
32
|
-
# plot.to_png('./result.png', size: [300, 500])
|
33
|
-
# contents = plot.to_svg(size: [100, 100])
|
34
|
-
# plot.to_dumb('./result.txt', size: [30, 15])
|
35
|
-
def to_specific_term(terminal, path = nil, **options)
|
36
|
-
if path
|
37
|
-
result = plot(term: [terminal, options], output: path)
|
38
|
-
else
|
39
|
-
path = Dir::Tmpname.make_tmpname(terminal, 0)
|
40
|
-
plot(term: [terminal, options], output: path)
|
41
|
-
result = File.binread(path)
|
42
|
-
File.delete(path)
|
43
|
-
end
|
44
|
-
result
|
45
|
-
end
|
46
|
-
|
47
15
|
##
|
48
16
|
# ====== Overview
|
49
17
|
# In this gem #method_missing is used both to handle
|
@@ -98,5 +66,60 @@ module GnuplotRB
|
|
98
66
|
term = meth[0..2] == 'to_' && OptionHandling.valid_terminal?(meth[3..-1])
|
99
67
|
term || super
|
100
68
|
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# This method is used to embed plottable objects
|
72
|
+
# into iRuby notebooks. There is
|
73
|
+
# {a notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/basic_usage.ipynb]
|
74
|
+
# with examples of its usage.
|
75
|
+
def to_iruby
|
76
|
+
available_terminals = {
|
77
|
+
'png' => 'image/png',
|
78
|
+
'pngcairo' => 'image/png',
|
79
|
+
'jpeg' => 'image/jpeg',
|
80
|
+
'svg' => 'image/svg+xml',
|
81
|
+
'dumb' => 'text/plain'
|
82
|
+
}
|
83
|
+
terminal, options = term.is_a?(Array) ? [term[0], term[1]] : [term, {}]
|
84
|
+
terminal = 'svg' unless available_terminals.keys.include?(terminal)
|
85
|
+
[available_terminals[terminal], send("to_#{terminal}".to_sym, **options)]
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# :call-seq:
|
90
|
+
# to_png('file.png') -> creates file with plot
|
91
|
+
# to_svg -> svg file contents
|
92
|
+
# to_canvas('plot.html', size: [300,300]) -> creates file with plot
|
93
|
+
#
|
94
|
+
# ====== Overview
|
95
|
+
# Method which outputs plot to specific terminal (possibly some file).
|
96
|
+
# Explicit use should be avoided. This method is called from #method_missing
|
97
|
+
# when it handles method names like #to_png(options).
|
98
|
+
# ====== Arguments
|
99
|
+
# * *path* - path to output file, if none given it will output to temp file
|
100
|
+
# and then read it and return binary contents of file
|
101
|
+
# * *options* - used in #plot
|
102
|
+
# ====== Examples
|
103
|
+
# ## plot here may be Plot, Splot, Multiplot or any other plottable class
|
104
|
+
# plot.to_png('./result.png', size: [300, 500])
|
105
|
+
# contents = plot.to_svg(size: [100, 100])
|
106
|
+
# plot.to_dumb('./result.txt', size: [30, 15])
|
107
|
+
def to_specific_term(terminal, path = nil, **options)
|
108
|
+
if path
|
109
|
+
result = plot(term: [terminal, options], output: path)
|
110
|
+
else
|
111
|
+
path = Dir::Tmpname.make_tmpname(terminal, 0)
|
112
|
+
plot(term: [terminal, options], output: path)
|
113
|
+
result = File.binread(path)
|
114
|
+
File.delete(path)
|
115
|
+
end
|
116
|
+
result
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# Returns terminal object linked with this Plottable object.
|
121
|
+
def own_terminal
|
122
|
+
@terminal ||= Terminal.new
|
123
|
+
end
|
101
124
|
end
|
102
125
|
end
|
data/lib/gnuplotrb/multiplot.rb
CHANGED
@@ -2,6 +2,7 @@ module GnuplotRB
|
|
2
2
|
##
|
3
3
|
# === Overview
|
4
4
|
# Multiplot allows to place several plots on one layout.
|
5
|
+
# It's usage is covered in {multiplot notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/multiplot_layout.ipynb].
|
5
6
|
class Multiplot
|
6
7
|
include Plottable
|
7
8
|
##
|
@@ -11,32 +12,16 @@ module GnuplotRB
|
|
11
12
|
##
|
12
13
|
# ====== Arguments
|
13
14
|
# * *plots* are Plot or Splot objects which should be placed
|
14
|
-
# on this multiplot
|
15
|
+
# on this multiplot layout
|
15
16
|
# * *options* will be considered as 'settable' options of gnuplot
|
16
|
-
# ('set xrange [1:10]' for { xrange: 1..10 }
|
17
|
-
# "set title 'plot'" for { title: 'plot' } etc) just as in Plot.
|
17
|
+
# ('set xrange [1:10]' for { xrange: 1..10 } etc) just as in Plot.
|
18
18
|
# Special options of Multiplot are :layout and :title.
|
19
19
|
def initialize(*plots, **options)
|
20
20
|
@plots = plots[0].is_a?(Hamster::Vector) ? plots[0] : Hamster::Vector.new(plots)
|
21
21
|
@options = Hamster.hash(options)
|
22
|
-
@terminal = Terminal.new
|
23
22
|
OptionHandling.validate_terminal_options(@options)
|
24
23
|
end
|
25
24
|
|
26
|
-
##
|
27
|
-
# Create new Multiplot object with the same set of plots and
|
28
|
-
# given options.
|
29
|
-
def new_with_options(options)
|
30
|
-
self.class.new(@plots, options)
|
31
|
-
end
|
32
|
-
|
33
|
-
##
|
34
|
-
# Check if given options corresponds to multiplot.
|
35
|
-
# Multiplot special options are :title and :layout.
|
36
|
-
def mp_option?(key)
|
37
|
-
%w(title layout).include?(key.to_s)
|
38
|
-
end
|
39
|
-
|
40
25
|
##
|
41
26
|
# ====== Overview
|
42
27
|
# This outputs all the plots to term (if given) or to this
|
@@ -47,15 +32,13 @@ module GnuplotRB
|
|
47
32
|
# ('set xrange [1:10]', 'set title 'plot'' etc)
|
48
33
|
# Options passed here have priority over already existing.
|
49
34
|
# Inner options of Plots have the highest priority (except
|
50
|
-
# :term and :output which are ignored).
|
51
|
-
def plot(term = nil, **options)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
terminal = term || (plot_options[:output] ? Terminal.new :
|
56
|
-
terminal
|
57
|
-
@plots.each { |graph| graph.plot(terminal, multiplot_part: true) }
|
58
|
-
terminal.unset(plot_options.keys)
|
35
|
+
# :term and :output which are ignored in this case).
|
36
|
+
def plot(term = nil, multiplot_part: false, **options)
|
37
|
+
plot_options = mix_options(options) do |plot_opts, mp_opts|
|
38
|
+
plot_opts.merge(multiplot: mp_opts.to_h)
|
39
|
+
end
|
40
|
+
terminal = term || (plot_options[:output] ? Terminal.new : own_terminal)
|
41
|
+
multiplot(terminal, plot_options)
|
59
42
|
if plot_options[:output]
|
60
43
|
# guaranteed wait for plotting to finish
|
61
44
|
terminal.close unless term
|
@@ -78,10 +61,10 @@ module GnuplotRB
|
|
78
61
|
# * *position* - position of plot which you need to update
|
79
62
|
# (by default first plot is updated)
|
80
63
|
# * *options* - options to update plot with
|
81
|
-
# * method also may take a block which returns a plot
|
64
|
+
# * *&block* - method also may take a block which returns a plot
|
82
65
|
# ====== Example
|
83
66
|
# mp = Multiplot.new(Plot.new('sin(x)'), Plot.new('cos(x)'), layout: [2,1])
|
84
|
-
# updated_mp = mp.update_plot(title: 'Sin(x) and Exp(x)') { |sinx| sinx.
|
67
|
+
# updated_mp = mp.update_plot(title: 'Sin(x) and Exp(x)') { |sinx| sinx.add('exp(x)') }
|
85
68
|
def update_plot(position = 0, **options)
|
86
69
|
return self unless block_given? if options.empty?
|
87
70
|
replacement = @plots[position].options(options)
|
@@ -110,20 +93,22 @@ module GnuplotRB
|
|
110
93
|
|
111
94
|
##
|
112
95
|
# ====== Overview
|
113
|
-
# Create new Multiplot with given *
|
96
|
+
# Create new Multiplot with given *plots* added before plot at given *position*.
|
114
97
|
# (by default it adds plot at the front).
|
115
98
|
# ====== Arguments
|
116
99
|
# * *position* - position before which you want to add a plot
|
117
|
-
# * *
|
100
|
+
# * *plots* - sequence of plots you want to add
|
118
101
|
# ====== Example
|
119
102
|
# mp = Multiplot.new(Plot.new('sin(x)'), Plot.new('cos(x)'), layout: [2,1])
|
120
|
-
# enlarged_mp = mp.
|
121
|
-
def
|
122
|
-
|
103
|
+
# enlarged_mp = mp.add_plots(Plot.new('exp(x)')).layout([3,1])
|
104
|
+
def add_plots(*plots)
|
105
|
+
plots.unshift(0) unless plots[0].is_a?(Numeric)
|
106
|
+
self.class.new(@plots.insert(*plots), @options)
|
123
107
|
end
|
124
108
|
|
125
|
-
alias_method
|
126
|
-
alias_method
|
109
|
+
alias_method :add_plot, :add_plots
|
110
|
+
alias_method :<<, :add_plots
|
111
|
+
alias_method :add, :add_plots
|
127
112
|
|
128
113
|
##
|
129
114
|
# ====== Overview
|
@@ -142,9 +127,64 @@ module GnuplotRB
|
|
142
127
|
|
143
128
|
##
|
144
129
|
# ====== Overview
|
145
|
-
# Equal to #plots[*args]
|
130
|
+
# Equal to #plots[*args]
|
146
131
|
def [](*args)
|
147
132
|
@plots[*args]
|
148
133
|
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
##
|
138
|
+
# Default options to be used for that plot
|
139
|
+
def default_options
|
140
|
+
{
|
141
|
+
layout: [2, 2],
|
142
|
+
title: 'Multiplot'
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# This plot have some specific options which
|
148
|
+
# should be handled different way than others.
|
149
|
+
# Here are keys of this options.
|
150
|
+
def specific_keys
|
151
|
+
%w(
|
152
|
+
title
|
153
|
+
layout
|
154
|
+
)
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# Create new Multiplot object with the same set of plots and
|
159
|
+
# given options.
|
160
|
+
# Used in OptionHandling module.
|
161
|
+
def new_with_options(options)
|
162
|
+
self.class.new(@plots, options)
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Check if given options corresponds to multiplot.
|
167
|
+
# Uses #specific_keys to check.
|
168
|
+
def specific_option?(key)
|
169
|
+
specific_keys.include?(key.to_s)
|
170
|
+
end
|
171
|
+
|
172
|
+
##
|
173
|
+
# Takes all options and splits them into specific and
|
174
|
+
# others. Requires a block where this two classes should
|
175
|
+
# be mixed.
|
176
|
+
def mix_options(options)
|
177
|
+
all_options = @options.merge(options)
|
178
|
+
specific_options, plot_options = all_options.partition { |key, _value| specific_option?(key) }
|
179
|
+
yield(plot_options, default_options.merge(specific_options))
|
180
|
+
end
|
181
|
+
|
182
|
+
##
|
183
|
+
# Just a part of #plot.
|
184
|
+
def multiplot(terminal, options)
|
185
|
+
terminal.set(options)
|
186
|
+
@plots.each { |graph| graph.plot(terminal, multiplot_part: true) }
|
187
|
+
terminal.unset(options.keys)
|
188
|
+
end
|
149
189
|
end
|
150
190
|
end
|
data/lib/gnuplotrb/plot.rb
CHANGED
@@ -14,27 +14,21 @@ module GnuplotRB
|
|
14
14
|
# * *options* will be considered as 'settable' options of gnuplot
|
15
15
|
# ('set xrange [1:10]' for { xrange: 1..10 },
|
16
16
|
# "set title 'plot'" for { title: 'plot' } etc)
|
17
|
-
def initialize(*datasets
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
def initialize(*datasets)
|
18
|
+
# had to relace **options arg with this because in some cases
|
19
|
+
# Daru::DataFrame was mentioned as hash and added to options
|
20
|
+
# instead of plots
|
21
|
+
@options = Hamster.hash
|
22
|
+
if datasets[-1].is_a?(Hamster::Hash) || datasets[-1].is_a?(Hash)
|
23
|
+
@options = Hamster.hash(datasets[-1])
|
24
|
+
datasets = datasets[0..-2]
|
25
|
+
end
|
26
|
+
@datasets = parse_datasets_array(datasets)
|
25
27
|
@cmd = 'plot '
|
26
|
-
@terminal = Terminal.new
|
27
28
|
OptionHandling.validate_terminal_options(@options)
|
28
29
|
yield(self) if block_given?
|
29
30
|
end
|
30
31
|
|
31
|
-
##
|
32
|
-
# For inner use!
|
33
|
-
# Creates new Plot with existing data and given options.
|
34
|
-
def new_with_options(options)
|
35
|
-
self.class.new(@datasets, options)
|
36
|
-
end
|
37
|
-
|
38
32
|
##
|
39
33
|
# ====== Overview
|
40
34
|
# This outputs plot to term (if given) or to this plot's own terminal.
|
@@ -45,21 +39,23 @@ module GnuplotRB
|
|
45
39
|
# ('set xrange [1:10]', 'set title 'plot'' etc)
|
46
40
|
# Options passed here have priority over already existing.
|
47
41
|
def plot(term = nil, multiplot_part: false, **options)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
42
|
+
fail ArgumentError, 'Empty plots are not supported!' if @datasets.empty?
|
43
|
+
inner_opts = if multiplot_part
|
44
|
+
@options.merge(options).reject { |key, _| [:term, :output].include?(key) }
|
45
|
+
else
|
46
|
+
@options.merge(options)
|
47
|
+
end
|
48
|
+
terminal = term || (inner_opts[:output] ? Terminal.new : own_terminal)
|
49
|
+
ds_string = @datasets.map { |dataset| dataset.to_s(terminal) }.join(' , ')
|
50
|
+
full_command = @cmd + ds_string
|
51
|
+
terminal.set(inner_opts).stream_puts(full_command).unset(inner_opts.keys)
|
52
|
+
if inner_opts[:output]
|
56
53
|
# guaranteed wait for plotting to finish
|
57
54
|
terminal.close unless term
|
58
55
|
# not guaranteed wait for plotting to finish
|
59
56
|
# work bad with terminals like svg and html
|
60
|
-
sleep 0.01 until File.size?(
|
57
|
+
sleep 0.01 until File.size?(inner_opts[:output])
|
61
58
|
end
|
62
|
-
@already_plotted = true
|
63
59
|
self
|
64
60
|
end
|
65
61
|
|
@@ -101,20 +97,25 @@ module GnuplotRB
|
|
101
97
|
|
102
98
|
##
|
103
99
|
# ====== Overview
|
104
|
-
# Create new Plot object where given
|
105
|
-
# be
|
100
|
+
# Create new Plot object where given datasets will
|
101
|
+
# be inserted into dataset list before given position
|
102
|
+
# (position = 0 by default).
|
106
103
|
# ====== Arguments
|
107
|
-
# * *
|
104
|
+
# * *position* - position where to insert given datasets
|
105
|
+
# * *datasets* - sequence of datasets to add
|
108
106
|
# ====== Example
|
109
107
|
# sinx = Plot.new('sin(x)')
|
110
|
-
#
|
108
|
+
# sinx_and_cosx_with_expx = sinx.add(['cos(x)'], ['exp(x)'])
|
111
109
|
#
|
112
110
|
# cosx_and_sinx = sinx << ['cos(x)']
|
113
|
-
def
|
114
|
-
|
111
|
+
def add_datasets(*datasets)
|
112
|
+
datasets.map! { |ds| ds.is_a?(Numeric) ? ds : dataset_from_any(ds) }
|
113
|
+
datasets.unshift(0) unless datasets[0].is_a?(Numeric)
|
114
|
+
self.class.new(@datasets.insert(*datasets), @options)
|
115
115
|
end
|
116
116
|
|
117
|
-
alias_method
|
117
|
+
alias_method :add_dataset, :add_datasets
|
118
|
+
alias_method :<<, :add_datasets
|
118
119
|
|
119
120
|
##
|
120
121
|
# ====== Overview
|
@@ -138,15 +139,58 @@ module GnuplotRB
|
|
138
139
|
@datasets[*args]
|
139
140
|
end
|
140
141
|
|
142
|
+
private
|
143
|
+
|
144
|
+
##
|
145
|
+
# Checks several conditions and set options needed
|
146
|
+
# to handle DateTime indexes properly.
|
147
|
+
def provide_with_datetime_format(data, using)
|
148
|
+
return unless defined?(Daru)
|
149
|
+
return unless data.is_a?(Daru::DataFrame) || data.is_a?(Daru::Vector)
|
150
|
+
return unless data.index.first.is_a?(DateTime)
|
151
|
+
return if using[0..1] != '1:'
|
152
|
+
@options = @options.merge(
|
153
|
+
xdata: 'time',
|
154
|
+
timefmt: '%Y-%m-%dT%H:%M:%S',
|
155
|
+
format_x: '%d\n%b\n%Y'
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
141
159
|
##
|
142
|
-
# Method for inner use.
|
143
160
|
# Check if given args is a dataset and returns it. Creates
|
144
161
|
# new dataset from given args otherwise.
|
145
162
|
def dataset_from_any(source)
|
146
|
-
|
163
|
+
ds = case source
|
164
|
+
# when initialized with dataframe (it passes here several vectors)
|
165
|
+
when (defined?(Daru) ? Daru::Vector : nil)
|
166
|
+
Dataset.new(source)
|
167
|
+
when Dataset
|
168
|
+
source.clone
|
169
|
+
else
|
170
|
+
Dataset.new(*source)
|
171
|
+
end
|
172
|
+
data = source.is_a?(Array) ? source[0] : source
|
173
|
+
provide_with_datetime_format(data, ds.using)
|
174
|
+
ds
|
175
|
+
end
|
176
|
+
|
177
|
+
##
|
178
|
+
# Parses given array and returns Hamster::Vector of Datasets
|
179
|
+
def parse_datasets_array(datasets)
|
180
|
+
case datasets[0]
|
181
|
+
when Hamster::Vector
|
182
|
+
datasets[0]
|
183
|
+
when (defined?(Daru) ? Daru::DataFrame : nil)
|
184
|
+
Hamster::Vector.new(datasets[0].map { |ds| dataset_from_any(ds) })
|
185
|
+
else
|
186
|
+
Hamster::Vector.new(datasets.map { |ds| dataset_from_any(ds) })
|
187
|
+
end
|
147
188
|
end
|
148
189
|
|
149
|
-
|
150
|
-
|
190
|
+
##
|
191
|
+
# Creates new Plot with existing data and given options.
|
192
|
+
def new_with_options(options)
|
193
|
+
self.class.new(@datasets, options)
|
194
|
+
end
|
151
195
|
end
|
152
196
|
end
|