class CTioga2::PlotMaker
This class is the core of ctioga. It parses the command-line arguments, reads all necessary files and plots graphs. Most of its functionality is delegated into classes.
todo An important point would be to provide a facility that holds all the default values. To each would be assigned a given name, and programs would only use something like code value = Default::value('stuff') endcode
Setting up defaults would only be a question of using one single command (with admittedly many optional arguments)
Constants
- CleanupCommand
- CleanupPDFCommand
- DepsCommand
- EPSCommand
- LaTeXGroup
- LatexFontCommand
- MarkCommand
- NameCommand
- OpenViewerCommand
- OutputAndResetCommand
- OutputDirCommand
- OutputNowCommand
- OutputSetupGroup
- PNGCommand
- PageSizeCommand
- PlotCommand
- PlotGroup
- PlotLastCommand
- PlotLastOptions
- PlotOptions
- PreambleCommand
- ResolutionCommand
- SVGCommand
- UsePackageCommand
- Utf8Command
- ViewerCommand
These commands belong rather to the
PostProcess
file, but, well, they don't do much harm here anyway…- XpdfViewerCommand
Attributes
Whether intermediate files are cleaned up automatically afterwards or not…
A Graphics::CurveGenerator
object in charge of producing suitable elements to be added to the Graphics::RootObject
The stack of CurveStyle objects that were used so far.
The Data::DataStack
object that manipulates Dataset objects
The name of the figure
The Commands::Interpreter
object which runs all the commands.
Global font information
Additional preamble for LaTeX output
If not empty, a Makefile file where the dependencies are written out
Whether or not to include the command-line used to produce the file in the target PDF file.
The output directory
Whether or not one should pause at the end if there are errors. Useful on windows, where the windows closes before one has a chance to see anything.
The resolution of the PDF file
What happens to generated PDF files (a PostProcess
object)
The Graphics::RootObject
in charge of holding all things that will eventually get drawn
Public Class Methods
Setting up of the PlotMaker
object
# File lib/ctioga2/plotmaker.rb, line 253 def initialize CTioga2::Log::init_logger @data_stack = Data::DataStack.new @root_object = Graphics::RootObject.new @interpreter = Commands::Interpreter.new(self) @curve_generator = Graphics::CurveGenerator.new # Figure name: @figure_name = nil # Original preamble @latex_preamble = "" @latex_font = Graphics::Styles::FullLatexFont.new @latex_font.size = 15 @postprocess = PostProcess.new # Make sure it is registered @@first_plotmaker_instance ||= self # We mark by default, as it comes dead useful. @mark = true # Remove intermediate files by default. @cleanup = true # Make curve style stack empty @curve_style_stack = [] end
Returns the first created instance of PlotMaker
. This sounds less object-oriented, yes, but that can come in useful some times.
# File lib/ctioga2/plotmaker.rb, line 247 def self.plotmaker return @@first_plotmaker_instance end
Public Instance Methods
Add one Data::Dataset
object using the current style (that can be overridden by stuff given as options) to the root_object
.
todo here, keep a state of the current styles:
-
which is the color/marker/filling and so on of the curve ?
-
are we drawing plain 2D curve, a histogram or something even more fancy ?
-
this should be a separated class.
todo all curve objects should only take a Data::Dataset
and a style as arguments to new.
# File lib/ctioga2/plotmaker.rb, line 446 def add_curve(dataset, options = {}) plot = @root_object.current_plot curve = @curve_generator. curve_from_dataset(plot, dataset, options) plot.add_element(curve) @curve_style_stack << curve.curve_style info { "Adding curve '#{dataset.name}' to the current plot" } end
Transforms a dataset_spec into one or several Data::Dataset
using the current backend (or any other that might be specified in the options), and add them as curves to the root_object
, using add_curve
# File lib/ctioga2/plotmaker.rb, line 459 def add_curves(dataset_spec, options = {}) begin sets = @data_stack.get_datasets(dataset_spec, options) rescue Exception => exception error { "A problem occurred while processing dataset '#{dataset_spec}' using backend #{@data_stack.backend_factory.current.description.name}. Ignoring it." } debug { format_exception(exception) } return end for set in sets add_curve(set, options) end end
Draws the figure currently accumulated in the root_object
. It returns the path of the PDF file produced.
If figname contains a % sign, it will be interpreted as a format, and ctioga will attempt to find the first numbered file that does not exists.
todo
-
cleanup or not ?
# File lib/ctioga2/plotmaker.rb, line 351 def draw_figure(figname = "Plot-%03d", last = false) return if @root_object.empty? if figname =~ /%/ i = 0 prev = figname.dup while true f = figname % i if f == prev figname = f break end if File::exist?("#{f}.pdf") i += 1 else figname = f break end prev = f end end info { "Producing figure '#{figname}'" } t = create_figure_maker path = Pathname.new(figname) if @output_directory out = Pathname.new(@output_directory) path = out + path end # We always cd into the target directory for creading the Utils::chdir(path.dirname) do fn = path.basename.to_s efn = fn.gsub(/[.\s]/) do |x| "__#{x[0].ord}__" end if efn != fn debug { "Mangled name to '#{efn}'"} end t.def_figure(efn) do @latex_font.set_global_font(t) @root_object.draw_root_object(t) end t.make_preview_pdf(t.figure_index(efn)) # We look for latex errors if t.respond_to? :pdflatex_errors errs = t.pdflatex_errors if errs.size > 0 error { "pdflatex returned with #{errs.size} error lines"} for l in errs warn { "pdflatex error: #{l.chomp}" } end end end # We first rename the PDF file if it was mangled. if efn != fn File::rename("#{efn}.pdf", "#{fn}.pdf") end end file = path.to_s + ".pdf" if @makefile_dependencies File.open(@makefile_dependencies, "w") do |f| deps = Utils::used_files.values # TODO: handle spaces f.puts "#{file}: #{deps.join(" ")}" end end # Feed it @postprocess.process_file(file, last) return file end
Returns a quoted version of the command line, that possibly could be used again to reproduce the same results.
# File lib/ctioga2/plotmaker.rb, line 334 def quoted_command_line quoted_args = @command_line.collect do |s| Utils::shell_quote_string(s) end.join ' ' return "#{File.basename($0)} #{quoted_args}" end
Flushes the current root object and starts a new one:
# File lib/ctioga2/plotmaker.rb, line 325 def reset_graphics draw_figure(@figure_name || "Plot-%03d", true) @root_object = Graphics::RootObject.new @curve_generator = Graphics::CurveGenerator.new end
ctioga's entry point.
Returns true if there was no errors and false if there was one or more.
# File lib/ctioga2/plotmaker.rb, line 289 def run(command_line) # The main catch-all around the plot: begin @command_line = command_line.dup if ENV.key? 'CTIOGA2_PRE' command_line.unshift(*Shellwords.shellwords(ENV['CTIOGA2_PRE'])) end if ENV.key? 'CTIOGA2_POST' command_line.push(*Shellwords.shellwords(ENV['CTIOGA2_POST'])) end @interpreter.run_command_line(command_line) # Now, draw the main figure file = draw_figure(@figure_name || "Plot-%03d", true) rescue SystemExit => e # We special-case the exit exception ;-)... rescue Exception => e debug { format_exception(e) } fatal { "#{e.message}" } end errs = Log.counts[:error] warns = Log.counts[:warn] if errs + warns > 0 puts "ctioga2 finished with #{errs} errors and #{warns} warning" if @pause_on_errors puts "Hit ENTER to exit" STDIN.gets end end return errs == 0 end
Protected Instance Methods
Creates a new FigureMaker object and returns it
# File lib/ctioga2/plotmaker.rb, line 475 def create_figure_maker t = Tioga::FigureMaker.new(@pdf_resolution || 100) t.tex_preamble += @latex_preamble t.autocleanup = @cleanup # The title field of the information is the command-line if marking # is on. if @mark title = "/Title (#{Utils::pdftex_quote_string(quoted_command_line)})\n" else title = "" end # We use Vincent's algorithm for major ticks when available ;-)... begin t.vincent_or_bill = true info { "Using Vincent's algorithm for major ticks" } rescue info { "Using Bill's algorithm for major ticks" } end # We now use \pdfinfo to provide information about the version # of ctioga2 used to produce the PDF, and the command-line if # applicable. t.tex_preamble += "\n\\pdfinfo {\n#{title}/Creator(#{Utils::pdftex_quote_string("ctioga2 #{Version::version}")})\n}\n" #" #emacs ruby-mode is a dummy return t end