Class: RVGP::Plot::Gnuplot::Plot

Inherits:
Object
  • Object
show all
Defined in:
lib/rvgp/plot/gnuplot.rb

Overview

This class represents, and generates, a gnuplot gpi file. Either to string, or, to the filesystem. This class will typically work with classes derived from ChartBuilder, and an instance of this class is provided as a parameter to the #initialize method of a ChartBuilder.

Constant Summary collapse

ELEMENTS =

These are the gnuplot elements, that we currently support:

[AreaChart, ColumnAndLineChart].freeze
SET_QUOTED =

These attributes were pulled from the gnuplot gem, and indicate which #set key’s require string quoting. This implementation isn’t very good, but, was copied out of the Gnuplot gem

%w[title output xlabel x2label ylabel y2label clabel cblabel zlabel].freeze
PLOT_COMMAND_LINE =

This is a string formatting specifier, used to composed a plot directive, to gnuplot

['%<using>s', 'title %<title>s', 'with %<with>s'].compact.join(" \\\n    ").freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(title, dataset, opts = {}) ⇒ Plot

Create a plot

Parameters:

  • title (String)

    The title of this plot

  • dataset (Array<Array<String>>)

    A grid, whose first row contains the headers, and in which each additional row’s first element, is a keystone.

  • opts (Hash) (defaults to: {})

    options to configure this plot, and its #element. Unrecognized options, in this parameter, are delegated to the specified :chart_type for further handling.

Options Hash (opts):

  • :additional_lines (Symbol) — default: []
  • :template (Symbol)

    see #template

  • :chart_type (String)

    A string, that is matched against .types of available ELEMENTS, and used to initialize an instance of a matched class, to create our #element

Raises:

  • (StandardError)


358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/rvgp/plot/gnuplot.rb', line 358

def initialize(title, dataset, opts = {})
  @title = title
  @dataset = dataset
  @settings = []
  @additional_lines = Array(opts[:additional_lines])
  @template = opts[:template]

  element_klass = ELEMENTS.find { |element| element.types.any? opts[:chart_type] }
  raise StandardError, format('Unsupported chart_type %s', opts[:chart_type]) unless element_klass

  @element = element_klass.new opts, self
end

Instance Attribute Details

#additional_linesArray<String>

Arbitrary lines, presumably of gnuplot code, that are appended to the generated gpi, after the settings, and before the plot commands(s).

Returns:

  • (Array<String>)

    the current value of additional_lines



336
337
338
# File 'lib/rvgp/plot/gnuplot.rb', line 336

def additional_lines
  @additional_lines
end

#datasetArray<Array<String>> (readonly)

A grid, whose first row contains the headers, and in which each additional row’s first element, is a keystone.

Returns:

  • (Array<Array<String>>)

    the current value of dataset



336
337
338
# File 'lib/rvgp/plot/gnuplot.rb', line 336

def dataset
  @dataset
end

#elementRVGP::Plot::Gnuplot::ChartBuilder (readonly)

An instance of ELEMENTS, to which plot directive generation is delegated.

Returns:



336
337
338
# File 'lib/rvgp/plot/gnuplot.rb', line 336

def element
  @element
end

#settingsHash[String, String] (readonly)

A hash of setting to value pairs, whech are transcribed (via the ‘set’ directive) to the plot

Returns:



336
337
338
# File 'lib/rvgp/plot/gnuplot.rb', line 336

def settings
  @settings
end

#templateHash[Symbol, Object] (readonly)

A hash containing a :header string, and a :colors Hash. These objects are used to construct the aesthetics of the generated gpi. For more details on what options are supported in the :colors key, see the colors section of: default.yml

Returns:

  • (Hash[Symbol, Object])

    the current value of template



336
337
338
# File 'lib/rvgp/plot/gnuplot.rb', line 336

def template
  @template
end

Instance Method Details

#column(num) ⇒ Array<String>

Returns column n of dataset, not including the header row

Parameters:

  • num (Integer)

    The column number to return

Returns:

  • (Array<String>)

    The column that was found, from top to bottom



426
427
428
# File 'lib/rvgp/plot/gnuplot.rb', line 426

def column(num)
  dataset[1...].map { |row| row[num] }
end

#execute!(persist: true) ⇒ String

Runs the gnuplot command, feeding the contents of #script to it’s stdin and returns the output. raises StandardError, citing errors, if gnuplot returns errors.

Returns:

  • (String)

    the output of gnuplot, with some selective squelching of output



386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
# File 'lib/rvgp/plot/gnuplot.rb', line 386

def execute!(persist: true)
  output, errors, status = Open3.capture3 Gnuplot.gnuplot(persist), stdin_data: script

  # For reasons unknown, this is sent to stderr, in response to the
  # 'set decimal locale' instruction. Which we need to set.
  errors = errors.lines.reject { |line| /^decimal_sign in locale is/.match(line) }

  unless status.success? || !errors.empty?
    raise StandardError,
          format('gnuplot exited non-zero (%<status>s): %<errors>s',
                 status: status.exitstatus,
                 errors: errors.join("\n"))
  end

  output
end

#num_colsInteger

Returns the number of columns in the dataset, including the keystone

Returns:

  • (Integer)

    the length of dataset



439
440
441
# File 'lib/rvgp/plot/gnuplot.rb', line 439

def num_cols
  dataset[0].length
end

#paletteObject

The current RVGP::Plot::Gnuplot::Palette instance that we’re using for our color queries



444
445
446
# File 'lib/rvgp/plot/gnuplot.rb', line 444

def palette
  @palette ||= Palette.new @template[:colors]
end

#scriptString

Assembles a gpi file’s contents, and returns them as a string

Returns:

  • (String)

    the generated gpi file



373
374
375
376
377
378
379
380
381
# File 'lib/rvgp/plot/gnuplot.rb', line 373

def script
  vars = { title: @title }.merge palette.base_to_h

  [format("$DATA << EOD\n%sEOD\n", to_csv),
   format(template[:header], vars),
   @settings.map { |setting| setting.map(&:to_s).join(' ') << "\n" },
   format(@additional_lines.join("\n"), vars),
   plot_command, "\n"].flatten.join
end

#series_name(num) ⇒ String

Returns the header row, at position num

Parameters:

  • num (Integer)

    The series number to query

Returns:

  • (String)

    The name of the series, at row num



433
434
435
# File 'lib/rvgp/plot/gnuplot.rb', line 433

def series_name(num)
  dataset[0][num]
end

#set(key, value = nil) ⇒ void

This method returns an undefined value.

Transcribes a ‘set’ directive, into the generated plot, with the given key as the set variable name, and the provided value, as that set’s value. Some values (See SET_QUOTED) are interpolated. Others are merely transcribed directly as provided, without escaping.

Parameters:

  • key (String)

    The gnuplot variable you wish to set

  • value (String) (defaults to: nil)

    The value to set to, if any



409
410
411
412
413
# File 'lib/rvgp/plot/gnuplot.rb', line 409

def set(key, value = nil)
  quoted_value = value && SET_QUOTED.include?(key) ? quote_value(value) : value
  @settings << [:set, key, quoted_value].compact
  nil
end

#unset(key) ⇒ void

This method returns an undefined value.

Transcribes an ‘unset’ directive, into the generated plot, with the given key as the unset variable name.

Parameters:

  • key (String)

    The gnuplot variable you wish to unset



418
419
420
421
# File 'lib/rvgp/plot/gnuplot.rb', line 418

def unset(key)
  @settings << [:unset, key]
  nil
end