Random Etc. Notes to self. Work, play, and the rest.

Archive for January 2008

Simple Text Outlines in Flash

(This post is part of the series I threatened to write about actionscript 3.)

For the mySociety travel time maps I wanted to have user-defined labels that looked pretty much like the map styles in the OpenStreetMap base maps we were using, like this one:

London SW1P 4DR, from OpenStreetMap.org (licensed CC-BY-SA)

It turns out Flash doesn't have a way to draw the outlines of text easily, nor does it have a stroke filter like Photoshop. I tried a few different solutions that didn't work out, including a combinations of ConvolutionFilters (too hard to get right), GlowFilters (too blurry) and stacks of offset BevelFilters (nasty looking edges). Since the only thing in Flash that has the same quality antialiasing as the text does is, well, more text, that's what I ended up using. It looks like this:

Flash Text Outlines

I've included a sample SWF and pulled out the relevant AS3 code (for Flex Builder) in the full post, below.

(more...)

mySociety Travel Time and House Price Maps

O'Reilly Radar has the scoop on the most recent thing I've finished working on at Stamen. Interactive travel time and house price maps for London. Go play, and read what mySociety have to say, including the ones for BBC TV Centre and the Olympic Stadium site. Then come back and read this full post if you want the background info...

mySociety travel time map for SW1P 4DR

I've had a slow debate running with mySociety's Tom Steinberg since Euro FOO '06 about the best way to present travel time mapping, after we compared notes from my travel time tube map for London and the work Chris Lightfoot did on mapping transport travel times in the UK as a whole.

It seemed like the best way to settle this debate would be for mySociety and Stamen to work together updating their maps and see if we could get the best of both worlds. MySociety had comprehensive travel time data that they, uh, acquired from Transport Direct and Transport for London's journey planners. They also had an ace up their sleeves with the purchase of house price data for London from the UK's land registry. So far the volunteer-led map design had come up with strong proofs of concept, but a consistent set of presentation material was needed to make a compelling argument about the usefulness of these maps in the general case.

Our initial attempts to update the map began with a couple of days of Tom Steinberg and I alternately hunched over Photoshop and poring over the Edward Tufte books (passages recommended by the man himself) and looking for an appropriate colour gradient to represent travel contours (I didn't know about this resource at the time). All the while Francis Irving was back in the UK working on the heavy lifting behind the project, getting the data gathering and overlay rendering up to speed. We tried a few different things, but actually I thought that the palette Tom had worked on with mySociety volunteer Richard Pope was pretty good, and that's the one we used for these static contour maps. (Early mySociety results on the left, updated one in the middle, my final one on the right).

mySociety map options

These maps got much less satisfying with the addition of the house price zones, however. That was what Tom had originally asked us to help with; a thorny problem that needed a new approach. After poking around with the various two and three colour overlays with my colleague Mike it became clear that the combinations of masks and outlines were immensely confusing to work with. In addition to this problem, Tom and Francis at mySociety wanted to be flexible about the most appropriate configuration of house prices and travel times to tell a convincing story about the data later. My initial plan had been to set up a workflow in Photoshop to quickly produce the image files they needed. As the complexity of that task became clear, it got less and less attractive.

I had been resisting reaching for a programming solution to the design and cartography problem, but it became clear the manual processing was going to be onerous and difficult to keep consistent. So I asked Francis to provide me with a house price overlay that displayed small price increments using a grey-scale gradient, instead of solid colours between large price bands. Then whilst Tom Steinberg was out at a meeting I cooked up a quick slider experiment in flash to see if the approach had merit, and the difference was astounding. From that moment I was hooked on giving everyone access to what we were playing with, even if it meant working on it over Stamen's christmas break (time/budget constraints had already excluded building a slippy Google-Maps-style map, for example).

Here's a picture of what the house price masks looked like at that point, two colour bands on the left (constrained, harsh), and the new small price increment one (cloudy, beautiful) on the right:

mySociety house price mask comparison

The next task focused on getting a consistent set of base maps for the work, rather than using a hotch-potch of Ordnance Survey maps. The OS maps are world-class for accuracy, of course, but the cartography changes radically at each different scale and the maps aren't designed for on-screen viewing, let alone for data presentation. Naturally (given my history with the project) we turned to OpenStreetMap as a data source and asked Nick Black from ZXV to help produce maps that would be a drop-in replacement for the OS maps mySociety had been using so far.

OSM layers for mySociety maps

One thing that Nick's involvement got us was separate layers of data (above), which let us get more fancy with the presentation later on, and keep the labels on top of the data. Of course flexibility giveth, and flexibility taketh away: later on, it took me a while to figure out how to get the text rendering in Flash to match the mapnik style Nick was providing us (more on that later).

So, armed with new map layers, gradient overlays and masks for travel time and house prices, I set about creating a Flash piece that Tom and Francis could configure for themselves (and they did). They're tough cookies to please, of course, and getting something ready that we were all happy with (on volunteer time, across an 8 hour time difference) took patience on everyone's part. Looking at the finished pieces I hope you'll agree that it's worth it, and if you happen to be a transport routing expert sitting on a system that could help produce these maps for everyone, working around the issues Francis identified, then I hope you get in touch!

I have to leave this post here for now, but I hope to go into more detail about the Flash code (which is over here, under a BSD license) in a future post.

Stamen ‘07

Eric just posted a review of what we got up to at Stamen in 2007. My second Thanksgiving at the end of November 2007 marked the end of my first year in San Francisco; 2 months after that it still feels new, fresh and exciting.

The variety of projects and clients at Stamen over the last year or so has been extremely satisfying. I probably won't get a chance to write them up thoroughly for myself, but I'm proud to have had a hand (large or small) in all the projects Eric wrote up (and several more besides!).

Here's to 2008!

…And You Will Know Us by the Shape of Thames

Simon Foxell's Mapping London

Pete from Trulia sent me and Eric a copy of Simon Foxell's Mapping London, and I've been poring over its pages for the last couple of days.

Visually, my favourite map is definitely the one entitled "Social and Functional Analysis", which has a beautiful cellular structure:

London - Social & Functional Analysis

London - Social & Functional Analysis

But lest I get too involved with the aesthetics or content of any one particular map, or the print quality of the book, or the sheer Londonness of the thing, there's also the "Fetish Map of London", whose description warns:

[Chris] Kenny draws attention to the way that maps can become fetishised objects, by creating links between Kongo fetish figures—with their nailed in 'pledges' or 'commitments'—and the pins in a wall map. His map of London is covered in such pins, tacks and nails to the point of rendering it almost unitelligible.

Fetish Map of London

Normally that reference would be enough to keep me quiet, except I'm delighted to find that I'm mentioned in the book, on page 137 for my Travel Time Tube Map. Sadly the link is a little muddled (pointing people to del.icio.us instead of here) but I hope that can be corrected in future editions.

That aside, the book is of a very high quality and full of historical and contemporary mapping gems from all kinds of sources, including many that I can't find anywhere online (who says print is dead?). I've taken a few snaps of my favourites so you can get an idea of what's in store if you buy a copy, and I can definitely recommend that you do.

I'd been saving this title for a potential Pecha Kucha presentation, covering 20 different maps of London, but it doesn't look like happening any time soon. Meanwhile, maps of London are on my mind: watch this space for some new ones coming soon!

Unintuitive E4X Gotcha in Actionscript 3

This is the second in a series of posts about actionscript 3 that I announced earlier, and my last for today. Here's the feed of posts tagged as3.

Testing for the existence of a property on an Object is simple in actionscript 3:

 
 
var object:Object = { sub: "sub" };
 
trace("testing object properties");
 
if (object.sub) {
	trace("CORRECT: object has a sub element");
}
else {
	trace("WRONG: object has no sub element");
}
 
if (object.nosub) {
	trace("WRONG: object has a nosub element");
}
else {
	trace("CORRECT: object has no nosub element");
}
 

This yields the correct output:

testing object properties
CORRECT: object has a sub element
CORRECT: object has no nosub element

However, the same thing isn't as intuitive with XML and E4X:

 
 
var xml:XML = <xml><sub>sub</sub></xml>;
 
trace("testing xml element");
 
// don't do this, it will give false positives!
if (xml.sub) {
	trace("CORRECT: xml has a sub element");
}
else {
	trace("WRONG: xml has no sub element");
}
 
// don't do this, it will give false positives!
if (xml.nosub) {
	trace("WRONG: xml has a nosub element");
}
else {
	trace("CORRECT: xml has no nosub element");
}
 

This gives incorrect output:

testing xml element
CORRECT: xml has a sub element
WRONG: xml has a nosub element

The way to test reliably for the existence of xml elements is to check the length() method on the element:

 
 
trace("testing xml length()");
 
// this works to test for the existence of an element
if (xml.sub.length()) {
	trace("CORRECT: xml has a sub element");
}
else {
	trace("WRONG: xml has no sub element");
}
 
// this also works to test for the non-existence of an element
if (xml.nosub.length()) {
	trace("WRONG: xml has a nosub element");
}
else {
	trace("CORRECT: xml has no nosub element");
}
 

This yields the correct output:

testing xml length()
CORRECT: xml has a sub element
CORRECT: xml has no nosub element

Hey, it's boring but true!

Optimising Actionscript 3

This is the first in a series of posts about actionscript 3 that I announced earlier. Here's the feed of posts tagged as3.

Even with the great speed improvements that actionscript 3 and Flash 9 offer over actionscript 2 and Flash 8, I've occasionally had the need to revisit a project and look for places to optimise.

Miscellaneous Tips

Here's a list of suggestions I recently made to Gabe, who has his own actionscripting notes, as he was revisiting an old project looking to reduce CPU usage.

Tweaking the framerate

Simply dropping the framerate of an application might work as far as CPU usage goes too.

(Be careful with this though - if you're watching exclusively watching the CPU meters, and not the app, you might be optimising for the wrong audience!)

You can do that with the SWF metadata tag above your main app class in Flex Builder. The main bit is [SWF(frameRate='15')] but check the help file as you might have background colours and width/height in there already.

Memoization

You probably won't need it, but the trick used in Digg Arc (for calculating arc points before redrawing them) was to use what's called memoization — it helps with space-time trade-offs.

The idea is to remember the results of calling a function with certain arguments and only recalculate when the arguments change.

e.g. You might have a function that you're calling it a lot with the same values e.g. calculatePoints(1,2,3,4) that looks a bit like this:

 
 
function calculatePoints(a,b,c,d):Array
{
  var points:Array = [];
  /*
    lots of heavy math with a,b,c,d and points
  */
  return points;
}
 

Instead of calculating every possible variation, you can create a hash of the common results:

 
private var results:Object = {};
 
function calculatePoints(a,b,c,d):Array
{
  var key:String = [a, b, c, d].join();
  var points:Array = results[key] as Array;
  if (points) {
    return points;
  }
  else {
    points = [];
  }
  /*
    lots of heavy math with a,b,c,d and points
  */
  results[key] = points;
  return points;
}
 

Then if calculatePoints is called again with 1,2,3,4 you grab the answer from your results Object and return that instead of calculating it again. You probably want to set a limit on the number of things you cache though, so don't use this technique without thinking about that, and only consider this if your performance bottleneck is definitely one maths-heavy function!

Caveat Optimisor!

The only way to be sure about optimisations is to time things, manually or in your development environment, and bear in mind that even to experienced coders some performance issues can be unintuitive.

Writing About Actionscript 3

I've been programming interactive maps visualisations using Flash and Actionscript 3 for almost a year now. Actionscript 3 code is what's behind the scenes of most the Flash work I've been involved with at Stamen so far: Trulia Hindsight, Digg Arc, Twitter Blocks, Modest Maps and more.

So in the spirit of writing about what's important to me (and what I'm actually doing) instead of only writing tangential asides, I'm going to start writing occasional notes on Actionscript 3 here. Hopefully the ideas explored will contribute to my upcoming workshop at Etech in San Diego in March.

I considered starting a new blog, but I've had to deal with my fractured blogging personae twice before already. Hopefully there'll be enough visualisation and project links to keep non-coders interested.

All kinds of people read this blog for all kinds of reasons, you might not care who I spent New Year with and that's OK with me. The actionscript posts will be tagged with as3, if that's all you're interested in you can subscribe to a feed of them here. (The same is true of the Processing posts, which have a feed here).

The Importance of Perspective

I'm reading Kurt Vonnegut's Breakfast of Champions at the moment. Our protagonist, Kilgore Trout, is hitch-hiking in a truck which has PYRAMID written on it in massive letters. He wonders about the implications:

Gone to the Trouble

"Trout wondered what a child who was just learning to read would make of a message like that. The child would suppose that the message was terrifically important, since somebody had gone to the trouble of writing it in letters so big."

I often wonder the same thing about blogging, twittering, linking on del.icio.us, open source programming, and so on. The things we do in public, on the web, aren't always that significant. And yet to a passing reader they must appear to be very important to us. It seems that often we don't get around to writing the important stuff down, precisely because it matters so much.

My new year's resolution is to take time to write the important stuff down, in MASSIVE LETTERS.

New Year’s Degobah

Like Mike, I spent New Year in a holiday cottage in Sonoma, enjoying the company of friends good and new. Aaron was a permanent fixture in the kitchen, tending to his cassoulet for three days in a quest for the mythical crust.

Dagobah

Being vegetarian, I didn't sample the dish itself (though that didn't stop some people!). I did manage to document the eating using the timelapse feature on my camera. It's not quite up to Cassidy's standards, but it's a nice memento of the evening and it was interesting to have an instant replay of dinner as soon as we were done!


Degobah Timelapse from RandomEtc on Vimeo.