Archive for the ‘Reporting’ Category

h1

SAS : obtenez des couleurs sympas dans vos rapports en 5 minutes

août 20, 2018

h1

Deux exemples d’usage de la syntaxe de l’ODS : PROC PRINT et PROC REPORT

juin 26, 2011

Jusqu’à présent, j’ai présenté la syntaxe de l’ODS (Output Delivery System) de SAS avec la procédure PROC REPORT pour générer vos tableaux dans des fichiers .rtf (ODS RTF), .pdf (ODS PDF) ou en XML avec extension .xls (ODS TAGSETS.EXCELXP).

PROC PRINT se révèle dans les cas les plus simples aussi avantageux. Voici deux fichiers .pdf contenant la même table, une fois générée avec PROC REPORT et une fois avec PROC PRINT.

ods listing close;

*1. Exemple de l’ODS avec PROC REPORT;

ods pdf file=‘O:/sasref/exemple_report.pdf’;
proc report data=sashelp.class nowd;
columns sex age;
define sex / display style(column)=[cellwidth=2cm];
define age / display style(column)=[cellwidth=3cm];
run;
ods pdf close;

*2. Exemple de l’ODS avec PROC PRINT;

ods pdf file=‘O:/sasref/exemple_print.pdf’;
proc print data=sashelp.class nobs;
var sex / style(column)=[cellwidth=2cm];
var age / style(column)=[cellwidth=3cm];
run;
ods pdf close;

ods listing;

h1

Répéter la valeur d’une variable sur chaque page avec ODS RTF

septembre 26, 2010

Il y a un peu plus d’un mois, je vous parlais de l’option SPANROWS de PROC REPORT pour pouvoir répéter une valeur groupée sur chaque page du listing.

Mais si vous devez créer un fichier .RTF et non un fichier .PDF ou si vous n’avez pas SAS 9.2, vous pouvez vous rabattre sur cette solution.

Elle présente le seul inconvénient de séparer la table en table distincte à chaque nouvelle valeur du la variable groupée.

Voici donc un exemple à tester par vous même.

1. Le setting

Par simple soucis de présentation, quelques instructions de paramétrage sont données.

  • Enlever le titre par défaut avec l’instruction TITLE.
  • Enlever la date et le numéro de page par défaut et alignez le résultat à gauche.
  • Créer un format caractère SEX où M réfère à Garçon et F à Fille.


*——————————————–;
* Setting;
*——————————————–;

title;
options nodate nonumber nocenter;

proc format;
value $ sex ‘M’=‘Garçon’
‘F’=‘Fille’;
run;

2. Préparation des données

Afin d’avoir assez de données le fichier CLASS est multiplié par 5. Les noms sauvegardés dans la variable NAME sont incrémentés d’un nombre.

*——————————————–;
* 2. Data Preparation;
*——————————————–;

data class;
set sashelp.class;
output;
name=cats(name,’1′);
output;
name=cats(name,’2′);
output;
name=cats(name,’3′);
output;
name=cats(name,’4′);
output;
name=cats(name,’5′);
output;
run;

3. Reporting;

Vos données doivent être triées afin d’utiliser l’instruction BY dans PROC REPORT.

L’option d’ODS RTF STARTPAGE=NEVER empêchera le passage à une nouvelle feuille à chaque nouvelle valeur de la variable SEX.

Au moyen des options COMPUTE/ENDCOMP, il est possible de personnaliser le texte en début de chaque page. Un texte aligné à gauche est ajouté. Une ligne avant et une ligne après sont ajoutées pour faciliter la lisibilité du rapport. Ce texte est composé de « SEXE :  » suivi de la valeur formatée de la variable SEX.

*——————————————–;
* 3. Reporting;
*——————————————–;

proc sort data=class;
by sex;
run;

*options nobyline;

ods rtf file=’C:/…/test1.rtf’ startpage=never;
proc report data=class;
by sex;
column sex name;
define sex  / /*id*/ group noprint ;
define name / display  ‘Nom’;

compute before _page_ /style=[just=left] ;
line ‘ ‘;
line @1 ‘Sexe:’ @6 sex $sex. ;
line ‘ ‘;
endcomp;

run;

ods rtf close;

h1

Avec ODS, comment ajouter des caractères spéciaux ≤ et ≥

septembre 19, 2010

Comment inclure dans un rapport généré par ODS les symboles ≤ et ≥ ? En effet, ils ne font pas parti des caractères spéciaux ASCII classiques, il s’agit de caractères dépendants d’une police de caractères en particulier : la police « symbol ».

SAS propose un article sur le sujet. Je vous propose de détailler l’exemple utilisé qui a été utilisé avec SAS 8.2 sous environnement DBCS.

1. Setting

Dans cette instruction ODS ESCAPECHAR, est précisé que l’accent circonflexe sera utilisé, non pas comme simple caractère, mais comme caractère introduisant une notation particulière pour le style.

ods escapechar= »^ »;

Un format appelé TEMP est créé. La valeur 11 aura un label composé du symbole « inférieur ou égal ».

  • Le symbole « inférieur ou égal » en lui même est introduit par le code hexadécimal A3.
  • Pour que ce que code corresponde à « inférieur ou égal », il faut utiliser la police de caractère, d’où le code font_face=symbol.
  • Avant A3, on change le style et en particulier la police de caractère. Notez ici l’accent circonflexe introduit précédemment pour entrer la police.
  • Après A3, on arrête d’utiliser cette police.

proc format;
value temp 11=‘The value is ^S={font_face=symbol}’ « A3″x ‘^S={} the value’;
run;

2. Reporting

A présent SAS va écrire tout ce qui suite dans un fichier temp.rtf. Vous avez ici seulement besoin de préciser le chemin d’accès au fichier dans les guillemets.

Le résultat s’affichera correctement dans votre fichier .RTF mais pas dans votre sortie listing classique. Autant fermer cette destination avec ODS LISTING CLOSE.

ods listing close;

ods rtf file=‘temp.rtf’;

Les deux tableaux imprimé se basent sur la table CLASS dans la bibliothèque SASHELP.

Dans le premier cas, le format créé précédemment est appliqué à la variable AGE. On aura dont le label de format défini précédemment quand AGE=11.

title ‘This uses the special characters in the value’;
proc print data=sashelp.class;
format age temp.;
run;

Dans ce second exemple, le symbole « supérieur ou égal » est introduit avec le code hexadécimal B3 d’où « B3″x.

Comme précédemment, il est entouré de ^S={font_face=symbol} avant et ^S={} après.

Cette fois ci pas contre le symbole est ajouté dans le label d’une variable. Chacun des groupes de mot est donc mis entre guillemets.

title ‘This uses the special characters in the label’;
proc print data=sashelp.class label;
label age=« Age » « ^S={font_face=symbol} » « B3″x « ^S={} » « 10 »;
run;

Enfin, on précise de former le fichier .rtf et donc de ne plus ajouter d’info dedans à partir de maintenant.

ods rtf close;

ods listing;

Source : Usage Note 24054: In ODS, how can I add special characters such as GE or LE to my output?

Lecture complémentaire

h1

Une option SAS 9.2 pour ODS PDF : répéter une valeur groupée sur plusieurs pages

août 3, 2010

Lorsque vous construisez un listing avec ODS PDF et PROC REPORT l’option GROUP de l’instruction DEFINE sert à n’afficher chaque valeur de la variable concernée qu’une seule fois.

Hors, si cette valeur s’applique aux observations de plusieurs pages, elle ne sera pas répétée à moins d’ajouter l’option SPANROWS nouvelle avec SAS 9.2.

Cette options ne fonctionne pas actuellement avec ODS RTF.

Voici un exemple pour tester par vous même.

1. Le setting

Par simple soucis de présentation, quelques instructions de paramétrage sont données.

  • Enlever le titre par défaut avec l’instruction TITLE.
  • Enlever la date et le numéro de page par défaut et alignez le résultat à gauche.
  • Créer un format caractère SEX où M réfère à Garçon et F à Fille.


*——————————————–;
* Setting;
*——————————————–;

title;
options nodate nonumber nocenter;

proc format;
value $ sex ‘M’=‘Garçon’
‘F’=‘Fille’;
run;

2. Préparation des données

Afin d’avoir assez de données le fichier CLASS est multiplié par 5. Les noms sauvegardés dans la variable NAME sont incrémentés d’un nombre.

*——————————————–;
* 2. Data Preparation;
*——————————————–;

data class;
set sashelp.class;
output;
name=cats(name,’1′);
output;
name=cats(name,’2′);
output;
name=cats(name,’3′);
output;
name=cats(name,’4′);
output;
name=cats(name,’5′);
output;
run;

3. Reporting

Enfin la section qui nous intéresse vraiment : générer un fichier .RTF et un fichier .PDF avec l’option SPANROWS et voir que que seul ODS RTF tient compte de cette option pour répéter l’observation en début de chaque nouvelle page.


*——————————————–;
* 3. Reporting;
*——————————————–;

ods listing close;
ods rtf file=‘C:\sasref\test1.rtf’;
ods pdf file=‘C:\sasref\test1.pdf’;


proc report data=class spanrows nowd;
column sex name;
define sex / group ‘Sexe’;
define name / display ‘Nom’ ;
run;


ods pdf close;
ods rtf close;
ods listing;

h1

Mettre des données côte-à-côte pour votre reporting

mai 24, 2010

Lorsque vous devez présenter vos données (faire du reporting), vous pouvez vous trouver dans la situation suivante : mettre côte-à-côte des données qui n’ont rien à voir entre elles. La situation peut se résoudre très rapidement avec un merge sans instruction BY. Mais que faire dans le cas où vous devez quand même grouper vos données par une clé (exemple l’identifiant du client) mais dans chaque source plus d’une observation par clé ? C’est ce que je vous propose de découvrir dans cet article.

1. Les données pour l’exemple

Deborah a deux lignes d’observation et Patrick aussi.

data demography;
length cl_name $10 criteria $10 ;
input cl_name $ criteria $ crit_value ;
datalines;
deborah age 15
deborah height 1.66
patrick age 14
patrick height 1.75
;
run;

Deborah a acheté 4 articles (DVD, téléphone portable, une radio et des écouteurs (4 lignes d’observations pour Deborah) tandis que Patrick a acheté deux articles.

data sell;
length cl_name $10 achat $10;
input cl_name $ achat $;
datalines;
deborah dvd
deborah mobile
deborah radio
deborah headset
patrick mobile
patrick tv
;
run;

2. Le résultat sans instruction BY

data mix_demo_sell;
merge demography
sell;
by cl_name;
run;

Vous vous retrouvez avec un merge MANY-to-MANY qui ne résous par votre problème. Pensez toujours à vérifer votre log après un MERGE. Ce type de note est souvent signe d’une erreur de raisonnement dans votre programme.

proc print data=mix_demo_sell;
run;

On observe ici un RETAIN implicite propre au merge.

3. Ajouter un compteur pour chaque client

Pour contourner le problème, on ajouter un identifiant supplémentaire dans les deux tables.

Dans la table DEMOGRAPHY, le client DEBORAH a deux observations. On aura donc CNT=1 et CNT=2.

data demography;
set demography;
by cl_name;
if first.cl_name then cnt=1;
else cnt+1;
run;

Dans la table SELL, le client DEBORAH a quatre observations. On aura donc CNT=1, CNT=2, CNT=3 et CNT=4.

data sell;
set sell;
by cl_name;
if first.cl_name then cnt=1;
else cnt+1;
run;

Il ne reste plus qu’à combiner les deux tables à partir de la variable client (CL_NAME) et de la variable CNT.

data mix_demo_sell;
merge demography
sell;
by cl_name cnt;
run;

proc print data=mix_demo_sell;
run;

Le résultat désiré se présente ainsi :

Lecture complémentaire

h1

Passer d’un format A4 à un format LETTRE

mars 1, 2010

Vous voulez imprimer les fichiers RTF générés avec ODS RTF dans une autre forme que le format A4. Quelle option utiliser pour utiliser un autre format standard comme le format LETTRE ? Comment personnaliser la zone d’impression et gérer les marges en conséquences ?

1. Par défaut, le papier est au format A4 (21cm/29,7cm)

ods listing close;
ods rtf file=‘C:/sasref/margin_example.rtf’;
proc print data=sashelp.class;
run;
ods rtf close;
ods listing;

2. Changer la taille du papier pour l’impression pour une lettre (21,59cm/27,94cm)

options papersize=letter;

ods listing close;
ods rtf file=‘C:/sasref/margin_example.rtf’;
proc print data=sashelp.class;
run;
ods rtf close;
ods listing;

3. Personnaliser la taille (21cm/27,94cm)

Afin de personnaliser les marges dans l’instruction globale OPTIONS, je choisi ici d’enlever toute valeur au niveau du template (undefine margin). Ensuite ce template TEST_PAPERSIZE est appelé dans l’instruction ODS RTF.

proc template;
Define Style style.test_papersize;
parent=styles.rtf;
style Body from Body /
leftmargin=_undef_
right margin=_undef_
topmargin=_undef_
bottommargin=_undef_;
End;
run;

De la taille du papier, il faut enlever les marges. Ici, nous voulons un papier avec une largeur de 21cm et une hauteur de 27,94cm. Les marges étant de 2 centimètres de chaque côté, on enlève 4 cm à la hauteur et 4 cm à la largeur définie par l’option PAPERSIZE.

Les paramètres de l’option PAPERSIZE :

  1. Le 1er paramètre : la largeur
  2. Le 2ème paramètre : la hauteur

options papersize=(’17cm’,‘23.94cm’) leftmargin=2cm rightmargin=2cm topmargin=2cm bottommargin=2cm;

ods listing close;
ods rtf file=‘C:/sasref/margin_example.rtf’ style=test_papersize;
proc print data=sashelp.class;
run;
ods rtf close;
ods listing;

Note : j’ai obtenu le résultat escompté avec Word 2003 mais pas avec Word 2007. Vous pouvez apporter un commentaire avec votre expérience sur le sujet.

h1

Ajouter des liens hypertextes dans vos fichiers PDF

octobre 4, 2009

Dans cet article, je vous propose d’ajouter des liens hypertextes dans vos fichiers .PDF créés avec la syntaxe de l’ODS PDF. Pour illustrer ce sujet, nous créerons une table des matières (table of contents ou TOC) rustique avec ODS PDF TEXT=’ ‘; où il suffira de cliquer sur la section qui vous intéresse pour l’atteindre.

1. Le principe de base

Pour ajouter des liens hypertextes, il faut deux informations :

  • la location du point d’encrage/de destination (anchor)
  • le lien vers ce point d’encrage

ods escapechar=‘^’;

ods listing close;
ods pdf file=‘C:/sasref/hyperlink_toc.pdf’;

ods pdf text=‘Table of Contents’;
ods pdf text= »;
ods pdf text=‘^S={url=’#hommes’}1. Hommes’;
ods pdf text=‘^S={url=’#femmes’}2. Femmes’;

ods pdf anchor=‘hommes’;
ods pdf text=1. Hommes’;
proc print data=sashelp.class(where=(sex=‘M’));
run;

ods pdf anchor=‘femmes’;
ods pdf text=‘2. Femmes’;
proc print data=sashelp.class(where=(sex=‘F’));
run;

ods pdf close;
ods listing;

Le point d’encrage : Le point d’encrage est donné par l’instruction ods pdf anchor=‘…’;. Entre guillemets est donné un nom de votre choix qui servira à l’identifier.

Le lien hypertexte : Le lien vers ce point d’encrage est donné par le mot URL à préciser sous forme de style donné au texte sur lequel cliquer.

ods pdf text=‘^S={url=’#…’}Je clique ici’;

Définition d’un style : Le style est défini avant le texte par S={…}. Pour indiquer à SAS qu’il faille interpréter ce texte comme un style et non un texte brut, un caractère doit précédé le tout. J’ai choisi le symbole du chapeau défini auparavant avec l’instruction ods escapechar=‘^’;

2. Personnaliser le style

Supprimer l’affichage du bookmark : Dans la version enrichie qui suit, j’ai choisi l’option NOTOC pour éviter l’affichage du bookmark sur la gauche de l’écran propre aux fichier PDF.

Les sauts de pages à la demande: J’ai aussi choisi d’enlever par défaut tous les sauts de pages ods pdf startpage=never; puis d’ajouter une fois un saut de page entre la table des matières et les tableaux avec ods pdf startpage=now;

Les en-têtes en moins : Le titre par défaut, la date et le numéro des pages sont enlevés :

title;
options nodate nonumber;

Les liens hypertextes invisibles : Par défaut, le lien hypertexte est présenté par un cadre bleu autour du texte à cliquer. Pour enlever ce cadre, travaillez le style avec ACTIVELINKCOLOR, VISITEDLINKCOLOR et LINKCOLOR.

ods pdf text=« ^S={activelinkcolor=white
visitedlinkcolor=white
linkcolor=white
url=’…’}… »
;

D’autres styles permettent ici d’affiner la présentation :

  • VJUST : ajustement vertical du texte
  • CELLHEIGHT : hauteur de la case contenant le texte
  • CELLWIDTH : largeur de la case contenant le texte
  • FONT_FACE : la police de style
  • FONT_SIZE : la taille du texte
  • INDENT : l’indentation du texte
  • FONT_WEIGHT : mise en gras du texte

J’ai choisi de sauvegarder ces informations dans des macros variables pour pouvoir centraliser l’information en début de programme.

3. Le résultat

Deux pages sont donc créées. La première contient la table des matières. Vous pouvez cliquer sur le texte 1. Hommes ou 2. Femmes pour rejoindre le tableau qui vous intéresse.

hyperlink_toc

hyperlink_main

Annexe : l’intégralité du code

%let titl=vjust=middle
cellheight=30pt
cellwidth=17cm
font_face=arial
activelinkcolor=white
visitedlinkcolor=white
linkcolor=white;
%let titl1=&titl indent=5cm font_size=16pt font_weight=bold;
%let titl2=&titl indent=6cm font_size=12pt;

title;
options nonumber nodate;
ods escapechar=’^’;

ods listing close;
ods pdf file=‘C:/sasref/hyperlink_toc.pdf’ notoc startpage=never;

ods pdf text=« ^S={&titl1.}Table of Contents »;
ods pdf text= »;
ods pdf text=« ^S={&titl2. url=’#hommes’}1. Hommes »;
ods pdf text=« ^S={&titl2. url=’#femmes’}2. Femmes »;

ods pdf startpage=now;

ods pdf anchor=‘hommes’;
ods pdf text=« ^S={&titl2.}1. Hommes »;
proc print data=sashelp.class(where=(sex=‘M’));
run;

ods pdf anchor=‘femmes’;
ods pdf text=« ^S={&titl2.}2. Femmes »;
proc print data=sashelp.class(where=(sex=‘F’));
run;

ods pdf close;
ods listing;

h1

Alterner les couleurs de fond dans un tableau : une ligne sur deux (ODS et PROC REPORT)

août 30, 2009

Ces semaines passées, je vous ai proposé une syntaxe pour changer le style des cellules d’un tableau généré sous SAS avec PROC REPORT. Aujourd’hui, je vous propose une variante permettant de changer la couleur de fond une ligne sur deux. L’exemple utilise une sortie PDF. Le programme peut s’appliquer aux sorties RTF et TAGSETS.EXCELXP.

1. Le programme

Dans PROC REPORT, l’instruction CALL DEFINE contenu entre les instructions COMPUTE et ENDCOMP permet de modifier le style des lignes dans un tableau.

La notion de RETAIN : Dans l’exemple qui suit une variable nommée CNT est créée avec un RETAIN implicite. Le changement de couleur de fond est fonction de la valeur prise par cette variable. Vous pouvez également utilisée une variable déjà existante dans le data set lu.

La foncton MOD() : Le modulo est le résidu d’une division. La fonction MOD() avec un modulo 2 permet de distinguer les valeurs pairs des valeurs impaires. Ici à chaque fois que la valeur CNT a une valeur pair, le fond est mis en gris.

ods listing close;
ods pdf file=‘C:/sasref/zebre.pdf’;
proc report data=sashelp.class nowd;
columns name age;
define name / display;
define age / display;
compute name;
cnt+1;
if mod(cnt,2) then call define (_row_,‘style’,‘style=[background=lightgrey]’);
endcomp;
run;
ods pdf close;
ods listing;

2. Le résultat

zebre

Lectures complémentaires

h1

Tout sur l’instruction BY

avril 14, 2009

Me rendant compte que l’instruction BY pouvait poser des difficultés lorsqu’on débute avec SAS, j’ai décidé de faire le point sur cette instruction.

1. Une instruction locale

L’instruction BY peut servir dans toutes les étapes data et procédures à l’exception de PROC SQL.

2. Un ordre défini par le nom des variables :

L’instruction BY est suivie du nom des variables servant pour le tri.

Dans un premier temps, les observations sont triées selon les valeurs de la première variable citée, ici SEX. Puis, pour chacune des valeurs prises par SEX (M et F), les données sont triées par NAME.

proc sort data=sashelp.class out=class;
   by sex name;
run;

3. PROC SORT : le premier usage de l’instruction BY : L’instruction BY est logiquement obligatoire dans un PROC SORT. Sinon SAS ne saurait pas dans quel ordre trier les données. Le mot DESCENDING peut-être ajouté pour préciser un ordre décroissant. Ici les données sont d’abord triées par SEX puis par nom en ordre descendant.

proc sort data=sashelp.class out=class;
   by sex descending name;
run;

L’autre manière de trier les données est d’utiliser la procédure PROC SQL.

Idée : Vous aurez souvent un PROC SORT avant d’utiliser l’instruction BY dans une autre procédure ou étape data. Simplifiez-vous la vie en copiant l’insstruction au niveau du PROC SORT et en la collant au niveau de la procédure ou étape data suivante.

4. SAS vous informe si les données ne sont pas triées comme indiqué

L’instruction BY précise à SAS dans quel ordre les données doivent être lues. Si les données ne respectent pas cet ordre, SAS s’arrête et fourni un message d’erreur.

5. L’instruction BY : obligatoire ou optionnelle ?

L’instruction BY est optionelle dans une instruction SET. Utilisée pour empiler les données de deux data sets, elle permettra d’intercaler les observations des deux sources selon leur valeurs au lieu de mettre d’abord toutes les observations du premier data set cité et ensuite toutes les observations du second data set.

L’instruction BY reste pratiquement indispensable avec MERGE puisqu’elle sert à relier les observations de deux data sets par les variables du même nom. Sans elle, les observations du second data set pour les variables du même nom réécrirait sur celle du premier.

L’instruction BY est indispensable avec FIRST et LAST.

6. D’autres usages de l’instruction BY

L’instruction BY peut s’ajouter dans un PROC REPORT. Une option NOBYLINE permettra de changer le titre à chaque nouvelle combinaison de valeurs désignée par l’instruction. Néanmoins la mise à jour du titre par cette approche avec ODS RTF par exemple ne fonctionne pas.

L’instruction BY peut servir dans toutes less procédures (sauf PROC SQL) et notamment dans les procédures statistiques. Voir dans les lectures complémentaire l’usage de l’instruction BY avec PROC FREQ.

Lectures Complémentaires

SAS Online Doc

  • BY-Group Processing in SAS Programs
h1

Numéroter ses pages avec ODS RTF

janvier 29, 2009

La syntaxe de ODS RTF a pour but de créer des fichiers ayant une extension .rtf lisible par Word notamment. Comment faire apparaître les numéros de pages en haut ou en bas de la page ? Comment faire pour ajouter des titres à vos tableaux par exemple quand les instructions TITLE et FOOTNOTE servent à la numérotation ?

1. Créer un document RTF

Stopper temporairement l’envoi vers la fenêtre OUTPUT : Dans un premier temps, la destination LISTING est désactivée. Elle est réactivée à la fin. En effet, par défaut le résultat d’un PROC PRINT est envoyé dans la fenêtre OUTPUT de SAS, fenêtre communément appelée LISTING en ODS.

Ouvrir et refermer le fichier RTF : la première instruction ODS RTF sert à définir le nom du fichier RTF à créer. Ici le fichier s’appelle NUMEROTATION.RTF et sera sauvegardé dans le répertoire SASREF du disque C. Toutes les impressions qui suivent (les deux PROC PRINT) seront inclues dans le document RTF. La dernière instruction ODS RTF indique la fermeture du fichier RTF. Plus aucune information ne sera ajoutée au fichier jusqu’à nouvel ordre.

Ajouter un en-tête : Une instruction TITLE située juste avant la première instruction ODS RTF ajoute une en-tête composée de deux parties :

  • Le centrage, l’alignement (justification) par défaut : Mon EN-TETE est centrée (center en américain)
  • Aligner à droite (right) : Page X/XX est affichée à droite de la page grâce à l’option qui la précède J. `

Par la suite X/XX seront remplacés par des numéros de page.

En effet par défaut les titres (title) et pieds de page (footnote) ne sont pas affichés dans le corps du document aux extrémités.

ods listing close;
title 'Mon EN-TETE' j=r 'Page x/xx';
ods rtf file='C:/sasref/numerotation.rtf';
proc print data=sashelp.class;
run;
proc print data=sashelp.class;
run;
ods rtf close;
ods listing;

2. Ajouter des numéros de page

A présent, deux petits ajouts sont fait.

Définir un symbole avec ODS ESCAPECHAR : Le symbole ^ servira de caractère pour introduire des mots-clés, comme l’indique l’instruction ODS ESCAPECHAR. Vous pouvez choisir le symbole de votre choix. La seule règle à respecter est de prendre un symbole qui n’a pas besoin d’être affiché dans le titre.

Afficher la page actuelle et le nombre total de page avec THISPAGE et LASTPAGE : dans l’instruction TITLE, les mots-clés THISPAGE et LASTPAGE doivent être englobés dans des accolades précédé de notre symbole ^ précédemment défini. SAS se chargera alors de les mettre à jour pour chaque page de votre document RTF.

Entre les deux numéros, la barre inclinée (slash) délimite le numéro de la page actuelle de celui de la dernière page. Vous être bien sûr libre d’ajouter le texte de votre choix entre les deux. De même, vous n´êtes pas obligé de faire précédé la numérotation du mot PAGE.

ods listing close;
ods escapechar='^';
title 'Mon EN-TETE' j=r 'Page ^{thispage}/^{lastpage}';
ods rtf file='C:/sasref/numerotation.rtf';
proc print data=sashelp.class;
run;
proc print data=sashelp.class;
run;
ods rtf close;
ods listing;

3. Ajouter des titres à mes différents tableaux

ODS RTF TEXT= : Maintenant que les options TITLE et FOOTNOTES servent pour les en-tête et pied de page, il faut trouver une alternative pour ajouter des titres à vos tableaux et graphiques. L’ODS RTF TEXT= se charge du travail.

La base, un exemple avec le titre du premier tableau : dans le premier exemple, on voit que l’instruction ODS RTF TEXT= contient entre guillemets ^S= suivi de deux accolades. De nouveau le symbole ^ est celui défini dans ODS ESCAPECHAR.

  • La première accolade contiendra des informations de mise en forme du texte.
  • La seconde accolade contiendra le titre.

Quelques options pour améliorer la mise en forme, un exemple avec le second titre : dans le second cas, on précise que

  • Le texte est à centrer horizontalement (JUST=C) et verticalement (VJUST=C).
  • Le texte sera afficher dans un emplacement de 3 cm de haut (OUTPUTHEIGHT=3cm) et cet emplacement prendra la totalité de la largeur de la page (OUTPUTWIDTH=100%).
  • Enfin le texte aura une taille de 18pt (FONT_SIZE=18pt).
ods listing close;
ods escapechar='^';
title 'Mon EN-TETE' j=r 'Page ^{thispage}/^{lastpage}';
ods rtf file='C:/sasref/numerotation.rtf';
proc print data=sashelp.class;
run;
ods rtf text='^S={}{Tableau 1}';
proc print data=sashelp.class;
run;
ods rtf text='^S={just=c vjust=c outputheight=3cm outputwidth=100% font_size=18pt}{Tableau 2}';
ods rtf close;
ods listing;

Poursuivre votre lecture : Trois articles sur l’ODS RTF

h1

Ajouter des indentations dans un tableau

octobre 20, 2008

Avec PROC REPORT et PROC TABULATE, SAS crée des tableaux à partir d’un jeu de donnée (SAS data set). Dans certains cas, la lisibilité de ces tableaux est améliorée en ajoutant des indentations au texte (to indent). Nous verrons donc ici deux approches possibles : l’option INDENT de PROC TABULATE et le caractère hexadécimal pour les blancs dans PROC REPORT.

1. Un exemple pour illustrer la syntaxe sur les indentations

Dans les essais cliniques, trois types de tableaux/listings sont produits :

  • Démographie (demography) : descriptif des patients en terme d’âge, de sexe, de pays, etc.
  • Efficacité (efficacy) : l’efficacité du médicament par rapport à un autre ou par rapport à un effet placebo (le patient prend en médicament en pensant qu’il est actif alors qu’il ne l’est pas).
  • Sécurité (safety) : ces tableaux permettent l’analyse des effets secondaires d’un médicament.

Je vais prendre la cas d’un tableau démographique version réduite (trois colonnes) pour présenter la syntaxe sur les indentations.

  • La première colonne contient les caractéristiques démographiques (sexe et pays),
  • la seconde colonne compte le nombre de patients (N) pour chaque caractéristique
  • la troisième colonne donnera la répartition des patients en pourcentage (%).
---------------------------------
|                   |  N  |  %  |
|-------------------------------|
|Gender             |           |
|   Male            |   12| 48 %|
|   Female          |   13| 52 %|
|Country            |           |
|   France          |    6| 24 %|
|   Belgium         |   10| 40 %|
|   Luxemburg       |    9| 36 %|
---------------------------------

Des variables numériques pour ordonner les valeurs : Pour faciliter le tri des données, j’ai choisi d’avoir des variables numériques dans mon data set SAS sur lesquelles j’applique des formats.

  • Ainsi la premier variable (GRP) réfère à l’intitulé des caractéristiques démographiques : Gender (1) Country (2).
  • La seconde variable (SUBGRP) est l’ordre pour chaque caractéristique. J’aurais pu choisir des valeurs de 1 à 5 mais j’ai préféré que chaque chiffre des décimal corresponde à la variable GRP.
data patient_info;
   input grp subgrp cnt_n pct_n;
   datalines;
1 11 12 0.48
1 12 13 0.52
2 21  6 0.24
2 22 10 0.40
2 23  9 0.36
;
run;

Je choisi de créer des formats du même nom (GRP et SUBGRP) :

proc format;
   value grp     1='Gender'
                 2='Country';
   value subgrp 11='Male'
                12='Female'
                21='France'
                22='Belgium'
                23='Luxemburg';
run;

En outre, je crée un format avec PICTURE pour l’affichage des pourcentages. La raison est la suivante : par défaut, deux chiffres après la virgules apparaissent avec PROC TABULATE. De plus, je souhaite voir le symbole % s’afficher pour chaque pourcentage.

Un format BEST5. est ajouté pour des fréquences composées jusqu’à 5 chiffres sans décimale. De plus, il remplace les points par des blancs. Cela servira pour PROC REPORT.

proc format;
   picture pct (round) .     = ''
                       other = '099 %' (multiplier=100);
   value cnt           .     = ' '
                       other = [best5.];
run;

Dans les deux exemples qui suivent une indentation est formée de trois blancs.

2. L’option INDENT de PROC TABULATE

Dans l’exemple suivant, les deux variables GRP et SUBGRP sont traitées comme des variables textuelles.

L’instruction TABLE contient l’option INDENT= et précise ainsi le nombre de blancs pour décaler les valeurs de la variable SUBGRP vers la droite. Le résultat a été donné en début d’article.

proc tabulate data=patient_info noseps;
   class grp subgrp;
   table grp=''*subgrp='', cnt_n='N'*sum=' '*f=5.
                           pct_n='%'*sum=' '*f=pct.
         / rts=20 indent=3;
   format grp grp. subgrp subgrp.;
run;

Les options NO=SEPS et RTS= sont là pour personnaliser la mise en forme. Pour plus de précisions sur ces options, vous pouvez consulter la documentation en ligne :

  • NOSEPS sur la page « PROC TABULATE Statement »
  • RTS= sur la page « TABLE Statement »

3. Créer des variables alphanumériques (caractères) avec PROC REPORT

Ajouter une ligne pour chacune des caractéristiques : Toutes les informations sont créées manuellement. Ainsi, il y a en plus une ligne pour chaque groupe dans le data set SAS. Au lieu d’avoir 5 lignes, on en aura 7. Pour chaque nouveau GRP, la variable SUBGRP prendre la valeur du GRP + un zero afin d’apparaître en premier dans le rapport après un tri.

proc sort data = patient_info 
          out  = patient_report;
   by grp subgrp;
run;
data patient_report;
   set patient_report;
   by grp subgrp;
   output;
   if first.grp then
      do;
         subgrp=grp*10;
         cnt_n=.;
         pct_n=.;
      end;
run;

Trier par SUBGRP pour afficher les données dans l’ordre voulu.

proc sort data=patient_report;
   by grp subgrp;
run;

Une fois triées les données sont toujours numériques.

grp subgrp cnt_n pct_n

  1    10     .     .
  1    11    12  0.48
  1    12    13  0.52
  2    20     .     .
  2    21     6  0.24
  2    22    10  0.40
  2    23     9  0.36

Créer des variables caractères : la variable DSPLAY nouvellement créée peut contenir jusqu’à 15 caractères. Elle est composée des variables GRP et SUBGRP converties avec la fonction PUT.

Des hexadécimales pour créer des blancs : Les espaces sont créés à partir de valeurs hexadécimales. On répète ici trois fois A0 entre guillemets pour créer trois espaces. La lettre x qui suit précise à SAS qu’il s’agit d’hexadécimales. Ces trois blancs sont concaténés au résultat de la fonction PUT grâce aux deux barres.

data patient_report;
   length dsplay $15;
   set patient_report;
   if subgrp=0 then dsplay=put(grp,grp.);
   else dsplay='A0A0A0'x || put (subgrp,subgrp.);
   cnt_c=put(cnt_n,cnt.);
   pct_c=put(pct_n,pct.);
run;

Trier les données : La variable SUBGRP sert uniquement à définir l’ordre d’affichage des données mais n’apparaît pas dans le tableau final (option NOPRINT dans l’instruction DEFINE).

Enlever le titre de la colonne : La variable DSPLAY contient les caractéristiques démographiques. Aucun nom n’apparaîtra dans le titre de la colonne. Si les guillemets vides ne sont pas précisés, le nom de la variable est affiché.

Aligner à droite : Les variables caractères CNT_C et PCT_C sont affichées en tant que texte (DISPLAY) et leurs observations sont alignées à droite plutôt que d’être centrées (option RIGHT).

proc report data=patient_report;
   columns subgrp dsplay cnt_c pct_c;
   define subgrp / noprint order order=data;
   define dsplay / ' ' display;
   define cnt_c  / 'N' display right;
   define pct_c  / '%' display right;
run;

Dans ce cas, la sortie se présente sans ligne autour du cadre :

                     N      %
Gender
   Male             12   48 %
   Female           13   52 %
Country
   France            6   24 %
   Belgium          10   40 %
   Luxemburg         9   36 %

Sur le blog, vous trouverez d’autres articles sur les notions abordées ici :

h1

Améliorer l’habillage de vos tableaux (débuter avec PROC TEMPLATE via PROC REPORT)

juin 2, 2008

La syntaxe ODS (Output Delivery System) de SAS fait appel à des templates pour définir la mise en forme des tableaux, graphiques à publier. Dans le cas présent, il s’agira de définir un template qui s’appliquera à tous les tableaux générés par un PROC REPORT. Les styles caractérisant les templates sont définis avec la procédure PROC TEMPLATE. Tout d’abord, il s’agit de savoir comment appliquer les styles sans template pour un seul PROC REPORT et ainsi se familiariser avec la syntaxe.

1. Le tableau par défaut

Le programme suivant créé un document RTF (CLASS_V1.RTF) contenant un tableau avec 5 colonnes. Les données proviennent du data set CLASS de la bibliothèque SAS.

ods rtf file = ‘C:/sasreference/class_v1.rtf’;
proc report data=sashelp.class nowd;
   columns sex name age height weight;
   define sex    / display ‘Sexe’;
   define name   / display ‘Nom’;
   define age    / display ‘Age’;
   define height / display ‘Taille’;
   define weight / display ‘Poids’;
run;
ods rtf close;

Le tableau est quadrillé. Les lettres sont alignées à gauche et les chiffres à droite. Le nom des colonnes ont un fond grisé et sont mises en gras. Le tout a une police Times New Roman de taille 10pt.

2. Des styles pour trois destinations différentes

Dans PROC REPORT, on peut ajouter des options au niveau de l’instruction PROC REPORT pour appliquer le résultat à l’intégralité de la table ou dans une instruction DEFINE en particulier pour agir sur une colonne. Il est possible de grouper les deux méthodes. Par exemple, on peut choisir d’avoir des colonnes de trois centimètres partout sauf dans une colonne.

  • STYLE(COLUMN) : pour changer les informations au niveau des colonnes, c’est-à-dire les données sans le titre, on ajoutera STYLE(COLUMN)=[…] dans l’instruction DEFINE.
  • STYLE(HEADER) : pour modifier les caractéristiques des noms de colonnes, les headers, il faudra utiliser STYLE(HEADERr)=[…]
  • STYLE(REPORT) : pour définir les bordures, leur position, couleur et épaisseur, et les espaces entre les cellules, STYLE(REPORT)=[…] est utilisé dans l’instruction PROC REPORT.

3. De multiples options

Les options sont listées dans les crochets, Un espace sert de séparateur entre les options. Voici un aperçu de ces options:

3.1 Agir sur le texte

  • FONT_FACE= ou comment définir une police différente de Times : pour changer la police en Arial, on fait appel à FONT_FACE=’Arial’.
  • FONT_SIZE= ou comment opter pour une taille de caractères différente de 10pt : pour changer la taille du texte en 12, cela donne FONT_SIZE=12pt.
  • FONT_WEIGHT ou comment jongler entre gras et normal : pour mettre en gras, on utilisera FONT_WEIGHT=BOLD. Si au contraire est déjà en gras, et qu’on souhaite le remettre en normal, il faut choisir FONT_WEIGHT=MEDIUM.
  • FOREGROUND= ou comment changer la couleur du texte : l’option FOREGROUND= sert à définir la couleur du texte. Ainsi FOREGROUND=DARKBLUE mettra le texte en bleu foncé.

3.2 Agir sur la position du texte

  • JUST= ou comment changer l’alignement en largeur du texte dans une cellule : par défaut les lettres sont alignés à gauche et les nombres sont alignés à droite. Pour définir le même alignement partout et ensuite changer ponctuellement si besoin, il y a JUST=. Ainsi, JUST=C (center) centre, JUST=R (right) aligne à droite et JUST=L (left) aligne à gauche.
  • VJUST= ou comment changer l’alignement vertical du texte dans une cellule : si le texte d’une case s’étend sur plusieurs lignes, celui des autres cellules est aligné vers le haut. Pour changer l’alignement, on utilise VJUST=BOTTOM.

3.3 Changer la couleur de fond

  • STYLE(COLUMN)=[BACKGROUND=…] ou comment changer le fond des cellules contenant les observations.
  • STYLE(HEADER)=[BACKGROUND=…] ou comment changer la couleur de fond des titres des colonnes.
  • STYLE(REPORT)=[BACKGROUND=… ] ou comment changer l’arrière plan : défini dans STYLE(REPORT), la couleur s’applique à l’arrière du tableau. Si l’espace qui sépare les cellules n’est pas de zéro (CELLSPACING), cette couleur de fond apparaît. Par défaut la couleur noir apparaît entre les cellules. On peut soit changer la couleur pour blanc (BACKGROUND=WHITE) ou réduire l’espace entre les cellules à zéro (CELLSPACING=0).
  • CELLWIDTH= ou comment définir la largeur des colonnes : la largeur de toutes les cellules d’une colonne est défini par CELLWIDTH. Cela donne CELLWIDTH=3cm.

3.4 Agir sur les bordures

  • BORDERCOLOR= ou comment changer la couleur des bordures
  • BORDERWIDTH= ou comment changer  la largeur des bordures du cadre (frame).
  • FRAME= ou comment décider quels côtés du cadre doivent apparaître : on distingue huit valeurs pour FRAME :
    • BOX garde tout le cadre extérieur
    • VOID enlève les bords du cadre
    • HSIDES (horizontal side) garde les deux côtés horizontaux
    • VSIDES (vertical side) garde les deux côtés verticaux
    • ABOVE garde la ligne du dessus,
    • BELOW garde la ligne du dessous
    • LHS (left hand side) garde le côté gauche
    • RHS (right hand side) garde le côté droite
  • RULES= ou comment décider quelles lignes à l’intérieur du tableau doivent être visible : on a cinq valeurs à disposition pour RULES :
    • NONE (none ou aucun) enlève toutes les lignes intérieures
    • ROWS (row ou ligne) ne garde que les lignes horizontales
    • COLS (column ou colonne) ne garde que les lignes verticales
    • GROUP ne garde que la ligne séparant les titres de colonnes, des observations.

Voici donc un schéma récapitulalif des combinaisons de FRAME et RULES lorsque, dans STYLE(REPORT), BACKGROUND=WHITE ou CELLSPACING=0. Pour facilité la lecture, l’effet de FRAME est en noir et celui de RULES est en rouge.

*NB: Cette image contient une erreur : remplacez grps par group.

4. L’effet final avec les options de PROC REPORT

Voici un résumé de l’Exemple ci-dessous :

  • Seules les bordures du haut et du bas sont gardées (FRAME=HSIDES), et épaissie (BORDERWIDTH=.2cm) après avoir mis en blanc l’arrière plan du tableau pour qu’il n’apparaisse pas entre les cellules (BACKGROUND=WHITE). On choisi de séparer les titres des valeurs par une ligne  (RULES=GROUPS) et de mettre tous les trais en gris (BORDERCOLOR=GRAY).
  • Au niveau des titres, la couleur de fond est enlevée (BACKGROUND=WHITE).  Une police Arial de 12pt non gras est choisie.
  • Enfin au niveau des données, la police est également Arial de taille 12pt. Les colonnes sont de 3 cm de largeur et le texte est aligné à droite.

ods rtf file  = ‘C:/sasreference/final_v1.rtf’
        style = sasref;

proc report data=sashelp.class nowd
   style(report)=[rules       = groups
                  frame       = hsides
                  background  = white
                /*cellspacing = 0*/
                  bordercolor = gray
                  borderwidth = .2cm]
   style(header)=[background  = white
                  font_size   = 12pt
                  font_face   = ‘Arial’
                  font_weight = medium]
   style(column)=[font_size   = 12pt
                  font_face   = ‘Arial
                  cellwidth   = 3 cm
                  just        = r];
   columns name sex age height weight;
   define name   / display ‘Nom’;
   define sex    / display ‘Sexe’;
   define age    / display ‘Age’;
   define height / display ‘Taille’;
   define weight / display ‘Poids’;
run;

ods rtf close;

5. Obtenir le même résultat avec un proc template

 A présent que vous avez vu les différentes régions sur lesquelles vous pouvez agir et une grande partie des options que vous pouvez changer, voici la syntaxe de PROC TEMPLATE.

Ici, le nouveau template s’appelle SASREF (DEFINE STYLE). Il est basé sur le style par défaut (PARENT=).

proc template;
   define style styles.sasref;
   parent = styles.default;
   /*.à compléter..*/
   end;
run;

Vous remarquerez que les informations listées dans REPLACE TABLE sont les mêmes que dans notre précédent ODS(REPORT). Celles listées dans REPLACE HEADER correspondent à celle de ODS(HEADER) et enfin celle de REPLACE DATE sont identiques à ODS(COLUMN).

proc template;
   define style styles.sasref;
   parent = styles.default;
   replace table /  rules       = groups
                    frame       = hsides
                    background  = white
                  /*cellspacing = 0*/
                    bordercolor = gray
                    borderwidth = .2cm;
   replace header / foreground  = black
                    background  = white
                    font_size   = 12pt
                    font_face   = ‘Arial’
                    font_weight = medium;
   replace data   / background  = white
                    font_size   = 12pt
                    font_face   = ‘Arial’
                    cellwidth   = 3 cm
                    just        = r;
   end;
run;

Vous noterez en plus l’utilisation de FOREGOUND dans REPLACE HEADER et BACKGROUND dans REPLACE DATA. En effet, si vous appelez le template sans les instructions REPLACE, SAS ajoute un font gris aux données et met les titres en bleu.

A présent, il s’agit de faire référence à ce template dans l’instruction ODS RTF.

ods rtf file  = ‘C:/sasreference/class_v1.rtf’
        style = sasref;

Avant de terminez, il vous faudra supprimer le template.

proc template;
   delete styles.sasref;
run;

h1

Mes 1ers pas avec ODS TAGSETS.EXCELXP (3/3)

mai 26, 2008

L’ODS TAGSETS.EXCELXP, alternative au PROC EXPORT, permet de créer des fichiers Excel à partir de données SAS. Afin de personnaliser ce fichier, nous avons vu dans un premier article la syntaxe de PROC REPORT. Puis dans un second article, le PROC TEMPLATE a permis de modifier des couleurs, polices et marges du document à imprimer. Pour ce dernier article sur « Mes premiers pas avec l’ODS TAGSETS.EXCELXP », il s’agit de voir les options de l’instruction ODS.

ods tagsets.excelxp file = ‘C:/excel/mon_nouveau_fichier.xls’
style = vero_xls
options (…);

1. Personaliser la feuille de calcul

1.1 Donner un nom à une feuille : pour personnaliser le nom de la feuille de calcul, il faut ajouter l’option SHEET_NAME=’Mon nom de feuille’.

ods tagsets.excelxp options (sheet_name=‘Mon nom de feuille’);

1.2 Figer la première ligne contenant les titres de colonnes : sous Excel, on peut figer les x premières lignes de sorte que quelque soit la ligne consultée, la ligne figée reste visible. Sur le même principe, la première ligne contenant le nom des colonnes peut être figé grâce à l’option FROZEN_HEADER=.

ods tagsets.excelxp options (frozen_headers = ‘Yes’);

1.3 Ajouter un filtre aux colonnes : sous Excel, un filtre est une petite flèche qui apparaît dans la première ligne d’une colonne donnée. En cliquant dessus, on voit apparaître toutes les valeurs prises par la colonne. L’utilisateur peut ainsi choisir de ne faire apparaître que les lignes ayant une valeur ou un groupe de valeurs données. Pour ajouter ce type de filtre à toutes les colonnes du fichier Excel avec ODS, il y a l’option AUTOFILTER=.

ods tagsets.excelxp options (autofilter = ‘All’);

1.4 Créer plusieurs feuilles dans un seul fichier Excel

Pour créer plusieurs feuilles dans un fichier Excel unique, il faut dans un premier temps, définir les données communes aux multiples feuilles : nom du fichier Excel et Style.

ods tagsets.excelxp file = ‘C:/excel/mon_nouveau_fichier.xls’
style = vero_xls;

Dans un deuxième temps, on actualise cette information pour chaque feuille en précisant les options SHEET_NAME .

ods tagsets.excelxp options (sheet_name = ‘Feuille 1’);
proc report…;
run;
ods tagsets.excelxp options (sheet_name = ‘Feuille 2’);
proc report…;
run;
ods tagsets.excelxp close;

2. Agir sur le document à imprimer

2.1 Faire les titres de colonnes sur toutes les pages : l’option ROW_REPEAT= va permettre de répéter le titre des colonnes sur chacune des pages à imprimer.

ods tagsets.excelxp options (row_repeat = ‘header’);

2.2 Modifier l’orientation de la page : par défaut l’orientation de la page à imprimer est orientée portrait (portrait). Pour changer en Paysage (landscape), il faut le préciser avec l’option ORIENTATION=.

ods tagsets.excelxp options (orientation = ‘landscape’);

Cette liste des options est loin d’être exhaustive. Vous pouvez vous reporter à la page du support SAS pour avoir la liste complète de options.

Références : la documentation sur les ODS TAGSETS.EXCELXP reste encore très limitée. Voici néanmoins quelques liens :

h1

Mes 1ers pas avec ODS TAGSETS.EXCELXP (2/3)

mai 19, 2008

Sous SAS, l’ODS TAGSETS.EXCELXP est une alternative au PROC EXPORT. Dans une première partie, vous avez vu comment modifier la largeur d’une colonne, gérer l’alignement des valeurs textes et former une cellule unique servant de titre à plusieurs colonnes, le tout avec la syntaxe de proc report. Maintenant vous allez découvrir comment modifier les couleurs, polices de caractères, etc. en créant un nouveau template.

1. La structure de base de PROC TEMPLATE

Une autre particularité que l’on rencontrera dans le fichier Excel, c’est la présence de la couleur grise pour le fond ces cellules ayant des données, une couleur bleuté pour le texte des cellules contenant le nom des variables, etc.

Pour altérer ces couleurs, disons remettre du blanc en fond et du texte en noir, on va créer un nouveau template à partir d’un existant. Il suffira alors de modifier les quelques paramètres qui nous intéresse.

La structure de base du PROC TEMPLATE est la suivante :

proc template;
   define style styles.vero_xls;
   parent=style.default;
   *style x from x /…;
run;

J’ai donné le nom vero_xls à ce nouveau STYLE. Vous pouvez choisir le nom qui vous plaira. L’important est de se référer au même nom par la suite. 

2. Les instructions STYLE de PROC TEMPLATE

Il existe plusieurs instructions STYLE, selon qu’il s’agisse :

  • de la partie non couverte par les données : style Table from Table
  • de la partie couverte par les noms de colonnes : style Header from Header
  • de la partie couverte par le nom des lignes (dans un proc print, les valeurs de la variable obs) : style RowHeader from RowHeader
  • de la partie couverte par les données : style Data from Data
  • de l’apparence de la page A4 d’impression : style Body from Body

Voicic trois autres styles :

  •    style SystemTitle from SystemTitle /…;
  •    style SystemFooter from SystemFooter /…;
  •    style SysTitleAndFooterContainer from SysTitleAndFooterContainer /…;

3. Les options des instructions STYLE

Les options sont situées après la barre inclinée (slash /). Les valeurs prises par ces options sont notées entre guillemets.

 Les options les plus courantes sont :

  • FOREGROUND = (couleur du texte). Ici, on choisira le mot ‘black’ entre guillemets.
  • BACKGROUND = (couleur des cellules). Ici, on choisira ‘white’.
  • FONT_SIZE = (la taille du texte). Ici, on choisira 1.5 par exemple.
  • FONT_FACE = (la ou les polices de caractères). Ici, on choisi ‘Courier’. Mais on peut aussi opter pour ‘Courier,Arial’. Ainsi si la police Courier n’est pas disponible, Arial sera le second choix.

Deux autres options du langage courant

  • FONT_WEIGHT= (mette en gras). La valeur BOLD sert à mettre en gras
  • FONT_STYLE= (mettre en italique ou non). La valeur ITALIC met en italique tandis que ROMAN fait l’inverse.

Agir dur les bordures des cellules :

  • BORDER_COLOR= (couleur de la bordure)
  • BORDER_WIDTH= (largeur de la bordure)

Agir sur les marges du document A4.

  • LEFTMARGIN = (marge de gauche)
  • RIGHTMARGIN = (marge de droite)
  • TOPMARGIN = (marge du haut)
  • BOTTOMMARGIN = (marge du bas)

Note : Une liste des différents styles est disponible sur ce forum : http://www.tek-tips.com/viewthread.cfm?qid=1178234&page=1.

4. Faire référence au nouveau template

Pour que ce template soit lu à la place de celui par défaut, on ajoutera STYLE=nom_du_nouveau_template dans l’instruction ODS TAGSETS.EXCELXP de début.

ods tagsets.excelxp file  = ‘C:/excel/mon_nouveau_fichier.xls’
                    style = vero_xls;
proc report …;
run;
ods tagsets.excelxp close;

Après avoir vu les actions menées au niveau du PROC REPORT et du PROC TEMPLATE pour personnaliser son fichier Excel, vous verrez dans le troisième et dernier article sur « Mes premiers pas avec ODS TAGSETS.EXCELXP », lundi prochain, les options disponibles dans l’instruction ODS.

h1

Mes 1ers pas avec ODS TAGSETS.EXCELXP (1/3)

mai 12, 2008

SAS propose une alternative au PROC EXPORT pour créer un fichier Excel à partir de données SAS. Il s’agit de l’ODS TAGSETS.EXCELXP. Celle-ci fait preuve de flexibilité tant pour ajouter les labels des variables, définir la largeur des colonnes qu’ajouter les filtres aux colonnes ou encore créer plusieurs feuilles par fichier Excel. Voici donc le premier des articles consacrées à mes découvertes de ces derniers jours sur le sujet : « syntaxe de base et options changeables au niveau de la procédure Proc Report ».

1. La syntaxe de base : tout d’abord, il s’agit d’encadrer la proc report, proc print, ou autre entre deux instructions ODS TAGSETS.EXCELXP. La première instruction servira en premier lieu à définir le nom et la destination du nouveau fichier Excel. La seconde instruction fermera le processus de création du fichier Excel.

ods tagsets.excelxp file=‘C:/excel/mon_nouveau_fichier.xls’;
   proc report data=resultats;
      columns pop grp subgrp check;
      define pop    / display ‘Pop’;
      define grp    / display ‘Pays’;
      define subgrp / display ‘Ville’;
      define check  / display ‘Check’;
      run;
ods tagsets.excelxp close;

Un premier essai au résultat et on se rendra compte de plusieurs « imperfections » que l’on souhaitera changer à commencer par la largeur des colonnes.

2. Changer la largeur des colonnes : avec un PROC REPORT, il est possible d’affiner l’apparence (le STYLE) des colonnes et notamment celui de la largeur des colonnes. Si on veut que toutes les colonnes soient de la même largeur, l’option STYLE(COLUMN) sera ajoutée dans l’instruction PROC REPORT, sinon elle sera ajoutée dans chaque instruction DEFINE. Si un grand nombre de colonnes doit avoir la même largeur, il est possible de combiner les deux méthodes. Tout d’abord, la largeur la plus fréquente dans l’instruction PROC REPORT est définie. Ensuite, les colonnes devant avoir une valeur différente sont actualisées dans leur instruction DEFINE.

proc report data=resultats style(column)=[cellwidth=3cm];
   columns pop grp subgrp check;
   define pop    / display ‘Pop’
                   style(column)=[cellwidth=5cm];
   define grp    / display ‘Pays’;
   define subgrp / display ‘Ville’;
   define check  / display ‘Check’;
run;

Note : Les options WIDTH= et FLOW des instructions DEFINE perdent ici leur utilisé puisque le texte n’est pas coupé.

3. Centrer ou aligner à gauche, à droite : de la même manière que définir la largeur des colonnes, changer l’alignement du texte (pas des nombres) est possible avec JUST=center (left ou right). Par défaut, les textes sont alignés à gauche et les nombres sont alignés à droite. On peut choisir de changer l’alignement :

  • soit au niveau des valeurs (style(column)),
  • soit au niveau du nom des variable (style(header)).

Gérer certains formatage avec TAGATTR= est un autre attribut possible de STYLE(COLUMN). Voici deux exemples d’application :

  • Sur le même principe que le format Zw., les zéros situées en entête d’une variable numérique sont conservés. On ajoutera autant de zéro que nécessaire.
  • Les variables numériques sont affichées comme du texte, si l’arobas @ est utilisé.
  • Mais il ne semble pas possible de combiner les deux notations. Mais corrigez-moi si je me trompe.

proc report …;
   define check    / display ‘Check’
                     style(column)=[tagattr=’format:000′];
   define check    / display ‘Check’
                     style(column)=[tagattr=’format:@’];
run;

4. Un nom de colonne commun à plusieurs colonnes : sous Excel, il est très simple de sélectionner deux cellules et de demander à ce qu’elles n’en forment plus qu’une seule. Pour faire la même chose en SAS, on fait appel à la syntaxe de PROC REPORT.

   columns pop (‘Zone géographique’) grp subgrp check;

Si on choisi de combiner des cellules, l’ajout d’un filtre sur les colonnes concernées peut paraître inapproprié. En effet, le filtre n’utilisera que les valeurs de la première colonne.

Dans la seconde partie (lundi prochain) sur ODS TAGSETS.EXCELXP, vous verrez comment modifier les couleurs, la police de caractère, etc. en créant un template.

Annexe : data set servant d’exemple

data resultats;
   input pop grp $2. subgrp $5. check $4.;
   datalines;
1 AL Alger 001A
1 AL Oran  003
1 MO Rabat 002
2 CH Bern  001A
2 NO Oslo  004
;
run;

h1

3 propositions pour exporter un graphique

mai 8, 2008

Créer un graphique est une chose. Pouvoir l’extraire de SAS pour l’exploiter en est une autre. Ici, nous verrons comment l’envoyer directement dans un document Word, comment sauvegarder son graphique sous forme de fichier image ou sous forme de catalogue graphique SAS. Pour cela nous utiliserons un diagramme en barre généré avec PROC GCHART.

A chaque fois, les options graphiques sont au préalable réinitialisées avec RESET=ALL. Puis un DEVICE GIF est assigné.

goptions reset=all;
goptions device=gif;

1. Ajouter un graphique dans un fichier Word

L’output Delivery System (ODS) est assez récent dans SAS. RTF est le format lu part Word. La procédure générant le code SAS est entouré de deux instructions ODS RTF. La première définie le nom et la destination du fichier RTF. La seconde stoppe l’écriture dans le fichier RTF

goptions reset=all;
goptions device=gif;

ods rtf file=‘C:/sasref/dest_word.rtf’;
   proc gchart data=cnt;
      vbar maingrp /sumvar=cnt ;
   run;

ods rtf close;

2. Envoyer un graphique dans un catalogue graphique SAS

Un catalogue (catalog) est un fichier propre à SAS. On peut y stocker soit des graphiques (graphic catalog), soit des formats (format catalog) mais pas les deux à la fois. Ici, on stocke le fichier dans un catalogue graphique nommé DEST_CAT, qui est sauvegardé dans la bibliothèque SASREF. Ces graphiques peuvent être ensuite rappelés par un PROC GREPLAY pour créer une nouvelle image. Celle-ci sera soit une superposition de graphiques, soit des graphiques mis les uns à côté des autres. Cette image pourra aussi être insérés dans un document RTF via ODS RTF TEXT (fichiers JPG ou PNG seulement, pas de fichier GIF…). Dans tous les cas, ODS LISTING doit être activé.

goptions reset=all;
goptions device=jpeg;
  
libname sasref ‘C:/sasref/dest_pic.jpg’;

proc gchart data=cnt gout=sasref.dest_cat;
   vbar maingrp /sumvar=cnt ;
run;

3. Sauvegarder un graphique sous forme de fichier image

Pour créer une image, il faut au préalable ajouter GSFNAME= à l’instruction GOPTIONS. Le chemin d’accès à l’image et son nom sont définis dans une instruction FILENAME. Le nom de ce FILENAME est rappelé dans GSFNAME.

filename orig ‘C:/sasref/dest_pic.gif’;

goptions reset=all;
goptions device=gif gsfname=orig;

proc gchart data=cnt;
   vbar maingrp /sumvar=cnt ;
run;

filename orig clear;

Annexe : data set source

data cnt;
   input maingrp $ subgrp $ subgrp2 $ cnt;
   datalines;
1 1 A 12
1 2 A 13
1 3 B  6
2 1 A 15
2 2 B 22
2 3 B 10
2 4 B  2
2 5 B 51
3 1 A 13
3 2 A 21
;
run;

h1

5 options courantes de PROC REPORT

avril 4, 2008

Après avoir vu les notions de bases de PROC report, je vous propose 5 points de syntaxe que j’utilise régulièrement pour un résultat un peu plus personnalisé.

  • Les points 1 et 2 sont des options de l’instruction PROC REPORT.
  • Le point 3 concerne l’instruction COLUMN.
  • Les points 4 à 5 servent dans les instructions DEFINE.

En fin d’article, vous avez un exemple de syntaxe pour mieux cerner le tout.

1. Changer le symbole coupant les mots pour l’utiliser comme du texte : par défaut, la barre inclinée (/) est le symbole pour les sauts à la ligne dans le titre des colonnes et les valeurs textes. Du coup, si on veut considérer celui-ci comme du texte à part entière, il faut définir un autre caractère pour couper le texte. Par exemple, on peut utiliser le symbole dièse # dans l’option SPLIT=’…’ de l’instruction PROC REPORT

2. Affichez les valeurs manquantes : lorsque des valeurs sont groupées, SAS ignore par défaut les valeurs manquantes (missing et special missing). Pour changer cela, il faut précisez l’option MISSING dans l’instruction PROC REPORT, avec GROUP, ORDER ou ACROSS. Un exemple de la documentation en ligne illustre ce sujet. How PROC REPORT Handle Missing Values. Les valeurs manquantes d’ANALYSIS et DISPLAY restent affichées.

3. Un titre pour plusieurs colonnes : il est possible d’ajouter un titre commun à plusieurs colonnes. Pour cela, il faut agir sur l’instruction COLUMN. Les variables concernées sont listées entre parenthèses. Le nom commun est donné entre guillemets en premier dans les parenthèses.

4. Définir la largeur des colonnes : pour définir la largeur de la colonne, il existe l’option WIDTH=. Cette largeur peut ne pas être suffisante pour afficher tout le texte. Mais, heureusement, il y a l’option FLOW. Celle-ci fait apparaître le texte sur plusieurs lignes, s’il n’y a pas assez de place sur une seule. Cela évite à celui-ci d’être coupé.

Même si, a priori, le texte est contenu dans la largeur défini, il est donc conseillé d’utiliser l’option FLOW pour éviter des coupures involontaires ou repérer plus facilement des textes plus longs que prévus.

5. Et les formats ? : Les formats s’utilisent indifféremment en option dans les instructions DEFINE avec un signe égal ou dans une instruction FORMAT.

Exemple :

proc report data=mesresultats nowd
split=‘#’
missing;
column pays patient_id
(‘Statistiques’ cnt pct);
define pays / display ‘Pays’
format=$cntry.;
define patient_id / display ‘ID’;
define cnt / display ‘N’;
define pct / display ‘%’;
*format pays $cntry.;
run;

NOTE 1 : Les options HEADLINE, HEADSKIP et les tirets bas pour entourer un titre commun à plusieurs colonnes n’ont pas été mentionnés ici car ils perdent leur intérêt avec un ODS RTF.

NOTE 2 : La modification de l’apparence peut-être amélioré en changer le « style » au niveau local c’est-à-dire dans la procédure REPORT ou au niveau global, en créant ou actualisant le Template de la procédure REPORT. Cela pourrait faire l’objet de plusieurs articles tant le sujet est vaste.

h1

9 points pour personnaliser ses titres

mars 28, 2008

silhouettes

Ajouter un titre à vos tableaux et graphiques est simple avec l’instruction TITLE. Je vous rappelle la différence entre les guillemets simples et doubles. Je vous parle des méthodes pour aligner vos titres, etc. Vous saurez ensuite comment supprimer vos titres. Pour rendre vos titres un peu plus flexibles, je vous donne un tuyau (l’option NOBYLINE). Pour ce qui est d’un titre de tableau avec ODS RTF, je vous parle de l’option BODYTITLE. Et pour un titre de graphique, on parlera de l’option NOGTITLE. Bonne lecture.

1. Créer un titre : l’instruction globale TITLE permet d’ajouter un titre. Pour cela, on fait suivre le mot-clé du titre entre guillemets.

title ‘Mon titre’;

2. Créer plusieurs titres : SAS autorise jusqu’à 10 lignes servant de titre. Pour les distinguer, un numéro a été ajouté au mot-clé TITLE1-TITLE10. Ainsi TITLE est équivalent de TITLE1.

title1 ‘Mon premier titre’;
title2 ‘Mon second titre’;

title10 ‘Mon dixième titre’;

3. Supprimer un titre : Par défaut, SAS inscrit « The SAS System » comme titre de vos sorties. Pour l’enlever, vous pouvez soit réécrire dessus ou l’enlever définitivement avec une instruction TITLE vide. Notez que pas seulement le premier titre sera supprimé mais l’intégralité des titres définis.

title ;

4. Un titre sur une seule page d’éditeur : votre titre est long et vous avez besoin d’utiliser la barre de défilement horizontale de votre éditeur SAS pour le lire en entier. La solution est de couper votre titre.

title ‘Ma première partie’
      ‘Ma deuxième partie’
;

5. Guillemets simples ou doubles : pour alléger le programme, utilisez de préférence des guillemets simples. Dans certains cas, cependant, vous aurez besoin de guillemets doubles :

  • Résoudre une macro variable
  • Avoir un titre avec des apostrophes

title « Etude : &numero_etude. »;
title « Don’t do it »;

Une autre solution pour traiter les apostrophes est de mettre deux apostrophes simples l’une à coter de l’autre.

title ‘Don »t do it’;

6. Changer l’alignement : votre titre sera par défaut centré. Pour aligner à gauche, vous pouvez suspendre temporairement l’option globale de centrage (options nocenter; /*votre programme*/ options center). Vous pouvez aussi utiliser l’option pour justifier (j=). Celle-ci peut prendre trois valeurs :

  • j=l (left) pour aligner à gauche,
  • j=c (center) pour centrer,
  • j=r (right) pour aligner à droite.

7. Un texte à gauche et un texte à droite : vous pouvez aussi avoir sur une seule ligne plusieurs éléments à positionner : un à gauche, un à droite et un au milieu.

L’ancienne méthode : l’ancienne méthode consiste à assembler le texte de gauche, x blancs, le texte du milieu, y blancs et le texte de droite. Le tout faisant la largeur de la page. Pour cela un petit calcul s’impose.

  • On prend le nombre total de caractères sur la ligne (linesize).
  • La longueur des trois morceaux de texte y est soustraite.
  • Le reste est divisé par deux. Si on a un nombre impair, les deux textes blancs auront un espace de différence.

La nouvelle méthode : avec SAS 8.2 il existait une alternative, temporairement indisponible sous SAS 9.1.3 mais qui devrait redevenir disponible sous SAS 9.2 (cette année !).

title j=l ‘Mon texte de gauche (left)’
      j=c ‘Mon texte du milieu (center)’
      j=r‘Mon texte de droite (right)’;

En fait, l’option ‘justifié’ (j=) est toujours disponible sous SAS 9.1.3 mais seul le dernier est pris en considération par SAS. D’ici là, il ne vous reste plus que l’ancienne méthode.

8. Personnaliser son titre avec la valeur d’une BY variable : l’option globale BYLINE permet d’ajouter automatiquement un titre pour précisez la valeur d’une valeur BY variable. Par exemple, vous construisez un proc report…; by pop;… D’un côté vous avez la forme automatique avec BYLINE (Par Protocol). De l’autre, vous pouvez personnaliser votre titre (Population : Par Protocol).  Pour cela, on désactive l’option avec NOBYLINE (options nobyline;). Puis on utilise #byvar() et ou #byval() dans le titre. Soit on souhaite faire apparaître le nom de la BY variable soir la valeur de la BY variable. Dans le second cas, cette valeur est rendue parlante avec un format.

title ‘Population : #byval(pop)’;proc report …;
  by pop;
  …;
  format pop pop.;
run;

9. ODS RTF : lorsqu’on crée des documents RTF lisibles par Word, il faut pouvoir adapter les options par défaut des titres pour répondre à ses besoins.

Un titre de tableau dans le corps du document : par défaut les titres d’un tableau sont inclus dans les entêtes du document RTF. Pour qu’il fasse partie intégrante du corps du document, on ajoute l’option BODYTITLE.

Un titre de graphique dans le corps du document : par défaut les titres des graphiques sont inclus dans l’image graphique générée par SAS. Pour que cela ne soit plus le cas, on ajoute l’option NOGTITLE dans l’instruction ODS RTF.

h1

6 notions pour débuter avec PROC REPORT

mars 26, 2008

Feu 

Pour créer un tableau et le publier, la procédure REPORT est disponible. Je vous propose de voir sa structure de base.

1. Lister vos variables avec l’instruction COLUMN : la procédure REPORT doit contenir au minimum une instruction COLUMN listant les variables à publier dans l’ordre d’apparition souhaité.

Pour les utilisateurs de SAS pour Windows, on ajoutera l’option NOWD dans l’instruction PROC REPORT, pour éviter l’ouverture d’une fenêtre indépendante.

2 Personnalisez les colonnes : par défaut, les colonnes auront pour nom celui de la variable. Pour les personnalisez, on ajoute une instruction DEFINE par colonne.

proc report data=result_pat nowd;
   column pays pays_txt patient_id cnt pct;
   define pays       / display ‘ ‘;
   define pays_txt   / display ‘Pays’;
   define patient_id / display ‘ID’;
   define cnt        / display ‘N’;
   define pct        / display ‘%’;
run;

3. Privilégiez l’affiche en mode DISPLAY : par défaut les variables textes seront en mode DISPLAY tandis que les variables numériques seront en mode ANALYSIS. En d’autres termes, SAS peut potentiellement regrouper et additionner des valeurs numériques. Je pense notamment lorsqu’on utilise l’option GROUP sur d’autres variables. De plus, les valeurs textes seront alignées à gauche et les valeurs numériques seront alignées à droite.

Mon choix est donc de convertir toutes mes variables à afficher en texte avant et de n’utiliser PROC REPORT que comme un outil de publication. Vous pouvez, de plus, explicitement indiquer le mode DISPLAY dans les instructions DEFINE.

4. Trier les données et ne pas afficher certaines colonnes : en plus des affichages par défaut DISPLAY et ANALYSIS, vous avez l’affichage ORDER. Il est vivement conseillé de noter explicitement l’option ORDER= (formated, data, freq ou internal) car la valeur par défaut risque d’évoluer dans les prochaines versions de SAS. On peut également utiliser le mot-clé DESCENDING pour un tri par ordre décroissant.

Il est souvent plus facile de trier les données si elles sont numériques. Par exemple, imaginez que vous vouliez trier vos données par pays avec en premier des pays d’Europe par ordre alphabétique (Allemagne, France, Royaume-Uni) puis des pays d’Asie par ordre alphabétique (Indonésie, Malaisie, Singapour, Thaïlande). Vous pouvez créer un format numérique avec des valeurs allant de 1 à 7 (1 pour Allemagne, 7 pour Thaïlande).

Pour être cohérent avec mon propos précédent, je vous conseille d’avoir deux variables :

  • d’un côté la variable numérique qui sert pour le tri mais que ne sera pas affichées. Pour cela, il y a l’option NOPRINT de l’instruction DEFINE ;
  • et de l’autre, la variable texte créée préalablement à partir de la variable numérique et du format avec une fonction PUT.

5. Grouper les données et créer des breaks : imaginez que vous ayez plusieurs patients du même pays. Vous aurez autant de fois le nom de pays qu’il y a de patients. Pour alléger le tableau, vous pouvez n’afficher le pays que la première fois. Au lieu de DISPLAY, ANALYSIS, ORDER, etc. vous utilisez alors l’option GROUP dans l’instruction DEFINE.

Notez que toutes les colonnes à gauche devront donc être également groupées.

Il est possible d’utiliser ORDER=… avec GROUP comme pour l’option ORDER.

Un des avantages de GROUP est de définir entre les groupes des séparations. Pour cela, il y l’instruction BREAK AFTER appelle la variable groupée en question. Le type de séparation est défini par l’option. SKIP par exemple permet de sauter une ligne entre les groupes. Mais cette instruction ne fonctionne pas avec ODS RTF. Il faut alors utiliser la syntaxe COMPUTE/ENDCOMP.

proc report data=result_pat nowd;
   column pays pays_txt patient_id cnt pct;
   define pays       / group order=data noprint;
   define pays_txt   / group ‘Pays’;
   define patient_id / display ‘ID’;
   define cnt        / display ‘N’;
   define pct        / display ‘%’;
   *break after pays / skip;
   compute before;
      line ‘ ‘;
   endcomp;
   compute after pays_num;
      line ‘ ‘;
   endcomp;
run;

6. Les faiblesses de l’instruction ACROSS : imaginez que vous ayez les fréquences et pourcentages pour deux drogues. Cela vous donne 4 colonnes dans votre tableau finale. Mais, dans votre tableau d’origine, vous avez 3 colonnes : le type de drogue, les fréquences et les pourcentages. L’instruction ACROSS permet de « transposer » l’information. Mais si, en plus, vous voulez rajouter une colonne à droite, vous rencontrerez de réelles difficultés.

Comme précédemment, je choisi d’agencer mes données comme il me convient avant la procédure. Je n’utilise PROC REPORT que pour l’affichage. Cela implique souvent l’usage d’un PROC TRANSPOSE et d’un MERGE (where=() rename=()).

proc sort data=result_drug;
   by pays;
run;

proc transpose data   = result_drug
               out    = result_drug_across
               prefix = drug_;
   by pays;
   var cnt pct;
   id drug;
run;

data result_drug_across (drop=_NAME_);
   merge result_drug_across
          (where=(lowcase(_name_)=‘cnt’)
           rename=(drug_1=cnt_1 drug_2=cnt2))
         result_drug_across
          (where=(lowcase(_name_)=‘pct’)
           rename=(drug_1=pct_1 drug_2=pct2));
   by pays;
run;

Pour une information plus détaillées sur DISPLAY, ANALYSIS, GROUP, ORDER, ACROSS vous trouverez la page « Concept: REPORT procedure ». Notez que je n’ai pas parlé de COMPUTED, dans la même veine que GROUP, DISPLAY, ACROSS, ANALYSIS, mais que celle-ci permet de faire des calculs simples (sommation, etc).

Conclusion

En conclusion, la procédure REPORT est un outil qui, certes très puissant, peut vite devenir très compliqué. De mon expérience, il apparaît plus judicieux de restreindre l’usage de PROC REPORT à la diffusion de résultats préalablement agencés en triant les données avec des variables numériques non affichées et ne montrant que les variables textes.

Pour plus de détails sur la procédure REPORT, vous pouvez consulter le prochain article intitulé « 6 subtilités de PROC REPORT » et le chapitre PROC REPORT de la documentation en ligne.

Annexe:

data result_pat;
   length pays_txt $10;
   input pays pays_txt $ patient_id cnt pct;
   datalines;
1 Maroc      1 10  20
1 Maroc      2 25  50
1 Maroc      3 15  30
2 Luxembourg 1 18  36
2 Luxembourg 2 32  64
3 Canada     1  5 100
;
run;

data result_drug;
   input pays drug cnt pct;
   datalines;
1 1 10 20
2 1 18 36
1 2 40 80
2 2 32 64
3 1 5 100
;
run;