Je m'adresse spécialement à ceux d'entre vous qui publient des articles scientifiques sur le web.
Nous sommes en présence d'une contradiction.
Il y a sur le web un langage natif il s'agit d'html.
Il y a en sciences un standard il s'agit de Latex.
Que font en pratique les auteurs scientifiques? Ils écrivent en Latex, et transforment en format pdf ou postscript. Ils rendent ensuite accessibles leurs articles au moyen des visionneurs de pdf plus ou moins intégrés aux navigateurs standard. Le résultat est généralement correct, mais aucun espoir d'avoir une moindre forme d'interactivité. Les pdf sont essentiellement statiques ...
Le temps est venu d'écrire des mathématiques INTERACTIVES, avec des programmes javascript, des applets java, etc... Je m'y emploie depuis une année déjà.
A souligner que les initiatives de ce genre sont suffisamment peu nombreuses pour qu'on en parle.
L'auteur de sites web consacrés à la science a donc un problème qu'il peut résoudre de deux manières.
Convertir automatiquement le pdf en html (le résultat est épouvantable). Pour vous en convaincre, vous n'avez qu'à voir les 'versions html' des documents pdf, c'est à peine lisible.
Convertir avec des produits comme 'KILE' les formules en images au format GIF ou PNG. C'est un truc que j'ai utilisé et que j'utilise encore parfois. Toutefois, le rendu n'est pas toujours excellent d'une part, l'image est figée d'autre part de sorte que toute correction est laborieuse.. En outre les images n'obéissent pas aux commandes de zoom du navigateur, elles ne font pas partie du texte.
Il existe une solution théorique extrêmement élégante et promue à un bel avenir: le langage MathML. A mon avis MathML est beaucoup plus cohérent, plus 'clean' que Latex (avec tout le respect que nous devons tous à D. Knuth) Mais il y a un mais ...
Firefox sait lire les formules MathML pourvu qu'elles se trouvent dans un fichier d'extension xhtml. Explorer ne sait pas lire directement un fichier xhtml. Explorer peut lire une formule MathML mais avec un 'plug-in', nommé MathPlayer. Encore que la version du plugin doit être conpatible avec la version d'internet explorer 6,7,8, demain 9 ????
D'autres navigateurs 'Opera' sont éduqués pour lire du MathML dans un fichier html, d'autres comme Chrome ne le sont pas.
Bref, c'est pour le moment un véritable 'casse-tête' que de faire un document html comportant des formules MathML et lisible par tous les navigateurs leaders du marché.
La solution sera bien sûr la reconnaissance du format MathML et son intégration dans tous les navigateurs. Ce jour viendra, et quand les internautes auront mis à jour leurs navigateurs vers les versions les plus récentes on peut espérer qu'il sera possible d'écrire pour le grand public...
Que faire en attendant ???
J'ai remarqué que les symboles mathématiques sont disponibles en totalité dans le langage html sous la forme &....;
exemples;
∀ ∃ ∅
Tout l'alphabet grec est disponible en majuscules comme en minuscules.
Bref, du point de vue des symboles il ne manque rien et tous les navigateurs les lisent.
Seul problème, en html on ne peut produire que des expressions 'linéaires' et pas des formules étagées.
D'où les trucs habituels (1+x)/(1-y) au lieu de la notation étagée traditionnelle.
Indices et exposants sont également disponibles <sub> ..</sub> <sup>..</sup>
mais s'appliquent encore une fois à des expressions linéaires, pas à des expressions étagées.
Gérer les niveaux en html pur nécessite l'emploi des tableaux.
C'est possible, à la main, mais fort laborieux (gestion du format des cellules, des bordures, des alignements, des fusions, etc...)
D'où l'idée d'écrire un script python qui gère les écritures à plusieurs niveaux.
Voici ce programme:
L'idée est assez simple. La syntaxe utilisée est préfixée à la LISP mais avec la syntaxe python des listes.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 # -*- coding: utf-8 -*- # To change this template, choose Tools | Templates # and open the template in the editor. __author__ = "gilles" __date__ = "$3 août 2009 16:42:34$" Ops=['ind','pow','frac','par','abs','integ','sum','prod','prod_null','prod_dot','prod_cross','equ','radic','add','sub','neq','le','ge','lt','gt','cpn','lim','forces','equiv'] Varsm=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'] VarsM=[x.upper() for x in Varsm] Grecm=['alpha','beta','gamma','delta','epsilon','zeta','eta','theta','iota','kappa','lambda','mu','nu','ksi','omicron','pi','rho','sigma','tau','upsilon','phi','khi','psi','omega'] def string_form(exp): return isinstance(exp, str) def number_form(exp): return isinstance(exp,int) or isinstance(exp,float) or isinstance(exp,long) def index_form(exp): return exp[0] == "ind" def pow_form(exp): return exp[0] == "pow" def frac_form(exp): return exp[0]=="frac" def par_form(exp): return exp[0]=="par" def abs_form(exp): return exp[0]=="abs" def integ_form(exp): return exp[0]=="integ" def sum_form(exp): return exp[0]=="sum" def prod_form(exp): return exp[0]=="prod" def lim_form(exp): return exp[0]=="lim" def prod_null_form(exp): return exp[0]=="prod_null" def prod_dot_form(exp): return exp[0]=="prod_dot" def prod_cross_form(exp): return exp[0]=="prod_cross" def equ_form(exp): return exp[0]=="equ" def le_form(exp): return exp[0]=="le" def ge_form(exp): return exp[0]=="ge" def lt_form(exp): return exp[0]=="lt" def gt_form(exp): return exp[0]=="gt" def neq_form(exp): return exp[0]=="neq" def radic_form(exp): return exp[0]=="radic" def add_form(exp): return exp[0]=="add" def sub_form(exp): return exp[0]=="sub" def cpn_form(exp): return exp[0]=="cpn" def forces_form(exp): return exp[0]=="forces" def equiv_form(exp): return exp[0]=="equiv" def http_code(exp): if string_form(exp): return exp if number_form(exp): return str(exp) if index_form(exp): return http_code(exp[1]) + "<sub>" + http_code(exp[2]) + "<sub>" if pow_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td></td><td>"+http_code(exp[2])+"</td></tr><tr><td>"+http_code(exp[1])+"</td><td></td></tr></table>" if frac_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>"+http_code(exp[1])+"</td></tr><tr><td><hr></td></tr><tr><td align='center'>"+http_code(exp[2])+"</td></tr></table>" if par_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td><font size='6'>(</font></td><td>"+http_code(exp[1])+"</td><td><font size='6'>)</font></td></tr></table>" if abs_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td><font size='6'>|</font></td><td>"+http_code(exp[1])+"</td><td><font size='6'>|</font></td></tr></table>" if integ_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>"+http_code(exp[2])+"</td><td></td></tr><tr><td><font size='20'>∫</font></td><td>"+http_code(exp[3])+"</td></tr><tr><td align='center'>"+http_code(exp[1])+"</td><td></td></tr></table>" if sum_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>"+http_code(exp[2])+"</td><td></td></tr><tr><td><font size='20'>Σ</font></td><td>"+http_code(exp[3])+"</td></tr><tr><td align='center'>"+http_code(exp[1])+"</td><td></td></tr></table>" if lim_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>lim </td><td align='center' rowspan='1'>"+http_code(exp[2])+"</td></tr><tr><td>"+http_code(exp[1])+"</td></tr></table>" if prod_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>"+http_code(exp[2])+"</td><td></td></tr><tr><td><font size='20'>Π</font></td><td>"+http_code(exp[3])+"</td></tr><tr><td align='center'>"+http_code(exp[1])+"</td><td></td></tr></table>" if prod_null_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td>"+http_code(exp[2])+"</td></tr></table>" if add_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td>+</td><td>"+http_code(exp[2])+"</td></tr></table>" if sub_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td> - </td><td>"+http_code(exp[2])+"</td></tr></table>" if prod_dot_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td valign='middle'>"+".</td><td>"+http_code(exp[2])+"</td></tr></table>" if prod_cross_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td valign='middle' >"+"×</td><td>"+http_code(exp[2])+"</td></tr></table>" if equ_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td>=</td><td>"+http_code(exp[2])+"</td></tr></table>" if forces_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td>⇒</td><td>"+http_code(exp[2])+"</td></tr></table>" if equiv_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td>⇔</td><td>"+http_code(exp[2])+"</td></tr></table>" if neq_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td>≠</td><td>"+http_code(exp[2])+"</td></tr></table>" if le_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td>≤</td><td>"+http_code(exp[2])+"</td></tr></table>" if ge_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td>≥</td><td>"+http_code(exp[2])+"</td></tr></table>" if lt_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td><</td><td>"+http_code(exp[2])+"</td></tr></table>" if gt_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>"+http_code(exp[1])+"</td><td>></td><td>"+http_code(exp[2])+"</td></tr></table>" if radic_form(exp): return "<table cellpadding='0' cellspacing='0' border='0'><tr><td>√</td><td>"+http_code(exp[1])+"</td></tr></table>" if cpn_form(exp): return "<table cellpadding='O' cellspacing='O' border='0'><tr><td rowspan='2'><font size='5'>(</font></td><td>"+http_code(exp[2])+"</td><td rowspan='2'><font size='5'>)</font></td></tr><tr><td>"+http_code(exp[1])+"</td></tr></table>" def subst(x,y,E): if number_form(E): return E if string_form(E): if E==x: return y else: return E else: return [E[0]]+ [subst(x,y,X) for X in E[1:]] def su(x,y): global E E=subst(x,y,E) def init_globals(): globals().update([(k,k) for k in Ops]) globals().update([(k,k) for k in Varsm]) globals().update([(k,k) for k in VarsM]) globals().update([(k,'&'+k+';') for k in Grecm]) GrecM=[x.capitalize() for x in Grecm] globals().update([(k,'&'+k+';') for k in GrecM]) if __name__ == "__main__": init_globals()
Ainsi [frac,x,y] est la fraction x/y (étagée)
Ensuite on peut substituer à x une autre fraction ou une puissance ou une racine.
Voici par exemple un quotient à niveaux multiples:
et voici le code html généré:Code:
1
2
3
4
5
6
7
8
9
10
11
12 #exemple direct print http_code([equ,[frac,"u<sub>n+1</sub>-u<sub>n</sub>","u<sub>n</sub>-u<sub>n-1</sub>"],[prod_cross,[frac,"u<sub>n</sub>-a","u<sub>n-1</sub>-a"],[frac,[sub,1,[frac,"u<sub>n+1</sub>-a","u<sub>n</sub>-a"]],[sub,1,[frac,"u<sub>n</sub>-a","u<sub>n-1</sub>-a"]]]]]) #exemple avec utilisation de subst E=[equ, A,B] E=subst(A,[frac,"v<sub>n</sub>-a","u<sub>n</sub>-a"],E) E=subst(B,[sub,X,Y],E) E=subst(X,[prod_cross,U,V],E) E=subst(U,[frac,k,"1-k"],E) E=subst(V,[frac,"u<sub>n+1</sub>-a","u<sub>n</sub>-a"],E) E=subst(Y,[frac,k,"1-k"],E) print http_code(E)
Des raccourcis on été prévus pour les substitutions su(X,[frac,A,B]) au lieu deCode:
1
2 <table cellpadding='0' cellspacing='0' border='0'><tr><td><table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>u<sub>n+1</sub>-u<sub>n</sub></td></tr><tr><td><hr></td></tr><tr><td align='center'>u<sub>n</sub>-u<sub>n-1</sub></td></tr></table></td><td>=</td><td><table cellpadding='0' cellspacing='0' border='0'><tr><td><table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>u<sub>n</sub>-a</td></tr><tr><td><hr></td></tr><tr><td align='center'>u<sub>n-1</sub>-a</td></tr></table></td><td valign='middle' >×</td><td><table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'><table cellpadding='0' cellspacing='0' border='0'><tr><td>1</td><td> - </td><td><table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>u<sub>n+1</sub>-a</td></tr><tr><td><hr></td></tr><tr><td align='center'>u<sub>n</sub>-a</td></tr></table></td></tr></table></td></tr><tr><td><hr></td></tr><tr><td align='center'><table cellpadding='0' cellspacing='0' border='0'><tr><td>1</td><td> - </td><td><table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>u<sub>n</sub>-a</td></tr><tr><td><hr></td></tr><tr><td align='center'>u<sub>n-1</sub>-a</td></tr></table></td></tr></table></td></tr></table></td></tr></table></td></tr></table> <table cellpadding='0' cellspacing='0' border='0'><tr><td><table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>v<sub>n</sub>-a</td></tr><tr><td><hr></td></tr><tr><td align='center'>u<sub>n</sub>-a</td></tr></table></td><td>=</td><td><table cellpadding='0' cellspacing='0' border='0'><tr><td><table cellpadding='0' cellspacing='0' border='0'><tr><td><table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>k</td></tr><tr><td><hr></td></tr><tr><td align='center'>1-k</td></tr></table></td><td valign='middle' >×</td><td><table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>u<sub>n+1</sub>-a</td></tr><tr><td><hr></td></tr><tr><td align='center'>u<sub>n</sub>-a</td></tr></table></td></tr></table></td><td> - </td><td><table cellpadding='0' cellspacing='0' border='0'><tr><td align='center'>k</td></tr><tr><td><hr></td></tr><tr><td align='center'>1-k</td></tr></table></td></tr></table></td></tr></table>
E=subst(E,X,...).
Bref, tout cela fait que ce petit programme sans prétention est utilisable pour une production très rapide de code html pour le rendu des formules. J'écris avec aussi vite qu'en Latex ou en MathML et mes formules sont tout à fait lisibles par tous les navigateurs. Il va de soi que c'est une solution provisoire, pour quelques mois ou quelques années en attendant que le standard MathML soit reconnu. Tout programmeur python comprendra immédiatement comment il fonctionne et pourra l'étendre à sa guise.