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

@Rick_SAS

Your video about heat maps in SAS/IML https://youtu.be/GgBOfVcz0vE inspired me to put it into practice.

As your Do Loop blog is my tool box and my first resort when encountering a problem, you'll find many code snippets from the Do Loop rebuilt into this code. 

The motivation for this program is to give my daughter a sense of prices. And although she does well in mathematics it's easier to grap the magnitude visually. 

Therefore I convert the price in Euros into a 0,1 square matrix whose dimensions I determine using the root function froot. 

 

As an optimisation I'd like to scale the ods graphic elements like title and markers according to the dimension of the matrix.

Is there a way I can calculate their optimal size?

 

ODS HTML FILE="C:\USERS\DKXENLO\DESKTOP\OUTOUT\FLIGHTS.HTM" 
NOGTITLE GPATH="C:\USERS\DKXENLO\DESKTOP\OUTOUT\"  ;

ODS GRAPHICS / WIDTH=3000 HEIGHT=3000 IMAGENAME='FLIGHTS' NOBORDER  ;

PROC IML;

PRICE=1709;
PRICE=CEIL(PRICE);

START FUNC (X) GLOBAL (PRICE);
RETURN ( X*(X+1)/2 -PRICE);
FINISH;

SOL=FROOT("FUNC",{0, 100});

MONEY=J(CEIL(SOL), CEIL(SOL),.);

START ROW (M);
RETURN(REPEAT(T(1:NROW(M)),1, NCOL(M)));
FINISH;

START COL (M);
RETURN(REPEAT(1:NROW(M), NROW(M)));
FINISH;

START GETDIAGIDX(A);
   DIAGIDX = DO(1,NROW(A)*NCOL(A), NCOL(A)+1); /* INDEX DIAGONAL ELEMENTS */
   RETURN(DIAGIDX);                             /* RETURN */
FINISH;

R=ROW(MONEY);
C=COL(MONEY);

LOW_TRI= (R >= C);

LOW_IDX=LOC(LOW_TRI ^= 0);

DIAGIDX=GETDIAGIDX(LOW_TRI);

EXCESS=NCOL(LOW_IDX)-PRICE;

EXCESS_ID=(NCOL(DIAGIDX)-EXCESS+1):NCOL(DIAGIDX);

LOW_TRI[DIAGIDX[EXCESS_ID]]=-1;

DIM=DIMENSION(MONEY);

H1=NDX2SUB(DIM,LOC(LOW_TRI=1));

CALL SYMPUTX("PRICE", PRICE);

RAMP={BWH "WHITE" "LIGHTBLUE" };

CALL HEATMAPDISC(LOW_TRI, RAMP) TITLE=CHAR(PRICE)+" EUROS";

CREATE SPEND FROM H1;
APPEND FROM H1;
CLOSE;

SUBMIT;

DATA SPEND;
SET SPEND;
MONEDA="EURO";
RUN;

TITLE " %SYSFUNC(PUTN(&PRICE,EURO9.2)) IS THAT MUCH MONEY VISUALLY";
PROC SGPLOT DATA=SPEND NOBORDER ;
SYMBOLIMAGE NAME=EURO IMAGE='C:\USERS\DKXENLO\DESKTOP\OUTOUT\1EUROA.JPG';
STYLEATTRS DATASYMBOLS=(EURO);
SCATTER X=COL1 Y=COL2 / GROUP=MONEDA MARKERATTRS=(SIZE=22);

XAXIS REVERSE DISPLAY=NONE;
YAXIS DISPLAY=NONE;


RUN;


ENDSUBMIT;

ODS HTML CLOSE;

 

VUELOS31.png  

1 ACCEPTED SOLUTION

Accepted Solutions
Rick_SAS
SAS Super FREQ

Glad you enjoyed the video.

 

This seems like an ODS graphics question rather than an IML question. My understanding is that you want to scale the size of the according to some measure.  You can use the ODS GRAPHICS statement like this:

ODS GRAPHICS / WIDTH=w HEIGHT=h;

where w and h are computed in the program and stored in the macro variable.

 

Another option (and probably what I would do) is to embed all matrices into the largest sized matrix. Then the heat maps will all have the same number of cells and size of cells. For example, the following creates a 4x4 matrix and a 5x5 matrix. To embed the 4x4 matrix into a 5x5 matrix, allocate a 5x5 matrix of all missing values, then use subscripts to assign the 4x4 matrix to certain rows and columns:

 

proc iml;
ods graphics / width=400px height=400px;
x4 = j(4,4,1); x4[do(2,16,2)]=0; /* 4x4 matrix */
x5 = j(5,5,1); x5[do(2,25,2)]=0; /* 5x5 matrix */
call heatmapdisc(x4);
call heatmapdisc(x5);

/* make cells in x4 the same size as the cells in x5 by 
   embedding x4 into a 5x5 matrix that has missing values */
newx4 = j(5,5,.);
newx4[1:4, 1:4] = x4;
call heatmapdisc(newx4);

-----

 

PS. Regarding your program, you don't need to use the FROOT function to solve a quadratic equation. Just use the quadratic formula: 

sol = 0.5*(-1 + sqrt(1 - 4*(-2*PRICE)));

Also, on modern versions of SAS, the ROW and COL functions are built-in functions that you do not need to define.

View solution in original post

1 REPLY 1
Rick_SAS
SAS Super FREQ

Glad you enjoyed the video.

 

This seems like an ODS graphics question rather than an IML question. My understanding is that you want to scale the size of the according to some measure.  You can use the ODS GRAPHICS statement like this:

ODS GRAPHICS / WIDTH=w HEIGHT=h;

where w and h are computed in the program and stored in the macro variable.

 

Another option (and probably what I would do) is to embed all matrices into the largest sized matrix. Then the heat maps will all have the same number of cells and size of cells. For example, the following creates a 4x4 matrix and a 5x5 matrix. To embed the 4x4 matrix into a 5x5 matrix, allocate a 5x5 matrix of all missing values, then use subscripts to assign the 4x4 matrix to certain rows and columns:

 

proc iml;
ods graphics / width=400px height=400px;
x4 = j(4,4,1); x4[do(2,16,2)]=0; /* 4x4 matrix */
x5 = j(5,5,1); x5[do(2,25,2)]=0; /* 5x5 matrix */
call heatmapdisc(x4);
call heatmapdisc(x5);

/* make cells in x4 the same size as the cells in x5 by 
   embedding x4 into a 5x5 matrix that has missing values */
newx4 = j(5,5,.);
newx4[1:4, 1:4] = x4;
call heatmapdisc(newx4);

-----

 

PS. Regarding your program, you don't need to use the FROOT function to solve a quadratic equation. Just use the quadratic formula: 

sol = 0.5*(-1 + sqrt(1 - 4*(-2*PRICE)));

Also, on modern versions of SAS, the ROW and COL functions are built-in functions that you do not need to define.

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!

Multiple Linear Regression in SAS

Learn how to run multiple linear regression models with and without interactions, presented by SAS user Alex Chaplin.

Find more tutorials on the SAS Users YouTube channel.

From The DO Loop
Want more? Visit our blog for more articles like these.
Discussion stats
  • 1 reply
  • 825 views
  • 0 likes
  • 2 in conversation