iBrasten

My methods of calculating time are far superior to yours, in every way.

 

This is the blog of Brasten Sager, a software engineer, Mariners fan, guitarist, haphazard philosopher.

We all do stupid things.

August 30, 2006 @ 06:39 AM

Earlier this month, Ben Bleything posted an article about something that annoyed and/or surprised him in Ruby. I suspect maybe Ben regrets posting that particular post, as a lot of people misunderstood what he was saying.

Along those lines, I ran into a particular feature of Ruby that has continually caused me grief. Hopefully I can preempt some of the comments Ben received by noting that I completely understand why the code does what it does, and I’m not saying it should be different; merely that I instinctually expect it to be different.

Enumerable#inject. For whatever reason I continually space-out on the fact that the memo object becomes the object returned by the block. This can manifest itself in my code as an inject method that conditionally modifies the memo object directly. If the conditions are not met, NOTHING is done, and all hell breaks loose.

Even with this incorrect understanding of Enumerable#inject, I can usually write inject calls that work as expected purely by accident. This just re-enforces my misunderstanding, leading to more stupid mistakes later. (Most of these are quickly caught, but…)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Dumb method, but a proper understanding of inject.  This works.
[1, 2, 3, 4, 5].inject { |memo, elem| memo + elem }
# => 15

# This is what I tend to do.  It also works, but you can easily see
# it works by accident, and I'm misunderstanding how inject works.
[1, 2, 3, 4, 5].inject { |memo, elem| memo = memo + elem }
# => 15

# This is where it first starts to show up.
# This particular case is caught very quickly.
[1, 2, 3, 4, 5].inject([]) { |memo, elem| memo << elem unless elem == 4 }
# => NoMethodError: undefined method `<<' for nil:NilClass


# Here's where I get into trouble.
# I'm expecting [1, 2, 3, 4].
# This code does not raise an error, but I'm
# left with a bogus value.
[1, 2, 3, 4, 5].inject([]) { |memo, elem| memo << elem unless elem == 5 }
# => nil

Anyone else do anything stupid like that? Leave a comment!

Scruffy Nearly PI'd

August 21, 2006 @ 07:28 AM

has emerged from his weekend-long seclusion with a functional first-cut of pie charts for Scruffy. From my initial glances at graphs and code, I’m thrilled!

We’re still a week away from integrating this into a Scruffy release. A.J.’s got a few more features to add before it’s ready for public consumption (very cool stuff, I must say). But I wanted everyone to know they’re on their way, and thank A.J. for his much-needed work on this!

To 0.2.3… and BEYOND!

I’ve been quietly patching bugs and adding minor features. We’re up to 0.2.2 right now, so if you’re having an issue, please try 0.2.2 and see if your problem continues.

For the next couple releases, I’ll be cleaning up some of the complexity that’s been inadvertently pushed down to the user-level API. For example:

  • Common options such as hiding values, number of grid lines, legend orientation, etc. should be specified using a simple API on the graph.
  • Value formatting should accept a block for simple transformations.
  • I want to reduce or eliminate the need to refer to internal Scruffy classes for common use cases. “graph.layout = :standard” is preferable to “graph.renderer = Scruffy::Renderers::Standard.new”

Please continue sending me feature requests and bug reports, or just say hi and let me know how you’re using Scruffy: brasten AT nagilum.com.

Shameless Promotion

Just to quickly piggyback on my 15-minutes of “fame,” I am actively pursuing Ruby/Rails work - contracts, consulting, etc. If you have a need for a Ruby developer, please contact me at brasten -AT nagilum.com!

Scruffy Docs Updated!

August 17, 2006 @ 06:28 AM

The Scruffy Documentation has been updated to better reflect the current code. It is still a little light on examples, but at least a basic explanation of most things now exists.

Also, previous documentation was missing several code directories. The rake task has been updated to include those files, and documentation added to them.

Thanks to some feedback, I will be adding more examples to the documentation shortly, probably using the examples from my last couple posts here.

Scruffy 0.2.0

August 14, 2006 @ 03:56 PM

Well, I warned you.

Scruffy 0.2.0 has been released, and with it comes some significant changes. However, I said the majority of the changes would affect only the rendering system, and for the most part I stuck to that.

What’s new (Layout/Rendering) & what isn’t…

The result of these large changes is a pretty nifty rendering/layout engine that allows you to make your graphs look pretty much however you want. In addition, all elements on the graph have been made into components. You can move anything anywhere on the graph with ease.

To demonstate the capabilities of the renderers, I created a couple different layouts that are included with Scruffy. You can use them, or create your own.

Still no piecharts, but yes, those are coming, as are a few more chart types that I personally need.

Using Scruffy

The documentation is out of date at the moment. I will fix that in the next day or two to reflect the changes. The API for using the graph hasn’t changed much and is fairly simple. Below is a collection of code of resulting images.

Installing

1
2

    gem install scruffy

Using

1
2
3
4
5

    require 'scruffy'

    graph = Scruffy::Graph.new
             (...)

Examples

Split Graph

1
2
3
4
5
6
7
8
9
10
11
12
13
14

    graph = Scruffy::Graph.new
    graph.title = "Long-term Comparisons"
    graph.value_formatter = Scruffy::Formatters::Currency.new(:special_negatives => true, 
                                                              :negative_color => '#ff7777')
    graph.renderer = Scruffy::Renderers::Split.new(:split_label => 'Northeastern (Top) / Central (Bottom)')

    graph.add :area, 'Jeff', [20, -5, 100, 70, 30, 106, 203, 100, 50, 203, 289, 20], :category => :top    
    graph.add :area, 'Jerry', [-10, 70, 20, 102, 201, 26, 30, 106, 203, 100, 50, 39], :category => :top
    graph.add :bar,  'Jack', [30, 0, 49, 29, 100, 203, 70, 20, 102, 201, 26, 130], :category => :bottom
    graph.add :line, 'Brasten', [42, 10, 75, 150, 130, 70, -10, -20, 50, 92, -21, 19], :categories => [:top, :bottom]
    graph.add :line, 'Jim', [-10, -20, 50, 92, -21, 56, 92, 84, 82, 100, 39, 120], :categories => [:top, :bottom]
    graph.point_markers = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

… generates …

Stacking Graph Types

1
2
3
4
5
6
7
8
9
10

    graph = Scruffy::Graph.new
    graph.title = "Comparative Agent Performance"
    graph.value_formatter = Scruffy::Formatters::Percentage.new(:precision => 0)
    graph.add :stacked do |stacked|
      stacked.add :bar, 'Jack', [30, 60, 49, 29, 100, 120]
      stacked.add :bar, 'Jill', [120, 240, 0, 100, 140, 20]
      stacked.add :bar, 'Hill', [10, 10, 90, 20, 40, 10]
    end
    graph.point_markers = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']

… generates …

Multi-viewport Multi-layered (This was Fun)

1
2
3
4
5
6
7
8
9
10
11

    graph = Scruffy::Graph.new
    graph.title = "Some Kind of Information"
    graph.renderer = Scruffy::Renderers::Cubed.new

    graph.add :area, 'Jeff', [20, -5, 100, 70, 30, 106], :categories => [:top_left, :bottom_right]    
    graph.add :area, 'Jerry', [-10, 70, 20, 102, 201, 26], :categories => [:bottom_left, :buttom_right]
    graph.add :bar,  'Jack', [30, 0, 49, 29, 100, 203], :categories => [:bottom_left, :top_right]
    graph.add :line, 'Brasten', [42, 10, 75, 150, 130, 70], :categories => [:top_right, :bottom_left]
    graph.add :line, 'Jim', [-10, -20, 50, 92, -21, 56], :categories => [:top_left, :bottom_right]
    graph.point_markers = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']

… generates …

Scruffy 0.1.0

August 11, 2006 @ 05:04 AM

I released Scruffy 0.1.0 just before midnight this morning. 0.1.0 is the first release that I’m considering public. Support was added for rendering graphs to images (instead of SVG), as well as a legend.

Rendering to an image is fairly simple:
# Assuming graph is an instantiated Scruffy::Graph object

#Render to PNG
graph.render(:width => 800, :as => 'PNG')

#Render to PNG, save to file
graph.render(:width => 3500, :as => 'PNG', :to => )

You’d think you could save the SVG code to a file using o => ... without the :as option, but you’d be wrong. :) Expect to see that in 0.1.1.

I’d really like to get feedback from some people on this, but I should warn you that I expect to make some backwards-incompatible changes in the next week. I had some amazing ideas this morning on how to make the thing much more powerful and easy, and I’d like to get them in there are released ASAP. This likely means we’ll be jumping to 1.0.0 by the end of the week (backwards-incompatible releases usually require a whole version point increase).

But it will be worth it, I promise. :)

Anyway, go check it out.

Getting Scruffy With It

August 10, 2006 @ 09:40 AM

So I’ve been up to some fun stuff lately with projects and such, and I’d like to give my blog readers a head start on my latest one.

This last weekend I found myself with two desires colliding into one project. I’d been tinkering with SVG for a little bit and wanted to explore the possibility of SVG-based graphs, and at the same time I needed some functionality out of a graphing library that Gruff didn’t provide out-of-the-box. So in standard Ruby fashion, I decided to roll my own graphing library. The result of that is the (http://scruffy.rubyforge.org) project.

What It Does, What It Will Do, Etc…

Keep in mind I haven’t officially released this yet, I hope to do that by this weekend. There are a couple features I want to throw in before it goes super public. At that time I will go into more detail with the whats and whys. Until then, here’s a quick summary:

Current Features
  • The graphs are built entirely using SVG. Whether or not you want to render to SVG is up to you, you will be able to render to another graphics format easily. But building the whole thing on SVG provided me with some fun capabilities as well as extremely clean, maintainable code.
  • It’s very easy to extend. The first release will include 5-8 graph types, most of which are only a few lines of code. Adding new graph types is extremely easy, so I’m hoping to see custom graphs popping up all over.
  • Very useable. For the most part, Scruffy doesn’t limit you if it doesn’t have to. Graphs can contain multiple types (line graph, area graph, etc) at the same time, and Scruffy doesn’t need to know what size your graph will be until the moment it’s rendered. And rendering doesn’t affect your graph in any way, you can continue adding data, changing colors, and re-rendering at any size with the same graph object.
Coming Soon (like, very soon)...
  • As of this writing, you can’t actually render the graphs to an image format other than SVG, at least not directly. This is a 5-line change, and I plan on adding that capability tonight. If you really need to see that working before tonight, you can use RMagick to transform the resulting SVG into a format of your choice.
  • Specifications. Yes, I do have specifications mostly finished for behavior testing Scruffy (should you wish to make any changes), and they will be checked in shortly.
Not Present in First Release
  • Pie charts will not be included in the first release. I know these are very important, and they will be done in short order, but I wanted to get Scruffy out there before I worked on these.
  1. Installation
Installing Scruffy is easy:
gem install scruffy
  1. Basic Example

You can find more detailed examples in the documentation.

  graph = Scruffy::Graph.new(:title => 'Sales')
  graph.add :line, 'Brasten', [100, 200, 140] 
  graph.add :area, 'Jeff',    [150, 100, 40]

  graph.render(:width => 1500)
  1. Documentation You can view documentation online at http://scruffy.rubyforge.org/doc