## Generate a different number of random (or evenly distributed ) dots in every polygons of a map?

Solved
Frequent Contributor
Posts: 96

# Generate a different number of random (or evenly distributed ) dots in every polygons of a map?

Hi everyone,

I just stumbled on this map and I'm curious if something similar could be achievable  using SAS for Canada.  There are Cartographic Boundary Files available for multiple geographies (Province, Census division, Census subdivision) and one could easily get population data for these geographies on CanSim.

Once I know how many white/nativesblacks/asians/hispanic people I have in each area, I would like to create a single dot on the map for each of them.

Question:  Is it possible to do that in SAS?  So far my best idea using the random approach would be as follow:

a)  Taking each region individually, find it's minimum and maximum longitude/latitude and the total population P.

b)  Generate  10*P points within that rectangle using  RANUNI

c)  Determine which points are indisde the region using PROC GINSIDE

d)  Keep P points that are inside the region.

e) Randomly assign a race to each of the retained points.

Any improvement would be very appreciated,

Cheers

Simon

Accepted Solutions
Solution
‎08-20-2014 10:09 AM
SAS Employee
Posts: 170

## Re: Generate a different number of random (or evenly distributed ) dots in every polygons of a map?

You should look at the MAP papers on http://support.sas.com/rnd/papers/.

At this location, there are several papers.

Papers from SUGI 29.

Title: Tips and Tricks II.  Getting the most from your SAS/GRAPH maps.

SAS Presentations at SAS Global Forum 2011.

Title: Outbreak Maps: Visually Discovering Your Data.

All Replies
Super User
Posts: 12,148

## Re: Generate a different number of random (or evenly distributed ) dots in every polygons of a map?

I am including a dot map that randomly places points around a given centroid (think city location) that may give you some ideas. I downloaded this from a SAS site but don't remember which.

/*+-------------------------------------------------------+
|          SUGI 29 Sample                               |
|          SAS MAPPING: Tips and tricks                 |
|                                                       |
|    NAME: dotdensity.sas                               |
|   TITLE: Simulate a dot-density map.                  |
|          This example takes zipcode location data and |
|          finds the zipcode centroid location.  Then   |
|          it randomizes the locations so that the      |
|          same location doesn't fall at the same spot. |
| PRODUCT: GRAPH                                        |
|                                                       |
|   NOTES: Last Update 24FEB04                          |
|          This example outputs several ODS device types|
|          Dot size may need to change for different    |
|          ODS devices.                                 |
+-------------------------------------------------------+*/

%let name=dotdens;
filename odsout '.';
goptions reset=global ;
/** Sets goptions xpixels and ypixels **/
%inc '../setsize.sas';

/***********************************************************************/
/* Illness location by zipcode                                         */
/* Substitute your own zipcode based location data here.               */
/***********************************************************************/
infile 'zip.out';
length zip 5.;
input zip ;  /*must have variable 'zip' for matching*/
addr_data=1; /*unique var for separating data later*/
run;

/*---------------------------------------------------------------------*/
/* Find the x,y location of the zipcode centroid.                      */
/*                                                                     */
/* Sort the data by zipcode and then                                   */
/* get the X,Y centroid location for the zipcode by merging with the   */
/* zipcode dataset.  This will give you more information than you want */
/* so you drop the records not in the original address data.           */
/* Arguments:                                                          */
/*   indata= input dataset with zipcode data to lookup x,y             */
/*   outdata= output dataset created with location information         */
/*   uniquevar= variable name used only in input data so you can       */
/*              eliminate other data.                                  */
/*   radians= set to 1 if the map data has x,y in radians.  zipcode    */
/*            data is in lat/long degrees.                             */
/*---------------------------------------------------------------------*/
proc sort data=&indata;
by zip;
run;
data temp(keep= zip &uniquevar x y city);
by zip;
run;

/***********************************************************************/
/* Now, drop the records that were not in the original data or         */
/* records that don't have a zipcode match. Adjust the lat/long to     */
/* match the map.                                                      */
/***********************************************************************/
data &outdata;
set temp;
if (&uniquevar ^= . and x NE . AND y NE .) then do;
x=atan(1)/45 * x *-1;
y=atan(1)/45 * y;
%end;
output;
end;
/* put out a message for bad zipcodes */
else if (&uniquevar ^=. and x=.) then do; /* couldn't find zipcode*/
put "WARNING: Check zipcode " zip " because it wasn't located.";
end;
run;
%mend;

/*----------------------------------------------------------------------*/
/* Create an annotate dataset with a randomized 'dot' a each location.  */
/* This simulates a dot-density map so that all dots at the same        */
/* location do not appear directly on top of each other.  The user      */
/*                                                                      */
/* Arguments:                                                           */
/* indata= input dataset; outdata= output dataset;                      */
/* spread= offset from center point in any direction.                   */
/* dotsize= size of dot for each value                                  */
/* color= color of dot;  idvar= variable to use in tooltip              */
/* Notes:  Dotsize and spread must change depending on the scale of the */
/*         Map, whether you are using degrees or radians and            */
/*         the number of items you are showing. The dot size may also   */
/*         vary between different types of output (eg, Gif, Java, actx) */
/* Warning:  Dot-density maps (or dot maps) are not 'accurate' because  */
/* of the random nature of the map and only show patterns.  Accuracy is */
/* better when you are showing a smaller area and fewer items.          */
/*----------------------------------------------------------------------*/
data &outdata;
set &indata;
length function style color \$ 8 position \$ 1 text \$ 20 html \$1024;
retain xsys ysys '2' hsys '3' when 'a' text '' ;
retain rotate 360 style 'solid' function 'pie' position '5';
anno_flag=1; /*so we can separate the datasets later*/
color=&color;
size=&dotsize;

/* create randomness around centroid so you can see more than one dot*/

/* Create a tool-tip for the dot */
html=
'alt='||
quote(
"&idvar : "||trim(left(&idvar))||' '
);
output;
run;
%mend;

/***********************************************************************/
/* Match zipcodes to an x,y location                                   */
/***********************************************************************/

/***********************************************************************/
/* Create a 'dot-density' annotate dataset                             */
/***********************************************************************/
%dot_density(zipxy,dotanno,.0001,.1,'red',zip);

/***********************************************************************/
/* Reduce the size of the actual map data.                             */
/***********************************************************************/
proc greduce data=maps.counties out=work.states;
id state;
run;

/************************************************************************/
/* Keep only 3 counties in NC                                           */
/************************************************************************/
proc sql;
create table work.states as select * from work.states
where fipstate(state) EQ ('NC')
and (county=183 or county=85 or county=101)
and density < 4
;
quit; run;

/***********************************************************************/
/* Combine the map and annotate Data to project it the same.           */
/* Then split it apart again for display.                              */
/***********************************************************************/
data work.combined; /* combine data*/
set work.states dotanno;
run;
/*project both datasets*/

proc gproject data=work.combined out=work.combined dupok;
id state;
run;

/*split the data*/
data work.states dotanno;
set work.combined;
if anno_flag=1 then output dotanno;
else output work.states;
run;

/* ---------------------------------------------------------*/
/* Declare a macro to do the plot, for the specified device */
/* ---------------------------------------------------------*/
%macro do_map(dev);

GOPTIONS DEVICE=&dev;
ODS LISTING CLOSE;
ODS HTML path=odsout body="&name._&dev..html"
parameters=('DataTipHighlightColor'='#00ff00')   /* color of outline when you mouse over an area in javameta */
style=statistical
;

pattern v=s c=CXE9E8DC r=100;
goptions border;

goptions htitle=2.75 htext=1.3;
Title 'Dot-density Map of Flu Outbreak by Zipcode';

proc gmap data=work.states map=work.states anno=work.dotanno;
id county;
choro county / coutline=black name="&name" nolegend;
run;
quit;

ODS HTML CLOSE;
ODS LISTING;

%mend do_map;
/* ---------------------------------------------------------*/

/***********************************************************************/
/* Run GMAP do 'display' the map.                                      */
/* Call the macro, for each desired 'device' type                      */
/***********************************************************************/
%do_map(gif);

/*
%do_map(javameta);
%do_map(java);
%do_map(activex);
%do_map(javaimg);
%do_map(actximg);
*/

SAS Employee
Posts: 989

## Re: Generate a different number of random (or evenly distributed ) dots in every polygons of a map?

I experimented with an algorithm similar to this for creating dot maps. If I recall, using 'proc ginside' to determine whether the random points were inside the map area/polygon was a bit slow ... but it could be done. See the 2 samples with the word 'density' in this set of examples:

SAS Employee
Posts: 989

## Re: Generate a different number of random (or evenly distributed ) dots in every polygons of a map?

For the US, I generated a dot map with a look similar to the original one you showed, by using the centroids of the census block map to position my dots, and then plotted the dots on a higher-level map (in the case, county borders):

Solution
‎08-20-2014 10:09 AM
SAS Employee
Posts: 170

## Re: Generate a different number of random (or evenly distributed ) dots in every polygons of a map?

You should look at the MAP papers on http://support.sas.com/rnd/papers/.

At this location, there are several papers.

Papers from SUGI 29.

Title: Tips and Tricks II.  Getting the most from your SAS/GRAPH maps.

SAS Presentations at SAS Global Forum 2011.

Title: Outbreak Maps: Visually Discovering Your Data.

Frequent Contributor
Posts: 96

## Re: Generate a different number of random (or evenly distributed ) dots in every polygons of a map?

Thanks everyone for the replies.  It often is a question of knowing what to look for. I 'm looking for "dot density" graph.

I'll try the %centroid and alpha-transparancy approach that Robert's use in his North Carolina map first, and if it doesnt look good I'll see what happens when I place the dots randomly instead of overlapping them.

I had read Tips and Trick 3 and 4, but hadnt gone all the way to 2.  I'll just read all of them and be done with it.  Thanks for the link to "outbreak maps" too!

S.

Frequent Contributor
Posts: 96

## Re: Generate a different number of random (or evenly distributed ) dots in every polygons of a map?

Just wantedo to say that I've managed to produce something with 1-dot per person at the city level.

This probably wont work for a more zoomed-out approach, it which case I'll probably use Robert's approach of alpha-transparency.

The code.  There is a lot of copy paste from Robert's multiple examples.

The required CSV file  for population by area

The output.

thanks for the help!

🔒 This topic is solved and locked.