Axiis is the open source data visualization framework Tom Gonzalez talked about at Adobe Max earlier this month. Watch his presentation here. At this session Tom announced the release of Beta 1.0 of the library which is built upon Flex 3.
I recently finished and deployed a complete rewrite of the map mashup RunningMap.com which uses Axiis to display elevation data in a line graph. After seeing his presentation 360|Flex last May I decided to give the (then alpha) Axiis framework a try. Upgrading to the Beta 1.0 release was painless and immediately I noticed the drawing performance of the graph went from slow(ish) (which actually was not a bad effect) to instantaneous.
Connecting my data source to the graph was a challenge and I had to use the debugger to get the data wrapped “just right”. I put together an example that illustrates:
- use of Axiis LineSeriesGroup
- wrapping an array collection “just right” so it can be bound as a data source
- overlaying the graph on a map
- setting the data tip using a function
The live example is here which is source view enabled.

I am building a widget to show routes for Runningmap.com and thought I would give Axiis a try for the elevation graph. The examples show a couple techniques for connecting a cvs formatted or xml source file as the data source for the graph. Connecting my ArrayCollection of value objects stumped me however. Tom Gonzalez was kind enough to guide me to the solution which was to wrap the collection in just the right way so that Axiis could get at the data. The rest was, as I expected, magic.
Wrapping the collection looked like this:
Actionscript:
-
protected function handleNewMapData(p_evt:Event):void{
-
var wrapper:Object = new Object();
-
wrapper.plots = model.routePoints;
-
var dataCollection:ArrayCollection = new ArrayCollection();
-
dataCollection.addItem(wrapper);
-
dataProvider = dataCollection;
-
dc.invalidateDisplayList();
-
}
Then set the "plotCollection" and "dataField" properties in the LineSeriesGroup:
Actionscript:
-
<axiis:DataCanvas
-
width="90%"
-
height="50"
-
y="15"
-
id="dc"
-
horizontalCenter="0">
-
<axiis:layouts>
-
<groupings:LineSeriesGroup
-
verticalScale="{vScale}"
-
id="myLineGroup"
-
x="0"
-
y="0"
-
height="{dc.height}"
-
width="{dc.width-10}"
-
plotCollection="plots"
-
dataProvider = "{dataProvider}"
-
dataField="elevation"
-
/>
-
</axiis:layouts>
-
</axiis:DataCanvas>
And here it is:
Map did not load
Converting FlashVars parameters to properties is an example where you are forced to deal with strings and sometimes these values need to be numbers. I have been annoyed with with my own inconsistencies with how I test to see if the FlashVar casts correctly or should be rejected (because it had a character other than a number in the string). I was discovering that some techniques were giving false negatives. So I spent some time of trying to establish a best practice.
I considered these four techniques for casting a string to a Number:
- parseInt("1234");
- new Number("1234");
- "1234" as Number;
- Number("1234");
Below is the AS3 code and the trace results which I used to base my conclusions here.
Results:
Using "as Number" to cast a string to a Number looks like bad news to me. All other techniques preformed as expected. Casting a string such as "foo" using "as Number" to cast is to a strongly typed variable results with a false value when isNaN() is applied to it. This is the false negative I mentioned before. Even casting the string "1337" using "as Number" results in the value 0 which not only fails the falsies ternary test but is wrong.
Conclusions
- don't use "as Number" to cast a string to a Number.
- Using a "falsies ternary test" is not a great approach for string to number validation since "0" is a valid number and will correctly fail this test. Maybe that works well for your logic anyhow.
Discussion
Casting is perhaps the wrong term since I am converting a primitive to an object which isn't true polymorphism, but perhaps string is being treated as an object.
I talked to Ryan Frishberg at the recent 360|Flex in Indianapolis about this. Ryan works on the Flex SDK team at Adobe. He said that "new Number('foo')" make use of conversion methods that are not available to the technique "'foo' as Number" which will evaluate to null since this casting is not possible. String can't be a Number. Ok, that is the d'oh moment for me. Should know better.
It's problematic though, because it fails to report a run-time or compile-time error.
Actionscript:
-
var n1a:Number = parseInt("foo");
-
var n2a:Number = new Number("foo");
-
var n3a:Number = "foo" as Number;
-
var n4a:Number = Number("foo");
-
-
var n1b = parseInt("foo");
-
var n2b = new Number("foo");
-
var n3b = "foo" as Number;
-
var n4b = Number("foo");
-
-
var n1c:Number = parseInt("1337");
-
var n2c:Number = new Number("1337");
-
var n3c:Number = "1337" as Number;
-
var n4c:Number = Number("1337");
-
-
trace (".............. strong typed 'foo'");
-
trace ("n1a: " + n1a);
-
trace ("n2a: " + n2a);
-
trace ("n3a: " + n3a);
-
trace ("n4a: " + n4a);
-
trace (".............. not strong typed 'foo'");
-
trace ("n1b: " + n1b);
-
trace ("n2b: " + n2b);
-
trace ("n3b: " + n3b);
-
trace ("n4b: " + n4b);
-
trace (".............. Strong typed '1337'");
-
trace ("n1c: " + n1c);
-
trace ("n2c: " + n2c);
-
trace ("n3c: " + n3c);
-
trace ("n4c: " + n4c);
-
trace (".............. isNaN n1");
-
trace ("n1a: " + isNaN(n1a));
-
trace ("n1b: " + isNaN(n1b));
-
trace ("n1c: " + isNaN(n1c));
-
-
trace (".............. isNaN n2");
-
trace ("n2a: " + isNaN(n2a));
-
trace ("n2b: " + isNaN(n2b));
-
trace ("n2c: " + isNaN(n2c));
-
-
trace (".............. isNaN n3");
-
trace ("n3a: " + isNaN(n3a));
-
trace ("n3b: " + isNaN(n3b));
-
trace ("n3c: " + isNaN(n3c));
-
-
trace (".............. isNaN n4");
-
trace ("n4a: " + isNaN(n4a));
-
trace ("n4b: " + isNaN(n4b));
-
trace ("n4c: " + isNaN(n4c));
-
-
trace (".............. falsies ternary test");
-
(n1a)?trace("n1a: true"):trace("n1a: false");
-
(n2a)?trace("n2a: true"):trace("n2a: false");
-
(n3a)?trace("n3a: true"):trace("n3a: false");
-
(n4a)?trace("n4a: true"):trace("n4a: false");
-
-
(n1b)?trace("n1b: true"):trace("n1b: false");
-
(n2b)?trace("n2b: true"):trace("n2b: false");
-
(n3b)?trace("n3b: true"):trace("n3b: false");
-
(n4b)?trace("n4b: true"):trace("n4b: false");
-
-
(n1c)?trace("n1c: true"):trace("n1c: false");
-
(n2c)?trace("n2c: true"):trace("n2c: false");
-
(n3c)?trace("n3c: true"):trace("n3c: false");
-
(n4c)?trace("n4c: true"):trace("n4c: false");
CODE:
-
.............. strong typed 'foo'
-
n1a: NaN
-
n2a: NaN
-
n3a: 0 //unexpected
-
n4a: NaN
-
.............. not strong typed 'foo'
-
n1b: NaN
-
n2b: NaN
-
n3b: null //unexpected
-
n4b: NaN
-
.............. Strong typed '1337'
-
n1c: 1337
-
n2c: 1337
-
n3c: 0 //unexpected
-
n4c: 1337
-
.............. isNaN test
-
n1a: true
-
n2a: true
-
n3a: false //unexpected
-
n4a: true
-
n1b: true
-
n2b: true
-
n3b: false //unexpected
-
n4b: true
-
n1c: false
-
n2c: false
-
n3c: false
-
n4c: false
-
.............. falsies ternary test
-
n1a: false
-
n2a: false
-
n3a: false
-
n4a: false
-
n1b: false
-
n2b: false
-
n3b: false
-
n4b: false
-
n1c: true
-
n2c: true
-
n3c: false //unexpected
-
n4c: true
I recently attended a 3-day "entrepreneur bootcamp" where angel investors taught how to pitch an idea to angel investors for investment capital. One of the first things they will want to know is how you protect your intellectual property. In the case of software, protection of algorithms is key and in the case of Flex your software secrets are protected from a right click "view source" since the application is contained within a compiled swf. Tools are available, however, that allow you to easily decompile the swf and look at the goodies inside.
Simplified Logic Inc has a product that uses a private key encryption method that stops decompilation of the swf. They also have developed a backend system that can manage licenses to your application. I have been developing a Flex application for use in teaching anatomy to students at the technical institute I work at. It has proven to be a powerful tool and there is opportunity to license this application to other institutions, but there is no infrastructure to do this. I have built a proof of concept using Nitro-LM to show that we can deploy this application on the web using a Software as a Service model without creating much of a deployment infrastructure on our end beyond what we already have in place.
The NitroAdmin AIR app is used to set up and manage the encryption and licenses. Videos and examples show how to integrate the system into your Flex app but I think they need to do a bit more work around this ... perhaps a "wizard" or video that shows from start to finish the basic setup. It still took a bit of handholding to get me up and running (thanks Andrew). The proof of concept is doing its job of proving this works in a way that is unobtrusive to users. Now all that is left is the easy part: to build a business model around my application and then go out and sell it. That is someone else's job.
Simplified Logic was a major sponsor of the recent 360 Flex conference in Indianapolis. I want to say thanks to them for supporting this event. It was a good one and I enjoyed the environs.
The conference in Indianapolis was fantastic and the sponge is full. Met so many fellow developers. Was accused of stalking Adobe employees, but I only said hi to Matt Chotin once. So much to experiment with. FlexUnit 4 is important. Degrafa looks compelling. Will definitely look into Axiis data visualization library. I am intrigued by Maté as a framework. OpenFlux ... Yes!!!! ESRI has a new free mapping API ... BAM. Lazy loading datagrid using cacheing and synchronization (props to Zach Pinter) ... I need that. According to Jeff Tapper's 7 golden rules of how not to code in Flex, I should have been fired 7 times. RSL's! RSLs! RSLs! But my favorite session was by Doug McCune. He talked about stuff that re-inspired him as a developer.
This slide is about how Flex application development became a job, and nothing much more than that.

Doug's live demo on head tracking in Flash. He showed an application that can be used for "Safe Sexting". You can do whatever you want on the video and your face will be tracked and blurred. Big laughs on this one.

Doug had a unique take on how to push the concept of Augmented Reality. He gave himself boobs in this live demo.

As Flash and Flex applications get more complex the ability to watch trace statements while running the application in a browser is invaluable. This is how I do it (in OSX):
1) find your mm.cfg file. Mine is located here: ~username/mm.cfg (substitute "username" with your real username)
2) open it in a text editor and add these lines:
CODE:
-
ErrorReportingEnable=1
-
TraceOutputFileEnable=1
-
MaxWarnings=0
3) open a terminal window and add this to your .profile file.
CODE:
-
alias trace=tail\ -f\ "/Users/username/Library/Preferences/Macromedia/Flash\ Player/Logs/flashLog.txt"
To watch your browser throw trace statements, just open a terminal window and type "trace" and they will now appear in the terminal window.
February 23rd, 2009
Randy
Consider this xml:
Actionscript:
-
var myImageXML:XML =
-
<image>
-
<term text="New Term 498"/>
-
<term text="a new term 550"/>
-
<term text="a new term"/>
-
<term text="New Term 668"/>
-
</image>
You can create an xmlListCollection and then sort the collection based on the term text.
Actionscript:
-
import mx.collections.SortField;
-
import mx.collections.Sort;
-
-
var terms:XMLListCollection = new XMLListCollection(myImageXML..term);
-
var sort:Sort = new Sort();
-
var sortField:SortField = new SortField("@text");
-
sort.fields = [sortField];
-
terms.sort = sort;
-
terms.refresh();
What threw me for a loop was the sort result (by term text value):
New Term 498
New Term 668
a new term
a new term 550
As it turns out the default value for the sort case insensitivity is false. To solve this, set the property in the SortField object:
Actionscript:
-
sortField.caseInsensitive = true;
and the sort will happen as expected:
a new term
a new term 550
New Term 498
New Term 668
Recently I struggled with trying to figure out why I could not traverse loaded XML data using E4X. In one case it was a RSS feed and in another it was Timed Text data. What these data sets have in common is that they declare name spaces. Consider this xml data:
XML:
-
<tt aaa:lang="en" xmlns="http://www.w3.org/2006/04/ttaf1" xmlns:tts="http://www.w3.org/2006/04/ttaf1#styling" xmlns:aaa="http://www.w3.org/XML/1998/namespace">
-
<head>
-
<styling>
-
<style id="1" tts:textAlign="right"/>
-
<style id="2" tts:color="transparent"/>
-
<style id="3" style="2" tts:backgroundColor="white"/>
-
<style id="4" style="2 3" tts:fontSize="20"/>
-
</styling>
-
</head>
-
<body>
-
<div aaa:lang="en">
-
<p begin="00:00:00.25" dur="00:00:03.25">Dreamweaver users now have access to Flash video. Didn't have it before.</p>
-
<p begin="00:00:04.20" dur="00:00:03.07">And if you were to talk to a Dreamweaver user about three or four years ago</p>
-
</div>
-
</body>
-
</tt>
I see that it declares a couple namespaces but I thought since the "p" nodes do not. This ...
yields nothing. Yet this ...
Actionscript:
-
if (timedTextXML.namespace("") != undefined){
-
default xml namespace = timedTextXML.namespace("");
-
}
-
trace(timedTextXML..p);
works fine.

It has been a little over a week since we got back from San Francisco and the MAX conference. It has taken me this long to surface for air after getting caught up from being away. Adobe announced a dizzying amount of updates and initiatives. Serge Jespers has a list of most of them here: http://www.webkitchen.be/2008/11/22/weekly-blend-the-max-edition/. Let's just say that it will be a while before I can digest all of this.
The picture above (taken by Charles Freedman) shows the massive display that was set up for the keynotes. I have never seen anything like it before. When I walked into the hall, Icky Thump by White Stripes was playing through the incredible sound system and I could feel the thumps on my chest. I had goosebumps.

Read more...
Mark Logic tells me that anyone who cares about free text analytics will be very interested in this visualization, because it previously was not available in any product. The keyword here being Real-Time. A geospatial analysis of documents returned from a free text search, plotted in arbitrary geographic bounding boxes, calculated in real-time. No other product can do this is real-time. Try out the demo..
When the initial heatmap is displayed you can hold the ctrl/cmd button down and either click on a "bucket" or click-drag to zoom in on an area and have new buckets calculated.
This widget was part of the recent MarkLogic Server 4.0 release.
My role was that of Flex developer of the map visualization. Craig Schlegelmilch directed the project and wrote the middleware integration using Xquery. Owen Brierley wrote the javascript (html controls are continually updated with search results). Tanya Camp provided graphic design consultation. Craig and Tanya form the dynamic company Bucketduck Inc. and the overall project is a production of GystWorks.