Plotting with the S-Lang Xfig module

From Remeis-Wiki
Jump to navigation Jump to search

SLxfig will not usually come with your standard ISIS installation, but it's an easy to install module. Get it from JedSoft/Xfig

Where to find examples

Most important

Note also the examples on the SLxfig websites of John E. Davis and Manfred Hanke.

--- Manfred's notes from his first introduction on 2010-04-28 --- (to be continued?)

General Tips & Tricks

--- Manfred's notes from his first introduction on 2010-04-28 --- (to be continued?)

If you never plotted with slxfig, please have a look at the next section.

Random pieces of helpful code:

  • Prevent the ticlabels from exceeding the plot size: pl.axis(;ticlabels_confine);
  • Format ticlabels:
    • linear scale: to e.g. 2 places after decimal point: pl.axis(;linear, format="$%.2f$");
    • log scale: to e.g. 2 places after decimal point in power of number: pl.axis(; log, format="$10^{%+.2f}$"); where the + tells to always show the sign of the power
  • LaTex packages which are not loaded per default can be added manually with xfig_add_latex_package("PACKAGENAME");

eps-Files with slxfig

(after Jörns Mail)

The eps produced by the slxfig module is usually VERY large because the postscript code produced by transfig is very inefficient. With some postprocessing you can significantly reduce the figure sizes:

- convert your figure to pdf (the -dEPSCrop is important - this tells ps2pdf to use the eps bounding box): ps2pdf -dEPSCrop bla.eps

- if you really need postscript, e.g., for a journal submission where pdf figures are not allowed, then convert the pdf back to (encapsulated) postscript: pdf2ps -dLanguageLevel=3 bla.pdf bla.ps

a few numbers:

  • original eps file size: 3.9MB
  • pdf file size: 37kB
  • eps file size after converting back: 187kB

the autoeps and tmp folders

The autoeps and tmp folders are always created by default in the folder you're executing your script. These folders contain caching information such that plotting of the same or similar things doesn't have to be done over and over again from scratch. As you have them in each folder separately, these folders tend to be annoying. Either you're deleting the folders occasionally, or you spent quite some amount of disk space for really useless stuff. The solution is to tell slxfig to create these folders in a specifc location. There they don't take up space on /home or /userdata and don't appear in your scripting folders.

So, in order to achieve this you have to do the following:

  1. Create a file named ".slxfigrc" in your home directory
  2. Add the lines
   variable slxfig_tmp_dir;
   if (stat_file("/scratch1") == NULL) {
      slxfig_tmp_dir = "/tmp/"+getenv("USER")+"/xfig/";
   } else {
      slxfig_tmp_dir = "/scratch1/"+getenv("USER")+"/xfig/";
   }
   xfig_set_tmp_dir(slxfig_tmp_dir);
   xfig_set_autoeps_dir(slxfig_tmp_dir);

Then all the temporary files in all of your slxfig scripts will from now on be stored in these directories.

Note that this more complicated setup is done in order to avoid putting files on /tmp, if a /scratch1 file system exists. The reason being that too many files on /tmp might crash your computer, as there is a maximal number of files that can be on a certain disk. And /tmp is located on the disk where the operating system is installed. And now just imagine the chaos when the system itself is not able to write any more files ... so better use a different disk (that means the /scratch1 disk) for the SLxfig tmp files, by following the approach above.


Programming preliminaries

References in S-Lang

References to variables

Functions cannot change scalar arguments that are passed by value:

define test(v)
{ vmessage("in test: v=%d", v);
  v = -1;  % only modifies variable local to test
  vmessage("in test: v=%d", v);
}

variable a=42;
test(a);              % a is passed by value
vmessage("a=%d", a);  % a has not been changed outside of test
test(42);             % test can also be run with a constant

reference operator &, dereference operator @:

variable r = &a;                 % reference to a (from previous example)
vmessage("r=%S; @r=%d", r, @r);  % reference and dereferenced reference

references to variables:

define test2(r)
{ vmessage("in test: @r=%d", @r);
            % r is still only a local variable
  @r = -1;  % r is not changed, but the variable referenced by r
  vmessage("in test: @r=%d", @r);
}

test2(&a);  % (from previous examples)
vmessage("a=%d", a);  % a *has* been changed


see also

References to functions

variable my_fun = &sin;
print( @my_fun(0) );
print( @my_fun(PI/2) );

variable x=[0:10:0.01];
plot(x, @my_fun(x));

my_fun = &exp;
plot(x, @my_fun(x));


Object-oriented programming

The following function only operates on "car-structures":

define drive_car(c, dest)
{
  vmessage("%s drives from %s to %s", c.plate, c.place, dest);
  c.place = dest;
}

define init_car(plate, place)
{
  return struct { plate=plate, place=place };
}

variable car = init_car("S-FR 3011", "Erlangen");
drive_car(car, "Bamberg");
drive_car(car, "Erlangen");

It should thus be more directly connected to such an object. => Define a new field of the structure with reference to the function:

define init_car(plate, place)
{
  return struct { plate=plate, place=place, drive=&drive_car };
}

variable car = init_car("S-FR 3011", "Erlangen");
(@car.drive)(car, "Bamberg");  % @car.drive  is actually the function  drive_car

OO in S-Lang

from the S-Lang manual, Appendix A.3 What's new for S-Lang 2.0:

Syntactic sugar for objected-oriented style method calls.
S-Lang 1 code such as
(@s.method)(s, args);
may be written much more simply as
s.method(args);
This should make "object-oriented" code somewhat more readable.

car.drive("Erlangen"); % car is implicitly passed as first argument to drive_car

Xfig

http://www.xfig.org/

The S-Lang xfig module

see John E. Davis' homepage, especially the examples page

The examples from the git repository

 git://git.jedsoft.org/git/slxfig.git

(or my Mh branch on http://www.sternwarte.uni-erlangen.de/~hanke/git.public/slxfig) are also available on http://pulsar.sternwarte.uni-erlangen.de/hanke/science/X-ray/ISIS/SLxfig/.

Xfig objects as OO-style S-Lang structures

variable po = xfig_new_polygon([0, 2, 1, 0], [0, 0, 2, 0]);
print(po);  % structure with many internal fields
            % and methods (function references) that should be used as interface
po.render("polygon.eps");  % writes .fig file, runs xfig to produce output

po.set_fill_color("red");
po.set_area_fill(20);
po.render("polygon_red.eps");

Polygon.pngPolygon red.png

High-level plot objects

variable pl = xfig_plot_new();
variable x = [0:10:0.01];
pl.plot(x, sin(x));  % x-y plot
pl.title("a nice sine wave $y=\sin(x)$"R);  % SLxfig renders text via latex
pl.xlabel("$x$");
pl.ylabel("$y$");
pl.render("plot.pdf");  % run XFig's fig2dev to create an pdf file
pl.render("plot.eps");  % run XFig's fig2dev to create an eps file
pl.render("plot.png");  % run XFig's fig2dev to create a png

plot

define world coordinate system(s):

variable pl2 = xfig_plot_new(7, 5);  % size of the plot window in cm x cm (default is 14 cm x 10 cm)
pl2.world(-2, 12, -1.5, 1.5);
pl2.world2(-2/PI, 12/PI, -1.5, 1.5);
pl2.plot(x, sin(x));
pl2.render("plot2.eps");

Plot2.png

configuration of the axes via qualifiers

variable pl3 = xfig_plot_new(7, 5);
pl3.world(-2, 12, -1.5, 1.5);
pl3.world2(-2/PI, 12/PI, -1.5, 1.5);
pl3.y2axis(; off);  % totally switch off y2-axis
pl3.y1axis(; ticlabels=0);  % only remove y1 tic mark labels
pl3.x2axis(; major=[0, PI/2, PI]);  % define own major tic marks
pl3.x1axis(; major=[-1, 5, 11], minor=[-5:15:0.5]);  % But then, one (currently) also has to define the minor tic marks!
pl3.plot(x, sin(x));
pl3.render("plot3.eps");

Plot3.png

I'm trying to document these functions. Suggested syntax for methods of objects: help("xfig_plot.x1axis"); Or directly from the method itself: pl.x1axis(; help);