We’re smarter together. Learn from this collection of community knowledge and add your expertise.

Mapping with SAS University Edition and JavaScript - Introducing the Framework

by Super Contributor on ‎05-05-2017 09:42 AM (1,534 Views)

Introduction

 

You don’t have to look at too many infographics these days to realise that mapping is an important weapon in the data visualization armoury. Maps are used to display information about political events, weather, sporting achievement and just about any other subject you could think of. So, I was more than a little disappointed when I realised that SAS University Edition didn’t contain Proc Gmap. However, as a programmer, when I’m either told that something can’t be done or that the facility to do something isn’t contained in a product I see that as a challenge and so I set out to find another way to generate maps for my SAS projects. This series of articles will explore how to do just that using only SAS University Edition and “free for learning purposes” JavaScript products without having to be a JavaScript expert.

 

The JavaScript Framework

 

To achieve our aim, it will be necessary to select an appropriate JavaScript framework. The criteria I decided on were:

 

  1. The framework must have an extensive free component to be compatible with the ethos of SAS University Edition; and
  2. It must be available on a Content Delivery Network (CDN) meaning we would not have to set up and host it on our own web server; and
  3. There must be an extensive collection of free maps available which can be easily used with it

 

Having previously worked on web-based projects integrating SAS and JavaScript I was already familiar with a JavaScript charting framework called Highcharts and so it was helpful to discover that the same company which produces that also produces a mapping framework called Highmaps which met all the criteria including supplying hundreds of free maps which should prove sufficient for most purposes.

 

Our First Map

 

To demonstrate the process of mapping from SAS University Edition through Highcharts we will create a simple choropleth map displaying Gross Value Added (GVA) per head in each of the four constituent countries of the United Kingdom. GVA is a measurement of economic production linked to Gross Domestic Product (GDP). The map we will be using is the United Kingdom countries map from the maps collection page of the Highcharts web site.

 

Getting the Data Ready

 

Assuming we already have the data that we want to load into the map in a SAS Data Set we need to ensure that we have a variable that can link the geographical identifier in the Data Set with the geographical identifier in the map. We will achieve this by creating a custom format to apply to the Data Set. You can get the map identifiers for the supplied maps by following these steps:

 

  1. Go to the maps collection page on the Highcharts web site at http://code.highcharts.com/mapdata/ and select the JavaScript link against the map you want to use (Fig 1).
  2. This opens a web page showing the JavaScript which creates the map. The fields to search for are “name” which holds the plain English name of the area plus ”hc-key” which denotes the identifier associated with that area (Fig 2).
  3. The layout of the JavaScript means you must either search for these fields in your browser or load them into a “JavaScript beautifier” such as http://jsbeautifier.org which will reformat it to make it more easily readable.

 

Figure 1

 

Figure 1 - Maps Collection

 

Figure 2

 

Figure 2 - Map JavaScript

 

Now that we have the identifiers we will create a custom format which we will apply to the geographical field in the data set.  Here is the SAS code for the format we will use for the UK map (saved to the work library for convenience – in practice you may want to save this to a permanent formats library). This will achieve the desired link with the map.

 

 

proc format;
	value $gbcountries 'England'='gb-eng'
			   'Wales' = 'gb-wls'
			   'Scotland' = 'gb-sct'
			   'N Ireland' = 'gb-nir';
run;

 

Now that we have our format we can create the data for the map:

 

 

data countryGVA2015;
	length country $10;
	format country gbcountries.;
	infile datalines dlm=',';
	input country $ gva;
	datalines;
England,26159
Wales,18002
Scotland,23685
N Ireland,18584
;
run;

 

Highmaps, like most JavaScript frameworks, like it’s data to be in JavaScript Object Notation (JSON) format. Fortunately, SAS have given us a procedure to do that conversion. Here is the Proc JSON code we will use:

 

 

filename gva "/folders/myshortcuts/Dropbox/SAS and Highmaps/countrygva2015.json";

proc json out=gva pretty;
	export countryGVA2015 / nosastags nokeys fmtcharacter;
run;

 

In this call to Proc JSON the “pretty” option simply formats the output so it is easily readable, the “nosastags” and “nokeys” options suppress the output of SAS metadata and variable names in the output file. The “fmtcharacter” option ensures that the formatted value of any character variable is output to the file.

 

Drawing the Map

 

We now have a file containing the data we want to map – all that we need is a way to render it. To do this we will build an HTML file containing all the HTML, CSS and JavaScript code required plus the JSON file we have just created. The HTML, CSS and JavaScript are contained in the files init.html. and term.html which are attached to this post and will be merged into one file along with the JSON data  file by utilising Proc Stream. I won’t go into detail about the code in these files but there are a couple of things you will note if you look through them:

 

  1. The code contains SAS macro variables such as “&titletag” – these variables will be resolved when the complete file is built; and
  2. Each line is terminated by “&streamdelim newline;” - Proc Stream does not preserve line feeds and this can cause problems if an HTML tag is split across two lines in the output. By putting “&streamdelim newline;” at the end of each line we are forcing the procedure to start a new line at that point.

We are now ready to start drawing the map – the first thing we need to do is to declare some filerefs and then decide whether we want the colour scale to start at zero. In this case, all the values to be mapped are close in magnitude so if we start at zero it is likely that the colours will be close in value making it difficult to distinguish the differences. Therefore, we will get the smallest value in the file and round it down (in this case) to the nearest thousand and set that value to be the minimum of the scale.

 

 

filename myfile "/folders/myshortcuts/Dropbox/SAS and Highmaps/ukgva.html"; 
filename init "/folders/myshortcuts/Dropbox/SAS and Highmaps/Core/init.html"; 
filename term "/folders/myshortcuts/Dropbox/SAS and Highmaps/Core/term.html";

proc sql noprint;
	select min(gva) into :min
	from countryGVA2015;
quit;

%let min=%sysfunc(round(&min-500,1000));

 

 

We will now create a few macro variables for the values we want to substitute in the init.html and term.html files. These are self-explanatory except perhaps for mapfile which corresponds to the map file name in the Highmaps collection.

 

 

%let mapfile=countries/gb/custom/gb-countries;
%let titletag=UK GVA;
%let title=UK GVA Per Head 2015;
%let subtitle=United Kingdom;

 

Finally, we will run Proc Stream which, as its name implies, processes an input stream of text performing macro substitution and executing any SAS macros it finds in the text.

 

 

proc stream outfile=myfile prescol resetdelim='label' resetdelim="goto"; begin
goto; %include init;
goto newline;
goto; %include gva;
goto newline;
goto; %include term;
</html>
;;;;
run;

 

Essentially the three files we have created are run through the procedure one at a time performing macro substitution and stitching them together into one single file. All the files required are attached to this article (init.html and term.html have been renamed with .txt extensions for upload purposes).

 

The Output

 

The Proc Stream code we have run will generate an HTML file which you can open in a browser. A static image of it is in Figure 3 below. Here is a list of the features you get with this map:

 

  1. Tooltips on hover-over; and
  2. Zoom in and out buttons (you can also zoom by using the mouse); and
  3. The sub-area of the map you are pointing at with the mouse is highlighted in a different colour; and
  4. A legend at the bottom with an indicator which moves on hover-over of the sub-area; and
  5. A menu button at the top right of the map allowing you to either print the map or export it to png, jpeg, svg or pdf format.

 

Figure 3

Figure 3 - Final Map

 

Summary

 

We have seen how you can build a customisable map in SAS University Edition by utilising a JavaScript framework along with your SAS code. There are many more features you can add to your maps and in future articles I will be covering some of these.

 

If you have any features you would like to see demonstrated, any questions or any examples of maps you would like replicated please leave the details in the comments section below. I would love to hear from you!

Attachment
Comments
by Super User
on ‎05-05-2017 10:13 AM

Here is an example generated by UE.

Also you could check @Rick_SAS 's blog. there already are several bolg cover this topic.

 

http://blogs.sas.com/content/sastraining/2017/03/23/creating-heat-maps-with-proc-sgplot/

by Super Contributor
on ‎05-05-2017 10:32 AM

Thanks - I have seen Robert's blog post but the problem with his approach for me was that he used SAS supplied maps to extract the polygons for the map, which you can't use unless you have a licence covering you for Proc Gmap. I've also seen one of Rick's posts and he does the same thing. As I mention if you only have SAS UE you don't have the necessary licence.

by Super User
on ‎05-05-2017 10:51 AM

This is great! I look forward to testing it out with Canadian Census data this year. 

Any chance you're working on one to create a dynamic pivot chart? That's one that will be super popular and useful :)

by Super Contributor
on ‎05-05-2017 11:55 AM

Thanks Reeza - are you thinking of a Pivot Table with a linked chart that updates when you drill into the table? That would be a nice challenge!

by Community Manager
on ‎05-05-2017 12:55 PM

I think @DonH would be quite proud to see this PROC STREAM example.  He's a "SAS server pages" advocate!

by Super User
on ‎05-05-2017 12:55 PM

@ChrisBrooks I was thinking of implementing this javascript package and using a SAS macro to pass the parameters to set it up.

Pretty similar to the map one above but dynamic. It may be possible to embed the javascript library and everything into an HTML5 page to allow it to work even without network connectivity, so I could send an email from SAS with the file attached and anyone who receives it can work with the file automatically. It's a big project that I've only gotten a very small way down so far...but I have a lot of 'little' side projects like this on the go :)

 

 

by Regular Contributor
on ‎05-05-2017 03:42 PM

Spot-On ChrisH. And Kudos to Rick Langston for creating PROC STREAM. His additions to my original set of requirements made this a much more robust tool.

by Super Contributor
on ‎05-05-2017 04:54 PM

 @Reeza Yes you're right about using macros to set up the output - I just wanted to show as simple an example as possible for the first article on this technique. In future articles I plan to show how you can make the map more dynamic, use macros to build the HTML file and do some other really nice stuff :smileyhappy:

 

I think your idea of completely embedding the framework in the HTML file is technically possible but I'd be a little concerned about file size particularly as this particular framework (like many others) is dependent on jQuery so you'd have to embed that as well.

by Super User
on ‎05-06-2017 07:18 AM

If you have longtitude and latitude , you could also get map by UE.

Maybe you could download it from internet .

 

Check

http://blogs.sas.com/content/iml/2017/01/06/la-quinta-next-to-dennys.html

 

especially this part of code:

data US;
   set maps.states;
   where State NOT IN (2, 15, 72) AND Density < 4; /* AK, HI, PR */
   by State Segment;
   if first.Segment then PolyID+1;    /* create ID variable for polygons */
   Long = -180 / constant("pi") * X; /* convert radians to degrees West */
   Lat  =  180 / constant("pi") * Y; /* convert radians to degrees */
   keep State Segment Long Lat PolyID;
run;
Contributors
Your turn
Sign In!

Want to write an article? Sign in with your profile.


Looking for the Ask the Expert series? Find it in its new home: communities.sas.com/askexpert.