using sas® to create custom tables and presentations in … · 2013. 12. 5. · using sas® to...

20
1 Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE) Kathryn Fingar, MPH, PhD, Maternal, Child and Adolescent Health Program California Department of Public Health, Sacramento, California ABSTRACT Dynamic Data Exchange (DDE) offers SAS® users a way to create custom output in Microsoft® Office. The benefit of DDE is that tables and slides can be easily created in Excel and PowerPoint—exactly how you want them to look— with design features that are often difficult to generate in SAS using other methods, such as the Output Delivery System (ODS). After the table or slide is created, DDE can be used to populate it with data. This paper reviews DDE code necessary to transfer data from SAS to both Excel and PowerPoint. Surveillance products from California’s Maternal and Infant Health Assessment (MIHA) Survey will be shown as examples, demonstrating how DDE and macro do-loops can generate a series of worksheets containing county-level data tables that were designed in Excel and contain a number of rich features. Similarly, DDE can loop through slides, populating charts with data on a series of indicators. The volume of publication-ready data products that SAS can create in minutes using DDE makes this a valuable method for displaying and disseminating results. INTRODUCTION Often the data products we wish to disseminate contain design features that can be difficult to program in SAS. The person best suited to develop these graphics—to consider things like page layout, and color schemes, and user readability—might also have a graphic design or marketing background, rather than SAS experience. This paper will provide an overview of how templates can be designed in Microsoft Excel and PowerPoint. DDE is then used to copy and paste the template and to transfer data from SAS into the new worksheet or slide. This method was used to produce a series of surveillance products with data from California’s Maternal and Infant Health Assessment (MIHA) Survey, shown as examples below. For the Excel products, which we called “MIHA Snapshots,” macro-do loops were used to copy the template into a series of worksheets containing county-level data. For the PowerPoint products, macro-do loops were used to copy the template into a series of slides containing charts on various health indicators. These and other MIHA data products can be found at www.cdph.ca.gov/MIHA

Upload: others

Post on 24-Aug-2020

8 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

1

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE)

Kathryn Fingar, MPH, PhD, Maternal, Child and Adolescent Health Program California Department of Public Health, Sacramento, California

ABSTRACT

Dynamic Data Exchange (DDE) offers SAS® users a way to create custom output in Microsoft® Office. The benefit of DDE is that tables and slides can be easily created in Excel and PowerPoint—exactly how you want them to look—with design features that are often difficult to generate in SAS using other methods, such as the Output Delivery System (ODS). After the table or slide is created, DDE can be used to populate it with data. This paper reviews DDE code necessary to transfer data from SAS to both Excel and PowerPoint. Surveillance products from California’s Maternal and Infant Health Assessment (MIHA) Survey will be shown as examples, demonstrating how DDE and macro do-loops can generate a series of worksheets containing county-level data tables that were designed in Excel and contain a number of rich features. Similarly, DDE can loop through slides, populating charts with data on a series of indicators. The volume of publication-ready data products that SAS can create in minutes using DDE makes this a valuable method for displaying and disseminating results.

INTRODUCTION

Often the data products we wish to disseminate contain design features that can be difficult to program in SAS. The person best suited to develop these graphics—to consider things like page layout, and color schemes, and user readability—might also have a graphic design or marketing background, rather than SAS experience. This paper will provide an overview of how templates can be designed in Microsoft Excel and PowerPoint. DDE is then used to copy and paste the template and to transfer data from SAS into the new worksheet or slide. This method was used to produce a series of surveillance products with data from California’s Maternal and Infant Health Assessment (MIHA) Survey, shown as examples below. For the Excel products, which we called “MIHA Snapshots,” macro-do loops were used to copy the template into a series of worksheets containing county-level data. For the PowerPoint products, macro-do loops were used to copy the template into a series of slides containing charts on various health indicators. These and other MIHA data products can be found at www.cdph.ca.gov/MIHA

Page 2: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

2

UNDERLYING DATA

First SAS output must be saved in a format that is ready to send using DDE. Because MIHA is a survey with a complex sample, the output in this paper was generated using PROC SURVEYFREQ. However, similar methods can be used to save output from PROC FREQ.

The products shown above display the prevalence of health indicators in California, and within counties. In the tabular data product (entitled “MIHA Snapshot”), we examined whether the prevalence was different in the county compared with the rest of California using a chi-square test. Therefore, the SAS code below was run on a data set containing dummy variables for each county (e.g., 1=Alameda County, 0=Rest of California) and a series of indicators formatted dichotomously, which labeled the category that was reported (e.g., 4=Daily folic acid use, month before pregnancy’) and flagged the other category so that it could be deleted (e.g., other=’Other’). P-values from chi-square tests were entered into a column outside the print area on the snapshot, and used to display a symbol for whether the indicator in the county was “better” or “worse” than in the rest of the state.

proc format; *Counties/column headers; value alameda 1 ='Alameda County' 0='Rest of California'; value la 1 ='Los Angeles County' 0='Rest of California'; value sd 1 ='San Diego County' 0='Rest of California'; /*etc*/ *Indicators/row headers; value ptdlbw 1='Prior low birth weight or preterm delivery' other='Other'; value csec 2,12,22,32,4,15,16 ='Prior delivery by c-section' other='Other'; value health 1,2='In good to excellent health before pregnancy' other='Other'; value diabetes 1='Diabetes or gestational diabetes' other='Other'; value htn 1='Hypertension, preeclampsia or eclampsia' other='Other'; value asthma 1='Asthma' other='Other'; value folic 4='Daily folic acid use, month before pregnancy' other='Other'; /*etc*/ run; proc surveyfreq data = miha2010 rate=sampfrac2010 nomcar; weight statewt; stratum stratum; tables (ptdlbw csec health diabetes htn asthma folicacid)*(county1 county2 county3)/col cl chisq; format ptdlbw ptdlbw. csec csec. health health. diabetes diabetes. htn htn. asthma asthma. folicacid folic. county1 alameda. county2 la. county3 sd.; ods output crosstabs=crosstabs; ods output chisq=chisq; run;

The ODS data set is further modified using the code below. The temporary arrays correspond to the names of the variables for the counties and indicators, and the regular arrays to the actual variables in the ODS data set. SAS automatically creates a character copy of the numeric variables, which contains the formatted values; “f_” is added to the variable name.

data crosstabs; set crosstabs; *County/indicator names; county=upcase(scan(table,4," ")); indicator=upcase(scan(table,2," ")); *County/indicator labels; array iname [7] $ 50 _temporary_ ('ptdlbw' 'csec' 'health' 'diabetes' 'htn' 'asthma' 'folicacid'); array cname [3] $ 50 _temporary_ ('county1' 'county2' 'county3'); array ivalue [*] $ f_ptdlbw f_csec f_health f_diabetes f_htn f_asthma f_folicacid; array cvalue [*] f_county1-f_county3; do i=1 to dim(ivalue); if indicator=upcase(iname[i]) then indicatorlabel=ivalue[i]; end; do i=1 to dim(cvalue); if county=upcase(cname[i]) then countylabel=cvalue[i]; end; *Delete SAS output that we do not need; if countylabel='Rest of California' or indicatorlabel in('Other','Total') then delete;

Page 3: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

3

*Statewide prevalence estimates (only need to keep totals for first crosstab); if county ne 'COUNTY1' and countylabel='Total' then delete; if countylabel='Total' then do; countylabel='California'; county='COUNTY0'; colpercent=percent; collowercl=lowercl; coluppercl=uppercl; end; *Round population estimates to the nearest hundred, and percentages to 1 decimal place; np = put(round(wgtfreq,100),6.0); pct= put(colpercent,4.1); low= put(collowercl,4.1); up = put(coluppercl,4.1); keep indicator county indicatorlabel countylabel np pct low up; run; data chisq; set chisq; where label1='Pr > ChiSq'; county=upcase(scan(table,4," ")); indicator=upcase(scan(table,2," ")); pvalue=nvalue1; keep county indicator pvalue; run; proc sort data = crosstabs; by county indicator; run; proc sort data = chisq; by county indicator; run; data sasoutput; merge crosstabs chisq; by county indicator; if pct='*' then pvalue=.; run;

The resulting data set SASOUTPUT looks like this:

Page 4: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

4

DDE TO EXCEL: THE BASICS

Now that SAS output is saved in a format that can easily be sent to Excel or PowerPoint via DDE, let’s review some basics. Whereas DDE sends data from SAS to Excel using filename references, data is sent from SAS to PowerPoint using keystrokes. Because these approaches have different methods, this paper is broken into separate sections for Excel and PowerPoint. Each section will begin with basic principles and then combine these principles to create the surveillance products shown earlier.

DDE FILENAME REFERENCES: DOUBLETS AND TRIPLETS

The DDE code below is called a system doublet. It refers to the Excel system and is used in conjunction with a DATA step to do things like save and add worksheets to Excel files.

filename xlsys dde 'excel|system';

The DDE triplet, in comparison, refers to a specific worksheet and range of cells in an Excel file. The triplet is also used in conjunction with a DATA step to format cells, send data, or import data. Notice that the Excel file name itself is not specifically referenced, only the worksheet name (e.g., “Template”). Therefore, SAS assumes that the file is open and active in the Excel application. This example covers cells below row 9 and to the right of column 16, through row 18 and column 17.

filename getdata dde 'excel|Template!r9c16:r18c17';

READING DATA FROM EXCEL INTO SAS

To transfer data to the MIHA snapshots, SAS needs information on which row corresponds to which indicator. Therefore, the templates in Excel store the indicator name and row number in cells outside the print area.

A DDE triplet is used to import these data into SAS. The file reference GETDATA is first specified in a FILENAME statement, and then again in an INFILE statement within a DATA step. When SAS communicates with Excel via DDE, by default, tab characters are translated as spaces. This is problematic because the default delimiter between cell values in Excel is also a tab character. Therefore, the DLM=’09’x and NOTAB options are needed so that different data values are imported into separate SAS variables. Without them the first row would be imported as one variable= ‘PTDLBW 9.’ MISSOVER and DSD are needed because there are blank cells with missing data. The resulting data set INDICATORS is shown on the right.

filename getdata dde 'excel|Template!r9c16:r18c17'; data indicators; infile getdata dlm='09'x notab missover dsd; format indicator $200.; input indicator $ row; if indicator = ' ' then delete; indicator=upcase(indicator); run;

Page 5: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

5

ADDING A WORKSHEET

The system doublet can be used to add a worksheet to an Excel file, creating a copy of the template for each county. In the code below, the first PUT statement supplies the DDE command to copy the worksheet “Template,” and specifies the name of the open Excel file and location of the new worksheet (e.g., 2nd worksheet). After the worksheet is copied, by default it is named “Template (2),” which is the same thing that would happen if you created a copy of the worksheet manually in Excel by right-clicking on “Template” and selecting “Move or Copy.” In the second PUT statement, the new worksheet called “Template (2)” is renamed “Alameda County.”

data _null_; file xlsys; put '[workbook.copy("Template","MIHA Snapshot.xlsx",2)]'; put '[workbook.name("Template (2)","Alameda County")]';

run;

SENDING DATA FROM SAS TO EXCEL

Triplets are used to send data to a range of cells in Excel. Let’s start by sending data on prior poor birth outcomes in Alameda County. First, use a WHERE statement to select the row containing data on the indicator PTDLBW for Alameda in the data set SASOUTPUT created above. Notice that a dash is created to place between the lower and upper bounds of the confidence interval. A PUT statement specifies the variables to transfer to the columns referenced in the triplet, 3 through 7. The options NOTAB and ‘09’X are included so variables are delimited correctly.

filename senddata dde "excel|Alameda County!r9c3:r9c7" notab; data _null_; set sasoutput; where countylabel="Alameda County" and indicator="PTDLBW"; dash="-"; file senddata; put pct '09'x low '09'x dash '09'x up '09'x np '09'x; run;

Next similar code is used to insert data for California and the p-value comparing the prevalence in Alameda County with the prevalence in the rest of the state.

filename senddata dde "excel|Alameda County!r9c9:r9c13" notab; data _null_; set sasoutput; where countylabel="California" and indicator="PTDLBW"; dash="-"; file senddata; put pct '09'x low '09'x dash '09'x up '09'x np '09'x; run;

filename senddata dde "excel|Alameda County!r9c14" notab; data _null_; set sasoutput; where countylabel="Alameda County" and indicator="PTDLBW"; file senddata; put pvalue; run;

Page 6: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

6

Now row 9 contains data on prior poor birth outcomes in Alameda County:

SAVING EXCEL FILES

Finally, the system doublet is used to save Excel files. data _null_; file xlsys; put '[save]'; run;

ITERATIVE MACRO VARIABLES

It is possible to iterate the basic steps above over both counties and indicators using macro variables. First, macro variables containing lists of counties, indicators, and rows in which to insert the indicator data need to be created. This is easily done in PROC SQL.

proc sql; select indicator into: indicator separated by '#' from indicators; select row into: row separated by '#' from indicators; select distinct countylabel into: county separated by "#" from sasoutput where countylabel ne "California" order by county desc; quit;

In the code above macro variables called COUNTY, INDICATOR, and ROW are created which store the data values from the data set SASOUTPUT in a list, where each value is delimited by “#.” %PUT would return the following:

%put &county; San Diego County#Los Angeles County#Alameda County %put &indicator; PTDLBW#CSEC#HEALTH#DIABETES#HTN#ASTHMA#FOLICACID %put &row; 9#10#12#14#15#16#18

To isolate the ith value in the list, use the macro function %SCAN. The arguments are (macro variable name, return text in the ith position, delimiter).

%put %scan(&county,1,'#'); San Diego County

The number of counties and indicators should also be stored in macro variables to end the DO-LOOPS. In this example, &NUMCTY will return a value of 3 and &NUMIND will return a value of 7. proc sql; select count(*) into: numind separated by '#' from indicators; select count(distinct county) into: numcty separated by '#' from sasoutput where countylabel ne "California"; quit;

Page 7: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

7

Note that the macro variable containing the county names was sorted in descending alphabetical order above, so the template will be copied first for San Diego, and inserted into the 2nd position. On the next iteration, it will be copied for Los Angeles and inserted into the 2nd position, moving San Diego to the 3rd position.

MACRO QUOTING FUNCTIONS

When the DDE code above is modified to include macro variables, the macro quoting functions %UNQUOTE and %BQUOTE should be used. These are needed because macro variables do not resolve if they are in single quotation marks (e.g., ‘&county’). Yet, single quotation marks are required in DDE syntax. Therefore, %BQUOTE allows the macro variable to resolve, then the text is unquoted using %UNQUOTE so that it can be processed using DDE. Equivalent code without and with macro variables is listed below. put '[workbook.name("Template (2)","Alameda County")]'; put %unquote(%bquote('[workbook.name("Template (2)","%scan(&county,&c,'#')")]'));

EXCEL TEMPLATE FEATURES

There are also important features that were designed within the Excel template. The title “MIHA Snapshot, Sample County 2010” and the column header “Sample County” are based on formulas containing the first cell in column N. DDE was used to send the county name to r1c14.

The Excel formulas for the symbols are also worth noting. Using the Excel formula below, if the p-value in column N is greater than 0.05, the symbol (which is “s” in the font Wingdings) is inserted. If the p-value is <0.05 and the county is doing better than the rest of the state (e.g., the county prevalence is less than in the rest of the state and the indicator is negative, or the county prevalence is higher than in the rest of the state and the indicator is positive) the symbol is inserted. Finally, if the p-value is <0.05 and the county is doing worse than the rest of the state, the symbol  is inserted. The colors (gray vs. teal vs. orange) are programmed using conditional formatting.

DDE TO EXCEL: APPLYING THE BASICS

Now, the basic steps above can be combined into a macro, creating worksheets for all three counties and inserting data for all seven indicators in this example. Consider how useful the program is when conducted for all counties in California, and for all indicators on the front and back of the MIHA snapshot. The macro assumes the macro variables have already been created using the PROC SQL code above.

Page 8: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

8

%macro mihasnapshots; %do c=1 %to &numcty;

/*Add worksheet for county &c*/ filename xlsys dde 'excel|system'; data _null_; file xlsys; put '[workbook.copy("Template","MIHA Snapshot.xlsx",2)]'; put %unquote(%bquote('[workbook.name("Template (2)","%scan(&county,&c,'#')")]')); run;

/*Send county name for title and column header*/ filename senddata dde "excel|%scan(&county,&c,'#')!r1c14" notab; data _null_; file senddata; put "%scan(&county,&c,'#')" '09'x; run;

%do i=1 %to &numind; /*Send prevalence data for indicator &i for county &c*/ filename senddata dde "excel|%scan(&county,&c,'#')!r%scan(&row,&i,'#')c3:r%scan(&row,&i,'#')c7" notab; data _null_; set sasoutput; where countylabel="%scan(&county,&c,'#')" and indicator="%scan(&indicator,&i,'#')"; dash="-"; file senddata; put pct '09'x low '09'x dash '09'x up '09'x np '09'x; run;

/*Send prevalence data for indicator &i for state*/ filename senddata dde "excel|%scan(&county,&c,'#')!r%scan(&row,&i,'#')c9:r%scan(&row,&i,'#')c13" notab; data _null_; set sasoutput; where countylabel="California" and indicator="%scan(&indicator,&i,'#')"; dash="-"; file senddata; put pct '09'x low '09'x dash '09'x up '09'x np '09'x; run;

/*Send p-value for indicator &i comparing county &c to the rest of the state*/ filename senddata dde "excel|%scan(&county,&c,'#')!r%scan(&row,&i,'#')c14" notab; data _null_; set sasoutput; where countylabel="%scan(&county,&c,'#')" and indicator="%scan(&indicator,&i,'#')"; file senddata; put pvalue; run; %end; %end;

/*Save file*/ filename xlsys dde 'excel|system'; data _null_; file xlsys; put '[save]'; run; %mend mihasnapshots;

Page 9: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

9

DDE TO POWERPOINT: THE BASICS

While there is a large amount of literature on using DDE to communicate between SAS and Excel, there is less literature on communicating with PowerPoint. However, communicating with PowerPoint is possible using Excel as an intermediate. Once the connection is made, basic functions in PowerPoint can be manipulated via keystrokes. Although this may seem complicated, virtually anything you can do in PowerPoint through keystrokes can be programmed in SAS and going through the keystrokes manually in PowerPoint provides an easy road map for developing SAS code.

COMMUNICATING WITH POWERPOINT VIA EXCEL

SAS can communicate with PowerPoint using an X4ML macro worksheet in Excel. Assuming the Excel application is open, this can be created using the following code. Notice that the system doublet is used first to create the macro worksheet, which by default is named “Macro1.” Next, using a triplet file reference, code is inserted to slow communication between SAS and Excel, giving time for PowerPoint to process the keystrokes. If no delay is specified, the keystrokes will not work. Depending on your computer’s speed, you might also need to increase the wait time. This is one downside to sending data using keystrokes—because it depends on processing speed, what works on one computer, may not work on another. In our case, two seconds worked well on most computers.

data _null_; file xlsys; put '[error(false)]'; put '[workbook.insert(3)]'; put '[workbook.delete("Sheet1")]'; run;

filename xlmacro dde "excel|macro1!r1c1:r10c1" notab lrecl = 200; data _null_; file xlmacro; put '=wait(now()+"00:00:02)'; put '=halt(true)'; run; filename xlmacro clear;

SLIDE TEMPLATE

To start, a blank template was created in PowerPoint (shown below). Notice there are text boxes for the slide title, y-axis title, statewide prevalence rate, and footnote. Also notice there are dummy data entered in the underlying Excel worksheet for the PowerPoint chart. This slide template will be copied and pasted for each indicator, and then that indicator’s data will be transferred to the Excel worksheet containing the chart data.

x

Page 10: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

10

COMMON KEYSTROKES

Below is a list of common keystrokes. Most of them are intuitive, but some are slightly different than the key name.

Key Code

BACKSPACE {BACKSPACE} or {BS}

BREAK {BREAK}

CAPS LOCK {CAPSLOCK}

CLEAR {CLEAR}

DELETE or DEL {DELETE} or {DEL}

DOWN ARROW {DOWN}

END {END}

ENTER {ENTER}

ESC {ESCAPE} or {ESC}

HOME {HOME}

INS {INSERT}

LEFT ARROW {LEFT}

NUM LOCK {NUMLOCK}

PAGE DOWN {PGDN}

PAGE UP {PGUP}

RIGHT ARROW {RIGHT}

TAB {TAB}

UP ARROW {UP}

Keys can be used in combination, by putting them in front of another code. For instance, CTRL-C, for copy, is “^{C}”.

KEYSTROKE SEQUENCES

Let’s review what can be accomplished using sequences of keystrokes, step-by-step. The code below requires that the cursor starts in the window of the main slide, not for instance, in the slide selection panel on the left. This is because the keystrokes need to be active within the slides themselves, not in the selection panel. It is important to check the location of the cursor and where it moves next after hitting TAB, before starting any keystrokes.

Although it isn’t apparent in the screen shot images shown here, the slide objects are in order, such that:

- 1st TAB – highlights the slide title - 2nd TAB – highlights the chart - 3rd TAB – highlights the grouped text boxes containing the California prevalence rate and red arrow - 4th TAB – highlights the text box for the California prevalence rate, alone - 5th TAB – highlights the arrow, alone - 6th TAB – highlights the y-axis title - 7th TAB – highlights the footnote

Key Code

SHIFT +

CTRL ^

ALT %

COMMAND *

Correct

Incorrect

Page 11: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

11

If the tab order were different, the following code presented in this paper would not work. Therefore, when using keystrokes, it is important to check the tab order in your PowerPoint presentation. If something is off, you can change the order by cutting that object (CTRL-X) and re-pasting it (CTRL-C), so that it is now at the end. Do this for all objects in the desired order. Alternatively, adjust your SAS code to TAB until the correct object is selected.

Duplicate Selected Slides

If you were going to copy and paste a slide manually in PowerPoint, using only keystrokes, you could use the sequence: ALT-H, I, D. Selecting ALT-H highlights the “Home” dashboard. The screenshot below on the left is what you would see. Letters are now printed by each option. Selecting “I” is equivalent to clicking on “New Slide.” After selecting “I,” a drop down menu appears (shown on the right), where the option “D” is equivalent to clicking on “Duplicate Selected Slides.”

To do this in SAS, use the following code. The system doublet is referenced first. Next, the PowerPoint presentation is activated. It is assumed that the file is already open. The file name must appear in SAS exactly as is appears at the top of the PowerPoint application, which may differ from computer to computer (see below). Last, the macro worksheet in Excel is called, and then it is possible to send keystrokes. After duplicating the slide, the active slide is the 2nd slide. In this example, let’s highlight the 1st slide again, by using the up arrow.

data _null_; file xlsys; put '[app.activate("MIHA Charts.pptx - Microsoft PowerPoint")]'; put '[run("macro1!r1c1")]'; put '[send.keys("%{h}",true)]'; /*ALT=% plus H, highlights menu and selects home*/ put '[send.keys("{i}",true)]'; /*Selects "Insert"*/ put '[send.keys("{d}",true)]'; /*Selects "Duplicate Selected Slides"*/ put '[send.keys("{up}",true)]'; /*Edit slide ahead of this one (so template remains last)*/ run;

Page 12: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

12

The resulting file now has two slides, and the first one is active.

Insert Text into a Text Box

Next, the following keystrokes insert text into the slide title.

data _null_; file xlsys; put '[app.activate("MIHA Charts.pptx - Microsoft PowerPoint")]'; put '[run("macro1!r1c1")]'; put '[send.keys("{tab}",true)]'; /*One TAB and cursor will be on slide title*/ put '[send.keys("{enter}",true)]'; /*ENTER places cursor inside text box ready to type*/ put '[send.keys("Daily folic acid use in the month before pregnancy, MIHA 2010",true)]'; /*Type title*/

put '[send.keys("{esc}",true)]'; /*ESC moves cursor out of text box*/ run;

Open and Insert Chart Data

In this file, another TAB highlights the chart. The following keystrokes can be used to open the chart data in Excel.

data _null_; file xlsys; put '[app.activate("MIHA Charts.pptx - Microsoft PowerPoint")]'; put '[run("macro1!r1c1")]'; put '[send.keys("{tab}",true)]'; /*One more TAB and the cursor will be on the chart*/ put '[send.keys("^+{F10}",true)]'; /*CTRL=^ plus SHIFT=+ plus F10 is right click*/ put '[send.keys("{E}",true)]'; /*The letter "E" selects the option in the list "Edit"*/ run;

Page 13: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

13

Now it is possible to send data to Excel using the methods discussed previously. The data set SASOUTPUT is modified so it only contains prevalence data in counties 1-20 on the indicator of interest (e.g., folic acid use). A variable for the state prevalence rate is set equal to 33.1 for every observation, and the difference between the confidence interval and the county prevalence rate is calculated for the chart’s error bars. It was important that in all the slides, the county with the best rate was on the left. Therefore, if the indicator was positive (protective) the data were sorted in descending order. If the indicator was negative (risk factor), the data were sorted in ascending order. data folicacid; set sasoutput; where countylabel ne "California" and indicator="FOLICACID"; *Take out the word "County" because the text is too long for the chart; countylabel=tranwrd(countylabel,"County",""); *State percent; statepct="33.1"; *Difference between county prevalence rate and upper and lower CL for the error bars; plus = input(up,4.2) - input(pct,4.2); minus= input(pct,4.2) - input(low,4.2); run;

*Sort so the county with the best rate is on the left. Because this is a positive indicator, sort descending; proc sort data = folicacid; by descending pct; run; *Send data to the PowerPoint chart in Excel using DDE; filename senddata dde "excel|Sheet1!r2c1:r21c5" notab; data _null_; set folicacid; file senddata; put countylabel '09'x statepct '09'x pct '09'x plus '09'x minus '09'x; run;

The resulting chart data now look like this:

The code below is used to close the chart data in Excel.

data _null_; file xlsys; put '[file.close(false)]'; run;

Page 14: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

14

Move Objects on a Slide

Ideally, the state rate would be directly above the red line and not overlap with the blue bars. Its location depends on whether the indicator is positive or negative (e.g., protective or risk factor) and on the prevalence rate, and may need to move left or right, and up or down. The code below includes an algorithm that adjusts the location of the text box based on these factors. First, the statewide prevalence rate is added to the text box using methods discussed above.

data _null_; file xlsys; put '[app.activate("MIHA Charts.pptx - Microsoft PowerPoint")]'; put '[run("macro1!r1c1")]'; put '[send.keys("{tab 2}",true)]'; /*Two TABS and cursor will be on text box for "California"*/ put '[send.keys("{enter}",true)]'; /*ENTER places cursor inside text box ready to type*/ put '[send.keys("{end}",true)]'; /*END moves cursor to end of "California"*/ put '[send.keys("{enter}",true)]'; /*ENTER moves cursor to next line*/ put '[send.keys("33.1",true)]'; /*Type the statewide prevalence rate for this indicator*/ put '[send.keys("{esc}",true)]'; /*ESC moves cursor out of text box*/ put '[send.keys("+{tab}",true)]'; /*SHIFT=+ plus TAB moves back, cursor on grouped state%+arrow*/

/*Since folic acid is a protective factor, move state box to right 40 times*/ do m=1 to 40; put '[send.keys("{right}",true)]'; end;

/*Now reposition the text box so that the state rate is above the red line*/ /*Programming adjusts the number of 'down' and 'up' strokes based on the value of the state rate*/ statepct= 33.1; if statepct lt 50 then move=floor(abs((50-statepct)/2)); if statepct gt 50 then move=floor(abs((50-statepct)/1.8)); if statepct lt 50 then do m = 1 to move; put '[send.keys("{down}",true)]'; end; if statepct gt 50 then do m = 1 to move; put '[send.keys("{up}",true)]'; end; run;

The statewide rate is now positioned above the red line, on the right side where it does not overlap with blue bars.

Special Characters

The characters + % ( ) ^ ~ have special meaning in keystroke syntax, and cause errors when included in DDE code. To send these characters, enclose them in braces “{}”.The code below inserts the y-axis title, containing “(95% CI)”.

data _null_; file xlsys; put '[app.activate("MIHA Charts.pptx - Microsoft PowerPoint")]'; put '[run("macro1!r1c1")]'; put '[send.keys("{tab 3}",true)]'; /*3 TABS places the cursor on the axis title*/ put '[send.keys("{enter}",true)]'; /*ENTER places cursor inside text box ready to type*/ put '[send.keys("Percentage of women who used folic acid daily {(}95{%} CI{)}",true)]'; /*Type title*/ put '[send.keys("{esc}",true)]'; /*ESC moves cursor out of text*/ run;

Page 15: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

15

Find and Replace

Keystrokes were used to insert the year and sample size into the footnote with the following code. #YEAR and #N were used as place holders in the slide template. Note that the code was broken up into three DATA steps, because we ran into problems with time and needed to slow SAS down so PowerPoint could process the keystrokes. data _null_; file xlsys; put '[app.activate("MIHA Charts.pptx - Microsoft PowerPoint")]'; put '[run("macro1!r1c1")]'; put '[send.keys("^{h}",true)]'; /*CTRL=^ plus H opens find and replace*/ put '[send.keys("(#N)",true)]'; /*Enters #N into the field for "Find"*/ put '[send.keys("{tab}",true)]'; /*TAB to the field for "Replace"*/ put '[send.keys("6,817",true)]'; /*Type the sample size for 2010*/ run; data _null_; file xlsys; put '[run("macro1!r1c1")]'; put '[send.keys("+{tab 2}",true)]'; /*SHIFT=^ plus 2 TABS places cursor on "Replace All"*/ put '[send.keys("{enter 2}",true)]'; /*Hit ENTER to "Replace All" and again to close dialog box*/ put '[send.keys("(#YEAR)",true)]'; /*Cursor is now on the field for "Find" again, type #YEAR*/ put '[send.keys("{tab}",true)]'; /*TAB to the field for "Replace"*/ put '[send.keys("2010",true)]'; /*Type the data year*/ run; data _null_; file xlsys; put '[run("macro1!r1c1")]'; put '[send.keys("+{tab 2}",true)]'; /*SHIFT=^ plus 2 TABS places cursor on "Replace All"*/ put '[send.keys("{enter 2}",true)]'; /*Hit ENTER to "Replace All" and again to close dialog box*/ put '[send.keys("{esc}",true)]'; /*ESC moves cursor out of find and replace*/

run;

Select the Next Slide

Now that this slide is complete, the following code is used to select the next slide, which is the template. The steps discussed above can be replicated for the next indicator.

data _null_; file xlsys; put '[app.activate("MIHA Charts.pptx - Microsoft PowerPoint")]'; put '[run("macro1!r1c1")]'; put '[send.keys("{esc}",true)]'; /*ESC moves cursor back to slide selection*/ put '[send.keys("{down}",true)]'; /*DOWN selects next slide, which is the template*/ run; /*Ready to start from beginning, for next indicator*/

Page 16: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

16

ITERATIVE MACRO VARIABLES

Before combining the code above to create slides for multiple indicators, iterative macro variables need to be created to store lists of indicators and titles. The Excel file (below) was imported into a SAS data set called TITLES and modified to enclose problematic characters in braces. There are variables for indicator name, slide title, axis title, and whether the indicator is a risk or protective factor.

Again, this information was stored in macro lists delimited by ‘#.’ The function TRANWRD was used to replace problematic characters. STRIP was used to remove leading and trailing blanks. Macro variables were also created for the number of indicators/slides to loop through, and for the PowerPoint file name, data year, and sample size.

data titles; format slidetitles $250. axistitles $250.; set titles; slidetitles=strip(tranwrd(slidetitles,"(","{(}")); slidetitles=strip(tranwrd(slidetitles,")","{)}")); slidetitles=strip(tranwrd(slidetitles,"%","{%}")); slidetitles=strip(tranwrd(slidetitles,"+","{+}")); axistitles=strip(tranwrd(axistitles,"(","{(}")); axistitles=strip(tranwrd(axistitles,")","{)}")); axistitles=strip(tranwrd(axistitles,"%","{%}")); axistitles=strip(tranwrd(axistitles,"+","{+}")); run;

proc sql noprint; select indicators into: indicators separated by "#" from titles; select slidetitles into: slidetitles separated by "#" from titles; select axistitles into: axistitles separated by "#" from titles; select factors into: factors separated by "#" from titles; select count(*) into: numind from titles; quit; %let fname=MIHA Charts.pptx - Microsoft PowerPoint; %let year=2010; %let sampsize=6,817;

Page 17: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

17

COMMAS AND %SUPERQ

Commas can cause errors in macro language because they delimit arguments in functions. For instance, a macro string with commas will return errors if you try to parse it with %SCAN because when SAS reads the comma it moves to the next argument. The %SUPERQ function can be used to avoid these errors. The function is placed around the macro variable without an ampersand. Because the function takes effect at run-time, when the macro is compiled and read by the %SCAN function, it is treated as text. For instance, this code will return an error: %let test=Tile 1 with a , this is still title 1#Title 2; %put %scan(&test,1,'#'); ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: this is still title 1#Title 2 ERROR: Argument 2 to macro function %SCAN is not a number.

The following code will parse the string correctly. %put %scan(%superq(test),1,'#'); Tile 1 with a , this is still title 1

SAS, SLOW DOWN!

SAS processing is slowed using the macro worksheet in Excel, which was described above. However, you might need to slow SAS down in another area of your program. To do this you can add a null DATA step that uses the function SLEEP, which has the arguments (number, unit). The unit 1 corresponds to seconds. The code below waits 2 seconds before proceeding. If your code is not working and everything looks correct, you may want to go through the keystrokes manually and note points where your computer’s processing speed is slow. For instance, we noticed that our computer took a while to open and insert chart data. Yet, SAS did not recognize this and proceeded with the code, causing errors. We inserted the code below at these key points, and it worked.

data _null_; x=sleep(2,1); run;

DOUBLE AMPERSANDS

The only code the macro below uses, which has not yet been reviewed, is a double ampersand. Double ampersands tell SAS to resolve a macro variable twice and are useful for nesting iterative macro variables. We created macro variables for the statewide prevalence rate for each indicator, where &STATEPCT1 corresponds to the 1st indicator, and so on. When using &&STATEPCT&I in the DO-LOOP, on the first iteration SAS resolves once to &STATEPCT1, and then resolves again to the percent for indicator 1.

DDE TO POWERPOINT: APPLYING THE BASICS

The code described above was combined in a macro, which loop through multiple indicators, creating a slide for each one.

%macro mihacharts; %do i=1 %to &numind;

/*Duplicate selected slides*/ data _null_; file xlsys; put %unquote(%bquote('[app.activate("&fname")]')); put '[run("macro1!r1c1")]'; put '[send.keys("%{h}",true)]'; /*Alt=% plus h, highlights menu and selects home*/ put '[send.keys("{i}",true)]'; /*Selects "Insert"*/ put '[send.keys("{d}",true)]'; /*Selects "Duplicate Selected Slides"*/ put '[send.keys("{up}",true)]'; /*Edit slide ahead of this one (so template remains last)*/ run;

Page 18: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

18

/*Insert text into the text box containing the slide title for indicator &i*/ data _null_; file xlsys; put %unquote(%bquote('[app.activate("&fname")]')); put '[run("macro1!r1c1")]'; put '[send.keys("{tab}",true)]'; /*One TAB and cursor will be on slide title*/ put '[send.keys("{enter}",true)]'; /*ENTER places cursor inside text box ready to type*/ put %unquote(%bquote('[send.keys("%scan(%superq(slidetitles),&i,'#'), MIHA &year",true)]')); /*Title*/ put '[send.keys("{esc}",true)]'; /*ESC moves cursor out of text box*/ run;

/*Open chart data*/ data _null_; file xlsys; put %unquote(%bquote('[app.activate("&fname")]')); put '[run("macro1!r1c1")]'; put '[send.keys("{tab}",true)]'; /*One more TAB and the cursor will be on the chart*/ put '[send.keys("^+{F10}",true)]'; /*CTRL=^ plus SHIFT=+ plus F10 is right click*/ put '[send.keys("{E}",true)]'; /*The letter "E" selects the option in the list "Edit"*/ run;

/*Store statewide prevalence rate for indicator &i in a macro variable*/ proc sql; select pct into: statepct&i from sasoutput where countylabel="California" and indicator="%scan(&indicators,&i,'#')"; quit;

/*Delete "county" from labels, create a variable containing the statewide prevalence rate, calculate the difference between the county prevalence rate and upper and lower CL for error bars*/ data %scan(&indicators,&i,'#'); set sasoutput; where countylabel ne 'California' and indicator="%scan(&indicators,&i,'#')"; countylabel=tranwrd(countylabel,"County",""); statepct="&&statepct&i"; plus = input(up,4.2) - input(pct,4.2); minus= input(pct,4.2) - input(low,4.2); run;

/*Sort so the county with the best rate is on the left Descending for protective factors and ascending for risk factors*/ proc sort data = %scan(&indicators,&i,'#'); by %if %scan(&factors,&i,'#')=protective %then %do; descending %end; pct; run;

/*Slow SAS down to give PPT time to process data*/ data _null_; x=sleep(2,1); run;

/*Send data to the PowerPoint chart in Excel using DDE*/ filename senddata dde "excel|Sheet1!r2c1:r21c5" notab; data _null_; set %scan(&indicators,&i,'#'); file senddata; put countylabel '09'x statepct '09'x pct '09'x plus '09'x minus '09'x; run;

/*Slow SAS down to give PPT time to process data*/ data _null_; x=sleep(2,1); run;

/*Close the chart data in Excel*/ data _null_; file xlsys; put '[file.close(false)]'; run;

Page 19: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

19

/*Insert and re-position the statewide prevalence rate for indicator &i*/ data _null_; file xlsys; put %unquote(%bquote('[app.activate("&fname")]')); put '[run("macro1!r1c1")]'; put '[send.keys("{tab 2}",true)]'; /*Two TABS and cursor will be on text box for "California"*/ put '[send.keys("{enter}",true)]'; /*ENTER places cursor inside text box ready to type*/ put '[send.keys("{end}",true)]'; /*END moves cursor to end of "California"*/ put '[send.keys("{enter}",true)]'; /*ENTER moves cursor to next line*/ put %unquote(%bquote('[send.keys("&&statepct&i",true)]')); /*Type state prevalence rate*/ put '[send.keys("{esc}",true)]'; /*ESC moves cursor out of text box*/ put '[send.keys("+{tab}",true)]'; /*SHIFT=+ plus TAB moves back, cursor grouped state%+arrow'*/

/*If protective factor, move state box to right 40 times*/ %if %scan(&factors,&i,'#')=protective %then %do m=1 %to 40; put '[send.keys("{right}",true)]'; %end;

/*If risk factor, move state box to left 40 times*/ %if %scan(&factors,&i,'#')=risk %then %do m=1 %to 40; put '[send.keys("{left}",true)]'; %end;

/*Reposition the text box so that the state rate is above the red line*/ statepct=round(&&statepct&i,1); if statepct lt 50 then move=floor(abs((50-statepct)/2)); if statepct gt 50 then move=floor(abs((50-statepct)/1.8)); if statepct lt 50 then do m = 1 to move; put '[send.keys("{down}",true)]'; end; if statepct gt 50 then do m = 1 to move; put '[send.keys("{up}",true)]'; end; run;

/*Insert text into the text box containing the axis title for indicator &i*/ data _null_; file xlsys; put %unquote(%bquote('[app.activate("&fname")]')); put '[run("macro1!r1c1")]'; put '[send.keys("{tab 3}",true)]'; /*3 TABS places the cursor on the axis title*/ put '[send.keys("{enter}",true)]'; /*ENTER places cursor inside text box ready to type*/ put %unquote(%bquote('[send.keys("%scan(%superq(axistitles),&i,'#')",true)]')); /*Type title*/ put '[send.keys("{esc}",true)]'; /*ESC moves cursor out of text*/ put '[send.keys("{esc}",true)]'; /*ESC moves cursor back to slide selection*/ put '[send.keys("{down}",true)]'; /*DOWN selects next slide, which is the template*/ run; /*Ready to start from beginning, for next indicator*/

%end; /*Find and replace data year and sample size*/ data _null_; file xlsys; put %unquote(%bquote('[app.activate("&fname")]')); put '[run("macro1!r1c1")]'; put '[send.keys("^{h}",true)]'; /*CTRL=^ plus H opens find and replace*/ put '[send.keys("(#N)",true)]'; /*Enters #N into the field for "Find"*/ put '[send.keys("{tab}",true)]'; /*TAB to the field for "Replace"*/ put %unquote(%bquote('[send.keys("&sampsize",true)]')); /*Type the sample size*/ data _null_; file xlsys; put '[run("macro1!r1c1")]'; put '[send.keys("+{tab 2}",true)]'; /*SHIFT=^ plus 2 TABS places cursor on "Replace All"*/ put '[send.keys("{enter 2}",true)]'; /*Hit ENTER to "Replace All" and again to close dialog box*/ put '[send.keys("(#YEAR)",true)]'; /*Cursor is now on the field for "Find" again, type #YEAR*/ put '[send.keys("{tab}",true)]'; /*TAB to the field for "Replace"*/ put %unquote(%bquote('[send.keys("&year",true)]')); /*Type the data year*/ run; data _null_; file xlsys; put '[run("macro1!r1c1")]'; put '[send.keys("+{tab 2}",true)]'; /*SHIFT=^ plus 2 TABS places cursor on "Replace All"*/ put '[send.keys("{enter 2}",true)]'; /*Hit ENTER to "Replace All" and again to close dialog box*/ put '[send.keys("{esc}",true)]'; /*ESC moves cursor out of find and replace*/ run; %mend mihacharts;

Page 20: Using SAS® to Create Custom Tables and Presentations in … · 2013. 12. 5. · Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange

Using SAS® to Create Custom Tables and Presentations in Microsoft® Office through Dynamic Data Exchange (DDE), continued

20

CONCLUSION

DDE provides SAS programmers a powerful tool for transferring data to Microsoft Office. The goal of this paper was to give readers a foundation for using DDE by reviewing basic examples, and at the same time, demonstrate how these tools have been combined and used to create a number of design-rich products. Hopefully, these examples will help others use DDE to meet their dissemination needs.

REFERENCES

Koval, Scott. 2013. “Can You Create Another PowerPoint for Me? How to Use Base SAS® and DDE to Automate Snappy PowerPoint Presentations.” Proceedings of the SAS Global 2013 Conference. San Francisco, CA. Available at: http://support.sas.com/resources/papers/proceedings13/042-2013.pdf

Vyverman, Koen. 2005. A Matter of Presentation: Generating PowerPoint Slides from Base® SAS using Dynamic Data Exchange.” Proceedings of the 30th Annual SAS Users Group International Conference. Philadelphia, PA.. Available at: http://www2.sas.com/proceedings/sugi30/045-30.pdf

Vyverman, K. 2002. “Creating Custom Excel Workbooks from Base SAS® with Dynamic Data Exchange: A Complete Walkthrough”. Proceedings of the 27th Annual SAS Users Group International Conference. Orlando, FL. Avaialble at: http://www2.sas.com/proceedings/sugi27/p190-27.pdf

CONTACT INFORMATION

Your comments and questions are valued and encouraged. Contact the author at:

Kathryn Fingar Maternal, Child and Adolescent Health Program California Department of Public Health (916) 650-0333 [email protected]

SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of SAS Institute Inc. in the USA and other countries. ® indicates USA registration.

Other brand and product names are trademarks of their respective companies.