From 7b34bab6af30df9cfca7df9e0c644a0ea967ff04 Mon Sep 17 00:00:00 2001 From: sucanjan Date: Wed, 14 Feb 2018 21:57:30 +0100 Subject: Initial commit --- lib/knapsack_solver/graph_printer.rb | 115 +++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 lib/knapsack_solver/graph_printer.rb (limited to 'lib/knapsack_solver/graph_printer.rb') diff --git a/lib/knapsack_solver/graph_printer.rb b/lib/knapsack_solver/graph_printer.rb new file mode 100644 index 0000000..318e02e --- /dev/null +++ b/lib/knapsack_solver/graph_printer.rb @@ -0,0 +1,115 @@ +require 'gnuplot' + +module KnapsackSolver + # This class provides support for making graphs from statistics of datasets + # solving results. It uses Gnuplot and also generates a Gnuplot config file + # for each generated graph. + class GraphPrinter + # Initializes printer for graph data (graphs, Gnuplot config files). + # + # @param dataset_filenames [Array] dataset filenames + # @param stats [Hash] statistics of results + # @param out_dir [String] statistics of results to print + def initialize(dataset_filenames, stats, out_dir) + @dataset_basenames = file_basenames(dataset_filenames) + @stats = stats + @out_dir = out_dir + end + + # Create graphs from statistics and Gnuplot configuration files. + def print + stats_to_datasets.each do |title, ds| + ofn = File.join(@out_dir, title + '.png') + plot(title, ds, ofn) + end + end + + protected + + # Create graph. + # + # @param title [String] title of the graph + # @param data [Array] Gnuplot datasets to plot + # @param filename [String] path to the output image file + def plot(title, data, filename) + Gnuplot.open do |gp| + Gnuplot::Plot.new(gp, &plot_config(title, 'dataset', 'y', data, filename)) + end + File.open(File.join(File.dirname(filename), File.basename(filename, '.png') + '.gnuplot'), 'w') do |gp| + Gnuplot::Plot.new(gp, &plot_config(title, 'dataset', 'y', data, filename)) + end + end + + # Creates Gnuplot datasets from statistics. + # + # @return [Array] Gnuplot datasets created from the statistics. + def stats_to_datasets + graphs = @stats.values.first.values.first.first.keys + x_data = @stats.keys + datasets(graphs, x_data) + end + + # Creates Gnuplot datasets from statistics. + # + # @param graphs [Array] array of graph titles + # @param x_data [Array] array of X axis values + def datasets(graphs, x_data) + graphs.each_with_object({}) do |g, gnuplot_datasets| + @stats.each_value do |s| + gnuplot_datasets[g.to_s] = s.each_key.with_object([]) do |method, o| + o << plot_dataset(method.to_s, x_data, @stats.map { |_, v| v[method].first[g] }) + end + end + end + end + + # Create dataset from provided title, X axis data and Y axis data. + # + # @param title [String] Gnuplot dataset title + # @param x_data [Array] Array of X values + # @param y_data [Array] Array of Y values + # @return [Gnuplot::DataSet] Gnuplot dataset. + def plot_dataset(title, x_data, y_data) + Gnuplot::DataSet.new([x_data, y_data]) { |ds| ds.title = escape_gnuplot_special_chars(title) } + end + + # Creates Gnuplot plot configuration (configuration text lines). + # + # @param title [String] graph title + # @param xlabel [String] label of X axis + # @param ylabel [String] label of Y axis + # @param plot_datasets [Array] Gnuplot datasets for plotting + # @param out_file [String] output file + # @return [lambda] Lambda for setting plot configuration. + def plot_config(title, xlabel, ylabel, plot_datasets, out_file) + lambda do |plot| + plot.term('png') + plot.output(out_file) + plot.title("'#{escape_gnuplot_special_chars(title)}'") + plot.ylabel("'#{escape_gnuplot_special_chars(ylabel)}'") + plot.xlabel("'#{escape_gnuplot_special_chars(xlabel)}'") + plot.key('outside') + plot.data = plot_datasets + end + end + + # Escapes Gnuplot special characters. + # + # @param str [String] a string + # @return [Strnig] the string with Gnuplot special chars escaped + def escape_gnuplot_special_chars(str) + # underscore means subscript in Gnuplot + str.gsub('_', '\_') + end + + # Gets basenames of supplied file paths. + # + # @param paths [Array] path to files + # @return [Array] basenames of the paths + def file_basenames(paths) + paths.each_with_object([]) do |path, basenames| + basenames << File.basename(path, File.extname(path)) + end + end + end +end -- cgit v1.2.3