loading shapefiles: actionscript3 or php?

I’ve recently become interested in loading shapefiles into Flash applications. Doing so opens up many possibilities.

  • Cartograms
  • Projections
  • Flash-based GIS

Perhaps best of all, it may mean that, for simple mapping tasks, I could do without ArcGIS altogether. I could load a shapefile into my Flash application, project it into one of dozens of projections, zoom into a continent, apply a choropleth, dot density, or proportional symbol symbology, and then export to SVG or EPS format for later touch-ups in Illustrator.

But we’re a long way from that. Two packages that I’ve recently stumbled onto make this easier.

  • Actionscript 3 SHP Library by Edwin Vanrijkom (who works for Adobe)
  • PHP Class Shapefile Reader by Juan Carlos Gonzalez

The former uses only Actionscript 3, thanks to the new ByteArray class. It easily loads and parses shapefiles, and has built-in functions to draw the imported polygons, polylines, or points. He also has classes for loading DBF files, in which shapefiles store their attribute data. And it’s blazing fast. I loaded a highly detailed world countries shapefile and drew it in less than a second. That’s nice.

So why would one bother with the PHP route, if one can do everything in the Flash environment? Great question. For simply loading and displaying shapefiles, you probably wouldn’t. But for more complicated, processor-intensive applications such as point transformation-based projections or diffusion-based cartograms it is nice to do the hard math and thousands of loops on the server side.

Mr. Gonzalez’s Shapefile Reader class gives us a good start. I’ve already set up an AMFPHP service to send the shapefile information back to Flash after the PHP class has done it’s heavy lifting. Time-wise, this approach has nothing on Mr. Vanrijkom’s AS-only approach. Loading the same shapefile as above in PHP, transmitting it via AMFPHP, and drawing it in Flash took about 5 seconds. Computing a point transformation for the hundreds of thousands of points in this shapefile (to construct a Mercator projection) on the server side, however, took only an additional second, and added one second more to the AMFPHP side. I haven’t tried to compute the Mercator projection in AS yet, but I will, and will report on the findings here. I’m guessing the AS-only approach will still be better/faster, but by a smaller margin.

Why PHP? Wouldn’t Python or C be much faster? Yes! But PHP is easier to use in Flash Remoting and many Flash developers (including myself) have little experience with these other languages. One advantage of the server-side technique, though, is that when I become more comfortable in Python, I could easily port my PHP to Python, and the Flash code would change very little.

So for now I’m going to be working with the PHP class, trying to optimize it for AMFPHP transmission to Flash, and seeing how easy it is to add additional projections, build topologies, and perhaps even tackle a cartogram in the PHP code. I’ll post some experimentation soon.

TimeSeriesGraph — now with flags!!

I’ve made a few changes to my AS3 Time Series Graph charting class. The biggest is the addition of flagging. Now you (the Flash programmer using the TimeSeriesGraph class) can easily add flags to your application’s chart (much like on the Google Finance charts, upon which TimeSeriesGraph is based).

It’s easy. To add a flag (after creating an instance of TimeSeriesGraph and passing it some data), just use the following public method:

myGraph.addFlag(date:Date, description:String);

So here’s a new version of my example chart — George W. Bush’s approval ratings, now with a few key events from his presidency to explain some spikes.

The above was created with the following lines of code (after processing the approval data into two arrays — one of dates, the other of data (see my original post for more info)):

myGraph = new TimeSeriesGraph(this);
myGraph.setGraphSize(stage.stageWidth, stage.stageHeight);
myGraph.drawGraphs(approval, dateArray);
myGraph.applySecondGraph(unsure, dateArray);
myGraph.changeLabels("Approval Rating", "Unsure", "%", "%");
myGraph.addFlag(new Date(2001,8,11), "September 11th attacks on American soil");
myGraph.addFlag(new Date(2003,2,20), "Beginning of Operation Iraqi Freedom");
myGraph.addFlag(new Date(2003,11,13), "Saddam Hussein captured in Iraq");

There’s nothing fancy about these flags — their behavior is not as cool or complex as those on Google Finance. But they work fine, and provide a minimal, quick way of flagging key points in your data

The current behavior (seen above) is just to show the flag’s description in the top bar on mouseover. However, there is one publicly broadcast (or dispatched) listener that you can listen for, if you’d like to perform some action whenever the user clicks on a flag. Simply use the following code anywhere in your application:

this.addEventListener(Flag.FLAG_CLICK, functionToBeCalled);

The description of each flag is stored as a public variable, so here’s an example of a function to simply trace the description of the clicked flag:

function clickFlag(e:Event) {
trace(e.target.description);
}

The latest .zip file of the charting class (and examples) can be found here. Or, feel free to go to town and check out my Subversion repository. Enjoy!!

that was difficult — installing the Python Imaging Library (PIL)

This post is a little dry, so I’ll start it off with a graphic — — of the number of visitors to this blog since October 8 (I won’t get into scale here). The preceding graphic is a sparkline produced using Joe Gregorio’s fabulously simple code. The other interesting aspect of the sparkline is that it is contained in an inline “data: URI”, meaning that it is not an external image, but rather is encoded directly into the html code (view source of this page to see what I’m talking about). There are many advantages to this scheme, but I won’t go into them here.

If you don’t see the preceding sparkline, then you’re probably using a crappy browser. You probably also can’t see my embedded Flash movies in other posts. Switch to Firefox or Safari. I believe in accessibility and whatnot, but this is a blog about cartography, graphics, and programming, so I have a few expectations for my audience’s internet capabilities.

Onto the main event. Joe Gregorio’s sparkline code requires the Python Imaging Library, or PIL. Python lacks a standard imaging library, but PIL is the de facto standard. Unfortunately, this means you must install it yourself. Easier said than done. At least, it was for me. If you’re very comfortable with Apple’s Terminal and UNIX commands then this should be no biggie. But alas I was not. I was used to DMGs and auto-installers. And it took me a *long time* to get this going. So below I’ll walk you through how I finally got the library installed. I should mention that this is on a Mac running Leopard and MacPython 2.5. I guess I can’t speak for other configurations, but the tips below should still hold true.

Before installing PIL you’ll need to have Apple’s XCode installed on your machine. I have no idea why, but it seems to be necessary. This is the easy part. Just go here and download the XCode 3.0 DMG (you’ll need a free ADC membership to download it). It’s a beefy download, but once you have it, just run the installer.

Assuming you have Python installed, you’ll need three more things to get this going: obviously PIL (latest tar.gz here), but also the JPEG library (latest tar.gz here) and Freetype2 (latest tar.gz here). Install libjpeg and freetype2 first. The most important thing to remember is to NOT extract these tar.gz files using the standard Archive Utility (don’t just double-click the tar.gz file in Finder). This will corrupt the files and lead to many errors later than you don’t understand (trust me here). Rather, open Terminal and navigate to the directory where you have your tar.gz files (I would just put them in your root directory — then you don’t have to navigate anywhere). Let’s install freetype2 first. Type the following in terminal (NOTE: you’ll be asked for your password a few times — this is just your standard system password):

tar zxvf freetype-2.3.5.tar.gz
cd freetype-2.3.5
./configure
make
make install

Hopefully that didn’t complain. If not, Freetype2 is installed!! Now go back to your root directory and we’ll install the JPEG Library:

tar zxvf jpegsrc.v6b.tar.gz
cd jpeg-6b
./configure
make
sudo make install-lib

Now we’re really having fun. The JPEG library should be installed. Now for PIL itself. Go back to where your tar.gz files are kept and type the following:

tar zxvf Imaging-1.1.6.tar.gz
cd Imaging-1.1.6
sudo python setup.py install

Now it’s installed and you’re ready to use it. However, the path to PIL won’t be in your standard Python sys.path, so you’ll need to add it before you can start rocking PIL. To do so, open IDLE or whatever you’re using for Python and type the following into the command line:

import sys
sys.path.append('/path/to/Imaging-1.1.6/PIL')
sys.path.append( '/path/to/Imaging-1.1.6/build/lib.macosx-10.5-i386-2.5')
import Image

In the above, ‘path to’ is the path to wherever you initially extracted the Imaging library. In my case it is simply ‘/Users/zachjohnson’. The second appended path is the path to the binary _imaging module which is also required by the PIL classes. The above path should work if you’re running Leopard. If it doesn’t, search your computer for ‘_imaging.so’ and use whatever path that file is found in. If ‘import Image’ in the above code didn’t complain, then you are off and running. Try running this file to generate the html for the sparkline shown above.

introducing time-series-graph

A Google Finance-esque Charting Class for Flash written in AS3

Over at Google Code you’ll find my new time-series-graph class. It’s a simple charting class that lets you insert a chart similar (very similar) to that used by Google in their Finance Pages.

Go over to my project page or just download the .zip file of the class. The .zip file includes

  • a folder called “Charting” that contains a .fla file that includes the movie clips necessary for the class (compile this for an example of the class)
  • a folder lib/com/indiemaps/charting that contains the actual .as file of the class

To use the charting class, do the following:

  • Drop my indiemaps folder into your lib/com directory
  • Open up Charting/charting.fla and copy the files in its library into your .fla file’s library
  • Use the following code in your .as or .fla file
var myGraph = new TimeSeriesGraph(this);
myGraph.setGraphSize(width, height);
myGraph.drawGraphs(valueArray, dateArray);
myGraph.applySecondGraph(valueArray,dateArray);
addChild(myGraph);

The above code should be pretty self-explanatory, except perhaps for the arrays. You need to have your data that you’d like to graph in two arrays. The first is an array of your data values, from first to last, in chronological order. The second needs to be an array of date objects that corresponds to your value array. Creating these arrays is up to you, though it should be pretty simple.

Other public methods include

removeSecondGraph() //removes the smaller bar graph, showing only the main graph in the graph window
changeLabels("First Label", "Second Label", "First Units", "Second Units")
mainAverage() //returns the average value of the currently viewed main window
mainMin() //returns the minimum value in the currently viewed main window
mainMax() //returns the maximum value in the currently viewed main window

Below you’ll find an example of the chart in action. I’ve loaded in George W. Bush’s Gallup Poll approval ratings on the main graph window and those who responded “unsure” in the smaller bar chart.

This was originally a part of the Hydrologic Dashboard that I’m working on for UW Sea Grant. I recoded it as a general class so that I (and others) could simply add it to any project. Of course, there’s plenty more to do. I can think of a dozen more public methods that could be added to the class. So if you’re interested, go ahead and check out the code and go to town.

Coding this has also made me realize that I need to learn Flex. Brendan Meutzner has already coded a very similar but better charting component for use in Flex. And apparently it took much less than the dozen+ hours it took me to create time-series-graph, thanks mostly to the use of mxml and Flex’s built-in charting components. I hadn’t seen Brendan’s component until after I completed mine; at least now Flash programmers can get in on the charting fun.

all i want for christmas is a ffffound account

FFFFound (that’s 4 F’s) is an image bookmarking service that is currently in private beta, meaning you need to be invited, somehow, to use it. I haven’t been invited yet.

I first found out about it on the wonderful notebook of Michal Migurski (Migurski’s found can be found here). It has also received glowing reviews recently over at Speak Up and kottke.org. Put simply, ffffound is like del.icio.us, except specifically for images. Users can save and share their favorite images, see others’ ffffinds, and get links to recommended images. And, like del.icio.us, it can lead to a broader view of what images are hot right now. And as pointed out by the kottke article above, this can lead to a new form of art curating:

In the case of FFFFOUND! and other RCOPIWSs [Randomly Curated Other People's Images White Background Site], I would argue that these sites showcase a new form of art curating. The pace is faster, you don’t need a physical gallery or museum, and you don’t need to worry about crossing arbitrary boundaries of style or media. Nor do you need to concern yourself with questions like “is this person an artist or an outsider artist?” If a particular piece is good or compelling or noteworthy, in it goes.

One notable deviation from the del.icio.us model is the lack of tags. I’m not sure the reasoning behind this, but some people just aren’t into folksonomies.

I can definitely see the utility in this. Over the past week I would have saved dozens of images. Including this one. Often we find images that we want to remember, but bookmarking the URL seems odd, and saving the image file to hard disk isn’t a very good solution. And neither of these options would include the social component that makes del.icio.us so great. Here’s hoping somebody invites me to ffffound or it goes public pretty soon.