Class: CTioga::PlotMaker

Inherits:
Object
  • Object
show all
Extended by:
MetaBuilder::DescriptionExtend
Includes:
Axes, Backends, Debug, Log, Themes, Utils, MetaBuilder::DescriptionInclude, SciYAG, Tioga, Tioga::Utils
Defined in:
lib/CTioga/plotmaker.rb

Overview

This class is responsible for reading the command-line, via it’s parse function, and to actually turn it into nice Tioga commands to make even nicer graphes.

Constant Summary collapse

CONFIG_FILE_NAME =
".ctiogarc"

Constants included from Axes

Axes::Alignment, Axes::AxisSpecification, Axes::Justification, Axes::LabelSide, Axes::LabelSpecification

Constants included from Themes

Themes::DisableRe, Themes::StyleTypes

Constants included from Utils

Utils::FrameNames, Utils::Locations, Utils::NaturalDistances, Utils::NaturalDistancesNonLinear

Instance Attribute Summary collapse

Attributes included from Axes

#decimal_separator, #x_factor, #x_log, #x_offset, #y_factor, #y_log, #y_offset

Attributes included from Themes

#histogram, #override_style

Instance Method Summary collapse

Methods included from MetaBuilder::DescriptionExtend

base_description, create_factory, describe, description, factory_class, factory_description, factory_description_hash, factory_description_list, group, has_factory?, inherit_parameters, param, param_accessor, param_reader, param_writer, register_class, set_description

Methods included from Axes

#axes_options, #init_axes, #parse_edge_visibility, #run_with_axis, #run_with_label

Methods included from Themes

#choose_theme, #current_theme, #get_current_style, #initialize_themes, #reset_override_style, #style_argument, #theme_bod_hook, #theme_prepare_parser

Methods included from Backends

#backend, #backends, #current_push_filter, #expand_spec, #init_backend_structure, #prepare_backend_options, #set_backend, #xy_data_set

Methods included from Utils

apply_margin_to_frame, compose_margins, frame_to_array, frames_str, framespec_str, inset_margins, interpret_arg, location_index, margin_hash, partition_nonlinear, partition_segment, #safe_float, side, side?

Methods included from Log

#identify, #init_logger, #logger, #logger_options, #spawn

Methods included from Debug

#debug_figmaker, #debug_patterns, #debug_puts, #figmaker_options, #test_pattern, #test_pattern_right

Methods included from MetaBuilder::DescriptionInclude

#description, #get_param, #get_param_raw, #long_name, #option_parser_banner, #option_parser_fill, #option_parser_options, #parameter, #restore_state, #save_state, #set_param, #set_param_raw

Constructor Details

#initializePlotMaker

Returns a new instance of PlotMaker.



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/CTioga/plotmaker.rb', line 215

def initialize
  # The first thing to do is to setup logging, as you really
  # want to be able to communicate with users, don't you ?
  init_logger


  @args = []                # Holding the command-line
  @parser = OptionParser.new

  initialize_themes

  # Whether the plots should be interpolated.
  @interpolate = false 

  @line_width = nil

  @fig_name = "Plot"

  # Initialize the backend structure:
  init_backend_structure

  init_axes

  # now, the elements for the structure of the plot:
  @root_object = SubPlot.new
  # We start with a very simple layout
  SimpleLayout.new(@root_object)
  
  # the current object is the one to which we'll add plot elements.
  @current_object = @root_object

  # @legend is holding the text attached to the current item being
  # plotted; it has to be cleared manually after every item processed
  @legend = nil

  # general purpose variables:
  @cleanup = true           # Now, cleaning is done by default !
  @viewer = false

  # Some options we could set on the command line
  @init_funcalls = []

  # Whether to provide default legends. On by default
  @autolegends = true

  @command_line = ""

  @real_size = "12cmx12cm"

  # If set, should be the size of the TeX font
  
  @tex_fontsize = nil

  # The frame sides for the setup_real_size function
  @frame_sides = [0.1,0.9,0.9,0.1]
  # Override this, as the layout scheme makes it more or less
  # obsolete
  @frame_sides = [0,1,1,0]

  # If set, we create separate legend informations:
  @separate_legend = false

  # The array holding the styles.
  @separate_legend_styles = []
  # The size of the produced PDF in PDF points.
  @separate_legend_width = 12
  @separate_legend_height = 8

  # Whether to mark the command-line in the PDF file
  @mark = true              # On by default, really useful !!!

  # The LaTeX preamble:
  @preamble = ""

  # The last curve used:
  @last_curve = nil

  # Specifications for the --next stuff: an array, the first
  # element is the class to be created for children and the
  # rest are arguments to be added at the beginning.
  @next_specs = [SubPlot, :subplot]

  # A block to be run on both the old and new object
  # when --next is encountered.
  @next_block = nil

  # Whether we automatically start a --next stuff on each spec
  # or even on each dataset
  @auto_next = false

  # We don't make any PNG file:
  @png = false

  # The standard PNG density...
  @png_oversampling = 2

  # We don't produce SVG output by default
  @svg = false

  # The default padding;
  @default_padding = []
  4.times do 
    @default_padding << Dimension.new(0.05)
  end

  # And we use it :
  use_default_padding
  
  prepare_option_parser
end

Instance Attribute Details

#autolegendsObject

Whether to automatically add a legend to all curves



213
214
215
# File 'lib/CTioga/plotmaker.rb', line 213

def autolegends
  @autolegends
end

#cleanup=(value) ⇒ Object (writeonly)

these are basically the attributes which are modified directly on the command-line



188
189
190
# File 'lib/CTioga/plotmaker.rb', line 188

def cleanup=(value)
  @cleanup = value
end

#current_objectObject

The current object



201
202
203
# File 'lib/CTioga/plotmaker.rb', line 201

def current_object
  @current_object
end

#fig_name=(value) ⇒ Object (writeonly)

these are basically the attributes which are modified directly on the command-line



188
189
190
# File 'lib/CTioga/plotmaker.rb', line 188

def fig_name=(value)
  @fig_name = value
end

#last_curveObject (readonly)

The last Curve object on the stack



194
195
196
# File 'lib/CTioga/plotmaker.rb', line 194

def last_curve
  @last_curve
end

#legend=(value) ⇒ Object (writeonly)

these are basically the attributes which are modified directly on the command-line



188
189
190
# File 'lib/CTioga/plotmaker.rb', line 188

def legend=(value)
  @legend = value
end

#parserObject (readonly)

The command-line parser



191
192
193
# File 'lib/CTioga/plotmaker.rb', line 191

def parser
  @parser
end

#pngObject

Whether we are making a PNG file



204
205
206
# File 'lib/CTioga/plotmaker.rb', line 204

def png
  @png
end

#png_sizeObject

The PNG’s size:



207
208
209
# File 'lib/CTioga/plotmaker.rb', line 207

def png_size
  @png_size
end

#real_sizeObject

Whether we are trying to do real-size PDF or not. When set, it is the size of the PDF



198
199
200
# File 'lib/CTioga/plotmaker.rb', line 198

def real_size
  @real_size
end

#separate_legendsObject

Whether to create separate legends



210
211
212
# File 'lib/CTioga/plotmaker.rb', line 210

def separate_legends
  @separate_legends
end

Instance Method Details

#add_elem_funcall(sym, *args) ⇒ Object

Push a function call onto the stack of the current element



442
443
444
# File 'lib/CTioga/plotmaker.rb', line 442

def add_elem_funcall(sym, *args)
  @current_object.add_funcall(TiogaFuncall.new(sym, *args))
end

#add_elems_to_current(*elems) ⇒ Object



1202
1203
1204
1205
1206
# File 'lib/CTioga/plotmaker.rb', line 1202

def add_elems_to_current(*elems)
  for el in elems
    @current_object.add_elem(el)
  end
end

#add_init_funcall(sym, *args) ⇒ Object

Push a function call onto the stack of things we should do just after creating the FigureMakerobject



448
449
450
# File 'lib/CTioga/plotmaker.rb', line 448

def add_init_funcall(sym, *args)
  @init_funcalls << TiogaFuncall.new(sym, *args)
end

Ctioga’s banner



1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
# File 'lib/CTioga/plotmaker.rb', line 1418

def banner
  <<"EOBANNER" 
This is ctioga version #{Version::version}
ctioga is copyright (C) 2006, 2007, 2008 by Vincent Fourmond 

ctioga comes with absolutely NO WARRANTY. This is
free software, you are welcome to redistribute it under certain
conditions. See the COPYING file in the original tarball for
details. You are also welcome to contribute if you like it, see in
the manual page where to ask.   
EOBANNER
end

#current_plot_styleObject

Returns the current object’s plot style



360
361
362
# File 'lib/CTioga/plotmaker.rb', line 360

def current_plot_style
  return current_object.plot_style
end

#do_figure(t) ⇒ Object

Runs the code to make the actual figure.



1413
1414
1415
# File 'lib/CTioga/plotmaker.rb', line 1413

def do_figure(t)
  @root_object.do(t)
end

#endObject



1198
1199
1200
# File 'lib/CTioga/plotmaker.rb', line 1198

def end
  @current_object = @current_object.parent if @current_object.parent
end

#enter_child_object(object) ⇒ Object

Adds the given object to the current’s stack and set it as the current object, so that it will receive further children



340
341
342
343
# File 'lib/CTioga/plotmaker.rb', line 340

def enter_child_object(object)
  @current_object.add_elem(object)
  self.current_object = object
end

#expand_sides(txt) ⇒ Object

Splits a text into four components, expanding if necessary:

  • if there is only one element, all four become this one

  • if there are two: w,h, it becomes w,w,h,h

  • if there are three, the last element is duplicated.



470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/CTioga/plotmaker.rb', line 470

def expand_sides(txt)
  ary = txt.split(/\s*,\s*/)
  case ary.size
  when 1
    return [ary[0], ary[0], ary[0], ary[0]]
  when 2
    return [ary[0], ary[0], ary[1], ary[1]]
  when 3
    return [ary[0], ary[1], ary[2], ary[2]]
  else
    return ary
  end
end

#leave_child_objectObject

Goes out from a child object to its parent. Returns the child object. Issues a warning if already at top level (in which case it returns the current object)



348
349
350
351
352
353
354
355
356
# File 'lib/CTioga/plotmaker.rb', line 348

def leave_child_object
  prev = current_object
  if current_object.parent
    self.current_object = current_object.parent
  else
    warn "--end while in top level"
  end
  return prev
end

#lookup_config_fileObject

Looks for a configuration file, either in the current directory or in the HOME directory.



389
390
391
392
393
394
395
396
397
398
399
400
401
# File 'lib/CTioga/plotmaker.rb', line 389

def lookup_config_file
  if File.readable? CONFIG_FILE_NAME
    return CONFIG_FILE_NAME
  end

  if ENV.has_key?('HOME')
    home_rc = File.join(ENV['HOME'], CONFIG_FILE_NAME)
    if File.readable?(home_rc)
      return home_rc
    end
  end
  return nil
end

#margins_from_text(txt) ⇒ Object



484
485
486
487
# File 'lib/CTioga/plotmaker.rb', line 484

def margins_from_text(txt)
  ary = expand_sides(txt).map {|s| s.to_f}
  return ary
end

#next_objectObject

Start the next object in a complex plot (–grid, –col…)



1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
# File 'lib/CTioga/plotmaker.rb', line 1162

def next_object
  # We swicth back to the parent object
  old = leave_child_object
  a = @next_spec.dup      # We need to dup, else shift would make the
  # next curve not that happy...
  cls = a.shift
  # We push the parent object as the last element for new.
  a << current_object
  plot = cls.new(*a)
  @current_object.layout.add_child(GridItemLayout.new(plot))
  enter_child_object(plot)

  # We copy the style from the old plot to the new one:
  plot.plot_style = old.plot_style.deep_copy(plot)
    
  @next_block.call(old, plot) if @next_block
end

#output_figure(fig_name) ⇒ Object

Output a figure with the given name



1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
# File 'lib/CTioga/plotmaker.rb', line 1432

def output_figure(fig_name)
  # now, we plot the stuffs... if there is actually
  # something to be plotted ;-) !

  @figmaker = t = FigureMaker.new
  # Cleanup code off by default, as this could cause problems for
  # legend pictures generation/EPS generation.
  # The files will get cleaned up anyway.
  t.autocleanup = false


  # Now, we must use real_size stuff !! (default 12cmx12cm)
  # This is not part of setup_figure_maker, as it can strongly interfere
  # when ctioga is used to produce a figure.
  info "Producing PDF file of real size #{@real_size}"
  setup_real_size(t) 

  # And, after that, the generic setup of the FigureMaker object.
  setup_figure_maker(t)

  info "Generating file '#{fig_name}.pdf'"

  # If fig_name is clearly a path, we split that bit out
  if File::basename(fig_name) != fig_name
    dir = File::dirname(fig_name)
    # If path is relative and output_directory is specified, we make
    # the path relative to output_dir
    if @output_directory && dir =~ /^[^\/~]/
      dir = File::join(@output_directory, dir)
    end
    t.save_dir = dir
    fig_name = File::basename(fig_name)
  elsif @output_directory
    t.save_dir = @output_directory
  end

  t.def_figure(fig_name) {
    do_figure(t)
  }

  debug "Contents of the main FigureMaker object: " +
    figmaker_options(t)


  if @fast
    # It isn't that fast, actually.
    info "Producing a fast version"
    # We output only the temporary PDF file
    class << t
      undef show_text
      # We replace show_text by show_marker, to at least get text
      # Doesn't work for axes and ticks... Pity ! 
      def show_text(dict)
        for key in %w{side shift position pos justification}
          dict.delete key
        end
        show_marker(dict)
      end
    end
    t.create_figure_temp_files(t.figure_index(fig_name))
    base_name = if t.save_dir
                  File.join(t.save_dir,fig_name)
                else
                  fig_name
                end
    # Remove the _figure.txt files
    File.rename(base_name + "_figure.pdf", base_name + ".pdf")
  else
    t.make_preview_pdf(t.figure_index(fig_name))
  end

  if @eps
    info "Attempting to create an EPS file, watch out error messages"
    # First, we convert the _figure.pdf into eps with pdftops
    cmd = "pdftops -eps #{output_filename('_figure.pdf', fig_name)}"
    debug "Running #{cmd}"
    system cmd
    f = output_filename('.tex', fig_name)
    new = output_filename('.new.tex', fig_name)
    debug "Modifying #{f}"
    orig = open(f)
    out = open(new, "w")
    for l in orig
      l.gsub!('pdftex,','') # \usepackage[pdftex,...]...
      l.gsub!('_figure.pdf', '_figure.eps')
      out.print l
    end
    orig.close
    out.close

    spawn "latex #{new}"
    spawn "dvips -o #{output_filename('.eps', fig_name)} -t unknown -T " +
      "#{@real_size.gsub(/x/,',')} #{output_filename('.new.dvi', fig_name)}"
  end

  if @png
    # We create the PNG file:
    spawn "convert -density #{(@png_oversampling * 72).to_i} "+
      "#{output_filename('.pdf', fig_name)} -resize " +
      "#{@png_size.join('x')} #{output_filename('.png', fig_name)}"
  end

  if @svg
    # We create the SVG file
    spawn "pdf2svg #{output_filename('.pdf', fig_name)} " +
      "#{output_filename('.svg', fig_name)}"
  end

  
  # Generating the separate legends if requested
  if not @separate_legend_styles.empty?
    index = 0
    info "Creating separate lengends"
    for style in @separate_legend_styles 
      name = sprintf "%s_legend_%02d", fig_name, index
      index += 1
      t.def_figure(name) {
        t.set_device_pagesize(@separate_legend_width * 10,
                              @separate_legend_height * 10)
        t.set_frame_sides(0,1,1,0) 
        t.update_bbox(0,0)
        t.update_bbox(1,1)
        style.output_legend_pictogram(t)
      }
      # create_figure takes a number. It is part of Tioga's internals.
      t.create_figure_temp_files(t.figure_index(name))
      

      # Some post_processing to rename the files appropriately
      # and delete the unwanted _figure.txt file
      base_name = if t.save_dir
                    File.join(t.save_dir,name)
                  else
                    name
                  end
      # Remove the _figure.txt files
      begin
        File.rename(base_name + "_figure.pdf", base_name + ".pdf")
        if @eps             # Create also EPS files:
          spawn "pdftops -eps #{base_name}.pdf"
        end
        File.delete(base_name + ".tex")
        File.delete(base_name + "_figure.txt")
      rescue
        warn "Files should have been deleted, but were not found"
      end
    end
  end

  if @cleanup
    files_to_remove = %w(.tex .out .aux .log _figure.pdf _figure.txt) +
      %w(.new.tex .new.aux .new.dvi .new.log _figure.eps) # EPS-related files
  elsif @tex_cleanup
    files_to_remove = %w(.tex .out .aux .log .pdf)
  elsif @clean_all
    files_to_remove = %w(.tex .out .aux .log .pdf _figure.pdf _figure.txt) +
      %w(.new.tex .new.aux .new.dvi .new.log .eps _figure.eps) # EPS-related files

  end
  if @viewer 
    # we display the output file:
    info "Starting the viewer #{@viewer} as requested"
    pdf_file = if t.save_dir
                 File.join(t.save_dir,fig_name+".pdf")
               else
                 fig_name+".pdf"
               end
    system("#{@viewer} #{pdf_file}")
  end
  
  if files_to_remove
    files_to_remove.collect! {|s| 
      output_filename(s, fig_name)
    }
    files_to_remove << "pdflatex.log" 
    info "Cleaning up temporary files"
    debug "Cleaning #{files_to_remove.join ' '}"
    files_to_remove.each do |f| 
      begin
        File.delete(f)
      rescue
        debug "File #{f} absent, not deleted" 
      end
    end
  end

end

#output_filename(suffix, base = @fig_name) ⇒ Object

Provides the name of an output file, given its suffix and optionnaly it base name (defaults to @figure_name).



1254
1255
1256
1257
1258
1259
1260
# File 'lib/CTioga/plotmaker.rb', line 1254

def output_filename(suffix, base = @fig_name) 
  if @figmaker.save_dir
    File.join(@figmaker.save_dir,"#{base}#{suffix}")
  else
    "#{base}#{suffix}"
  end
end

#parse_command_line_arguments(args) ⇒ Object

Parses args as command-line arguments.



1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
# File 'lib/CTioga/plotmaker.rb', line 1263

def parse_command_line_arguments(args)

  # A little trick to allow in-place modification of the
  # command-line from an option.
  @args += args

  # Runs the command to set command-line defaults. Ignored silently
  # in the files given on the command-line.

  quoted_args = args.collect do |s|
    CTioga.shell_quote_string(s)
  end.join ' '

  @command_line = "#{File.basename($0)} #{quoted_args}"

  # Read the CTIOGA environment variable 
  if ENV.key? "CTIOGA"
    ctioga_env = Shellwords.shellwords(ENV["CTIOGA"])
    @parser.parse(ctioga_env)
  end

  if respond_to? :ctioga_defaults
    send :ctioga_defaults
  end

  first = true
  done = false
  while ! done
    begin
      @parser.order!(@args) do |spec|
        # We use Backend#expand to leave room for the backend to
        # interpret the text as many different sets.
        sets = expand_spec(spec)
        info "Expanding #{spec} to #{sets.join(', ')}"
        # Auto --next: 
        next_object if (@auto_next == :element and !first)
        for set in sets
          next_object if (@auto_next == :dataset and !first)
          process_data_set(set)
          first = false
        end
      end
      done = true
    rescue OptionParser::InvalidOption => o
      # Here, we should try to be clever about options:
      new_arg = nil
      option_name = o.args.first.gsub(/^--?/,'')
      # First, we check whether it corresponds to a shortcut:
      if Shortcut.has? option_name
        new_arg = ["--short", option_name]
      # Or an option of the current backend:
      elsif backend.description.param_hash.key? option_name
        new_arg = ["--#{backend.description.name}-#{option_name}"]
      end

      if new_arg
        info "Option #{o.args.first} was reinterpreted " +
          "as #{new_arg.join ' '}"
        @args.unshift(*new_arg)
      else
        debug "Invalid option: #{o.inspect}"
        debug "Remaining args: #{@args.inspect}"
        error "Invalid option: #{o.args.first}. Please run " + 
          "ctioga --help to have a list of valid ones"
        exit 1
      end
    rescue Exception => ex
      # Do not catch normal exit !
      if ex.is_a? SystemExit
        raise
      end
      fatal "ctioga encountered the following problem: #{ex.to_s}"
      debug "Error backtrace: #{ex.backtrace.join "\n"}"
      fatal "Aborting"
      exit 1
    end
  end
end

#prepare_option_parserObject

This function prepares the parser by giving it the arguments and some small help text going along with them. This function will unfortunately get really large with time, but there’s nothing to do about it.



499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
# File 'lib/CTioga/plotmaker.rb', line 499

def prepare_option_parser
  theme_prepare_parser(@parser)

  @parser.separator "\nLaTeX options"
  @parser.on("--use PACKAGE",
             "Adds PACKAGE to the LaTeX preamble") do |w|
    @preamble += "\\usepackage{#{w}}\n"
  end

  @parser.on("--preamble STRING",
             "Adds STRING to the LaTeX preamble") do |w|
    @preamble += "#{w}\n"
  end

  @parser.separator "\nGlobal look:"

  @parser.on("--[no-]background [COLOR]",
             "Sets the background color for plots") do |c|
    # Keep it to false if only false
    c = CTioga.get_tioga_color(c) if c
    current_plot_style.background_color = c
  end

  @parser.on("--[no-]watermark [TEXT]",
             "Writes a text as a watermark at the back ", 
             "of the plot") do |c|
    current_plot_style.watermark_text = c
  end

  @parser.on("--watermark-color [COLOR]",
             "Chooses the color of the watermark") do |c|
    c = CTioga.get_tioga_color(c) if c
    current_plot_style.watermark_color = c
  end

  @parser.on("--watermark-scale SCALE",
             "Chooses the color of the watermark") do |c|
    current_plot_style.watermark_scale = Float(c)
  end

  @parser.on("--aspect-ratio [RATIO]",
             "Sets the aspect ratio (defaults to 1)") do |a|
    a = 1.0 unless a
    a = a.to_f
    if a <= 0.0
      warn "Aspect ratio #{a} not valid, ignored" 
    else
      add_elem_funcall(:set_aspect_ratio, a)
    end
  end
  @parser.on("--golden-ratio",
             "Sets the aspect ratio to the golden number") do |a|
    add_elem_funcall(:set_aspect_ratio, 1.61803398874989)
  end
  @parser.on("--xrange RANGE",
             "X plotting range") do |a|
    set_range('left','right', a)
  end
  @parser.on("--yrange RANGE",
             "y plotting range") do |a|
    set_range('bottom','top', a)
  end
  @parser.on("--margin MARGIN",
             "Sets the margin around data", "(left,right,top,bottom",
             "in fractions of the corresponding size)") do |v|
    current_object.plot_margins = margins_from_text(v)
  end

  @parser.on("--rescale FACTOR",
             "Scales everything by a given factor",
             "(useful for subplots)") do |fact|
    current_object.rescale = safe_float(fact)
  end


  # TODO: this should probably move to PlotStyle
  @parser.on("--padding PADDING",
             "Changes the padding for the current object",
             "and subsequent ones") do |pad|
    ary = expand_sides(pad)
    @default_padding = ary.map {|dim| Dimension.new(dim)}
    use_default_padding
  end

  axes_options(@parser)

  @parser.separator "\nSubfigures, subplots, regions..."

  @parser.on("--y2",
             "Switch to an alternative Y axis") do
    begin
      current_object.disable_axis(:y)
    rescue
      # Purely ignore errors
      warn "Something should have happened here "+
        "that did not happen properly"
    end
    plot = SharedAxisPlot.new(:y, current_object)
    # The label will be on the right
    plot.plot_style.ylabel.side = RIGHT
    plot.plot_style.edges.yaxis.loc = RIGHT
    plot.plot_style.edges.set_edges(AXIS_HIDDEN, :left,:top,:bottom)
    current_plot_style.edges.set_edges(AXIS_LINE_ONLY, :right)
    # A simple layout will control the plot
    layout = FixedLayout.new(plot)        
    # And this layout should report its info to
    # the current one.
    #
    # Note that we add the child's *layout* to the
    # objects layout, not the child itself.
    #
    # Won't fail if the current plot does not have a layout
    if current_object.layout
      current_object.layout.add_child(layout)
    end
    enter_child_object(plot)
  end

  @parser.on("--x2",
             "Switch to an alternative X axis") do
    begin
      current_object.disable_axis(:y)
    rescue
      # Purely ignore errors
      warn "Something should have happened here " +
        "that did not happen properly"
    end
    plot = SharedAxisPlot.new(:x, current_object)
    # The label will be on the right
    plot.xlabel.side = TOP
    plot.edges.xaxis.loc = TOP
    plot.edges.set_edges(AXIS_HIDDEN, :left,:right,:bottom)
    current_object.edges.set_edges(AXIS_LINE_ONLY, :top)
    layout = FixedLayout.new(plot)        
    # And this layout should report its info to
    # the current one.
    #
    # Note that we add the child's *layout* to the
    # objects layout, not the child itself.
    current_object.layout.add_child(layout)
    enter_child_object(plot)
  end

  @parser.on("--inset SPEC",
             "Creates an inset with the given",
             "specifications (x,y:w[xh] or x1,y1;x2,y2)" ) do |a|
    plot = SubPlot.new(:subplot, current_object)
    plot.show_legend = true
    enter_child_object(plot)
    # TODO - high priority !
    # implement a way to specify insets with *real* tex dimensions
    # !!!! (such as 3cm,2cm:5cm) !
    #
    # This would *really* make way for real-size graphs
    margins = Utils::inset_margins(a)
    debug "inset margins: #{margins.inspect}"
    current_object.convert_layout(FixedLayout)
    current_object.layout.position = margins
    # By default, we redirect all legends for the inset
    # to the parent.
    current_object.accept_legend = false
  end

  @parser.on("--zoom-inset SPEC",
             "Creates an inset as with --inset " +
             "and copies all the ",
             "elements in the current plot there") do |a|
    plot = SubPlot.new(:subplot, current_object)
    # We redirect all legends for the inset to the parent.
    plot.accept_legend = false
    # Temporarily disable legends.
    plot.disable_legend = true
    for obj in @current_object.elements
      plot.add_elem(obj.dup)
    end
    for obj in @current_object.funcalls
      plot.add_funcall(obj.dup)
    end
    plot.disable_legend = false
    # Better add it afterwards...
    enter_child_object(plot)
    margins = Utils::inset_margins(a)
    debug "zoom margins: #{margins.inspect}"
    current_object.convert_layout(FixedLayout)
    current_object.layout.position = margins
  end

  @parser.on("--next-inset SPEC",
             "Equivalent to --end --inset SPEC, except that",
             "various style information are carried from",
             "the previous inset") do |a|
    plot = SubPlot.new(:subplot, current_object)
    plot.show_legend = true
    old = leave_child_object
    enter_child_object(plot)

    # Force copy of the style:
    plot.plot_style = old.plot_style.deep_copy(plot)

    margins = Utils::inset_margins(a)
    debug "inset margins: #{margins.inspect}"
    current_object.convert_layout(FixedLayout)
    current_object.layout.position = margins
    # We redirect all legends for the inset to the parent.
    current_object.accept_legend = false
  end

  @parser.on("--subplot SPEC",
             "Creates a subplot with the given specifications",
             "(x,y:w[xh] or x1,y1;x2,y2)" ) do |a|
    plot = SubPlot.new(:subplot, current_object)
    enter_child_object(plot)
    margins = Utils::inset_margins(a)

    debug "subplot margins: #{margins.inspect}"
    # In contrast with --inset, we use a layout:
    current_object.layout = SimpleLayout.new(current_object)
    current_object.layout.bounding_box = margins

    # We do not redirect legends for a subplot
    current_object.accept_legend = true

  end

  @parser.on("--next-subplot SPEC",
             "Creates a subplot with the given specifications",
             "(x,y:w[xh] or x1,y1;x2,y2)" ) do |a|
    plot = SubPlot.new(:subplot, current_object)
    old = leave_child_object
    enter_child_object(plot)
    margins = Utils::inset_margins(a)

    # Force copy of the style:
    plot.plot_style = old.plot_style.deep_copy(plot)

    debug "subplot margins: #{margins.inspect}"
    # In contrast with --inset, we use a layout:
    current_object.layout = SimpleLayout.new(current_object)
    current_object.layout.bounding_box = margins

    # We do not redirect legends for a subplot
    current_object.accept_legend = true

  end



  @parser.on("--disable-legends",
             "Disable the display of legends for the current " +
             "subplot/subfigure") do
    current_object.disable_legend = true
  end

  @parser.on("--enable-legends",
             "Reverts --disable-legends") do
    current_object.disable_legend = false
  end

  @parser.on("--[no-]forward-legends",
             "Forwards the legends to the parent object") do |v|
    current_object.accept_legend = ! v
  end

  # Black magic is starting here !
  @parser.on("--grid SPEC",
             "Creates a grid. SPEC is column|row=nb") do |s|
    # get the spec:
    s =~ /(\w+)=(\d+)/
    which = "#{$1}s=".to_sym
    number = $2.to_i
    if which == :columns= or which == :rows=
      current_object.layout = current_object.layout.
        convert_layout(GridLayout)

      current_plot_style.hide_axis_and_edges(:x, :y)

      # We rescale the padding by a factor of 1/number, so it looks
      # reasonable in the end.
      @default_padding.each do |dim|
        dim.scale!(1.0/number)
      end

      # We use the default padding for the chidren
      use_default_padding

      current_plot_style.set_xy_labels(nil, nil)

      current_object.layout.send(which, number)
      plot = SubPlot.new(:subplot, current_object)
      plot.accept_legend = false
      @current_object.layout.add_child(GridItemLayout.new(plot))
      @current_object.add_elem(plot)
      self.current_object = plot
      @next_spec = [SubPlot, :subplot]
      @next_block = proc do |old, new|
        new.accept_legend = false # By default, forward to the parent.
        use_default_padding(new)
      end
    else
      warn "Unrecognized spec #$1"
    end
  end

  # Black magic is starting here !
  @parser.on("--col",
             "Starts a column of graphes with shared X axis") do
    # We convert the current object to a GridLayout. If
    # there are already plots, that really won't look good.
    # You've been warned !!!
    current_object.layout = current_object.layout.
      convert_layout(GridLayout)
#        current_object.edges.disable

    current_plot_style.hide_axis_and_edges(:x, :y)

    current_object.layout_preferences.padding[2] = Dimension.new(0.0)
    current_object.layout_preferences.padding[3] = Dimension.new(0.0)

    current_object.layout.columns = 1
    plot = SharedAxisPlot.new(:y, current_object)
    @next_spec = [SharedAxisPlot, :y]
    @current_object.layout.add_child(GridItemLayout.new(plot))
    @current_object.add_elem(plot)
    
    # We copy the X label and the title
    plot.plot_style.xlabel.label = current_plot_style.xlabel.label
    current_plot_style.xlabel.label = nil
    plot.plot_style.title.label = current_plot_style.title.label
    current_plot_style.title.label = nil
    self.current_object = plot

    # We cancel vertical padding by default:
    @default_padding[2] = Dimension.new(0.0)
    @default_padding[3] = Dimension.new(0.0)

    use_default_padding(plot)
    # Forwards the x label to the child, and cancels it here.
    # The code to be run on the old and new tings
    @next_block = proc do |old, new|
      old.plot_style.edges.
        set_axis_and_edges_style(:x, AXIS_WITH_TICKS_ONLY)
      old.plot_style.xlabel.label = nil

      # Disable title by default
      new.plot_style.title.label = nil
      use_default_padding(new)
    end
  end

  @parser.on("--next",
             "Start the next object") do
    next_object
  end

  @parser.on("--[no-]auto-next",
             "Automatically start a --next graph",
             "for every element on the command-line") do |v|
    if v
      @auto_next = :element
    else
      @auto_next = false
    end
  end

  @parser.on("--auto-next-expanded",
             "Automatically start a --next graph",
             "for every element on the command-line",
             "after data set expansion !") do
    @auto_next = :dataset
  end


#       @parser.on("--subframes FRAMES",
#                  "Setup the frames relative to the parent", 
#                  "for the current " +
#                  "subplot",
#                  "(distance from left,right,top,bottom)") do |v|
#         current_object.frame_margins = margins_from_text(v)
#       end

  @parser.on("--region",
             "Start a colored region") do
    plot = Region.new(current_object)
    @current_object.add_elem(plot)
    self.current_object = plot
  end

  @parser.on("--region-color COLOR",
             "The color of the region") do |v|
    c = CTioga.get_tioga_color(v)
    begin
      current_object.region_color = c
    rescue
      error "The current container isn't a --region !"
    end
  end

  @parser.on("--region-transparency TRANS",
             "The transparency of the region") do |v|
    c = v.to_f
    begin
      current_object.region_transparency = c
    rescue
      error "The current container isn't a --region !"
    end
  end

  @parser.on("--region-dont-display",
             "No curve until the next --end will actually be ",
             "displayed: they are just used to delimit the ",
             "region used for the fills") do
    begin
      current_object.dont_display = true
    rescue
      error "The current container isn't a --region !"
    end
  end

  @parser.on("--region-debug",
             "Setup the fills for the curves inside the",
             "region to help understanding what happens") do
    begin
      current_object.region_debug = true
    rescue
      error "The current container isn't a --region !"
    end
  end

  @parser.on("--region-invert-rule",
             "Inverts the rule for choosing the filled region") do
    begin
      current_object.invert_rule = true
    rescue
      error "The current container isn't a --region !"
    end
  end

  @parser.on("--region-fill-twice",
             "Fills the region twice, choosing opposite",
             "rules for the boundaries.") do
    begin
      current_object.fill_twice = true
    rescue
      error "The current container isn't a --region !"
    end
  end

  @parser.on("--end",
             "Ends the last subplot or region") do 
    leave_child_object
  end
  

  @parser.separator "\nOptions for real size output:"
  # Real size
  @parser.on("-r", "--[no-]real-size [SIZE]",
             "Tries to produce a PDF file suitable",
             "for inclusion " +
             "with \\includegraphics") do |spec|
    @real_size = spec
  end
  @parser.on("--frame-margins VAL",
             "The proportion of space to leave on", 
             "each side for the text display" ) do |val|
    set_frame_margins(margins_from_text(val))
  end

  Legends::fill_option_parser(@parser, self)

  @parser.separator "\nTexts:"

  ## Default TeX fontsize
  @parser.on("--fontsize NB",
             "Default TeX fontsize in points") do |size|
    @tex_fontsize = size
  end

  @parser.on("--tick-label-scale SCALE",
             "Sets the scale of the text for tick labels") do |l|
    add_elem_funcall(:xaxis_numeric_label_scale=,Float(l))
    add_elem_funcall(:yaxis_numeric_label_scale=,Float(l))
  end


  @parser.on("--[no-]separate-legends",
             "If set, PDF files are produced that contain",
             "what the legend pictogram would look like") do |l|
    @separate_legends = l
    if l
      # Switches off autolegends by default
      @autolegends = false
    end
  end

  @parser.separator "\nGraphic primitives:"
  @parser.on("-d","--draw SPEC",
             "Draw a graphic primitive") do |spec|
    add_elems_to_current(*TiogaPrimitiveMaker.parse_spec(spec, self))
  end
  @parser.on("--draw-help",
             "Display what is known about graphic", 
             "primitives and exit") do
    puts
    puts "Currently known graphics primitives are"
    puts
    puts TiogaPrimitiveMaker.introspect
    exit
  end

  prepare_backend_options(@parser)
                                          
  @parser.separator "\nHousekeeping and miscellaneous options:"
  @parser.on("--xpdf", 
             "Runs xpdf to show the plot obtained") do 
    @viewer = "xpdf -z page" # With the zoom set to full page
  end

  @parser.on("--open", 
             "Runs open to show the plot obtained") do 
    @viewer = "open"
  end

  @parser.on("--[no-]viewer [VIEWER]", 
             "Runs VIEWER to show the plot obtained --",
             "or doesn't show up the viewer at all") do |x|
    @viewer = x
  end
  
  @parser.on("--[no-]cleanup", 
             "Removes all the accessory files produced") do |x|
    @cleanup = x
  end

  @parser.on("--tex-cleanup", 
             "Removes all files produced except those",
             "necessary " +
             "for inclusion in a TeX document") do 
    @tex_cleanup = true
  end

  @parser.on("--clean-all", 
             "Removes all files produced -- better use",
             "along with " +
             "--xpdf or --open") do 
    @clean_all = true
  end
  
  @parser.on("--save-dir DIR", 
             "Sets the directory for output") do |x|
    add_init_funcall(:save_dir=, x)
  end

  
  @parser.on("--include FILE",
             "Imports the file's functions into ctioga's",
             "namespace so that they can be used", 
             "by backends") do |file|
    read_config_file(file)
  end

  @parser.on("-n", "--name NAME",
             "Base name") do |name|
    @fig_name = name
  end

  @parser.on("-o", "--output NAME",
             "Produces a graph named NAME with the current output") do |name|
    output_figure(name)
  end

  @parser.on("-O", "--output-dir DIR",
             "Sets the output directory") do |dir|
    @output_directory = dir
  end

  @parser.on("--echo", "Prints command-line to standard output") do
    puts "Command-line used:"
    puts @command_line
  end

  @parser.on("--display-commandline",
             "Adds the command line used to make",
             "to graph on the bottom of the graph") do 
    add_elem_funcall(:show_marker, 
                     {
                       "x" => 0.5,
                       "y" => -0.2,
                       "text" => @command_line,
                       "scale" => 0.6,
                       "font" => Tioga::MarkerConstants::Courier,
                     }
                     )
  end

  @parser.on("--[no-]mark", 
             "Fills the 'creator' field of the " ,
             "produced PDF file with the command-line",
             "when on. ") do |v|
    @mark = v
  end

  logger_options(@parser)
  @parser.on("--debug-patterns", 
             "Produces an alignement-checking PDF file") do |v|
    @debug_patterns = v
  end

  @parser.on("--eps", 
             "Attempt to produce an EPS file,",
             "using pdftops, LaTeX and dvips.",
             "The PDF output is kept in any case") do |v|
    @eps = v
  end

  @parser.on("--png SIZE", 
             "Runs ctioga as usual, and runs convert afterwards",
             "to produce a nice PNG file") do |s|
    @png = true
    s =~ /(\d+)x(\d+)/
    @png_size = [$1,$2]
    # We setup the real size so that it matches the number of
    # postscript points:
    @real_size = "#{$1}bpx#{$2}bp"
  end

  @parser.on("--png-oversampling NB", 
             "How many more points to produce before downscaling") do |s|
    @png_oversampling = s.to_f
  end

  @parser.on("--svg", 
             "Runs ctioga as usual, and runs pdf2svg afterwards",
             "to produce a nice SVG file") do |s|
    @svg = true
  end


  @parser.on("--args FILE",
             "Reads argument from FILE, *one per",
             "line* and then resumes normal processing") do |v|
    File.open(v) do |f|
      unshift_cmdline_args(*f.readlines.collect {|s| s.chomp})
    end
  end

  @parser.on_tail("-h", "--help", "Show this message") do
    puts banner
    puts 
    puts @parser
    puts 
    puts "Please note that all the options can be abbreviated"
    puts "as long as they are still unique"
    exit
  end

  @parser.on_tail("--version", "Show version number") do
    puts "This is ctioga version " + Version::version
    exit
  end
end

#process_data_set(set) ⇒ Object

This function is called whenever PlotMaker needs to process one data set. It’s name is given in parameter here.



1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
# File 'lib/CTioga/plotmaker.rb', line 1210

def process_data_set(set)
  # First, we get the dataset:
  begin
    data = xy_data_set(set)
  rescue Exception => ex
    error "Problem when processing set #{set} " +
      "(backend #{backend.class}): #{ex.message}"
    debug "Error backtrace: #{ex.backtrace.join "\n"}"
    warn "Simply ignoring set #{set}"
    return                  # Simply return.
  end
    
  # Scale plots if necessary:
  data.mul!(:x,x_factor) if x_factor
  data.mul!(:y,y_factor) if y_factor

  # Add an offset
  data.add!(:x,x_offset) if x_offset
  data.add!(:y,y_offset) if y_offset

  # Implement a logarithmic scale
  data.safe_log10!(:x) if x_log
  data.safe_log10!(:y) if y_log

  data.strip_nan

  # Then we create a curve object and give it style
  if histogram
    curve = Histogram2D.new(get_current_style(set)) 
  else
    curve = Curve2D.new(get_current_style(set)) 
  end
  if @separate_legends
    @separate_legend_styles << curve.style
  end
  curve.set_data(data)

  # Then we add ot to the current object:
  add_elems_to_current(curve)
  @last_curve = curve       # And we update the last_curve pointer.
end

#read_configObject

Reads a configuration file if one is found.



434
435
436
437
438
# File 'lib/CTioga/plotmaker.rb', line 434

def read_config
  if lookup_config_file
    read_config_file(lookup_config_file)
  end
end

#read_config_file(file) ⇒ Object

This function reads a configuration file and executes it’s statements in the scope of a local module, which is then included in this instance, and in the backend’s instances.



369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/CTioga/plotmaker.rb', line 369

def read_config_file(file)
  f = File.open(file)
  info "Reading config file #{file}"
  lines = f.readlines
  lines << "\nend\n"
  lines.unshift "module CTiogaRC\n"
  code = lines.join
  eval code
  extend CTiogaRC
  for b_e in backends.values
    b_e.extend CTiogaRC
  end
  # This is for the compute_formula function.
  Dvector.extend CTiogaRC
end

#run(args) ⇒ Object

Runs the plots, using the arguments given in the command-line. Now delegates to some other small functions.



1622
1623
1624
1625
1626
1627
1628
1629
1630
# File 'lib/CTioga/plotmaker.rb', line 1622

def run(args)

  # First, we parse command-line arguments:
  parse_command_line_arguments(args)

  # Then, we spit the output:
  output_figure(@fig_name)

end

#set_bounds(which, val) ⇒ Object

Forwards the boundary settings to the current object.



453
454
455
456
# File 'lib/CTioga/plotmaker.rb', line 453

def set_bounds(which, val)
  method = ("bound_#{which}=").to_sym
  @current_object.send(method, val)
end

#set_frame_margins(val) ⇒ Object

In the order: left, right, bottom, top, to suit Tioga’s default positioning of the text along the axis.



491
492
493
# File 'lib/CTioga/plotmaker.rb', line 491

def set_frame_margins(val)
  @frame_sides = [val[0], 1.0 - val[1], 1.0 - val[3], val[2]]
end

#set_range(a, b, str) ⇒ Object



458
459
460
461
462
463
464
# File 'lib/CTioga/plotmaker.rb', line 458

def set_range(a,b,str)
  first,last = str.split(/\s*:\s*/)
  first = first.to_f if first
  last = last.to_f if last
  set_bounds(a,first)
  set_bounds(b,last)
end

#set_root_frame(*frames) ⇒ Object

Sets the frame of the root object. This is absolutely necessary for layout computation. Failure to do so will result in failed plots.



406
407
408
# File 'lib/CTioga/plotmaker.rb', line 406

def set_root_frame(*frames)
    @root_object.root_frame = frames
end

#setup_figure_maker(t) ⇒ Object

Setups up various figuremaker variables



1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
# File 'lib/CTioga/plotmaker.rb', line 1343

def setup_figure_maker(t)
  # Setting the TeX fontsize if default is not adequate
  t.tex_fontsize = @tex_fontsize if @tex_fontsize

  # add hyperref preamble to have nice PDF comments:
  if @mark
    # We should use the \pdfinfo pdftex primitive, as
    # this will allow to have less surprises...
    t.tex_preview_preamble += 
      "\n\\pdfinfo {\n  /Title (" +
      CTioga.pdftex_quote_string(@command_line) +
      ")\n" + "/Creator(" +
      CTioga.pdftex_quote_string("ctioga #{Version::version}") +
      ")\n}\n"
  end

  if @debug_patterns
    debug_patterns(t)
  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


  return unless @root_object.number > 0 

  # Asking the theme to do something.
  theme_bod_hook(t)

  # We put the command line used in the .tex file:
  t.tex_preview_preamble += 
    "% Produced by ctioga, with the command-line\n" +
    "% #{@command_line.gsub(/\n/,"\n% ")}\n"
  
  if decimal_separator
    t.tex_preamble += <<'EOD'.gsub(',',decimal_separator) # Neat !
\def\frenchsep#1{\frenchsepma#1\endoffrenchsep} 
\def\fseat#1{\frenchsepma}
\def\frenchsepma{\futurelet\next\frenchsepmw}
\def\frenchsepmw{\ifx\next\endoffrenchsep\let\endoffrenchsep=\relax%
\else\if\next.\ifmmode\mathord,\else,\fi%
\else\next\fi\expandafter
\fseat\fi}
EOD
    t.yaxis_numeric_label_tex = t.
      yaxis_numeric_label_tex.gsub('#1','\frenchsep{#1}')
    t.xaxis_numeric_label_tex = t.
      xaxis_numeric_label_tex.gsub('#1','\frenchsep{#1}')
  end

  # Add custom preamble:
  t.tex_preview_preamble += @preamble

  # If the initialization function was found, we call it
  if respond_to? :ctioga_init
    send :ctioga_init, t
  end

  for funcall in @init_funcalls
    funcall.do(t)
  end

end

#setup_real_size(t) ⇒ Object

sets up the FigureMaker object to use for real size. Uses the



412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/CTioga/plotmaker.rb', line 412

def setup_real_size(t)
  # Get the width and height from @real_size
  sizes = @real_size.split("x").collect {|s| 
    tex_dimension_to_bp(s)
  }

  t.def_enter_page_function {
    t.page_setup(*sizes)
    t.set_frame_sides(*@frame_sides) 
    set_root_frame(sizes[0] * @frame_sides[0], 
                   sizes[0] * @frame_sides[1],
                   sizes[1] * @frame_sides[2], 
                   sizes[1] * @frame_sides[3])
  }

  # Setting label and title scale to 1
  t.title_scale = 1
  t.xlabel_scale = 1
  t.ylabel_scale = 1
end

#subfigureObject



1192
1193
1194
1195
1196
# File 'lib/CTioga/plotmaker.rb', line 1192

def subfigure
  new_object = SubPlot.new(:subfigure,@current_object)
  @current_object.add_elem(new_object)
  @current_object = new_object
end

#subplotObject

the functions for plot structure…



1186
1187
1188
1189
1190
# File 'lib/CTioga/plotmaker.rb', line 1186

def subplot
  new_object = SubPlot.new(:subplot,@current_object)
  @current_object.add_elem(new_object)
  @current_object = new_object
end

#unshift_cmdline_args(*args) ⇒ Object



1181
1182
1183
# File 'lib/CTioga/plotmaker.rb', line 1181

def unshift_cmdline_args(*args)
  @args.unshift(*args)
end

#use_default_padding(obj = nil) ⇒ Object

Sets the given’s object padding to the current default:



327
328
329
330
331
332
333
334
# File 'lib/CTioga/plotmaker.rb', line 327

def use_default_padding(obj = nil)
  obj = current_object unless obj
  4.times do |i|
    obj.layout_preferences.padding[i] = @default_padding[i].dup
  end
  debug "Setting padding for #{identify(obj)} to " +
    obj.layout_preferences.padding.inspect
end