The “Heat Map” Scenario

Have you ever looked at a table of data and wondered if there was a better way to represent the data, so as to better judge the impact of the information?

The technique of “Heat Mapping” is a common mechanism for visualizing data. According to Wikipedia:

A “heat map” (or heatmap) is a graphical representation of data where the individual values contained in a matrix are represented as colors [or shades of a color]. The term ‘heat map’ was originally coined and trademarked by software designer Cormac Kinney in 1991, to describe a 2D display depicting financial market information, though similar plots such as shading matrices have existed for over a century.

For example, this webpage contains a map of the United States and two tables of data (displayed vertically in the right page column). Clicking or tapping the map image on this page adds a map of the United States to the current OmniGraffle canvas, and clicking or tapping each table will transfer data from the table to the map on the current canvas.

This kind of interactivity enables a workflow that really shows off OmniGraffle‘s ability to visualize data! And best of all, the techniques demonstrated on this webpage work on both macOS and iOS. Here’s the workflow using OmniGraffle for macOS:

*Example webpage shown in the video above

Adding Stencil Content to the Current Canvas

In this example, each of the states in a map of the U.S. are colorized with a shade indicating the percentage that Federal tax revenue comprises of each state’s budget. To visualize the data from the provided tables, two instances of the USA map will be added to the document, each on its own canvas.

To add an instance of the map to the current canvas, the user taps or clicks the map image on the webpage. This simple user-action triggers the running of an Omni Automation script embedded in the webpage that automatically imports the contents of the previously installed USA Map stencil to the current document canvas.

usa-map

The Omni Automation script shown below, performs the task of checking for the stencil and then duplicating all of the stencil items (states) to the current canvas in OmniGraffle.

omnigraffle:///omnijs-run?script=function%20importAllGraphicsFromNamedStencil%28stencilName%2CstencilURL%29%7B%0A%09if%20%28stencilURL%20%3D%3D%20null%29%7BstencilURL%20%3D%20%27https%3A%2F%2Fstenciltown%2Eomnigroup%2Ecom%27%7D%0A%09var%20installed%20%3D%20false%0A%09for%28i%20%3D%200%3B%20i%20%3C%20app%2Estencils%2Elength%3B%20i%2B%2B%29%20%7B%0A%09%09var%20stencil%20%3D%20app%2Estencils%5Bi%5D%3B%0A%09%09if%20%28stencil%2Ename%2ElocaleCompare%28stencilName%29%20%3D%3D%200%29%20%7B%0A%09%09%09cnvs%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Ecanvas%0A%09%09%09stencil%2Eload%28function%28s%29%20%7B%0A%09%09%09%09console%2Elog%28%22Loaded%20stencil%3A%20%E2%80%9C%22%20%2B%20s%2Ename%20%2B%20%22%E2%80%9D%22%29%0A%09%09%09%09cnvs%2Eduplicate%28s%2Egraphics%29%0A%09%09%09%7D%29%0A%09%09%09installed%20%3D%20true%0A%09%09%09break%0A%09%09%7D%0A%09%7D%0A%09if%20%28installed%20%3D%3D%20false%29%7B%0A%09%09var%20alert%20%3D%20new%20Alert%28%22MISSING%20STENCIL%22%2C%20%22The%20stencil%20%E2%80%9C%22%20%2B%20stencilName%20%2B%20%22%E2%80%9D%20is%20not%20installed%2E%5Cn%5CnDo%20you%20want%20to%20download%20it%20from%20StencilTown%3F%22%29%0A%09%09alert%2EaddOption%28%22Download%22%29%0A%09%09alert%2EaddOption%28%22Cancel%22%29%0A%09%09alert%2Eshow%28function%28result%29%7B%0A%09%09%09if%20%28result%20%3D%3D%200%29%7B%0A%09%09%09%09targetURL%20%3D%20URL%2EfromString%28stencilURL%29%0A%09%09%09%09targetURL%2Ecall%28function%28result%29%7B%7D%29%0A%09%09%09%7D%0A%09%09%7D%29%0A%09%7D%0A%7D%0AstencilURL%20%3D%20%27https%3A%2F%2Fstenciltown%2Eomnigroup%2Ecom%2Fstencils%2Fusa-map%2F%27%0AimportAllGraphicsFromNamedStencil%28%27USA%20Map%27%2C%20stencilURL%29
function importAllGraphicsFromNamedStencil(stencilName,stencilURL){ if (stencilURL == null){stencilURL = 'https://stenciltown.omnigroup.com'} var installed = false for(i = 0; i < app.stencils.length; i++) { var stencil = app.stencils[i]; if (stencil.name.localeCompare(stencilName) == 0) { cnvs = document.windows[0].selection.canvas stencil.load(function(s) { console.log("Loaded stencil: “" + s.name + "”") cnvs.duplicate(s.graphics) }) installed = true break } } if (installed == false){ var alert = new Alert("MISSING STENCIL", "The stencil “" + stencilName + "” is not installed.\n\nDo you want to download it from StencilTown?") alert.addOption("Download") alert.addOption("Cancel") alert.show(function(result){ if (result == 0){ targetURL = URL.fromString(stencilURL) targetURL.call(function(result){}) } }) } } stencilURL = 'https://stenciltown.omnigroup.com/stencils/usa-map/' importAllGraphicsFromNamedStencil('USA Map', stencilURL)

 01-27  This function imports all graphics from the stencil whose name is passed to the handler.

 02  If the passed-in value for the stencil download URL is null, then set it to the URL for the StencilTown website.

 04-15  Check each of the installed stencils to see if it is the one whose name was passed-into the handler.

 08-11  If the stencil name is a match, use the load() method to open the stencil file and duplicate its graphics to the current canvas.

 16-26  If the passed stencil name was not matched any of the installed stencils, alert the user and give them the option to visit the StencilTown website.

 27  The URL string for the USA Map stencil on the StencilTown website.

 28  Call the function and pass-in the name of the stencil and its corresponding download URL.

To make the script executable from the webpage, it is encoded into an Omni Automation URL that is used as the target (href) of an HMTL link encasing the image object in the webpage’s HTML code. The script is then triggered when the user taps or clicks the image.

It’s an effortless way to add a specific map to a document, triggered from a webpage. Try it yourself by tapping or clicking the USA Map image above.

Table Data Export and Heat Mapping

Once an instance of the USA Map stencil has been placed on the current cavas in OmniGraffle by the embedded automation, the next challenge is to colorize the map using the data from either of the data tables on this page.

This involves a multi-step process of:

To enable their data to be “extracted” by webpage JavaScripts, each of the data tables is assign a unique identifier and its elements (rows and column cells) are assigned keys and values that make them and their components accessible to script queries.

NOTE: the name of each table row is a U.S. postal code that corresponds to the tag assigned to one of the stencil graphics. These postal codes act as unique identifiers that enable the formatting scripts to match data to objects in OmniGraffle.

<table class="data-table"> <tBody id="fedAidPerStateRev2000"> <tr name="AL"> <td name="state" class="state">Alabama</td> <td name="data" class="data">33.6</td> </tr> </tBody> </table>

Here is the main JavaScript function embedded in the webpage that performs the series of steps listed before. It is trigger when the user taps or clicks the OmniGraffle icon at the top right of either table.

function extractAndMapData(tableID){ tableData = getTableData(tableID); scriptDiv = document.getElementById(tableID + 'Code'); scriptCode = scriptDiv.innerHTML; text = encodeURIComponent(tableData); scriptCode = scriptCode.replace("XXXXX",tableData); var targetURL = "omnigraffle://localhost/omnijs-run?script=" + scriptCode; window.location = targetURL; }

 01-09  This embedded JavaScript function extracts table data, inserts the data into the encoded Omni Automation mapping script, and executes the encoded script URL. The function takes the id of the source table as a direct parameter.

 02  Passes the tableID to the getTableData() function to retrieve the data from the source table as a JSON string.

 03  References the hidden DIV that holds the encoded Omni Automation script code. The ID of the DIV is the ID of its corresponding table with the word “Code” appended to it.

 04  Extracts the Omni Automation script code from the DIV.

 05  Percent-encodes the JSON string containing the extracted table data.

 06  Replaces the placeholder “XXXXX” in the Omni Automation script with the encoded JSON data.

 07  Generates an Omni Automation script URL by concatenating the URL opening with the edited script code.

 08  Executes the Omni Automation script URL.

Next, let’s examine how the data is extracted from the tables.

Extract Table Data Function

The JavaScript code used to extract table data is the standard JavaScript implementation used with HTML web pages. There are no 3rd-party libraries or frameworks used.

The JavaScript function is passed the ID of the target table, which it then uses to iterate the table rows and extract the data and add it to standard JSON objects.

function getTableData(tableID){ var table = document.getElementById(tableID); tableData = new Array(); for (var r = 0, n = table.rows.length; r < n; r++) { rowData = new Object(); rowName = table.rows[r].getAttribute('name'); if (rowName != ""){ rowData.id = rowName; for (var c = 0, m = table.rows[r].cells.length; c < m; c++) { cellName = table.rows[r].cells[c].getAttribute('name'); cellData = table.rows[r].cells[c].innerHTML; rowData[cellName] = cellData; } tableData.push(rowData); } } return JSON.stringify(tableData); }

The result of the function is a JSON array of objects containing the data for every row in the targeted table.

[{"id":"AL","state":"Alabama","data":"33.6"},{"id":"AK","state":"Alaska","data":"16.3"},{"id":"AZ","state":"Arizona","data":"26.9"},{"id":"AR","state":"Arkansas","data":"29.7"},{"id":"CA","state":"California","data":"24.8"},{"id":"CO","state":"Colorado","data":"25.4"},{"id":"CT","state":"Connecticut","data":"20.9"},{"id":"DE","state":"Delware","data":"18.2"},{"id":"FL","state":"Florida","data":"23.8"},{"id":"GA","state":"Georgia","data":"27.4"},{"id":"HI","state":"Hawaii","data":"19.6"},{"id":"ID","state":"Idaho","data":"25.5"},{"id":"IL","state":"Illinois","data":"23.9"},{"id":"IN","state":"Indiana","data":"25.4"},{"id":"IA","state":"Iowa","data":"26.6"},{"id":"KS","state":"Kansas","data":"27.6"},{"id":"KY","state":"Kentucky","data":"29.5"},{"id":"LA","state":"Louisiana","data":"31.8"},{"id":"ME","state":"Maine","data":"29.3"},{"id":"MD","state":"Maryland","data":"22.4"},{"id":"MA","state":"Massachusetts","data":"19.8"},{"id":"MI","state":"Michigan","data":"23.2"},{"id":"MN","state":"Minnesota","data":"20.9"},{"id":"MS","state":"Mississippi","data":"34.8"},{"id":"MO","state":"Missouri","data":"31.6"},{"id":"MT","state":"Montana","data":"33.9"},{"id":"NE","state":"Nebraska","data":"27.0"},{"id":"NV","state":"Nevada","data":"18.2"},{"id":"NH","state":"New Hampshire","data":"25.7"},{"id":"NJ","state":"New Jersey","data":"22.7"},{"id":"NM","state":"New Mexico","data":"27.0"},{"id":"NY","state":"New York","data":"30.9"},{"id":"NC","state":"North Carolina","data":"29.0"},{"id":"ND","state":"North Dakota","data":"34.8"},{"id":"OH","state":"Ohio","data":"27.2"},{"id":"OK","state":"Oklahoma","data":"27.5"},{"id":"OR","state":"Oregon","data":"32.8"},{"id":"PA","state":"Pennsylvania","data":"25.2"},{"id":"RI","state":"Rhode Island","data":"26.6"},{"id":"SC","state":"South Carolina","data":"30.4"},{"id":"SD","state":"South Dakota","data":"34.2"},{"id":"TN","state":"Tennessee","data":"37.5"},{"id":"TX","state":"Texas","data":"29.9"},{"id":"UT","state":"Utah","data":"24.4"},{"id":"VT","state":"Vermont","data":"29.8"},{"id":"VA","state":"Virginia","data":"19.0"},{"id":"WA","state":"Washington","data":"24.0"},{"id":"WV","state":"West Virginia","data":"33.6"},{"id":"WI","state":"Wisconsin","data":"21.9"},{"id":"WY","state":"Wyoming","data":"35.8"}]

To enable the JSON data to be inserted into the Omni Automation script that performs the action with the OmniGraffle document, the last statement in the extraction function converts the JSON array of objects into a JSON string using the JSON.stringify() method.

Transfer Data (Mapping)

Here is the Omni Automation script that performs the task of matching data with graphics in the OmniGraffle document. In order to be available for execution by the main JavaScript webpage function, it is encoded and placed within a hidden DIV on the webpage. Here is the script unencoded:

blob = 'XXXXX' jblob = JSON.parse(blob) jblob.forEach(function(item){ aValue = Number(item.data) if (aValue < 20){ aColorValue = Color.RGB(0,1,0,1) } else if (aValue < 23){ aColorValue = Color.RGB(0,0.9,0,1) } else if (aValue < 26){ aColorValue = Color.RGB(0,0.8,0,1) } else if (aValue < 29){ aColorValue = Color.RGB(0,0.7,0,1) } else if (aValue < 31){ aColorValue = Color.RGB(0,0.6,0,1) } else if (aValue < 34){ aColorValue = Color.RGB(0,0.5,0,1) } else if (aValue < 37){ aColorValue = Color.RGB(0,0.4,0,1) } else if (aValue < 40){ aColorValue = Color.RGB(0,0.3,0,1) } else { aColorValue = Color.RGB(0,0.2,0,1) } aGraphic = document.windows[0].selection.canvas.graphicWithName(item.id) aGraphic.fillColor = aColorValue aGraphic.notes = item.state + ': ' + item.data })

 01  When this function is called by the main extractAndMapData() function, the placeholder XXXXX is replaced with the encoded JSON data string.

 02  The JSON string is converted into a JSON object array using the parse() method.

 03-27  Process each object in the JSON object array using the forEach() method.

 04  Get the object’s data value as a number.

 05-23  Create a color value based upon the data value.

 24  Use the graphicWithName() method to identify the target graphic by passing it the value of the object’s id property. This value will match one of the names of the state graphics, which in this case, is the postal abbreviation for a state, like MA for Massachusetts.

 25  Assign the color value to the graphic’s fillColor property.

 26  Set the value of the graphic’s notes property to the value of the object’s state and data properties.

To be available for use, the script is encoded and placed within a hidden DIV whose ID matches the ID of its corresponding source table.

Works on iPad Pro Too!

And the best part is that Omni Automation is dual platform: macOS and iOS. See for yourself!

blob%20%3D%20%27XXXXX%27%0Ajblob%20%3D%20JSON%2Eparse%28blob%29%0Ajblob%2EforEach%28function%28item%29%7B%0A%09aValue%20%3D%20Number%28item%2Edata%29%0A%09if%20%28aValue%20%3C%2020%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C1%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2023%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E9%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2026%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E8%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2029%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E7%2C0%2C1%29%20%09%20%20%0A%09%7D%20else%20if%20%28aValue%20%3C%2031%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E6%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2034%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E5%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2037%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E4%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2040%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E3%2C0%2C1%29%09%0A%09%7D%20else%20%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E2%2C0%2C1%29%0A%09%7D%0A%09aGraphic%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Ecanvas%2EgraphicWithName%28item%2Eid%29%0A%09aGraphic%2EfillColor%20%3D%20aColorValue%0A%09aGraphic%2Enotes%20%3D%20item%2Estate%20%2B%20%27%3A%20%27%20%2B%20item%2Edata%0A%7D%29
2000OmniGraffle-iOS-1024
Alabama33.6
Alaska16.3
Arizona26.9
Arkansas29.7
California24.8
Colorado25.4
Connecticut20.9
Delware18.2
Florida23.8
Georgia27.4
Hawaii19.6
Idaho25.5
Illinois23.9
Indiana25.4
Iowa26.6
Kansas27.6
Kentucky29.5
Louisiana31.8
Maine29.3
Maryland22.4
Massachusetts19.8
Michigan23.2
Minnesota20.9
Mississippi34.8
Missouri31.6
Montana33.9
Nebraska27.0
Nevada18.2
New Hampshire25.7
New Jersey22.7
New Mexico27.0
New York30.9
North Carolina29.0
North Dakota34.8
Ohio27.2
Oklahoma27.5
Oregon32.8
Pennsylvania25.2
Rhode Island26.6
South Carolina30.4
South Dakota34.2
Tennessee37.5
Texas29.9
Utah24.4
Vermont29.8
Virginia19.0
Washington24.0
West Virginia33.6
Wisconsin21.9
Wyoming35.8
blob%20%3D%20%27XXXXX%27%0Ajblob%20%3D%20JSON%2Eparse%28blob%29%0Ajblob%2EforEach%28function%28item%29%7B%0A%09aValue%20%3D%20Number%28item%2Edata%29%0A%09if%20%28aValue%20%3C%2020%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C1%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2023%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E9%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2026%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E8%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2029%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E7%2C0%2C1%29%20%09%20%20%0A%09%7D%20else%20if%20%28aValue%20%3C%2031%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E6%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2034%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E5%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2037%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E4%2C0%2C1%29%0A%09%7D%20else%20if%20%28aValue%20%3C%2040%29%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E3%2C0%2C1%29%09%0A%09%7D%20else%20%7B%0A%09%09aColorValue%20%3D%20Color%2ERGB%280%2C0%2E2%2C0%2C1%29%0A%09%7D%0A%09aGraphic%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Ecanvas%2EgraphicWithName%28item%2Eid%29%0A%09aGraphic%2EfillColor%20%3D%20aColorValue%0A%09aGraphic%2Enotes%20%3D%20item%2Estate%20%2B%20%27%3A%20%27%20%2B%20item%2Edata%0A%7D%29
2013OmniGraffle-iOS-1024
Alabama34.9
Alaska26.9
Arizona35.9
Arkansas33.5
California26.0
Colorado29.1
Connecticut24.6
Delware26.7
Florida33.2
Georgia36.7
Hawaii24.8
Idaho33.8
Illinois26.8
Indiana33.0
Iowa32.6
Kansas25.5
Kentucky38.5
Louisiana40.1
Maine36.6
Maryland29.4
Massachusetts27.8
Michigan32.3
Minnesota25.5
Mississippi40.9
Missouri38.0
Montana39.1
Nebraska31.0
Nevada24.8
New Hampshire28.1
New Jersey27.3
New Mexico34.5
New York32.8
North Carolina32.7
North Dakota16.8
Ohio35.0
Oklahoma34.0
Oregon36.0
Pennsylvania30.8
Rhode Island34.7
South Carolina30.7
South Dakota37.2
Tennessee39.9
Texas31.8
Utah28.1
Vermont33.6
Virginia22.8
Washington29.2
West Virginia34.8
Wisconsin27.8
Wyoming35.5