Odds On Flex

Logging to Server from Flex

August 6th, 2010

An issue that can crop up with Flex applications is the lack of any log information to match up against users’ bug reports. It is possible to configure the debug version of Flash Player to record trace() output, but most users do not have this setup. Additionally, it is much more desirable to maintain this kind of information server-side, where the development team have control, rather than relying on users’ whilst also clogging up their machines. A general approach to this problem is relatively obvious – send the information back to the server – but there are all sorts of ways this could be implemented. Of course, sending lots of logging information to the server creates an overhead in the application, so this should very much be considered on a case by case basis.

A solution that we use takes advantage of Flex’s native logging API, allowing it to be transparently added or removed from an application while providing us with the benefits of a decent logging framework, for example logging levels. Flex provides the ILogger class, instances of which are obtained using Log’s getLogger() method, to log messages. In turn, these messages are sent to one or more ILoggingTargets, the most common of which, TraceTarget outputs the logging information using the trace() method. The logging API documentation provides details and examples for how to get started with this basic logging setup.

On the Flex side, our solution consists of little more than a custom ILoggingTarget implementation, RemoteTarget, that attempts to send the logging information to a specified URL and the appropriate code to initialise the target. Note that RemoteTarget uses URLLoaders rather than HTTPServices because HTTPService itself uses the logging API, thereby causing an infinite loop. Another feature worth highlighting is that our implementation stops logging if it has encounters any errors when sending the information to the server, so that, for example, an application does not repeatedly hit a server that is unavailable. All source code and examples associated with this article can be found here.

package com.scottlogic.logging
{
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.net.URLVariables;
 
    import mx.logging.AbstractTarget;
    import mx.logging.ILogger;
    import mx.logging.LogEvent;
    import mx.utils.StringUtil;
 
    /**
     * ILoggingTarget implementation that sends logging details
     * to a remote service.  The following details are sent as
     * request parameters:
     *  - level: the log level as an integer (see LogEventLevel)
     *  - category: the log category
     *  - timestamp: as milliseconds from 1st Jan 1970
     *  - message: the log message
     */
    public class RemoteTarget extends AbstractTarget
    {
        /**
         * Flag to indicate whether remote logging is enabled
         * or not.  The RemoteTarget will automatically disable
         * itself if it encounters any errors.
         */
        private var enabled:Boolean = true;
 
        /**
         * Constructor
         */
        public function RemoteTarget()
        {
            super();
        }
 
        private var _url:String;
        /**
         * The URL of the service to which to log.
         */
        public function get url():String
        {
            return _url;
        }
        /**
         * @private
         */
        public function set url(value:String):void
        {
            _url = value;
        }
 
        /**
         * @private
         */
        override public function logEvent(event:LogEvent):void
        {
            // if there has been any issue with remote logging
            if (!enabled)
                return;
            // if no url is set then do nothing
            if (!_url || StringUtil.trim(_url).length == 0)
                return;
 
            // attempt to log to the server
            try
            {
                var variables:URLVariables = new URLVariables();
                variables.level = event.level;
                variables.category = ILogger(event.target).category;
                variables.timestamp = new Date().time;
                variables.message = event.message;
                var request:URLRequest = new URLRequest(_url);
                request.method = "POST";
                request.data = variables;
                var loader:URLLoader = createLoader();
                loader.load(request);
            }
            catch (e:Error)
            {
                enabled = false;
                trace(e.message);
                trace(e.getStackTrace());
            }
        }
 
        /**
         * Creates a URLLoader with all the appropriate event listeners.
         */
        private function createLoader():URLLoader
        {
            var loader:URLLoader = new URLLoader();
            loader.addEventListener(IOErrorEvent.IO_ERROR,
                                    ioErrorHandler,
                                    false, 0, true);
            loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,
                                    securityErrorHandler,
                                    false, 0, true);
            return loader;
        }
 
        /**
         * Disables the remote logging and traces debug information
         * when there is an IO error during logging to the remote server.
         */
        private function ioErrorHandler(event:IOErrorEvent):void
        {
            enabled = false;
            trace("ERROR - IO error in RemoteTarget");
            trace(event.text);
        }
 
        /**
         * Disables the remote logging and traces debug information
         * when there is a security error during logging to the remote
         * server.
         */
        private function securityErrorHandler(event:SecurityErrorEvent):void
        {
            enabled = false;
            trace("ERROR - Security error in RemoteTarget");
            trace(event.text);
        }
    }
}

Here is a small example showing how RemoteTarget can be used:

<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="horizontal"
    applicationComplete="initialise()"
>
    <mx:Script>
        <![CDATA[
            import com.scottlogic.logging.RemoteTarget;
            import mx.logging.Log;
            import mx.logging.LogEventLevel;
            import mx.logging.ILogger;
 
            private static const LOG:ILogger = Log.getLogger("RemoteLogging");
 
            private function initialise():void
            {
                var target:RemoteTarget = new RemoteTarget();
                target.url = ""; // set logging service URL here
                target.level = LogEventLevel.INFO;
                Log.addTarget(target);
            }
        ]]>
    </mx:Script>
    <mx:Label text="Text:" />
    <mx:TextInput id="input" />
    <mx:Button label="Log Text" click="LOG.info(input.text);" />
</mx:Application>

As the information is being sent back as a standard example server-side code I have included is in Java and consists of a relatively simple HttpServlet that parses the information and mirrors it onto its own logging framework, in this case log4j.

Stephen Few Data Visualisation Workshop

June 28th, 2010

Last week I attended a series of information visualisation workshops run by Stephen Few. The classes were based around his three books to date: Show Me The Numbers, Information Dashboard Design and Now You See It. Here follows an overview of the material covered and my thoughts on the event.

Show Me The Numbers

Day one of the workshops was titled “Designing Tables and Graphs to Enlighten” and focused on how to effectively communicate a single story in a data set using a table or graph. The starting point was to highlight that the Gricean Maxims apply equally well to the communication of quantitative data as they do conversational communication, i.e. information visualisation should:

  • be as informative as necessary but not more informative than necessary (maxim of quantity)
  • not convey any message that is believed to be false or for which there is a lack of evidence (maxim of quality)
  • be relevant (maxim of relation)
  • be brief and orderly, avoiding ambiguity and obscurity of expression

Fundamentally, to achieve this, Stephen Few proposes 2 major steps. First, you should determine the medium that tells the story best. (Should you use a table or a graph? If a graph, then which kind of graph?) Then you must design the chosen component so that the story is told clearly.

For the first step, the relative strengths and weaknesses of tables and graphs and different graph types were presented. Regarding graphs, Stephen presented what he considers to be the 7 relationships commonly displayed in graphs – time-series, ranking, part-to-whole, deviation, distribution, correlation and nominal comparison – and which graph types most concisely convey these relationships. Unsurprisingly, pie charts were a graph type singled out for their general ineffectiveness (see Save The Pies For Dessert for details). In addition to graph types, the concept of small multiples was highlighted as a simple technique for improving the affordance of graphs that endeavour to compare across data that differs only along a single variable.

Oh, and 3D charts, where to begin… The almost guaranteed occlusion (where something is hidden behind something else) meaning it is impossible to see the entire picture at once? The inability to directly compare values, sizes and/or positions due to depth? The colour variation due to “lovely” lighting effects?

With determining the appropriate medium covered, a range of techniques and areas for consideration were introduced with the aim of maximising the effectiveness of the chosen component(s). Edward Tufte’s argument that the “data-ink ratio” should be maximised by removing, de-emphasising and/or regularising the unnecessary and emphasising the most important was introduced as the foundation of good table and graph design. Additionally, the fundementals of visual perception were considered and how they can be harnessed to improve the clarity of the story being portrayed. In particular, attributes such as size, shape, orientation and colour are processed pre-attentively. That is, we perceive and process them instantaneously, in a highly parallelised fashion and without conscious thought, thereby laying down an immediate interpretation before conscious thought is required. Further to this, the pre-attentive attributes of length, 2-dimensional position, width, size and colour intensity are perceived quantitatively, i.e. some values are greater than others, and are therefore powerful building blocks for data visualisation.

As well as covering areas such as where best to locate the scale, how to arrange the visualisation to avoid label rotation and how to minimise problems associated with legends, there was an emphasis on the importance of colour, from when and where it is (not) required to palette choice. A fair amount of Stephen’s thoughts on colour are covered in his article Rules for Using Color. A couple of useful links that came up were Cynthia Brewer’s Color Brewer, a tool for colour palette choice, and VisCheck, a tool for simulating colour blindness.

Information Dashboard Design

The 2nd day of the workshops, “Dashboard Design for at-a-glance monitoring”, built heavily on the first day’s lessons and focused on techniques and constructs that are of use when designing dashboards. First up was the problem that the term “dashboard” is used for all manner of products. Stephen defines a dashboard as “a visual display of the most important information needed to achieve one or more objectives that has been consolidated on a single computer screen so it can be monitored and understood at a glance” and states that “dashboards are not comprehensive tools for analysis, decision making or management“. The monitoring requirement suggests that to some extent there must be a “live” element to the screen, while their not being comprehensive tools suggests that there should not be an abundance of controls to facilitate filtering, etc. In my opinion Stephen is potentially limiting his audience with this, as most of what he presents under the context of dashboard design is just as valuable to report design and data presentation and/or analysis applications in general.

We started by focussing on the common mistakes made in dashboard design, such as introducing meaningless variety, arranging data poorly, misusing or overusing colour and introducing useless decoration. Unfortunately, many of these problems appear to stem from vendors. They are (understandably) assumed to be experts, yet their examples are usually little more than marketing fluff, so their designs are usually more concerned with graphical glitz than the actual intended purpose of a dashboard: communication.

Moving on to considering the techniques and practices that will improve dashboard design, the core idea was once again Tufte’s “data-ink ratio” argument: “reduce the non-data ink; enhance the data ink“. A number of objectives specifically for the visual design of dashboards were also prescribed: eliminate clutter and distraction, group data into logical sections, highlight what’s most important, support meaningful comparisons and discourage meaningless comparisons. Each of 6 categories of dashboard display mechanisms (graphs, icons, text, images, drawings and organisers) was considered with the aim of achieving these goals. The most time was spent addressing graphs; re-iterating some of the previous day’s content and introducing a couple of graph types more specifically designed for the dashboard context: bullet graphs (see image below) and sparklines. Bullet graphs are Stephen Few’s own development to address the requirement (unfortunately) usually fulfilled using gauges, i.e. the display of a single quantitative value against one or more comparative measures within the context of some qualitative ranges, e.g. poor, satisfactory, good. The benefits that bullet graphs have over gauges are numerous, but in particular they take up significantly less space and are more conducive to the aforementioned objectives. Sparklines, on the other hand, were introduced by Tufte in his book The Visual Display of Quantitative Information, and are designed to present trends or variations in a simple, space-saving way.

After touching on the importance of the aesthetics of the design (it should look appealing without impeding the aforementioned visual design objectives), we moved to critiqueing dashboard examples submitted by attendees. This proved to be a good exercise of the day’s lessons both for the submitters and class as a whole.

Now You See It

The final day, titled “Simple Visualisation Techniques for Quantitative Analysis”, was quite different to the preceeding days as it was focused on how to gain an understanding of and insights into data sets, rather than the communication of existing understanding. As a basis for the rest of the day’s material, the power of sight compared to our other senses was introduced and used as the argument for why data visualisation is a vital tool for exploring and understanding data sets. This was followed by a brief history of data visualisation, from the first evidence of tabular arrangement of data in the 2nd Century, through William Playfair’s invention of line charts, bar charts and pie charts, to the spread of home computers in the 1980s and beyond.

The traits of a skilled data analyst and characteristics of good data were considered before emphasising the necessity for a solid understanding of visual perception and cognition to be able to take advantage of those traits and characteristics through visual analysis. Consequently, some time was then spent introducing a number of core aspects of visual perception and cognition. As during the previous classes, it was highlighted that visual perception is selective, meaning that we must encode data in such a way that what is potentially interesting or meaningful pops out by contrasting with the norm. Pre-attentive visual attributes were again introduced as the means by which this can be achieved, with length, 2-dimensional position, width, size and colour intensity able to encode quantitative values and shape and colour hue ideal for indicating categorisation. The limitations of perception were highlighted, with particular emphasis on the issue of inattentional blindness (the fun examples caught most of us out). Finally, some attention was given to the meaningful characteristics of data: trends, patterns and outliers; how to highlight those characteristics; and, which patterns and comparisons in data are meaningful, e.g. steep vs gradual and random vs repeating.

The final stretch of the class focused on techniques for performing meaningful data analysis by attempting to bring the characteristics and patterns introduced in the preceeding material to the fore. First we considered the various types of useful analytical interactions, such as comparing, filtering, aggregating, drilling and zooming/panning. Specific analysis techniques were then introduced for each of 7 categories of data analysis: time series, ranking and part-to-whole, deviation, distribution, correlation, multivariate and geospatial. Stephen used a number of different analytical tools – Spotfire, Tableau and Panopticon – to demonstrate not only some of these techniques, but also the state of what he considers to be the best of the current crop of data analysis tools. This crossed over into discussion of what the ultimate data analysis tool would provide: a tool that provides the appropriate set of visualisations and aforementioned analytical interactions that has no distracting lag between seeing something, thinking about it and manipulating it.

Closing Thoughts

My overall reaction to the workshops is definitely positive. Stephen Few is an engaging presenter who is able to eloquently convey many practical techniques and principles for information visualisation. The workshops appropriately complement the corresponding books by presenting similar material in a different way, with the group exercises and interactivity of the classes more actively re-inforcing the concepts.

The minor negative I would highlight about both his books and the workshops is that they appear to overly target the business intelligence domain. This in itself is not a problem, but I think it potentially sells short some of the ideas and information in the material, as I believe they are potentially much further reaching. Many of the fundemental concepts he teaches are too frequently ignored or simply not appreciated by those producing even the most basic of data visualisations. Moreover, visualisation and visual perception are key to other areas such as user experience and human-computer interaction, so it is unsurprising that most of his lessons cross over to such areas.

For those who like the sound of this course, it is being run again later in the year in London, as well as in the States and Australasia.

Contextual cues in user interface design

May 19th, 2010

Contextual cues are frequently used in user interface design to communicate functionality and behaviour to the user, removing the need for the user to guess. For example, on the web, the underlining of text is commonly used to indicate a hyperlink. In addition to underlining, one or more of a different text colour, colour change on mouse-over and cursor change on mouse-over is usually also seen. This stems from the convention that all interactive elements of a modern user interface will display some state change on mouse-over, as it clearly indicates to the user that they are “active”. Conversely, disabled functionality is commonly greyed out and do not react to the mouse to indicate that they are “inactive”. Neither the state-changes nor the greying-out are essential to the functionality of the interface. However, they are key to informing the user of the interface’s behaviour and to guiding their interaction with the interface. Without these subtle contextual cues, the user will forever be guessing at what they can do and will inevitably be left frustrated and lost.

Many modern development technologies come pre-packaged with an abundance of features, such as drop shadows, translucency and transitional animations, for creating “shiny” user interfaces. Unfortunately, it seems that they are frequently misused and/or overused, usually due to their being used solely in an attempt to make an interface more visually appealing, rather than to enhance usability. However, they should be considered additions to our arsenal of contextual cues, with the bonus of an aesthetic side-effect, rather than mere prettifying graphic design flourishes. When used appropriately, as with the now “standard” cues such as those mentioned above, they can be invaluable in effectively communicating the functionality and behaviour of our increasingly complex user interfaces.

Drop Shadows

Drop shadows imply an element of depth in user interfaces due to our natural interpretation of shadows in the real world. In accordance with this intrinsic understanding, they should be used when a user interface element is “over” another element, as it clarifies the layering that is occuring. A simple, common example is a pop-up dialog, as shown here:
Pop-up dialog

Furthermore, they can be used subtly, yet effectively, to provide a more real-world understanding of a user interface’s behaviour, as in this example:

Adobe Reader - Drop Shadow
This is a screen capture of a PDF displayed in Adobe Reader. Notice how the drop shadow under the control bar at the top result in our instinctively understanding that the pages will go “under” the control bar. The interface’s behaviour would be acceptably clear without the drop shadow, due to the positioning of the scrollbar indicating the pages will scroll but not the control bar, however, the natural interpretation would be that the pages magically disappear off at the top. Although users are probably accustomed to this idea through general computer use, the “goes under” concept is understood more instinctively as it is more natural.

The main concern regarding drop shadows is that they can horribly mislead when misused or overused. Misuse is usually a case of a shadow suggesting an above-below relationship between elements of the user interface when there isn’t one, i.e. behaviour has been implied that is not the case. In contrast, overuse simply results in difficulty interpreting the behaviour due to drop shadows only creating a pseudo-3D effect that does not scale beyond a relatively small number of layers. Related to this is the issue that drop shadows only provid a layering cue in their immediate vicinity. Therefore, a design should never rely on the user naturally interpreting the relationship of user interface elements with drop shadows in different areas of the the interface.

Transitional Animations

Transitional animations are short animations of user interface elements when changing from a particular state to another. Their aim is to infuse the interface with a more organic feel by providing a context for the appearing, disappearing and changing of elements, rather than having the “magically” flick between appearances, whilst not impeding the user by forcing them to wait for animations to complete. When used appropriately, the context provided by the animation reassures the user of what is happening and ensures that they do need to guess what has changed. For example, in the following tree explorer control, the animated expanding and collapsing of nodes complements the indentation in conveying the parent-child relationships by suggesting the child nodes are “coming out of” or “going into” the parent node as we navigate through the tree.

Explorer Tree Example

Transitional animations can be taken even further than such subtle enhancements and become a quite pronounced aspect of a tool. For example, a common feature of data visualisation is the concept of drilling down (or up) on datasets. Frequently, an understanding of the context in which lower-level details reside is as useful as the details themselves. The example below shows a bar chart of some abstract data that allows the user to drill down on individual bars. Without the transitional animation the user can still work out the context into or out of which it is drilling, but the transitional animation allows the user to passively consume this information instead, resulting in a more powerful experience for the user.

Chart Drill-down Example
Note: the code for this example is based on Ely Greenfield’s chart drill-down article.

Another example is on display in the Market Map tool we have developed. Once again the transitional animation when drilling down or up assists the user’s understanding of the data by clearly portraying relationships and context.

As mentioned, the key to using transitional animations as contextual cues is that they do not impede the user whilst communicating their additional information. Therefore, the duration of a transitional animation is vital to getting the “feel” right. Unfortunately, my experience has shown that working out the ideal duration is not an exact science and requires a largely trial and error approach. However, as a general rule of thumb, the more contextual information there is for the user to absorb, the longer the animation can take.

Translucency

A translucent user interface element is one which is neither wholly invisible nor fully solid, i.e. it is semi-transparent, resulting in the user being able to see the user interface detail “underneath” the translucent element to some extent. It inherently loses an element’s contrast and makes it appear somewhat insubstantial, or ghost-like. This can be leveraged for two purposes: to enable user interface elements to be layered whilst not fully obscuring underlying details and/or to draw the focus away from an element. For example, in the pop-up dialog image used above to illustrate drop shadow use, there is visually no suggestion that the user cannot continue to interact with the underlying text. Here is a screenshot of the same application, but this time there is a (slightly blurred) translucent layer over the underlying text. It is now clear that the user can only interact with the pop-up dialog, whilst also satisfying the user that the text has not been lost, as they are still able to see it. At the same time, the translucent overlay pushes attention away from the text, i.e. towards the pop-up dialog to which the user must respond.

Translucent overlay pop-up.

Notice how the border of the pop-up dialog is also translucent. Once again this allows the user to see a rough outline of the underlying detail whilst softening the border’s visual strength so that the user is pushed toward the only “solid” part of the interface, the area with which they must interact.

All together now…

To better understand how these contextual cues can improve an interface, here is an example based on an interface component devised for our Hindsight application which has subsequently been used in a variety of applications for our clients. This example shows the same functional component, but with different contextual cues enabled and disabled.

The Flash plugin is required to view this object.

The contextual cues vastly improve the understanding of the component’s behaviour, since they help communicate the concept of a pullout tab (like in a pop-up picture book): the drop shadow indicates that the tab is “on top”; the transitional animation clarifies that the tab is pulled out and pushed back; and, the subtle translucency ensures the underlying content is not completely obscured whilst still providing sufficient contrast for the tab’s contents to be usable.

Closing Thoughts

Contextual cues are an important aspect of user interface design. They communicate information to the user about an interface’s behaviour without the need for explicit instructions. As users increasingly expect entirely intuitive applications, this form of communication is vital to modern user interfaces. Basic contextual cues are already commonplace in all applications, usually in the form of cues such as mouse-over state changes that guide the user but, arguably, do not necessarily add a great deal to the aesthetics of user interfaces.

More modern contextual cues such as drop shadows, transitional animations and translucency are able to both act as contextual cues and prettifying additions in user interfaces when used appropriately. As the importance of the visual appeal of devices and applications is increasingly recognised and encouraged it becomes vital that, as developers and designers, we fully understand the tools at our disposal so that we can strike the appropriate balance between aesthetics and functionality in a user interface.

Flex Sparkline

February 8th, 2010

Sparklines are described by their inventor, Edward Tufte, as “data-intense, design-simple, word-sized graphics”. They are an ideal tool for displaying trends for single entries within large data sets, for example, stock prices. As well as the standard miniature line series, Tufte’s original specification introduces a ternary sparkline, a.k.a. win-loss sparkline, where small columns are used to indicate “win” or “loss” and no column to indicate “draw”.

This article is intended to present, and distribute, Flex 3 implementations of sparklines, win-loss sparklines and another common variation, column sparklines. The code and documentation can be obtained from here. The following is an example showing some of the variations available:

Sparkline Examples

The Sparkline, TernarySparkline and ColumnSparkline classes are all implemented using core Flex functionality, i.e. there are no dependencies. They all implement IListItemRenderer and IDropInListItemRenderer interfaces, so can readily be used as standalone components or as item renderers in a DataGrid or other list control. Based on the original specification, the Sparkline allows the user to optionally show a normal range, x-axis min and max points and y-axis min and max points. All of these features and the line itself can be styled. Similarly, the TernarySparkline and ColumnSparkline allow the user to specify the “zero” value, and style positive, negative and zero styles independently. A final feature of the sparklines is that they will update automatically based on dataProvider updates, as shown in the following example, which plots a constantly-updating, randomly generated series of numbers:

Updating sparkline example.

It is worth noting that there are a number of alternative Flex implementations available. However, they all have further dependencies, potentially making them more heavyweight. For example, Tom Gonzalez and Andrew Trice both present implementations using the Degrafa graphics framework. Because of their use of Degrafa, these implementations inherently allow users to easily use any number of extravagant styling. Although potentially initially appealing, this goes against the good data visualisation practices suggested by experts such as Stephen Few and Tufte himself; “eloquence through simplicity”[ref]. Lucas Pereira and Sherlock Informatics both present implementations using the Flex Data Visualization library. The charts contained in the library are wonderfully feature-rich and flexible. However, this means that they are also rather heavyweight components and, therefore, using a large number of these as item renderers in an application is likely to use a lot of memory and/or make the application non-performant. A final potential alternative are the micro-charts available in the BirdEye visualisation library. Much like the examples using the Flex Data Visualization library, these can be perfect in situations where small numbers of instances are present, but again they introduce features that cause them to be more heavyweight than necessary.

The components are being made available under the GNU General Public License and can be obtained from here. The zip also includes some documentation and an swc of components, using the namespace http://www.scottlogic.com/sparkline.

Microsoft apply for “Sparkline in the grid” patent

November 25th, 2009

Microsoft have recently submitted US patent application 20090282325, entitled Sparklines in the Grid. My initial reaction, like many others in the data visualisation community, was one of anger at what appeared a blatant attempt by Microsoft to abuse the US patent system. However, I decided to examine the application more closely in order to attempt to discern what was actually going on.

One glaring omission from the application is any acknowledgement of Edward Tufte as the inventor of sparklines. His book, Beautiful Evidence, is the first documentation of the concept and terminology of sparklines, an excerpt of which can be read here. What makes the omission particularly odd is that the primary author of the application, Sam Radakovitz, has previously blogged about the sparkline feature of Excel 2010, where he readily acknowledges Edward Tufte as their inventor. This indicates that ignorance is clearly not the reason for the omission.

Another concern about the application is the vagueness of its title, “Sparklines in the Grid”. As Edward Tufte has commented, “Every data table has a grid, sometimes invisible, sometimes with little ordered boxes. Nearly all typography has an underlying grid, so even a sparkline embedded in a sentence might qualify as a ’sparkline in a grid.’”[ref]. Most examples of sparkline use involve their being displayed in tables, see Tufte’s original documentation of the concept, Wikipedia’s illustrative example and our own Market Overview pages. It seems odd, then, that the application fails to mention that tables/grids have always been the primary use case for sparklines.

The general response from the team submitting the application has been that patent would be for use in Excel only; for example, the response Stephen Few received was “Microsoft is not trying to patent Sparklines, but instead an innovation that would allow Sparklines to work more effectively within the Excel environs.” [ref]. However, this appears to be in direct conflict with a statement in the application regarding the generation of sparklines:

“In this example, the application is a spreadsheet application, such as Microsoft Excel® produced by Microsoft Corporation of Redmond, Wash. However, the generation and modification of sparklines also may be implemented in word processing applications, database applications, presentation applications, and other applications, whether the applications are network-based, host-based, or workstation-based.”

One can only assume that this contradiction is the result of the application having gone through a more involved process at Microsoft and the statement coming directly from a project manager. Unfortunately, only the application matters.

However, the application is for a software patent and, as such, boils down to technical and implementation details. Therefore, the main grounds on which the patent would not stand would be prior art. A quick search for sparkline implementations highlights numerous implementations. Sparkline PHP Graphing Library is a free PHP library that allows sparklines to be produced by writing the appropriate server-side, procedural code. This implementation clearly differs from that outlined in the patent application, where users are able to generate sparklines without writing any code. Similarly, the jQuery Sparklines library, which uses JavaScript, jQuery and the Canvas HTML element to generate sparklines, cannot be construed as prior art.

A further search sparkline implementations specifically for Excel also throws up some results. Sparklines for Excel is a well-established, free plug-in for Excel 2003 and 2007. Sparklines can be generated using this plug-in by entering simple formulae in cells. This implementation differs from that outlined in the patent application, as, for example, the application details that sparklines will be generated by selecting a range of values before using a dialog box to configure the resulting sparkline. BonaVista Systems have a commercial product, MicroCharts, that has an Excel plug-in feature. Initially, this product appears to be very similar to that outlined in the application, but there are some small differences. For example, MicroCharts appears to render its sparklines using a font-based system that does not size itself based on the containing cell, where as the application indicates that sparklines will be rendered using a matrix-based system that scales based on “associated location”, i.e. containing cell.

Bearing in mind that I am not trained in legalese and the number of other products I have considered is relatively small, it would appear that Microsoft may have a legitimate claim with this patent application. However, it does appear to have a disconcerting number of omissions and misstatements. Besides missing key information regarding the background of sparklines it also states “In the case of creating sparkline graphs, conventionally, sparklines are created manually” – a clear falsehood given the numerous existing examples of implementations that automatically generate sparklines.

Missing values in Flex charts

April 14th, 2009

An oddness in default behaviour that can throw those new to Flex Charting is that segments in charts that should correspond to a data point are missing. By this I mean charts like those in the following example:
You must have Adobe Flash Player 9 installed to view this application.
When what is actually desired is the following:
You must have Adobe Flash Player 9 installed to view this application.
This is achieved by setting the filterData property on the Series to false, for example:

<mx:LineSeries filterData="false" />

However, it is worth understanding the functionality that ties in with this property to appreciate the potential consequences. Adobe states:

When possible, set the filterData property to false. In the transformation from data to screen coordinates, the various series types filter the incoming data to remove any missing values that are outside the range of the chart; missing values would render incorrectly if drawn to the screen. For example, a chart that represents vacation time for each week in 2003 might not have a value for the July fourth weekend because the company was closed. If you know your data model will not have any missing values at run time, or values that fall outside the chart’s data range, you can instruct a series to explicitly skip the filtering step by setting its filterData property to false. [ref]

What is actually happening under the covers is that the series a collection of “all the data points” and a collection of “all the data points I think I want to draw”. When filterData is true, i.e. by default, the series creates the collection of “all the data points I think I want to draw” by iterating through the collection of “all the data points” and throwing away any that are null or NaN or that fall outside the axes minimum and maximum values. By contrast, when filterData is false, the two collections are identical. Knowing this it is obvious why the segments are missing in the example above: with the LineSeries if a data point is not to be drawn then the line segments to that data point will not be drawn; with the ColumnSeries if a data point is not to be drawn then the column representing that data point will not be drawn.

Performance-wise, it is worth noting that performance gained by the removal of data point filtering step by setting the filterData property to false will be offset against the performance lost by drawing data points that have no bearing on the view of the chart, i.e. data points that are one or two data points removed from those around the axes maximums. As such, the performance gain/loss and appearance gain/loss should be considered on a case by case basis.

An approach that can be used to get the best of both worlds is to extend the applicable series class and override the updateFilter method to ensure that data points that have no bearing on the view of the chart are filtered out, but any others aren’t. This could, for example, amount to filtering out any data points that do not lie in the range of the x-axis and that are not adjacent in the x-axis to a data point that does lie in the range of the x-axis.

An unfortunate note about the filterData property is that there is a bug when setting it to false on a LineSeries no data tips will show on the series (as can be seen in the example above). The bug has been filed with Adobe and has recently been marked fixed, however, the fix has not yet been released. The bug report details the relatively simple but somewhat nasty workaround that can be used in the meantime.

At Scott Logic the functionality relating to the filterData property as well as the property itself have been carefully manipulated to produce the various zooming and panning capabilities in our Hindsight application and the research charts available through our Market Overview pages.

The source code is now available.

Custom data tips in stacked Flex charts

March 24th, 2009

The number of frustrating decisions in Flex’s charting API is minimal, but high up on my list is a strange decision that prevents developers from accessing information that is frequently desirable for custom data tips in stacked area, bar and column charts. The default data tips for stacked charts display, amongst other things, the total of the values for all the series at a specific point along the x-axis and the percentage the highlighted segment forms of this total, as shown in the following example (source code):
You must have Adobe Flash Player 9 installed to view this application.
If you wanted to customise the data tips and still include information such as the total and percentage values then you would be out of luck. This why I consider the decision to give the necessary information protected scope in the relevant classes in the charting API as strange. Fortunately circumnavigating this issue only requires a little bit of dirty work…

But first, a brief diversion to provide a little background…
The code used to create a stacked column chart generally takes the following form:

<mx:ColumnChart type="stacked">
    <mx:series>
        <mx:ColumnSeries />
        ...
    </mx:series>
</mx:ColumnChart>

This is in fact a shortcut syntax. The ColumnChart automatically wraps the array of series into a ColumnSet with type “stacked”, as it is the ColumnSet class that takes care of the stacking and associated behaviour rather than the ColumnChart class. The same pattern occurs in stacked AreaChart or BarChart. Consequently, the following MXML produces the same end result:

<mx:ColumnChart>
    <mx:series>
        <mx:ColumnSet type="stacked">
            <mx:ColumnSeries />
            ...
        </mx:ColumnSet>
    </mx:series>
</mx:ColumnChart>

When wanting to create more complex combinations of stacking, clustering and overlaying in charts, this can only be achieved by explicitly introducing (and nesting) sets – as in the second code snippet. For further details on this see Adobe’s Stacking Charts article.
Diversion over…

To be able to display customised data tips that include information relating to the stacking in a stacked ColumnChart, BarChart or AreaChart we can take one of two approaches. Both approaches involve extending the ColumnSet, BarSet or AreaSet class (depending on the desired chart type) as it is the protected-scoped negTotalsByPrimaryAxis, posTotalsByPrimaryAxis, stackedMaximum and stackedMinimum properties that contain the interesting information. The first approach is to override the formatDataTip method in the extended class, resulting in something along the following lines:

/**
 * ColumnSet extension to introduce custom data tips.
 */
public class ColumnSet extends mx.charts.series.ColumnSet
{
    /**
     * @inheritDoc
     */
    override protected function formatDataTip(hd:HitData):String
    {
        // build up the custom data tip
        var tip:String = "";
        ...
        return tip;
    }
}

However, I think that this approach is slightly short-sighted because it means that for every customisation of the data tips you would create a new extension. The other, and in my opinion more reusable, approach is to expose the aforementioned properties publicly in extensions to the ColumnSet, BarSet and AreaSet classes. By creating these extensions, the standard approach to customising data tips can be used, i.e. a method with the appropriate signature is passed to the chart’s dataTipFunction property. The classes resulting from this approach would be something along the following lines:

/**
 * ColumnSet extension to expose the stack totals for public 
 * use, e.g. in a data tip function.
 */
public class ColumnSet extends mx.charts.series.ColumnSet
{        
    /**
     * @see StackedSeries.posTotalsByPrimaryAxis
     */
    public function get positiveTotalsByAxis():Dictionary
    {
        return posTotalsByPrimaryAxis;
    }
 
    ...
}

The minor downside to this approach is that the shortcut syntax for achieving stacked series, as used in the first example and explained above, cannot be used. The explicit syntax must be used to ensure that the extended version of the relevant StackedSeries extension is used.

The following example uses the approach presented above to provide customised data tips in the chart. The source code for the example includes the necessary extensions to the ColumnSet, BarSet and AreaSet classes, so feel free to use them.
You must have Adobe Flash Player 9 installed to view this application.

Save Flex chart as image

March 4th, 2009

The ability to allow a user to save a Flex chart, or in fact any Flex UI component, as an image has popped up on my radar several times over the last few years.  Solutions to the problem have generally involved producing a pop-up window with the UI component as an image that the user can then save, either by bouncing the information off a server (James Ward – RIA Cowboy and Flex Cookbook) or interacting with JavaScript (Doug McCune).  However, additions made to the framework in Flex 3 combined with new features of Flash Player 10 have made these cumbersome techniques redundant.  It is now possible to provide this functionality directly from your Flex application in two simple steps.

The first step involves capturing the UI component’s bitmap information.  The Flex 3 API introduced the ImageSnapshot class specifically to simplify this process.  The following line of code is sufficient to capture the image data:

ImageSnapshot.captureImage(myChart);

However, we are able to control the image capturing more precisely by using some of the method’s optional parameters. These allow us to specify the target resolution in dots per inch and the image encoder to use (the Flex 3 API provides a PNGEncoder and a JPEGEncoder).  So, for example, the following line of code would capture a chart as a PNG image at a  resolution of 300dpi:

ImageSnapshot.captureImage(myChart, 300, new PNGEncoder());

Now that we have captured the image data all that remains is the second, and last, step: saving the image data to the user’s file-system. Flash Player 10 introduced a number of changes to its security sandbox, principally the ability to programmatically prompt the user
to save a file to their file-system. This is done using the FileReference class, as shown in the following lines of code:

var file:FileReference = new FileReference();
file.save(image.data, "chart.png");

So, putting the steps together results in a method along the lines of the following code snippet:

/**
 * Attempts to save the chart to the user's file-system.
 */
private function saveChart():void
{
    var image:ImageSnapshot = ImageSnapshot.captureImage(myChart, 300, new PNGEncoder());
    var file:FileReference = new FileReference();
    file.save(image.data, "chart.png");
}

The application below shows this code in action. The values in the data grid can be changed,
with the changes reflected in the chart (just to show that I’m not cheating).
You must have Adobe Flash Player 10 installed to view this application.

The source code is now available.