BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
vinny68
Calcite | Level 5

Good day all.  I am stuck on a problem that I cannot seem to resolve.  I am attempting to develop individual student data sheets, that will be shared to those students showing where they stand on various tests and objectives at the institution.  I have all the necessary data and through a series of proc prints, I am able to traffic light the student areas.  The problem I am encountering is that I need to build individual graphs for each of these areas, which contain the students individual score and the group average/median.  I have all the data but I cannot figure how to get SAS to generate this simple line graph.  I should mention that since I am dealing with 250+ students, I have all the procedures within a macro to create the 250+ resulting pdfs.  I used proc timeplot but the faculty did not like the look of the graphic and wanted something "prettier".  I have tried Proc GKPI but I am unable to get the macro I am using in the where clause of the other procs to run individual Proc GKPI.

 

If anyone has any thoughts or suggestions I am certainly open to hear them.

 

Thank you for your time and consideration.

1 ACCEPTED SOLUTION

Accepted Solutions
ballardw
Super User

You mention that you want some sort of line plot but I don't see a very clear definition of what the plot should look like for your example code:

 

proc timeplot data=enroll_comb_new;
   plot Calculations_first_attempt=full_name/ 
      ref=87.49 refchar='*' joinref axis=1 to 100 by 2;
   where full_name ="&&E&I";

proc timeplot data=enroll_comb_new;
   plot Law_grade_weight=full_name/ 
      ref=3.30 refchar='*' joinref axis=1 to 4 by .05;
   where full_name ="&&E&I";

proc timeplot data=enroll_comb_new;
   plot Overall_SS=full_name/ 
      ref=340.41 refchar='*' joinref axis=1 to 700 by 14;
   where full_name ="&&E&I";

 

Can you provide some dummy data for maybe two students that we can plot with the above code? Supply the data in the form of data step code .

 

The main reason timeplot exists is for the days of character graphics and was the procedure that could use fanfold or roll paper to create either longer graphs than would fit across pages using such as Proc Plot or to show the data label with the row. Did you use timeplot because you wanted bigger plots than were fitting on page?

 

I don't see why proc sgplot can't create something.

 

View solution in original post

7 REPLIES 7
Reeza
Super User

Have you looked at SGPLOT? It's much better quality graphics. Beyond that, it's hard to understand what your question is here.

 


@vinny68 wrote:

Good day all.  I am stuck on a problem that I cannot seem to resolve.  I am attempting to develop individual student data sheets, that will be shared to those students showing where they stand on various tests and objectives at the institution.  I have all the necessary data and through a series of proc prints, I am able to traffic light the student areas.  The problem I am encountering is that I need to build individual graphs for each of these areas, which contain the students individual score and the group average/median.  I have all the data but I cannot figure how to get SAS to generate this simple line graph.  I should mention that since I am dealing with 250+ students, I have all the procedures within a macro to create the 250+ resulting pdfs.  I used proc timeplot but the faculty did not like the look of the graphic and wanted something "prettier".  I have tried Proc GKPI but I am unable to get the macro I am using in the where clause of the other procs to run individual Proc GKPI.

 

If anyone has any thoughts or suggestions I am certainly open to hear them.

 

Thank you for your time and consideration.


 

vinny68
Calcite | Level 5

Reeza,

 

Yes I have been playing around some with SGPLOT as well.  The main problem I have is in my program, I have a macro that contains each students name, in the various procs I use that macro in the where command, so I only grab that particular students data.  At the same time the macro is running creating an individual pdf for each student.  So when I go to make a graph, there is essentially two values, the students individual score and the class average which is repeated for each of the students, in other words a dummy column that contains the average.  This works great for creating the individualized pdfs with individual data but the graphs simply will not work because it is not a line but rather a singular dot with the average on one axis and the student score on the other.  Ideally, I would like a horizontal slider, showing the min and max, with a mark for the average and then another mark for the student indiviudal score, that way the faculty could see at a glance is the student over, under or within bounds.

 

Does that help?

Reeza
Super User

This is a design problem then. The only part that needs the macro is the part to create the reports. However, using a WHERE to dynamically filter is better than creating subsets. 

 

 

I would recommend the following:

 

1. Calculate the data points needed for individual values, store these as macro variables. 

2. Use an SGPLOT which references the main data set instead of your subset and then you can add in the points/refline using a REFLINE or TEXT or MARKERCHAR within SGPLOT to add the points relative to the student with the macro variables created from #1. 

 

 

ods html file = "/folders/myfolders/MileageReport_Toyota.html" 
         gpath= '/folders/myfolders/' 
         style = meadow;

ods graphics / imagemap=on ;
title 'Report on Mileage for Toyota';
title2 'Summary Statistics';
proc means data=sashelp.cars (where=(make='Toyota')) N Mean Median P5 P95 MAXDEC=2;
class type;
ways 0 1;
var mpg_city mpg_highway;
run;


proc sql noprint;
create table summary as
select make, mean(mpg_city) format=8.1 as mpg1, mean(mpg_highway) as mpg2 format=8.1 from sashelp.cars
where make = "Toyota";
quit;


data cars / view=cars;
set sashelp.cars summary;;
run;

title 'City vs Highway Mileage';
proc sgplot data=cars (where=(make='Toyota'));
scatter x=mpg_city y=mpg_highway / group = type;
text x=mpg1 y=mpg2 text=make; ;
run;

proc sql;
drop view cars;
quit;

ods html close;

 

https://github.com/statgeek/SAS-Tutorials/blob/master/Turning%20a%20program%20into%20a%20macro.md

 

I modified the code from the link above. 

 


@vinny68 wrote:

Reeza,

 

Yes I have been playing around some with SGPLOT as well.  The main problem I have is in my program, I have a macro that contains each students name, in the various procs I use that macro in the where command, so I only grab that particular students data.  At the same time the macro is running creating an individual pdf for each student.  So when I go to make a graph, there is essentially two values, the students individual score and the class average which is repeated for each of the students, in other words a dummy column that contains the average.  This works great for creating the individualized pdfs with individual data but the graphs simply will not work because it is not a line but rather a singular dot with the average on one axis and the student score on the other.  Ideally, I would like a horizontal slider, showing the min and max, with a mark for the average and then another mark for the student indiviudal score, that way the faculty could see at a glance is the student over, under or within bounds.

 

Does that help?


 

vinny68
Calcite | Level 5

Reeza,

 

Thank you for the link.  Looks like I may have to re-think how I am processing the output file.  

 

Thank again.

GraphGuy
Meteorite | Level 14

I'm not sure exactly how you've got your code structured, but I would recommend creating a dataset of all the student id's, and then looping through them (with a data step), and using 'call execute' to call a macro for each student. In the macro, subset the data to just the desired student, and then generate the reports/graphs for that student.

 

Here is some SAS code that does that sort of thing (but using student name rather than some unique id number, since this particular sample dataset only has names ... but you get the idea)...

 

%macro do_report(student);

data foo; set sashelp.class (where=(name="&student"));
run;

title "Data for student &student";
proc print data=foo;
run;

/* could also do graphs, etc, for the selected student */

%mend;


proc sql noprint;
create table loopdata as
select unique name from sashelp.class;
quit; run;

data _null_; set loopdata;
call execute('%do_report('|| name ||');');
run;

vinny68
Calcite | Level 5

Robert,

 

Thank you for the suggestion but I think that is essentially what I am already doing, without the call execute.  I am not much of a macro guy, most of my time is doing statistical analysis and they are one shot programs.  I did put a similar code into production that compiled data by course for a given semester but even selecting one course left me with more than one data point in each of the pulls.  The loops work great for creating the data output, but the graphs are simply not what, all I am trying to do is generate a pretty version of proc timeplot such as this:

 

 

 

                     Individual        min                                                        max                   
                   Pharmacy Law        1                                                            4                   
                   Grade Weight       *-------------------------------------------------------------*                   
                           3.70       |                                              *-------A      |                   
                                      *-------------------------------------------------------------*                   

 

 

 Here is my current code, I apologize for the lack of comments but I have always worked alone and never had a need.

 

/*Macro Code for doing loops through procedures*/

PROC SQL;
create table num_courses as
select distinct full_name
from enroll_comb_new;
QUIT;

DATA _null_; set num_courses end=last;
if last then call symput("numids",compress(put(_n_,12.)));
RUN;
%PUT &numcrs;

PROC SQL noprint;
select distinct full_name
into :E1 - :E&numids
from num_courses;
QUIT;


/*(goptions reset=all device=javaimg xpixels=130 ypixels=250;*/
%MACRO OUTDATA;
%DO I=1 %TO 2/*&numids*/;
%let pds=%STR(G:\APPE_PRE_Dashboard\Dashboard_prototypes\);
ods pdf file="&pds.&&E&I.._Pre_APPE_Dashboard.pdf" startpage=no;
options nobyline;
title'Pre-APPE Worksheet for P3 Students';

proc sort data=enroll_comb_new;by full_name;

proc print data=enroll_comb_new noobs label STYLE(Header)={just=c};
label full_name='Student Name';label id_num = 'Student Id';label class_cde = 'Student Class Level';
var /*full_name id_num*/ class_cde/ style(data)={just=c};
where full_name ="&&E&I";

proc print data=enroll_comb_new noobs label STYLE(Header)={just=c};
var calc_traffic law_traffic pcoa_traffic / style={background=sigb. width=200 just=center} ;
where full_name ="&&E&I";
ods text='1 denotes within one standard error, 2 is within two standard errors, 3 is three or more standard errors';

proc print data=enroll_comb_new noobs label STYLE(Header)={just=c};
var Calculations_first_attempt / style={background=calc. width=150 just=center};
var Calc_avg/style(header)=[just=center color=black fontsize=8PT] style(column)={width=150};
where full_name ="&&E&I";
/*ods text='Summary of Student work on Pharmacy Calculations';*/

/*
proc sgplot data=enroll_comb_new (where=(full_name="&&E&I."));
band x=Calculations_first_attempt upper=86 lower=1;
series x=Calculations_first_attempt y=calc_avg;
*/

proc timeplot data=enroll_comb_new;
plot Calculations_first_attempt=full_name/ ref=87.49 refchar='*' joinref axis=1 to 100 by 2;
where full_name ="&&E&I";

proc print data=enroll_comb_new noobs label STYLE(Header)={just=c};
var pharmacy_law_grade / style={background=$law. width=200 just=center};
var Law_median_grade /style(header)=[just=center color=black fontsize=8PT] style(column)={width=150};
where full_name ="&&E&I";
/*ods text='Summary of Student work in Pharmacy Law';*/

proc timeplot data=enroll_comb_new;
plot Law_grade_weight=full_name/ ref=3.30 refchar='*' joinref axis=1 to 4 by .05;
where full_name ="&&E&I";

proc print data=enroll_comb_new noobs label STYLE(Header)={just=c};
var Overall_SS/ style={background=pcoa. width=200 just=center};
var Overall_SS_mean Overall__ile Overall__ile_median/ style(header)=[just=center color=black fontsize=8PT] style(column)={width=150};
where full_name ="&&E&I";
/*ods text='Summary of Student work on the PCOA Overall';*/

proc timeplot data=enroll_comb_new;
plot Overall_SS=full_name/ ref=340.41 refchar='*' joinref axis=1 to 700 by 14;
where full_name ="&&E&I";

proc print data=enroll_comb_new noobs label STYLE(Header)={just=c};
var Area_1_SS Area_1_SS_mean Area_1__ile Area_1__ile_median/ style(header)=[just=center color=black fontsize=8PT] style(column)={width=200};
where full_name ="&&E&I";
/*ods text='Summary of Student work on the PCOA Area 1';*/

proc print data=enroll_comb_new noobs label STYLE(Header)={just=c};
var Area_2_SS Area_2_SS_mean Area_2__ile Area_2__ile_median/ style(header)=[just=center color=black fontsize=8PT] style(column)={width=200};
where full_name ="&&E&I";
/*ods text='Summary of Student work on the PCOA Area 2';*/

proc print data=enroll_comb_new noobs label STYLE(Header)={just=c};
var Area_3_SS Area_3_SS_mean Area_3__ile Area_3__ile_median/ style(header)=[just=center color=black fontsize=8PT] style(column)={width=200};
where full_name ="&&E&I";
/*ods text='Summary of Student work on the PCOA Area 3';*/


run;

ods pdf close;
run;
%END;
%MEND;
%OUTDATA;


run;

 

Thank you for the assistance,

George

 

 

ballardw
Super User

You mention that you want some sort of line plot but I don't see a very clear definition of what the plot should look like for your example code:

 

proc timeplot data=enroll_comb_new;
   plot Calculations_first_attempt=full_name/ 
      ref=87.49 refchar='*' joinref axis=1 to 100 by 2;
   where full_name ="&&E&I";

proc timeplot data=enroll_comb_new;
   plot Law_grade_weight=full_name/ 
      ref=3.30 refchar='*' joinref axis=1 to 4 by .05;
   where full_name ="&&E&I";

proc timeplot data=enroll_comb_new;
   plot Overall_SS=full_name/ 
      ref=340.41 refchar='*' joinref axis=1 to 700 by 14;
   where full_name ="&&E&I";

 

Can you provide some dummy data for maybe two students that we can plot with the above code? Supply the data in the form of data step code .

 

The main reason timeplot exists is for the days of character graphics and was the procedure that could use fanfold or roll paper to create either longer graphs than would fit across pages using such as Proc Plot or to show the data label with the row. Did you use timeplot because you wanted bigger plots than were fitting on page?

 

I don't see why proc sgplot can't create something.

 

SAS Innovate 2025: Call for Content

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 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 7 replies
  • 1285 views
  • 0 likes
  • 4 in conversation