JOG: Jhack's Own Graphics

A very slim and portable graphic software:

jogging is good for your figures!

Features

This software was designed to produce scatter and triangular plots from plain ascii files using the postscript language. It is a small set of postscript functions and a C program to wrap the postscript code into either a printable A4 page document or a so called encapsulated postscript image suitable to include in office documents. This slim software is not designed to produce 3d plots or contour plots. So if you need this, check somewhere else: scilab may be a possibility.

Jogging: first steps

The next few examples provides a quick survey and and a set of templates for the impatients. They are intended to help potential users to find out if this software is able to efficiently tackle their problem. A more formal description of the software is given elsewhere but this document should be enough for a quick evaluation of the features strengths and weaknesses versus that of other tools such as gnuplot, grace (Xmgr), spreadsheets...

A basic understanding of postscript syntaxe is needed to fully understand this document: see for instance <insert some url or link>

Simple scatter plots

This exemple shows 3 instructions used to define a rectangular scatter plot. The argument of Axe2 command is a vector giving the low and high bounds of the X and Y axis, i.e. [ Xmin Xmax Ymin Ymax ]. The next two lines defines the graduations and labels of both axis. All other layout parameters are default values. This should be the most common way to start a graphic. Note that labels are given as a vector of strings of numerical values between (). This enables to choose precisely the format for the labels.
 
exemple 0
[ 0 100 -0.6 1.6 ] Axe2
[ (0) (25) (50) (75) (100) ] GradX
[ (-0.50) (0) (0.50) (1.00) (1.50) ] GradY

The previous figure is a bitmap image ( 0.png ) of the original encapsulated postscript imahe ( 0.eps ) obtained with the command ge 0 which uses the source jog file 0.jog ( on the right side of the figure ). However to get a hard copy on an A4 page the companion command g 0 will produce 0.ps which is shown below (using ghostview) and illustrates the standard layout of the plot on an A4 page. I choosed to leave blank space above the figure for tables of labels or other informations and on the left for binding. Note that the eps figure is cropped automatically with a small 10 points margin around the  drawing, so its actual location and size are not critical. Also eps can be scaled as needed in the final document without loss of information.

0_A4.png

The next example shows a plot of  data points using the default plot mode ( black open circles ). The coordinates of each data point are given in a vector delimited by []. The actual layout of the code is unimportant (spaces, tabs and end of line are not distinguished in Postscript), however the presentation used shows Xi and Yi in two columns for clarity.
exemple 1
[ 0 100 -0.6 1.6 ] Axe2
[ (0) (25) (50) (75) (100) ] GradX
[ (-0.50) (0) (0.50) (1.00) (1.50) ] GradY
[
10 -0.3
20 0.15
30 0.25
40 0.40
60 0.65
80 0.73
] Plot

Data points can be given in several other ways. The next example shows the same data points plotted as the previous example, then using two vectors [ xi ] then [ yi ] and plotted in red with lines and crosses. A small set of commands enable to modify the current plot mode, controlling the symbol used, color, filled or not, with or without lines/symbol.

exemple 2
[ 0 100 -0.6 1.6 ] Axe2
[ (0) (25) (50) (75) (100) ] GradX
[ (-0.50) (0) (0.50) (1.00) (1.50) ] GradY
[
10 -0.3
20 0.15
30 0.25
40 0.40
60 0.65
80 0.73
] Plot

[ 10 20 30 40 60 80 ]
[ -0.3 0.15 0.25 0.40 0.65 0.73 ]
WithLines Red Cross

Postscrip is a full fledge programing language. The following example shows how to use variables. Vector a and b are defined then used in two plot instructions.

exemple 3
[ 0 100 -0.6 1.6 ] Axe2
[ (0) (25) (50) (75) (100) ] GradX
[ (-0.50) (0) (0.50) (1.00) (1.50) ] GradY
/a [ 10 20 30 40 60 80 ] def
/b [ -0.3 0.15 0.25 0.40 0.65 0.73 ] def
a b Black Circles
a [ 1.2 0.95 0.6 0.3 -0.1 -0.3 ]
WithLines Green Filled Diamonds
 

Using tables of data: Cols and Col

Often the data are selected colums of a table (may be copied from a spreadsheet). The funtions Cols and Col shown in the next example help to handle this type of data. The Cols functions prototype is:
amn n jx jy Cols -> xy
where amn is an array of m*n elements seen as an m rows by n column matrix; the number of column n must be given as 2d argument and consistent with the actual length of the array; then jx and jy are the indices of the columns used for X and Y values respectively. The second function Col extract a single column of a table. Its use is shown in the last paragraph of the code ploting the orange squares and dashed line, using the first column of t1 and the second of t2.

NOTE: t1 and t2 identifiers are actually substituted by an array and an integer; the integer is the number of columns of the m by n matrix mapped on the postscript array. Therefore the calls to Cols or Col are t1 jx jy Cols or t1 jx Col because the array and n are hidden in t1 or t2. Remember that postscript does not care for end of lines, so that the layout of t1 suggest that I consider an array of 20 elements  as a matrix of 4 rows by 5 columns, but this must be asserted explicitly giving the number of columns and assuming a row major ordering (C style) for the array.

cols.png
% Using tables of data
% note the number of col after the array.
% t1 represents an array and an integer
% needed in this order in the plot functions
/t1 { [
1 0 -1 2 1
2 2 0 5 0
3 4 2 3 1
4 3 3 2 2
] 5 } def

% same number of lines as t1
% BTW NOTE 1/3 and 2/3 accurate values in col 3
% coded 1 3 div ! YES it works !
/t2 { [
2 1 3 div
5 2 3 div
3 0.6
2 2.4
] 2 } def

[ -2 6 -2 6 ] Axe2
[(0)(2)(4)(6)] GradX
[(-2)(0)(2)(4)(6)] GradY

Filled % symbols
Blue
t1 1 5 Cols Circles
Violet
t1 1 3 Cols WithLines Diamonds

% plot x y vectors of the same size taken from different tables
Orange 2 Dash
t1 1 Col t2 2 Col Squares
 

Labels and other tricks

Several other features are shown in the next figure:
exemple 4
(Times-Roman) 15 Font
[70 570 70 570][ 0 100 0 100 ] Axe2
[(25)(50)(75)] GradX
[(25)(50)(75)] GradY
25 Font
(Axe X) GradX
(Axe Y) GradY
?
0 10 [ 0 10 20 30 40 50 60 ] Violet Filled Circles
?
[0 10 20 30 40 50 60]
[60 50 40 30 20 10 0 ]
Blue Cross
?
[
0 5 10 15 20 25 30 35
40 45
50 55
60 65
] WithLines Red Filled Squares
?
Black 15 Font
10 90 s2o % paper location to start writing labels
(NoLines Violet Filled Circles) ( What it is ) Label
(WithLines Red Filled Squares) ( Another one ) Label
(NoLines Blue Cross) (and the last one) Label
?

Jogging with style

Using some simple postscript features to get a clearly structured file and first of all comments. Some other tricks are used: metric conversion of points with the mm command. Using some predefined dashed patterns and gsave grestore postscript instructions to save and restore the current graphic mode ( color, line thickness etc...). Another convenient instruction is used to convert from user coordinate to paper coordinate ( currently named s2o  from french sujet -> objet ; I might change this to pp for paper or postscript points).

exemple 5
(Times-Roman) 15 Font
0.35 mm Pen % modify curent line width in mm
[70 570 70 570] % [left right bottom top] in paper coordinates
[
0 100 0 100 ] % [Xmin Xmax Ymin Ymax ] in user coordinates
Axe2


[
(25)(50)(75)] GradX % array of string means text and position
[(25)(50)(75)] GradY % of labels for GradX and GradY
25 Font % use larger font for titles
(Axe X) GradX % a string argument is understood as the title
(Axe Y) GradY
% Here we define the data vectors to plot
/X [ 5 15 30 45 50 70 80 ] def
/Y1 [60 50 40 30 20 10 0 ] def
/Y2 [ 30 35 40 43 25 22 12 ] def
% we can do some simple calculation on data
/Y3 [ Y2 { 1.2 mul } forall ] def
/XY [ 30 35 60 65 80 85 ] def
% then use them in plot function call
0 10 Y1 NoLines Violet Filled Circles
X Y1 NoLines Orange Filled Squares
X Y2 NoLines Red Cross
X Y3 WithLines Blue Empty Diamonds
gsave XY Red 1 Dash Lines grestore % local dash
% write some labels for the various plots
Black 15 Font
10 90 s2o % paper location to start writing labels
% s2o convert from user coordinate to paper coordinats
% these 2 numbers are used by the first Label call
% subsequent calls just skip to the next line
(NoLines Violet Filled Circles) ( 0 10 Y1 ) Label
(NoLines Orange Filled Squares) ( X Y1 ) Label
(NoLines Red Cross) ( X Y2 ) Label
(WithLines Blue Empty Diamonds) ( X Y3 ) Label
gsave
(Red 1 Dash Lines) ( XY ) Label
grestore
% some more drawing on the graph in user coord
0.1 mm Pen
[ 0 20 100 20 ] Black Lines

Colors and other decorations


Managing colors and simple calculations to layout a table of colored symbols and a few other things:  plotting closed lines and surfaces, clipping.

exemple 6
?
[ 0 100 -0.6 1.6 ] Axe2
[ (0) (25) (50) (75) (100) ] GradX
[ (-0.50) (0) (0.50) (1.00) (1.50) ] GradY
?
% axes titles can also be provided in GradX and GradY functions
18 Font (Axe X) (Axe Y) Titles
25 Font (Labels and colors) Titles
18 Font Blue 2 Pen
?
% Test for clipping within a given area default the plot window
% this is not recommanded because export software may not handle clipping properly
gsave
?
Clip % by default Fobj Clip
?
[ -20 0.9 40 0.2 120 -0.4 ] Lines
grestore % returns to unclipped
% clip is off after restore so circles are drawn across border line
20 Size % change symbol size
[0 0 50 0 100 0] Green Plot
10 Size
% Draw in reverse depth so background first...
0.9 setgray
[
5 -0.15
20 0.2
35 0.45
50 0.23
60 -0.11
] Surface
10 Size Red WithLines Diamonds
?
[
30 0.123
50 0.456
70 0.895
] Plot
% the plot statement is the last one Order of other is unimportant
% They can be placed even before the data vector
[ 80 1.21 85 0.85 ] Violet 6 Size NoLines Filled Circles
% or Lines : here same thing if called before symbol
[ 85 1.0 95 0.90 ] Red WithLines Empty Squares
?
15 Size NoLines Black % color for text of legends while symbols
% will have their own color as given in first arg.
/x 150 def /y 700 def % we need variables to
% layout our table of symbols and labels
?
x y
( 0 Color Filled Circles ) (Color 0) Label
( 1 Color Filled Circles ) (Color 1) Label
( 2 Color Filled Circles ) (Color 2) Label
( 3 Color Filled Circles ) (Color 3) Label
( 4 Color Filled Circles ) (Color 4) Label

x 100 add y
( 5 Color Filled Circles ) (Color 5) Label
( 6 Color Filled Circles ) (Color 6) Label
( 7 Color Filled Circles ) (Color 7) Label
( 8 Color Filled Circles ) (Color 8) Label
( 9 Color Filled Circles ) (Color 9) Label

x 200 add y
( 10 Color Filled Circles ) (Color 10) Label
( 11 Color Filled Circles ) (Color 11) Label
( 12 Color Filled Circles ) (Color 12) Label
( 13 Color Filled Circles ) (Color 13) Label
( 14 Color Filled Circles ) (Color 14) Label
?
x 320 add y
( 15 Color Filled Circles ) ( Color 15 ) Label
( 16 Color Filled Circles ) ( Color 16 ) Label
( 17 Color Filled Circles ) ( Color 17 ) Label
( 18 Color Filled Circles ) ( Color 18 ) Label
( 19 Color Filled Circles ) ( Color 19 ) Label
% example of strings with index/exponents and greek letters
% Only one modifier for the next char ( NO greek index/exponent though ! )
Black
30 Font
200 385 moveto (`m_1 `u_a `b `G) Show
200 350 moveto (H_2O f_H_2 `DG_r) Show

Jogging and running

One important feature is to be able to run external commands and include the output in the graphic. This is illustrated with 2 trivial shell script in the next example. Lines with a leading ! are replaced by the output of the following shell command. In the example we use two external awk scripts to generate the functions ploted.

Note: The F appended to the font name indicates a re-encoded font for the latin character set ( so that french accented characters are maped properly ). Both Times-RomanF and HelveticaF are available. Times-Roman and Helvetica are standard postscript fonts with posrscript encoding ( this is ok for plain ascii ).

exemple 7
(Times-RomanF) 25 Font
0.5 mm Pen
[ 50 550 50 800][ 0 30 -0.5 1 ] Axe2
[ (0) (10) (20) (30) ] GradX
[ (-0.4) (-0.2) (0) (0.2) (0.4) (0.6) (0.8) (1.0) ] GradY

gsave % save current color pen etc...
0.15 mm Pen
[ Xmin 0 Xmax 0 ] Black 1 Dash Lines
grestore % restore color pen dash...
?
gsave
[
% LC_NUMERIC=C to make sure that "." is the decimal separator
! LC_NUMERIC=C ./sinx.awk
] Blue Lines
grestore
?
gsave
[
! LC_NUMERIC=C ./sinx2.awk
] 1 Dash Red Lines
grestore
300 720
% beware to escape ( in a postscript string
( Blue ) ( sin\(x\)/x ) Label
( Red 1 Dash Lines ) ( sin\(x\)/sqrt\(x\) ) Label
?

The two simple awk script are shown below:

sinx.awk
sinx2.awk
#! /bin/awk -f
BEGIN {
for ( x=0.02; x<30.0; x+=0.05 ) {
printf("%10.3f %10.5f\n",x,sin(x)/x)
}
}

#! /bin/awk -f

BEGIN {
for ( x=0.02; x<30; x+=0.05 ) {
printf("%10.3f %10.5f\n",
x,
sin(x)/sqrt(x)+0.1)
}
}
 

Multiple plots

This shows how to use several plot windows simultaneously in the same graphic; 4 plotting windows are defined and their properties saved in the variables W1, W2, W3 and W4 using the Win command with an identifier as argument e.g. /W1 Win. Then the second variant of the Win command with a value argument enables to chose the current plot windowe.g. W1 Win.
There is also a test of Clipping within the plot window. This is sometimes needed, but note that clipping will make your graphics less portable in the sense that translation to different vector languages ( xfig, open office draw, svg... ) will most probably not handle clipping properly.

exemple 8

% kludge to move and scale the fig on the page without
% modification to the code
% 0.7 0.7 scale
% 130 320 translate
(Times-Roman) 12 Font
/Data [ 15 10 20 20 50 50 75 25 12 18 ] def
/Width 250 def
/Height 250 def
/Bottom 60 def
/Left 50 def
/Xshift { Width 10 add } def
/Yshift { Height 10 add } def
% same values for all windows
[ 0 100 0 100 ] Axe2
/gr [(20)(40)(60)(80)] def
gr (Titre X_1) GradX
gr (Y_1 axis title) GradY
/W1 Win % save user window 1
%
/Left Left Xshift add def
[ 0 100 0 100 ] Axe2
(Titre X_2) gr GradX
gr false GradY
/W2 Win % save user window 2
%
/Left Left Xshift sub def % order
/Bottom Bottom Yshift add def % is
[ 0 100 0 100 ] Axe2
gr false GradX
(Y_3 axis title) gr GradY
/W3 Win % save user window 3
%
/Left Left Xshift add def
[ 0 100 0 100 ] Axe2
gr false GradX
gr false GradY
/W4 Win % save user window 4
%
W1 Win %=== recall W1 user window
Data Filled Red Circles
%
W2 Win % now in the 2d window and so on...
Data Empty Blue Circles
?
W3 Win
Data Filled Green Circles
?
W4 Win
Data Filled Black Squares
?
W1 Win
[-5 -10 120 110 ] 1 Dash 0.5 setgray Lines
gsave
Fobj Clip % Clip plot in current window
[-5 -10 120 110 ] Red Lines
grestore % revert to unclipped plot mode

Jogging along a triangle

The Axe3 module must be loaded as it is not included by default. Point coordinates are given as fractions of component 2 (SiO2) and 3 (K2O). A simple postscript code is used to adjust the data given in % to the default scale of the plot which is 0..1. This is just to point out again that postscript offers all standard control such as loops. There are variants of Axe3 function to avoid this kind of trick.

exemple 9
#include Axe3
(Na_2O) (SiO_2) (K_2O) Axe3
/Tbl [
20.0 25.0
35.0 15.0
50.0 16.5
60.0 5.33
] def
% here I scale to 0..1 instead of 0..100
[ Tbl { 100 div } forall ] Plot


Multiple plots can also be used with triangular plots as illustrated below:

exemple asub and superscripts in a string
#include Axe3
% TODO ? change Xa Ya -> Gauche Bas or Left Bottom
% and Cote should be Largeur / Width...

/Cote 70 mm def
8 Font
0.5 Pen
2 Size

/Xa 30 def
/Ya 30 def
(Na_2O) (SiO_2) (K_2O) Axe3
/T1 Win

/Ya Yc 30 add def
(K_2O) (SiO_2) (K_2O) Axe3
/T2 Win

/Ya Yc 30 add def
(Al_2O_3) (SiO_2) (FeO) Axe3
/T3 Win

/Xa Xb 50 add def
/Ya 30 def
(Na_2O) (SiO_2) (K_2O) Axe3
/T4 Win

/Ya Yc 30 add def
(K_2O) (SiO_2) (K_2O) Axe3
/T5 Win

/Ya Yc 30 add def
(Al_2O_3) (SiO_2) (FeO) Axe3
/T6 Win

% the data table
/Tbl [
20.0 25.0
35.0 15.0
50.0 16.5
60.0 5.33
] def

Filled % all symbols filled

T1 Win
[ Tbl { 100 div } forall ] Blue Circles

T5 Win
[ Tbl { 100 div } forall ] Red Squares

T2 Win
4 Size
[ 0.3 0.2 0.154 0.233 ] Olive WithLines Squares

Careful or sloppy text

The function Wrt enables to write lines of text anywhere; the following example is also meant to be a quick reference on how to code all greek characters.
Default line spacing is used controlled by the current font size. Advance text processing IS NOT within the scope of a slim software, and kept deliberately very simple.
Note: in this example no plot window is defined. In this case the standard postscript coordinate system is used: isometric, length in points ( 1/72 inch ) origin at the botom left corner of the page.











greek.png

% Writing one line at 50,700
50 700 (Table of) Wrt
% without coord. writes on the next line(s)
(matching) Wrt
% append other lines to the current paragraph...
(Roman) (and Greek) (characters) Wrt
% This can also be achieved in a single Wrt with
% a pair of coordinates and one or several strings
200 700
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13)
Wrt
% now let's print a nice blue table of greek letters
Blue
/xo 270 def
/yo 700 def
xo yo
(a `a) (b `b) (c `c) (d `d) (e `e) (f `f)
(g `g) (h `h) (i `i) (j `j) (k `k) (l `l) (m `m) Wrt
/xo xo 60 add def
xo yo
(n `n) (o `o) (p `p) (q `q) (r `r) (s `s)
(t `t) (u `u) (v `v) (w `w) (x `x) (y `y) (z `z) Wrt
/xo xo 60 add def
xo yo
(A `A) (B `B) (C `C) (D `D) (E `E) (F `F)
(G `G) (H `H) (I `I) (J `J) (K `K) (L `L) (M `M) Wrt
/xo xo 60 add def
xo yo
(N `N) (O `O) (P `P) (Q `Q) (R `R) (S `S)
(T `T) (U `U) (V `V) (W `W) (X `X) (Y `Y) (Z `Z) Wrt
%
/p1 {68 126} def % defining coord. of a point p1
/p2 {170 287} def % and p2
/p3 {270 160} def % and yet a third point
%
[ p1 p2 p3 ] Green Polygone
Violet
% NOTE points p1 must be different from p2 otherwise slope is undefined
[ p1 p2 ] ( <- p_1 p_2 -> ) Wrt
p1 p3 ( <- p_1 p_3 -> ) Wrt % this variant is also accepted
% yet I prefer [] () Wrt for consistency with Plot functions
[ p2 p3 ] ( <- p_2 p_3 -> ) Wrt
[ p3 p2 ] ( <- p_3 p_2 -> ) Wrt



A simplified version of the previous example is shown below, with the encapsulated postscript image as a screen copy of ghostview window. This shows how to use the Wrt function. First we select the current font at 30 points. Then locate the first string to print on the page and print the first column. Then we offset the x value to the right and prints the other 3 columns. Note: the ` modifier applies to the next character only.
30 Font
/xo 270 def
/yo 700 def
xo yo
(a `a) (b `b) (c `c) (d `d) (e `e) (f `f)
(g `g) (h `h) (i `i) (j `j) (k `k) (l `l) (m `m) Wrt   
/xo xo 80 add def
xo yo
(n `n) (o `o) (p `p) (q `q) (r `r) (s `s)
(t `t) (u `u) (v `v) (w `w) (x `x) (y `y) (z `z) Wrt
/xo xo 80 add def
xo yo
(A `A) (B `B) (C `C) (D `D) (E `E) (F `F)
(G `G) (H `H) (I `I) (J `J) (K `K) (L `L) (M `M) Wrt
/xo xo 80 add def
xo yo
(N `N) (O `O) (P `P) (Q `Q) (R `R) (S `S)
(T `T) (U `U) (V `V) (W `W) (X `X) (Y `Y) (Z `Z) Wrt