Coder Social home page Coder Social logo

ruby_gnuplot's Introduction

Ruby Gnuplot – How To

ChangeLog
Authors
License

History and Background

Gnuplot is a program that has a rich language for the generation of plots. It has a unique place in academia as it was one of the first freely available programs for plot generation. I started using gnuplot over 10 years ago while pursuing my Master’s degree in Physics and have been using it actively ever since. Now rdp maintains it. See also the changelog for more detail.

Pre-requisites and Installation

1. (mac) Install XQuartz from here:

http://xquartz.macosforge.org/landing/

2. Install gnuplot with homebrew (not OS X? install it using your package manager):
brew install gnuplot --with-x11

3. Install gnuplot gem:
gem install gnuplot

Ruby Gnuplot Concepts

Gnuplot has a very simple conceptual model. Calls to Set are made to set parameters and either Plot or Splot is called to generate the actual plot. The dataset to be plotted can be specified in a number of ways, contained in a separate file, generated from a function, read from standard input, or read immediately after the plot command. The object model for the Ruby gnuplot wrapper directly mimics this layout and flow. The following are the standard steps for generating a plot:

1. Instantiate a Plot or Splot object and set parameters by gnuplot variable name.

2. Instantiate DataSet objects and attach Ruby objects containing the data to be plotted to the DataSet. Attach properties that modify the plot command using the modifier name.

3. Send the Plot/Splot object to a Gnuplot instance for plotting.

The Version 2.0 interface makes very heavy use of blocks leading to very readable code.

Gnuplot.open

Instantiates a new Gnuplot process. The path to the executable is
determined on a Unix or MacOSX system using the which command. Windows
users, I have no idea what to do.
If a block is given to the function the opened process is passed into
the block. This mimics the most common usage of the File.open method.

Plot.new

SPlot.new

Create a new Plot or SPlot object. DataSet s are attached to the object
to specify the data and its properties.
If a block is given to the function, the plot object is passed into the
block.

DataSet.new

Associates a Ruby object containing the data to plot with the properties
that will be passed to the plot command for that dataset. Any Ruby
object can be associated with a DataSet as long as it understands the
to_gplot method.

to_gplot

Within Gnuplot, plot data is read in very simple formats. The
to_gplot method is expected to write the data of the object in a format
that is understandable by Gnuplot. One of the many great things about
Ruby is that methods can be added after the original declaration. The
gnuplot module defines the to_gplot method on the following classes:
Array, String, and Matrix.
Simply define a to_gplot method on your own class to tie the class into
gnuplot.

Examples

Simple sin wave

The following example simply plots the value of sin(x) between the
ranges of -10 and 10. A few points to notice:

  • The code uses nested blocks to construct the plot. The newly created object is passed to the block so it can be modified in place.
  • Each of the gnuplot plot variables are modified using the variable name as a method name on the plot object or on the dataset object. The wrapper also takes care of the single quoting that is required on some of the variables like title, ylabel, and xlabel.
  • The plot object simply has an array of @DataSet@s. The constructor initializes this empty array before yielding to the block. This method uses the << operator to add the DataSet to the plot.
  • When the plot block ends, if an IO object is given to the Plot constructor, the plot commands will be written to the IO object. Any object can be passed to the constructor as long as it understands the << operator.
Gnuplot.open do |gp|
  Gnuplot::Plot.new( gp ) do |plot|
  
    plot.xrange "[-10:10]"
    plot.title  "Sin Wave Example"
    plot.xlabel "x"
    plot.ylabel "sin(x)"
    
    plot.data << Gnuplot::DataSet.new( "sin(x)" ) do |ds|
      ds.with = "lines"
      ds.linewidth = 4
    end
    
  end
  
end

Or you can write it out to a file (the above snippet displays the graph, in Linux, but in windows you’d need to write it to a file).

See the file examples/output_image_file.rb.

Plotting discrete points

Array data can be plotted quite easily since @Array@s have a defined to_gplot method.

Simply pass an array of data to the constructor of the DataSet object or set the data property of the DataSet. In this example, because there are two arrays, each array will be a single column of data to the gnuplot process.

Gnuplot.open do |gp|
  Gnuplot::Plot.new( gp ) do |plot|
  
    plot.title  "Array Plot Example"
    plot.xlabel "x"
    plot.ylabel "x^2"
    
    x = (0..50).collect { |v| v.to_f }
    y = x.collect { |v| v ** 2 }

    plot.data << Gnuplot::DataSet.new( [x, y] ) do |ds|
      ds.with = "linespoints"
      ds.notitle
    end
  end
end

Multiple Data Sets

As many data sets as are desired can be attached to a plot. Each of these can have their own plot modifiers. Notice in this example how the data array is explicitly set instead of using the << operator.

Also in this example, the commands are not written to the Gnuplot process but are instead written to a File called gnuplot.dat. This file can later be run directly by a gnuplot process as it contains only the gnuplot commands.

File.open( "gnuplot.dat", "w") do |gp|
  Gnuplot::Plot.new( gp ) do |plot|
  
    plot.xrange "[-10:10]"
    plot.title  "Sin Wave Example"
    plot.ylabel "x"
    plot.xlabel "sin(x)"
    
    x = (0..50).collect { |v| v.to_f }
    y = x.collect { |v| v ** 2 }

    plot.data = [
      Gnuplot::DataSet.new( "sin(x)" ) { |ds|
        ds.with = "lines"
        ds.title = "String function"
    	  ds.linewidth = 4
      },
    
      Gnuplot::DataSet.new( [x, y] ) { |ds|
        ds.with = "linespoints"
        ds.title = "Array data"
      }
    ]

  end
end

Miscellanrous

You can also add arbitrary lines to the output

plot.arbitrary_lines << "set ylabel \"y label\" font \"Helvetica,20\""

See more in the examples folder. Also since this is basically just a wrapper for gnuplot itself, you should be able to do anything that it can do (demos:
http://gnuplot.sourceforge.net/demo_4.4/ )

Security

Note that if you pass any user-controlled strings to the gem, it’s possible for an attacker to run arbitrary commands.

In addition to title, any other graph properties that accept strings should be affected too. they’re all passed to the system command. So only use strings you trust.

ruby_gnuplot's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ruby_gnuplot's Issues

Error: histogram.rb does not want to work

Trying to run the histogram.rb examples (the other work fine by the way)

rb histogram.rb

Error:

ruby_gnuplot-master/lib/gnuplot.rb:204:in `style': wrong number of arguments (given 1, expected 0) (ArgumentError)

The code in question is:

def style &blk
  s = Style.new &blk
  @styles << s
  s
end

Unfortunately I do not know how to fix the above.

Gnuplot and GSL seem to conflict

I'm trying to use Gnuplot in a regular Ruby application (which uses Bundler). When I require "gnuplot", that works fine (it returns true). Unfortunately, the Gnuplot constant does not exist.

One questioner on StackOverflow suggested it's due to gem require order (gnuplot needs to come before gsl). I've tried rearranging my Gemfile in every manner of order (bundler now requires in the user-specified order), but no luck.

How does one use the gnuplot gem when gsl is also being used?

Getting this error gnuplot.rb:219:in `instance_of?': class or module required (TypeError) when running examples.

I have Gnuplot installed on Windows 10 and is on the [path settings].
The gem version is 2.6.2 from a 'gem install gnuplot'

[Running] ruby "c:\Ruby23-x64\lib\ruby\gems\2.3.0\gems\gnuplot-2.6.2\examples\sin_wave.rb"
c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:219:in instance_of?': class or module required (TypeError) from c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:219:in plot_args'
from c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:160:in block in store_datasets' from c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:160:in collect'
from c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:160:in store_datasets' from c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:102:in initialize'
from c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/examples/sin_wave.rb:4:in new' from c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/examples/sin_wave.rb:4:in block in

'
from c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:74:in block in open' from c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:73:in popen'
from c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:73:in open' from c:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/examples/sin_wave.rb:3:in '

[Done] exited with code=1 in 0.708 seconds

That was in VS Code editor.
The command line would be similar but I'll give it to ya.
C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:219:in instance_of?': class or module required (TypeError) from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:219:in plot_args'
from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:160:in block in store_datasets' from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:160:in collect'
from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:160:in store_datasets' from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:102:in initialize'
from sin_wave.rb:4:in new' from sin_wave.rb:4:in block in

'
from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:74:in block in open' from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:73:in popen'
from C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/gnuplot-2.6.2/lib/gnuplot.rb:73:in open' from sin_wave.rb:3:in '

rake fails - no default task

when you run rake, it fails.
EXAMPLE:
$ rake
rake aborted!
Don't know how to build task 'default'
/Users/joenorton/.rvm/gems/ruby-2.1.2-mri/bin/ruby_executable_hooks:15:in eval' /Users/joenorton/.rvm/gems/ruby-2.1.2-mri/bin/ruby_executable_hooks:15:in

'
(See full trace by running task with --trace)

warnings

C:/Ruby/lib/ruby/gems/1.8/gems/gnuplot-2.2/lib/gnuplot.rb:196: warning: instance variable @title not initialized
C:/Ruby/lib/ruby/gems/1.8/gems/gnuplot-2.2/lib/gnuplot.rb:202: warning: instance variable @matrix not initialized
C:/Ruby/lib/ruby/gems/1.8/gems/gnuplot-2.2/lib/gnuplot.rb:204: warning: instance variable @linewidth not initialized
C:/Ruby/lib/ruby/gems/1.8/gems/gnuplot-2.2/lib/gnuplot.rb:202: warning: instance variable @matrix not initialized
C:/Ruby/lib/ruby/gems/1.8/gems/gnuplot-2.2/lib/gnuplot.rb:204: warning: instance variable @linewidth not initialized

Output stream

Is there anyway to output results to something other than a file? I'm looking to take the results into a rails process, cache it and send back the raw data.

Nothing happens when I use the Gnuplot.open idiom

Hi,

If I run your first example, ruby executes the program without error, but nothing happens. If I change Gnuplot.open to File.open and write out the commands instead, I am able to feed them to gnuplot without any problems. When using the Gnuplot.open idiom, and setting the $VERBOSE flag to true, I do get gnuplot command output, but it never launches gnuplot.

Any ideas?

I'm on: Mac OS X 10.6.6, gnuplot 4.4 patchlevel 0 (from Fink), and the GEM version of ruby_gnuplot (gnuplot (2.3.5)).

Thanks,
Dan

Provide support for starting gnuplot process and keep it running

What I mean is, provide support for doing:

gnuplot = Gnuplot.open
....
gnuplot.close

This way you can start gnuplot and have the process running and do multiple graphs from different parts of your code. This avoids starting up a gnuplot process for each plotting operation.

This could be achieved by simply doing:

if (block_given?) IO::popen( cmd, "w") { |io| yield io }
else IO::popen( cmd, "w")

at the openmethod

Real time plot

Hi,
Can I ask please whether I can plot real time data? I have a program which generates data periodically (say every one second), so is it possible to monitor the data on a screen using this gem?
Regards

Axis labels on examples

It looks to me like the axis labels on your examples are backwards.

For example, from sin_wave.rb

plot.xrange "[-10:10]"
plot.title "Sin Wave Example"
plot.ylabel "x"
plot.xlabel "sin(x)"

Here, x has values -10 to 10, but is labeled "sin(x)". I see the same issue in discrete_points, multiple_data_sets, and output_image_file too.

Am I missing something?

Plot attribute ordering not adhering to gnuplot syntax

From the gnuplot manual:
plot {}
{}
{ | {"" {datafile-modifiers}}}
{axes } {} {with <style>}
{, {definitions{,}} ...}

ruby_gnuplot will however put the with attribute into the wrong position, so that when e.g. using the with and smooth attribute at the same time on a dataset fails.

Plotting Float::NAN values.

It happens that the current version of ruby_gnuplot plots NaN data values as equal to the labels, as in

Gnuplot.open do |gp|
  Gnuplot::Plot.new gp do |plot|
    ary =  [ [0, 1, 2, 3], [ Float::NAN ] * 4 ]
    plot.data << Gnuplot::DataSet.new( ary ) { |set| set.with = "linespoints" }
  end
end

This is misleading. It caused me a long debugging session. The gem should warn and not display the NaN values in the chart at all. There should be a special setting on how to handle Float::NAN and Float::INFINITY values, and only when the user sets this setting explicitly should the warning go away. Btw. congrats to writing a great gem.

boris

Read DataSet from file

Hi,

this is more a question than an issue but I cannot fine anything anywhere about it. I want the dataset to be read from a file with two columns. I just do:

plot.data << Gnuplot::DataSet.new("file.dat")

but it seems not to work since it complains when running:

     line 0: undefined variable: data

What should I do to use a data file as input?

Thanks,
Juanpe.

Plotting timeseries data

How can timeseries data best be plotted using this gem?

When using

require 'gnuplot'

Gnuplot.open do |gp|
  Gnuplot::Plot.new(gp) do |plot|
    plot.xdata :time
    plot.timefmt '"%s"'
    plot.format 'x "%H:%m"'

    plot.data << Gnuplot::DataSet.new( [[Time.now, Time.now + 60], [1, 2]] ) do |ds|
      ds.with = "linespoints"
      ds.title = "Howdy"
    end
  end
end

the errors I get are:

gnuplot> plot '-' title 'Howdy' with linespoints
                                                ^
         line 0: Need full using spec for x time data


gnuplot> 2015-11-23 18:46:14 +0100 1
         ^
         line 0: invalid command


gnuplot> 2015-11-23 18:47:14 +0100 2
         ^
         line 0: invalid command

Workaround: add ds.using = '1:2' to the dataset.
Would it be better if this gem includes a default using for each dataset?

See also http://stackoverflow.com/a/18121824/2866660

change the pipe calling the gnuplot command from a write-only to read-write?

Hi!

In Debian, there is this bug report by a user:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=626984
reported also on rubyforge:
http://rubyforge.org/tracker/index.php?func=detail&aid=29177&group_id=173&atid=741
proposing to transform the pipe calling the gnuplot command from write-only to read-write, so that the output of the plot could be stored in a variable.

Here is the relevant part of the patch

--- gnuplot.rb.orig 2005-11-15 03:33:42.000000000 +0100
+++ gnuplot.rb  2011-05-06 23:04:02.000000000 +0200
@@ -56,7 +56,12 @@

   def Gnuplot.open( persist=true )
     cmd = Gnuplot.gnuplot( persist ) or raise 'gnuplot not found'
-    IO::popen( cmd, "w") { |io| yield io }
+    IO::popen( cmd, "w+") { |io|
+      yield io
+      io.close_write
+      @output = io.read
+     }
+    return @output
   end 

the rest is about adding a smooth attribute, but this has already been included.
Would you consider this modification as possible?

Thanks!

Cédric

Plotting vectors

I would like to get this example to work using ruby_gnuplot:

http://stackoverflow.com/questions/16541040/how-do-i-use-gnuplot-to-plot-a-simple-2d-vector-arrow

However, my attempt is not working. I think the problem is, I don't know what Dataset.new does. If this could be fixed, I would like to contribute it to the /examples.

#!/usr/bin/env ruby

require 'gnuplot'

data = [
  [0, 0,  0.5, 0.5],
  [0, 1, -0.5, 0.5],
  [1, 1,  1,   0]
]

Gnuplot.open do |gp|
  Gnuplot::Plot.new(gp) do |plot|
    plot.term   "dumb"
    plot.output "/dev/stderr"

    plot.data << Gnuplot::DataSet.new(data) do |ds|
      ds.using = "1:2:3:4"
      ds.with  = "vectors filled head lw 3"
    end
  end
end

histogram

ruby histogram.rb
/home/user/ruby_gnuplot/lib/gnuplot.rb:204:in style': wrong number of arguments (given 1, expected 0) (ArgumentError) from histogram.rb:7:in block (2 levels) in

'

Outputting plot data to stdout

Hello

I would like this script to output nice ASCII formatted plot data via the 'dumb' terminal to STDOUT, but I can't find a way? In fact, it could also be nice to allow output of raw PNG, PS and PDF data to STDOUT.

#!/usr/bin/env ruby

require 'gnuplot'
require 'pp'

# options = {
#   terminal: "png",
#   title: "Title",
#   xlabel: "X-axis",
#   ylabel: "Y-axis",
#   data_out: "foo.png"
# }

options = {
  terminal: "dumb",
  title: "Title",
  xlabel: "X-axis",
  ylabel: "Y-axis"
}

x = [0, 1, 2, 3]
y = [4, 5, 6, 7]

Gnuplot.open do |gp|
  Gnuplot::Plot.new(gp) do |plot|
    plot.terminal options[:terminal]
    plot.title    options[:title]
    plot.xlabel   options[:xlabel]
    plot.ylabel   options[:ylabel]
    plot.output   options[:data_out] if options[:data_out]
    plot.output   options[:data_out] if options[:data_out]
    plot.logscale "y"                if options[:logscale_y]
    plot.xrange   "[#{x.min - 1}:#{x.max + 1}]"
    plot.style    "fill solid 0.5 border"
    plot.xtics    "out"
    plot.ytics    "out"

    plot.data << Gnuplot::DataSet.new([x, y]) do |ds|
      ds.with = "boxes"
      ds.notitle
    end
  end
end

Capture gnuplot warnings

Is there a mechanism to capture gnuplot warnings such as:

Warning: empty y range [0:0], adjusting to [-1:1]

so that these can be handled in Ruby instead of being output to stderr?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.