JOG: Jhack's own graphics

Jogging is good for your figures !

Ce logiciel est un prologue Postscript qui permet de composer des graphiques de façon simple et automatisable. Il suppose une connaissance élémentaire de la syntaxe Postscript. L'utilisateur dispose de deux systèmes de coordonnées, le premier est le système Postscript par défaut en points ( 1/72e de pouces ) origine en bas à gauche de la page (dénommé coordonnées objets). Une option permet d'utiliser des coordonnées métriques en mm. Le second système de coordonnées est celui qui est défini par les limites du rectangle de tracé ; on parlera de coordonnées utilisateur (ou sujet). Pour définir le second système de coordonnées il faut donner les valeurs des coordonnées sujets correspondant aux limites objets de la fenêtre de tracé (rectangulaire ou triangulaire suivant les cas).


Un petit nombre de commandes permet de reporter des symboles, lignes, polygones et textes en utilisant l'un ou l'autre des 2 systèmes de coordonnées. Le logiciel permet de plus d'insérer des valeurs explicitement ou à partir de commandes arbitraires ( programmes ou commandes externes ). On peut donc réaliser des opérations à l'aide du language Postscript ou de programmes quelconques. Les quelques exemples suivants peuvent servir de modèles pour réaliser des graphes simples sans connaissance approfondies du language Postscript.

On présente une série d'exemples qui donnent les principales fonctions du logiciel. Il faut copier les exemples dans un fichier texte et utiliser la commande g ou ge <le nom du fichier avec/ou sans le suffixe .jog> pour voir la figure avec ghostview et obtenir le fichier Postscript de même nom avec suffixe .ps ou .eps suivant la commande utilisée ( g ou ge ).

En résumé, si la source est toto.jog La commande shell g toto fabrique le fichier toto.ps qui peut être imprimé ne varietur. La visioneuse Postscript montrera la page A4 complète. La commande ge toto fabrique le fichier Postscript encapsulé toto.eps, qui est une image utilisable dans un document bureautique ou autre et qui est limité à la zone utile du dessin avec une petite marge blanche de 10 points. Ces commandes g et ge sont des scripts simples de quelques lignes modifiables si besoin.

Le programme minimum

Des options par défaut limitent au maximum les informations à fournir. La première ligne de l'exemple suivant défini les bornes de la fenêtre rectangulaire dans le système de coordonnées de l'utilisateur et trace cette fenêtre. Les deux instructions suivantes trace les valeur numériques et graduations.

0.png

./fig/0.jog



[ 0 100 -0.6 1.6 ] Axe2
[ (0) (25) (50) (75) (100) ] GradX
[ (-0.50) (0) (0.50) (1.00) (1.50) ] GradY

L'exemle suivant ajoute des points à ce graphe. Les coordonnées utilisateur des points sont données à la commande Plot dans un vecteur. Le symbole par défaut (cercle vide) est utilisé.

1.png

./fig/1.jog



[ 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

Il est possible de communiquer les coordonnées de point sous la forme de deux vecteurs X et Y comme il est illustré dans l'exemple suivant dans le dernier paragraph où les mêmes points sont reportés avec des croix rouges et des lignes.

2.png

./fig/2.jog



[ 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

Une des caractéristique de ce logiciel est qu'il utilise l'interpréteur Postscript et donc on peut comme illustré ci-dessous nommer des vecteurs pour les utiliser plus loin. Dans une première étape on défini les vecteurs a et b, puis on peut les utiliser en argument des instructions de report de points. On a aussi illustré différents attributs qui permettent de controller le style des graphiques: symboles vides ou pleins, avec ou sans lignes, couleurs nommées...

En fait toute la puissance du language peut être utilisée pour paramétrer les graphiques.

3.png

./fig/3.jog



[ 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

Quelques points nouveaux:

4.png

./fig/4.jog



(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

On peut structurer la présentation d'un fichier jog en paragraphes définissant la présentation, les données, et les instructions de report de points assez facilement comme illustré ci-dessous.

On peut aussi réaliser facilement des calculs élémentaires sur les éléments d'un vecteur: changement d'échelle, translation etc. en utilisant les opérateurs Postscript:

/Y3 [ Y2 { 1.2 mul } forall ] def
Les éléments du vecteur Y3 sont ceux de Y2 multipliés par 1.2.

5.png

./fig/5.jog



(Times-Roman) 15 Font
0.35 mm Pen
[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
% 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

Clochettes et sifflets

6.png

./fig/6.jog



?
[ 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 on 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

Données calculées

Une ligne commençant par ! est remplacée par la sortie de la commande shell qui suit le !. Cette méthode permet de faire des figures dynamiques, qui ne contiennent que la mise en page et dont les données sont calculées par un programme externe quelconque. L'exemple suivant montre comment dessiner des fonctions avec des shell script simples:

sinx.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)
  }
}
sinx2.awk
#! /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)
  }
}

J'ai choisi des exemples simples et courts avec awk mais on peut utiliser n'importe quel commande externe pour générer les couples x y ad hoc.

7.png

./fig/7.jog



(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
?

Plusieurs figures

Cet exemple illustre la réalisation de plusieurs figures sur la même page et comment reporter des données dans l'une ou l'autre avec la fonction Win

Les positions des fenêtres sur la page peuvent être celles par défaut, ou communiquées ( voir exemples précédants ) par un vecteur donnant en coordonnées papier les bornes du rectangle : [ Gauche Droite Bas Haut ]. Ces informations peuvent aussi être fournies par des valeurs de variables /Bas /Gauche /Largeur et /Hauteur. Dans ce cas les variables /Droite et /Haut sont calculées par Axe2 et utilisables dans le graphique.

La fonction Win utilise un argument qui peut être une variable Postscript ( nom précédé de /) ou une valeur (un nom). Dans le premier cas les informations qui définissent la fenêtre courante de dessin ( calculée par Axe2 ) sont mémorisées, dans l'autre ces données sont modifiées à partir de celle de la variable

8.png

./fig/8.jog



% 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
/Largeur 250 def
/Hauteur 250 def
/Bas 60 def
/Gauche 50 def
/Xshift { Largeur 10 add } def
/Yshift { Hauteur 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
%
/Gauche Gauche Xshift add def
[ 0 100 0 100 ] Axe2
(Titre X_2) gr GradX
gr false GradY
/W2 Win % save user window 2
%
/Gauche Gauche Xshift sub def % order
/Bas Bas Yshift add def       % is
[ 0 100 0 100 ] Axe2
gr false GradX
(Y_3 axis title) gr GradY
/W3 Win % save user window 3
%
/Gauche Gauche 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

Diagramme triangulaire

9.png

./fig/9.jog



#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

La même chose avec plusieurs graphiques sur la même page.

a.png

./fig/a.jog



#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