Fun With Squeak: Sparklines!

Before you read this, I suggest you take a second to get familiar with sparklines. They are like tiny, embeddable plots, as originally coined by my statistics hero, Edward Tufte, in his book Beautiful Evidence.

In short, a sparkline is a small plot, generally a line plot, that is about the same height as the text around it. It should also have a dot at its maximum point, if it’s trying to be a real, true sparkline, and it should have a greyish line. However, there is a lot of variation here, and people even make sparkhistograms and sparkpiecharts.

Now that you know what sparklines are, I bet you want to make some. Well…okay! There are a lot of ways to do this. There are (presumably good) sparklines libraries for PHP, Ruby, jQuery (this one looks especially interesting), and even Excel. Or, if you’re a bit crazy and/or like doing things yourself, you could make your own sparkline library! I chose the latter option.

Thus, I’ve created a working, not-yet-perfect sparkline maker for Squeak Smalltalk. Squeak makes graphics (called Morphs) ridiculously easy, and thus makes sparklines pretty simple. Before we begin, a quick note: Squeak represents (x,y) positions as x@y.

Step 1: Create a Form for drawing. I’m going to make an ImageMorph, which has an empty ColorForm as its image. The ColorForm is given a width and height based on various properties of the SparkLinePlot instance.

morph := (ImageMorph new) openInWorld.
morph isOpaque: false.
morph image: (ColorForm extent: (((data size) + 2) * (pointSpace))@(height * 2) depth: 8).

Step 2: Prepare a few variables for use. x and y are going to refer to the (x,y) coordinates of each point, while scale is going to be multiplied against each data point to “shrink” the data to fit into the desired…well, scale.

scale := (height) / (data range).
x := y := 0.

Step 3: Next, we’re going to make a Pen object that’s going to draw the lines for us. Pen objects are remarkably simple to operate: just create one and move it around with the place:, go:, and goto: messages (e.g. “pen goto: 4@4″). The place: method doesn’t draw lines on its way, so it’s good for initial positioning.

pen := (Pen newOnForm: (morph image)) defaultNib: lineWidth.
pen place: x@y.

Step 4: Finally, we get the pen to draw! The do: message iterates over a collection, calling the associated block once per item in the collection (That is to say, the block runs once per item in the collection, each time setting the variable “dp” to be equal to that item). The y variable is negated because, in Squeak, positive y is down.

data do: [:dp |
		y := height + ((dp * scale) negated).
		(x = 0) ifFalse: [pen goto: x@y] ifTrue: [pen place: x@y].
		x := x + pointSpace.]

Step 5: Let’s make this plot pretty. I want to see a little indicator where the max data point is, and maybe even have it change colors from positive to negative. Not so hard! Inside the “data do: []” block, we could add stuff so it looks like the following:

data do: [:dp |
	y := height + ((dp * scale) negated).
	(x = 0) ifFalse: [pen goto: x@y] ifTrue: [pen place: x@y].
	(dp = data max) ifTrue: [ pen color: Color yellow lighter.
		                         pen goto: (x + (lineWidth * 2))@
                                                       (y - (lineWidth * 2)).
					 pen goto: (x - (lineWidth * 2))@
                                                       (y - (lineWidth * 2)).
					 pen place: x@y.].
	(dp >= 0) ifTrue: [pen color: colorPositive]
			 ifFalse: [pen color: colorNegative].
	x := x + pointSpace.]

Of course, all this stuff, the meat of the sparkline-generation, is wrapped up in a message called drawPlot. The message belongs to SparkLinePlot, a class that provides storage for variables and some convenience messages.

The point of having a SparkLinePlot class is that you can be both succinct:

plot := SparkLinePlot newWithData #(1 2 3 4 3 2 1 4 4).
plot drawPlot.

Or specific:
plot := SparkLinePlot newWithData #(1 2 3 4 3 2 1 4 4).
plot height: 10; negativeColor: Color black; lineWidth: 2; pointSpace: 20.
plot drawPlot.

One final note: These sparklines are created “in the world”: they just pop into being in the Squeak window alongside your code. However, you can drag them around and stuff, and if you right-click on them, you can export them into various image formats including JPEG and PNG.

Published in: on February 17, 2010 at 6:50 pm  Leave a Comment  

Fun With Squeak: Stack Overflow Parser!

The first thing I did when I started with Squeak was to see if I could program a nice interface for parsing Stack Overflow data. I’ve tried before, with various languages, but Ruby was way too slow and Clojure’s interface to SAX seemed…pretty difficult, for some reason. Would Smalltalk be any different/easier?

Yes (both different and easier). Well…the parser was easier, anyways. I made my own subclass of the SAXHandler class, and gave it a message for collecting data from each element:

startElement: elementName attributeList: attributeList
(elementName = 'row')
ifTrue: [self saveAttributes: attributeList]
ifFalse: [Transcript show: 'Parsed "', elementName, '" is not a  element. Skipping.'; cr

Then, I defined a saveAttributes message (so I don’t have to rewrite too much if I want to find different data later). I started out simply getting the reputations from all the people and putting them in a Bag: a dictionary that keeps a counter for each different item in it (so, if there are 5 1s, the bag would have a key “1″ and value “5″):

saveAttributes: attributeList
"This method should be edited to provide proper searching for the desired attributes."
| foundData |
foundData := (attributeList at: 'Reputation') asNumber.
self data add: foundData.

Note that “data” is a reference to an instance variable that was created as a Bag when an instance of the class is created. I took a while trying to figure out how to get this thing to actually return the bag so I could do stuff with it, and finally ended up rewriting the SAXHandler’s message parseDocumentFromFile: (I named it the much shorter parseFile:). I rewrote it so that it created the SAX driver and handler and started the parsing all in one function, and gave it a return statement, returning the data instance variable.

parseFile: fileName
   | stream driver parser |
   stream := FileDirectory default readOnlyFileNamed: fileName.
   driver := SAXDriver on: stream.
   driver validating: true.
   parser := self new driver: driver.
   parser useNamespaces: false.
   parser startDocument.
   parser parseDocument.
   ^ parser data

Thus, I could assign the results of the message to something or other like so (in a workspace):

aBag := StackOverflowParser parseFile: 'C:/dir/subdir/file.xml'.

Published in: on February 16, 2010 at 2:04 am  Leave a Comment  

Squeak Is Cool

I have been pretty busy, but here I am again and I’m going to talk about a new programming language. I haven’t dumped Clojure, but my Linux installation is bothering me so I’m using Windows for the time being, and I lack the energy to try to set Clojure up. Instead, I’m trying a new language: Squeak Smalltalk, since all I have to do is download a ZIP file, extract, and run for a full environment. I’ve never dipped my toes into Smalltalk before, but now that I have, I have to say: it’s pretty cool. The Squeak development environment is like the ultimate IDE ever. If you thought SLIME was good, this will knock your socks off (knocked mine). I can’t really go into too much detail in this post, but I’m learning from a great, free online book called Squeak by Example that has a detailed description of the whole thing.

Squeak reminds me a lot of Ruby, although the syntax is quite different. Both languages are (extremely and completely) object-oriented, both languages have a lot of high-level commands (Squeak has more) and both languages make use of blocks (do…end in ruby, [...] in Squeak). Here are some standard expressions in Squeak and Ruby:

Object method: [block].

Object.method {block}

#(1 2 3 4 5) do [ :n | Transcript show: (n * n); cr ].

[1, 2, 3, 4, 5].each do |n| puts(n*n) end

However, Squeak has some interesting components that I don’t think Ruby has (If it does, it’s hidden from the programmer). For example, conditionals are actually messages (the equivalent of methods) to the Boolean class. If the object that they are called on returns the right boolean value (true or false), the conditionals execute the contents of a block. Example:

(2 > 1) ifTrue: [Transcript show: 'Trueness!'].

You can chain them:
(2 > 1) ifFalse: [Transcript show: 'I hope to God this never happens'] ifTrue: [Transcript show: 'Whew, math still works!'].

Also, the periods at the end of the Squeak expressions are not accidental! Squeak ends expressions with “.” rather than “;”. Squeak doesn’t just generate variables like Ruby does, so you can’t go: “x = 1″ out of the blue. However, Squeak does let you declare temporary variables in a succinct and unusual way:

| x y |
x := 1
y := 2

Anyways, that stuff isn’t even the weirdest or most interesting aspects of Squeak, but it’s simple to explain, so there you go. Squeak is weird, sure, and the development environment might at first seem irritating (why can’t I write everything in one file with my favorite text editor?) but quickly becomes one of the most awesome things about Squeak as you get to know it. Give it a try, it’s pretty cool.

Published in: on February 15, 2010 at 10:35 pm  Leave a Comment  
Follow

Get every new post delivered to your Inbox.