Roland's Graphical Patient Profiler (v4.0)

[last updated: 15 May 2011]

Introduction

The title of this page is "Roland's Graphical Patient Profiler". I'll explain what this means. To put it into context, it is to do with patients and their progress on a clinical trial. Taking the first word "Roland" -- that's the guy who wrote this thing called a "graphical patient profiler". It's me! So that's the first word cleared up. And as for the rest of it, the "graphical" part means "pretty pictures", if you like, so combined with what's left, "patient profiler", it means something I wrote so that you can see pretty pictures of what is happening to a patient during the progress of a clinical trial.

example rgpp output

The full explanation about the patient profiler will be given on seven pages starting with this one, and they should be read in the order given. The following page can be linked to at the bottom of the previous page. The first page (this one) will explain what RGPP is and you will be able to download it and play with it. The second page will tell you how to improve layout of demography ites. The third page will show you how to transform your data into a format that the patient profiler can use. The fourth page will give a practical demonstration of transforming CDISC data into the RGPP format (which created the example you can link to above). The fifth page will explain how you can enhance your output to include graphical legends in pop-up widows so that where you have color-coded certain things, the explanation of the colors can be made to appear. The sixth page will explain how I expect you to set up your html for viewing the patient profiler output. The seventh page will set out my vision for RGPP. You can link to these other pages below, but I must stress that it is important that you have read and understood the previous pages.

A better display of Demography details
Transforming your data for RGPP
Transforming CDISC data for RGPP
Creating graphical legends for RGPP
Html for viewing RGPP
My Vision for RGPP

Terms for RGPP Licencing and Support

"html" pages

This page you are looking at now is an "html" page. The page above you linked to was also an html page. "Html" stands for "hyper-text markup language" but you don't have to worry about what that means. All you need to know is that it is a common format for use over the Internet or Intranet (for where a company has their own collection of web sites that they don't want outsiders to see). The dummy patient profile page you linked to above was an "html" page that referred to a "gif" file. A "gif" file is a type of image file. You have probably heard of "jpegs" - that's what your digital camera creates. "Gifs" are image files that are commonly used for graphical diagrams and this is applicable to patient profiles. "Html" pages and "gif" images are very easy to distribute or allow access to. Clinicians following the progress of a clinical trial will be able to log onto their local Intranet and it is easily possible for patient profile graphics to be made available to them. If need be, an "html" page with its associated "gif" file could be emailed to anybody who needed it. In short - it is very easy to distribute or make available graphical html files. Giving access to or sending graphical patient profiles to clinicians will be simplicity itself if this format is used. It is this style of output that will be created using my Patient Profiler.

Another thing about html pages is that you can hide messages behind shapes, text and pictures. If you move your cursor (mouse pointer) over a shape, text or pictures then you can see this text behind it, if there is any put there. Again, my patient profiler is aimed to fully exploit that ability. People using it will be strongly encouraged to put full detail in text form behind every object shown. So a bar that shows the period an AE lasts will give extra details about the AE such as its system organ class, its severity, whether it is considered serious or not plus any other information a clinician needs to see, providing that data is recorded. The same for Vital Signs or Lab values, even if these are shown as numeric values on the chart. The same for drug dosing. So lurking behind every representation of data, either in text or shape form, it is intended to put fuller details so that a clinician just has to "mouse over" it to get more details.

Now before we leave this section I would ask you to click on the dummy patient profile above and mouse over the shapes and values displayed. Apart from the demography details, all the other text values shown in the timescale region and the shapes have more text behind it. Mouse over each one and you will see.

The graphical patient profiler is aimed for viewing and not for printing. If it is printed out then not only will it be less clear but the information hiding behind the values will be lost. So this is not something to be printed and faxed to somebody. Instead, you can email the html page and its related gif to people who need to see it. They will then have the full "picture" and be able to see the text behind the values as well. Remember that html format is easy to distribute. People don't have to be logged onto a server to see it because you can email it to them. But, of course, you should treat this sort of information as confidential and be careful who you send it to.

What data does it work on?

You might be wondering what sort of data the patient profiler needs to work on. The answer is any sort of data but there is a proviso that will be explained. It can be raw data that is not clean. In can be derived data that has been cleaned. It does not matter. But whatever data you have, has to be transformed into data the patient profiler can understand. This can be a lot of work but oncen done then the code can hopefully be reused on other studies. Transforming the data is a lot of bother but it is unavoidable. Putting displays of extra data behind the values and shapes takes a lot of preparation and can't be done automatically. You may choose to display values using different colors and this will not be something that is in your original data. You may choose to display values using a mixture of different letter heights. Again, this is not something to be found in study data. So you have some transforming of data to do to get the patient profiler to work and when you do this the first time it will take a lot of coding effort.

The four patient profiler datasets

For the patient profiler to work, it requires four datasets that must be named exactly as stated below. Their structure will be explained shortly but first I will list them and say what they do.

There will be a dataset with only one observation in it that contains the style settings for the patient profiler that controls the general layout and colors and the default scale spacing to use. This dataset is named rgpp_style. This dataset has many variables and takes a while to set up but once set, can be used without change on all clinical trials. It holds the unchanging values that dictate the patient profiler layout style that is intended for use throughout an organisation without alteration. If you are used to using sas macros then you should think of this dataset as a "macro parameter dataset". In fact, the contents of this dataset will be converted to effective macro parameters by the patient profiler.

There will be a dataset with only one observation in it that contains the global values for a run of the graphical patient profiler. You would put the name of the patient variable in this, the folder destination for the html pages and gif files produced and the scale you want to display. This dataset is named rgpp_global. If you are used to using sas macros then you should think of this dataset as a "macro parameter dataset". In fact, the contents of this dataset will be converted to effective macro parameters by the patient profiler.

There will be a dataset with one observation per patient (subject). This will contain the subject identity, the html file name, the gif image name and the start and end days for the data you want selected for a patient and the start and end days to show on the scale. This dataset is named rgpp_patients.

Lastly, there is the data you want to display. There will be multiple observations per patient. This dataset should be is named rgpp_data.

In the following sections, the structure of each of these datasets will be explained.

rgpp_style

This is the dataset that controls the general layout for the patient profiler display. This dataset has a lot of variables that control the layout style. You are expected to use one layout style only throughout an organisation. Once the layout has been decided upon, this dataset is intended for use throughout an organisation with no changes being made to it so that the style of the reports is uniform throughout the organisation. The sas programmer who sets this up is expected to know something of sas graphics, especially in regard to choosing the values of ypixels, xpixels, vpos and hpos.

You can tailor the display of the patient profiler to get it to look how you want. You can choose colors and fonts. You can choose the size of the html page. You can choose how much of it you want to use for the time display area and how much to leave for text on the left. What I will say at this point is that you are required to choose some colors and because of the way sas works, your color names must not be more than eight characters long. This does not mean you are limited to colors with names that are eight characters long or less. Any and every color in existence can be referred to as an eight character name once you know how. So if you wanted to use AntiqueWhite as a background then you can use it. If you wanted to use DarkSlateBlue as the default text color then you can use that as well. You just have to find out how to refer to these colors by an eight character code and use that instead. This involves a bit of study so I have written a page on this that explains it all very clearly that you can link to below. It will open in a new window. Keep referring to that page to become expert on choosing colors for your sas html displays.

sas_colors

Assuming you can choose whatever color you like and refer to it by an eight character name (or less) I will continue with the description of the rgpp_settings dataset. What you will see below is an example of it with settings filled in. Note that this is sas code you can use. You can changes the settings but you must not change the length of the variables or change their type. The variable declarations must not be changed. Just their values. And you must make sure that numeric variables and given numeric values and character variable are given character values that do not exceed the allowed length.

Note that some of the numeric variables used are of the True/False type and should only be given the numeric value "0" or "1". 0=False, 1=True.

Note that fonts declared below that are non-sas internal fonts must be specified inside single quotes that in turn are contained in double quotes. You are not seeing double!

All heights are in "cells", if you know "goptions" and annotate datasets. The patient profiler uses the cell reference system, rather than percentages. This is the sas default. Using cells is much better for "long" pages such patient profile html pages.

This first dataset, with only one observation, has a lot of variables. It dictates the style you want for the patient profiler output. Once this dataset is created correctly it is intended to be used without change for the forseeable future. You can always store this dataset somewhere, call it with a "set" statement and override individual values in your code if you need to. (you can run this code)
 

data sasuser.rgpp_style;
  *- This is the version 4.0 template for the RGPP style dataset. -;
  *- The version of this dataset should match the version of RGPP -;
  *- you are using which will be displayed in the log if you call -;
  *- the macro with a positional parameter value set like this:   -;
  *- %rgpp(xxx)                                                   -;
  *- Note that the above call only gives you information about    -;
  *- the macro and does not do any processing of data. Do not use -;
  *- the word "check" (unquoted) for this call as this is for     -;
  *- checking input datasets in addition to providing information -;
  *- about the macro.                                             -;

  *- Whether you want a border drawn around your output. The only -;
  *- permitted values are "noborder" and "border".                -;

  RETAIN border "noborder";  /* new in version 2.0 */

  *- Whether you want the html output to be transparent to the    -;
  *- browser window. The only permitted values are "transparency" -;
  *- and "notransparency".                                        -;

  RETAIN transparency "notransparency";  /* new in version 2.0 */
 

  *- Note that ALL COLORS ARE LIMITED TO 8 CHARACTERS except for cback. -;
  *- Refer to the web site sas tips for how to specify any sas color in -;
  *- short form.  -;

  *- Do not change any of these variable names or their characteristics -;
  *- or RGPP will fail due to errors.   -;
  length cstripe cscale $ 8
         fitemtext fitemdesc fblockdesc fpatient cback $ 32
         fscaletext $ 32   /* new in version 3.0 */
         citemdesc citemdesctrunc cblockdesc cpatient citemtext cfigure $ 8
         citemline $ 8     /* new in version 3.1 */
         cblockbox $ 8
         cblockdescbg cpatientbg $ 8
         hblockdescbg wblockdescbg hpatientbg wpatientbg 8
         hitemdesc hblockdesc hpatient hitemtext hfigure hscaletext 8
         drawblockbox uniformscale usearrows stripeonfirst 8
         ypixels xpixels vpos hpos 8
         hposdmin hposdmax hposdmean hposminfigwidth hposmingap 8
         maxucletters maxmcletters 8
         ;

  *- Note that ALL VARIABLES MUST BE SET to mon-missing values.       -;
  *- You are not allowed to default any values or omit any variables. -;
  *- If any value is missing then RGPP will fail due to errors.       -;

  *- Size of html output with number of rows and columns. -;
  *- You need a knowledge of sas graphics to set these.   -;
  ypixels=2400;
  vpos=120;  /* number of rows */
  xpixels=1100;
  hpos=55;   /* number of columns */

  *- Start and end hpos positions for date area. The maximum -;
  *- value must not exceed what was specifed in hpos= above. -;
  hposdmin=10;
  hposdmax=55;
  *- mean position calculated automatically -;
  hposdmean=(hposdmin+hposdmax)/2;

  *- Colors of the stripes across the date area -;
  cstripe="beige";
  *- Alternate lines within a block will be striped so that it is -;
  *- easy for the eye to scan across without going up or down a   -;
  *- line. You specify here whether you want the lines striped    -;
  *- starting from the first line or not. If not then striping is -;
  *- done on the second line. Your choice will depend on the      -;
  *- color of the block description background color because it   -;
  *- might be better to have the first line as a background color -;
  *- to contrast with the block description background.           -;
  *- 0=no, 1=yes            -;
  stripeonfirst=1;

  *- Backgound color. This can be up to 32 characters long. -;
  *- All other colors are limited to 8 characters due to    -;
  *- annotate dataset restrictions.     -;
  cback="FloralWhite";

  *- Font, color and height of text displayed on the left of the date area  -;
  *- (note that non-sas fonts need to be enclosed in an extra set of single quotes) -;
  *- Note that hitemdesc must not be given a value greater than 1.0 -;
  fitemdesc="'Arial'";
  citemdesc="maroon";
  hitemdesc=0.8;

  *- Height, font and default color of the text to use when text values -;
  *- are displayed in the date area such as vital signs values.   -;
  *- (note that non-sas fonts need to be enclosed in an extra set of single quotes) -;
  *- Note that hitemtext must not be given a value greater than 1.0 -;
  fitemtext="'Arial'";
  hitemtext=0.7;
  citemtext="maroon";

  *- Maximum upper case and mixed case letters that you know will  -;
  *- fit on the left of the date area. You will have to do a trial -;
  *- run, inspect the outputs and adjust these values. -;
  *- (for pure upper case) -;
  maxucletters=23;
  *- (for mixed case) -;
  maxmcletters=30;
  *- Color to show this text when it gets truncated. You will be  -;
  *- able to mouse over this truncated text to see the full text. -;
  citemdesctrunc="blue";

  *- Font, color, height and background color of Patient top-of-page title -;
  *- (note that non-sas fonts need to be enclosed in an extra set of single quotes) -;
  fpatient="'Arial / Bold'";
  cpatient="black";
  hpatient=2.2;
  *- color, height and width of patient background -;
  cpatientbg="CXE0E0E0";
  hpatientbg=2.4;
  wpatientbg=20;

  *- Font, color, height and background color of block titles -;
  *- (note that non-sas fonts need to be enclosed in an extra set of single quotes) -;
  fblockdesc="'Arial / Bold'";
  cblockdesc="black";
  hblockdesc=1.05;

  *- color, height and width of block description background -;
  cblockdescbg="CXE0E0E0";
  hblockdescbg=1.5;
  wblockdescbg=43;

  *- Whether to draw a box around each block of information displayed -;
  *- and the color if so. 0=no 1=yes  -;
  drawblockbox=1;
  cblockbox="maroon";

  *- Height, color and font of the time scale to draw if this is requested. -;
  *- Note that block box color (cblockbox) overrides the scale color  -;
  *- if drawblockbox=1.  -;
  hscaletext=0.8;
  cscale="maroon";
  fscaletext="'Arial'";

  *- Whether the time ticks on the scale should be uniformly spaced. -;
  *- 0=no, 1=yes -;
  uniformscale=1;

  *- Whether to use arrow heads to point to start or end day values -;
  *- that have been imputed where their exact value is unknown.     -;
  *- This also applies to start or end values that fall off the     -;
  *- day scale at either end. 0=no, 1=yes.    -;
  usearrows=1;

  *- Height and color of the figures. Height is effectively the   -;
  *- thickness of the arrow or rod shafts used for showing period -;
  *- information such as the duration of an adverse event. Note   -;
  *- that if arrows are used then the value for hfigure must not  -;
  *- be greater than 0.5 . "citemline" is the color of the line   -;
  *- drawn around the figure which if changed from black could be -;
  *- used to indicate an alternative relationship to that shown   -;
  *- by the figure color, such as using "red" to indicate a       -;
  *- possible relationship of an AE to the study drug. The line   -;
  *- width is determined by "witemline". Allowed values are 1, 2  -;
  *- and 3. 1=normal, 2=thick, 3=very thick. Fractional values    -;
  *- are not effective.     -;
  hfigure=0.4;
  cfigure="BIYG";
  citemline='black';
  witemline=1;

  *- This is the minimum width in hpos values that you want for -;
  *- period data. Some adverse events might only last a day and -;
  *- so a rod or an arrow used to represent it might be too     -;
  *- short to see. This setting will ensure that these short    -;
  *- periods are visible. The position on the day scale will be -;
  *- the mid position of the start and end day. This will be a  -;
  *- box shape that will override an arrow shape. Set it to a   -;
  *- value that is slightly less than the hfigure value.        -;
  hposminfigwidth=0.3;

  *- hposmingap is a control used when you are displaying text   -;
  *- values. If two text values are very close to each other due -;
  *- to the dates being close then the two sets of text will     -;
  *- overlap and become unreadable. What the patient profiler    -;
  *- will do is to display a box for the second set of text      -;
  *- instead of the text if the values are too close. It is up   -;
  *- to you to decide how close you want to get before it makes  -;
  *- this substitution. This is given in hpos positions. Look at -;
  *- the range of hpos values you used for the scale (hposdmin   -;
  *- and hposdmax) and decide what value, based on this, you     -;
  *- require to ensure displayed text values stay separate.      -;
  hposmingap=1.3;

run;
 

rgpp_global

This dataset has very few variables and only one observation. It states what the patient variable name is, the destination folder for the html pages and gif files that gets created and the scale to use. Note that a macro variable "patvar" is created that contains the same contents as the sas variable of the same name. You can run this code.
 

data rgpp_global;
  *- This is the version 4.0 template for the RGPP global dataset.       -;
  *- Do not change any of these variable names or their characteristics. -;
  length patvar $ 32  webout scale $ 200;

  *- Name of the unique patient identifier variable present -;
  *- in the rgpp_patients and rgpp_data datasets. -;
  patvar="subjid";

  *- Destination folder for the html files and gif files -;
  *- created during a run of the patient profiler. Note  -;
  *- this destination folder must actually exist. For a  -;
  *- complete run of new reports you should ensure that -;
  *- the destination folder is empty before you do the   -;
  *- full run.   -;
  webout="C:\webtemp";

  *- Set this to your scale you want to show on the time axis. They should be pairs -;
  *- of study day numbers (first day of study being Day 0) and labels separated     -;
  *- with a #. Pairs of study days and labels should be separated from others like  -;
  *- themselves with a single upright line that sas normally uses (in pairs) for    -;
  *- concatenantion.  An example is given below.  -;
  scale="-14#Screen | 0#Baseline | 7#WK1 | 14#WK2 | 28#WK4 | 56#WK8 | 112#WK16";

  *- write out the contents of "patvar" to a macro variable of the same name -;
  call symput('patvar',trim(patvar));
run;

 

rgpp_patients

This dataset has very few variables. One observation is required for each patient you want to create a patient profile for. If a patient is not listed in this dataset then no profile will be shown. Also, you should ensure that data exists in the rgpp_data dataset for all the patients you have listed in rgpp_patients. Note that you must give valid values to these variables. Missing values are not allowed and will result in errors.

The code you see below is there to help you. It lists the variables the patient profiler needs and describes them. You need your subject variable as well, as described in the code. It is not the complete code. You will need a "set" statement for whatever dataset of patients you have got and you will maybe merge with a dataset (or two) of day values you need. How you do this is entirely up to you. The important thing is that the patient profiler gets the variables it needs with specific names and characteristics. (do not run this code)
 
data rgpp_patients;
  *- This is the version 4.0 template for the RGPP patients dataset.     -;
  *- Do not change any of these variable names or their characteristics. -;
  *- This list of variables does not include the subject variable        -;
  *- defined in rgpp_global and you should ensure that this subject      -;
  *- variable is also present on this dataset and added to the "keep"    -;
  *- list you will find below.  -;
  length htmlfile $ 64 
         gifname $ 8
         minscaleday mindataday maxdataday maxscaleday 8
         ;

  *- Note that "&patvar" will be assigned when rgpp_global is created -;
  KEEP &patvar htmlfile gifname minscaleday mindataday
       maxscaleday maxdataday ;

  *- "htmlfile" will be the name of the html file created. Do not put -;
  *- the suffix ".html" at the end as the software does that for you. -;
  *- You must ensure that this name is unique for each patient. Its   -;
  *- name should allow you to easily match a patient id to the html   -;
  *- filename.   -;

  *- "gifname" can only be eight characters long. You must ensure that -;
  *- this name is unique for a patient. It must start with a letter    -;
  *- and not a number. It's  name should allow you to easily match a   -;
  *- patient id to the gif name.   -;

  *- "minscaleday" is the lowest day to show on the scale for this patient -;

  *- "mindataday" is the lowest day for accepting data for this patient. -;
  *- It must not be less than the minscaleday value. You would normally  -;
  *- set this slightly higher than the minscaleday value to ensure that  -;
  *- information you are displaying as text values does not get written  -;
  *- over the end of the scale. 

  *- "maxscaleday" is the highest day to show on the scale for this patient -;

  *- "maxdataday" is the highest day for accepting data for this patient. -;
  *- It must not be more than the maxscaleday value. You would normally   -;
  *- set this slightly lower than the maxscaleday value to ensure that    -;
  *- information you are displaying as text values does not get written   -;
  *- over the end of the scale.
 

  /***************
  your set statement or merge statement go here plus whatever
  manipulations are required to populate the output variables the 
  patient profiler needs which are your subject variable you defined 
  to rgpp_global plus the variables in the keep list below. All these
  variables must contain valid values. None of them should contain 
  missing values. 
  ****************/

run;

rgpp_data

This dataset has many variables and multiple observations per patient. There is the subject variable plus a set of "block" variables and a set of "item" variables. There are two "day" variables as well - "day1" and "day2". A "block" is a group of items you want to display together as a block. An "item" is the thing you want to display within that block and will have characteristics like a height, a color, its day1 values (and a day2 value for period data). Day values are calculated as days from first dose. You might display the value as text or it might be a box or, for period data, it will be a rod or an arrow. Creating this dataset is quite a lot of work but once you have done it for one study then you should be able to adapt it for other studies. Typically, you would create separate datasets for each block of information. Your datasets might be called something like demog, dosing, vitals, labs, aes, conmeds and then right at the end you bring all these datasets together and give the collection of this data the name rgpp_data.

Once you get used to it, coding this dataset will become easy. The real hard work will be in setting up the variable itemhtml. Each and every item you display on the time scale (not "demog" type of data which does not have a day associated with it) should have a text box that appears when you mouse over it that states what the value is, what the parameter or type of measure is, the units, the days since first dose and maybe many other things. It is important to repeat whatever information is implicit for its position on the day scale. Even if you were displaying the value "98.4°F" as text then you would still need to have this value in your box that appears when you mouse over it.

To help you code this dataset faster, you are allowed to have missing values for things like "citemtext" and "hitemtext". In this case, the patient profiler will use the defaults defined in the rgpp_style dataset. (do not run this code as there is no data)
 

%macro dclvars;
  *- This is the version 4.0 template for the RGPP data dataset.         -;
  *- Do not change any of these variable names or their characteristics. -;
  *- This list of variables does not include the subject variable        -;
  *- defined in rgpp_global and you should ensure that this subject      -;
  *- variable is also present on this dataset and added to the "keep"    -;
  *- list you will find below.  -;

  LENGTH blockisdemog blockismsg blockscale 8
         blockhtml itemhtml $ 1024
         blockseq itemseq 8
         blockdesc itemdesc $ 200
         itemtext $ 40  /* you can choose a length up to 200 characters */
         fitemdesc fitemtext $ 32  /* new in version 3.0 */
         citemdesc citemtext $ 8   /* new in version 3.0 */
         citemline $ 8             /* new in version 3.1 */
         mitemfill $ 8             /* new in version 4.0 */
         witemline 8               /* new in version 3.2 */
         hitemdesc hitemtext 8     /* new in version 3.0 */
         day1 day2 8
         pctdata1 pctdata2 8       /* new in version 2.0 */
         day1_imp day2_imp 8
         ;

  *- Note that "&patvar" will be assigned when rgpp_global is created -;
  KEEP   &patvar
         blockisdemog blockismsg blockscale
         blockhtml itemhtml
         blockseq itemseq
         blockdesc itemdesc
         itemtext
         fitemdesc fitemtext
         citemdesc citemtext citemline mitemfill
         hitemdesc hitemtext witemline
         day1 day2
         pctdata1 pctdata2
         day1_imp day2_imp
         ;
%mend dclvars;
 

data rgpp_data;

  %dclvars

  *- Below is a "retain list" to help you. You will declare all the   -;
  *- variables you need in the above length statement. If you do not  -;
  *- refer to these variables in your code then you will get an       -;
  *- "uninitialized" note in the log so IF YOU ARE NOT CHANGING these -;
  *- variables in your block of code then you should have these       -;
  *- delared in a "retain list" to make sure they get referred to.    -;
  *- But IF YOU ARE SETTING these variables in your code then they    -;
  *- SHOULD NOT also be in the "retain list". Some of these variables -;
  *- can be set in the retain list and left. For example, blockscale  -;
  *- is for saying whether you want the day scale drawn for a block.  -;
  *- You can either leave it set to 1 (Yes) or 0 (no) and not bother  -;
  *- setting it in your code. Some of the variables declared in the   -;
  *- "length" statement are not included in the retain list below     -;
  *- because you will always be setting them in your code.   -;

  RETAIN blockisdemog 0 blockismsg 0 blockscale 1
         blockhtml " " 
         itemtext " "
         fitemdesc fitemtext " "
         citemdesc citemtext citemline mitemfill " "
         hitemdesc hitemtext witemline .
         day2 .
         day1_imp 0 day2_imp 0
         ;

  *- "blockisdemog" is set to 1 if what is contained within the block is -;
  *- demography-type information (like the text values of age, sex, race -;
  *- and any other textual information such as end-of-study status).     -;
  *- This will alert the patient profiler that your text items should be -;
  *- displayed at the start of the date area and that the day1 value,    -;
  *- even if non-missing, should be ignored. 0=no, 1=yes    -;

  *- "blockismsg" is set to 1 if what is contained within the block      -;
  *- description is a message you want the patient profiler to display   -;
  *- where the block description would be placed. You would typically    -;
  *- use this to put out a message such as "No Adverse Events were       -;
  *- recorded for this Subject".  0=no, 1=yes  -;

  *- "blockscale" is set to 1 if you want to display the day scale -;
  *- underneath the block.  0=no, 1=yes   -;

  *- For "blockhtml" refer to "itemhtml" for how to construct this.  -;
  *- if you set up blockhtml then it allows you to have a pop-up box -;
  *- behind the text of the block description shown in the middle of -;
  *- the data area. For SAS versions 8.2 and 9.1.3 there is an       -;
  *- alignment problem with the pop-up text as it will only appear   -;
  *- if you mouse over left of centre of the text. This bug is       -;
  *- supposed to be fixed in sas 9.2   -;

  *- "itemhtml" should be set for each and every item you want to    -;
  *- show in the date area. If you are displaying text then this     -;
  *- same text should be in your pop-up box along with other useful  -;
  *- information. It is easy to make a coding mistake with this      -;
  *- variable. There is an example below that will help you to code  -;
  *- it. Be especially careful with the double and single quotes.    -;
  *- The "0D"x are new-line characters and they are Zero D and not   -;
  *- Oh D. Note that all your text and numeric values at the end of  -;
  *- each line should be kept short by using trim(left( )) and each  -;
  *- line, except the last one, should end with a pair of "||" for   -;
  *- concatenation to the following line.     -;

/********
itemhtml='ALT="Parameter: '||trim(itemdesc)||
"0D"x||'Value: '||trim(itemtext)||
"0D"x||'Visit: '||trim(left(put(visitcd,visit.)))||
"0D"x||'Days after first dose: '||trim(left(put(day1,6.)))||
"0D"x||'Date imputed (Y/N)?: '||put(day1_imp,ny.)||
'"';
********/

  *- "blockseq" is the block sequence number used for sorting the -;
  *- order of the blocks and displaying them in that order.       -;

  *- "itemseq" is the item sequence number used for sorting the  -;
  *- order of the items within the block and displaying them in  -;
  *- that order. You can have more than one observation within a -;
  *- block with the same "itemseq" value, in which case it will  -;
  *- put all the items on the same line. You have to be careful  -;
  *- to set this value correctly if you are doing this.  -;

  *- "blockdesc" is the block description that will get displayed -;
  *- above the block in the middle of the date area.  -;

  *- "itemdesc" is the item description that will get displayed -;
  *- to the left of the date area.    -;

  *- "citemdesc", if blank, will default to the color defined in -;
  *- the rgpp_style dataset.                                     -;

  *- "hitemdesc", if missing, will default to the height defined -;
  *- in the rgpp_style dataset.                                  -;

  *- "fitemdesc", if left missing, will default to the font      -;
  *- defined in the rgpp_style dataset.                         -;

  *- "itemtext" is the text, such as the value of a vital signs  -;
  *- measure, that you want to display as text in the date area. -;
  *- you should only do this for timepoint data and not period   -;
  *- data (i.e. it has a day1 value but a missing day2 value).   -;

  *- "citemtext", if blank, will default to the color defined in -;
  *- the rgpp_style dataset. You can set this to indicate the    -;
  *- severity or intensity of something and it applies to shapes -;
  *- drawn as well as text displayed. With all colors, you are   -;
  *- limited to eight characters for the color name. Read my web -;
  *- page on sas colors if you need to know more about what      -;
  *- colors you can use and how you can refer to any and all     -;
  *- colors by an eight letter name or less.   -;

  *- "citemline", if blank, will default to the color defined in -;
  *- the rgpp_style dataset which wil most likely be "black".    -;
  *- This is the color of the line drawn around figures. You can -;
  *- set this to indicate the existence of an extra relationship -;
  *- from that shown by the item color "citemtext". For example, -;
  *- you could set it to "red" for an AE to indicate a possible  -;
  *- relationship to study drug whereas the figure color purely  -;
  *- indicates the severity of the AE.                           -;

  *- "witemline", if missing, will default to the width defined  -;
  *- in the rgpp_style dataset which will most likely be 1. This -;
  *- determines the thickness of the line drawn around figures.  -;
  *- Use 1 for a normal line, 2 for a thicker line and 3 for a   -;
  *- very thick line.  -;

  *- "mitemfill" is the "map" pattern to fill the drawn shapes   -;
  *- with and this defaults to "mempty" (i.e. no pattern). See   -;
  *- the SAS documentation for what map patterns are possible    -;
  *- and how to specify them. The recommended map pattern is     -;
  *- "m5x135". Note that for the box shape then the pattern you  -;
  *- are using will be difficult to identify, due to the small   -;
  *- size, so you should take care using this facility to ensure -;
  *- nothing important is flagged by a pattern but missed.       -;

  *- "hitemtext", if left missing, will default to the height    -;
  *- defined in the rgpp_style dataset. You would typically use  -;
  *- this to make the display of "itemtext" smaller such as when -;
  *- you were displaying wide text for lab values such as        -;
  *- "NEGATIVE" instead of narrow lab measures such as "12.4".   -;
  *- This height value applies to text only, not shapes drawn.   -;

  *- "fitemtext", if left missing, will default to the font      -;
  *- defined in the rgpp_style dataset.                          -;

  *- "day1" is start day of event calculated as days since first -;
  *- dose of study drug. Do not adjust this, as is customary in  -;
  *- the industry, by adding "1" to its value. It should be      -;
  *- strictly the event date minus date of first dose. If event  -;
  *- date is first dose date then day1=0. It is not day1=1.      -;

  *- "day2" is end day of event calculated as days since first   -;
  *- dose of study drug. Do not adjust this, as is customary in  -;
  *- the industry, by adding "1" to its value. It should be      -;
  *- strictly the event date minus date of first dose. For non-  -;
  *- period data, such as lab value and vital signs, then day2   -;
  *- should be set to missing.   -;

  *- "pctdata1" acts like "day1" except it places your item in a -;
  *- position that is the percentage of the data area, ignoring  -;
  *- the date scaling. It overrides the day1 value. Using it     -;
  *- allows full control for positioning things like variable    -;
  *- labels and their values across the page in case you want a  -;
  *- space-saving display of demography data. -;

  *- "pctdata2" is the "day2" equivalent of "pctdata1" and       -;
  *- although it is provided, you will probably never need to    -;
  *- use it. -;

  *- "day1_imp" is the flag that tells the patient profiler if  -;
  *- you imputed the value for day1. You would set this if you   -;
  *- were not sure of the date because it was a partial date,    -;
  *- for example. For period data it will use an arrow head to   -;
  *- point backwards to this start day. This action can be       -;
  *- overriden in the rgpp_style dataset.  0=no, 1=yes  -;

  *- "day2_imp" is the flag that tells the patient profiler if   -;
  *- you imputed the value for day2. You would set this if you   -;
  *- were not sure of the date because it was a partial date,    -;
  *- for example. For period data it will use an arrow head to   -;
  *- point forwards to this end day. This action can be          -;
  *- overriden in the rgpp_style dataset.  0=no, 1=yes   -;
 

Running the Patient Profiler

Remember that the patient profiler is expecting to find 4 datasets and they must be named as described. You have to prepare these datasets carefully. The patient profiler macro is named %rgpp but you should note that it relies on the utility macros and especially the %rannomac macro must must be explicitly called before you can use %rgpp.

When you are ready to run, you have to make sure the 4 datasets are present and correct and that the output folder (that you defined in rgpp_global) actually exists and is ready to receive the created html and gif files and they you run the %rgpp macro like in the following very simplified case. (do not run this code as it is just template code)
 
data rgpp_style;
  set sasuser.rgpp_style;
run;

data rgpp_global;
  all your lines of sas code;
run;

data rgpp_patients;
  all your lines of sas code;
run;

data rgpp_data;
  all your lines of sas code;
run;

%rgpp

libname _mstore clear; 

Downloading RGPP

RGPP is what I will be calling it from now on as the name is shorter. It is a macro in the "clinmacros" zip file.

download

You can view the source code here.

Playing with RGPP

On another page, I will give details on how to transform your clinical data into a format that RGPP will accept. I will show you how to deal with both horizontal and vertical data and set up the itemhtml entries for these. That's a bit complicated. Before you do that you are encouraged to play around the RGPP using the code below. It assumes you have set up the stored macro catalog. It also assumes you have run the code that produced rgpp_style and written it to your sasuser library. It can be fun to play around with RGPP and you will learn a lot about it that way (you can run this code).
 
*- Run the code on the web site to create rgpp_style in your sasuser library -;
*- and then when you need it just copy it like in the code below. -;
data rgpp_style;
  set sasuser.rgpp_style;
run;

data rgpp_global;
  *- do not change any of these variable names or their characteristics -; 
  *- Webout should be a real location as the html and gif files will be -;
  *- written to there. -;
  length patvar $ 32  webout scale $ 200; 
  patvar="subjectid";
  scale="-14#Screen | 0#Baseline | 7#WK1 | 14#WK2 | 28#WK4 | 56#WK8 | 112#WK16"; 
  webout="C:\webtemp";
  call symput('patvar',trim(patvar));
run;

*- Note that "&patvar" will be assigned when rgpp_global is created -;
data rgpp_patients;
  &patvar="1234-001-0001";
  htmlfile="P1234-001-0001";
  gifname="G0010001";
  minscaleday=-20;
  mindataday=-15;
  maxdataday=115;
  maxscaleday=120;
run;

data rgpp_data;
  LENGTH blockisdemog blockismsg blockscale 8 
         blockhtml itemhtml $ 1024 
         blockseq itemseq 8 
         blockdesc itemdesc $ 200 
         itemtext $ 40
         fitemdesc fitemtext $ 32
         citemdesc citemtext citemline mitemfill $ 8 
         hitemdesc hitemtext witemline 8 
         day1 day2 8 
         pctdata1 pctdata2 8
         day1_imp day2_imp 8 
         ; 

  *-     Note that "&patvar" will be assigned when rgpp_global is created -;
  KEEP   &patvar
         blockisdemog blockismsg blockscale 
         blockhtml itemhtml 
         blockseq itemseq 
         blockdesc itemdesc 
         itemtext 
         fitemdesc fitemtext 
         citemdesc citemtext citemline mitemfill
         hitemdesc hitemtext witemline
         day1 day2 
         pctdata1 pctdata2
         day1_imp day2_imp 
         ; 

  RETAIN blockisdemog 0 blockscale 0 &patvar "1234-001-0001"
         blockhtml " " itemhtml " " blockismsg 0 itemseq 0
         itemtext " "
         fitemdesc fitemtxt " " 
         citemdesc citemtxt citemline mitemfill " " 
         hitemdesc hitemtext witemline . 
         day2 pctdata1 pctdata2 . 
         day1_imp 0 day2_imp 0 
         ; 

  blockseq=1;
  blockismsg=0;
  blockisdemog=1;
  blockdesc="Demography and Outcome";
  hitemtext=0.8;
  itemseq=1;
  itemdesc="Sex";
  itemtext="Female";
  output;

  itemseq=2;
  itemdesc="Age";
  itemtext="30";
  output;

  itemseq=3;
  itemdesc="Status";
  itemtext="Withdrew due to lack of efficacy";
  output;
 

  blockseq=2;
  blockismsg=0;
  blockisdemog=0;
  blockscale=1;
  blockdesc="Vital Signs";
  itemseq=1;
  itemdesc="Weight (kg)";
  day1=0;
  itemtext="76";
  output;

  day1=7;
  itemtext="76";
  output;

  day1=14;
  itemtext="75";
  output;

  day1=30;
  itemtext="73";
  output;

  day1=54;
  itemtext="76";
  output;
 

  blockseq=3;
  blockismsg=1;
  blockisdemog=0;

  itemseq=1;
  day1=.;
  blockdesc="No Concomitant Medications recorded for this Subject";
  itemdesc=" ";
  output;
 

  blockseq=4;
  blockismsg=0;
  blockisdemog=0;
  blockscale=1;
  blockdesc="Adverse Events";

  itemseq=1;
  itemdesc="runny nose";
  itemtext=" ";
  day1=7;
  day2=8;
  citemtext=" ";
  output;

  itemseq=2;
  itemdesc="fracture of right hip";
  citemtext="red";
  day1=40;
  day2=200;
  output;

  itemseq=3;
  itemdesc="influenza";
  day1=50;
  day2=65;
  citemtext=" ";
  output;

run;

%rgpp;
 

You can see the output here

Extending RGPP

I have a small confession to make. That is, RGPP isn't really a graphical patient profiler. I know I called it that - it is just easier to think of it in that way if you encounter it for the first time. RGPP is really a graphics rendering macro that I designed especially for handling the normal requirements of patient profiles. In the four datasets it requires, what you are basically doing in those datasets is telling it what to draw. It doesn't know it is patient data you are giving it. It could be any data you wish so long as what RGPP can draw suits your needs. A tailor-made graphical patient profiler will almost certainly put demography information just under the main header. All the real ones I have seen do that. Mine does not. The reason it does not is because I have kept it flexible so it can be used for other purposes and is not just limited to showing patient data - one patient per page. Once you break that mould then an obvious and immediate extension to the idea of a patient profiler is to have it report on a study such that the study is the main title and the blocks are patients. For example, the clinician might be interested in all the AEs of patients who have had at least one serious adverse event. It is an easy matter to display that on one page. I will give you some dummy code to do this so you can see what the output looks like.

Please take time to play with RGPP. The more you play with it, the more you will understand the way it works and the more uses you will find for it. Remember my quote, "RGPP is really a graphics rendering macro". After you have run the following code for yourself, I hope you will be closer to realizing that. Two patient's AE data will be displayed on the same page when you run the code below. I have been lazy and made the patients AEs the same, but you can see what I mean, I hope! (you can run this code)
 
 *- Run the code on the web site to create rgpp_style in your sasuser library -;
 *- and then when you need it just copy it like in the code below. -;
 data rgpp_style;
   set sasuser.rgpp_style;
 run;

 data rgpp_global;
   *- do not change any of these variable names or their characteristics -; 
   *- Webout should be a real location as the html and gif files will be -;
   *- written to there. -;
   length patvar $ 32  webout scale $ 200; 
   patvar="studyid";
   scale="-14#Screen | 0#Baseline | 7#WK1 | 14#WK2 | 28#WK4 | 56#WK8 | 112#WK16"; 
   webout="C:\webtemp";
   call symput('patvar',trim(patvar));
 run;

*- Note that "&patvar" will be assigned when rgpp_global is created -;
 data rgpp_patients;
   &patvar="Study 1234";
   htmlfile="sae1234";
   gifname="G1234SAE";
   minscaleday=-20;
   mindataday=-15;
   maxdataday=115;
   maxscaleday=120;
 run;

 data rgpp_data;
   LENGTH blockisdemog blockismsg blockscale 8 
          blockhtml itemhtml $ 1024 
          blockseq itemseq 8 
          blockdesc itemdesc $ 200 
          itemtext $ 32 
          fitemdesc fitemtext $ 32
          citemdesc citemtext citemline mitemfill $ 8 
          hitemdesc hitemtext witemline 8 
          day1 day2 8 
          pctdata1 pctdata2 8
          day1_imp day2_imp 8 
          ; 

   *-     Note that "&patvar" will be assigned when rgpp_global is created -;
   KEEP   &patvar
          blockisdemog blockismsg blockscale 
          blockhtml itemhtml 
          blockseq itemseq 
          blockdesc itemdesc 
          itemtext 
          fitemdesc fitemtext 
          citemdesc citemtext citemline mitemfill
          hitemdesc hitemtext witemline
          day1 day2 
          pctdata1 pctdata2 
          day1_imp day2_imp 
          ; 

   RETAIN blockisdemog 0 blockismsg 0 blockscale 0 studyid "Study 1234"
          blockhtml " " itemhtml " " itemseq 0
          itemtext " "
          fitemdesc fitemtext " " 
          citemdesc citemtext citemline mitemfill " " 
          hitemdesc hitemtext witemline . 
          pctdata1 pctdata2 .
          day1_imp 0 day2_imp 0 
          ; 

   blockseq=1;
   blockismsg=1;
   blockisdemog=0;
   blockscale=0;
   blockdesc="All Adverse Events for Subjects experiencing at least one Serious Adverse Event";
   output;

   blockseq=2;
   blockismsg=0;
   blockisdemog=0;
   blockscale=1;
   blockdesc="Subject 001-0001";
   itemseq=1;
   itemdesc="runny nose";
   itemtext=" ";
   day1=7;
   day2=8;
   citemtext=" ";
   output;
   itemseq=2;
   itemdesc="fracture of right hip";
   citemtext="red";
   day1=40;
   day2=200;
   output;
   itemseq=3;
   itemdesc="influenza";
   day1=50;
   day2=65;
   citemtext=" ";
   output;

   blockseq=3;
   blockismsg=0;
   blockisdemog=0;
   blockscale=1;
   blockdesc="Subject 002-0002";
   itemseq=1;
   itemdesc="runny nose";
   itemtext=" ";
   day1=7;
   day2=8;
   citemtextr=" ";
   output;
   itemseq=2;
   itemdesc="fracture of right hip";
   citemtext="red";
   day1=40;
   day2=200;
   output;
   itemseq=3;
   itemdesc="influenza";
   day1=50;
   day2=65;
   citemtext=" ";
   output;

 run;

 %rgpp;
 

If you can't run the code you can link to the output it created here.

A better display of Demography details

You can have more control as to the layout of demography details and this is explained on the page below.

A better display of Demography details
 

Conclusion

You have been introduced to Roland's Graphical Patient Profiler and have learnt that it is really a graphics rendering macro especially designed to handle patient profiler work. Its four driver datasets have been explained and the need to transform your data for RGPP has been explained.
 
 
 

Go back to the home page.

E-mail the macro and web site author.




counter on tumblr