blackwinter-gnuplot 2.3.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS.txt +7 -0
- data/ChangeLog +54 -0
- data/LICENSE.txt +27 -0
- data/README.rdoc +203 -0
- data/Rakefile +32 -0
- data/examples/.gitignore +1 -0
- data/examples/discrete_points.rb +15 -0
- data/examples/histogram.rb +18 -0
- data/examples/multiple_data_sets.rb +22 -0
- data/examples/output_file1.rb +26 -0
- data/examples/output_file2.rb +15 -0
- data/examples/sine_wave.rb +13 -0
- data/lib/gnuplot/version.rb +5 -0
- data/lib/gnuplot.rb +332 -0
- data/test/test_gnuplot.rb +110 -0
- metadata +106 -0
data/AUTHORS.txt
ADDED
data/ChangeLog
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
2.3.5
|
2
|
+
* Cleanup readme, add examples as real code files (thanks blambeau!)
|
3
|
+
|
4
|
+
2.3.4
|
5
|
+
* Include more files in the gem by switching to Jeweler (thanks Jeweler guyz)!
|
6
|
+
|
7
|
+
2.3.3
|
8
|
+
* Fix issue #4 (thanks Jakobs)
|
9
|
+
* Fix some unit tests (thanks Nobu!)
|
10
|
+
|
11
|
+
2.3.2 Feb 2010
|
12
|
+
* Add an arbitrary_lines specifier
|
13
|
+
|
14
|
+
2.3.1 Feb 2010
|
15
|
+
|
16
|
+
* Fix a bug I introduced in 2.3.0
|
17
|
+
|
18
|
+
2.3.0 Feb 2010
|
19
|
+
|
20
|
+
* incorporate a few patch changes
|
21
|
+
|
22
|
+
2.2.3.1 July 18 2009
|
23
|
+
|
24
|
+
* output the raw "to gnuplot" data if $VERBOSE
|
25
|
+
|
26
|
+
Version 2.2.2 July 2009
|
27
|
+
|
28
|
+
* raise if no executable found, should be windows compat. now
|
29
|
+
|
30
|
+
Version 2.2 14-Nov-2005
|
31
|
+
|
32
|
+
* Formally added the LICENSE.txt file. It is the new BSD license as defined
|
33
|
+
by opensource.org. See that file for details.
|
34
|
+
|
35
|
+
* Added Gnuplot.which to try and fix the recurring problem of windows users
|
36
|
+
having to hack code to get things working.
|
37
|
+
|
38
|
+
* Added the Gnuplot.gnuplot function so that I can unit test the finding
|
39
|
+
gnuplot executable routine.
|
40
|
+
|
41
|
+
* In the Array.to_gplot method the terminating e is added to the output. This
|
42
|
+
is in response to Bug #2209.
|
43
|
+
|
44
|
+
Version 2.1 17-Nov-2004
|
45
|
+
|
46
|
+
* Array.to_gplot and Array.to_gsplot now support passing in arrays of
|
47
|
+
arbitrary objects. This is in response to a request by Yoshiki Tsunesada
|
48
|
+
(Tracker ID 1063)
|
49
|
+
|
50
|
+
Version 2.0 10-Nov-2004
|
51
|
+
|
52
|
+
* The 2.0 version of the gnuplot interface is a cross between the original,
|
53
|
+
object oriented version, and the version 1.0 which was simply a string
|
54
|
+
manipulation library.
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright (c) 2004-2005, Gordon James Miller (gmiller@bittwiddlers.com)
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
* Redistributions in binary form must reproduce the above copyright
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
12
|
+
documentation and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
* Neither the name of the BitTwiddlers, Inc. nor the names of its
|
15
|
+
contributors may be used to endorse or promote products derived from
|
16
|
+
this software without specific prior written permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
22
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
23
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
24
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
25
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
26
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
= Ruby Gnuplot - Utility library to aid in interacting with GNUPLOT
|
2
|
+
|
3
|
+
* {Rubyforge Project page}[http://rubyforge.org/projects/rgplot]
|
4
|
+
* {Documentation}[http://blackwinter.github.com/ruby_gnuplot]
|
5
|
+
* {Source code}[http://github.com/blackwinter/ruby_gnuplot]
|
6
|
+
|
7
|
+
|
8
|
+
== History and Background
|
9
|
+
|
10
|
+
GNUPLOT[http://gnuplot.info] is a program that has a rich language for the
|
11
|
+
generation of plots. It has a unique place in academia as it was one of the
|
12
|
+
first freely available programs for plot generation. I started using GNUPLOT
|
13
|
+
over 10 years ago while pursuing my Master's degree in Physics and have been
|
14
|
+
using it actively ever since.
|
15
|
+
|
16
|
+
=== Version 0.9
|
17
|
+
|
18
|
+
My first attempt at a Ruby interface to GNUPLOT was an object interface
|
19
|
+
encapsulating GNUPLOT language. This was taken directly from the Python
|
20
|
+
GNUPLOT interface. In spite of my being very familiar with GNUPLOT and Ruby
|
21
|
+
and being the author of the RGnuplot package, I found it non-intuitive to
|
22
|
+
use the RGnuplot package. I found myself constantly looking at the code to
|
23
|
+
figure out what I needed to do. This was not sufficient and did not sit well.
|
24
|
+
|
25
|
+
=== Version 1.0
|
26
|
+
|
27
|
+
The second attempt at a Ruby interface was to do absolutely nothing but use
|
28
|
+
Ruby's built in string manipulation methods. This meant that I could simply
|
29
|
+
use my knowledge of GNUPLOT without having to worry about objects. While in
|
30
|
+
some ways an improvement over version 0.9, it still did not sit well with me.
|
31
|
+
|
32
|
+
=== Version 2.0
|
33
|
+
|
34
|
+
After attending RubyConf 2004 I was inspired by Rich Kilmer's use of Ruby to
|
35
|
+
implement domain specific languages. That is the current implementation of
|
36
|
+
Gnuplot and quite probably the one that I'll stick with for some time. This
|
37
|
+
version combines the direct mapping of the GNUPLOT language without wrapping
|
38
|
+
with the Ruby syntax and mechanism of adding methods to existing classes to
|
39
|
+
interface Ruby objects with GNUPLOT.
|
40
|
+
|
41
|
+
|
42
|
+
== Setup
|
43
|
+
|
44
|
+
=== Version 2.2
|
45
|
+
|
46
|
+
If the +gnuplot+ command is in your path then there is no required setup. If
|
47
|
+
the GNUPLOT executable for your system is called something other than simply
|
48
|
+
+gnuplot+ then set the +RB_GNUPLOT+ environment variable to the name of the
|
49
|
+
executable. This must either be a full path to the GNUPLOT command or an
|
50
|
+
executable filename that exists in your +PATH+ environment variable.
|
51
|
+
|
52
|
+
|
53
|
+
== Ruby Gnuplot Concepts
|
54
|
+
|
55
|
+
GNUPLOT has a very simple conceptual model. Calls to _set_ are made to set
|
56
|
+
parameters and either _plot_ or _splot_ is called to generate the actual plot.
|
57
|
+
The _dataset_ to be plotted can be specified in a number of ways, contained
|
58
|
+
in a separate file, generated from a function, read from standard input, or
|
59
|
+
read immediately after the plot command.
|
60
|
+
|
61
|
+
The object model for the Ruby Gnuplot wrapper directly mimics this layout and
|
62
|
+
flow. The following are the standard steps for generating a plot:
|
63
|
+
|
64
|
+
* Instantiate a Gnuplot::Plot or Gnuplot::SPlot object and set parameters by
|
65
|
+
GNUPLOT variable name.
|
66
|
+
* Instantiate Gnuplot::DataSet objects and attach Ruby objects containing the
|
67
|
+
data to be plotted to the data set.
|
68
|
+
* Attach properties that modify the plot command using the modifier name.
|
69
|
+
* Send the Plot/SPlot object to a GNUPLOT instance for plotting.
|
70
|
+
|
71
|
+
The version 2.0 interface makes heavy use of blocks leading to very readable
|
72
|
+
code.
|
73
|
+
|
74
|
+
[<tt>Gnuplot.open</tt>]
|
75
|
+
Instantiates a new GNUPLOT process. The path to the executable is determined
|
76
|
+
using the Gnuplot.which command. If a block is given to the function the
|
77
|
+
opened process is passed into the block. This mimics the most common usage
|
78
|
+
of the File.open method.
|
79
|
+
|
80
|
+
[<tt>Gnuplot::Plot.new</tt>, <tt>Gnuplot::SPlot.new</tt>]
|
81
|
+
Create a new Plot or SPlot object. DataSets are attached to the object to
|
82
|
+
specify the data and its properties. If a block is given to the function,
|
83
|
+
the plot object is passed into the block.
|
84
|
+
|
85
|
+
[<tt>Gnuplot::DataSet.new</tt>]
|
86
|
+
Associates a Ruby object containing the data to plot with the properties
|
87
|
+
that will be passed to the plot command for that data set. Any Ruby object
|
88
|
+
can be associated with a DataSet as long as it understands the +to_gplot+
|
89
|
+
method.
|
90
|
+
|
91
|
+
[<tt>to_gplot</tt>]
|
92
|
+
Within GNUPLOT, plot data is read in very simple formats. The +to_gplot+
|
93
|
+
method is expected to write the data of the object in a format that is
|
94
|
+
understandable by GNUPLOT. One of the many great things about Ruby is that
|
95
|
+
methods can be added after the original declaration. The Gnuplot module
|
96
|
+
defines the +to_gplot+ method on the classes Array and Matrix. Simply
|
97
|
+
define a +to_gplot+ method on your own class to tie the class into gnuplot.
|
98
|
+
|
99
|
+
|
100
|
+
== Examples
|
101
|
+
|
102
|
+
=== Simple sine wave
|
103
|
+
|
104
|
+
The following example simply plots the value of <tt>sin(x)</tt> between the
|
105
|
+
ranges of -10 and 10. A few points to notice:
|
106
|
+
|
107
|
+
The code uses nested blocks to construct the plot. The newly created object
|
108
|
+
is passed to the block so it can be modified in place.
|
109
|
+
|
110
|
+
Each of the GNUPLOT plot variables is modified using the variable name as a
|
111
|
+
method name on the plot object or on the data set object. The wrapper also
|
112
|
+
takes care of the single quoting that is required on some of the variables
|
113
|
+
like +title+, +ylabel+, and +xlabel+.
|
114
|
+
|
115
|
+
The plot object simply has an array of Gnuplot::DataSet objects. The
|
116
|
+
constructor initializes this empty array before yielding to the block. This
|
117
|
+
method uses the <tt><<</tt> operator to add the DataSet to the plot.
|
118
|
+
|
119
|
+
When the plot block ends, if an IO object is given to the Gnuplot::Plot
|
120
|
+
constructor, the plot commands will be written to the IO object. Any object can
|
121
|
+
be passed to the constructor as long as it understands the <tt><<</tt> operator.
|
122
|
+
|
123
|
+
Gnuplot.open { |gp|
|
124
|
+
Gnuplot::Plot.new(gp) { |plot|
|
125
|
+
|
126
|
+
plot.xrange '[-10:10]'
|
127
|
+
plot.title 'Sine Wave Example'
|
128
|
+
plot.xlabel 'x'
|
129
|
+
plot.ylabel 'sin(x)'
|
130
|
+
|
131
|
+
plot.data << Gnuplot::DataSet.new('sin(x)') { |ds|
|
132
|
+
ds.with = 'lines'
|
133
|
+
ds.linewidth = 4
|
134
|
+
}
|
135
|
+
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
=== Plotting discrete points
|
140
|
+
|
141
|
+
Array data can be plotted quite easily since Arrays have a defined
|
142
|
+
Array#to_gplot method.
|
143
|
+
|
144
|
+
Simply pass an array of data to the constructor of the Gnuplot::DataSet
|
145
|
+
object or set the data property of the DataSet. In this example, because
|
146
|
+
there are two arrays, each array will be a single column of data to the
|
147
|
+
GNUPLOT process.
|
148
|
+
|
149
|
+
Also, this example uses the Gnuplot.plot convenience method which wraps
|
150
|
+
the calls to Gnuplot.open and Gnuplot::Plot.new.
|
151
|
+
|
152
|
+
Gnuplot.plot { |plot|
|
153
|
+
plot.title 'Array Plot Example'
|
154
|
+
plot.xlabel 'x'
|
155
|
+
plot.ylabel 'x^2'
|
156
|
+
|
157
|
+
x = (0..50).map { |v| v.to_f }
|
158
|
+
y = x.map { |v| v ** 2 }
|
159
|
+
|
160
|
+
plot.data << Gnuplot::DataSet.new([x, y]) { |ds|
|
161
|
+
ds.with = 'linespoints'
|
162
|
+
ds.notitle
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
=== Multiple Data Sets
|
167
|
+
|
168
|
+
As many data sets as are desired can be attached to a plot. Each of these can
|
169
|
+
have their own plot modifiers. Notice in this example how the data array is
|
170
|
+
set through the Gnuplot::DataSet#data convenience method instead of using the
|
171
|
+
<tt><<</tt> operator.
|
172
|
+
|
173
|
+
Also in this example, the commands are not written to the GNUPLOT process but
|
174
|
+
are instead written to a File called <tt>gnuplot.dat</tt>. This file can later
|
175
|
+
be run directly by a GNUPLOT process as it contains only the GNUPLOT commands.
|
176
|
+
|
177
|
+
Gnuplot.plot_to('gnuplot.dat') { |plot|
|
178
|
+
plot.xrange '[-10:10]'
|
179
|
+
plot.title 'Sin Wave Example'
|
180
|
+
plot.xlabel 'x'
|
181
|
+
plot.ylabel 'sin(x)'
|
182
|
+
|
183
|
+
x = (0..50).map { |v| v.to_f }
|
184
|
+
y = x.map { |v| v ** 2 }
|
185
|
+
|
186
|
+
plot.data('sin(x)') { |ds|
|
187
|
+
ds.with = 'lines'
|
188
|
+
ds.title = 'String function'
|
189
|
+
ds.linewidth = 4
|
190
|
+
}
|
191
|
+
|
192
|
+
plot.data([x, y]) { |ds|
|
193
|
+
ds.with = 'linespoints'
|
194
|
+
ds.title = 'Array data'
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
You can also add arbitrary lines to the output:
|
199
|
+
|
200
|
+
plot.arbitrary_lines << 'set ylabel "y label" font "Helvetica,20"'
|
201
|
+
|
202
|
+
# or more conveniently
|
203
|
+
plot << 'set ylabel "y label" font "Helvetica,20"'
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.expand_path(%q{../lib/gnuplot/version}, __FILE__)
|
2
|
+
|
3
|
+
require 'jeweler'
|
4
|
+
require 'rdoc/task'
|
5
|
+
require 'rake/testtask'
|
6
|
+
|
7
|
+
Jeweler::Tasks.new { |s|
|
8
|
+
s.name = 'blackwinter-gnuplot'
|
9
|
+
s.version = Gnuplot::VERSION
|
10
|
+
s.summary = 'Utility library to aid in interacting with GNUPLOT'
|
11
|
+
s.authors = ['Roger Pack', 'Jens Wille']
|
12
|
+
s.email = ['rogerpack2005@gmail.com', 'jens.wille@uni-koeln.de']
|
13
|
+
s.homepage = 'http://github.com/blackwinter/ruby_gnuplot'
|
14
|
+
|
15
|
+
s.add_dependency 'ruby-nuggets'
|
16
|
+
}
|
17
|
+
|
18
|
+
RDoc::Task.new(:doc) { |t|
|
19
|
+
t.rdoc_dir = 'doc'
|
20
|
+
t.rdoc_files = FileList[
|
21
|
+
'lib/**/*.rb', 'README.rdoc', 'ChangeLog', 'AUTHORS.txt', 'LICENSE.txt'
|
22
|
+
].to_a
|
23
|
+
t.options = [
|
24
|
+
'--title', "Gnuplot Application documentation (v#{Gnuplot::VERSION})",
|
25
|
+
'--main', 'README.rdoc', '--charset', 'UTF-8', '--line-numbers', '--all'
|
26
|
+
]
|
27
|
+
}
|
28
|
+
|
29
|
+
Rake::TestTask.new { |t|
|
30
|
+
t.test_files = FileList['test/**/test_*.rb'].to_a
|
31
|
+
t.ruby_opts << '-rubygems'
|
32
|
+
}
|
data/examples/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
sine_wave_example*.*
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'gnuplot'
|
2
|
+
|
3
|
+
Gnuplot.plot { |plot|
|
4
|
+
plot.title 'Discrete Points Example'
|
5
|
+
plot.xlabel 'x'
|
6
|
+
plot.ylabel 'x^2'
|
7
|
+
|
8
|
+
x = (0..50).map { |v| v.to_f }
|
9
|
+
y = x.map { |v| v ** 2 }
|
10
|
+
|
11
|
+
plot.data([x, y]) { |ds|
|
12
|
+
ds.with = 'linespoints'
|
13
|
+
ds.notitle
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'gnuplot'
|
2
|
+
|
3
|
+
Gnuplot.plot { |plot|
|
4
|
+
plot.title 'Histogram Example'
|
5
|
+
plot.xlabel 'x'
|
6
|
+
plot.ylabel 'frequency'
|
7
|
+
|
8
|
+
plot << 'bin(x, s) = s*int(x/s)'
|
9
|
+
|
10
|
+
x = (0..500).map { |v| (rand - 0.5) ** 3 }
|
11
|
+
|
12
|
+
plot.data([x]) { |ds|
|
13
|
+
ds.title = 'smooth frequency'
|
14
|
+
ds.using = '(bin($1,.01)):(1.)'
|
15
|
+
ds.smooth = 'freq'
|
16
|
+
ds.with = 'boxes'
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'gnuplot'
|
2
|
+
|
3
|
+
Gnuplot.plot { |plot|
|
4
|
+
plot.xrange '[-10:10]'
|
5
|
+
plot.title 'Multiple Data Sets Example'
|
6
|
+
plot.xlabel 'x'
|
7
|
+
plot.ylabel 'y'
|
8
|
+
|
9
|
+
x = (0..50).map { |v| v.to_f }
|
10
|
+
y = x.map { |v| v ** 2 }
|
11
|
+
|
12
|
+
plot.data('sin(x)') { |ds|
|
13
|
+
ds.with = 'lines'
|
14
|
+
ds.title = 'String function'
|
15
|
+
ds.linewidth = 4
|
16
|
+
}
|
17
|
+
|
18
|
+
plot.data([x, y]) { |ds|
|
19
|
+
ds.with = 'linespoints'
|
20
|
+
ds.title = 'Array data'
|
21
|
+
}
|
22
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'gnuplot'
|
2
|
+
|
3
|
+
file = File.expand_path('../output_file_example1.gif', __FILE__)
|
4
|
+
|
5
|
+
Gnuplot.plot { |plot|
|
6
|
+
# The following lines allow outputting the graph to an image file.
|
7
|
+
# The first sets the kind of image that you want, while the second
|
8
|
+
# redirects the output to a given file.
|
9
|
+
#
|
10
|
+
# Typical terminals: gif, png, postscript, latex, texdraw
|
11
|
+
#
|
12
|
+
# See http://mibai.tec.u-ryukyu.ac.jp/~oshiro/Doc/gnuplot_primer/gptermcmp.html
|
13
|
+
# for a list of recognized terminals.
|
14
|
+
plot.terminal 'gif'
|
15
|
+
plot.output file
|
16
|
+
|
17
|
+
plot.xrange '[-10:10]'
|
18
|
+
plot.title 'Sine Wave Example'
|
19
|
+
plot.xlabel 'x'
|
20
|
+
plot.ylabel 'sin(x)'
|
21
|
+
|
22
|
+
plot.data('sin(x)') { |ds|
|
23
|
+
ds.with = 'lines'
|
24
|
+
ds.linewidth = 4
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'gnuplot'
|
2
|
+
|
3
|
+
file = File.expand_path('../output_file_example2.dat', __FILE__)
|
4
|
+
|
5
|
+
Gnuplot.plot_to(file) { |plot|
|
6
|
+
plot.xrange '[-10:10]'
|
7
|
+
plot.title 'Sine Wave Example'
|
8
|
+
plot.xlabel 'x'
|
9
|
+
plot.ylabel 'sin(x)'
|
10
|
+
|
11
|
+
plot.data('sin(x)') { |ds|
|
12
|
+
ds.with = 'lines'
|
13
|
+
ds.linewidth = 4
|
14
|
+
}
|
15
|
+
}
|
data/lib/gnuplot.rb
ADDED
@@ -0,0 +1,332 @@
|
|
1
|
+
require 'matrix'
|
2
|
+
require 'nuggets/file/which'
|
3
|
+
|
4
|
+
# Methods and variables for interacting with the GNUPLOT process. Most of
|
5
|
+
# these methods are for sending data to a GNUPLOT process, not for reading
|
6
|
+
# from it. Some of the methods are implemented as added methods to the built
|
7
|
+
# in classes.
|
8
|
+
|
9
|
+
module Gnuplot
|
10
|
+
|
11
|
+
# Holds the map of file extensions to GNUPLOT terminals.
|
12
|
+
TERMINAL = Hash.new { |h, k| h[k] = k }.update(
|
13
|
+
'dat' => nil,
|
14
|
+
'jpg' => 'jpeg',
|
15
|
+
'ps' => 'postscript'
|
16
|
+
)
|
17
|
+
|
18
|
+
class << self
|
19
|
+
|
20
|
+
attr_writer :gnuplot
|
21
|
+
|
22
|
+
# Maps file extension (with optional dot) to GNUPLOT terminal (cf.
|
23
|
+
# TERMINAL).
|
24
|
+
def terminal(ext)
|
25
|
+
TERMINAL[ext.to_s.sub(/\A\./, '')]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Delegates to File.which, but String#strip's +bin+ first.
|
29
|
+
def which(bin)
|
30
|
+
File.which(bin.strip)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Finds the path to the GNUPLOT executable. The name of the executable
|
34
|
+
# can be specified using the link:#gnuplot= accessor or the RB_GNUPLOT
|
35
|
+
# environment variable but will default to the command +gnuplot+.
|
36
|
+
#
|
37
|
+
# Adds the persist flag to the GNUPLOT executable if +persist+ is +true+.
|
38
|
+
#
|
39
|
+
# Returns the path to the GNUPLOT executable or raises an error if one
|
40
|
+
# cannot be found.
|
41
|
+
def gnuplot(persist = true)
|
42
|
+
@gnuplot ||= which(ENV['RB_GNUPLOT'] || 'gnuplot')
|
43
|
+
raise 'GNUPLOT executable not found' unless @gnuplot
|
44
|
+
|
45
|
+
"#{@gnuplot}#{' -persist' if persist}"
|
46
|
+
end
|
47
|
+
|
48
|
+
# Opens a GNUPLOT process via Gnuplot.gnuplot (passing the +persist+ flag) and
|
49
|
+
# yields the IO object associated with the GNUPLOT process to the block.
|
50
|
+
#
|
51
|
+
# See the {GNUPLOT documentation}[http://gnuplot.sourceforge.net/documentation.html]
|
52
|
+
# for information on the persist flag.
|
53
|
+
def open(persist = true, mode = 'w')
|
54
|
+
IO.popen(gnuplot(persist), mode) { |gp| yield gp }
|
55
|
+
end
|
56
|
+
|
57
|
+
# Wraps the calls to Gnuplot.open and Gnuplot::Plot.new.
|
58
|
+
def plot(persist = true, *args, &block)
|
59
|
+
open(persist) { |gp| Plot.new(gp, *args, &block) }
|
60
|
+
end
|
61
|
+
|
62
|
+
# If +file+ is a file name that has a Gnuplot.terminal associated with it,
|
63
|
+
# the GNUPLOT process's terminal will be set accordingly and its output
|
64
|
+
# redirected to +file+.
|
65
|
+
#
|
66
|
+
# If +file+ is an IO object or doesn't have a terminal associated with it,
|
67
|
+
# the GNUPLOT process's output will simply be written to +file+.
|
68
|
+
def plot_to(file, persist = false, *args, &block)
|
69
|
+
io, file = file, nil if file.respond_to?(:write)
|
70
|
+
|
71
|
+
if file and term = terminal(File.extname(file))
|
72
|
+
plot(persist, *args) { |plot|
|
73
|
+
block[plot]
|
74
|
+
|
75
|
+
plot.terminal term unless plot[:terminal] || plot[:term]
|
76
|
+
plot.output file.to_s unless plot[:output] || plot[:out]
|
77
|
+
}
|
78
|
+
else
|
79
|
+
begin
|
80
|
+
io ||= File.open(file, 'w')
|
81
|
+
Plot.new(io, *args, &block)
|
82
|
+
ensure
|
83
|
+
io.close if file && io
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
# Holds command information and performs the formatting of that command
|
91
|
+
# information to a GNUPLOT process. When constructing a new plot for
|
92
|
+
# GNUPLOT, this is the first object that must be instantiated. On this
|
93
|
+
# object set the various properties and add data sets.
|
94
|
+
|
95
|
+
class Plot
|
96
|
+
|
97
|
+
QUOTED = %w[title output xlabel ylabel]
|
98
|
+
|
99
|
+
attr_accessor :io, :cmd, :data, :sets, :arbitrary_lines
|
100
|
+
|
101
|
+
def initialize(io = nil, cmd = 'plot')
|
102
|
+
@io, @cmd, @data, @sets, @arbitrary_lines = io, cmd, [], [], []
|
103
|
+
|
104
|
+
yield self if block_given?
|
105
|
+
|
106
|
+
plot! if io
|
107
|
+
end
|
108
|
+
|
109
|
+
# Sends the data and commands to the GNUPLOT process, drawing the plot.
|
110
|
+
#
|
111
|
+
# Prints the plot commands that are sent to the GNUPLOT process to +io+
|
112
|
+
# if +verbose+ is +true+.
|
113
|
+
def plot!(verbose = $VERBOSE, io = $stderr)
|
114
|
+
if verbose && io
|
115
|
+
io << "Writing this to GNUPLOT:\n"
|
116
|
+
to_gplot(io)
|
117
|
+
end
|
118
|
+
|
119
|
+
to_gplot
|
120
|
+
end
|
121
|
+
|
122
|
+
# Invoke the set method on the plot using the name of the invoked method
|
123
|
+
# as the set variable and any arguments that have been passed as the
|
124
|
+
# value. See the #set method for more details.
|
125
|
+
def method_missing(method, *args)
|
126
|
+
set(method, *args)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Set a variable to the given +value+. +var+ must be a GNUPLOT variable
|
130
|
+
# and +value+ must be the value to set it to. Automatic quoting will be
|
131
|
+
# performed if the variable requires it (see QUOTED).
|
132
|
+
def set(var, value = '')
|
133
|
+
var = var.to_s
|
134
|
+
value = %Q{"#{value}"} if QUOTED.include?(var) && value !~ /\A'.*'\z/
|
135
|
+
|
136
|
+
@sets << [var, value]
|
137
|
+
end
|
138
|
+
|
139
|
+
alias_method :[]=, :set
|
140
|
+
|
141
|
+
# Return the current value of the GNUPLOT variable +var+. This will
|
142
|
+
# return the setting that is currently in the instance, not one that's
|
143
|
+
# been given to the GNUPLOT process.
|
144
|
+
def [](var)
|
145
|
+
assoc = @sets.assoc(var.to_s)
|
146
|
+
assoc.last if assoc
|
147
|
+
end
|
148
|
+
|
149
|
+
# If +args+ is non-empty or +block+ is given, calls #add_data. Returns
|
150
|
+
# the current data otherwise.
|
151
|
+
def data(*args, &block)
|
152
|
+
args.empty? && !block ? @data : add_data(*args, &block)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Adds the DataSet +data+ to the GNUPLOT process's data sets. If +data+
|
156
|
+
# is not already a DataSet object, DataSet.new will be called with +data+
|
157
|
+
# and +block+ as arguments.
|
158
|
+
def add_data(data = nil, &block)
|
159
|
+
@data.push(data.is_a?(DataSet) ? data : DataSet.new(data, &block))
|
160
|
+
end
|
161
|
+
|
162
|
+
# Adds an arbitrary +line+ to write to the GNUPLOT process. Returns +self+
|
163
|
+
# to allow chaining.
|
164
|
+
def <<(line)
|
165
|
+
@arbitrary_lines << line.to_s
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
169
|
+
# Sends the GNUPLOT data and commands to +io+.
|
170
|
+
def to_gplot(io = io)
|
171
|
+
to_plot(io) { |ds| ds.to_gplot(io) }
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
def to_plot(io)
|
177
|
+
return unless io
|
178
|
+
|
179
|
+
@sets.each { |var, val| io << "set #{var} #{val}\n" }
|
180
|
+
@arbitrary_lines.each { |line| io << line << "\n" }
|
181
|
+
|
182
|
+
unless @data.empty?
|
183
|
+
io << @cmd
|
184
|
+
io << ' '
|
185
|
+
io << @data.map { |e| e.plot_args }.compact.join(', ')
|
186
|
+
io << "\n"
|
187
|
+
|
188
|
+
@data.each { |ds| io << "e\n" if yield ds } if block_given?
|
189
|
+
end
|
190
|
+
|
191
|
+
io
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
class SPlot < Plot
|
197
|
+
|
198
|
+
def initialize(io = nil, cmd = 'splot')
|
199
|
+
super
|
200
|
+
end
|
201
|
+
|
202
|
+
# Sends the GNUPLOT data and commands to +io+.
|
203
|
+
def to_gplot(io = io)
|
204
|
+
to_plot(io) { |ds| ds.to_gsplot(io) }
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
# Container for a single data set being displayed by GNUPLOT. Each object
|
210
|
+
# has a reference to the actual data being plotted as well as settings that
|
211
|
+
# control the +plot+ command. The data object must support the +to_gplot+
|
212
|
+
# command.
|
213
|
+
#
|
214
|
+
# The other attributes correspond to their related string in the GNUPLOT
|
215
|
+
# command. See the {GNUPLOT documentation}[http://gnuplot.sourceforge.net/documentation.html]
|
216
|
+
# for more information on this.
|
217
|
+
|
218
|
+
class DataSet
|
219
|
+
|
220
|
+
attr_accessor :data, :title, :with, :using, :linewidth, :matrix, :smooth, :axes
|
221
|
+
|
222
|
+
def initialize(data = nil)
|
223
|
+
@data = data
|
224
|
+
yield self if block_given?
|
225
|
+
end
|
226
|
+
|
227
|
+
# Set no title.
|
228
|
+
def notitle
|
229
|
+
@title = 'notitle'
|
230
|
+
end
|
231
|
+
|
232
|
+
# Write the plot arguments to +io+.
|
233
|
+
def plot_args(io = '')
|
234
|
+
# Order of these is important or GNUPLOT barfs on 'em
|
235
|
+
%w[data using axes title matrix smooth with linewidth].each { |arg|
|
236
|
+
plot_arg(io, arg)
|
237
|
+
}
|
238
|
+
|
239
|
+
io
|
240
|
+
end
|
241
|
+
|
242
|
+
# Write the plot data to +io+.
|
243
|
+
def to_gplot(io = '')
|
244
|
+
@data.to_gplot(io) if plot?
|
245
|
+
end
|
246
|
+
|
247
|
+
# Write the splot data to +io+.
|
248
|
+
def to_gsplot(io = '')
|
249
|
+
@data.to_gsplot(io) if plot?
|
250
|
+
end
|
251
|
+
|
252
|
+
private
|
253
|
+
|
254
|
+
def plot_arg(io, arg)
|
255
|
+
var = "@#{arg}"
|
256
|
+
val = instance_variable_get(var) if instance_variable_defined?(var)
|
257
|
+
|
258
|
+
case arg
|
259
|
+
when 'data'
|
260
|
+
io << (val.is_a?(String) ? val : "'-'")
|
261
|
+
when 'title'
|
262
|
+
io << (val =~ /notitle/ ? ' notitle' : " title '#{val}'") if val
|
263
|
+
when 'matrix'
|
264
|
+
io << ' matrix' if val
|
265
|
+
else
|
266
|
+
io << " #{arg} #{val}" if val
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def plot?
|
271
|
+
@data && !@data.is_a?(String)
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
end
|
277
|
+
|
278
|
+
class Array
|
279
|
+
|
280
|
+
# Write GNUPLOT plot data to +io+.
|
281
|
+
def to_gplot(io = '')
|
282
|
+
case x = self[0]
|
283
|
+
when Array
|
284
|
+
x.zip(*self[1..-1]).each { |a| io << a.join(' ') << "\n" }
|
285
|
+
io << 'e'
|
286
|
+
when Numeric then each { |i| io << "#{i}\n" }
|
287
|
+
else x.zip(*self[1..-1]).to_gplot(io)
|
288
|
+
end
|
289
|
+
|
290
|
+
io
|
291
|
+
end
|
292
|
+
|
293
|
+
# Write GNUPLOT splot data to +io+.
|
294
|
+
def to_gsplot(io = '')
|
295
|
+
case x = self[0]
|
296
|
+
when Array
|
297
|
+
y, d = values_at(1, 2)
|
298
|
+
|
299
|
+
x.each_with_index { |xv, i|
|
300
|
+
y.each_with_index { |yv, j|
|
301
|
+
io << [xv, yv, d[i][j]].join(' ') << "\n"
|
302
|
+
}
|
303
|
+
}
|
304
|
+
|
305
|
+
io
|
306
|
+
when Numeric then each { |i| io << "#{i}\n" }
|
307
|
+
else x.zip(*self[1..-1]).to_gsplot(io)
|
308
|
+
end
|
309
|
+
|
310
|
+
io
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
class Matrix
|
316
|
+
|
317
|
+
# Write GNUPLOT plot data to +io+.
|
318
|
+
def to_gplot(io = '', xgrid = nil, ygrid = nil)
|
319
|
+
xgrid ||= (0...column_size).to_a
|
320
|
+
ygrid ||= (0...row_size).to_a
|
321
|
+
|
322
|
+
ygrid.each_with_index { |y, j|
|
323
|
+
xgrid.each_with_index { |x, i|
|
324
|
+
z = self[j, i]
|
325
|
+
io << "#{x} #{y} #{z}\n" if z
|
326
|
+
}
|
327
|
+
}
|
328
|
+
|
329
|
+
io
|
330
|
+
end
|
331
|
+
|
332
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'gnuplot'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class StdDataTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_array_1d
|
7
|
+
data = (0..5).to_a
|
8
|
+
ds = Gnuplot::DataSet.new(data)
|
9
|
+
|
10
|
+
assert data == ds.data
|
11
|
+
assert data.join("\n") + "\n", ds.to_gplot
|
12
|
+
end
|
13
|
+
|
14
|
+
# Test a multidimensional array.
|
15
|
+
|
16
|
+
def test_array_nd
|
17
|
+
d1 = (0..3).to_a
|
18
|
+
d2 = d1.map { |v| 3 * v }
|
19
|
+
d3 = d2.map { |v| 4 * v }
|
20
|
+
|
21
|
+
data = [d1, d2, d3]
|
22
|
+
ds = Gnuplot::DataSet.new(data)
|
23
|
+
|
24
|
+
assert data == ds.data
|
25
|
+
assert "0 0 0\n1 3 12\n2 6 24\n3 9 36\n", ds.to_gplot
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class DataSetTest < Test::Unit::TestCase
|
31
|
+
|
32
|
+
def test_yield_ctor
|
33
|
+
ds = Gnuplot::DataSet.new { |ds|
|
34
|
+
ds.with = 'lines'
|
35
|
+
ds.using = '1:2'
|
36
|
+
ds.data = [[0, 1, 2], [1, 2, 5]]
|
37
|
+
}
|
38
|
+
|
39
|
+
assert 'lines', ds.with
|
40
|
+
assert '1:2', ds.using
|
41
|
+
|
42
|
+
assert nil == ds.title
|
43
|
+
assert [[0, 1, 2], [1, 2, 5]] == ds.data
|
44
|
+
|
45
|
+
assert "''-' using 1:2 with lines", ds.plot_args
|
46
|
+
assert "0 1\n1 2\n2 5\n", ds.to_gplot
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
class PlotTest < Test::Unit::TestCase
|
52
|
+
|
53
|
+
def test_no_data
|
54
|
+
plot = Gnuplot::Plot.new { |p|
|
55
|
+
p.set 'output', "'foo'"
|
56
|
+
p.set 'terminal', 'postscript enhanced'
|
57
|
+
}
|
58
|
+
|
59
|
+
assert plot.sets == [
|
60
|
+
['output', "'foo'"],
|
61
|
+
['terminal', 'postscript enhanced']
|
62
|
+
]
|
63
|
+
|
64
|
+
assert plot.to_gplot, "set output 'foo'\nset terminal postscript enhanced\n"
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_set
|
68
|
+
plot = Gnuplot::Plot.new { |gp| gp.set 'title', 'foo' }
|
69
|
+
assert "'foo'", plot['title']
|
70
|
+
|
71
|
+
plot.set 'title', "'bar'"
|
72
|
+
assert "'bar'", plot['title']
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
require 'rbconfig'
|
78
|
+
CONFIG = Config::MAKEFILE_CONFIG
|
79
|
+
|
80
|
+
# This attempts to test the functions that comprise the gnuplot package. Most
|
81
|
+
# of the bug reports that I get for this package have to do with finding the
|
82
|
+
# gnuplot executable under different environments so that makes it difficult
|
83
|
+
# to test on a single environment. To try to get around this I'm using the
|
84
|
+
# rbconfig library and its path to the sh environment variable.
|
85
|
+
|
86
|
+
class GnuplotModuleTest < Test::Unit::TestCase
|
87
|
+
|
88
|
+
def test_which
|
89
|
+
# Put the spaces around the command to make sure that it gets stripped
|
90
|
+
# properly.
|
91
|
+
assert CONFIG['SHELL'], Gnuplot.which(' sh ')
|
92
|
+
assert CONFIG['SHELL'], Gnuplot.which(CONFIG['SHELL'])
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_gnuplot
|
96
|
+
cmd = Gnuplot.gnuplot
|
97
|
+
assert Gnuplot.which('gnuplot') + ' -persist', cmd
|
98
|
+
|
99
|
+
cmd = Gnuplot.gnuplot(false)
|
100
|
+
assert Gnuplot.which('gnuplot'), cmd
|
101
|
+
|
102
|
+
# If I set the name of the gnuplot environment variable to a different
|
103
|
+
# name (one that is in the path) then I should get the shell name as the
|
104
|
+
# result of the gnuplot call.
|
105
|
+
|
106
|
+
ENV['RB_GNUPLOT'] = 'sh'
|
107
|
+
assert CONFIG['SHELL'], Gnuplot.gnuplot(false)
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: blackwinter-gnuplot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 97
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 2
|
8
|
+
- 3
|
9
|
+
- 5
|
10
|
+
- 1
|
11
|
+
version: 2.3.5.1
|
12
|
+
platform: ruby
|
13
|
+
authors:
|
14
|
+
- Roger Pack
|
15
|
+
- Jens Wille
|
16
|
+
autorequire:
|
17
|
+
bindir: bin
|
18
|
+
cert_chain: []
|
19
|
+
|
20
|
+
date: 2011-02-22 00:00:00 +01:00
|
21
|
+
default_executable:
|
22
|
+
dependencies:
|
23
|
+
- !ruby/object:Gem::Dependency
|
24
|
+
name: ruby-nuggets
|
25
|
+
prerelease: false
|
26
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
hash: 3
|
32
|
+
segments:
|
33
|
+
- 0
|
34
|
+
version: "0"
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
description:
|
38
|
+
email:
|
39
|
+
- rogerpack2005@gmail.com
|
40
|
+
- jens.wille@uni-koeln.de
|
41
|
+
executables: []
|
42
|
+
|
43
|
+
extensions: []
|
44
|
+
|
45
|
+
extra_rdoc_files:
|
46
|
+
- ChangeLog
|
47
|
+
- LICENSE.txt
|
48
|
+
- README.rdoc
|
49
|
+
files:
|
50
|
+
- AUTHORS.txt
|
51
|
+
- ChangeLog
|
52
|
+
- LICENSE.txt
|
53
|
+
- README.rdoc
|
54
|
+
- Rakefile
|
55
|
+
- examples/.gitignore
|
56
|
+
- examples/discrete_points.rb
|
57
|
+
- examples/histogram.rb
|
58
|
+
- examples/multiple_data_sets.rb
|
59
|
+
- examples/output_file1.rb
|
60
|
+
- examples/output_file2.rb
|
61
|
+
- examples/sine_wave.rb
|
62
|
+
- lib/gnuplot.rb
|
63
|
+
- lib/gnuplot/version.rb
|
64
|
+
- test/test_gnuplot.rb
|
65
|
+
has_rdoc: true
|
66
|
+
homepage: http://github.com/blackwinter/ruby_gnuplot
|
67
|
+
licenses: []
|
68
|
+
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 3
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
requirements: []
|
93
|
+
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 1.5.2
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: Utility library to aid in interacting with GNUPLOT
|
99
|
+
test_files:
|
100
|
+
- examples/discrete_points.rb
|
101
|
+
- examples/histogram.rb
|
102
|
+
- examples/multiple_data_sets.rb
|
103
|
+
- examples/output_file1.rb
|
104
|
+
- examples/output_file2.rb
|
105
|
+
- examples/sine_wave.rb
|
106
|
+
- test/test_gnuplot.rb
|