BookmarkSubscribeRSS Feed
JeffMeyers
Barite | Level 11

I was hoping to be able to apply a user created function as a format to the x or y axis in SGPLOT but was met with a warning: WARN: format () could not be instantiated.

JeffMeyers_1-1671119173803.png

 

The code I was using was trying to map the tick values of the x-axis to be their squared values.  I'm looking into this as a way to potentially show square root transformed data on a numeric axis with non-linear intervals (similar to a log axis).  This is the code I was trying:

proc fcmp outlib=work.functions.smd;
   function sqr(num);
      sq=num**2;
      return(sq);
   endsub;
run;

options cmplib=(work.functions);
proc format;
    value test
        other=[sqr()];run;
    run;

proc sgplot data=sashelp.class;
    scatter x=height y=weight;
xaxis tickvalueformat=test.; run;

My goal would be to have the axis look like this without the manual selection of values for the format:

proc format;
    value test2v
        50='2500'
        55='3025'
        60='3600'
        65='4225'
        70='4900';
    run;
    
proc sgplot data=sashelp.class;
    scatter x=height y=weight;
xaxis tickvalueformat=test2v.; run;

JeffMeyers_0-1671118992431.png

 

Is it possible to make this work? 

4 REPLIES 4
PeterClemmensen
Tourmaline | Level 20

Good question. I suspect the answer is No.

 

The Doc lists the following restriction to the Valuesformat Option: This option currently honors most, but not every, SAS format. For more information, see Format Support in ODS Graphics in SAS Graph Template Language: Reference.

 

Browsing the link, I suspect that user defined formats, that are based on FCMP logic should be added to User-Defined Formats That Are Not Supported.

ballardw
Super User

I suspect that even if that format were acceptable that you might not be happy with the results. An experiment you might try would be to create an additional variable that is the square of the current x axis variable and plot using that.

 

With the ranges you show from that manual format I would expect that the axis labels that would come from the typical logic for numeric variables to be rounded at the multiples of 1000 or possibly 500. It would be very unlikely to select a multiple of 25 like 4225 when the range of values exceeds 2000 .

 

If the "problem" is not wanting to write a lot of Proc format code then you could use a data step to create a CNTLIN data set to make the values.

data makefmt;
   fmtname='Test';
   type='N';
   do start=50 to 70 by 5;
      label= start**2;
      output;
   end;
run;
proc format cntlin=makefmt;
run;

proc sgplot data=sashelp.class;
    scatter x=height y=weight;    
    xaxis  tickvalueformat=test.;
run;

Actually a quick test, with this data, and the Start= loop going from 0 to 300 resulted in the same graph as with the values as shown.

 

If your actual data has a large enough range of values you may have to indicate the Values= option to provide a list for the Xaxis statement that corresponds to the desired tick marks. Luckily the values=(50 to 70 by 5) is valid so is relatively easy to control

JeffMeyers
Barite | Level 11

The goal in the end is to make something automated within a macro where the axis intervals are not linear like this square root transformation or log transformation.  I am hoping to have a variable that has the transformation (e.g. x2=sqrt(x) and then plot x2) but then format the axis so that the original scale is shown.  The macro I am writing will cover a wide variety of lab types so the ranges are quite different and are quite difficult to make manual formats for especially with outliers blowing up the axis range.  If I could just take whatever value SAS picked for tick values and apply a transformation to them somehow it would work, but I don't think it's possible without applying a format/function.

ballardw
Super User

Unless your transformations aren't one-to-one then a CNTLIN data set such as shown should be possible to construct with your transform. If you don't want the intervals with equal spacing then the VALUES statement would be must unless you use an axis with Log  options or interval=time-interval.

 

If you are expecting to use moderately obnoxious results, such as from some complex regression then perhaps using Proc Score would generate the Label values for provided x values and then just add the format name and type for use as Cntlin data set to proc format.

 

The rules for selecting tick mark values involve elements such as range of values, graph display size (fewer ticks int a 3 inch wide graph than 8 inch for example), options related to font sizes (force a font size for the xaxis that is huge and see how many ticks you get), options for the axis like types and values. Instead of trying to "guess" what SAS might pick I would suggest that it is better to set your own. That may involve summarizing some data to determine range, divide the range of values into a likely number of intervals and create the values that way. I call that routine and tedious programming. I have done that in ancient days to break up graphs that had relatively extreme values of Y variables that resulted in a "spike" and the remaining graph nearly flat so that i could have usable Y variance to see what was going on by adding a "by" value to the data to create multiple graphs with smaller ranges of Y values.

 

 

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

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
  • 4 replies
  • 493 views
  • 2 likes
  • 3 in conversation