redplot 0.0.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.
- data/lib/redplot.rb +234 -0
- metadata +46 -0
data/lib/redplot.rb
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
# RedPlot is Copyright (c) 2011 Hugo Benichi <hbenichi@gmail.com>
|
2
|
+
#
|
3
|
+
# RedPlot is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# RedPlot is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
9
|
+
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
10
|
+
# See the GNU General Public License for more details.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU General Public License along with RedPlot.
|
13
|
+
# If not, see <http://www.gnu.org/licenses/>.
|
14
|
+
#
|
15
|
+
# Description: a simple layer to gnuplot;
|
16
|
+
# can enhance any ruby object with plotting facilities;
|
17
|
+
#
|
18
|
+
# How it works: cf examples/;
|
19
|
+
# you can either mixin Redplot to any object;
|
20
|
+
# you can also directly use the Plotter class;
|
21
|
+
#
|
22
|
+
|
23
|
+
|
24
|
+
#main namespace
|
25
|
+
#also used for mixin
|
26
|
+
module RedPlot
|
27
|
+
|
28
|
+
VersionNumber, VersionDate = '0.1.2', '2011-04-04'
|
29
|
+
|
30
|
+
#helper class to store callbacks to the data and plot command options
|
31
|
+
class ToDraw
|
32
|
+
attr_reader :options, :callbacks
|
33
|
+
def initialize
|
34
|
+
reinit
|
35
|
+
end
|
36
|
+
def reinit
|
37
|
+
@options, @callbacks = [], []
|
38
|
+
self
|
39
|
+
end
|
40
|
+
#main client method
|
41
|
+
#expects a callback block that return an object with access to data to plat
|
42
|
+
#different object are possible (cf Plotter#formatdata)
|
43
|
+
def add(option="", &block)
|
44
|
+
unless block.nil?
|
45
|
+
@options << option
|
46
|
+
@callbacks << block
|
47
|
+
end
|
48
|
+
self
|
49
|
+
end
|
50
|
+
alias_method :clear, :reinit #add to test
|
51
|
+
end
|
52
|
+
|
53
|
+
#main class whose instances are wrapper to gnuplot process
|
54
|
+
#the instances manage the necessary ressources and have all the callable methods
|
55
|
+
#
|
56
|
+
#if an object is mixed with RedPlot, then an instance of Plotter is hooked to that object
|
57
|
+
#the instance of Plotter is then the path to gnuplot and helps to avoid name conflicts
|
58
|
+
class Plotter
|
59
|
+
|
60
|
+
attr_accessor :header, # stores in an array settings such as "set xrange [a,b]"
|
61
|
+
:path, # gives a path to save data and pritn graph
|
62
|
+
:command # determine the main plotting command: plot, splot, ...
|
63
|
+
attr_reader :todraw # holds callbacks to the data to be plotted
|
64
|
+
|
65
|
+
#destructor to close the gnuplot process
|
66
|
+
def self.release instance
|
67
|
+
instance.close
|
68
|
+
end
|
69
|
+
|
70
|
+
def method_missing(*args)
|
71
|
+
(scoped_header = @header ) << args.join(" ") + " "
|
72
|
+
args[0].to_s.tap do |eval_space|
|
73
|
+
eval_space.singleton_class.instance_eval do
|
74
|
+
define_method(:method_missing) do |*args|
|
75
|
+
scoped_header[-1] << args.join(" ") + " "
|
76
|
+
self
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def initialize(args={}, &configuration_block)
|
83
|
+
@header = args[:header] || []
|
84
|
+
@path = args[:path] || 'redplot'
|
85
|
+
@command = args[:command] || 'plot'
|
86
|
+
@todraw = ToDraw.new
|
87
|
+
self.instance_eval &configuration_block if block_given?
|
88
|
+
self
|
89
|
+
end
|
90
|
+
|
91
|
+
#start the gnuplot process if @proc is nil
|
92
|
+
def start
|
93
|
+
@proc ||= IO.popen("gnuplot","w+").tap do |open|
|
94
|
+
ObjectSpace.define_finalizer(self) { open.close }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
#directly write to the gnuplot process stdin
|
99
|
+
def <<( *args )
|
100
|
+
start.puts args
|
101
|
+
end
|
102
|
+
|
103
|
+
#main client method to draw data
|
104
|
+
#happens in 3 steps:
|
105
|
+
# 1) sends the header args to gnuplot
|
106
|
+
# 2) sends the plot command
|
107
|
+
# 3) sends the data one block at a time
|
108
|
+
def draw
|
109
|
+
start
|
110
|
+
@proc.puts @header
|
111
|
+
@proc.puts format_command( @command, @todraw.options )
|
112
|
+
@todraw.callbacks.each { |block| @proc.puts format_data( block.call ) }
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
#format the plot command
|
117
|
+
def format_command( command, options )
|
118
|
+
"%s '-' %s" % [command, options.join(",'-' ")] #not tested yet
|
119
|
+
end
|
120
|
+
|
121
|
+
#format the data from the callback blocks to fit gnuplot
|
122
|
+
#several interface are possible
|
123
|
+
# 1) a plain Array
|
124
|
+
# 2) an array of arrays, in which case these arrays are taken as data columns
|
125
|
+
# 3) anything with an each method
|
126
|
+
# the block send to each takes one or more Numerics and/or numbers hidden in string
|
127
|
+
def format_data( raw_data )
|
128
|
+
if raw_data.is_a? Array
|
129
|
+
if raw_data[0].is_a? Array
|
130
|
+
raw_data.transpose.map!{ |one_row| one_row.join " "}
|
131
|
+
else
|
132
|
+
raw_data
|
133
|
+
end
|
134
|
+
else
|
135
|
+
[].tap{ |data| raw_data.each { |*vals| data << vals.join(" ") } } #not tested yet
|
136
|
+
end.<< 'end'
|
137
|
+
end
|
138
|
+
|
139
|
+
#write to disc the result of format_Data
|
140
|
+
def save_data(path=@path)
|
141
|
+
File.open( path+".dat", "w+") do |file|
|
142
|
+
@todraw.callbacks.each do |block|
|
143
|
+
file.puts format_data( block.call ).tap{|ary| ary[-1] = ''}
|
144
|
+
end
|
145
|
+
end
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
149
|
+
#write to disc the content of @header and format_command
|
150
|
+
def save_script(path=@path)
|
151
|
+
File.open( path + ".scr", "w+") do |file|
|
152
|
+
file.puts @header
|
153
|
+
file.puts format_command( @command, @todraw.options )
|
154
|
+
end
|
155
|
+
self
|
156
|
+
end
|
157
|
+
|
158
|
+
#either draw in png or eps mode
|
159
|
+
def save_graph(type=:png, path=@path)
|
160
|
+
case type
|
161
|
+
when :png then save_png( path )
|
162
|
+
when :eps then save_eps( path )
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
#set gnuplot terminal to eps and draw
|
167
|
+
#!the terminal will stay in eps mode
|
168
|
+
def save_eps(path=@path)
|
169
|
+
start.puts "set term postscript eps color blacktext \"Helvetica\" 24",
|
170
|
+
"set output '#{path}.eps'"
|
171
|
+
draw
|
172
|
+
end
|
173
|
+
|
174
|
+
#set gnuplot terminal to png and draw
|
175
|
+
#!the terminal will stay in png mode
|
176
|
+
def save_png(path=@path)
|
177
|
+
start.puts 'set term png enhanced',
|
178
|
+
"set output '#{path}.png'"
|
179
|
+
draw
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
#all the mechanism for object extention happens here
|
185
|
+
class << self
|
186
|
+
|
187
|
+
#if a class includes RedPlot, RedPlot inserts itself in the class instead
|
188
|
+
def included who
|
189
|
+
insert in: who, as: :plot
|
190
|
+
end
|
191
|
+
|
192
|
+
#if an object extends RedPlot, RedPlot adds itself to the object via its eigenclass
|
193
|
+
def extended who
|
194
|
+
insert in: who.singleton_class, as: :plot
|
195
|
+
end
|
196
|
+
|
197
|
+
#this method takes a class and adds an attr_reader to it
|
198
|
+
#it also adds a lazy initialization reader with a shortcut name
|
199
|
+
# ! a call to the attr_reader before a call to the shorcut reader will return nil
|
200
|
+
def insert(args, &block)
|
201
|
+
target = args[:in]
|
202
|
+
name = args[:as] || :plot
|
203
|
+
target.class_eval do
|
204
|
+
attr_reader :gnuplot_wrapper
|
205
|
+
define_method(name) { @gnuplot_wrapper ||= RedPlot::Plotter.new(args,&block) }
|
206
|
+
end if target.is_a? Class
|
207
|
+
end
|
208
|
+
|
209
|
+
#returns a string with version number
|
210
|
+
def version
|
211
|
+
'RedPlot version "%s" (%s)' % [RedPlot::VersionNumber, RedPlot::VersionDate]
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
class Array
|
220
|
+
#this provide a quick hook for Array instances
|
221
|
+
def plot!(args={})
|
222
|
+
args[:as] ||= :plot
|
223
|
+
args[:in] = self.singleton_class
|
224
|
+
data = self
|
225
|
+
RedPlot::insert(args) { todraw.add args[:style] {data} }
|
226
|
+
wrapper = self.send args[:as]
|
227
|
+
end
|
228
|
+
#hook RedPlot to the array and draw what is inside it
|
229
|
+
def plot_now!(args={})
|
230
|
+
self.plot!(args).draw
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redplot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Hugo Benichi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-05 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: redplot gives convenience handler methods from and to Ruby objects to
|
15
|
+
easily communicate with a gnuplot process
|
16
|
+
email: hugo.benichi@m4x.org
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/redplot.rb
|
22
|
+
homepage: https://github.com/hugobenichi/redplot
|
23
|
+
licenses: []
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 1.8.11
|
43
|
+
signing_key:
|
44
|
+
specification_version: 3
|
45
|
+
summary: A simple layer wrapping around a gnuplot process.
|
46
|
+
test_files: []
|