blackwinter-gnuplot 2.3.5.1
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/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
|