The first task that we are going to focus on during Custom Task Tuesday is a task on macro proc execution, which is probably the most editable and customizable of all of the tasks we will discuss.
The Macro Proc Execution allows you to select a dataset and select any number of procs from a list to run on the chosen dataset.
Here is how this task's finished product will look:
In my implementation, each of these procs is enclosed in a macro that is executed conditionally on whether or not the checkbox is checked. My macros contain only one proc for the purposes of this blog post, but this concept becomes even more powerful when you think about the idea of executing your own macros that you may already have on any dataset with the click of a checkbox.
In SAS Studio, under the Task and Utilities section, open a “New Task” as well as the “Sample Task.” We will copy and paste the necessary Velocity Template code from the Sample Task to our task.
Name: Macro Proc Execution
Description: This task allows you to specify a dataset as well as any number of procs from a list to run on the dataset. The list of procs include: proc print, proc freq, proc means, and proc corr. These procs will run with their default setting and therefore should be appropriate for any dataset that the user may choose.
At the top of the VTL code for your New Task, you will need to fill in the Name and Description portions as shown below:
After you’ve done that, you should save this task to your My Tasks folder, so you don’t lose it. Click the button in the upper left corner of the task to bring up this option screen:
To make things easier on ourselves, we are going to steal VTL code from the Sample Task. From our “finished product,” you can see that our task is going to include one dataset selector as well as a group of checkboxes, which will have 4 checkboxes. Find the several lines of code in the Sample Task that correspond with a dataset selector and checkboxes in the Metadata section, and copy and paste them into the same place in your newly created Macro Proc Execution task. Edit the code you copied (change the labels) to correspond with what we want as our finished product.
This is what your finished Metadata portion should look like:
<Metadata>
<DataSources>
<DataSource name="DATASOURCE">
</DataSource>
</DataSources>
<Options>
<Option inputType="string" name="DATATAB">DATA</Option>
<Option inputType="string" name="DATAGROUP">DATA</Option>
<Option inputType="string" name="GROUPCHECK">ANALYSIS</Option>
<Option inputType="string" name="labelCHECK">Select the types of output you would like for your dataset. Choose at least one.</Option>
<Option defaultValue="0" inputType="checkbox" name="chkFREQ">Frequency Analysis</Option>
<Option defaultValue="0" inputType="checkbox" name="chkMEANS">Statistical Summary</Option>
<Option defaultValue="0" inputType="checkbox" name="chkPRINT">Data Print Out</Option>
<Option defaultValue="0" inputType="checkbox" name="chkCORR">Correlation Matrix</Option>
</Options>
</Metadata>
Each object that we just put code for in the metadata portion will have corresponding code in the UI section. The code for the UI portion is what determines the order items are displayed in the finished task.
Just like we did in the previous step, find the lines of code that correspond with the dataset selector and checkbox group in the UI section of the Sample Task, and copy and paste them into the same place in your task. Edit the code you copied (make sure your names in the Metadata section match the option= lines in the UI section) to correspond with what we want as our finished product.
This is what your finished UI portion should look like:
<UI>
<Container option="DATATAB">
<Group open="true" option="DATAGROUP">
<DataItem data="DATASOURCE"/>
</Group>
<Group open="true" option="GROUPCHECK">
<OptionItem option="labelCHECK"/>
<OptionItem option="chkPRINT"/>
<OptionItem option="chkFREQ"/>
<OptionItem option="chkMEANS"/>
<OptionItem option="chkCORR"/>
</Group>
</Container>
</UI>
This is the portion of the task that contains your SAS Code. Velocity Template Language has its own macro variables, and each of our UI elements has one. This is how you make sure that your code works with what the user selects in the interface you created. When you select an option in the UI, the value of the VTL macro variable will change immediately. As you'll see below, VTL macro variables are denoted by a dollar sign, such as $DATASOURCE.
Since the code for this task is quite short, the full SAS code is below:
%macro analysis;
*Value for print checkbox: 1 if checked, 0 if unchecked.;
%if $chkPRINT = 1 %then %do;
proc print data = $DATASOURCE;
run;
%end;
*Value for freq checkbox: 1 if checked, 0 if unchecked.;
%if $chkFREQ = 1 %then %do;
proc freq data = $DATASOURCE;
run;
%end;
*Value for means checkbox: 1 if checked, 0 if unchecked.;
%if $chkMEANS = 1 %then %do;
proc means data = $DATASOURCE;
run;
%end;
*Value for corr checkbox: 1 if checked, 0 if unchecked.;
%if $chkCORR = 1 %then %do;
proc corr data = $DATASOURCE;
run;
%end;
%mend analysis;
%analysis;
You’re finished! You just created a task that will allow a user to select any dataset and run a proc on it from your custom list of procs. Click the button to save, then click the
button to open the task. Make your selections, then click
again to watch it run!
Get the code from the zip file at the end of this article or from GitHub.
Can you think of a way to customize or improve this task? Post it in the comments below!
i don´t m know that is possible in sas
I have a slightly different question regarding custom tasks and macros: Is it possible to %include a custom task in a SAS program? A colleague set up a custom task to get username and password information, and it would be great to just %include this custom task in other pre-existing programs that need to be converted from %windows. I tried:
%include "x:\folderwhereCTMstored\login.ctk";
and it didn't work. However, I'm not sure if it's not possible, or I am using the wrong method.
Thanks!
That is an interesting example of using the check boxes in the GUI part of the SAS/Studio task. But for the code generation it would probably be better to use the code generation features of the SAS/Studio task rather than having to wrap the code into a SAS macro and then calling the macro.
I think that if you do it this way the generated code will be easier to use.
<CodeTemplate>
<![CDATA[
#if ($chkPRINT == "1")
*Value for print checkbox: 1 if checked, 0 if unchecked.;
proc print data = $DATASOURCE;
run;
#end;
#if ($chkFREQ == "1")
*Value for freq checkbox: 1 if checked, 0 if unchecked.;
proc freq data = $DATASOURCE;
run;
#end
#if ($chkMEANS == "1")
*Value for means checkbox: 1 if checked, 0 if unchecked.;
proc means data = $DATASOURCE;
run;
#end
#if ($chkCORR == "1")
*Value for corr checkbox: 1 if checked, 0 if unchecked.;
proc corr data = $DATASOURCE;
run;
#end
]]>
</CodeTemplate>
If you did have a macro that you want to call using the SAS/Studio task then it is probably helpful to link the parameters of the macro to user choices in the task. The macro could be defined in the task or included from some previously defined location. But the references to the SAS/Studio variables could then be limited to just the generation of the macro call.
%macro analysis(dsn,print,freq,means,corr);
...
%if (&print) %then %do;
proc print data=&dsn ;
run;
%end;
...
%mend analysis;
%analysis
(dsn=$DATASOURCE
,print=$chkPRINT
,freq=$chkFREQ
,means=$chkMEANS
,corr=$chkCORR
);
@Michelle Hi Michelle! At this time, it is not possible to include a ctm or ctm file in a SAS program. SAS doesn't know about task files. However, a process flow in SAS Studio might be helpful for your situation. You could have the task run first to fetch the information and set up the macro variables, and then your SAS code would run which would use the macro variables.
You're definitely not using the wrong method, just trying to do something that's not possible. 🙂 Let me know if I can help in any other way!
Olivia
Hi @Tom! You are absolutely right about the fact that this task did not need to be put in a macro, I was really doing it more for an example to show how easy it would be to execute complex macros with the click of a checkbox. The code in your first example would work perfectly and is a much more straight forward approach.
As for your second example, this is an approach I had never thought of before and look forward to using it in the future! I have used %let statements before to set SAS macro variables equal to Velocity macros, but I've never actually passed the values through a macro call. This is really interesting.
Thank you so much for sharing!
Olivia
I have been always thinking to create a custom task. It is possible in SAS Stuido.
By any chance can we use the same in enterprise guide ??
@Hi @cpagrawal - yes, you can create custom tasks in SAS Enterprise Guide! It's a development task, requiring some Microsoft .NET skills. But it can be done with free tools, and we have lots of examples. See the many articles here.
I was not aware that was possible in SAS studio. Thanks for writing this page
@RahulG Of course! Thank you so much for reading! This is just the first task post in a series called Custom Task Tuesday. Check out some of the other articles if you're interested.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning and boost your career prospects.