CategoriesArchiveSearchRandom
View the archives

or

Search the archives
 

Archive for July, 2009

Concerning Color Algorithms

Thursday, July 30th, 2009

Long ago I worked on an interface for a reporting system that displayed transaction volume data as a large table; days on one axis and hours on the other.  To improve the readability of this densely packed data we wrote a coloring algorithm to change the background color of the table cell.  The algorithm colored each cell in relation to every other cell using the minimum and maximum values of the displayed data.  The effect was quite good.  Users could instantly see patterns in the data without having to read the actual number in the cells.  This data display, though simple was one of the main selling points of the system.  End-users like the sexy packaging, the unseen technology that actually makes the system a wonder is only of interest to the developers — unless of course it does not work.

I spent a lot of time improving the UI of the system as a project once, and when my CTO asked me what I was going one day I said “optimizing the color algorithm” — that was a mistake.  I didn’t sleep for the next 6 months as I was assigned the new, high priority, has-to-be-done-now project.  For a new technology, that I had no idea how it worked.  It was fun, but that’s a story for another day. The reason I raise this here is that I never finished the intended work on the color algorithm. One of the major goals that I never got to was to fix the color range. The algorithm as implemented ended up with colors that transitioned from purple to yellow. I wanted to improve the algorithm to output colors that transitioned from red through yellow to green. Never got done.

Recently I was working on a project that required some visual UI work. One of the elements was a bar chart that displayed volume over time. So I used the same-old, same-old color algorithm (in PHP):

/* 
* getColor()
* $max := the highest value in the set to be colored.
* $min := the lowest value in the set to be colored.
* $c := the current item's value.
*
* Returns a string; the HEX representation of an RGB color.
*/
function getColor( $max, $min, $c) {
$j=0;
$r=0;
$g=0;
$b=0;

$j = $max != $min ? ( $c - $min ) * 20 / ( $max - $min) : 0;
$j = $j > 20 ? 20 : $j;

$r = 5 + $j;
$r = $r > 15 ? 15 : $r;

$g = 5 + $j/2;
$g = $g > 15 ? 15 : $g;

$b = 10 - $j/2;
$b = $b < 0 ? 0 : $b;

return sprintf( "%01x%01x%01x%01x%01x%01x", $r,$r,$g,0,$b,0 );
}

Simple right? Well using that you end up with this:
Old getColor output

So I started scratching my itch to fix the colors.

My first thought was to just ask a question over at StackOverflow [stackoverflow.com]. As I was typing in my question the system suggested existing questions… and since it’s an SO faux pas to repeat questions I started looking at them. It didn’t take long before I found two questions that seemed to be pointing me in the right direction: 1. Generate colors between red and green for a power meter [stackoverflow.com] and 2. Color scaling function [stackoverflow.com].

Reading the answers to those questions it took about 30 minutes to do this:

/* 
* getColor()
*
* $max := the highest value in the set to be colored.
* $min := the lowest value in the set to be colored.
* $c := the current item's value.
*
* Returns a string; the RGB representation of a color (eg. "rgb(255, 255, 255)").
*/
function getColor( $max, $min, $c) {
   $h = (.33 / ($max - $min)) * ($c - $min);
   $s = .8;
   $v = 1;

   $rgb = hsv2rgb($h, $s, $v);

   return(sprintf("rgb(%d,%d,%d)", $rgb['r'], $rgb['g'], $rgb['b']));
}

/* 
* hsv2rgb()
*
* $h := the hue, normalized to 0-1.
* $s := the saturation, normalized to 0-1.
* $v := the value, normalized to 0-1.
*
* Returns an associative array containing the red ('r'), green ('g') and blue ('b') values in the range 0-255.
*/
function hsv2rgb ($h, $s, $v){
   $rgb = array();

   if($s == 0){
      $r = $g = $b = $v * 255;
   } else {
      $var_h = $h * 6;
      $var_i = floor( $var_h );
      $var_1 = $v * ( 1 - $s );
      $var_2 = $v * ( 1 - $s * ( $var_h - $var_i ) );
      $var_3 = $v * ( 1 - $s * (1 - ( $var_h - $var_i ) ) );

      if ($var_i == 0) { $var_r = $v ; $var_g = $var_3 ; $var_b = $var_1 ; }
      else if ($var_i == 1) { $var_r = $var_2 ; $var_g = $v ; $var_b = $var_1 ; }
      else if ($var_i == 2) { $var_r = $var_1 ; $var_g = $v ; $var_b = $var_3 ; }
      else if ($var_i == 3) { $var_r = $var_1 ; $var_g = $var_2 ; $var_b = $v ; }
      else if ($var_i == 4) { $var_r = $var_3 ; $var_g = $var_1 ; $var_b = $v ; }
      else { $var_r = $v ; $var_g = $var_1 ; $var_b = $var_2 ; }

      $r = $var_r * 255;
      $g = $var_g * 255;
      $b = $var_b * 255;
   }

   $rgb['r'] = $r;
   $rgb['g'] = $g;
   $rgb['b'] = $b;

   return $rgb;
}

New getColor output

That’s great! Now maybe I’ll play with the hue bounds, the saturation and the value, but it looks fairly good on my first try.

Moral of the story: this is what StackOverflow is for; getting an answer to a question without even asking it… Because you are not re-inventing the wheel, someone had your problem before, and maybe someone found the answer already. SO, thanks to Paul Dixon [stackoverflow.com] (also here [blog.dixo.net]) and ΤΖΩΤΖΙΟΥ [stackoverflow.com] for their answers!

Happy Birthday Tori!

Tuesday, July 28th, 2009

IMG_7375

Happy birthday Tori.  It will be years before you can even read this, and you won’t remember the party but I know the happiness you show — at the party and always — continues.  If, and when, you look back I hope you will be able to understand that the past 12 months has been the best, the most rewarding, year of my life.  There are so many to look forward to, I can’t imagine how it can feel any better but I’m excited to find out.  I love you.

Published 2

Tuesday, July 21st, 2009

I’ve been published; [confusion.cc] again… This time by the Norwegians:

Delte Meninger

I don’t read Norwegian but judging from the website [deltemeninger.no], it’s something to do with ‘the social web’. My photo (here on Flickr [flickr.com]) appears on page 37. Funny that neither this photo nor the one chosen for the cover of Vocabulaire du chinois contemporain 1 are ones I would consider to be among my best [flickr.com].

Interesting that the published cover above (scanned from the book I got) differs from the cover distributed with the ebook in HTML format here [f9.no].

One small step

Monday, July 20th, 2009

Buzz Aldran's boot print on the moon.

It’s not Armstrong’s [wikipedia.org] “one small step” footprint, it’s a later footprint by Buzz Aldrin [wikipedia.org] but it is from the Apollo 11 mission.

That was 40 years ago today… shouldn’t I be able to make one by now?

The sidewalk incident

Wednesday, July 15th, 2009

This is another rant on the lack of common courtesy in the world, in general and in Singapore in particular… so if you are tired of listening to me complain about how fucked up most people are… move along and ponder the rainbow puking panda of explore… [flickr.com].

Still with me?

Good.  Let me set the stage… Candice and I took Victoria for a walk last night, we do this most nights — well maybe not most but a lot.  On our walk we traverse a long sidewalk along a plot of undeveloped land that is quite old and not very wide.  Two people can walk side by side comfortably but no extra room.  Additionally it has been quite wet in Singapore recently, raining often so the ground, while not muddy was wet.

Now for some visual help in explaining this particular fuck-headed rude behavior, yes I’m a geek I made a picture to help explain…:

The sidewalk incident as it happened.

As Candice, Victoria and I walked along said sidewalk another couple, a teenage girl and guy, approached us headed in the opposite direction.  This can be seen in step 1 of the figure above.  Nothing wrong with this, both the guy and I are walking next to our respective partners.  This makes conversation easier.  In this case the couple approaching us was even walking to their left — the appropriate orientation when walking in Singapore another oft-ignored guideline.

In step 2 you can see that both the guy and I have moved to our lefts.  I have moved further but he has begun to move left to allow for Candice, Victoria and I to pass on the right.  Great.

The problem, shown in step 3, is that he did not continue his move to the left.  Rather than getting behind the girl (or in front) for 30 seconds to allow us to pass easily, he was so obsessed with standing next to his girl that he managed to take up most of the sidewalk, thus forcing Candice and I to stop and wait or move off the sidewalk or… I don’t even know what he expected… But this is what he go:

“Get the fuck to the left you dip shit.  Have some fucking common courtesy and let other people use the sidewalk”

He kind of stared at me like a fish out of water… mouth opening slowly and eyes unable to focus.  We walked on.

The girl said something rule a few second later so I yelled back “shut the fuck up.”

As a side note my asshole attitude in cases like this has been developed after 4+ years in Singapore dealing with people who are so programmed by the nanny state in so many aspects of their life that they can’t think on their own and have therefore lost all common courtesy and common sense.  I used to be much nicer about things like this — I’ve always complained about dip shits but now I’m like a Manhattanite…  Cussing at them releases my frustration and they are so brain dead it can’t hurt them.

Anyway, in the interest of public service this is how it should have happened:
The sidewalk incident as it should have happened

See?  Now we can pass each other with nary-a-problem, birds sing, babies laugh and the soft light of the sun shines down and a happy ending.

Maybe I’ll diagram the proper way to not-be-that-asshole-trying-to-shove-their-way-on-the-train-before-people-can-get-off for everyone’s benefit.  And what about the I-can’t-be-bothered-to-watch-where-I-am-going-because-I-am-too-busy-<playing a game on my DS|PSP or texting or watching something on my PMP> issue that seems to be so in vogue?  Well, I’m not saying there is a problem with this behavior but let’s take all the manhole covers off and see if the problem fixes itself [telegraph.co.uk].