Discussion:
long macro program - need help
(too old to reply)
adjgiulio
2012-12-21 17:33:50 UTC
Permalink
Hi,

I'm using the macro %SASGoogleMaps to query google maps, get a map and plot data on it.
The macro is working just perfect in SAS, however is giving me a huge headache when I try to run in Enterprise Guide (even if I'm using my Local Server). The problem is that in EG the final output, which is supposed to be the google map with my data plotted on it, only shows the google map with no data.
The whole macro code is down below. The piece of log down here, to the best of my understanding, is where the problem might be occuring (seems like the output file is being saved in a temp folder, but I do not understand which piece of the code is driving that output location).

SYMBOLGEN: Macro variable MAP_OUT resolves to
C:\temp\tmp_img.png
MPRINT(GPOINTS): filename output "C:\temp\tmp_img.png";
SYMBOLGEN: Macro variable SIZE_X resolves to 500
SYMBOLGEN: Macro variable SIZE_Y resolves to 500
MPRINT(GPOINTS): goptions reset=all xpixels=500 ypixels=500 ;
SYMBOLGEN: Macro variable DEV resolves to png
MPRINT(GPOINTS): goptions device=png gsfname=output;
MPRINT(GPOINTS): data _null_;
SYMBOLGEN: Macro variable INPUT resolves to WORK.GEOCODED
MPRINT(GPOINTS): set WORK.GEOCODED end=last ;
MPRINT(GPOINTS): if _n_ = 1 then do ;
MPRINT(GPOINTS): rc=ginit();
MPRINT(GPOINTS): rc=graph('clear');
SYMBOLGEN: Macro variable MAP_IN resolves to
C:\temp\tmp_img.png
31 The SAS System
08:58 Friday, December 21, 2012

MPRINT(GPOINTS): rc=gdraw('image',"C:\temp\tmp_img.png", 0,
0, 100, 100,'fit');
MPRINT(GPOINTS): end ;
SYMBOLGEN: Macro variable PTYPE resolves to 12
MPRINT(GPOINTS): rc=gset('martype', 12);
SYMBOLGEN: Macro variable PCOLOR resolves to color
MPRINT(GPOINTS): rc=gset('marcolor', color);
SYMBOLGEN: Macro variable PSIZE resolves to 3
MPRINT(GPOINTS): rc=gset('marsize', 3);
MPRINT(GPOINTS): rc=gdraw('mark',.,__Xp__, __Yp__);
MPRINT(GPOINTS): if last then do ;
MPRINT(GPOINTS): rc=graph('update');
MPRINT(GPOINTS): rc=gterm();
MPRINT(GPOINTS): end ;
MPRINT(GPOINTS): run;

NOTE: 33 records written to
C:\Users\us41836\AppData\Local\Temp\SEG5304\SAS Temporary
Files\_TD5040\Prc2\dsgi8.png.
NOTE: There were 8 observations read from the data set
WORK.GEOCODED.


/*-----------------------MACRO HERE-------------------------*/

/**************************************************************************************************
* The macro SASGoogleMaps enables SAS users to overlay spatial patterns in SAS data
* set with Google Static Maps. It implements three fundamental steps:
* 1. retrieve map; 2. convert coordinate; 3. plot pattern on map
* Author: Jizhou Fu
* Wayne Zhang
* Date: Oct 09, 2011
* Please contact Wayne Zhang if you have any questions.
**************************************************************************************************/

/* This is the main function the user should call */
%macro SASGoogleMaps(
center = , /* center coordinates of map*/
zoom = 15, /* zoom level of map */
size = 640x640, /* size of map */
format = png, /* format of output image */
maptype = roadmap, /* type of map */
input = , /* data to be plotted */
lat = Y, /* the latitude to be used */
lon = X, /* the longitude to be used */
plot_type = , /* type of spatial pattern */
out_dir = , /* output directory */
out_file = , /* output image name */
group = , /* pattern (polygon) group */
add = 0 , /* add on an input image? */
map_in = , /* path for an input map */
read_meta = 1, /* read meta info? */
convert_coord = 1, /* convert coordinate? */
lat2 = ,
lon2 = ,
zoom_max = 1,
text = ,
ptype = 12,
pcolor = 2,
psize = 2,
ltype = 1,
lcolor = 2,
lwidth = 1,
ftype = HOLLOW ,
fcolor = 2 ,
fstyle = 1 ,
tfont = swiss,
tcolor = 1,
theight = 2) ;

%local path format2;

%if %quote(&center) = and &input= %then %do ;
%put ERROR: either 'input' or 'center' should be specified! ;
%goto endline ;
%end ;

%if &plot_type ^= %then %do ;
%if %index(%upcase(&plot_type), POINTS)=0 and
%index(%upcase(&plot_type), TEXT)=0 and
%index(%upcase(&plot_type), POLYLINES)=0 and
%index(%upcase(&plot_type), LINES)=0 and
%index(%upcase(&plot_type), POLYGON)=0 %then %do ;
%put ERROR: invalid 'plot_type'! ;
%goto endline ;
%end ;
%end ;

/* default out_dir and out_file according to whether the plot is to
be added onto existing images */
%if &add gt 0 %then %do ;
%if %quote(&out_dir) = %then
%let out_dir = %scan(%qscan(%quote(&_meta_),4,%str(|)),2,=);
%if %quote(&out_file) = %then
%let out_file = %scan(%qscan(%quote(&_meta_),5,%str(|)),2,=);
%end ;
%else %do ;
%if %quote(&out_dir) = %then
%let out_dir = %sysfunc(getoption(work));
%if %quote(&out_file) = %then
%let out_file = tmp_img ;
%end ;

/* get map if no map is supplied*/
%if &add = 0 %then %do ;
%get_map(center = %quote(&center),
zoom = &zoom ,
size = &size,
format = &format,
maptype = &maptype,
input = &input,
lat = &lat,
lon = &lon,
zoom_max = &zoom_max,
out_dir = &out_dir,
out_file = &out_file )
%end ;

/* plot only if plot_type is supplied */
%if &plot_type ^= %then %do ;

/* update path of map to read in */
%if &add gt 0 %then %do ;
%if %quote(&map_in)^= %then %let path = %quote(&map_in) ;
%else %do ;
%let format2= %scan(%qscan(%quote(&_meta_),6,%str(|)),2,=);
%let path = &out_dir\&out_file..&format2 ;
%end ;
%end ;
%else %let path = &out_dir\&out_file..&format ;

/* update meta info if map not supplied, or map supplied but need read meta*/
%if &add = 0 or &read_meta = 1 %then %do ;
%let center= %scan(%qscan(%quote(&_meta_),1,%str(|)),2,=);
%let zoom= %scan(%qscan(%quote(&_meta_),2,%str(|)),2,=);
%let size= %scan(%qscan(%quote(&_meta_),3,%str(|)),2,=);
%end ;

/* generate requested plot */
%if %index(%upcase(&plot_type), POINTS)>0 %then %do ;
%gpoints(map_in= &path,
out_dir = &out_dir,
out_file = &out_file,
input = &input,
lat = &lat,
lon = &lon,
center = %quote(&center),
zoom = &zoom,
size = &size,
format = &format,
convert_coord = &convert_coord,
ptype = &ptype,
pcolor = &pcolor,
psize = &psize)
%end ;
%else %if %index(%upcase(&plot_type), TEXT)>0 %then %do ;
%gtext(map_in= &path,
out_dir = &out_dir,
out_file = &out_file,
input = &input,
lat = &lat,
lon = &lon,
center = %quote(&center),
zoom = &zoom,
size = &size,
format = &format,
text = &text,
convert_coord = &convert_coord,
tfont = &tfont,
tcolor = &tcolor,
theight = &theight)
%end ;
%else %if %index(%upcase(&plot_type), POLYLINES)>0 %then %do ;
%gpolylines(map_in= &path,
out_dir = &out_dir,
out_file = &out_file,
input = &input,
lat = &lat,
lon = &lon,
center = %quote(&center),
zoom = &zoom,
size = &size,
format = &format,
convert_coord = &convert_coord,
ltype = &ltype,
lcolor = &lcolor,
lwidth = &lwidth,
group=&group)
%end ;
%else %if %index(%upcase(&plot_type), LINES)>0 %then %do ;
%glines(map_in= &path,
out_dir = &out_dir,
out_file = &out_file,
input = &input,
lat1 = &lat,
lon1 = &lon,
lat2 = &lat2,
lon2 = &lon2,
center = %quote(&center),
zoom = &zoom,
size = &size,
format = &format,
convert_coord = &convert_coord,
ltype = &ltype,
lcolor = &lcolor,
lwidth = &lwidth)
%end ;
%else %if %index(%upcase(&plot_type), POLYGON)>0 %then %do ;
%gpolygon(map_in= &path,
out_dir = &out_dir,
out_file = &out_file,
input = &input,
lat = &lat,
lon = &lon,
center = %quote(&center),
zoom = &zoom,
size = &size,
format = &format,
convert_coord = &convert_coord,
ftype = &ftype,
fcolor = &fcolor,
fstyle = &fstyle,
group=&group)
%end ;
%end ;

%endline:
%mend ;


/* The following are functions for each step of the implementioins,
called by %SASGoogleMaps
*/


/***********************************************************************
Step 0: utility functions
************************************************************************/

/************************************************************************************************/
/* This macro is used to extract a specific pattern from a string. */
/* The returned value of the macro is the specified buffer. */
/* Two global macro variables, _pre_buffer and _post_buffer, are generated */
/* to represent the string before and after the pattern respectively. */
/* Wayne (Yanwei) Zhang */
/* 04/28/2009 */
/************************************************************************************************/

%macro PRXSEARCH(string= , pattern= , buffer=0) ;
/* String: the name of the string which holds the pattern */
/* Pattern: the regular expression wanted */
/* Buffer: the position of the capture buffer. A second buffer can be supplied to */
/* so that the value of _pre_buffer and _post_buffer will depend on */
/* the second buffer, while the return value of the function still depends on */
/* the first. The two buffers are separated by space. A value of 0 means the */
/* whole pattern is to be returned. */
%local string len1 prxid match start len2 ext buffer1 buffer2;
%global _pre_buffer _post_buffer ;

/* Validate argument inputs */
%let buffer1=%scan(%sysfunc(compbl(&buffer)),1,%str( )) ;
%let buffer2=%scan(%sysfunc(compbl(&buffer)),2,%str( )) ;
%if &buffer1 < 0 %then %do ;
%put ERROR: Invalid buffer! Buffer number must not be negative! ;
%return ;
%end;
%if &buffer2^= %then %do ;
%if &buffer2 < 0 %then %do ;
%put ERROR: Invalid buffer! Buffer number must not be negative! ;
%return ;
%end;
%end ;
/* End of validation */

%let string=%qsysfunc(compbl(%bquote(&string))) ;
%let len1=%length(&string) ;
%let prxid=%sysfunc(prxparse(%bquote(&pattern))) ;
%let match=%sysfunc(prxmatch(&prxid, %bquote(&string))) ;
%let start=0 ;
%let len2=0 ;
%syscall prxposn(prxid,buffer1,start,len2) ;
%let ext= ;
%if &len2 gt 0 %then %do ;
%let ext=%qsubstr(%bquote(&string),&start,&len2) ;
%if &buffer2^= %then %do ;
%syscall prxposn(prxid,buffer2,start,len2) ;
%end ;
%if &start=. or &len2 =. %then %do ;
%put ERROR: Invalide capture in the second position! ;
%return ;
%end ;
%if &start eq 1 %then %let _pre_buffer= ;
%else %let _pre_buffer=%qsubstr(%bquote(&string),1, %eval(&start-1)) ;
%if %eval(&start+&len2-1) eq &len1 %then %let _post_buffer= ;
%else %let _post_buffer=%qsubstr(%bquote(&string),%eval(&start+&len2)) ;
%end ;
%syscall prxfree(prxid) ;
&ext
%mend ;



/***********************************************************************
Step 1: download map from Google
************************************************************************/

/* function to geocode an address. The result is a SAS
GLOBAL macro variable passed in reference through 'out_center'.
This macro variable stores the geocoded coordinates
Arguments:
- address: address to be geocoded. Do not use quote.
- out_center: SAS global macro variable to store the coordinates
*/
%macro get_center(address = , out_center = _center_ ) ;
%global &out_center ;
%local geobase ;
%let geobase = http://maps.googleapis.com/maps/api/geocode/json ;
filename mydata url
"&geobase?address=%sysfunc(urlencode(%quote(&address)))%nrstr(&)sensor=false";
filename z "%sysfunc(getoption(work))\tmp";

data _null_;
infile mydata recfm=f lrecl=1 end=eof;
file z recfm=f lrecl=1;
input @1 x $char1.;
put @1 x $char1.;
if eof;
call symputx('filesize',_n_);
run;

data _null_;
infile z recfm=f lrecl=&filesize. ;
input @ 'location" : {' @;
input text $100. ;
lat = scan(text,2,",:") ;
lon = scan(text,4,",:") ;
pn = prxparse("/(\d|\.|\-)+/") ;
call prxsubstr(pn,lon,start,length);
lon = substrn(lon,start,length );
output;
call symputx("&out_center", compress(put(lat,13.8)||","||put(lon,13.8))) ;
stop ;
run;

filename mydata clear ;
filename z clear ;
%mend ;

/* function to get center and max zoom level for a set of
given locations. The results are two SAS
GLOBAL macro variables that store the center and max
zoom level.
Arguments:
- input: data set containing locations.
- lat, lon: latitude and longitude name
- size: size of desired map
- out_center: SAS global macro variable to store the coordinates
- out_zoom: SAS global macro variable to store max zoom level
*/
%macro get_bbox_center(input = ,
lat = Y,
lon = X,
size = 640x640,
out_center = _center_,
out_zoom = _zoom_ );
%GLOBAL &out_center &out_zoom ;
%local size_x size_y lat_max lat_min latRange lon_max lon_min lonRange ;

/* validate arguments */
%if %quote(&input)= %then %do ;
%put ERROR: argument 'input' is missing! ;
%goto endline ;
%end ;
%if %PRXSEARCH(string=&size, pattern=%str(/\d+\s*x\s*\d+/i)) = %then %do ;
%put ERROR: argument 'size' has wrong format! ;
%goto endline ;
%end ;

%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;

/*retrieves spatial bounding box from spatial data*/
proc sql noprint;
select
put(max(&lat),13.8),
put(min(&lat),13.8),
put(range(&lat),13.8),
put(max(&lon),13.8),
put(min(&lon),13.8),
put(range(&lon),13.8)
into
:lat_max,
:lat_min,
:latRange,
:lon_max,
:lon_min,
:lonRange
from &input;
quit;

data _null_;
/*computes a bounding box for the given lat,lon points */
lat = &lat_min + &latRange/2;
lon = &lon_min + &lonRange/2;
dlat = &latRange/2 * 1.05;
dlon = &lonRange/2 * 1.05;
latR_min = lat - dlat;
latR_max = lat + dlat;
lonR_min = lon - dlon;
lonR_max = lon + dlon;
/*computes the maximum zoom level which will contain the given lat/lon range*/
sinPhi_min=sin(latR_min*constant('pi')/180);
sinPhi_max=sin(latR_max*constant('pi')/180);
normX = (lonR_max-lonR_min)/180;
normY = ((0.5*log(abs((1 + SinPhi_max)/(1 - SinPhi_max))))-
(0.5*log(abs((1 + SinPhi_min)/(1 - SinPhi_min)))))/constant('pi');
MaxZoom_lon = floor(1 + log2(&size_y/256/normX));
MaxZoom_lat = floor(1 + log2(&size_x/256/normY));
zoom =min(MaxZoom_lon, MaxZoom_lat);
call symputx("&out_center", compress(put(lat,13.8)||","||put(lon,13.8))) ;
call symputx("&out_zoom", trim(zoom)) ;
run;

%endline:
%mend ;

/* Function to retrieve map from Google static map API
Arguments:
- center: center of the map. It could be in the form of coordinates, e.g.,
%str(40.71066,-74.00880), where latititude precedes longitude and they
are separated by a comma; or it could be an adress, e.g., chicago, and
in this case, the address will be geocoded first; or it could be missing.
in the last case, an input data file is needed, where the geographical
locations in the input data are used to determine the center.
- zoom: zoom level, must be greater than 0
- size: size of the retrieved map in the form width x height e.g., 640x640
- maptype: type of map
- input, lat, lon: see above
- zoom_max: indicate whether max zoom level is used
- out_dir, out_file: ouput directory and file name
- out_meta: global variable name that stores meta info (center, zoom, size)
that can be used in plot
*/
%macro get_map(center = ,
zoom = 15,
size = 640x640,
format = png,
maptype = roadmap,
input = ,
lat = Y,
lon = X,
zoom_max = 1,
out_dir = %sysfunc(getoption(work)),
out_file = tmp_img,
out_meta = _meta_ );
%local url url_base path;
/* validate arguments */
%if %quote(&center)= and &input= %then %do ;
%put ERROR: at least one of 'center' and 'input' should be supplied! ;
%goto endline ;
%end ;
%if &zoom le 0 %then %do ;
%put ERROR: argument 'zoom' must be greater than 0! ;
%goto endline ;
%end ;
%if %PRXSEARCH(string=&size, pattern=%str(/\d+\s*x\s*\d+/i)) = %then %do ;
%put ERROR: argument 'size' has wrong format! ;
%goto endline ;
%end ;
%if ^(%upcase(&format)=JPG or %upcase(&format)=GIF or %upcase(&format)=PNG) = %then %do ;
%put ERROR: argument 'format' must be either 'JPG', 'PNG' or 'GIF'! ;
%goto endline ;
%end ;

/* check if needs geocoding */
/* a. if center is missing, use input, lon, and lat to get center */
%if &center = %then %do ;
%get_bbox_center(input=&input, lon=&lon, lat=&lat, size=&size)
%let center = &_center_ ;
%if &zoom_max=1 %then %let zoom = &_zoom_ ;
%else %do ;
%if &_zoom_ < &zoom %then %do ;
%let zoom = &_zoom_ ;
%put WARNING: zoom is reset to be &zoom, the maximum level based on the bounding box! ;
%end ;
%end ;
%end ;
%else %do ;
%if %PRXSEARCH(string=&center, pattern=%str(/(\d|\.|\-)+\s*,\s*(\d|\.|\-)+/)) = %then %do ;
%get_center(address=&center)
%let center = &_center_ ;
%end ;
%end ;

/* get url to be used for downloading (encode center) */
%let url_base = http://maps.googleapis.com/maps/api/staticmap ;
%let url = &url_base?center=%sysfunc(urlencode(%quote(&center)))
%nrstr(&)zoom=&zoom%nrstr(&)size=&size%nrstr(&)format=&format
%nrstr(&)maptype=&maptype%nrstr(&)sensor=false ;
%let url = %qsysfunc(compress(%nrquote(&url))) ;

/* path for output map */
%let path= %sysfunc(compress(&out_dir\&out_file..&format)) ;

/* get map */
filename in url "&url" ;
filename out "&path";

data _null_;
length filein 8 fileid 8;
filein = fopen('in','I',1,'B');
fileid = fopen('out','O',1,'B');
rec = '20'x;
do while(fread(filein)=0);
rc = fget(filein,rec,1);
rc = fput(fileid, rec);
rc =fwrite(fileid);
end;
rc = fclose(filein);
rc = fclose(fileid);
run;

filename in clear;
filename out clear;

/* save meta info needed for later use */
%GLOBAL &out_meta ;
%let &out_meta = center = &center|zoom = &zoom|size = &size|out_dir = %quote(&out_dir)|
out_file = &out_file| format = &format;
%endline:
%mend ;


/***********************************************************************
Step 2: convert coordinates for a given data set
************************************************************************/
/* The macro creates two columns, "&out_lat" and "&out_lon", in the data set
supplied in the input argument. The "&out_lon" and "&out_lat" are transformations
of lon and lat, and they are used in subsequent plot in DSPI.
Arguments:
- input: data containing lat, lon and variables to be plotted
- lat: variable name containing latitude in degrees
- lon: variable name containing longitude in degrees
- zoom: zoom level
- center: center of map
- size: size of map
- out_lat, out_lon: names of newly created variables
*/
%macro convert_coord(input = ,
lat = Y,
lon = X,
zoom = 15,
center = ,
size = 640x640,
out_lat = __Yp__ ,
out_lon = __Xp__ ) ;

%local lat_ctr lon_ctr size_x size_y X_ctr Y_ctr ;

%let lat_ctr = %scan(%quote(&center), 1, %str(,)) ;
%let lon_ctr = %scan(%quote(&center), 2, %str(,)) ;

%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;

/* convert lat and lon of the center location to pixel */
data _null_ ;
X = 2**(&zoom-1)*(&lon_ctr/180+1) ;
latr = constant("pi") * &lat_ctr / 180 ;
Yh = log((1+sin(latr))/(1-sin(latr))) / (2 * constant("pi"));
Y = 2**(&zoom-1)*(1-Yh);
call symput("X_ctr",trim(left(put(X,20.10)))) ;
call symput("Y_ctr",trim(left(put(Y,20.10)))) ;
run ;

/* convert lat and lon of the data location to pixel */
data &input ;
set &input ;
/* convert longitude to pixel */
&out_lon = 2**(&zoom-1)*(&lon/180+1);
&out_lon = (256 * (&out_lon - &X_ctr) +(&size_x-1)/2)/&size_x *100 ;
/* convert latitude to pixel */
&out_lat = log((1+sin(constant("pi") * &lat / 180))/
(1-sin(constant("pi") * &lat / 180))) / (2 * constant("pi"));
&out_lat = 2**(&zoom-1)*(1-&out_lat);
&out_lat = (- 256 * (&out_lat - &Y_ctr) +(&size_y-1)/2)/&size_y *100 ;
run ;

%mend ;


/***********************************************************************
Step 3: read in map and overlay it with requested plots
************************************************************************/


/***********************
a. plot points
***********************/

/* The macro takes a map retrieved from google (whose path is specified in "map_in")
and plot points on top of that, the points coming from the data set supplied in
"input" and the locations are determined by "lat" and "lon". The resulting overlayed
map is then exported to the "map_out_dir" directory, with name "map_out_file" and
extension "format". One can also specify the plotting characteristics through the
arguments "ptype" (type of plotting characters), "pcolor" (color of points), and
"psize" (size of points). These can be specified as either constant numbers or
variable names in "input".
Arguments:
- map_in: path of google map to be read in
- map_out_dir: directory of the map to be placed in
- map_out_file: file name of exported map (no extension)
- format: format of the graph, either "jpg", or "png"
- ptype: plotting type of points
- pcolor: color of points
- psize: size of points
- convert_coord: whether coordinate is to be converted
For other arguments, see the explanations in the above macros.
*/

%macro gpoints(map_in= ,
out_dir = ,
out_file = ,
input = ,
lat = Y,
lon = X,
center = ,
zoom = 15,
size = 640x640,
format = png,
convert_coord = 1,
ptype = 12,
pcolor = 2,
psize = 3) ;

%local map_out size_x size_y dev ;
/* parse input arguments */
%let map_out= &out_dir\&out_file..&format ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
%let dev = &format ;
%if %upcase(&format)=JPG %then %let dev = jpeg ;

/* convert coordinate to be used in DSGI */
%if &convert_coord = 1 %then %do ;
%convert_coord(input = &input, lat = &lat,
lon = &lon, center = &center,
zoom = &zoom, size = &size) ;
%end ;
%else %do ;
data &input ;
set &input ;
__Xp__ = &lon ;
__Yp__ = &lat ;
run ;
%end ;

/* plot using DSPI */
filename output "&map_out";
goptions reset=all xpixels=&size_x ypixels=&size_y ;
goptions device=&dev gsfname=output;

data _null_;
set &input end=last ;
if _n_ = 1 then do ;
rc=ginit();
rc=graph('clear');
rc=gdraw('image',"&map_in",
0, 0, 100, 100,'fit');
end ;
rc=gset('martype', &ptype);
rc=gset('marcolor', &pcolor);
rc=gset('marsize', &psize);
rc=gdraw('mark',.,__Xp__, __Yp__);

if last then do ;
rc=graph('update');
rc=gterm();
end ;
run;
quit;

filename output clear ;
data &input ;
set &input ;
drop __Xp__ __Yp__ ;
run ;

%mend ;


/***********************
b. plot text
***********************/
/* The macro adds text in a similar fashion as %gpoints.
Arguments:
- tfont: font of the text
- tcolor: color of text
- theight: height of text
For other arguments, see the explanations in the above macros.
*/
%macro gtext(map_in= ,
out_dir = ,
out_file = ,
input = ,
lat = Y,
lon = X,
text = ,
center = ,
zoom = 15,
size = 640x640,
format = png,
convert_coord = 1,
tfont = swiss,
tcolor = 1,
theight = 2) ;

%local map_out size_x size_y dev ;
/* parse input arguments */
%let map_out= &out_dir\&out_file..&format ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
%let dev = &format ;
%if %upcase(&format)=JPG %then %let dev = jpeg ;

/* convert coordinate to be used in DSGI */
%if &convert_coord = 1 %then %do ;
%convert_coord(input = &input, lat = &lat,
lon = &lon, center = &center,
zoom = &zoom, size = &size) ;
%end ;
%else %do ;
data &input ;
set &input ;
__Xp__ = &lon ;
__Yp__ = &lat ;
run ;
%end ;

/* plot using DSPI */
filename output "&map_out";
goptions reset=all xpixels=&size_x ypixels=&size_y ;
goptions device=&dev gsfname=output;

data _null_;
set &input end=last ;
if _n_ = 1 then do ;
rc=ginit();
rc=graph('clear');
rc=gdraw('image',"&map_in",
0, 0, 100, 100,'fit');
end ;
rc=gset('texcolor',&tcolor);
rc=gset('texfont',"&tfont");
rc=gset('texheight',&theight);
rc=gdraw('text',__Xp__, __Yp__,&text);
if last then do ;
rc=graph('update');
rc=gterm();
end ;
run;
quit;

filename output clear ;
data &input ;
set &input ;
drop __Xp__ __Yp__ ;
run ;

%mend ;


/***********************
c. plot lines
***********************/
/* The macro adds a set of lines.
Arguments:
- lat1: lat of starting point
- lon1: lon of starting point
- lat2: lat of ending point
- lon2: lon of ending point
- ltype: type of the line
- lcolor: color of line
- lwidth: width of line
For other arguments, see the explanations in the above macros.
*/

%macro glines(map_in= ,
out_dir = ,
out_file = ,
input = ,
lat1 = ,
lon1 = ,
lat2 = ,
lon2 = ,
center = ,
zoom = 15,
size = 640x640,
format = png,
convert_coord = 1,
ltype = 1,
lcolor = 1,
lwidth = 1) ;

%local map_out size_x size_y dev ;
/* parse input arguments */
%let map_out= &out_dir\&out_file..&format ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
%let dev = &format ;
%if %upcase(&format)=JPG %then %let dev = jpeg ;


/* convert coordinate to be used in DSGI */
%if &convert_coord = 1 %then %do ;
%convert_coord(input = &input, lat = &lat1,
lon = &lon1, center = &center,
zoom = &zoom, size = &size,
out_lon = __Xp1__, out_lat = __Yp1__) ;
%convert_coord(input = &input, lat = &lat2,
lon = &lon2, center = &center,
zoom = &zoom, size = &size,
out_lon = __Xp2__, out_lat = __Yp2__) ;
%end ;
%else %do ;
data &input ;
set &input ;
__Xp1__ = &lon1 ;
__Yp1__ = &lat1 ;
__Xp2__ = &lon2 ;
__Yp2__ = &lat2 ;
run;
%end ;


/* plot using DSPI */
filename output "&map_out";
goptions reset=all xpixels=&size_x ypixels=&size_y ;
goptions device=&dev gsfname=output;

data _null_;
set &input end=last ;
if _n_ = 1 then do ;
rc=ginit();
rc=graph('clear');
rc=gdraw('image',"&map_in",
0, 0, 100, 100,'fit');
end ;
rc=gset('lincolor',&lcolor);
rc=gset('linwidth',&lwidth);
rc=gset('lintype', &ltype);
rc=gdraw('line',.,__Xp1__, __Xp2__, __Yp1__, __Yp2__);
if last then do ;
rc=graph('update');
rc=gterm();
end ;
run;

filename output clear ;
data &input ;
set &input ;
drop __Xp1__ __Yp1__ __Xp2__ __Yp2__ ;
run;

%mend ;


/***********************
d. plot polylines
***********************/
/* This macro plot connected lines that form a polygon
Arguments:
- group: the polygon identifier
*/
%macro gpolylines(map_in= ,
out_dir = ,
out_file = ,
input = ,
lat = Y,
lon = X,
center = ,
zoom = 15,
size = 640x640,
format = png,
convert_coord = 1,
ltype = 1,
lcolor = 1,
lwidth = 1,
group = ) ;

%local map_out size_x size_y dev i x y dsid nvar ne rc;

/* parse input arguments */
%let map_out= &out_dir\&out_file..&format ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
%let dev = &format ;
%if %upcase(&format)=JPG %then %let dev = jpeg ;

/* convert coordinate to be used in DSGI */
%if &convert_coord = 1 %then %do ;
%convert_coord(input = &input, lat = &lat,
lon = &lon, center = &center,
zoom = &zoom, size = &size) ;
%end ;
%else %do ;
data &input ;
set &input ;
__Xp__ = &lon ;
__Yp__ = &lat ;
run ;
%end ;

proc transpose data = &input out = __tmp1__ prefix=X;
%if &group ^= %then %do ;
by &group
%if %PRXSEARCH(string=&lcolor, pattern=%str(/^\d/))= %then &lcolor ;
%if %PRXSEARCH(string=&ltype, pattern=%str(/^\d)/)= %then &ltype ;
%if %PRXSEARCH(string=&lwidth, pattern=%str(/^\d)/)= %then &lwidth ;
;
%end ;
var __Xp__ ;
run ;
proc transpose data = &input out = __tmp2__ prefix=Y;
%if &group ^= %then %do ;
by &group ;
%end ;
var __Yp__ ;
run ;
data __tmp__ ;
set __tmp1__ ;
set __tmp2__ ;
run ;

/* get number of columns */
%let ne = 1 ;
%if &group ^= %then %let ne = %eval(ne+1) ;
%if %PRXSEARCH(string=&lcolor, pattern=%str(/^\d/))= %then %let ne = %eval(ne+1) ;
%if %PRXSEARCH(string=&ltype, pattern=%str(/^\d)/)= %then %let ne = %eval(ne+1) ;
%if %PRXSEARCH(string=&lwidth, pattern=%str(/^\d)/)= %then %let ne = %eval(ne+1) ;
%let dsid = %sysfunc(open(__tmp1__));
%let nvars=%eval(%sysfunc(attrn(&dsid,NVARS))-&ne) ;
%let rc = %sysfunc(close(&dsid));
%let x = x1; %let y = y1;
%do i=2 %to &nvars ;
%let x = &x%str(,) x&i ;
%let y = &y%str(,) y&i ;
%end ;

/* fill missing with the latest nonmissing values */
data __tmp__ ;
set __tmp__ ;
array x{&nvars} x1- x&nvars ;
array y{&nvars} y1- y&nvars ;
do i=1 to &nvars ;
if missing(x[i]) then x[i] = x[i-1] ;
if missing(y[i]) then y[i] = y[i-1] ;
end ;
run ;

/* plot using DSGI */
filename output "&map_out";
goptions reset=all xpixels=&size_x ypixels=&size_y ;
goptions device=&dev gsfname=output;

data _null_;
set __tmp__ end=last ;
if _n_ = 1 then do ;
rc=ginit();
rc=graph('clear');
rc=gdraw('image',"&map_in",
0, 0, 100, 100,'fit');
end ;
rc=gset('lincolor',&lcolor);
rc=gset('lintype',&ltype);
rc=gset('linwidth', &lwidth);
rc=gdraw('line',.,&x,&y);
if last then do ;
rc=graph('update');
rc=gterm();
end ;
run;

/* clean data sets */
filename output clear ;
proc datasets nolist ;
delete __tmp1__ __tmp2__ __tmp__ ;
quit;
data &input ;
set &input ;
drop __Xp__ __Yp__ ;
run ;

/* old method:
* plot using DSPI ;
%if &group ^= %then %do ;
proc sql noprint ;
select count(distinct &group) into: ngroup
from &input ;
select distinct &group into: vgroup separated by ","
from &input ;
quit ;
%end ;
%else %let ngroup = 1 ;

* plot polylines by group ;
%do i=1 %to &ngroup ;

data __tmp__ ;
set &input end=last;
%if &group ^= %then %do ;
where &group = "%scan(%quote(&vgroup),&i,%str(,))" ;
%end ;
__x1__ = lag(&lon) ;
__y1__ = lag(&lat) ;
if last then do ;
call symput("xlast", &lon) ;
call symput("ylast", &lat) ;
end ;
run ;

data __tmp__ ;
set __tmp__ ;
if _n_ = 1 then do ;
__x1__ = &xlast ;
__y1__ = &ylast ;
end ;
__x2__ = &lon ;
__y2__ = &lat ;
run ;

%if &i = 1 %then %let map_in2 = &map_in ;
%else %let map_in2 = &out_dir\&out_file..&format ;

%glines(map_in= &map_in2,
out_dir =&out_dir ,
out_file = &out_file,
input = __tmp__,
lat1 = __Y1__ ,
lon1 = __X1__,
lat2 = __Y2__,
lon2 = __X2__ ,
center = &center,
zoom = &zoom,
size = &size,
format = &format,
ltype = &ltype,
lwidth = &lwidth,
lcolor = &lcolor)
%end ;
*/

%mend ;

/***********************
e. plot filled polygon
***********************/
/*
Arguments:
-ftype: fill type
-fcolor: fill color
-fstyle: fill style, only useful when ftype=PATTERN or ftype=HATCH
*/

%macro gpolygon(map_in= ,
out_dir = ,
out_file = ,
input = ,
lat = Y,
lon = X,
center = ,
zoom = 15,
size = 640x640,
format = png,
convert_coord =1,
ftype = HOLLOW,
fcolor = 2,
fstyle = 1,
group = ) ;

%local map_out size_x size_y dev dsid nvars rc x y i ne;
/* parse input arguments */
%let map_out= &out_dir\&out_file..&format ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
%let dev = &format ;
%if %upcase(&format)=JPG %then %let dev = jpeg ;

/* convert coordinate to be used in DSGI */
%if &convert_coord = 1 %then %do ;
%convert_coord(input = &input, lat = &lat,
lon = &lon, center = &center,
zoom = &zoom, size = &size) ;
%end ;
%else %do ;
data &input ;
set &input ;
__Xp__ = &lon ;
__Yp__ = &lat ;
run ;
%end ;

proc transpose data = &input out = __tmp1__ prefix=X;
%if &group ^= %then %do ;
by &group
%if %PRXSEARCH(string=&fcolor, pattern=%str(/^\d/))= %then &fcolor ;
%if %PRXSEARCH(string=&fstyle, pattern=%str(/^\d)/)= %then &fstyle ;
;
%end ;
var __Xp__ ;
run ;
proc transpose data = &input out = __tmp2__ prefix=Y;
%if &group ^= %then %do ;
by &group ;
%end ;
var __Yp__ ;
run ;
data __tmp__ ;
set __tmp1__ ;
set __tmp2__ ;
run ;

/* get number of columns */
%let ne = 1 ;
%if &group ^= %then %let ne = %eval(ne+1) ;
%if %PRXSEARCH(string=&fcolor, pattern=%str(/^\d/))= %then %let ne = %eval(ne+1) ;
%if %PRXSEARCH(string=&fstyle, pattern=%str(/^\d)/)= %then %let ne = %eval(ne+1) ;

%let dsid = %sysfunc(open(__tmp1__));
%let nvars=%eval(%sysfunc(attrn(&dsid,NVARS))-&ne) ;
%let rc = %sysfunc(close(&dsid));
%let x = x1; %let y = y1;
%do i=2 %to &nvars ;
%let x = &x%str(,) x&i ;
%let y = &y%str(,) y&i ;
%end ;

/* fill missing with the latest nonmissing values */
data __tmp__ ;
set __tmp__ ;
array x{&nvars} x1- x&nvars ;
array y{&nvars} y1- y&nvars ;
do i=1 to &nvars ;
if missing(x[i]) then x[i] = x[i-1] ;
if missing(y[i]) then y[i] = y[i-1] ;
end ;
run ;

/* plot using DSGI */
filename output "&map_out";
goptions reset=all xpixels=&size_x ypixels=&size_y ;
goptions device=&dev gsfname=output ;

data _null_;
set __tmp__ end=last ;
if _n_ = 1 then do ;
rc=ginit();
rc=graph('clear');
rc=gdraw('image',"&map_in",
0, 0, 100, 100,'fit');
end ;
rc=gset('filcolor',&fcolor);
rc=gset('filtype',"&ftype");
rc=gset('filstyle', &fstyle);
rc=gdraw('fill',.,&x,&y);
if last then do ;
rc=graph('update');
rc=gterm();
end ;
run;

filename output clear ;
proc datasets nolist ;
delete __tmp1__ __tmp2__ __tmp__ ;
quit;
data &input ;
set &input ;
drop __Xp__ __Yp__ ;
run ;

%mend ;
e***@gmail.com
2018-06-16 16:01:06 UTC
Permalink
Hello,
I use the example in the article and running the macro code on PC 9.3 but got message below.
Do you know why it doesn't get any results.

thanks.

Ethan


%SASGoogleMaps(center = %str(41.878114,-87.629798),
zoom = 14,
size = 320x320,
maptype = roadmap,
format = png);


OTE: Argument 1 to function FPUT at line 2 column 42 is invalid.
NOTE: Argument 1 to function FPUT at line 2 column 42 is invalid.
NOTE: Argument 1 to function FPUT at line 2 column 42 is invalid.
NOTE: Over 100 NOTES, additional NOTES suppressed.
NOTE: Argument 1 to function FPUT at line 2 column 42 is invalid.
filein=1 fileid=0 rec=‚ rc=70021 _ERROR_=1 _N_=1
NOTE: Mathematical operations could not be performed at the following places. The results of the
operations have been set to missing values.
Each place is given by: (Number of times) at (Line):(Column).
32545 at 2:42
NOTE: DATA statement used (Total process time):
real time 0.85 seconds
cpu time 0.07 seconds


NOTE: Fileref IN has been deassigned.
NOTE: Fileref OUT has been deassigned.
Post by adjgiulio
Hi,
I'm using the macro %SASGoogleMaps to query google maps, get a map and plot data on it.
The macro is working just perfect in SAS, however is giving me a huge headache when I try to run in Enterprise Guide (even if I'm using my Local Server). The problem is that in EG the final output, which is supposed to be the google map with my data plotted on it, only shows the google map with no data.
The whole macro code is down below. The piece of log down here, to the best of my understanding, is where the problem might be occuring (seems like the output file is being saved in a temp folder, but I do not understand which piece of the code is driving that output location).
SYMBOLGEN: Macro variable MAP_OUT resolves to
C:\temp\tmp_img.png
MPRINT(GPOINTS): filename output "C:\temp\tmp_img.png";
SYMBOLGEN: Macro variable SIZE_X resolves to 500
SYMBOLGEN: Macro variable SIZE_Y resolves to 500
MPRINT(GPOINTS): goptions reset=all xpixels=500 ypixels=500 ;
SYMBOLGEN: Macro variable DEV resolves to png
MPRINT(GPOINTS): goptions device=png gsfname=output;
MPRINT(GPOINTS): data _null_;
SYMBOLGEN: Macro variable INPUT resolves to WORK.GEOCODED
MPRINT(GPOINTS): set WORK.GEOCODED end=last ;
MPRINT(GPOINTS): if _n_ = 1 then do ;
MPRINT(GPOINTS): rc=ginit();
MPRINT(GPOINTS): rc=graph('clear');
SYMBOLGEN: Macro variable MAP_IN resolves to
C:\temp\tmp_img.png
31 The SAS System
08:58 Friday, December 21, 2012
MPRINT(GPOINTS): rc=gdraw('image',"C:\temp\tmp_img.png", 0,
0, 100, 100,'fit');
MPRINT(GPOINTS): end ;
SYMBOLGEN: Macro variable PTYPE resolves to 12
MPRINT(GPOINTS): rc=gset('martype', 12);
SYMBOLGEN: Macro variable PCOLOR resolves to color
MPRINT(GPOINTS): rc=gset('marcolor', color);
SYMBOLGEN: Macro variable PSIZE resolves to 3
MPRINT(GPOINTS): rc=gset('marsize', 3);
MPRINT(GPOINTS): rc=gdraw('mark',.,__Xp__, __Yp__);
MPRINT(GPOINTS): if last then do ;
MPRINT(GPOINTS): rc=graph('update');
MPRINT(GPOINTS): rc=gterm();
MPRINT(GPOINTS): end ;
MPRINT(GPOINTS): run;
NOTE: 33 records written to
C:\Users\us41836\AppData\Local\Temp\SEG5304\SAS Temporary
Files\_TD5040\Prc2\dsgi8.png.
NOTE: There were 8 observations read from the data set
WORK.GEOCODED.
/*-----------------------MACRO HERE-------------------------*/
/**************************************************************************************************
* The macro SASGoogleMaps enables SAS users to overlay spatial patterns in SAS data
* 1. retrieve map; 2. convert coordinate; 3. plot pattern on map
* Author: Jizhou Fu
* Wayne Zhang
* Date: Oct 09, 2011
* Please contact Wayne Zhang if you have any questions.
**************************************************************************************************/
/* This is the main function the user should call */
%macro SASGoogleMaps(
center = , /* center coordinates of map*/
zoom = 15, /* zoom level of map */
size = 640x640, /* size of map */
format = png, /* format of output image */
maptype = roadmap, /* type of map */
input = , /* data to be plotted */
lat = Y, /* the latitude to be used */
lon = X, /* the longitude to be used */
plot_type = , /* type of spatial pattern */
out_dir = , /* output directory */
out_file = , /* output image name */
group = , /* pattern (polygon) group */
add = 0 , /* add on an input image? */
map_in = , /* path for an input map */
read_meta = 1, /* read meta info? */
convert_coord = 1, /* convert coordinate? */
lat2 = ,
lon2 = ,
zoom_max = 1,
text = ,
ptype = 12,
pcolor = 2,
psize = 2,
ltype = 1,
lcolor = 2,
lwidth = 1,
ftype = HOLLOW ,
fcolor = 2 ,
fstyle = 1 ,
tfont = swiss,
tcolor = 1,
theight = 2) ;
%local path format2;
%if %quote(&center) = and &input= %then %do ;
%put ERROR: either 'input' or 'center' should be specified! ;
%goto endline ;
%end ;
%if &plot_type ^= %then %do ;
%if %index(%upcase(&plot_type), POINTS)=0 and
%index(%upcase(&plot_type), TEXT)=0 and
%index(%upcase(&plot_type), POLYLINES)=0 and
%index(%upcase(&plot_type), LINES)=0 and
%index(%upcase(&plot_type), POLYGON)=0 %then %do ;
%put ERROR: invalid 'plot_type'! ;
%goto endline ;
%end ;
%end ;
/* default out_dir and out_file according to whether the plot is to
be added onto existing images */
%if &add gt 0 %then %do ;
%if %quote(&out_dir) = %then
%let out_dir = %scan(%qscan(%quote(&_meta_),4,%str(|)),2,=);
%if %quote(&out_file) = %then
%let out_file = %scan(%qscan(%quote(&_meta_),5,%str(|)),2,=);
%end ;
%else %do ;
%if %quote(&out_dir) = %then
%let out_dir = %sysfunc(getoption(work));
%if %quote(&out_file) = %then
%let out_file = tmp_img ;
%end ;
/* get map if no map is supplied*/
%if &add = 0 %then %do ;
%get_map(center = %quote(&center),
zoom = &zoom ,
size = &size,
format = &format,
maptype = &maptype,
input = &input,
lat = &lat,
lon = &lon,
zoom_max = &zoom_max,
out_dir = &out_dir,
out_file = &out_file )
%end ;
/* plot only if plot_type is supplied */
%if &plot_type ^= %then %do ;
/* update path of map to read in */
%if &add gt 0 %then %do ;
%if %quote(&map_in)^= %then %let path = %quote(&map_in) ;
%else %do ;
%let format2= %scan(%qscan(%quote(&_meta_),6,%str(|)),2,=);
%let path = &out_dir\&out_file..&format2 ;
%end ;
%end ;
%else %let path = &out_dir\&out_file..&format ;
/* update meta info if map not supplied, or map supplied but need read meta*/
%if &add = 0 or &read_meta = 1 %then %do ;
%let center= %scan(%qscan(%quote(&_meta_),1,%str(|)),2,=);
%let zoom= %scan(%qscan(%quote(&_meta_),2,%str(|)),2,=);
%let size= %scan(%qscan(%quote(&_meta_),3,%str(|)),2,=);
%end ;
/* generate requested plot */
%if %index(%upcase(&plot_type), POINTS)>0 %then %do ;
%gpoints(map_in= &path,
out_dir = &out_dir,
out_file = &out_file,
input = &input,
lat = &lat,
lon = &lon,
center = %quote(&center),
zoom = &zoom,
size = &size,
format = &format,
convert_coord = &convert_coord,
ptype = &ptype,
pcolor = &pcolor,
psize = &psize)
%end ;
%else %if %index(%upcase(&plot_type), TEXT)>0 %then %do ;
%gtext(map_in= &path,
out_dir = &out_dir,
out_file = &out_file,
input = &input,
lat = &lat,
lon = &lon,
center = %quote(&center),
zoom = &zoom,
size = &size,
format = &format,
text = &text,
convert_coord = &convert_coord,
tfont = &tfont,
tcolor = &tcolor,
theight = &theight)
%end ;
%else %if %index(%upcase(&plot_type), POLYLINES)>0 %then %do ;
%gpolylines(map_in= &path,
out_dir = &out_dir,
out_file = &out_file,
input = &input,
lat = &lat,
lon = &lon,
center = %quote(&center),
zoom = &zoom,
size = &size,
format = &format,
convert_coord = &convert_coord,
ltype = &ltype,
lcolor = &lcolor,
lwidth = &lwidth,
group=&group)
%end ;
%else %if %index(%upcase(&plot_type), LINES)>0 %then %do ;
%glines(map_in= &path,
out_dir = &out_dir,
out_file = &out_file,
input = &input,
lat1 = &lat,
lon1 = &lon,
lat2 = &lat2,
lon2 = &lon2,
center = %quote(&center),
zoom = &zoom,
size = &size,
format = &format,
convert_coord = &convert_coord,
ltype = &ltype,
lcolor = &lcolor,
lwidth = &lwidth)
%end ;
%else %if %index(%upcase(&plot_type), POLYGON)>0 %then %do ;
%gpolygon(map_in= &path,
out_dir = &out_dir,
out_file = &out_file,
input = &input,
lat = &lat,
lon = &lon,
center = %quote(&center),
zoom = &zoom,
size = &size,
format = &format,
convert_coord = &convert_coord,
ftype = &ftype,
fcolor = &fcolor,
fstyle = &fstyle,
group=&group)
%end ;
%end ;
%mend ;
/* The following are functions for each step of the implementioins,
called by %SASGoogleMaps
*/
/***********************************************************************
Step 0: utility functions
************************************************************************/
/************************************************************************************************/
/* This macro is used to extract a specific pattern from a string. */
/* The returned value of the macro is the specified buffer. */
/* Two global macro variables, _pre_buffer and _post_buffer, are generated */
/* to represent the string before and after the pattern respectively. */
/* Wayne (Yanwei) Zhang */
/* 04/28/2009 */
/************************************************************************************************/
%macro PRXSEARCH(string= , pattern= , buffer=0) ;
/* String: the name of the string which holds the pattern */
/* Pattern: the regular expression wanted */
/* Buffer: the position of the capture buffer. A second buffer can be supplied to */
/* so that the value of _pre_buffer and _post_buffer will depend on */
/* the second buffer, while the return value of the function still depends on */
/* the first. The two buffers are separated by space. A value of 0 means the */
/* whole pattern is to be returned. */
%local string len1 prxid match start len2 ext buffer1 buffer2;
%global _pre_buffer _post_buffer ;
/* Validate argument inputs */
%let buffer1=%scan(%sysfunc(compbl(&buffer)),1,%str( )) ;
%let buffer2=%scan(%sysfunc(compbl(&buffer)),2,%str( )) ;
%if &buffer1 < 0 %then %do ;
%put ERROR: Invalid buffer! Buffer number must not be negative! ;
%return ;
%end;
%if &buffer2^= %then %do ;
%if &buffer2 < 0 %then %do ;
%put ERROR: Invalid buffer! Buffer number must not be negative! ;
%return ;
%end;
%end ;
/* End of validation */
%let string=%qsysfunc(compbl(%bquote(&string))) ;
%let len1=%length(&string) ;
%let prxid=%sysfunc(prxparse(%bquote(&pattern))) ;
%let match=%sysfunc(prxmatch(&prxid, %bquote(&string))) ;
%let start=0 ;
%let len2=0 ;
%syscall prxposn(prxid,buffer1,start,len2) ;
%let ext= ;
%if &len2 gt 0 %then %do ;
%let ext=%qsubstr(%bquote(&string),&start,&len2) ;
%if &buffer2^= %then %do ;
%syscall prxposn(prxid,buffer2,start,len2) ;
%end ;
%if &start=. or &len2 =. %then %do ;
%put ERROR: Invalide capture in the second position! ;
%return ;
%end ;
%if &start eq 1 %then %let _pre_buffer= ;
%else %let _pre_buffer=%qsubstr(%bquote(&string),1, %eval(&start-1)) ;
%if %eval(&start+&len2-1) eq &len1 %then %let _post_buffer= ;
%else %let _post_buffer=%qsubstr(%bquote(&string),%eval(&start+&len2)) ;
%end ;
%syscall prxfree(prxid) ;
&ext
%mend ;
/***********************************************************************
Step 1: download map from Google
************************************************************************/
/* function to geocode an address. The result is a SAS
GLOBAL macro variable passed in reference through 'out_center'.
This macro variable stores the geocoded coordinates
- address: address to be geocoded. Do not use quote.
- out_center: SAS global macro variable to store the coordinates
*/
%macro get_center(address = , out_center = _center_ ) ;
%global &out_center ;
%local geobase ;
%let geobase = http://maps.googleapis.com/maps/api/geocode/json ;
filename mydata url
"&geobase?address=%sysfunc(urlencode(%quote(&address)))%nrstr(&)sensor=false";
filename z "%sysfunc(getoption(work))\tmp";
data _null_;
infile mydata recfm=f lrecl=1 end=eof;
file z recfm=f lrecl=1;
if eof;
call symputx('filesize',_n_);
run;
data _null_;
infile z recfm=f lrecl=&filesize. ;
input text $100. ;
lat = scan(text,2,",:") ;
lon = scan(text,4,",:") ;
pn = prxparse("/(\d|\.|\-)+/") ;
call prxsubstr(pn,lon,start,length);
lon = substrn(lon,start,length );
output;
call symputx("&out_center", compress(put(lat,13.8)||","||put(lon,13.8))) ;
stop ;
run;
filename mydata clear ;
filename z clear ;
%mend ;
/* function to get center and max zoom level for a set of
given locations. The results are two SAS
GLOBAL macro variables that store the center and max
zoom level.
- input: data set containing locations.
- lat, lon: latitude and longitude name
- size: size of desired map
- out_center: SAS global macro variable to store the coordinates
- out_zoom: SAS global macro variable to store max zoom level
*/
%macro get_bbox_center(input = ,
lat = Y,
lon = X,
size = 640x640,
out_center = _center_,
out_zoom = _zoom_ );
%GLOBAL &out_center &out_zoom ;
%local size_x size_y lat_max lat_min latRange lon_max lon_min lonRange ;
/* validate arguments */
%if %quote(&input)= %then %do ;
%put ERROR: argument 'input' is missing! ;
%goto endline ;
%end ;
%if %PRXSEARCH(string=&size, pattern=%str(/\d+\s*x\s*\d+/i)) = %then %do ;
%put ERROR: argument 'size' has wrong format! ;
%goto endline ;
%end ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
/*retrieves spatial bounding box from spatial data*/
proc sql noprint;
select
put(max(&lat),13.8),
put(min(&lat),13.8),
put(range(&lat),13.8),
put(max(&lon),13.8),
put(min(&lon),13.8),
put(range(&lon),13.8)
into
:lat_max,
:lat_min,
:latRange,
:lon_max,
:lon_min,
:lonRange
from &input;
quit;
data _null_;
/*computes a bounding box for the given lat,lon points */
lat = &lat_min + &latRange/2;
lon = &lon_min + &lonRange/2;
dlat = &latRange/2 * 1.05;
dlon = &lonRange/2 * 1.05;
latR_min = lat - dlat;
latR_max = lat + dlat;
lonR_min = lon - dlon;
lonR_max = lon + dlon;
/*computes the maximum zoom level which will contain the given lat/lon range*/
sinPhi_min=sin(latR_min*constant('pi')/180);
sinPhi_max=sin(latR_max*constant('pi')/180);
normX = (lonR_max-lonR_min)/180;
normY = ((0.5*log(abs((1 + SinPhi_max)/(1 - SinPhi_max))))-
(0.5*log(abs((1 + SinPhi_min)/(1 - SinPhi_min)))))/constant('pi');
MaxZoom_lon = floor(1 + log2(&size_y/256/normX));
MaxZoom_lat = floor(1 + log2(&size_x/256/normY));
zoom =min(MaxZoom_lon, MaxZoom_lat);
call symputx("&out_center", compress(put(lat,13.8)||","||put(lon,13.8))) ;
call symputx("&out_zoom", trim(zoom)) ;
run;
%mend ;
/* Function to retrieve map from Google static map API
- center: center of the map. It could be in the form of coordinates, e.g.,
%str(40.71066,-74.00880), where latititude precedes longitude and they
are separated by a comma; or it could be an adress, e.g., chicago, and
in this case, the address will be geocoded first; or it could be missing.
in the last case, an input data file is needed, where the geographical
locations in the input data are used to determine the center.
- zoom: zoom level, must be greater than 0
- size: size of the retrieved map in the form width x height e.g., 640x640
- maptype: type of map
- input, lat, lon: see above
- zoom_max: indicate whether max zoom level is used
- out_dir, out_file: ouput directory and file name
- out_meta: global variable name that stores meta info (center, zoom, size)
that can be used in plot
*/
%macro get_map(center = ,
zoom = 15,
size = 640x640,
format = png,
maptype = roadmap,
input = ,
lat = Y,
lon = X,
zoom_max = 1,
out_dir = %sysfunc(getoption(work)),
out_file = tmp_img,
out_meta = _meta_ );
%local url url_base path;
/* validate arguments */
%if %quote(&center)= and &input= %then %do ;
%put ERROR: at least one of 'center' and 'input' should be supplied! ;
%goto endline ;
%end ;
%if &zoom le 0 %then %do ;
%put ERROR: argument 'zoom' must be greater than 0! ;
%goto endline ;
%end ;
%if %PRXSEARCH(string=&size, pattern=%str(/\d+\s*x\s*\d+/i)) = %then %do ;
%put ERROR: argument 'size' has wrong format! ;
%goto endline ;
%end ;
%if ^(%upcase(&format)=JPG or %upcase(&format)=GIF or %upcase(&format)=PNG) = %then %do ;
%put ERROR: argument 'format' must be either 'JPG', 'PNG' or 'GIF'! ;
%goto endline ;
%end ;
/* check if needs geocoding */
/* a. if center is missing, use input, lon, and lat to get center */
%if &center = %then %do ;
%get_bbox_center(input=&input, lon=&lon, lat=&lat, size=&size)
%let center = &_center_ ;
%if &zoom_max=1 %then %let zoom = &_zoom_ ;
%else %do ;
%if &_zoom_ < &zoom %then %do ;
%let zoom = &_zoom_ ;
%put WARNING: zoom is reset to be &zoom, the maximum level based on the bounding box! ;
%end ;
%end ;
%end ;
%else %do ;
%if %PRXSEARCH(string=&center, pattern=%str(/(\d|\.|\-)+\s*,\s*(\d|\.|\-)+/)) = %then %do ;
%get_center(address=&center)
%let center = &_center_ ;
%end ;
%end ;
/* get url to be used for downloading (encode center) */
%let url_base = http://maps.googleapis.com/maps/api/staticmap ;
%let url = &url_base?center=%sysfunc(urlencode(%quote(&center)))
%nrstr(&)zoom=&zoom%nrstr(&)size=&size%nrstr(&)format=&format
%nrstr(&)maptype=&maptype%nrstr(&)sensor=false ;
%let url = %qsysfunc(compress(%nrquote(&url))) ;
/* path for output map */
%let path= %sysfunc(compress(&out_dir\&out_file..&format)) ;
/* get map */
filename in url "&url" ;
filename out "&path";
data _null_;
length filein 8 fileid 8;
filein = fopen('in','I',1,'B');
fileid = fopen('out','O',1,'B');
rec = '20'x;
do while(fread(filein)=0);
rc = fget(filein,rec,1);
rc = fput(fileid, rec);
rc =fwrite(fileid);
end;
rc = fclose(filein);
rc = fclose(fileid);
run;
filename in clear;
filename out clear;
/* save meta info needed for later use */
%GLOBAL &out_meta ;
%let &out_meta = center = &center|zoom = &zoom|size = &size|out_dir = %quote(&out_dir)|
out_file = &out_file| format = &format;
%mend ;
/***********************************************************************
Step 2: convert coordinates for a given data set
************************************************************************/
/* The macro creates two columns, "&out_lat" and "&out_lon", in the data set
supplied in the input argument. The "&out_lon" and "&out_lat" are transformations
of lon and lat, and they are used in subsequent plot in DSPI.
- input: data containing lat, lon and variables to be plotted
- lat: variable name containing latitude in degrees
- lon: variable name containing longitude in degrees
- zoom: zoom level
- center: center of map
- size: size of map
- out_lat, out_lon: names of newly created variables
*/
%macro convert_coord(input = ,
lat = Y,
lon = X,
zoom = 15,
center = ,
size = 640x640,
out_lat = __Yp__ ,
out_lon = __Xp__ ) ;
%local lat_ctr lon_ctr size_x size_y X_ctr Y_ctr ;
%let lat_ctr = %scan(%quote(&center), 1, %str(,)) ;
%let lon_ctr = %scan(%quote(&center), 2, %str(,)) ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
/* convert lat and lon of the center location to pixel */
data _null_ ;
X = 2**(&zoom-1)*(&lon_ctr/180+1) ;
latr = constant("pi") * &lat_ctr / 180 ;
Yh = log((1+sin(latr))/(1-sin(latr))) / (2 * constant("pi"));
Y = 2**(&zoom-1)*(1-Yh);
call symput("X_ctr",trim(left(put(X,20.10)))) ;
call symput("Y_ctr",trim(left(put(Y,20.10)))) ;
run ;
/* convert lat and lon of the data location to pixel */
data &input ;
set &input ;
/* convert longitude to pixel */
&out_lon = 2**(&zoom-1)*(&lon/180+1);
&out_lon = (256 * (&out_lon - &X_ctr) +(&size_x-1)/2)/&size_x *100 ;
/* convert latitude to pixel */
&out_lat = log((1+sin(constant("pi") * &lat / 180))/
(1-sin(constant("pi") * &lat / 180))) / (2 * constant("pi"));
&out_lat = 2**(&zoom-1)*(1-&out_lat);
&out_lat = (- 256 * (&out_lat - &Y_ctr) +(&size_y-1)/2)/&size_y *100 ;
run ;
%mend ;
/***********************************************************************
Step 3: read in map and overlay it with requested plots
************************************************************************/
/***********************
a. plot points
***********************/
/* The macro takes a map retrieved from google (whose path is specified in "map_in")
and plot points on top of that, the points coming from the data set supplied in
"input" and the locations are determined by "lat" and "lon". The resulting overlayed
map is then exported to the "map_out_dir" directory, with name "map_out_file" and
extension "format". One can also specify the plotting characteristics through the
arguments "ptype" (type of plotting characters), "pcolor" (color of points), and
"psize" (size of points). These can be specified as either constant numbers or
variable names in "input".
- map_in: path of google map to be read in
- map_out_dir: directory of the map to be placed in
- map_out_file: file name of exported map (no extension)
- format: format of the graph, either "jpg", or "png"
- ptype: plotting type of points
- pcolor: color of points
- psize: size of points
- convert_coord: whether coordinate is to be converted
For other arguments, see the explanations in the above macros.
*/
%macro gpoints(map_in= ,
out_dir = ,
out_file = ,
input = ,
lat = Y,
lon = X,
center = ,
zoom = 15,
size = 640x640,
format = png,
convert_coord = 1,
ptype = 12,
pcolor = 2,
psize = 3) ;
%local map_out size_x size_y dev ;
/* parse input arguments */
%let map_out= &out_dir\&out_file..&format ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
%let dev = &format ;
%if %upcase(&format)=JPG %then %let dev = jpeg ;
/* convert coordinate to be used in DSGI */
%if &convert_coord = 1 %then %do ;
%convert_coord(input = &input, lat = &lat,
lon = &lon, center = &center,
zoom = &zoom, size = &size) ;
%end ;
%else %do ;
data &input ;
set &input ;
__Xp__ = &lon ;
__Yp__ = &lat ;
run ;
%end ;
/* plot using DSPI */
filename output "&map_out";
goptions reset=all xpixels=&size_x ypixels=&size_y ;
goptions device=&dev gsfname=output;
data _null_;
set &input end=last ;
if _n_ = 1 then do ;
rc=ginit();
rc=graph('clear');
rc=gdraw('image',"&map_in",
0, 0, 100, 100,'fit');
end ;
rc=gset('martype', &ptype);
rc=gset('marcolor', &pcolor);
rc=gset('marsize', &psize);
rc=gdraw('mark',.,__Xp__, __Yp__);
if last then do ;
rc=graph('update');
rc=gterm();
end ;
run;
quit;
filename output clear ;
data &input ;
set &input ;
drop __Xp__ __Yp__ ;
run ;
%mend ;
/***********************
b. plot text
***********************/
/* The macro adds text in a similar fashion as %gpoints.
- tfont: font of the text
- tcolor: color of text
- theight: height of text
For other arguments, see the explanations in the above macros.
*/
%macro gtext(map_in= ,
out_dir = ,
out_file = ,
input = ,
lat = Y,
lon = X,
text = ,
center = ,
zoom = 15,
size = 640x640,
format = png,
convert_coord = 1,
tfont = swiss,
tcolor = 1,
theight = 2) ;
%local map_out size_x size_y dev ;
/* parse input arguments */
%let map_out= &out_dir\&out_file..&format ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
%let dev = &format ;
%if %upcase(&format)=JPG %then %let dev = jpeg ;
/* convert coordinate to be used in DSGI */
%if &convert_coord = 1 %then %do ;
%convert_coord(input = &input, lat = &lat,
lon = &lon, center = &center,
zoom = &zoom, size = &size) ;
%end ;
%else %do ;
data &input ;
set &input ;
__Xp__ = &lon ;
__Yp__ = &lat ;
run ;
%end ;
/* plot using DSPI */
filename output "&map_out";
goptions reset=all xpixels=&size_x ypixels=&size_y ;
goptions device=&dev gsfname=output;
data _null_;
set &input end=last ;
if _n_ = 1 then do ;
rc=ginit();
rc=graph('clear');
rc=gdraw('image',"&map_in",
0, 0, 100, 100,'fit');
end ;
rc=gset('texcolor',&tcolor);
rc=gset('texfont',"&tfont");
rc=gset('texheight',&theight);
rc=gdraw('text',__Xp__, __Yp__,&text);
if last then do ;
rc=graph('update');
rc=gterm();
end ;
run;
quit;
filename output clear ;
data &input ;
set &input ;
drop __Xp__ __Yp__ ;
run ;
%mend ;
/***********************
c. plot lines
***********************/
/* The macro adds a set of lines.
- lat1: lat of starting point
- lon1: lon of starting point
- lat2: lat of ending point
- lon2: lon of ending point
- ltype: type of the line
- lcolor: color of line
- lwidth: width of line
For other arguments, see the explanations in the above macros.
*/
%macro glines(map_in= ,
out_dir = ,
out_file = ,
input = ,
lat1 = ,
lon1 = ,
lat2 = ,
lon2 = ,
center = ,
zoom = 15,
size = 640x640,
format = png,
convert_coord = 1,
ltype = 1,
lcolor = 1,
lwidth = 1) ;
%local map_out size_x size_y dev ;
/* parse input arguments */
%let map_out= &out_dir\&out_file..&format ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
%let dev = &format ;
%if %upcase(&format)=JPG %then %let dev = jpeg ;
/* convert coordinate to be used in DSGI */
%if &convert_coord = 1 %then %do ;
%convert_coord(input = &input, lat = &lat1,
lon = &lon1, center = &center,
zoom = &zoom, size = &size,
out_lon = __Xp1__, out_lat = __Yp1__) ;
%convert_coord(input = &input, lat = &lat2,
lon = &lon2, center = &center,
zoom = &zoom, size = &size,
out_lon = __Xp2__, out_lat = __Yp2__) ;
%end ;
%else %do ;
data &input ;
set &input ;
__Xp1__ = &lon1 ;
__Yp1__ = &lat1 ;
__Xp2__ = &lon2 ;
__Yp2__ = &lat2 ;
run;
%end ;
/* plot using DSPI */
filename output "&map_out";
goptions reset=all xpixels=&size_x ypixels=&size_y ;
goptions device=&dev gsfname=output;
data _null_;
set &input end=last ;
if _n_ = 1 then do ;
rc=ginit();
rc=graph('clear');
rc=gdraw('image',"&map_in",
0, 0, 100, 100,'fit');
end ;
rc=gset('lincolor',&lcolor);
rc=gset('linwidth',&lwidth);
rc=gset('lintype', &ltype);
rc=gdraw('line',.,__Xp1__, __Xp2__, __Yp1__, __Yp2__);
if last then do ;
rc=graph('update');
rc=gterm();
end ;
run;
filename output clear ;
data &input ;
set &input ;
drop __Xp1__ __Yp1__ __Xp2__ __Yp2__ ;
run;
%mend ;
/***********************
d. plot polylines
***********************/
/* This macro plot connected lines that form a polygon
- group: the polygon identifier
*/
%macro gpolylines(map_in= ,
out_dir = ,
out_file = ,
input = ,
lat = Y,
lon = X,
center = ,
zoom = 15,
size = 640x640,
format = png,
convert_coord = 1,
ltype = 1,
lcolor = 1,
lwidth = 1,
group = ) ;
%local map_out size_x size_y dev i x y dsid nvar ne rc;
/* parse input arguments */
%let map_out= &out_dir\&out_file..&format ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
%let dev = &format ;
%if %upcase(&format)=JPG %then %let dev = jpeg ;
/* convert coordinate to be used in DSGI */
%if &convert_coord = 1 %then %do ;
%convert_coord(input = &input, lat = &lat,
lon = &lon, center = &center,
zoom = &zoom, size = &size) ;
%end ;
%else %do ;
data &input ;
set &input ;
__Xp__ = &lon ;
__Yp__ = &lat ;
run ;
%end ;
proc transpose data = &input out = __tmp1__ prefix=X;
%if &group ^= %then %do ;
by &group
%if %PRXSEARCH(string=&lcolor, pattern=%str(/^\d/))= %then &lcolor ;
%if %PRXSEARCH(string=&ltype, pattern=%str(/^\d)/)= %then &ltype ;
%if %PRXSEARCH(string=&lwidth, pattern=%str(/^\d)/)= %then &lwidth ;
;
%end ;
var __Xp__ ;
run ;
proc transpose data = &input out = __tmp2__ prefix=Y;
%if &group ^= %then %do ;
by &group ;
%end ;
var __Yp__ ;
run ;
data __tmp__ ;
set __tmp1__ ;
set __tmp2__ ;
run ;
/* get number of columns */
%let ne = 1 ;
%if &group ^= %then %let ne = %eval(ne+1) ;
%if %PRXSEARCH(string=&lcolor, pattern=%str(/^\d/))= %then %let ne = %eval(ne+1) ;
%if %PRXSEARCH(string=&ltype, pattern=%str(/^\d)/)= %then %let ne = %eval(ne+1) ;
%if %PRXSEARCH(string=&lwidth, pattern=%str(/^\d)/)= %then %let ne = %eval(ne+1) ;
%let dsid = %sysfunc(open(__tmp1__));
%let nvars=%eval(%sysfunc(attrn(&dsid,NVARS))-&ne) ;
%let rc = %sysfunc(close(&dsid));
%let x = x1; %let y = y1;
%do i=2 %to &nvars ;
%let x = &x%str(,) x&i ;
%let y = &y%str(,) y&i ;
%end ;
/* fill missing with the latest nonmissing values */
data __tmp__ ;
set __tmp__ ;
array x{&nvars} x1- x&nvars ;
array y{&nvars} y1- y&nvars ;
do i=1 to &nvars ;
if missing(x[i]) then x[i] = x[i-1] ;
if missing(y[i]) then y[i] = y[i-1] ;
end ;
run ;
/* plot using DSGI */
filename output "&map_out";
goptions reset=all xpixels=&size_x ypixels=&size_y ;
goptions device=&dev gsfname=output;
data _null_;
set __tmp__ end=last ;
if _n_ = 1 then do ;
rc=ginit();
rc=graph('clear');
rc=gdraw('image',"&map_in",
0, 0, 100, 100,'fit');
end ;
rc=gset('lincolor',&lcolor);
rc=gset('lintype',&ltype);
rc=gset('linwidth', &lwidth);
rc=gdraw('line',.,&x,&y);
if last then do ;
rc=graph('update');
rc=gterm();
end ;
run;
/* clean data sets */
filename output clear ;
proc datasets nolist ;
delete __tmp1__ __tmp2__ __tmp__ ;
quit;
data &input ;
set &input ;
drop __Xp__ __Yp__ ;
run ;
* plot using DSPI ;
%if &group ^= %then %do ;
proc sql noprint ;
select count(distinct &group) into: ngroup
from &input ;
select distinct &group into: vgroup separated by ","
from &input ;
quit ;
%end ;
%else %let ngroup = 1 ;
* plot polylines by group ;
%do i=1 %to &ngroup ;
data __tmp__ ;
set &input end=last;
%if &group ^= %then %do ;
where &group = "%scan(%quote(&vgroup),&i,%str(,))" ;
%end ;
__x1__ = lag(&lon) ;
__y1__ = lag(&lat) ;
if last then do ;
call symput("xlast", &lon) ;
call symput("ylast", &lat) ;
end ;
run ;
data __tmp__ ;
set __tmp__ ;
if _n_ = 1 then do ;
__x1__ = &xlast ;
__y1__ = &ylast ;
end ;
__x2__ = &lon ;
__y2__ = &lat ;
run ;
%if &i = 1 %then %let map_in2 = &map_in ;
%else %let map_in2 = &out_dir\&out_file..&format ;
%glines(map_in= &map_in2,
out_dir =&out_dir ,
out_file = &out_file,
input = __tmp__,
lat1 = __Y1__ ,
lon1 = __X1__,
lat2 = __Y2__,
lon2 = __X2__ ,
center = &center,
zoom = &zoom,
size = &size,
format = &format,
ltype = &ltype,
lwidth = &lwidth,
lcolor = &lcolor)
%end ;
*/
%mend ;
/***********************
e. plot filled polygon
***********************/
/*
-ftype: fill type
-fcolor: fill color
-fstyle: fill style, only useful when ftype=PATTERN or ftype=HATCH
*/
%macro gpolygon(map_in= ,
out_dir = ,
out_file = ,
input = ,
lat = Y,
lon = X,
center = ,
zoom = 15,
size = 640x640,
format = png,
convert_coord =1,
ftype = HOLLOW,
fcolor = 2,
fstyle = 1,
group = ) ;
%local map_out size_x size_y dev dsid nvars rc x y i ne;
/* parse input arguments */
%let map_out= &out_dir\&out_file..&format ;
%let size_x = %scan(%quote(&size), 1, x) ;
%let size_y = %scan(%quote(&size), 2, x) ;
%let dev = &format ;
%if %upcase(&format)=JPG %then %let dev = jpeg ;
/* convert coordinate to be used in DSGI */
%if &convert_coord = 1 %then %do ;
%convert_coord(input = &input, lat = &lat,
lon = &lon, center = &center,
zoom = &zoom, size = &size) ;
%end ;
%else %do ;
data &input ;
set &input ;
__Xp__ = &lon ;
__Yp__ = &lat ;
run ;
%end ;
proc transpose data = &input out = __tmp1__ prefix=X;
%if &group ^= %then %do ;
by &group
%if %PRXSEARCH(string=&fcolor, pattern=%str(/^\d/))= %then &fcolor ;
%if %PRXSEARCH(string=&fstyle, pattern=%str(/^\d)/)= %then &fstyle ;
;
%end ;
var __Xp__ ;
run ;
proc transpose data = &input out = __tmp2__ prefix=Y;
%if &group ^= %then %do ;
by &group ;
%end ;
var __Yp__ ;
run ;
data __tmp__ ;
set __tmp1__ ;
set __tmp2__ ;
run ;
/* get number of columns */
%let ne = 1 ;
%if &group ^= %then %let ne = %eval(ne+1) ;
%if %PRXSEARCH(string=&fcolor, pattern=%str(/^\d/))= %then %let ne = %eval(ne+1) ;
%if %PRXSEARCH(string=&fstyle, pattern=%str(/^\d)/)= %then %let ne = %eval(ne+1) ;
%let dsid = %sysfunc(open(__tmp1__));
%let nvars=%eval(%sysfunc(attrn(&dsid,NVARS))-&ne) ;
%let rc = %sysfunc(close(&dsid));
%let x = x1; %let y = y1;
%do i=2 %to &nvars ;
%let x = &x%str(,) x&i ;
%let y = &y%str(,) y&i ;
%end ;
/* fill missing with the latest nonmissing values */
data __tmp__ ;
set __tmp__ ;
array x{&nvars} x1- x&nvars ;
array y{&nvars} y1- y&nvars ;
do i=1 to &nvars ;
if missing(x[i]) then x[i] = x[i-1] ;
if missing(y[i]) then y[i] = y[i-1] ;
end ;
run ;
/* plot using DSGI */
filename output "&map_out";
goptions reset=all xpixels=&size_x ypixels=&size_y ;
goptions device=&dev gsfname=output ;
data _null_;
set __tmp__ end=last ;
if _n_ = 1 then do ;
rc=ginit();
rc=graph('clear');
rc=gdraw('image',"&map_in",
0, 0, 100, 100,'fit');
end ;
rc=gset('filcolor',&fcolor);
rc=gset('filtype',"&ftype");
rc=gset('filstyle', &fstyle);
rc=gdraw('fill',.,&x,&y);
if last then do ;
rc=graph('update');
rc=gterm();
end ;
run;
filename output clear ;
proc datasets nolist ;
delete __tmp1__ __tmp2__ __tmp__ ;
quit;
data &input ;
set &input ;
drop __Xp__ __Yp__ ;
run ;
%mend ;
Loading...