gnuplotrb 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +4 -4
- data/LICENSE +20 -20
- data/README.rdoc +163 -163
- data/Rakefile +16 -16
- data/gnuplotrb.gemspec +30 -30
- data/lib/gnuplotrb.rb +35 -35
- data/lib/gnuplotrb/animation.rb +129 -129
- data/lib/gnuplotrb/external_classes/array.rb +17 -17
- data/lib/gnuplotrb/external_classes/daru.rb +43 -43
- data/lib/gnuplotrb/external_classes/string.rb +6 -6
- data/lib/gnuplotrb/fit.rb +204 -204
- data/lib/gnuplotrb/mixins/error_handling.rb +48 -48
- data/lib/gnuplotrb/mixins/option_handling.rb +190 -190
- data/lib/gnuplotrb/mixins/plottable.rb +208 -208
- data/lib/gnuplotrb/multiplot.rb +269 -269
- data/lib/gnuplotrb/plot.rb +299 -299
- data/lib/gnuplotrb/splot.rb +18 -18
- data/lib/gnuplotrb/staff/datablock.rb +112 -112
- data/lib/gnuplotrb/staff/dataset.rb +294 -294
- data/lib/gnuplotrb/staff/settings.rb +89 -80
- data/lib/gnuplotrb/staff/terminal.rb +202 -202
- data/lib/gnuplotrb/version.rb +8 -8
- metadata +3 -4
data/lib/gnuplotrb/splot.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
|
-
module GnuplotRB
|
2
|
-
##
|
3
|
-
# Splot class correspond to simple 3D visualisation.
|
4
|
-
# Most of Plot's docs are right for Splot too.
|
5
|
-
#
|
6
|
-
# Examples of usage are in
|
7
|
-
# {a notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/3d_plot.ipynb]
|
8
|
-
class Splot < Plot
|
9
|
-
##
|
10
|
-
# @param *datasets [Sequence of Dataset or Array] either instances of Dataset class or
|
11
|
-
# "[data, **dataset_options]"" arrays
|
12
|
-
# @param options [Hash] see Plot top level doc for options examples
|
13
|
-
def initialize(*datasets, **options)
|
14
|
-
super
|
15
|
-
@cmd = 'splot '
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
1
|
+
module GnuplotRB
|
2
|
+
##
|
3
|
+
# Splot class correspond to simple 3D visualisation.
|
4
|
+
# Most of Plot's docs are right for Splot too.
|
5
|
+
#
|
6
|
+
# Examples of usage are in
|
7
|
+
# {a notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/3d_plot.ipynb]
|
8
|
+
class Splot < Plot
|
9
|
+
##
|
10
|
+
# @param *datasets [Sequence of Dataset or Array] either instances of Dataset class or
|
11
|
+
# "[data, **dataset_options]"" arrays
|
12
|
+
# @param options [Hash] see Plot top level doc for options examples
|
13
|
+
def initialize(*datasets, **options)
|
14
|
+
super
|
15
|
+
@cmd = 'splot '
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,112 +1,112 @@
|
|
1
|
-
module GnuplotRB
|
2
|
-
##
|
3
|
-
# This class corresponds to points we want to plot. It may be
|
4
|
-
# stored in temporary file (to allow fast update) or inside
|
5
|
-
# "$DATA << EOD ... EOD" construction. Datablock stores data passed
|
6
|
-
# to constructor and keeps datablock name or path to file where it is stored.
|
7
|
-
class Datablock
|
8
|
-
##
|
9
|
-
# @param data [#to_gnuplot_points] anything with #to_gnuplot_points method
|
10
|
-
# @param stored_in_file [Boolean] true here will force this datablock to store its data
|
11
|
-
# in temporary file.
|
12
|
-
def initialize(data, stored_in_file = false)
|
13
|
-
@stored_in_file = stored_in_file
|
14
|
-
data_str = data.to_gnuplot_points
|
15
|
-
if @stored_in_file
|
16
|
-
@file_name = Dir::Tmpname.make_tmpname('tmp_data', 0)
|
17
|
-
File.write(@file_name, data_str)
|
18
|
-
name = File.join(Dir.pwd, @file_name)
|
19
|
-
ObjectSpace.define_finalizer(self, proc { File.delete(name) })
|
20
|
-
else
|
21
|
-
@data = data_str
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
##
|
26
|
-
# Instantiate one more Datablock with updated data
|
27
|
-
# if data stored in here-doc. Append update to file
|
28
|
-
# if data stored there.
|
29
|
-
#
|
30
|
-
# @param data [#to_gnuplot_points] anything with #to_gnuplot_points method
|
31
|
-
# @return [Datablock] self if data stored in file (see constructor)
|
32
|
-
# @return [Datablock] new datablock with updated data otherwise
|
33
|
-
#
|
34
|
-
# @example
|
35
|
-
# data = [[0, 1, 2, 3], [0, 1, 4, 9]] # y = x**2
|
36
|
-
# db = Datablock.new(data, false)
|
37
|
-
# update = [[4, 5], [16, 25]]
|
38
|
-
# updated_db = db.update(update)
|
39
|
-
# # now db and updated_db contain DIFFERENT data
|
40
|
-
# # db - points with x from 0 up to 3
|
41
|
-
# # updated_db - points with x from 0 to 5
|
42
|
-
#
|
43
|
-
# @example
|
44
|
-
# data = [[0, 1, 2, 3], [0, 1, 4, 9]] # y = x**2
|
45
|
-
# db = Datablock.new(data, true)
|
46
|
-
# update = [[4, 5], [16, 25]]
|
47
|
-
# updated_db = db.update(update)
|
48
|
-
# # now db and updated_db contain THE SAME data
|
49
|
-
# # because they linked with the same temporary file
|
50
|
-
# # db - points with x from 0 up to 5
|
51
|
-
# # updated_db - points with x from 0 to 5
|
52
|
-
def update(data)
|
53
|
-
data_str = data.to_gnuplot_points
|
54
|
-
if @stored_in_file
|
55
|
-
File.open(@file_name, 'a') { |f| f.puts "\n#{data_str}" }
|
56
|
-
self
|
57
|
-
else
|
58
|
-
Datablock.new("#{@data}\n#{data_str}", false)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
##
|
63
|
-
# Update existing Datablock with new data.
|
64
|
-
# Destructive version of #update.
|
65
|
-
#
|
66
|
-
# @param data [#to_gnuplot_points] anything with #to_gnuplot_points method
|
67
|
-
# @return [Datablock] self
|
68
|
-
#
|
69
|
-
# @example
|
70
|
-
# data = [[0, 1, 2, 3], [0, 1, 4, 9]] # y = x**2
|
71
|
-
# db = Datablock.new(data, false)
|
72
|
-
# update = [[4, 5], [16, 25]]
|
73
|
-
# db.update!(update)
|
74
|
-
# # now db contains points with x from 0 up to 5
|
75
|
-
def update!(data)
|
76
|
-
data_str = data.to_gnuplot_points
|
77
|
-
if @stored_in_file
|
78
|
-
File.open(@file_name, 'a') { |f| f.puts "\n#{data_str}" }
|
79
|
-
else
|
80
|
-
@data = "#{@data}\n#{data_str}"
|
81
|
-
end
|
82
|
-
self
|
83
|
-
end
|
84
|
-
|
85
|
-
##
|
86
|
-
# Get quoted filename if datablock stored in file or output
|
87
|
-
# datablock to gnuplot and return its name otherwise.
|
88
|
-
#
|
89
|
-
# @param gnuplot_term [Terminal] should be given if datablock not stored in file
|
90
|
-
# @return [String] quoted filename if data stored in file (see contructor)
|
91
|
-
# @return [String] Gnuplot's datablock name otherwise
|
92
|
-
def name(gnuplot_term = nil)
|
93
|
-
if @stored_in_file
|
94
|
-
"'#{@file_name}'"
|
95
|
-
else
|
96
|
-
fail(ArgumentError, 'No terminal given to output datablock') unless gnuplot_term
|
97
|
-
gnuplot_term.store_datablock(@data)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
alias_method :to_s, :name
|
102
|
-
|
103
|
-
##
|
104
|
-
# Overridden #clone. Since datablock which store data
|
105
|
-
# in temporary files should not be cloned (otherwise it will cause
|
106
|
-
# double attempt to delete file), this #clone returns self for such
|
107
|
-
# cases. For other cases it just calls default #clone.
|
108
|
-
def clone
|
109
|
-
@stored_in_file ? self : super
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
1
|
+
module GnuplotRB
|
2
|
+
##
|
3
|
+
# This class corresponds to points we want to plot. It may be
|
4
|
+
# stored in temporary file (to allow fast update) or inside
|
5
|
+
# "$DATA << EOD ... EOD" construction. Datablock stores data passed
|
6
|
+
# to constructor and keeps datablock name or path to file where it is stored.
|
7
|
+
class Datablock
|
8
|
+
##
|
9
|
+
# @param data [#to_gnuplot_points] anything with #to_gnuplot_points method
|
10
|
+
# @param stored_in_file [Boolean] true here will force this datablock to store its data
|
11
|
+
# in temporary file.
|
12
|
+
def initialize(data, stored_in_file = false)
|
13
|
+
@stored_in_file = stored_in_file
|
14
|
+
data_str = data.to_gnuplot_points
|
15
|
+
if @stored_in_file
|
16
|
+
@file_name = Dir::Tmpname.make_tmpname('tmp_data', 0)
|
17
|
+
File.write(@file_name, data_str)
|
18
|
+
name = File.join(Dir.pwd, @file_name)
|
19
|
+
ObjectSpace.define_finalizer(self, proc { File.delete(name) })
|
20
|
+
else
|
21
|
+
@data = data_str
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Instantiate one more Datablock with updated data
|
27
|
+
# if data stored in here-doc. Append update to file
|
28
|
+
# if data stored there.
|
29
|
+
#
|
30
|
+
# @param data [#to_gnuplot_points] anything with #to_gnuplot_points method
|
31
|
+
# @return [Datablock] self if data stored in file (see constructor)
|
32
|
+
# @return [Datablock] new datablock with updated data otherwise
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# data = [[0, 1, 2, 3], [0, 1, 4, 9]] # y = x**2
|
36
|
+
# db = Datablock.new(data, false)
|
37
|
+
# update = [[4, 5], [16, 25]]
|
38
|
+
# updated_db = db.update(update)
|
39
|
+
# # now db and updated_db contain DIFFERENT data
|
40
|
+
# # db - points with x from 0 up to 3
|
41
|
+
# # updated_db - points with x from 0 to 5
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# data = [[0, 1, 2, 3], [0, 1, 4, 9]] # y = x**2
|
45
|
+
# db = Datablock.new(data, true)
|
46
|
+
# update = [[4, 5], [16, 25]]
|
47
|
+
# updated_db = db.update(update)
|
48
|
+
# # now db and updated_db contain THE SAME data
|
49
|
+
# # because they linked with the same temporary file
|
50
|
+
# # db - points with x from 0 up to 5
|
51
|
+
# # updated_db - points with x from 0 to 5
|
52
|
+
def update(data)
|
53
|
+
data_str = data.to_gnuplot_points
|
54
|
+
if @stored_in_file
|
55
|
+
File.open(@file_name, 'a') { |f| f.puts "\n#{data_str}" }
|
56
|
+
self
|
57
|
+
else
|
58
|
+
Datablock.new("#{@data}\n#{data_str}", false)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Update existing Datablock with new data.
|
64
|
+
# Destructive version of #update.
|
65
|
+
#
|
66
|
+
# @param data [#to_gnuplot_points] anything with #to_gnuplot_points method
|
67
|
+
# @return [Datablock] self
|
68
|
+
#
|
69
|
+
# @example
|
70
|
+
# data = [[0, 1, 2, 3], [0, 1, 4, 9]] # y = x**2
|
71
|
+
# db = Datablock.new(data, false)
|
72
|
+
# update = [[4, 5], [16, 25]]
|
73
|
+
# db.update!(update)
|
74
|
+
# # now db contains points with x from 0 up to 5
|
75
|
+
def update!(data)
|
76
|
+
data_str = data.to_gnuplot_points
|
77
|
+
if @stored_in_file
|
78
|
+
File.open(@file_name, 'a') { |f| f.puts "\n#{data_str}" }
|
79
|
+
else
|
80
|
+
@data = "#{@data}\n#{data_str}"
|
81
|
+
end
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Get quoted filename if datablock stored in file or output
|
87
|
+
# datablock to gnuplot and return its name otherwise.
|
88
|
+
#
|
89
|
+
# @param gnuplot_term [Terminal] should be given if datablock not stored in file
|
90
|
+
# @return [String] quoted filename if data stored in file (see contructor)
|
91
|
+
# @return [String] Gnuplot's datablock name otherwise
|
92
|
+
def name(gnuplot_term = nil)
|
93
|
+
if @stored_in_file
|
94
|
+
"'#{@file_name}'"
|
95
|
+
else
|
96
|
+
fail(ArgumentError, 'No terminal given to output datablock') unless gnuplot_term
|
97
|
+
gnuplot_term.store_datablock(@data)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
alias_method :to_s, :name
|
102
|
+
|
103
|
+
##
|
104
|
+
# Overridden #clone. Since datablock which store data
|
105
|
+
# in temporary files should not be cloned (otherwise it will cause
|
106
|
+
# double attempt to delete file), this #clone returns self for such
|
107
|
+
# cases. For other cases it just calls default #clone.
|
108
|
+
def clone
|
109
|
+
@stored_in_file ? self : super
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -1,294 +1,294 @@
|
|
1
|
-
module GnuplotRB
|
2
|
-
##
|
3
|
-
# Dataset keeps control of Datablock or String (some math functions like
|
4
|
-
# this 'x*sin(x)' or filename) and options related to original dataset
|
5
|
-
# in gnuplot (with, title, using etc).
|
6
|
-
#
|
7
|
-
# == Options
|
8
|
-
# Dataset options are explained in
|
9
|
-
# {gnuplot docs}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] (pp. 80-101).
|
10
|
-
# Several common options:
|
11
|
-
# * with - set plot style for dataset ('lines', 'points', 'impulses' etc)
|
12
|
-
# * using - choose which columns of input data gnuplot should use. Takes String
|
13
|
-
# (using: 'xtic(1):2:3'). If Daru::Dataframe passed one can use column names
|
14
|
-
# instead of numbers (using: 'index:value1:summ' - value1 and summ here are column names).
|
15
|
-
# * linewidth (lw) - integer line width
|
16
|
-
# * dashtype (dt) - takes pattern with dash style. Examples: '.. ', '-- ', '.- '.
|
17
|
-
# * pointtype (pt) - takes integer number of point type (works only when :with option is set to
|
18
|
-
# 'points'). One can call Terminal::test(term_name)
|
19
|
-
# or Terminal#test in order to see which point types are supported by terminal.
|
20
|
-
class Dataset
|
21
|
-
include Plottable
|
22
|
-
##
|
23
|
-
# Data represented by this dataset
|
24
|
-
attr_reader :data
|
25
|
-
|
26
|
-
##
|
27
|
-
# Order is significant for some options
|
28
|
-
OPTION_ORDER = %w(index using axes title)
|
29
|
-
|
30
|
-
private_constant :OPTION_ORDER
|
31
|
-
|
32
|
-
##
|
33
|
-
# Hash of init handlers for data given in
|
34
|
-
# different containers.
|
35
|
-
INIT_HANDLERS = Hash.new(:init_default).merge(
|
36
|
-
String => :init_string,
|
37
|
-
Datablock => :init_dblock
|
38
|
-
)
|
39
|
-
INIT_HANDLERS.merge!(
|
40
|
-
Daru::DataFrame => :init_daru_frame,
|
41
|
-
Daru::Vector => :init_daru_vector
|
42
|
-
) if defined? Daru
|
43
|
-
|
44
|
-
##
|
45
|
-
# Create new dataset out of given string with math function or filename.
|
46
|
-
# If *data* isn't a string it will create datablock to store data.
|
47
|
-
#
|
48
|
-
# @param data [String, Datablock, #to_gnuplot_points] String, Datablock or something acceptable
|
49
|
-
# by Datablock.new as data (e.g. [x,y] where x and y are arrays)
|
50
|
-
# @param options [Hash] options specific for gnuplot
|
51
|
-
# dataset (see Dataset top level doc), and some special options ('file: true' will
|
52
|
-
# make data to be stored inside temporary file)
|
53
|
-
#
|
54
|
-
# @example Math function:
|
55
|
-
# Dataset.new('x*sin(x)', with: 'lines', lw: 4)
|
56
|
-
# @example File with points:
|
57
|
-
# Dataset.new('points.data', with: 'lines', title: 'Points from file')
|
58
|
-
# @example Some data (creates datablock stored in memory):
|
59
|
-
# x = (0..5000).to_a
|
60
|
-
# y = x.map {|xx| xx*xx }
|
61
|
-
# points = [x, y]
|
62
|
-
# Dataset.new(points, with: 'points', title: 'Points')
|
63
|
-
# @example The same data but datablock stores it in temp file:
|
64
|
-
# Dataset.new(points, with: 'points', title: 'Points', file: true)
|
65
|
-
def initialize(data, **options)
|
66
|
-
# run method by name
|
67
|
-
send(INIT_HANDLERS[data.class], data, options)
|
68
|
-
end
|
69
|
-
|
70
|
-
##
|
71
|
-
# Convert Dataset to string containing gnuplot dataset.
|
72
|
-
#
|
73
|
-
# @param terminal [Terminal] must be given if data given as Datablock and
|
74
|
-
# it does not use temp file so data should be piped out
|
75
|
-
# to gnuplot via terminal before use
|
76
|
-
# @param :without_options [Boolean] do not add options to dataset if set
|
77
|
-
# to true. Used by Fit::fit
|
78
|
-
# @return [String] gnuplot dataset
|
79
|
-
# @example
|
80
|
-
# Dataset.new('points.data', with: 'lines', title: 'Points from file').to_s
|
81
|
-
# #=> "'points.data' with lines title 'Points from file'"
|
82
|
-
# Dataset.new(points, with: 'points', title: 'Points').to_s
|
83
|
-
# #=> "$DATA1 with points title 'Points'"
|
84
|
-
def to_s(terminal = nil, without_options: false)
|
85
|
-
result = "#{@type == :datablock ? @data.name(terminal) : @data} "
|
86
|
-
result += options_to_string unless without_options
|
87
|
-
result
|
88
|
-
end
|
89
|
-
|
90
|
-
##
|
91
|
-
# Create new dataset with updated data and merged options.
|
92
|
-
#
|
93
|
-
# Given data is appended to existing.
|
94
|
-
# Data is updated only if Dataset stores it in Datablock.
|
95
|
-
# Method does nothing if no options given and data isn't stored
|
96
|
-
# in in-memory Datablock.
|
97
|
-
#
|
98
|
-
# @param data [#to_gnuplot_points] data to append to existing
|
99
|
-
# @param options [Hash] new options to merge with existing options
|
100
|
-
# @return self if dataset corresponds to math formula or file
|
101
|
-
# (filename or temporary file if datablock)
|
102
|
-
# @return [Dataset] new dataset if data is stored in 'in-memory' Datablock
|
103
|
-
# @example Updating dataset with Math formula or filename given:
|
104
|
-
# dataset = Dataset.new('file.data')
|
105
|
-
# dataset.update(data: 'asd')
|
106
|
-
# #=> nothing updated
|
107
|
-
# dataset.update(data: 'asd', title: 'File')
|
108
|
-
# #=> Dataset.new('file.data', title: 'File')
|
109
|
-
# @example Updating dataset with data stored in Datablock (in-memory):
|
110
|
-
# in_memory_points = Dataset.new(points, title: 'Old one')
|
111
|
-
# in_memory_points.update(data: some_update, title: 'Updated')
|
112
|
-
# #=> Dataset.new(points + some_update, title: 'Updated')
|
113
|
-
# @example Updating dataset with data stored in Datablock (in-file):
|
114
|
-
# temp_file_points = Dataset.new(points, title: 'Old one', file: true)
|
115
|
-
# temp_file_points.update(data: some_update)
|
116
|
-
# #=> data updated but no new dataset created
|
117
|
-
# temp_file_points.update(data: some_update, title: 'Updated')
|
118
|
-
# #=> data updated and new dataset with title 'Updated' returned
|
119
|
-
def update(data = nil, **options)
|
120
|
-
if data && @type == :datablock
|
121
|
-
new_datablock = @data.update(data)
|
122
|
-
if new_datablock == @data
|
123
|
-
update_options(options)
|
124
|
-
else
|
125
|
-
self.class.new(new_datablock, options)
|
126
|
-
end
|
127
|
-
else
|
128
|
-
update_options(options)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
##
|
133
|
-
# Update Dataset with new data and options.
|
134
|
-
#
|
135
|
-
# Given data is appended to existing.
|
136
|
-
# Data is updated only if Dataset stores it in Datablock.
|
137
|
-
# Method does nothing if no options given and data isn't stored
|
138
|
-
# in in-memory Datablock.
|
139
|
-
#
|
140
|
-
# @param data [#to_gnuplot_points] data to append to existing
|
141
|
-
# @param options [Hash] new options to merge with existing options
|
142
|
-
# @return self
|
143
|
-
# @example Updating dataset with Math formula or filename given:
|
144
|
-
# dataset = Dataset.new('file.data')
|
145
|
-
# dataset.update!(data: 'asd')
|
146
|
-
# #=> nothing updated
|
147
|
-
# dataset.update!(data: 'asd', title: 'File')
|
148
|
-
# dataset.title
|
149
|
-
# #=> 'File' # data isn't updated
|
150
|
-
# @example Updating dataset with data stored in Datablock (in-memory):
|
151
|
-
# in_memory_points = Dataset.new(points, title: 'Old one')
|
152
|
-
# in_memory_points.update!(data: some_update, title: 'Updated')
|
153
|
-
# in_memory_points.data
|
154
|
-
# #=> points + some_update
|
155
|
-
# in_memory_points.title
|
156
|
-
# #=> 'Updated'
|
157
|
-
# @example Updating dataset with data stored in Datablock (in-file):
|
158
|
-
# temp_file_points = Dataset.new(points, title: 'Old one', file: true)
|
159
|
-
# temp_file_points.update!(data: some_update)
|
160
|
-
# #=> data updated but no new dataset created
|
161
|
-
# temp_file_points.update!(data: some_update, title: 'Updated')
|
162
|
-
# #=> data and options updated
|
163
|
-
def update!(data = nil, **options)
|
164
|
-
@data.update!(data) if data
|
165
|
-
options!(options)
|
166
|
-
self
|
167
|
-
end
|
168
|
-
|
169
|
-
##
|
170
|
-
# Own implementation of #clone. Creates new Dataset if
|
171
|
-
# data stored in datablock and calls super otherwise.
|
172
|
-
def clone
|
173
|
-
if @type == :datablock
|
174
|
-
new_with_options(@options)
|
175
|
-
else
|
176
|
-
super
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
##
|
181
|
-
# Create new Plot object with only one Dataset given - self.
|
182
|
-
# Calls #plot on created Plot. All arguments given to this #plot
|
183
|
-
# will be sent to Plot#plot instead.
|
184
|
-
# @param args sequence of arguments all of which will be passed to Plot#plot,
|
185
|
-
# see docs there
|
186
|
-
# @return [Plot] new Plot object with only one Dataset - self
|
187
|
-
# @example
|
188
|
-
# sin = Dataset.new('sin(x)')
|
189
|
-
# sin.plot(term: [qt, size: [300, 300]])
|
190
|
-
# #=> shows qt window 300x300 with sin(x)
|
191
|
-
# sin.to_png('./plot.png')
|
192
|
-
# #=> creates png file with sin(x) plotted
|
193
|
-
def plot(*args)
|
194
|
-
Plot.new(self).plot(*args)
|
195
|
-
end
|
196
|
-
|
197
|
-
private
|
198
|
-
|
199
|
-
##
|
200
|
-
# Create new dataset with existing options merged with
|
201
|
-
# the given ones. Does nothing if no options given.
|
202
|
-
#
|
203
|
-
# @param options [Hash] new options to merge with existing options
|
204
|
-
# @return [Dataset] self if options empty
|
205
|
-
# @return [Dataset] new Dataset with updated options otherwise
|
206
|
-
# @example Updating dataset with Math formula or filename given:
|
207
|
-
# dataset = Dataset.new('file.data')
|
208
|
-
# dataset.update_options(title: 'File')
|
209
|
-
# #=> Dataset.new('file.data', title: 'File')
|
210
|
-
def update_options(**options)
|
211
|
-
if options.empty?
|
212
|
-
self
|
213
|
-
else
|
214
|
-
new_with_options(@options.merge(options))
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
##
|
219
|
-
# Create string from own options
|
220
|
-
# @return [String] options converted to Gnuplot format
|
221
|
-
def options_to_string
|
222
|
-
options.sort_by { |key, _| OPTION_ORDER.find_index(key.to_s) || 999 }
|
223
|
-
.map { |key, value| OptionHandling.option_to_string(key, value) }
|
224
|
-
.join(' ')
|
225
|
-
end
|
226
|
-
|
227
|
-
##
|
228
|
-
# Needed by OptionHandling to create new object when options are changed.
|
229
|
-
def new_with_options(options)
|
230
|
-
self.class.new(@data, options)
|
231
|
-
end
|
232
|
-
|
233
|
-
##
|
234
|
-
# Initialize Dataset from given String
|
235
|
-
def init_string(data, options)
|
236
|
-
@type, @data = File.exist?(data) ? [:datafile, "'#{data}'"] : [:math_function, data.clone]
|
237
|
-
@options = Hamster.hash(options)
|
238
|
-
end
|
239
|
-
|
240
|
-
##
|
241
|
-
# Initialize Dataset from given Datablock
|
242
|
-
def init_dblock(data, options)
|
243
|
-
@type = :datablock
|
244
|
-
@data = data.clone
|
245
|
-
@options = Hamster.hash(options)
|
246
|
-
end
|
247
|
-
|
248
|
-
##
|
249
|
-
# Create new value for 'using' option based on column count
|
250
|
-
def get_daru_columns(data, cnt)
|
251
|
-
new_opt = (2..cnt).to_a.join(':')
|
252
|
-
if data.index
|
253
|
-
"1:#{new_opt}"
|
254
|
-
else
|
255
|
-
"#{new_opt}:xtic(1)"
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
##
|
260
|
-
# Initialize Dataset from given Daru::DataFrame
|
261
|
-
def init_daru_frame(data, options)
|
262
|
-
options[:title] ||= data.name
|
263
|
-
if options[:using]
|
264
|
-
options[:using] = " #{options[:using]} "
|
265
|
-
data.vectors.to_a.each_with_index do |daru_index, array_index|
|
266
|
-
options[:using].gsub!(/([\:\(\$ ])#{daru_index}([\:\) ])/) do
|
267
|
-
"#{Regexp.last_match(1)}#{array_index + 2}#{Regexp.last_match(2)}"
|
268
|
-
end
|
269
|
-
end
|
270
|
-
options[:using].gsub!('index', '1')
|
271
|
-
options[:using].strip!
|
272
|
-
else
|
273
|
-
options[:using] = get_daru_columns(data, data.vectors.size + 1)
|
274
|
-
end
|
275
|
-
init_default(data, options)
|
276
|
-
end
|
277
|
-
|
278
|
-
##
|
279
|
-
# Initialize Dataset from given Daru::Vector
|
280
|
-
def init_daru_vector(data, options)
|
281
|
-
options[:using] ||= get_daru_columns(data, 2)
|
282
|
-
options[:title] ||= data.name
|
283
|
-
init_default(data, options)
|
284
|
-
end
|
285
|
-
|
286
|
-
##
|
287
|
-
# Initialize Dataset from given data with #to_gnuplot_points method
|
288
|
-
def init_default(data, file: false, **options)
|
289
|
-
@type = :datablock
|
290
|
-
@data = Datablock.new(data, file)
|
291
|
-
@options = Hamster.hash(options)
|
292
|
-
end
|
293
|
-
end
|
294
|
-
end
|
1
|
+
module GnuplotRB
|
2
|
+
##
|
3
|
+
# Dataset keeps control of Datablock or String (some math functions like
|
4
|
+
# this 'x*sin(x)' or filename) and options related to original dataset
|
5
|
+
# in gnuplot (with, title, using etc).
|
6
|
+
#
|
7
|
+
# == Options
|
8
|
+
# Dataset options are explained in
|
9
|
+
# {gnuplot docs}[http://www.gnuplot.info/docs_5.0/gnuplot.pdf] (pp. 80-101).
|
10
|
+
# Several common options:
|
11
|
+
# * with - set plot style for dataset ('lines', 'points', 'impulses' etc)
|
12
|
+
# * using - choose which columns of input data gnuplot should use. Takes String
|
13
|
+
# (using: 'xtic(1):2:3'). If Daru::Dataframe passed one can use column names
|
14
|
+
# instead of numbers (using: 'index:value1:summ' - value1 and summ here are column names).
|
15
|
+
# * linewidth (lw) - integer line width
|
16
|
+
# * dashtype (dt) - takes pattern with dash style. Examples: '.. ', '-- ', '.- '.
|
17
|
+
# * pointtype (pt) - takes integer number of point type (works only when :with option is set to
|
18
|
+
# 'points'). One can call Terminal::test(term_name)
|
19
|
+
# or Terminal#test in order to see which point types are supported by terminal.
|
20
|
+
class Dataset
|
21
|
+
include Plottable
|
22
|
+
##
|
23
|
+
# Data represented by this dataset
|
24
|
+
attr_reader :data
|
25
|
+
|
26
|
+
##
|
27
|
+
# Order is significant for some options
|
28
|
+
OPTION_ORDER = %w(index using axes title)
|
29
|
+
|
30
|
+
private_constant :OPTION_ORDER
|
31
|
+
|
32
|
+
##
|
33
|
+
# Hash of init handlers for data given in
|
34
|
+
# different containers.
|
35
|
+
INIT_HANDLERS = Hash.new(:init_default).merge(
|
36
|
+
String => :init_string,
|
37
|
+
Datablock => :init_dblock
|
38
|
+
)
|
39
|
+
INIT_HANDLERS.merge!(
|
40
|
+
Daru::DataFrame => :init_daru_frame,
|
41
|
+
Daru::Vector => :init_daru_vector
|
42
|
+
) if defined? Daru
|
43
|
+
|
44
|
+
##
|
45
|
+
# Create new dataset out of given string with math function or filename.
|
46
|
+
# If *data* isn't a string it will create datablock to store data.
|
47
|
+
#
|
48
|
+
# @param data [String, Datablock, #to_gnuplot_points] String, Datablock or something acceptable
|
49
|
+
# by Datablock.new as data (e.g. [x,y] where x and y are arrays)
|
50
|
+
# @param options [Hash] options specific for gnuplot
|
51
|
+
# dataset (see Dataset top level doc), and some special options ('file: true' will
|
52
|
+
# make data to be stored inside temporary file)
|
53
|
+
#
|
54
|
+
# @example Math function:
|
55
|
+
# Dataset.new('x*sin(x)', with: 'lines', lw: 4)
|
56
|
+
# @example File with points:
|
57
|
+
# Dataset.new('points.data', with: 'lines', title: 'Points from file')
|
58
|
+
# @example Some data (creates datablock stored in memory):
|
59
|
+
# x = (0..5000).to_a
|
60
|
+
# y = x.map {|xx| xx*xx }
|
61
|
+
# points = [x, y]
|
62
|
+
# Dataset.new(points, with: 'points', title: 'Points')
|
63
|
+
# @example The same data but datablock stores it in temp file:
|
64
|
+
# Dataset.new(points, with: 'points', title: 'Points', file: true)
|
65
|
+
def initialize(data, **options)
|
66
|
+
# run method by name
|
67
|
+
send(INIT_HANDLERS[data.class], data, options)
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Convert Dataset to string containing gnuplot dataset.
|
72
|
+
#
|
73
|
+
# @param terminal [Terminal] must be given if data given as Datablock and
|
74
|
+
# it does not use temp file so data should be piped out
|
75
|
+
# to gnuplot via terminal before use
|
76
|
+
# @param :without_options [Boolean] do not add options to dataset if set
|
77
|
+
# to true. Used by Fit::fit
|
78
|
+
# @return [String] gnuplot dataset
|
79
|
+
# @example
|
80
|
+
# Dataset.new('points.data', with: 'lines', title: 'Points from file').to_s
|
81
|
+
# #=> "'points.data' with lines title 'Points from file'"
|
82
|
+
# Dataset.new(points, with: 'points', title: 'Points').to_s
|
83
|
+
# #=> "$DATA1 with points title 'Points'"
|
84
|
+
def to_s(terminal = nil, without_options: false)
|
85
|
+
result = "#{@type == :datablock ? @data.name(terminal) : @data} "
|
86
|
+
result += options_to_string unless without_options
|
87
|
+
result
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# Create new dataset with updated data and merged options.
|
92
|
+
#
|
93
|
+
# Given data is appended to existing.
|
94
|
+
# Data is updated only if Dataset stores it in Datablock.
|
95
|
+
# Method does nothing if no options given and data isn't stored
|
96
|
+
# in in-memory Datablock.
|
97
|
+
#
|
98
|
+
# @param data [#to_gnuplot_points] data to append to existing
|
99
|
+
# @param options [Hash] new options to merge with existing options
|
100
|
+
# @return self if dataset corresponds to math formula or file
|
101
|
+
# (filename or temporary file if datablock)
|
102
|
+
# @return [Dataset] new dataset if data is stored in 'in-memory' Datablock
|
103
|
+
# @example Updating dataset with Math formula or filename given:
|
104
|
+
# dataset = Dataset.new('file.data')
|
105
|
+
# dataset.update(data: 'asd')
|
106
|
+
# #=> nothing updated
|
107
|
+
# dataset.update(data: 'asd', title: 'File')
|
108
|
+
# #=> Dataset.new('file.data', title: 'File')
|
109
|
+
# @example Updating dataset with data stored in Datablock (in-memory):
|
110
|
+
# in_memory_points = Dataset.new(points, title: 'Old one')
|
111
|
+
# in_memory_points.update(data: some_update, title: 'Updated')
|
112
|
+
# #=> Dataset.new(points + some_update, title: 'Updated')
|
113
|
+
# @example Updating dataset with data stored in Datablock (in-file):
|
114
|
+
# temp_file_points = Dataset.new(points, title: 'Old one', file: true)
|
115
|
+
# temp_file_points.update(data: some_update)
|
116
|
+
# #=> data updated but no new dataset created
|
117
|
+
# temp_file_points.update(data: some_update, title: 'Updated')
|
118
|
+
# #=> data updated and new dataset with title 'Updated' returned
|
119
|
+
def update(data = nil, **options)
|
120
|
+
if data && @type == :datablock
|
121
|
+
new_datablock = @data.update(data)
|
122
|
+
if new_datablock == @data
|
123
|
+
update_options(options)
|
124
|
+
else
|
125
|
+
self.class.new(new_datablock, options)
|
126
|
+
end
|
127
|
+
else
|
128
|
+
update_options(options)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# Update Dataset with new data and options.
|
134
|
+
#
|
135
|
+
# Given data is appended to existing.
|
136
|
+
# Data is updated only if Dataset stores it in Datablock.
|
137
|
+
# Method does nothing if no options given and data isn't stored
|
138
|
+
# in in-memory Datablock.
|
139
|
+
#
|
140
|
+
# @param data [#to_gnuplot_points] data to append to existing
|
141
|
+
# @param options [Hash] new options to merge with existing options
|
142
|
+
# @return self
|
143
|
+
# @example Updating dataset with Math formula or filename given:
|
144
|
+
# dataset = Dataset.new('file.data')
|
145
|
+
# dataset.update!(data: 'asd')
|
146
|
+
# #=> nothing updated
|
147
|
+
# dataset.update!(data: 'asd', title: 'File')
|
148
|
+
# dataset.title
|
149
|
+
# #=> 'File' # data isn't updated
|
150
|
+
# @example Updating dataset with data stored in Datablock (in-memory):
|
151
|
+
# in_memory_points = Dataset.new(points, title: 'Old one')
|
152
|
+
# in_memory_points.update!(data: some_update, title: 'Updated')
|
153
|
+
# in_memory_points.data
|
154
|
+
# #=> points + some_update
|
155
|
+
# in_memory_points.title
|
156
|
+
# #=> 'Updated'
|
157
|
+
# @example Updating dataset with data stored in Datablock (in-file):
|
158
|
+
# temp_file_points = Dataset.new(points, title: 'Old one', file: true)
|
159
|
+
# temp_file_points.update!(data: some_update)
|
160
|
+
# #=> data updated but no new dataset created
|
161
|
+
# temp_file_points.update!(data: some_update, title: 'Updated')
|
162
|
+
# #=> data and options updated
|
163
|
+
def update!(data = nil, **options)
|
164
|
+
@data.update!(data) if data
|
165
|
+
options!(options)
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Own implementation of #clone. Creates new Dataset if
|
171
|
+
# data stored in datablock and calls super otherwise.
|
172
|
+
def clone
|
173
|
+
if @type == :datablock
|
174
|
+
new_with_options(@options)
|
175
|
+
else
|
176
|
+
super
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Create new Plot object with only one Dataset given - self.
|
182
|
+
# Calls #plot on created Plot. All arguments given to this #plot
|
183
|
+
# will be sent to Plot#plot instead.
|
184
|
+
# @param args sequence of arguments all of which will be passed to Plot#plot,
|
185
|
+
# see docs there
|
186
|
+
# @return [Plot] new Plot object with only one Dataset - self
|
187
|
+
# @example
|
188
|
+
# sin = Dataset.new('sin(x)')
|
189
|
+
# sin.plot(term: [qt, size: [300, 300]])
|
190
|
+
# #=> shows qt window 300x300 with sin(x)
|
191
|
+
# sin.to_png('./plot.png')
|
192
|
+
# #=> creates png file with sin(x) plotted
|
193
|
+
def plot(*args)
|
194
|
+
Plot.new(self).plot(*args)
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
##
|
200
|
+
# Create new dataset with existing options merged with
|
201
|
+
# the given ones. Does nothing if no options given.
|
202
|
+
#
|
203
|
+
# @param options [Hash] new options to merge with existing options
|
204
|
+
# @return [Dataset] self if options empty
|
205
|
+
# @return [Dataset] new Dataset with updated options otherwise
|
206
|
+
# @example Updating dataset with Math formula or filename given:
|
207
|
+
# dataset = Dataset.new('file.data')
|
208
|
+
# dataset.update_options(title: 'File')
|
209
|
+
# #=> Dataset.new('file.data', title: 'File')
|
210
|
+
def update_options(**options)
|
211
|
+
if options.empty?
|
212
|
+
self
|
213
|
+
else
|
214
|
+
new_with_options(@options.merge(options))
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
##
|
219
|
+
# Create string from own options
|
220
|
+
# @return [String] options converted to Gnuplot format
|
221
|
+
def options_to_string
|
222
|
+
options.sort_by { |key, _| OPTION_ORDER.find_index(key.to_s) || 999 }
|
223
|
+
.map { |key, value| OptionHandling.option_to_string(key, value) }
|
224
|
+
.join(' ')
|
225
|
+
end
|
226
|
+
|
227
|
+
##
|
228
|
+
# Needed by OptionHandling to create new object when options are changed.
|
229
|
+
def new_with_options(options)
|
230
|
+
self.class.new(@data, options)
|
231
|
+
end
|
232
|
+
|
233
|
+
##
|
234
|
+
# Initialize Dataset from given String
|
235
|
+
def init_string(data, options)
|
236
|
+
@type, @data = File.exist?(data) ? [:datafile, "'#{data}'"] : [:math_function, data.clone]
|
237
|
+
@options = Hamster.hash(options)
|
238
|
+
end
|
239
|
+
|
240
|
+
##
|
241
|
+
# Initialize Dataset from given Datablock
|
242
|
+
def init_dblock(data, options)
|
243
|
+
@type = :datablock
|
244
|
+
@data = data.clone
|
245
|
+
@options = Hamster.hash(options)
|
246
|
+
end
|
247
|
+
|
248
|
+
##
|
249
|
+
# Create new value for 'using' option based on column count
|
250
|
+
def get_daru_columns(data, cnt)
|
251
|
+
new_opt = (2..cnt).to_a.join(':')
|
252
|
+
if data.index.key(0).is_a?(DateTime) || data.index.key(0).is_a?(Numeric)
|
253
|
+
"1:#{new_opt}"
|
254
|
+
else
|
255
|
+
"#{new_opt}:xtic(1)"
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
##
|
260
|
+
# Initialize Dataset from given Daru::DataFrame
|
261
|
+
def init_daru_frame(data, options)
|
262
|
+
options[:title] ||= data.name
|
263
|
+
if options[:using]
|
264
|
+
options[:using] = " #{options[:using]} "
|
265
|
+
data.vectors.to_a.each_with_index do |daru_index, array_index|
|
266
|
+
options[:using].gsub!(/([\:\(\$ ])#{daru_index}([\:\) ])/) do
|
267
|
+
"#{Regexp.last_match(1)}#{array_index + 2}#{Regexp.last_match(2)}"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
options[:using].gsub!('index', '1')
|
271
|
+
options[:using].strip!
|
272
|
+
else
|
273
|
+
options[:using] = get_daru_columns(data, data.vectors.size + 1)
|
274
|
+
end
|
275
|
+
init_default(data, options)
|
276
|
+
end
|
277
|
+
|
278
|
+
##
|
279
|
+
# Initialize Dataset from given Daru::Vector
|
280
|
+
def init_daru_vector(data, options)
|
281
|
+
options[:using] ||= get_daru_columns(data, 2)
|
282
|
+
options[:title] ||= data.name
|
283
|
+
init_default(data, options)
|
284
|
+
end
|
285
|
+
|
286
|
+
##
|
287
|
+
# Initialize Dataset from given data with #to_gnuplot_points method
|
288
|
+
def init_default(data, file: false, **options)
|
289
|
+
@type = :datablock
|
290
|
+
@data = Datablock.new(data, file)
|
291
|
+
@options = Hamster.hash(options)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|