Giter VIP home page Giter VIP logo

gnuplotrb's Introduction

GnuplotRB

GnuplotRB is a plot generator for Ruby based on Gnuplot.

This software has been developed as a product in Google Summer of Code 2015 (GSoC2015). Its progress may be saw in SciRuby mailing list or in project's blog.

Gem Version Dependency Status Build Status Code Climate Test Coverage

Table of contents

Installation

Dependencies

  • Ruby 2.0+
  • It is required to install gnuplot 5.0 to use that gem.

Gem installation

Install latest stable version from Rubygems

gem install gnuplotrb

Install latest stable version using bundler

  • add gem gnuplotrb to your Gemfile
  • run bundle install

Install latest version from source (may be unstable)

git clone https://github.com/sciruby/gnuplotrb.git
cd gnuplotrb
bundle install
rake install

Getting started

GnuplotRB gem is based on Gnuplot so I would recommend to use Gnuplot doc and GnuplotRB doc at Rubydoc in cases when docs and examples (as notebooks and plain examples) present here are not enough to explain how to plot something.

Plottable classes

Each of plottable classes may be outputted to image file using #to_png, #to_svg, #to_gif and so on methods. You can read more about it in GnuplotRB doc related to Plottable module or see examples in beginners notebook.

Dataset

Single dataset may be created with math formula ('sin(x)') or some data. If your data is stored in a file you can just pass a filename (e.g. 'gnuplotrb.data'). Dataset may also be constructed out of data contained in Ruby classes (Array, Daru containers), see example notebooks.

Dataset have several possible options which are explained in gnuplot doc (pp. 80-102). Options are passed to Dataset.new as hash and are tranlated into gnuplot format before plotting:

Dataset.new(data, with: 'lines', using: '1:2')

Examples of option translation (nested containers allowed):

  • Hash:
{ key1: "value1", key2: { nested_key1: "nested_value1" } } # => "key1 value1 key2 nested key1 nested_value1"
  • Hashes with underscored keys (see #7):
{ style_data: 'histograms' } #=> "style data histograms"
  • Range:
{ xrange: 0..100 } # => "xrange [0:100]"
  • Array (often used with nested hashes) and Array of Numeric
['png', { size: [400, 500] }] # => "png size 400,500"
  • Others
some_object # => some_object.to_s

Once Dataset created, it may be updated with new data or options. Methods related to updating are explained in a notebook.

Just as other Plottable object Dataset has several plotting methods which are desribed in beginners notebook.

Plot

Plot is a container for several datasets and layout options:

Plot.new(ds1, ds2, ds2, xrange: 1..10)

Datasets contained bu Plot are outputted on single xy plain.

Plot's options are explained in gnuplot doc (pp. 105-181). Plot options are translated into gnuplot format the same way as Dataset's (except adding 'set' before each option). Plot's datasets and Plot itself may be updated with almost the same methods as desribed in Dataset section above.

Splot

Almost the same as Plot but for 3-D plots. See Plot section.

Multiplot

Container for several Plot or Splot objects, each of them is plotted in its own xy(z) space. So Multiplot offers single layout (image filewindow) for several plots. It's grid is tuned by :layout option, and you can also set layout's title:

Multiplot.new(plot1, plot2, splot1, layout: [3, 1], title: 'Three plots on a layout')

Updating methods for Multiplot are almost the same as Plot's and Dataset's and are covered in Multiplot's docs and multiplot notebook. See examples there.

Animation

Animation is a container for several Plot, Splot or Multiplot objects. Each of contained items is considered as frame in gif animation which is creating by #plot call. Animation's frames and options may be modifyed or updated just as other classes above. Animation does not support methods like #to_png and may be plotted only with #plot method. Please see related notebook and docs at RubyDoc for examples.

Notebooks

This notebooks are powered by Ruby kernel for IPython/Jupyter. I placed them here to show some GnuplotRB's capabilities and ways of using it together with iRuby.

To use GnuplotRB gem with iRuby you need to install them both.

  • iRuby installation is covered in its README. It also covers installation of iPython and other dependecies.
  • GnuplotRB gem installation covered in README too.

Embedding plots into iRuby

Using GnuplotRB inside iRuby notebooks is covered in:

2D and 3D plots

GnuplotRB is capable to plot vast range of plots from histograms to 3D heatmaps. Gem's repository contains examples of several plot types:

Possible datasources

GnuplotRB may take data in Ruby container or in a file. Supported containers for now are Array, Daru::Vector and Daru::DataFrame. When data given in file, GnuplotRB pass filename to Gnuplot without reading the file into memory.

Examples of using different datasources:

Multiplot

You can not only plot several datasets in single coordinate system but place several coordinate systems on a canvas.

Animation

It's possible to use several plots (Plot, Splot or Multiplot objects) to create gif animation.

Fitting data with formula

GnuplotRB also may be used to fit some data with given math formula.

Plain examples

You may find several examples in examples directory.

Contributing

  1. Fork repository
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

gnuplotrb's People

Contributors

abinoam avatar agisga avatar ievgrafov avatar noraj avatar rssdev10 avatar v0dro avatar

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

gnuplotrb's Issues

GnuplotRB loops undefinitely when trying to generate a histogram

I got some issues when trying to generate a histogram. I had no problems with points and lines, just with histograms. Below is a minimal example that recreates the behavior - at least on my machine.

require 'daru'
require 'gnuplotrb'
include GnuplotRB

days = %w(Monday Tuesday Wednesday Thursday Friday Saturday Sunday)
mean = [121.2, 95.6, 91.06, 133.037, 81.88, 82.33, 200.45]
std = [206.05, 94.35, 108.15, 208.53, 114.27, 104.77, 320.66]

cdata = Daru::DataFrame.new({ day: days, mean: mean, sd: std }, name: "test")

plot = Plot.new(cdata,
                style_data: 'histograms',
                style_fill: 'pattern',
                title: "Test")

plot.to_png 'test.png'

If I change style_data to lines, it works as expected.

I'm using Ruby 2.3.0, with gnuplotrb 0.3.4 and daru 0.1.4.1. Gnuplot is version 5.0 patchlevel 3.

Thanks for your work with this :)

Reason of Infinite loop

require 'gnuplotrb'
puts GnuplotRB::Plot.new('XXX').to_svg()

It may work like this:

create error handler thread (but not running)
check_errors => ok
check_errors => ok
.
.
.
check_errors => ok
handler thread start...
sleep 0.01 until File.size?(inner_opts[:output]) => loop forever

The error handler thread may start after all check ran, and the exception can not be raise.

Should show error message and not loop when there's an error

When the gnuplot program generates an error that isn't output instantly, GnuplotRB::Plot#plot loops forever and never displays the error message. This can come up in a number of ways and is particularly sinister because it hides the root cause of many different problems.

The code is reading the output of a separate process, so depending on execution order, you may not run into this problem. Sometimes just running it again works. But many times, it doesn't.

This may be somewhat related to #10. But I was trying to create a heatmap and ran into this. After hacking around it, I found that it's not related to a specific type of plot, but any error.

This is my workaround:

diff --git a/lib/gnuplotrb/plot.rb b/lib/gnuplotrb/plot.rb
index 1fb46f6..1809107 100644
--- a/lib/gnuplotrb/plot.rb
+++ b/lib/gnuplotrb/plot.rb
@@ -79,6 +79,7 @@ module GnuplotRB
       ds_string = @datasets.map { |dataset| dataset.to_s(terminal) }.join(' , ')
       full_command = @cmd + ds_string
       terminal.set(inner_opts).stream_puts(full_command).unset(inner_opts.keys)
+      sleep 1
       if inner_opts[:output]
         # guaranteed wait for plotting to finish
         terminal.close unless term

It's unsatisfactory because it sleeps unnecessarily, especially in non-error cases.

I think many people would appreciate having this fixed since showing the underlying error message is crucial, especially for new users (like me) who aren't familiar with what options they should be using. What ends up happening is people experiment with different options to see what happens. Unfortunately, as it is now, that often causes them to get stuck, not knowing how to proceed.

inconsistent xrange behaviour with time data

I have simplified an example as far as I could :

require 'gnuplotrb'
include GnuplotRB

#x = ["2013-05-22 02:49:49",    "2013-05-22 02:56:49", "2013-05-22 02:56:59"]
x = ["2012-05-22",    "2013-05-21", "2013-05-22"]
y = [ 2,5,9]

p x.first
p x.last

element = Dataset.new(
      [x, y], 
      with:'lines lw 3 lt rgb "black"', 
      xdata: 'time',
      timefmt: "%Y-%m-%d",           # timefmt: "%Y-%m-%d %H:%M:%S",
      xrange: '["2012-05-22":"2013-05-22"]'    #xrange: '["#{x.first}" : "{x.last}" ]'
      )
   
myBRTraces = Plot.new(
      element
       )
      
p myBRTraces.inspect
myBRTraces.to_png("/media/sf_D_DRIVE/Test/a.svg", size: [1200, 1800], truecolor:true)

behaviour:

 $ ruby test.rb 
"2012-05-22"
"2013-05-22"
"#<GnuplotRB::Plot:0x00000001bbe058 @options=Hamster::Hash[], @datasets=Hamster::Vector[#<GnuplotRB::Dataset:0x00000001bbdf68 @type=:datablock, @data=#<GnuplotRB::Datablock:0x00000001bbdc98 @stored_in_file=false, @data=\"2012-05-22 2\\n2013-05-21 5\\n2013-05-22 9\">, @options=Hamster::Hash[:with => \"lines lw 3 lt rgb \\\"black\\\"\", :xdata => \"time\", :timefmt => \"%Y-%m-%d\", :xrange => \"[\\\"2012-05-22\\\":\\\"2013-05-22\\\"]\"]>], @cmd=\"plot \">"
/var/lib/gems/2.3.0/gems/gnuplotrb-0.4.0/lib/gnuplotrb/mixins/error_handling.rb:28:in `check_errors': Error in previous command ("gnuplot> plot $DATA1 with lines lw 3 lt rgb "black" xdata time timefmt "%Y-%m-%d" xrange ["2012-05-22":"2013-05-22"]"): "line 4: unexpected or unrecognized token" (GnuplotRB::GnuplotError)
	from /var/lib/gems/2.3.0/gems/gnuplotrb-0.4.0/lib/gnuplotrb/staff/terminal.rb:183:in `close'
	from /var/lib/gems/2.3.0/gems/gnuplotrb-0.4.0/lib/gnuplotrb/plot.rb:85:in `plot'
	from /var/lib/gems/2.3.0/gems/gnuplotrb-0.4.0/lib/gnuplotrb/mixins/plottable.rb:111:in `to_specific_term'
	from /var/lib/gems/2.3.0/gems/gnuplotrb-0.4.0/lib/gnuplotrb/mixins/plottable.rb:53:in `method_missing'
	from test.rb:25:in `<main>'

Note : I have tweaked plot.rb as per [https://github.com//issues/14]

Should plot with options in the order given

Once I worked around #14, I discovered many problems. One of them was that my plot options were not being used in the correct order.

Since options are specified with a Ruby Hash, the simplest way that I can think of to specify an order of the options would be to simply use the native order of the input Hash. Ever since Ruby 1.9, iteration order of Hashes is insertion order.

As I dug deeper, I noticed that option order is specifically being changed by GnuplotRB::Dataset::OPTION_ORDER. It's great that I found out that I can change this constant to fix my issues, but the underlying problem remains. If I'm using options that GnuplotRB doesn't specifically know about and special-case, there's no way for me to plot without mucking in the library.

At first, I thought this change would be as simple as switching the #sort_by call to a stable sort. But it seems like the root cause runs deeper. GnuplotRB is converting the Hash options to a Hamster::Hash. Unlike Ruby's built-in Hash, Hamster::Hash doesn't preserve order.

Unfortunately, Hamster doesn't provide an OrderedHash. My first question is, what's the reason for using Hamster::Hash in favor of the built-in Hash?

Dataset initialisation broken in ruby 3.0.0

Running any examples from the basic usage notebook locally result in the following error:
ArgumentError: wrong number of arguments (given 2, expected 1) from /.gem/ruby/3.0.0/gems/gnuplotrb-0.4.0/lib/gnuplotrb/staff/dataset.rb:65:in 'initialize'

The only example that works locally for me is:
Plot.new('sin(x)').to_png('plot.png')

Examples here and here all return the same error as well.

ruby version: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]

Release new gem?

Last release was in March 2016 and recent commits are needed to make gnuplotrb work with ruby 2.5. Thanks!

Scatterplot in Dataframe

I'm trying to draw scatter plot of the following dataframe but it misses some points.

df = Daru::DataFrame.new({
  x: [3, 3, 3],
  y: [1, 2, 3]
  }, index: [0, 2, 3])
Plot.new [df, pt: 6, ps: 1, using: '2:3']

Although if I do not specify any index then it works pretty well.

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.