local expression A B C
foreach e of local expression {
list _ms
mac
}/*
_ms : A
_ms : B
_ms : C
*/
list _ms
mac * _ms: C
Automatiser la programmation
Les informations qui vont suivre demande un minimum de pratique avec la manipulation des macros Stata.
1 Macros empilées
Le principe est plutôt simple, il s’agit lors d’une expression en boucle de conserver et empiler les expressions générées à chaque itération, et les enregistrer dans une macro.
1.1 Syntaxe type
Exemple : On veut obtenir la chaîne de caractère «A B C » à partir des trois éléments distincts « A », « B » et « C ».
Avec une macro standard:
Dans chaque itération, chaque expression a bien été enregistrée, mais elle est écrasée à l’itération suivante. On pourrait à chaque itération enregistrer chaque macro et les empiler à l’extérieur de la boucle, mais il est possible de le faire automatiquement avec une macro dite « empilée ».
La syntaxe est simple, on appelle la macro dans l’expression qui la génère, ce qui permet de la garder en mémoire à chaque boucle.
Syntaxe:
local nom_macro `nom_macro' expression
global nom_macro $nom_macro expression
Avec une macro empilée:
local expression A B C
foreach e of local expression {
local me `me' `ms'
list _me
mac
}
/*A chaque itération
_me: A
_me: A B
_me: A B C
*/
*Expression finale enregistrée list _me
mac * _me: A B C
1.2 Automatiser la création du graphique
Pour un graphique, une application évidente est d’alléger et automatiser une syntaxe qui empile plusieurs objets graphiques de même nature. Si on reprend un type de nuage de points déjà exécuté de nombreuses fois dans ce document:
tw scatter price mpg if rep78==1
scatter price mpg if rep78==2
|| scatter price mpg if rep78==3
|| scatter price mpg if rep78==4
|| scatter price mpg if rep78==5 ||
Avec une macro empilée:
* On génère la syntaxelevelsof rep78, local(l)
foreach v of local l {
local scat `scat' scatter price mpg if rep78==`v' ||
}
* Exécution du graphiquetw `scat' , legend(off)
Ce qui est généré par la macro à chaque itération :
Itération 1:
scatter price mpg if rep78==1 ||
Itération 2:
scatter price mpg if rep78==1 || scatter price mpg if rep78==2 ||
Itération 3:
scatter price mpg if rep78==1 || scatter price mpg if rep78==2 ||
scatter price mpg if rep78==3 ||
Itération 4
scatter price mpg if rep78==1 || scatter price mpg if rep78==2 ||
scatter price mpg if rep78==3 || scatter price mpg if rep78==4 ||
Itération 5
scatter price mpg if rep78==1 || scatter price mpg if rep78==2 ||
scatter price mpg if rep78==3 || scatter price mpg if rep78==4 ||
scatter price mpg if rep78==5 ||
C’est la dernière qui est finalement enregistrée et il ne manque plus qu’à l’appeler après tw
. Au-delà de l’allègement de la syntaxe du grap recode rep78 (1=2) hique cette manière de procéder automatise des modifications faites en amont, par exemple ici un regroupement de modalités de la variable rep78.
de modifier le graphique
*Il n’est pas nécessaire
levelsof rep78, local(l)
foreach v of local l {
local scat `scat' scatter price mpg if rep78==`v' ||
}tw `scat' , legend(off)
1.3 Générer une légende
Sur le même principe, on peut générer automatiquement une légende. L’opération peut néanmoins s’avérer un peu plus délicate, en raison du contrôle des doubles quotes pour les labels.
Dans un premier temps on ne va pas utiliser les fonctions macro qui permettent de récupérer automatiquement les noms et le contenu des labels.
Sans les fonctions macro:
local l1 `""Domestic""'
local l2 `""Foreign""'
forvalue i=1/2 {
local ord `ord' `i' `l`i''
}
macro list _ord
* _ord: 1 "Domestic" 2 "Foreign"
#delimit ;
tw scatter price mpg if !foreign
|| scatter price mpg if foreign
||, legend(order(`ord'))
;
Rappel: pour la légende on doit explicitement récupérer les doubles quotes pour les expressions qui seront affichées dans la légende: local nom_macro `““expression”“’
Avec les fonctions macro:
Les fonctions utilisées sont value label
pour récupérer le nom du label et lab
pour récupérer l’expression affectée à la modalité. Comme les expressions de la légende vont être récupérées via des macros on va accroître le nombre de quotes, ce qui peut s’avérer fastidieux pour lire le programme et éventuellement le modifier. Dans le programme qui suit on va générer automatiquement la syntaxe principale du graphique avec une macro empilée, comme expliqué précédemment. Les noms des variables seront également transformés en token. Pour anticiper un changement de variable de stratification, ici foreign, on va utiliser un compteur pour automatiser le nombre d’éléments contenu dans la légende.
local varlist price weight foreign
tokenize `varlist'
* Légendelocal labn: value label `3' // on récupère le nom du label
levelsof `3', local(l)
local i=1
foreach l2 of local l {
local lab`l2': label `labn' `l2' // on récupère l’expressions pour chaque valeur
local lab`l2' `""`lab`l2''""' // on transforme l’expressions en macro
local ord `ord' `i++' `lab`l2'' // on génère la syntaxe de la légende
}
* Graphique
local ops mlc(black) mlw(vthin)
foreach i of local l {
local scat `scat' scatter `1' `2' if `3'==`i', `ops' ||
}
tw `scat', legend(order(`ord'))
2 Routine (.ado)
Manuel d’aide Stata [entrée syntax] https://www.stata.com/manuals/p.pdf#ppProgramming
Principe des programmes qui exécutent des commandes (.ado)
La routine/commande peut être programmée dans un programme principal (.do) ou sauvegardé comme .ado dans le répertoire où sont enregistrées les commandes externes (répertoire ado). Il est conseillé de sauvegarder ses propres commandes dans un sous répertoire personal, et de créer des sous répertoire par lettre de l’alphabet. Le nom du fichier .ado doit être identique au nom de la commande programmée.
Nous allons décrire seulement quelques principes qui utilisent les éléments vus dans ce chapitre. Il est difficilement envisageable de s’engager dans la programmation d’une commande sans utiliser le manuel d’aide officiel.
Syntaxe générique
capture program drop nom_commande // jusqu’à la validation du programme
program define nom_routine [options]
syntax [arguments]
de la routine...
* ....programme end
La première ligne est nécessaire tant que la commande est exécutée dans l’éditeur de programme. Elle peut être supprimée lorsque le programme est enregistré dans un sous répertoire du répertoire personal.
Exemple: une simple division
Programmation de la routine:
capture program drop division
program define division
syntax anything
tokenize `anything'
di ""
di as result "Le résultat de la division est: " `1' / `2'
end
Exécution et résultat:
division 1245 722
de la division est: 1.7243767 * Le résultat
Application pour un graphique
On va automatiser l’exécution du nuage de points avec une stratification, ici la variable foreign.
Programme
capture program drop sgraph
program define sgraph
syntax varlist(min=3 max=3), [gops(string)]
tokenize `varlist'
* Légendequi levelsof `3', local(l)
local i=1
local labn: value label `3'
foreach l2 of local l {
local lab`l2': label `labn' `l2'
local lab`l2' `""`lab`l2''""'
local ord `ord' `i++' `lab`l2''
}
* Syntaxe graphique
foreach l2 of local l{
local ops "mlc(black) mlw(*.3) jitter(3) mc(%80) msiz(*1) mlc(`mlc')"
local scat `scat' scatter `1' `2' if `3'==`l2', `ops' ||
}
* Exécution du graphique
tw `scat', legend(order(`ord') rows(1) pos(6) region(color(%0))) `title' `gops'
end
Exécution de la commande sgraph
ylabel(,labs(*.6)) title("mpg") name(mpg, replace)) sgraph price mpg foreign, gops(
Programme pas à pas
capture program drop sgraph
program define sgraph
syntax varlist(min=3 max=3), [gops(string)]
tokenize `varlist'
- La commande s’appelle
sgraph
. - Pour être exécutée, elle demande 3 arguments de type variable. On fixe un nombre obligatoire de variable égale à 3 : axe Y, axe X et la variable de stratification.
- La commande a un argument optionnel . Comme pour les fichiers d’aide, le caractère optionnel est indiqué par [nom_option].
- Le nom de l’option est précisé: elle permet de passer des options générales d’un graphique (
gops()
). On indique son format attendu, ici une chaîne de caractères.
* Légendequi levelsof `3', local(l)
local i=1
local labn: value label `3'
foreach l2 of local l {
local lab`l2': label `labn' `l2'
local lab`l2' `""`lab`l2''""'
local ord `ord' `i++' `lab`l2''
}
* Syntaxe graphique
foreach l2 of local l{
local ops "mlc(black) mlw(*.3) jitter(3) mc(%80) msiz(*1) mlc(`mlc')"
local scat `scat' scatter `1' `2' if `3'==`l2', `ops' ||
}
La légende et la syntaxe du graphique combiné sont générés avec une macro empilée
* Exécution du graphiquetw `scat', legend(order(`ord') pos(6) region(color(%0))) `title' `gops'
end
Le graphique est exécuté, l’option qui a été définie est entrées sous forme de macro.
Le programme du graphique indique déjà des éléments optionnels liés à la légende, comme la position et l’absence de contour. Il est possible d’écraser ces arguments « par défaut » dans l’option gopts
.
Exemple : générer rapidement un graphique qui combine le prix à plusieurs variables avec la commande sgraph
foreach X of varlist mpg trunk weight length {
#delimit ;`X' foreign,
sgraph price title("`X'")
gops( ylabel(, labs(*.6))
name(`X', replace)) nodraw
;
cr
#delimit
local g `g' `X' //macro empilée pour lister les graphiques combinés
}
`g', legendfrom(mpg) pos(11) title("Variables combinées avec" "la variable price") grc1leg