Assessment of my Interface and Information Design subject this semester required that we create a Multitouch interactive graphic which promoted social change. This post will detail that process from beginning to end.
Choosing an Area of Interest/Gathering Data:
The direction of the assignment was fairly broad, as far as content material goes. Whilst it had to be persuasive, and it had to be designed for a touch screen, it was otherwise quite open ended. Eventually, I settled on the rather fascinating question of how we go about dying. Whilst everyone will, eventually, most of us rather try and avoid it, with the unintended side affect that no one really knows, off the top of their head, what’s killing us. I headed to google and punched in ’causes of death,’ which led me almost immediately to The Australian Bureau of Statistics. They had compiled, from 1999-2009 the way every person who had expired in the last year. They’d also grouped them into categories (different types of cancer, external causes etc). You can find that spreadsheet on their website here; http://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/3303.02009?OpenDocument.
Identifying Inspirational Works
There’s a lot of really good examples of information design around the internet, and it comes in all shapes and sizes. I’d seen We Feel Fine back when it first launched, and was suitably impressed. They’d done some work since then, so I had another play when we were shown it in the lecture. It was even better than when it first launched – clean and tidy, yet allows you to drill down for really detailed looks at specific feelings or areas. I’d also long followed the work of The Oatmeal. While technically a webcomic, many of the strips take the form of (static) infographics, such as this one – a quick guide to diagnosing a computer.
Both of those where examples that I already knew of from my own experiences. GapMinder.org was unknown to me (though I vaguely remember seeing a TED talk from Hans Rosling at some point). The information design that they do tends to be less flashy than some other examples, but all the examples on that site (well worth looking at, if you’re interested), very clearly articulate the respective points they are trying to make.
Identifying an Assumption
Having already chosen to explore what was killing us, I began to focus on what I was wanting to show with the information graphic. It struck me that, perhaps as a correlation of our phobia of death – no one seemed to have any perspective on what killed us. While a death from drug overdose, violence or, heaven forbid, a celebrity, made the news, someone passing away in a hospital bed did not. A quick look of the numbers showed that what I believed was correct – infinetely more people expired from ‘natural’ causes, such as disease, than accidents or foul play. But I wanted to show this clearly, hopefully finally putting to rest every conversation that begins with, “You know, they say more people die from (x) than ever before)”
Substitute (x) for whatever’s been trending in the news lately, and you get uninformed drivel that sounds right, but really isn’t.
Developing a Use Case Scenario
We’d been told that the information graphic would be displayed on the yet-to-be-complete ‘Cube’ in the new Science and Technology Precinct, and that it would be open to the public. As such, I decided that it would be best to avoid using horrifying imagery, and animated sequences of Death cutting people’s head’s off with a Scythe. I elected for a light, bright colour scheme and stick figures to represent the categories of dead people. The idea was for people of all ages to see this, play around with it a little and come away a *little* better educated on what was killing us all. It didn’t have to tell them anything much more complicated, as that would probably just bounce anyway. I believed, for a public display, the simpler the better.
Developing an Interface
In case there were any trends on certain types of death being more popular in given years, I decided to use a timeline slider, to give people the ability to scroll through the given data. I also had a though to include some tickboxes – if someone just wanted to see people that had been killed versus the people that had died in accidents, they should be allowed to.
I also had a thought that I wanted this to be seen as a crowd of people, rather than a few people representing by their scale or position the rest. This resulted in an initial mockup that looked like this.
In order to find out what the person had died from, the idea was that you dragged a man into a circle in the middle, and more information would come up – kind of like a magnifying glass. I then thought to make better use of the multitouch capabilities, and make each ‘person’ expandable with a two fingered anti-pinch gesture, allowing the user to see information that had been recorded on him the whole time.
That, when I pushed it into flash and got it (mostly) working, looked like this:
Unfortunately, there where a few key things that DIDN’T work:
- It was supposed to scale up – deselecting ‘disease’ should put more men on the screen.
- I couldn’t remove old ‘people’ from the stage – no, its not ageism. There was a way to do it, but I ran out of time to find it. This broke both the timeline slider and the check boxes.
- It wasn’t displaying anywhere near enough people, and if it was, it wasn’t displaying them big enough. Something was wrong with my math, and despite calling in some outside help for the formulas, I couldn’t figure out what.
- The visible properties of the men didn’t seem to keen on changing – this broke both the timeline slider and the checkboxes
- The scaleamount was supposed to adjust according to what was on the screen – again, this wasn’t working.
- The man had a text label above his head (currently statically set to Example COD)* which was supposed to give the name of the disease he was dying from. Unfortunately, this didn’t work either.
- Resizing the men was a much more powerful visual tool than my initial idea of using a swarm
- There is a lot less complexity in the code (at least 3 less arrays, less calls back to the Arrays), and it performs much better for that.
- Because of the above, its a lot easier to code – if I had an additional day, I could probably get the bugs out – but alas, I’m out of time.
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.net.URLRequest;
import flash.display.Sprite;
import com.shortybmc.data.parser.CSV;
import flash.events.MouseEvent;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import fl.transitions.Tween;
import fl.transitions.easing.*;
import fl.transitions.TweenEvent;
import fl.events.SliderEvent;
import flash.display.IBitmapDrawable;
public class Main extends MovieClip
{
//A variable to hold the CSV file
var csv:CSV;
//an array for the number of deaths in all years
var totalDeaths:Array;
//For pointing to the appropriate part of the array/CSV file
var startIndex:int;
var rowLength:int = 44;
//For pointing to the right year
var thisYear:int = 2003;
//ScaleAmount (used later when drawing)
var scaleAmount:Number = 0.01;
//create an array to store the dead men from this year
var deadMen:Array = new Array;
public function Main()
{
//Import the CSV File
csv = new CSV(new URLRequest('../data/causes_of_death.csv'));
//EVENT LISTENERS
//When the data has loaded in, extract the useful parts
csv.addEventListener(Event.COMPLETE, completeHandler);
this.TimelineSlider.addEventListener(Event.CHANGE, TimelineUpdater);
} //Close off the main function
function completeHandler(e:Event)
{
trace("completeHandler has executed"); //debugging
//Set the TimelineSlider somewhere aesthetically pleasing
TimelineSlider.value = 2003;
//set the start index (year 2003)
this.startIndex = 20; //Column 21
//Read in the data from the spreadsheet, to save having to do it every time slider moves (big performance hit)
readCSV();
//give focus to the timeline slider
stage.focus = TimelineSlider
//Add the event listeners we weren't ready for yet
//Checkbox Event Listeners
this.ChAccident.addEventListener(MouseEvent.CLICK, setFilter);
this.ChFoulPlay.addEventListener(MouseEvent.CLICK, setFilter);
this.ChDisease.addEventListener(MouseEvent.CLICK, setFilter);
//Do the Initial update
update()
trace("completeHandler has stopped executing"); //debugging
}
function setFilter(e:Event)
{
//Make all the dead people visible by default, if this is their year
for (var i in this.deadMen)
{
if(deadMen[i].inYear == thisYear)
{
deadMen[i].visible = true;
}
}
//reset the scale amount
scaleAmount = .01;
//If the Filter is NOT selected, set its variable to false (used later by the update function)
if(this.ChAccident.selected == false)
{
trace("filterAccident = false");
for(i in this.deadMen)
{
if(deadMen[i].COD == "accident")
{
deadMen[i].visible == "false";
}
}
}
if(this.ChFoulPlay.selected == false)
{
trace("filterFoulPlay = false");
for(i in this.deadMen)
{
if(deadMen[i].COD == "foulplay")
{
deadMen[i].visible == "false";
}
}
}
if(this.ChDisease.selected == false)
{
trace("filterDisease = false");
//no need to be so skingy with the scale amount if this is deselected
scaleAmount = .5;
for(i in this.deadMen)
{
if(deadMen[i].COD == "disease")
{
deadMen[i].visible == "false";
}
}
}
update();
}
function TimelineUpdater(e:Event)
{
//Each additional year from 1999 is 4 over from the index of 5;
//Get the TimelineSlider, and adjust the index accordingly.
switch(TimelineSlider.value)
{
case 1999:
startIndex = 4;
thisYear = 1999;
trace("StartIndex = 4");
break;
case 2000:
startIndex = 8;
thisYear = 2000;
trace("StartIndex = 8");
break;
case 2001:
startIndex = 12;
thisYear = 2001;
trace("StartIndex = 12");
break;
case 2002:
startIndex = 16;
thisYear = 2002;
trace("StartIndex = 16");
break;
case 2003:
startIndex = 20;
thisYear = 2003;
trace("StartIndex = 20");
break;
case 2004:
startIndex = 24;
thisYear = 2004;
trace("StartIndex = 24");
break;
case 2005:
startIndex = 28;
thisYear = 2005;
trace("StartIndex = 28");
break;
case 2006:
startIndex = 32;
thisYear = 2006;
trace("StartIndex = 32");
break;
case 2007:
startIndex = 36;
thisYear = 2007;
trace("StartIndex = 36");
break;
case 2008:
startIndex = 40;
thisYear = 2008;
trace("StartIndex = 40");
break;
case 2009:
startIndex = 44;
thisYear = 2009;
trace("StartIndex = 44");
break;
}
update();
}
function readCSV()
{
//Arrays for search terms, to do the classification
var keyDisease:Array;
var keyFoulPlay:Array;
var keyAccident:Array;
//Fill the search terms to use later
keyDisease = ["CHAPTER I Certain infectious and parasitic diseases (A00-B99)", "CHAPTER II Neoplasms (C00-D48)",
"CHAPTER III Diseases of the blood and blood-forming organs and certain disorders involving the immune mechanism (D50-D89)",
"CHAPTER IV Endocrine, nutritional and metabolic diseases (E00-E90)", "CHAPTER V Mental and behavioural disorders (F00-F99)",
"CHAPTER VI Diseases of the nervous system (G00-G99)", "CHAPTER VII Diseases of the eye and adnexa (H00-H59)",
"CHAPTER VIII Diseases of the ear and mastoid process (H60-H95)", "CHAPTER IX Diseases of the circulatory system (I00-I99)",
"CHAPTER X Diseases of the respiratory system (J00-J99)", "CHAPTER XI Diseases of the digestive system (K00-K93)",
"CHAPTER XII Diseases of the skin and subcutaneous tissue (L00-L99)", "CHAPTER XIII Diseases of the musculoskeletal system and connective tissue (M00-M99)",
"CHAPTER XIV Diseases of the genitourinary system (N00-N99)", "CHAPTER XVI Certain conditions originating in the perinatal period (P00-P96)",
"CHAPTER XVII Congenital malformations, deformations and chromosomal abnormalities (Q00-Q99)"]
keyAccident = ["CHAPTER XV Pregnancy, childbirth and the puerperium (O00-O99)",
"CHAPTER XVIII Symptoms, signs and abnormal clinical and laboratory findings, not elsewhere classified (R00-R99)",
"Transport accidents (V01-V99)", "Other land transport accidents (V80-V89)", "Falls (W00-W19)", "Exposure to inanimate mechanical forces (W20-W49)",
"Exposure to animate mechanical forces (W50-W64)", "Accidental drowning and submersion (W65-W74)", "Other accidental threats to breathing (W75-W84)",
"Exposure to electric current, radiation and extreme ambient air temperature and pressure (W85-W99)", "Contact with heat and hot substances (X10-X19)",
"Contact with venomous animals and plants (X20-X29)", "Exposure to forces of nature (X30-X39)",
"Accidental poisoning by and exposure to noxious substances (X40-X49)", "Overexertion, travel and privation (X50-X57)",
"Exposure to other specified factors (X58)", "Exposure to unspecified factor (X59)", "Complications of medical and surgical care (Y40-Y84)",
"Sequelae of transport accidents (Y85)", "Sequelae of other accidents (Y86)",
"Supplementary factors related to causes of morbidity and mortality classified elsewhere (Y90-Y98)", "Nosocomial condition (Y95)",
"Work-related condition (Y96)", "Lifestyle-related condition (Y98)"]
keyFoulPlay = ["Handgun discharge (W32)", "Rifle, shotgun and larger firearm discharge (W33)", "Discharge from other and unspecified firearms (W34)",
"Hit, struck, kicked, twisted, bitten or scratched by another person (W50)", "Striking against or bumped into by another person (W51)",
"Crushed, pushed or stepped on by crowd or human stampede (W52)", "Exposure to smoke, fire and flames (X00-X09)", "Intentional self-harm (X60-X84)(f)",
"Assault (X85-Y09)", "Event of undetermined intent (Y10-Y34)", "Legal intervention and operations of war (Y35-Y36)",
"Sequelae of intentional self-harm, assault and events of undetermined intent (Y87)", "Sequelae with surgical and medical care as external cause (Y88)",
"Sequelae of other external causes (Y89)", "Evidence of alcohol involvement determined by blood alcohol level (Y90)",
"Evidence of alcohol involvement determined by level of intoxication (Y91)", "Environmental-pollution-related condition (Y97)"]
//keep track of the ManID
var ManID:int;
//Variables to store the information read from the CSV (so we only need to do it once)
var diseaseDeaths:Array = [];
var accidentalDeaths:Array = [];
var foulPlayDeaths:Array = [];
//For each entry found in the array, create a man
for(var i in keyDisease)
{
//For some reason, valid search keys return a null result sometimes. Searching by the row manually still works.
//For now, throwing in a if statement to catch null results (or it breaks things later)
if(csv.search(keyDisease[i], false) [0] != null)
{
//Get the array for the search result so we can create individual men for each year
var deadFromThis:Array = csv.search(keyDisease[i], false);
//trace(deadFromThis);
//Start at 4 (first index), increment by 3
for (var t:int = 4; t < deadFromThis[0].length; t = t+4)
{
deadMen.push(new Man(ManID, "disease", keyDisease[i], deadFromThis[0][t], t));
ManID = ManID + 1;
}
}
}
for(var i in keyAccident)
{
//For some reason, valid search keys return a null result sometimes. Searching by the row manually still works.
//For now, throwing in a if statement to catch null results (or it breaks things later)
if(csv.search(keyAccident[i], false) [0] != null)
{
//Get the array for the search result so we can create individual men for each year
var deadFromThis:Array = csv.search(keyAccident[i], false);
//trace(deadFromThis);
//Start at 4 (first index), increment by 3
for (var t:int = 4; t < deadFromThis[0].length; t = t+4)
{
deadMen.push(new Man(ManID, "accident", keyAccident[i], deadFromThis[0][t], t));
ManID = ManID + 1;
}
}
}
for(var i in keyFoulPlay)
{
//For some reason, valid search keys return a null result sometimes. Searching by the row manually still works.
//For now, throwing in a if statement to catch null results (or it breaks things later)
if(csv.search(keyFoulPlay[i], false) [0] != null)
{
//Get the array for the search result so we can create individual men for each year
var deadFromThis:Array = csv.search(keyFoulPlay[i], false);
//trace(deadFromThis);
//Start at 4 (first index), increment by 3
for (var t:int = 4; t < deadFromThis[0].length; t = t+4)
{
deadMen.push(new Man(ManID, "foulplay", keyFoulPlay[i], deadFromThis[0][t], t));
ManID = ManID + 1;
}
}
}
trace(deadMen);
//Get the total deaths for all the years
var index = startIndex;
//trace(index); //debugging
totalDeaths = csv.search("Total deaths") [0];
//trace(totalDeaths[index]);
}
//fill the screen with little men
function update()
{
trace("update has started running"); //debugging
//Go through the array and spawn a man on the stage for each entry.
for(var i:String in deadMen)
{
var currentPerson:Man = deadMen[i];
trace(currentPerson)
currentPerson.update(scaleAmount);
//set the y position
currentPerson.y = stage.stageHeight - 500;
//Determine the x position
var newX:Number = (currentPerson.width/2) + Number(i) * ((stage.stageWidth - deadMen[deadMen.length-1].width - currentPerson.width)/(deadMen.length-1)) + (currentPerson.width/2);
//set the xposition
currentPerson.x = newX;
//add to the stage
this.addChild(currentPerson);
//send it to the back
setChildIndex(currentPerson, 0);
//set everyone to visible by default
currentPerson.visible = true;
//hide anyone that isn't dead in this year
if(currentPerson.inYear != thisYear)
{
trace("That person wasn't born this year");
currentPerson.visible = false;
}
trace("update has finished running"); //debugging
}
}
} //Close off the public class Main
}
Man.as
package
{
import flash.display.MovieClip;
public class Man extends MovieClip
{
public var id:int; // unique ID
public var COD:String; //The cause of death (kept uniform in the calling function)
public var diseaseName:String; //The detailed cause of death (infection, stabbity stabbing etc)
public var deadFromThis:int;
public var inYear:int;
public function Man(id:int, expiryReason:String, detailDeath:String, numberDead:int, thisYear:int)
{
// constructor code
this.id = id;
this.COD = expiryReason;
this.diseaseName = detailDeath;
this.deadFromThis = numberDead;
this.inYear = thisYear;
//Display what disease the man has
switch(COD)
{
case "disease":
gotoAndStop(3);
break;
case "accident":
gotoAndStop(2);
break;
case "foulplay":
gotoAndStop(1);
break;
}
//Get the index value and turn it into a year
switch(thisYear)
{
case 4:
inYear = 4;
break;
case 8:
inYear = 2000;
break;
case 12:
inYear = 2001;
break;
case 16:
inYear = 2002;
break;
case 20:
inYear = 2003;
break;
case 24:
inYear = 2004;
break;
case 28:
inYear = 2005;
break;
case 32:
inYear = 2006;
break;
case 36:
inYear = 2007;
break;
case 40:
inYear = 2008;
break;
case 44:
inYear = 2009;
break;
}
//this.LabelCOD.text = diseaseName;
//Each man is 3 times as high as he is wide
this.height = this.deadFromThis;
this.width = this.deadFromThis / 3;
}
//Assign the specific properties to the man
public function update(scaleAmount:Number)
{
this.height = this.height * scaleAmount;
this.width = this.width * scaleAmount;
//Additional display charecteristics for the disease
}
// trace all property values of this person to the output window
public override function toString():String
{
var str:String = "";
str += "Person:";
str += "\n id = " + this.id;
str += "\n Cause of Death = " + this.COD;
str += "\n Disease = " + this.diseaseName;
str += "\n Dead From this = " + this.deadFromThis;
str += "\n Died in the year = " + this.inYear;
return str;
}
}
}












Long Cat is almost as long as the long tail. Which should be enough to tell you just how stupendously long the ‘long tail’ is.

