Plotting with the S-Lang Xfig module
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
- linear scale: to e.g. 2 places after decimal point:
- 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:
- Create a file named ".slxfigrc" in your home directory
- 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
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 ass.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
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");
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
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");
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");
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);