numplot 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2d354b2cc2c06f15dfb5130ea2ee5c48f1f157f2
4
+ data.tar.gz: 04ddb3b2c06dc8f02b43d9920b019df571abc151
5
+ SHA512:
6
+ metadata.gz: 7aad96c6901b48822dcc03bc3ae5dd6bc2f0c90e5662c3dab090295d553096e9a08321e56b050bbdac9586f0265646a66ee885b6a5045c033bb213e1d768a444
7
+ data.tar.gz: e9acde2f4a6165047da57a44de4f223a751a89c084d284fe7508f2467fffcf81ee598d64897f812517483a95c749976b94fa0decbd22813d3f3597b81156867d
@@ -0,0 +1,83 @@
1
+
2
+ module NumPlot
3
+ # The class handling options on gnuplot command.
4
+ # @!visibility private
5
+ class Option
6
+ def initialize(name, converter, aliases)
7
+ @name = name
8
+ @converter = converter
9
+ @aliases = aliases
10
+ end
11
+
12
+ def plot_arg(h)
13
+ ([@name] + @aliases).each do |key|
14
+ if h.has_key? (key)
15
+ return " #{@name} #{@converter[h[key]]}"
16
+ end
17
+ end
18
+
19
+ ""
20
+ end
21
+
22
+ def self.[](name, *aliases)
23
+ new(name, proc{|x| x }, aliases)
24
+ end
25
+ end
26
+
27
+ # The class handling color options on gnuplot command.
28
+ # @!visibility private
29
+ class ColorOption < Option
30
+ def self.[](name, *aliases)
31
+ new(name, Conversion.method(:convert_color), aliases)
32
+ end
33
+ end
34
+
35
+ # The class handling font options on gnuplot command.
36
+ # @!visibility private
37
+ class FontOption < Option
38
+ def self.[](name, *aliases)
39
+ new(name, Conversion.method(:convert_font), aliases)
40
+ end
41
+ end
42
+
43
+ # The class handling on/off options on gnuplot command.
44
+ # @!visibility private
45
+ class BoolOption
46
+ def initialize(name, *aliases)
47
+ @name = name; @aliases = aliases
48
+ end
49
+
50
+ def plot_arg(h)
51
+ ([@name] + @aliases).each do |key|
52
+ return " #{@name}" if h.has_key?(key)
53
+ end
54
+
55
+ ""
56
+ end
57
+
58
+ class << self
59
+ alias [] new
60
+ end
61
+ end
62
+
63
+ # The class handling XXX/noXXX options on gnuplot command
64
+ # @!visibility private
65
+ class YesNoOption
66
+ def initialize(name)
67
+ @name = name
68
+ @no_name = "no#{name}".intern
69
+ end
70
+
71
+ def plot_arg(h)
72
+ return " #{@name}" if h.has_key?(@name) && h[@name]
73
+ return " #{@name}" if h.has_key?(@no_name) && !h[@no_name]
74
+ return " #{@no_name}" if h.has_key?(@no_name) && h[@no_name]
75
+ return " #{@no_name}" if h.has_key?(@name) && !h[@name]
76
+ ""
77
+ end
78
+
79
+ class << self
80
+ alias [] new
81
+ end
82
+ end
83
+ end
data/lib/numplot.rb ADDED
@@ -0,0 +1,667 @@
1
+ require 'numplot/option'
2
+
3
+ require 'set'
4
+
5
+ # Call the given block once.
6
+ # This method is used to make yard to ignore the code in a block.
7
+ def __yard_ignore_here; yield; end
8
+
9
+ # A module wrapping gnuplot {http://www.gnuplot.info/}.
10
+ module NumPlot
11
+ # The collection of methods converting ruby objects to gnuplot strings.
12
+ #
13
+ # @!visibility private
14
+ module Conversion
15
+ module_function
16
+
17
+ def convert_range(range)
18
+ case range
19
+ when String then range
20
+ when Range then "[#{range.begin}:#{range.end}]"
21
+ when Array
22
+ if range.size != 2
23
+ raise TypeError, "Cannot convert #{range.inspect} to gnuplot's range"
24
+ end
25
+ "[#{range[0]}:#{range[1]}]"
26
+ else
27
+ raise TypeError, "Cannot convert #{range.inspect} to gnuplot's range"
28
+ end
29
+ end
30
+
31
+ def convert_color(color)
32
+ case color
33
+ when RGB then color.to_gnuplot_string
34
+ when String, Integer then color
35
+ else
36
+ raise TypeError, "Cannot convert #{color.inspect} to gnuplot's color"
37
+ end
38
+ end
39
+
40
+ def convert_font(font)
41
+ case font
42
+ when String then font
43
+ when Font then font.to_gnuplot_string
44
+ else
45
+ raise TypeError, "Cannot convert #{font.inspect} to gnuplot's font"
46
+ end
47
+ end
48
+
49
+ def quote(str)
50
+ "\"#{str}\""
51
+ end
52
+ end
53
+
54
+ # The class representing colors in gnuplot.
55
+ #
56
+ # You can use three types of color specifications like the following
57
+ # examples.
58
+ #
59
+ # Example:
60
+ # RGB[255, 0, 0] # => Red
61
+ # RGB["#00ff00"] # => Green
62
+ # RGB["blue"] # => blue
63
+ #
64
+ class RGB
65
+ # Create a new instance of RGB class.
66
+ #
67
+ # You can give three styles of arguments to specify a color.
68
+ # * an RGB component as three integers like NumPlot::RGB.new(0, 255, 0)
69
+ # * a "#xxyyzz" style string like NumPlot::RGB.new("#ff007f")
70
+ # * a string of the name of a color like NumPlot::RGB.new("blue")
71
+ def initialize(*args)
72
+ if args.size == 1 && String === args[0]
73
+ @s = args[0]
74
+ elsif args.size == 3
75
+ @s = "#%02x%02x%02x" % args
76
+ else
77
+ raise TypeError, "Unknown color format: #{args.inspect}"
78
+ end
79
+ end
80
+
81
+ # Convert self to gnuplot "rgbcolor" string.
82
+ # @visibility private
83
+ def to_gnuplot_string
84
+ "rgbcolor \"#{@s}\""
85
+ end
86
+
87
+ class << self
88
+ # @method [](*args)
89
+ # Create a new RGB object. See {#initialize}.
90
+ # @return [RGB] A new RGB object
91
+ __yard_ignore_here{ alias [] new }
92
+ end
93
+ end
94
+
95
+ # The class representing a font in gnuplot.
96
+ #
97
+ # Example:
98
+ # Font["ariel"] # ariel font, default size
99
+ # Font["ariel", 12] # ariel font, the size is 12 point
100
+ class Font
101
+ # Create a new Font object.
102
+ # @param fontname[String] the name of font
103
+ # @param size[String, nil] the size of font, nil to default
104
+ # @example
105
+ # Font.new("ariel") # ariel font, default size
106
+ # Font.new("ariel", 12) # ariel font, the size is 12 point
107
+ def initialize(fontname, size=nil)
108
+ @s = size ? "#{fontname},#{size}" : fontname
109
+ end
110
+
111
+ # Convert self to gnuplot font (quoted) string.
112
+ # @visibility private
113
+ def to_gnuplot_string
114
+ "\"#{@s}\""
115
+ end
116
+
117
+ class << self
118
+ # @!method [](fontname, size=nil)
119
+ # Create a new Font object. See {#initialize}.
120
+ # @return [Font] A new Font object
121
+ __yard_ignore_here{ alias [] new }
122
+ end
123
+ end
124
+
125
+ # The class communicating a gnuplot subprocess.
126
+ #
127
+ # In many cases, you use {Plotter#plot} and you don't need to use
128
+ # this class directly.
129
+ class Process
130
+ # Create a Process object for already opened pipe.
131
+ # Normally, you had better to use {.open} to create a new object.
132
+ # @param pipe a pipe to communicate to a subprocess
133
+ # @param wait wait for the output from a subprocess
134
+ def initialize(pipe, wait)
135
+ @pipe = pipe
136
+ @wait = wait
137
+ @output = nil
138
+ end
139
+
140
+ # Output string from a gnuplot subprocess.
141
+ # @return [String, nil]
142
+ attr_reader :output
143
+
144
+ # Close the pipe and terminate the subprocess.
145
+ #
146
+ # If you specify wait=true when the object is constructed,
147
+ # @return [void]
148
+ def close
149
+ if @wait
150
+ @pipe.close_write
151
+ @output = @pipe.read
152
+ @pipe.close
153
+ else
154
+ @pipe.close
155
+ end
156
+ end
157
+
158
+ # Write +str+ to the subprocess.
159
+ # @return [void]
160
+ def write(str)
161
+ @pipe.write(str)
162
+ end
163
+
164
+ # Write +str+ and a newline to the subprocess
165
+ # @return [void]
166
+ def puts(str)
167
+ @pipe.puts(str)
168
+ end
169
+
170
+ # Open a gnuplot process.
171
+ #
172
+ # If a block is given, the block is invoked with the opened
173
+ # Process object. Otherwise, opened Process object is returned.
174
+ # If you give true as +persist+, -persist option is added to the
175
+ # command line of gnuplot.
176
+ # @param persist add -persist option to gnuplot as a command line option
177
+ # @param waiting wait for termination of stdout of gnuplot pipe
178
+ # @param name the name of the gnuplot executable file
179
+ def self.open(persist=true, waiting=true, name="gnuplot")
180
+ pr = new(IO.popen(command(name, persist), "w+"), waiting)
181
+
182
+ if block_given?
183
+ begin
184
+ yield pr
185
+ ensure
186
+ pr.close
187
+ end
188
+ return pr.output
189
+ else
190
+ return pr
191
+ end
192
+ end
193
+
194
+ # Return a command line string to invoke a subprocess.
195
+ # @!visibility private
196
+ def self.command(name, persist)
197
+ name += " -persist" if persist
198
+ name
199
+ end
200
+ end
201
+
202
+ # The plotter class.
203
+ # To plot something, you need to create a Plotter object,
204
+ # set parameters to the object, add data sets to the object,
205
+ # and call {#plot} as in the example below.
206
+ # @example
207
+ # # An array of data to plot
208
+ # data = -2.0.step(2.0, 0.05).map{|x| [x, Math.sin(x)]}
209
+ # # Create a new Plotter object
210
+ # plotter = NumPlot::Plotter.new
211
+ # # Set parameters
212
+ # plotter.set("term", "png")
213
+ # plotter.set("output", "\"sin.png\"") # Need to quote
214
+ # plotter.xrange -2.0 .. 2.0
215
+ # # Set datasets
216
+ # plotter.datasets << NumPlot::Dataset.rows(data, title: "sin(x)", with: line)
217
+ # # Plot (output to sin.png)
218
+ # plotter.plot
219
+ class Plotter
220
+ include Conversion
221
+
222
+ # Create a new Plotter object.
223
+ # You can specifiy the plot command (plot/splot)
224
+ # by plot_command parameter.
225
+ # @param plot_command[String] "plot" or "splot"
226
+ def initialize(plot_command = "plot")
227
+ @plot_command = plot_command
228
+ @commands = []
229
+ @datasets = []
230
+ end
231
+
232
+ # An array of all data sets.
233
+ # @deprecated
234
+ # @return [Array]
235
+ attr_reader :datasets
236
+
237
+ # Add a command string to the list of commands.
238
+ # The commands are executed when {#plot} is called.
239
+ # @param command[String] a command to add
240
+ # @return [self]
241
+ def add_command(command)
242
+ @commands << command
243
+ self
244
+ end
245
+ private :add_command
246
+
247
+ # Gnuplot "set" command.
248
+ # This method is generic, but
249
+ # you can use some useful methods like {#xrange} and {#xlabel} for
250
+ # "set" command.
251
+ # @param key[String]
252
+ # the first argument for gnuplot "set" command like "term", "output".
253
+ # @param values[Array<String>] the rest arguments for gnuplot "set" command
254
+ # @return [self]
255
+ def set(key, *values)
256
+ add_command("set #{key} #{values.join(' ')}")
257
+ end
258
+
259
+ # Gnuplot "unset" command.
260
+ # @param key[String]
261
+ # the first argument for gnuplot "unset" command
262
+ # @param values[Array<String>] the rest arguments for gnuplot "unset" command
263
+ # @see #set
264
+ # @return [self]
265
+ def unset(key, *values)
266
+ add_command("unset #{key} #{values.join(' ')}")
267
+ end
268
+
269
+ # Add a dataset to the plotter.
270
+ # @param dataset[Dataset] a dataset
271
+ # @return [self]
272
+ def add_dataset(dataset)
273
+ @datasets << dataset
274
+ self
275
+ end
276
+
277
+ alias << add_dataset
278
+
279
+ # @!macro [new] range
280
+ # @overload $0(range, *opts)
281
+ # Set $0 parameter.
282
+ # You can specify the range with one of three styles.
283
+ # * a string such as: "[-1.0:1.0]" or "[:2.0]"
284
+ # * a range such as: -1.0 .. 1.0 or -Float::INFINITY .. 2.0
285
+ # * an array such as: [-1.0, 1.0] or [nil, 2.0]
286
+ # You can also specify the following options as args:
287
+ # * "reverse"
288
+ # * "no reverse"
289
+ # * "writeback"
290
+ # * "no writeback"
291
+ # @param range[String,Range,Array] the range of x axis
292
+ # @param opts[Array<String>] options
293
+ # @return [self]
294
+
295
+ # @macro range
296
+ def xrange(*args); _range("xrange", *args); end
297
+ # @macro range
298
+ def yrange(*args); _range("yrange", *args); end
299
+ # @macro range
300
+ def zrange(*args); _range("zrange", *args); end
301
+ # @macro range
302
+ def x2range(*args); _range("x2range", *args); end
303
+ # @macro range
304
+ def y2range(*args); _range("y2range", *args); end
305
+
306
+ def _range(type, r, opts={})
307
+ gnuplot_options = ""
308
+ RANGE_OPTIONS.each do |opt|
309
+ gnuplot_options << opt.plot_arg(opts)
310
+ end
311
+
312
+ set(type, convert_range(r), gnuplot_options)
313
+ end
314
+ private :_range
315
+
316
+ # @!visibility private
317
+ RANGE_OPTIONS = [YesNoOption[:reverse], YesNoOption[:writeback]]
318
+
319
+ # @!macro [new] label
320
+ # @overload $0(label, opts={})
321
+ # Set $0 parameter.
322
+ # You can specify the following options as a hash:
323
+ # * offset: OFFSET
324
+ # * font: FONT
325
+ # * textcolor: COLOR (tc: is also available)
326
+ # * enhanced: true OR noenhanced: true
327
+ # * rotate: (TODO: FIX IT) OR norotate: true
328
+ # @param label[String] label string
329
+ # @param opts[{Symbol => Object}] options
330
+ # @return [self]
331
+
332
+ # @macro label
333
+ def xlabel(*args); _label("xlabel", *args); end
334
+ # @macro label
335
+ def ylabel(*args); _label("ylabel", *args); end
336
+ # @macro label
337
+ def zlabel(*args); _label("zlabel", *args); end
338
+ # @macro label
339
+ def x2label(*args); _label("x2label", *args); end
340
+ # @macro label
341
+ def y2label(*args); _label("y2label", *args); end
342
+
343
+ def _label(type, *args)
344
+ set(type, LabelParser.parse(*args))
345
+ end
346
+ private :_label
347
+
348
+ # Plot given datasets with given parameters.
349
+ # @overload plot(opts={})
350
+ # Open a gnuplot process and write commands and data to the process.
351
+ # You get the result of plotting on a window or an image file
352
+ #
353
+ # You can specify the following options:
354
+ # * :persist - Add -persist to gnuplot command.
355
+ # The default value is true.
356
+ # * :waiting - Wait a gnuplot process to be terminate.
357
+ # The default value is true. If this value is true and
358
+ # the diagram is drawed on a new window, the ruby program
359
+ # is stopped until the window is closed. On the other hand,
360
+ # if this value is false, the ruby program continue
361
+ # although the window remains opened.
362
+ # * :gnuplot_command - gnuplot command name.
363
+ #
364
+ # @param opts options
365
+ # @return [void]
366
+ #
367
+ # @overload plot(io)
368
+ # Output all commands and data to IO object.
369
+ #
370
+ # Normally, you specify {Process} object as io.
371
+ # For debug use, you can specify the StringIO object as io.
372
+ #
373
+ # @param io[#write, #puts] output target
374
+ # @return [void]
375
+ def plot(arg={})
376
+
377
+ if Hash === arg
378
+ Process.open(arg.fetch(:persist, true),
379
+ arg.fetch(:waiting, true),
380
+ arg.fetch(:gnuplot_command, "gnuplot")) do |pr|
381
+ plot_to_io(pr)
382
+ end
383
+ else
384
+ plot_to_io(arg)
385
+ end
386
+ end
387
+
388
+ # Output all commands and data to IO object.
389
+ def plot_to_io(pr)
390
+ @commands.each{|cmd| pr.puts(cmd) }
391
+ pr.write(@plot_command)
392
+ pr.write(" ")
393
+ pr.write(@datasets.map{|e| e.to_plot_arg }.join(", "))
394
+ pr.write("\n")
395
+ pr.write(@datasets.map{|e| e.to_plot_dataset }.compact.join("e\n"))
396
+ end
397
+ private :plot_to_io
398
+ end
399
+
400
+ # The dataset class plotted by {Plotter}.
401
+ #
402
+ # You can construct a dataset object using one of the following three methods:
403
+ # * {.columns}: construct a dataset from columns
404
+ # * {.rows}: construct a dataset from rows
405
+ # * {.histogram}: construct a histogram dataset
406
+ #
407
+ # You need to choose from {.columns} and {.rows} according to
408
+ # the arrangement of your data.
409
+ #
410
+ # The dataset object is registered to {Plotter} object using
411
+ # {Plotter#add_dataset}.
412
+ #
413
+ # == Parameters for a dataset
414
+ # When you call {.columns}, {.rows}, or {.histogram},
415
+ # you can give some parameters to determine the style of
416
+ # plotting.
417
+ # The parameters are as follows. If you know the details
418
+ # of these parameters, please read the gnuplot documents.
419
+ # * title: "TITLE" or notitle: true
420
+ # * with: "points", "dots", etc.
421
+ # * axis:
422
+ # * linestyle: a style number (ls: is also available)
423
+ # * linetype: a line type number
424
+ # * linewidth: a line width multiplier (default is 1.0),
425
+ # (lw: is also available)
426
+ # * linecolor: a color number or an {RGB} object.
427
+ # (lc: is also available)
428
+ # * pointtype: a point type number (pt: is also available)
429
+ # * pointsize: a point size multiplier (default is 1.0),
430
+ # (ls: is also available)
431
+ # * fill: a fill style (fs: is also available)
432
+ # * nohidden3d: true if you need to activate this option
433
+ # * nocontours: true if you need to activate this option
434
+ # * nosurface: true if you need to activate this option
435
+ class Dataset
436
+ def initialize(data, opts={})
437
+ @data = data
438
+ @opts = opts
439
+ end
440
+
441
+ # Construct a dataset object form columns.
442
+ #
443
+ # If your data are xs = [x0, x1, x2, ... ] and ys = [y0, y1, y2, ...],
444
+ # you should use this method as:
445
+ # Dataset.columns([xs, ys])
446
+ #
447
+ # If your data is transposed, you need to use {.columns} instead of
448
+ # this method.
449
+ #
450
+ # You can give some parameters as a hash
451
+ # to set a plotting style. Please see
452
+ # {Dataset}.
453
+ # @param data[Enumerable<Enumerable<Numeric>>]
454
+ # @param opts[{Symbol => object}] options
455
+ # @return [Dataset]
456
+ def self.columns(data, opts={})
457
+ new(data.map(&:to_a).transpose, opts)
458
+ end
459
+
460
+ # Construct a dataset object form rows.
461
+ #
462
+ # If your data is [[x0, y0], [x1, y1], ...],
463
+ # you should use this method as:
464
+ # Dataset.rows(data)
465
+ #
466
+ # If your data is transposed, you need to use {.rows} instead of
467
+ # this method.
468
+ #
469
+ # You can give some parameters as a hash
470
+ # to set a plotting style. Please see
471
+ # {Dataset} for details.
472
+ # @param data[Enumerable<Enumerable<Numeric>>]
473
+ # @param opts[{Symbol => object}] options
474
+ # @return [Dataset]
475
+ def self.rows(data, opts={})
476
+ new(data.map(&:to_a), opts)
477
+ end
478
+
479
+
480
+ # Construct a histogram dataset object.
481
+ #
482
+ # You need to give some parameters to construct a histogram.
483
+ # * dim: the dimension of your data, now only 1-dim data is supported
484
+ # (default is 1)
485
+ # * binsize: the bin size (required, Numeric)
486
+ # * base: the coordinate of a left side of a bin (default is 0.0).
487
+ # If binsize = 1.0 and base = 0.0, the bins are
488
+ # ..., [-1.0, 0.0), [0.0, 1.0), ... .
489
+ # If binsize = 1.0 and base = 0.5, the bins are
490
+ # ..., [-1.5, -0.5), [-0.5, 0.5), [0.5, 1.5), ... .
491
+ # * histogram_style: You can choose one of the following normalization
492
+ # scheme:
493
+ # * :count not normalized
494
+ # * :ratio normailized to the number of data points
495
+ # * :density normalized to (the number of data points)*(binsize).
496
+ # You choose this option if you want to show the probability density
497
+ # function from the data.
498
+ # * cumulative: construct a cumulative histogram if true.
499
+ # If the cumulative option is true, the meaning of
500
+ # histogram_style option is changed.
501
+ # * :count not normalized
502
+ # * :ratio, :density normalized by the number of data, this means that
503
+ # the maximum value of a cumulative histogram is normalized to 1.
504
+ #
505
+ # You can also give some other parameters to determine
506
+ # a plotting style. See {Dataset} for details.
507
+ #
508
+ # @example
509
+ # require 'randomext' # install randomext gem
510
+ # # 1000 random samples from the standard normal distribution.
511
+ # rng = Random.new
512
+ # data = Array.new(1000){ rng.standard_normal }
513
+ # datasets = Dataset.histo(data, binsize: 0.1, histogram_style: :density,
514
+ # title: "Random samples from the normal distribution")
515
+ #
516
+ # @param data[Enumerable<Numeric>] a sequence of numbers
517
+ # @param opts[{Symbol => Object}] options
518
+ # @return [Dataset]
519
+ def self.histogram(data, opts={})
520
+ case opts.fetch(:dim, 1)
521
+ when 1
522
+ histo1d(data, opts)
523
+ when 2
524
+ raise NotImplementedError, "Histogram for 2D data is not implemented yet"
525
+ else
526
+ raise ArgumentError, "You can use only 1D or 2D histogram data"
527
+ end
528
+ end
529
+
530
+ # @!visibility private
531
+ def self.histo1d(data, opts)
532
+ binsize = opts.fetch(:binsize).to_f
533
+ basepoint = opts.fetch(:base, 0).to_f
534
+ histo_style = opts.fetch(:histogram_style, :count)
535
+ cumulative = opts.fetch(:cumulative, false)
536
+
537
+ bins = Hash.new(0)
538
+ data.each {|point| bins[bin1d(point, binsize, basepoint)] += 1 }
539
+
540
+ if cumulative
541
+ plotdata = cumulative_1d(bins, histo_style, data.size, binsize)
542
+ else
543
+ plotdata = histogram_plotdata_1d(bins, histo_style, data.size, binsize)
544
+ end
545
+
546
+ opts[:with] ||= "boxes"
547
+ Dataset.rows(plotdata, opts)
548
+ end
549
+
550
+ # @!visibility private
551
+ def self.bin1d(point, binsize, basepoint)
552
+ (point + binsize/2).div(binsize) * binsize
553
+ end
554
+
555
+ # @!visibility private
556
+ def self.histogram_plotdata_1d(bins, style, numdata, binsize)
557
+ r = case style
558
+ when :count then 1.0
559
+ when :ratio then numdata.to_f
560
+ when :density then numdata*binsize
561
+ end
562
+ bins.map{|k, v| [k, v/r, binsize]}
563
+ end
564
+
565
+ # @!visibility private
566
+ def self.cumulative_1d(bins, style, numdata, binsize)
567
+ cumulative_data = []
568
+ bins.sort_by{|k, v| k }.inject(0.0){|sum, (k, v)|
569
+ cumulative_data << [k, sum+v]
570
+ sum + v
571
+ }
572
+ r = case style
573
+ when :count then 1.0
574
+ when :ratio, :density then numdata
575
+ end
576
+ cumulative_data.map{|k, v| [k, v/r, binsize] }
577
+ end
578
+
579
+ private_class_method :bin1d, :histo1d, :histogram_plotdata_1d, :cumulative_1d
580
+
581
+ class << self; alias histo histogram; end
582
+
583
+ # Return a stirng for gnuplot's "plot" or "splot" like "'-' with dots"
584
+ # @return [String]
585
+ # @!visibility private
586
+ def to_plot_arg
587
+ ret = "'-'"
588
+ OPTIONS.each do |opt|
589
+ ret << opt.plot_arg(@opts)
590
+ end
591
+
592
+ ret
593
+ end
594
+
595
+ # Return a string for gnuplot's data like "1 2 3\n4 4 6\ne"
596
+ # @!visibility private
597
+ def to_plot_dataset
598
+ @data.map{|dataline| dataline.join(" ")}.join("\n") + "\ne"
599
+ end
600
+
601
+ # @!visibility private
602
+ class Title
603
+ def plot_arg(h)
604
+ if h[:notitle]
605
+ " notitle"
606
+ elsif h.has_key?(:title)
607
+ " title \'#{h[:title]}\'"
608
+ else
609
+ ""
610
+ end
611
+ end
612
+ end
613
+
614
+ # @!visibility private
615
+ OPTIONS = [Title.new,
616
+ Option[:axis],
617
+ Option[:with],
618
+ Option[:linestyle, :ls],
619
+ Option[:linetype, :lt],
620
+ Option[:linewidth, :lw],
621
+ ColorOption[:linecolor, :lc],
622
+ Option[:pointtype, :pt],
623
+ Option[:pointsize, :ps],
624
+ Option[:fill, :fs],
625
+ BoolOption[:nohidden3d],
626
+ BoolOption[:nocontours],
627
+ BoolOption[:nosurface],
628
+ Option[:palette],
629
+ ]
630
+
631
+
632
+ end
633
+
634
+ # @!visibility private
635
+ class LabelParser
636
+ def self.parse(*args)
637
+ if Hash === args.last
638
+ opts = args.pop
639
+ else
640
+ opts = {}
641
+ end
642
+
643
+ label = args.shift
644
+
645
+ raise ArgumentError, "Unknown label argument #{args.inspect}" if !args.empty?
646
+ raise ArgumentError, "No label text" if label.nil?
647
+
648
+ gnuplot_string = Conversion.quote(label)
649
+
650
+ OPTIONS.each do |opt|
651
+ gnuplot_string << opt.plot_arg(opts)
652
+ end
653
+
654
+ gnuplot_string
655
+ end
656
+
657
+ OPTIONS = [Option[:offset],
658
+ FontOption[:font],
659
+ ColorOption[:textcolor, :tc],
660
+ YesNoOption[:enhanced],
661
+ Option[:rotate],
662
+ BoolOption[:norotate],
663
+ ]
664
+ end
665
+
666
+
667
+ end
data/sample/sample1.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'numplot'
2
+
3
+ # Draw a random sample from the normal distribution (sigma = 0.3)
4
+ # with Box-Muller's method.
5
+ def rand_normal
6
+ x = rand
7
+ y = rand
8
+ Math.sqrt(-2*Math.log(x))*Math.cos(2*Math::PI*y)*0.3
9
+ end
10
+
11
+ plotter = NumPlot::Plotter.new
12
+
13
+ x_sin_pi_x = (-1.0 .. 1.0).step(0.05).map{|x| [x, Math.sin(Math::PI*x)] }
14
+ plotter <<
15
+ NumPlot::Dataset.rows(x_sin_pi_x, with: "points", title: "sin(x)")
16
+
17
+ xs = (0.0 .. 1.0).step(0.05)
18
+ squares = xs.map{|x| x**2 }
19
+ plotter <<
20
+ NumPlot::Dataset.columns([xs, squares], with: "lines", title: "x^2")
21
+
22
+ normal_random_dist = Array.new(10000){ rand_normal }
23
+ plotter <<
24
+ NumPlot::Dataset.histo(normal_random_dist,
25
+ binsize: 0.1, histogram_style: :density,
26
+ title: "a normal distribution")
27
+
28
+ plotter.xrange(-1.0 .. 1.0)
29
+ plotter.xlabel("x", font: NumPlot::Font["ariel", 12])
30
+ plotter.ylabel("y", font: NumPlot::Font["ariel"])
31
+
32
+ plotter.set("key", "below")
33
+
34
+ plotter.plot
data/test/run_test.rb ADDED
@@ -0,0 +1,5 @@
1
+ testdir = File.dirname(__FILE__)
2
+ Dir.glob("#{testdir}/**/test_*.rb") do |dir|
3
+ load dir
4
+ end
5
+
@@ -0,0 +1,14 @@
1
+ require 'numplot'
2
+
3
+ require 'test-unit'
4
+
5
+ class TestRGB < Test::Unit::TestCase
6
+ include NumPlot
7
+
8
+ def test_s_parse
9
+ assert_equal("\"foo\"", LabelParser.parse("foo"))
10
+ assert_equal("\"foo\" offset 32 font \"bar,14\"",
11
+ LabelParser.parse("foo", offset: 32, font: Font["bar",14]))
12
+
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ require 'numplot'
2
+
3
+ require 'test-unit'
4
+
5
+ class TestYesNoOption < Test::Unit::TestCase
6
+ include NumPlot
7
+
8
+ def test_plot_arg
9
+ assert_equal("", YesNoOption[:foo].plot_arg({}))
10
+ assert_equal("", YesNoOption[:foo].plot_arg({bar:true}))
11
+ assert_equal(" foo",
12
+ YesNoOption[:foo].plot_arg({bar:true, foo:true}))
13
+ assert_equal(" nofoo",
14
+ YesNoOption[:foo].plot_arg({bar:true, foo:false}))
15
+ assert_equal(" nofoo",
16
+ YesNoOption[:foo].plot_arg({bar:true, nofoo:true}))
17
+ assert_equal(" foo",
18
+ YesNoOption[:foo].plot_arg({bar:true, nofoo:false}))
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ require 'numplot'
2
+
3
+ require 'test-unit'
4
+ require 'stringio'
5
+
6
+ class TestRGB < Test::Unit::TestCase
7
+ include NumPlot
8
+
9
+ def test_xrange
10
+ strio = StringIO.new
11
+ Plotter.new.xrange(1 .. 2, noreverse: false, nowriteback: true).plot(strio)
12
+ assert_equal("set xrange [1:2] reverse nowriteback\nplot \n", strio.string)
13
+ end
14
+ end
data/test/test_rgb.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'numplot'
2
+
3
+ require 'test-unit'
4
+
5
+ class TestRGB < Test::Unit::TestCase
6
+ include NumPlot
7
+
8
+ def test_to_gnuplot_string
9
+ assert_equal("rgbcolor \"black\"", RGB["black"].to_gnuplot_string)
10
+ assert_equal("rgbcolor \"#0f12af\"", RGB["#0f12af"].to_gnuplot_string)
11
+ assert_equal("rgbcolor \"#0f12af\"", RGB[0xf, 0x12, 0xaf].to_gnuplot_string)
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: numplot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Ippei Obayashi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: test-unit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: |
28
+ This library is an wrapper for gnuplot.
29
+ email: ohai@kmc.gr.jp
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/numplot.rb
35
+ - lib/numplot/option.rb
36
+ - sample/sample1.rb
37
+ - test/run_test.rb
38
+ - test/test_labelparser.rb
39
+ - test/test_options.rb
40
+ - test/test_plotter.rb
41
+ - test/test_rgb.rb
42
+ homepage: http://www.kmc.gr.jp
43
+ licenses: []
44
+ metadata: {}
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 2.0.0
62
+ signing_key:
63
+ specification_version: 4
64
+ summary: An wrapper for gnuplot
65
+ test_files: []
66
+ has_rdoc: