I am trying to make my z-axis to have uniform scale (0 to 100) irrespective of the data range.
In the graph attached, I have two factors and one response on surface plot. The code I have below adjust the z-axis (response) based on the response data range (see the figures below).
I am thinking that I need a statement either in the proc template code or g3grid to impose the z-axis range but I am finding it difficult to know what to do.
I will aprreciate any hint, help or assistance.
Thanks
This is my code
proc template;
define statgraph surfaceplotparm;
begingraph;
entrytitle "Surface Plot of Final moisture content";
layout overlay3d /* cube=false*/;
surfaceplotparm x=Temp y=Duration z=Discolor/
reversecolormodel=true
/*surfacetype=fill*/
surfacecolorgradient=Discolor
name= 'surface'
colormodel=threecolorramp;
continuouslegend 'surface'/ title='Discoloration (%)';
endlayout;
endgraph;
end;
run;
proc g3grid data=Fungpred out=gridded;
by Variety MC;
grid Temp*Duration= Discolor ;
run;
proc sgrender data= gridded template=surfaceplotparm ;
by Variety MC;
run;
Your axis control information would go as options to the Layout Overlay3d statement.
Something like
Layout overlay3d/ zaxis=(tickvaluelist=(0 to 100 by 10));
Hi Thank you for your response.
I tried the approach you advise and I made some modifications because I was getting errors.
I finally arrived at the code below with no error but apparently there was no effect on my z-axis.
layout overlay3d/ zaxisopts = (linearopts=(tickvaluesequence=(start=0 end=100 increment=10) TICKVALUELIST=(0 10 20 30 40 50 60 70 80 90 100)));
I am using sas studio online
Thanks
To do this, you will want to create a little data step to normallize your Z data into the 0 to 100 range before feeding it to proc g3grid. Then, the plot sould come out as you would expect. in addition, you can also use the TICKVALUELIST option to set the tick values to show (as described by ballardw).
Hope this helps!
Dan
Thank you so much!
I will like to implement your advise but will you be willing to provide more detail on how I can proceed?
Here is a simple example that normalizes the WEIGHT column in the class data set to a 0-100 range:
%let min=50.5;
%let max=150;
data normalize;
set sashelp.class;
norm = ((weight-&min)/(&max-&min))*100;
run;
proc print data=normalize; run;
Hi
Thank you so much for your help. So I used proc means to identify the minimum and maximum data in my data set. I fed that information into the macro. I used the example code that you gave me to normalized the data. Hence, my grid is "grid Temp*Duration= norm". the surface plot disaapeared and I have something like grid line plot (see attached). are mine doing something wrong?
Proc means data = demos min max;
variable Discolor;
run;
%let min=3.26;
%let max=99.19;
data normalize;
set Fungpred;
norm = ((Discolor-&min)/(&max-&min))*100;
run;
proc print data = normalize;
run;
proc g3grid data=normalize out=gridded;
by Variety MC;
grid Temp*Duration= norm ;
run;
proc sgrender data= gridded template=surfaceplotparm ;
by Variety MC;
run;
DId you change your graph template to use "norm" as your Z variable? BTW, on the normalize data step, you might want to set the label of the norm variable to be the original variable name, something like:
label norm="Discolor";
Let us know the variable change fixes your problem.
Thanks!
Dan
Hi
I notices that I didn't use "norm" as my z-axis in the graph template: so I made the adjustment.
However, the graph just went back to the inital condition (the axis vary) see attached. I also added the label statement as you advised
Can you post all of your current code again. That will make it easier to spot any issue.
Thanks!
Dan
This is my complete code
proc template;
define statgraph surfaceplotparm;
begingraph;
entrytitle "Surface Plot of Final moisture content";
layout overlay3d/ zaxisopts = (linearopts=(tickvaluesequence=(start=0 end=100 increment=10) TICKVALUELIST=(0 10 20 30 40 50 60 70 80 90 100)));
surfaceplotparm x=Temp y=Duration z=norm/
reversecolormodel=true
/*surfacetype=fill*/
surfacecolorgradient=norm
name= 'surface'
colormodel = threecolorramp;
continuouslegend 'surface'/ title='Discoloration (%)';
endlayout;
endgraph;
end;
run;
proc sort data = dems out=Fungpred nodupkey;
by Variety MC Temp Duration;
run;
proc means data = dems min max;
variable Discolor;
run;
%let min=3.26;
%let max=99.19;
data normalize;
set Fungpred;
norm = ((Discolor-&min)/(&max-&min))*100;
label norm="Discolor";
run;
proc g3grid data=normalize out=gridded ;
by Variety MC;
grid Temp*Duration= norm;
run;
proc sgrender data= gridded template=surfaceplotparm ;
by Variety MC;
run;
Ah, I see the issue. The data step I gave normalizes the Z column across the entire data set, using the min and max of the whole data. However, you are generating plots using BY-groups, where the min and max is different per BY-group combination. To fix this, you would have to modify the data step to take the min and max for each BY-group and normalize the data within each BY group instead of across the whole data. The code below should do it for you.
proc template;
define statgraph surfaceplotparm;
begingraph;
entrytitle "Surface Plot of Final moisture content";
layout overlay3d/ zaxisopts = (linearopts=(tickvaluesequence=(start=0 end=100 increment=10) TICKVALUELIST=(0 10 20 30 40 50 60 70 80 90 100)));
surfaceplotparm x=Temp y=Duration z=norm/
reversecolormodel=true
/*surfacetype=fill*/
surfacecolorgradient=norm
name= 'surface'
colormodel = threecolorramp;
continuouslegend 'surface'/ title='Discoloration (%)';
endlayout;
endgraph;
end;
run;
proc sort data = dems out=Fungpred nodupkey;
by Variety MC Temp Duration;
run;
proc means data = Fungpred;
by Variety MC;
var Discolor;
output out=minmax min=min max=max;
run;
data merged;
merge Fungpred minmax;
by Variety MC;
run;
data normalize;
set merged;
norm = ((Discolor-min)/(max-min))*100;
label norm="Discolor";
run;
proc g3grid data=normalize out=gridded ;
by Variety MC;
grid Temp*Duration= norm;
run;
proc sgrender data= gridded template=surfaceplotparm ;
by Variety MC;
run;
DanH_sas,
You are awesome!!
I appreciate your help and the time you dedicated at looking through my code.
However, if I normalized the data by group what will happen is that the data set with lower data range will get bumped- up by normalization. If you see the first graph produced from the code that you sent to me (see attached). The range was between 5.8 and 25% but the plot has up to 100%. The visual comparison that the surface plot suppose to give as a result of factors are therfore lost.
In that case, you might just just want to normalize the column across the entire data set like we did before, but use the VIEWMIN and VIEWMAX options in the LINEAROPTS of the ZAXISOPTS to force the axis to a 0 to 100 range.
Thanks!
Dan
DanH_sas,
Thank you so much for your help.
I implemented your suggestion and I found out that VIEWMIN and VIEWMAX options are not in lLINEAROPTS of the ZAXISOPTS.
I also found out that g3grid z-axis cannot be modified with current sas and maybe there might be future release to address that issue but at moment there is n solution. However, to work round this, one need to create another data set that will have the desired maximum axis value. I did this and I still have no head way. Let me know if you hav any suggestion
proc template;
define statgraph surfaceplotparm;
begingraph;
entrytitle "Surface Plot of Final moisture content";
layout overlay3d/ zaxisopts = ( griddisplay = on ) cube = false ;
surfaceplotparm x=Temp y=Duration z=Discolor/
reversecolormodel=true
surfacecolorgradient=Discolor
name= 'surface'
colormodel = threecolorramp;
continuouslegend 'surface'/ title='Discoloration (%)';
surfaceplotparm x=Temp y=Duration z=z2 / DATATRANSPARENCY = 1 ;
endlayout;
endgraph;
end;
run;
data notreal;
set sorayass ;
z2 = 100 ;
run ;
proc sort data = notreal out=Fungpred nodupkey;
by Variety MC Temp Duration;
run;
proc g3grid data=Fungpred out=gridded ;
by Variety MC;
grid Temp*Duration= Discolor;
run;
proc sgrender data= gridded template=surfaceplotparm ;
by Variety MC;
run;
Thanks
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.
Ready to level-up your skills? Choose your own adventure.