gnuplotrb 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,65 @@
1
+ module GnuplotRB
2
+ ##
3
+ # This module takes care of path to gnuplot executable
4
+ # and checking its version.
5
+ module Settings
6
+ ##
7
+ # Since gem uses some modern gnuplot features it's
8
+ # required to have modern gnuplot installed.
9
+ MIN_GNUPLOT_VERSION = 5.0
10
+ ##
11
+ # ====== Overview
12
+ # Get path that should be used to run gnuplot executable.
13
+ # Default value: 'gnuplot'
14
+ def self.gnuplot_path
15
+ self.gnuplot_path = 'gnuplot' unless defined?(@gnuplot_path)
16
+ @gnuplot_path
17
+ end
18
+
19
+ ##
20
+ # ====== Overview
21
+ # Set path to gnuplot executable.
22
+ def self.gnuplot_path=(path)
23
+ validate_version(path)
24
+ opts = { stdin_data: "set term\n" }
25
+ @available_terminals = Open3.capture2e(path, **opts)
26
+ .first
27
+ .scan(/[:\n] +([a-z][^ ]+)/)
28
+ .map(&:first)
29
+ @gnuplot_path = path
30
+ end
31
+
32
+ ##
33
+ # ====== Overview
34
+ # Get list of terminals (png, html, qt, jpeg etc)
35
+ # available for that gnuplot.
36
+ def self.available_terminals
37
+ gnuplot_path
38
+ @available_terminals
39
+ end
40
+
41
+ ##
42
+ # ====== Overview
43
+ # Get gnuplot version. Uses gnuplot_path to find
44
+ # gnuplot executable.
45
+ def self.version
46
+ gnuplot_path
47
+ @version
48
+ end
49
+
50
+ ##
51
+ # ====== Overview
52
+ # Validates gnuplot version. Compares current gnuplot's
53
+ # version with ::MIN_GNUPLOT_VERSION.
54
+ # ====== Arguments
55
+ # * *path* - path to gnuplot executable.
56
+ def self.validate_version(path)
57
+ @version = IO.popen("#{path} --version")
58
+ .read
59
+ .match(/gnuplot ([^ ]+)/)[1]
60
+ .to_f
61
+ message = "Your Gnuplot version is #{@version}, please update it to at least 5.0"
62
+ fail(ArgumentError, message) if @version < MIN_GNUPLOT_VERSION
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,171 @@
1
+ module GnuplotRB
2
+ ##
3
+ # === Overview
4
+ # Terminal keeps open pipe to gnuplot process, cares about naming in-memory
5
+ # datablocks (just indexing with sequential integers). All the output
6
+ # to gnuplot handled by this class. Terminal also handles options passed
7
+ # to gnuplot as 'set key value'.
8
+ class Terminal
9
+ include ErrorHandling
10
+ OPTION_ORDER = [:term, :output, :multiplot]
11
+
12
+ class << self
13
+ ##
14
+ # Close given gnuplot pipe
15
+ def close_arg(stream)
16
+ stream.puts
17
+ stream.puts 'exit'
18
+ Process.waitpid(stream.pid)
19
+ end
20
+ end
21
+
22
+ ##
23
+ # ====== Overview
24
+ # Creates new Terminal connected with gnuplot.
25
+ # Uses Settings::gnuplot_path to find gnuplot
26
+ # executable. Each time you create Terminal it starts new
27
+ # gnuplot subprocess which is closed after GC deletes
28
+ # linked Terminal object.
29
+ # ====== Arguments
30
+ # * *persist* - gnuplot's -persist option
31
+ def initialize(persist: false)
32
+ @cmd = Settings.gnuplot_path
33
+ @current_datablock = 0
34
+ @cmd += ' -persist' if persist
35
+ @cmd += ' 2>&1'
36
+ stream = IO.popen(@cmd, 'w+')
37
+ handle_stderr(stream)
38
+ ObjectSpace.define_finalizer(self, proc { Terminal::close_arg(stream) } )
39
+ @in = stream
40
+ yield(self) if block_given?
41
+ end
42
+
43
+ ##
44
+ # ====== Overview
45
+ # Outputs datablock to this gnuplot terminal.
46
+ # ====== Arguments
47
+ # * *data* - data stored in datablock
48
+ # ====== Examples
49
+ # data = "1 1\n2 4\n3 9"
50
+ # Terminal.new.store_datablock(data)
51
+ # #=> returns '$DATA1'
52
+ # #=> outputs to gnuplot:
53
+ # #=> $DATA1 << EOD
54
+ # #=> 1 1
55
+ # #=> 2 4
56
+ # #=> 3 9
57
+ # #=> EOD
58
+ def store_datablock(data)
59
+ name = "$DATA#{@current_datablock += 1}"
60
+ self.puts "#{name} << EOD"
61
+ self.puts data
62
+ self.puts 'EOD'
63
+ name
64
+ end
65
+
66
+ ##
67
+ # ====== Overview
68
+ # Converts given options to gnuplot format;
69
+ # for {opt1: val1, .. , optN: valN} it returns
70
+ # set opt1 val1
71
+ # ..
72
+ # set optN valN
73
+ # ====== Arguments
74
+ # * *options* - hash of options to convert
75
+ def options_hash_to_string(options)
76
+ result = ''
77
+ options.sort_by { |key, _| OPTION_ORDER.find_index(key) || -1 }.each do |key, value|
78
+ if value
79
+ result += "set #{OptionHandling.option_to_string(key, value)}\n"
80
+ else
81
+ result += "unset #{key}\n"
82
+ end
83
+ end
84
+ result
85
+ end
86
+
87
+ ##
88
+ # ====== Overview
89
+ # Applies given options to current gnuplot instance;
90
+ # for {opt1: val1, .. , optN: valN} it will output to gnuplot
91
+ # set opt1 val1
92
+ # ..
93
+ # set optN valN
94
+ # ====== Arguments
95
+ # *options* - hash of options to set
96
+ # ====== Examples
97
+ # set({term: ['qt', size: [100, 100]]})
98
+ # #=> outputs to gnuplot: "set term qt size 100,100\n"
99
+ def set(options)
100
+ OptionHandling.validate_terminal_options(options)
101
+ self.puts(options_hash_to_string(options))
102
+ end
103
+
104
+ ##
105
+ # ====== Overview
106
+ # Unset some options
107
+ # ====== Arguments
108
+ # * **options* - Array of options need to unset
109
+ def unset(*options)
110
+ options.flatten
111
+ .sort_by { |key| OPTION_ORDER.find_index(key) || -1 }
112
+ .each { |key| self.puts "unset #{OptionHandling.string_key(key)}" }
113
+ self
114
+ end
115
+
116
+ ##
117
+ # ====== Overview
118
+ # Short way to plot Datablock, Plot or Splot object.
119
+ # Other items will be just piped out to gnuplot.
120
+ def <<(item)
121
+ case item
122
+ when Dataset
123
+ Plot.new(item).plot(self)
124
+ when Plottable
125
+ item.plot(self)
126
+ else
127
+ self.print(item.to_s)
128
+ end
129
+ self
130
+ end
131
+
132
+ ##
133
+ # ====== Overview
134
+ # Just puts *command* to gnuplot pipe and returns self
135
+ # to allow chaining.
136
+ def puts(command)
137
+ self.print("#{command}\n")
138
+ end
139
+
140
+ ##
141
+ # ====== Overview
142
+ # Just prints *command* to gnuplot pipe and returns self
143
+ # to allow chaining.
144
+ def print(command)
145
+ check_errors
146
+ @in.print(command)
147
+ self
148
+ end
149
+
150
+ ##
151
+ # ====== Overview
152
+ # Call replot on gnuplot. This will execute last plot once again
153
+ # with rereading data.
154
+ def replot(**options)
155
+ set(options)
156
+ self.puts('replot')
157
+ unset(options.keys)
158
+ sleep 0.01 until File.size?(options[:output]) if options[:output]
159
+ self
160
+ end
161
+
162
+ ##
163
+ # ====== Overview
164
+ # Send gnuplot command to turn it off and for its Process to quit.
165
+ # Closes pipe so Terminal object should not be used after #close call.
166
+ def close
167
+ check_errors
168
+ Terminal::close_arg(@in)
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,6 @@
1
+ ##
2
+ # === Overview
3
+ # Ruby bindings for gnuplot.
4
+ module GnuplotRB
5
+ VERSION = '0.2.0'
6
+ end
metadata ADDED
@@ -0,0 +1,191 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gnuplotrb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Ivan Evgrafov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: hamster
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rdoc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.29'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.29'
97
+ - !ruby/object:Gem::Dependency
98
+ name: codeclimate-test-reporter
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: chunky_png
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: daru
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Renewed ruby bindings for gnuplot. Started at GSoC 2015.
140
+ email:
141
+ - dilcom3107@gmail.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - Gemfile
147
+ - LICENSE
148
+ - README.rdoc
149
+ - Rakefile
150
+ - gnuplotrb.gemspec
151
+ - lib/gnuplotrb.rb
152
+ - lib/gnuplotrb/external_classes/array.rb
153
+ - lib/gnuplotrb/external_classes/daru.rb
154
+ - lib/gnuplotrb/external_classes/iruby.rb
155
+ - lib/gnuplotrb/external_classes/string.rb
156
+ - lib/gnuplotrb/mixins/error_handling.rb
157
+ - lib/gnuplotrb/mixins/option_handling.rb
158
+ - lib/gnuplotrb/mixins/plottable.rb
159
+ - lib/gnuplotrb/multiplot.rb
160
+ - lib/gnuplotrb/plot.rb
161
+ - lib/gnuplotrb/splot.rb
162
+ - lib/gnuplotrb/staff/datablock.rb
163
+ - lib/gnuplotrb/staff/dataset.rb
164
+ - lib/gnuplotrb/staff/settings.rb
165
+ - lib/gnuplotrb/staff/terminal.rb
166
+ - lib/gnuplotrb/version.rb
167
+ homepage: https://github.com/dilcom/gnuplotrb
168
+ licenses:
169
+ - MIT
170
+ metadata: {}
171
+ post_install_message:
172
+ rdoc_options: []
173
+ require_paths:
174
+ - lib
175
+ required_ruby_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '2.0'
180
+ required_rubygems_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ requirements: []
186
+ rubyforge_project:
187
+ rubygems_version: 2.4.5
188
+ signing_key:
189
+ specification_version: 4
190
+ summary: Ruby bindings for gnuplot
191
+ test_files: []