forked from friendly/SAS-macros
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cyarrow.sas
308 lines (250 loc) · 10.4 KB
/
cyarrow.sas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
%macro cyArrow(
/* coordinates --------------------------- */
x1, y1 /* starting point coordnate -- required */
, x2, y2 /* end point coordinate -- required */
/* cyArrow specific options -------------- */
, barbAngle =30 /* angle between barb and shaft in degrees */
, barbLengthType ="P" /* [F]ixed or [P]roportional to shaft len */
, barbLength =0.05 /* if type=F then absolute length in hsys */
/* unit. otherwise proportion of shaft */
/* length */
, barbAspectRatio=1 /* the ratio of width(x) to height(y) */
/* draw function options ----------------- */
, color ="*" /* color codes. */
, hsys =hsys /* coord sys for size option */
, line =1 /* line type 1...46 */
, size =0.5 /* thickness of lines in hsys units */
, when ="A" /* annotate "A"fter gproc outputs */
);
%*-- draw a simple arrow using annotate facility. This replaces --*;
%*-- the undocumented macro %arrow() --*;
%*-- by chang y chung and ya huang --*;
%*-- v1.0 on 2004-07-26 --*;
%*-- v1.5 on 2004-07-26 fixed the exit part --*;
%*-- helpers ---------------------------------------------------------*;
%*-- a random prefix for "global" things ------------------------*;
%global cyArrow;
%let cyArrow = %sysfunc(putn(%sysfunc(int(1e8*
%sysfunc(ranuni(0)))),z8.));
%*-- for data step runtime error handling -----------------------*;
%local err cond msg;
%let err = %nrstr(
if %unquote(&cond.) then do;
put "&preMsg. %unquote(&msg.). &postMsg.";
function = "comment";
output;
goto _&cyArrow._exit;
end;
);
%local preMsg postMsg commentAndExit;
%let preMsg = NOTE: (cyArrow);
%let postMsg= arrow not drawn.;
%*-- macro compile time error check ----------------------------------*;
%*-- no empty parameters. ---------------------------------------*;
%local params param value i;
%let params = x1 y1 x2 y2 barbAngle barbLength barbLengthType
barbAspectRatio color hsys line size when;
%let i = 1;
%let param = %scan(¶ms.,&i);
%do %while (¶m.^=);
%if %superq(¶m.)= %then %do;
%put &preMsg. ¶m. should not be blank. &postMsg.;
%goto exit;
%end;
%let i = %eval(&i. + 1);
%let param = %scan(¶ms., &i.);
%end;
%*-- data step runtime check -----------------------------------------*;
%*-- coordinates cannot be missing ------------------------------*;
%local i coord coords;
%let coords = x1 y1 x2 y2;
%do i = 1 %to 4;
%let coord = %scan(&coords., &i.);
_&cyArrow._&coord. = %unquote(&&&coord..);
%let cond = missing(_&cyArrow._&coord.);
%let msg = &coord. should not be missing;
%unquote(&err.)
%end;
%*-- barbs ------------------------------------------------------*;
_&cyArrow._barbAngle = (%unquote(&barbAngle.));
%let cond = not (0<=_&cyArrow._barbAngle<=90);
%let msg = barbAngle should be between 0 to 90 degrees;
%unquote(&err.)
_&cyArrow._barbLengthType = upcase(trim(left(
%unquote(&barbLengthType.))));
%let cond = missing(_&cyArrow._barbLengthType);
%let msg = barbLengthType should not be missing;
%unquote(&err.)
_&cyArrow._barbLengthType = substr(_&cyArrow._barbLengthType,1,1);
%let cond = not (_&cyArrow._barbLengthType in ("P" "F"));
%let msg = barbLengthType should be either [P]roportional
or [F]ixed;
%unquote(&err.)
_&cyArrow._barbLength = (%unquote(&barbLength.));
%let cond = not (0 <= _&cyArrow._barbLength);
%let msg = barbLength should not be negative;
%unquote(&err.)
if _&cyArrow._barbLengthType = "P" then do;
%let cond = not (_&cyArrow._barbLength<=1.0);
%let msg = Proportional type barbLength should be/*
*/ between 0 and 1;
%unquote(&err.)
end;
_&cyArrow._barbAspectRatio = (%unquote(&barbAspectRatio.));
%let cond = not (0 < _&cyArrow._barbAspectRatio);
%let msg = barbAspectRatio should be larger than zero;
%unquote(&err.)
%*-- calculation for the shaft ---------------------------------------*;
%*-- always adjust y for aspect ---------------------------------*;
_&cyArrow._ay1 = _&cyArrow._y1 * _&cyArrow._barbAspectRatio**-1;
_&cyArrow._ay2 = _&cyArrow._y2 * _&cyArrow._barbAspectRatio**-1;
%*-- calculate shaft angle and length ---------------------------*;
_&cyArrow._shaftLength = sqrt(
(_&cyArrow._x1 - _&cyArrow._x2)**2
+ (_&cyArrow._ay1 - _&cyArrow._ay2)**2
);
%*-- check ------------------------------------------------------*;
%let cond = _&cyArrow._shaftLength <= 0;
%let msg = shaft length <= 0;
%unquote(&err.)
%*-- direction --------------------------------------------------*;
_&cyArrow._shaftDirection = atan2(
_&cyArrow._ay1 - _&cyArrow._ay2
, _&cyArrow._x1 - _&cyArrow._x2
);
%*-- calculation for the barbs ---------------------------------------*;
%*-- angle ------------------------------------------------------*;
_&cyArrow._barbAngle =
_&cyArrow._barbAngle * constant('pi') / 180
;
if _&cyArrow._barbLengthType = "P" then do;
_&cyArrow._barbLength =
_&cyArrow._shaftLength * _&cyArrow._barbLength
;
end;
%*-- check ------------------------------------------------------*;
%let cond = _&cyArrow._barbLength <= 0;
%let msg = barb length <= 0;
%unquote(&err.)
%*-- coordinates ------------------------------------------------*;
_&cyArrow._barbX1 = _&cyArrow._x2 + _&cyArrow._barbLength
* cos(_&cyArrow._shaftDirection + _&cyArrow._barbAngle);
_&cyArrow._barbY1 = _&cyArrow._y2 + _&cyArrow._barbLength
* sin(_&cyArrow._shaftDirection + _&cyArrow._barbAngle)
* _&cyArrow._barbAspectRatio;
_&cyArrow._barbX2 = _&cyArrow._x2 + _&cyArrow._barbLength
* cos(_&cyArrow._shaftDirection - _&cyArrow._barbAngle);
_&cyArrow._barbY2 = _&cyArrow._y2 + _&cyArrow._barbLength
* sin(_&cyArrow._shaftDirection - _&cyArrow._barbAngle)
* (_&cyArrow._barbAspectRatio);
%*-- save xlast, ylast, xlastt, ylastt and other options--------------*;
function = "push";
output;
_&cyArrow._color = trim(color);
_&cyArrow._line = 1 * line;
_&cyArrow._size = 1 * size;
_&cyArrow._hsys = trim(hsys);
_&cyArrow._when = trim(when);
%*-- common vars to draw function ------------------------------------*;
color = %unquote(&color.); /* codes only */
hsys = %unquote(&hsys.); /* for size */
line = %unquote(&line.); /* 1, 2, ..., 46 */
size = %unquote(&size.); /* in hsys unit */
when = %unquote(&when.); /* draw before/after the proc output */
%*-- draw "shaft" ----------------------------------------------------*;
function = "move";
x = _&cyArrow._x1;
y = _&cyArrow._y1;
output;
function = "draw";
x = _&cyArrow._x2;
y = _&cyArrow._y2;
output;
%*-- draw "barbs" ----------------------------------------------------*;
%do i = 1 %to 2;
function = "move";
x = _&cyArrow._barbX&i.;
y = _&cyArrow._barbY&i.;
output;
function = "draw";
x = _&cyArrow._x2;
y = _&cyArrow._y2;
output;
%end;
%*-- restore saved values --------------------------------------------*;
function = "pop";
output;
color = _&cyArrow._color;
line = _&cyArrow._line;
size = _&cyArrow._size;
hsys = _&cyArrow._hsys;
when = _&cyArrow._when;
%*-- exits -----------------------------------------------------------*;
%exit:;
_&cyArrow._exit:;
drop _&cyArrow._:;
%mend cyArrow;
%macro cyArrow_test;
/*-- test data set ----------------------------------------------*/
data one;
one_x =-10; one_y =-10; output;
one_x = 10; one_y = 10; output;
run;
data anno;
%annomac(nomsg)
%dclanno
%system(2,2,2)
%frame(CXFF0000, 1, 1)
length text $30;
radius = 3.5;
%macro doCircle(ar=, labelX=, labelY=
,offsetX=, offsetY=, centerX=, centerY=
);
function="label";
text="barbAspectRatio = &ar.";
font="simplex";
x=&labelX.;
y=&labelY.;
size=0.5;
output;
do deg = 0 to 360 by 15;
rad = deg * constant('pi') / 180;
xx = &offsetX. + radius * (1/1.1429) * cos(rad);
yy = &offsetY. + radius * (1.1429) * sin(rad);
%cyArrow(&CenterX., &CenterY., xx, yy
, barbLengthType="Fixed"
, barbLength=0.4, barbAspectRatio=&ar.
, color="cx0000ff", size=0.5
)
end;
%mend doCircle;
%doCircle(ar=1.0000, labelX=-5, labelY=9.5
, offsetX=-4.5, offsetY= 4.5, centerX=-5, centerY= 5)
%doCircle(ar=0.7000, labelX= 5, labelY=9.5
, offsetX= 4.5, offsetY= 4.5, centerX= 5, centerY= 5)
%doCircle(ar=1.1429, labelX= 5, labelY=-9.5
, offsetX= 4.5, offsetY=-4.5, centerX= 5, centerY=-5)
%doCircle(ar=2.0000, labelX=-5, labelY=-9.5
, offsetX=-4.5, offsetY=-4.5, centerX=-5, centerY=-5)
run;
dm log 'graph1; clear; end;' wedit; /* close the graph1 window */
goptions goutmode=replace; /* entire contents of catalog replaced */
/*-- aspect ratio test - gplots----------------------------------*/
%macro doGPlot(hsize=, vsize=, labelSize=);
dm 'graph1; end;' wedit;
filename gout "shaftAndBarb.emf";
goptions reset=all hsize=&hsize. vsize=&vsize.
device=emf gsfname=gout gsfmode=replace
targetdevice=emf goutmode=replace
;
proc gplot data=one;
title font="Tahoma" "HSize=&hsize. and VSize=&vsize.";
plot one_y*one_x/ annotate=anno grid;
run;
quit;
title;
goptions reset=all;
%mend doGPlot;
%doGPlot(hsize=8 in, vsize=7 in)
%mend cyArrow_test;
%*cyArrow_test; /* uncomment to run the test macro */