dilcom/gnuplotrb

View on GitHub
lib/gnuplotrb/mixins/plottable.rb

Summary

Maintainability
A
0 mins
Test Coverage
module GnuplotRB
  ##
  # This module contains methods that should be mixed into
  # plottable classes. It includes OptionHandling and
  # implements several plotting methods.
  module Plottable
    include OptionHandling

    ##
    # @private
    # You should implement #plot in classes that are Plottable
    def plot(*_)
      fail NotImplementedError, 'You should implement #plot in classes that are Plottable!'
    end

    ##
    # In this gem #method_missing is used both to handle
    # options and to handle plotting to specific terminal.
    #
    # == Options handling
    # === Overview
    # You may set options using #option_name(option_value) method.
    # A new object will be constructed with selected option set.
    # And finally you can get current value of any option using
    # #options_name without arguments.
    # === Arguments
    # * *option_value* - value to set an option. If none given
    #   method will just return current option's value
    # === Examples
    #   plot = Splot.new
    #   new_plot = plot.title('Awesome plot')
    #   plot.title #=> nil
    #   new_plot.title #=> 'Awesome plot'
    #
    # == Plotting to specific term
    # === Overview
    # Gnuplot offers possibility to output graphics to many image formats.
    # The easiest way to to so is to use #to_<plot_name> methods.
    # === Arguments
    # * *options* - set of options related to terminal (size, font etc).
    #   Be careful, some terminals have their own specific options.
    # === Examples
    #   # font options specific for png term
    #   multiplot.to_png('./result.png', size: [300, 500], font: ['arial', 12])
    #   # font options specific for svg term
    #   content = multiplot.to_svg(size: [100, 100], fname: 'Arial', fsize: 12)
    def method_missing(meth_id, *args)
      meth = meth_id.id2name
      case
      when meth[0..2] == 'to_'
        term = meth[3..-1]
        super unless OptionHandling.valid_terminal?(term)
        to_specific_term(term, *args)
      when meth[-1] == '!'
        option!(meth[0..-2].to_sym, *args)
      when meth[-1] == '='
        option!(meth[0..-2].to_sym, *args)
        option(meth[0..-2].to_sym)
      else
        option(meth_id, *args)
      end
    end

    ##
    # @return [true] for existing methods and
    #   #to_|term_name| when name is a valid terminal type.
    # @return [false] otherwise
    def respond_to?(meth_id)
      # Next line is here to force iRuby use #to_iruby
      # instead of #to_svg.
      return super if defined? IRuby
      meth = meth_id.id2name
      term = meth[0..2] == 'to_' && OptionHandling.valid_terminal?(meth[3..-1])
      term || super
    end

    ##
    # This method is used to embed plottable objects into iRuby notebooks. There is
    # {a notebook}[http://nbviewer.ipython.org/github/dilcom/gnuplotrb/blob/master/notebooks/basic_usage.ipynb]
    # with examples of its usage.
    def to_iruby
      available_terminals = {
        'png'      => 'image/png',
        'pngcairo' => 'image/png',
        'jpeg'     => 'image/jpeg',
        'svg'      => 'image/svg+xml',
        'dumb'     => 'text/plain'
      }
      terminal, options = term.is_a?(Array) ? [term[0], term[1]] : [term, {}]
      terminal = 'svg' unless available_terminals.keys.include?(terminal)
      [available_terminals[terminal], send("to_#{terminal}".to_sym, **options)]
    end

    ##
    # @private
    # Output plot to specific terminal (possibly some file).
    # Explicit use should be avoided. This method is called from #method_missing
    # when it handles method names like #to_png(options).
    #
    # @param trminal [String] terminal name ('png', 'svg' etc)
    # @param path [String] path to output file, if none given it will output to temp file
    #   and then read it and return binary contents of file
    # @param options [Hash] used in #plot
    # @example
    #   ## plot here may be Plot, Splot, Multiplot or any other plottable class
    #   plot.to_png('./result.png', size: [300, 500])
    #   contents = plot.to_svg(size: [100, 100])
    #   plot.to_dumb('./result.txt', size: [30, 15])
    def to_specific_term(terminal, path = nil, **options)
      if path
        result = plot(term: [terminal, options], output: path)
      else
        path = Dir::Tmpname.make_tmpname(terminal, 0)
        plot(term: [terminal, options], output: path)
        result = File.binread(path)
        File.delete(path)
      end
      result
    end

    ##
    # @return [Terminal] terminal object linked with this Plottable object
    def own_terminal
      @terminal ||= Terminal.new
    end

    ##
    # @!method xrange(value = nil)
    # @!method yrange(value = nil)
    # @!method title(value = nil)
    # @!method option_name(value = nil)
    # Clone existing object and set new options value in created one or just return
    # existing value if nil given.
    #
    # Method is handled by #method_missing.
    #
    # You may set options using #option_name(option_value) method.
    # A new object will be constructed with selected option set.
    # And finally you can get current value of any option using
    # #options_name without arguments.
    # 
    # Available options are listed in Plot, Splot, Multiplot etc class top level doc.
    #
    # @param value new value for option
    # @return new object with option_name set to *value* if value given
    # @return old option value if no value given
    #
    # @example
    #   plot = Splot.new
    #   new_plot = plot.title('Awesome plot')
    #   plot.title #=> nil
    #   new_plot.title #=> 'Awesome plot'

    ##
    # @!method xrange!(value)
    # @!method yrange!(value)
    # @!method title!(value)
    # @!method option_name!(value)
    # Set value for an option.
    #
    # Method is handled by #method_missing.
    #
    # You may set options using obj.option_name!(option_value) or 
    # obj.option_name = option_value methods.
    # 
    # Available options are listed in Plot, Splot, Multiplot etc class top level doc.
    #
    # @param value new value for option
    # @return self
    #
    # @example
    #   plot = Splot.new
    #   plot.title #=> nil
    #   plot.title!('Awesome plot')
    #   plot.title #=> 'Awesome plot'
    #
    # @example
    #   plot = Splot.new
    #   plot.title #=> nil
    #   plot.title = 'Awesome plot'
    #   plot.title #=> 'Awesome plot'

    ##
    # @!method to_png(path = nil, **options)
    # @!method to_svg(path = nil, **options)
    # @!method to_gif(path = nil, **options)
    # @!method to_canvas(path = nil, **options)
    # Output to plot to according image format.
    #
    # All of #to_|terminal_name| methods are handled with #method_missing.
    #
    # Gnuplot offers possibility to output graphics to many image formats.
    # The easiest way to to so is to use #to_<plot_name> methods.
    #
    # @param path [String] path to save plot file to.
    # @param options [Hash] specific terminal options like 'size',
    #   'font' etc
    #
    # @return [String] contents of plotted file unless path given
    # @return self if path given
    #
    # @example
    #   # font options specific for png term
    #   multiplot.to_png('./result.png', size: [300, 500], font: ['arial', 12])
    #   # font options specific for svg term
    #   content = multiplot.to_svg(size: [100, 100], fname: 'Arial', fsize: 12)
  end
end