How I Made an Annual Color Algorithm

The foundation of my Kaleidoscope theme and Mini Quilt plugin is the color algorithm. For those who don’t know, the Kaleidoscope theme for WordPress is a simple theme I made (almost three years ago) that changes the colors of its pages based on when posts were written. (It’s the theme currently being used here.) It features quilts, which show recent posts in blocks of color. The small multicolored quilt in the sidebar of the theme is available separately, and can be added to any theme as a sidebar widget with the Mini Quilt plugin.

Both the theme and plugin are rather primitive by today’s WordPress standards because they’ve seen no changes in two and half years. But their current outdatedness is irrelevant to value of the underlying color algorithm. This article exists because someday someone may have the same idea I did and find this guide of what I did — both programmatically and philosophically — helpful. They may even find it useful to just lift my code — which is all GPL licensed — and use it as is. I’m not entirely satisfied that the methods I used here are the best possible ones, but I feel certain that anyone interested in the idea will benefit from knowing them.

The Mother Function

Let’s start with the primary function that either my theme or plugin calls. (Technically the currently available versions, call a similarly named but different function. As I’ve been working on getting better at web stuff, I decided to recode that version. If and when I update the theme or plugin, they’ll have this algorithm.)

function date_to_color( $day, $year ) {

	$red = color_maker( $day, $year, 20, 134 ); //18, 134
	$green = color_maker( $day, $year, 20, 240 ); //20, 240
	$blue = color_maker( $day, $year, 10, 0 ); // 10, 0

	return $rgb = "{$red}{$green}{$blue}"; //concanate the calculated colors and return them
}

Essentially, this is the function that is called anywhere — in WordPress the call looks like date_to_color(get_the_time('z'), get_the_time('Y')) — the color for a day is needed. You’ll notice that all this does is call the color_maker function three times and then return the concatenated (joined) six digit hexadecimal number to wherever it was called. The one thing I’d call your attention to is that it’s passing along four values to that function — the day and year that are submitted when this function is called, and two values that you’ll see later I call $broaden and $shift.

(If you’re wondering, it is considered good form to name functions you write with a prefix like kal_function_name. This prevents pollution of the global name space. For the purposes of this tutorial, I’ve left off the prefixes.)

The Color Determining Equation

Here we’ll begin the important function, color_maker. I’ve broken it into three separate sections that reflect the conceptual underpinnings of the function. Not coincidentally, when I first made this algorithm (the version that’s currently in the theme & plugin) these three parts were three separate functions. It was only upon looking at what I’d done at some distance that I saw that that was needless complexity.  Anyway, here’s the first conceptual unit.

function color_maker( $day, $year, $broaden=0, $shift=0 ) {

	$in_degree = .986*$day; // from 365.25=>360

	/* pshift =
	New degree value = incoming period shift + degree from year - sine function
	Sine Function = Random value * sine of shifted value
		> This essentially works to make the coming cosine function stay near its peak for a while
		> based on the magnitude of the random value
	*/
	$pshift = $shift+$in_degree-($broaden*sin((M_PI*($in_degree+$shift))/180));

The first line here — one of two that isn’t actually a comment — does a pretty simple thing. It converts from days of the year (of which there are 365.25), and makes that into 360 degrees in a circle. This is utterly straightforward.

The next part is a bit more complicated. Essentially, what we’re doing is getting a value ($pshift) ready for the next step,  a cosine function that really determines the color, by shifting our period values into more appropriate inputs to the next function. For example, January 23 needs different values for red, green, and blue in order to give the color I want. I do that here by shifting each color by the value passed on ($shift) from the first function. My shift values are 134 for red, 240 for green, and 0 for blue. This means that for January 23 we’ll pass along values of about 150, 260, and 20. If you know trigonometry well, you’re beginning to get a sense of what colors we’ll make.

There’s another component here though, which is that $broaden value I mentioned earlier. The need for broadening was something I realized as I started to see the colors the cosine wave function generated. They were frequently washed out and drab. I realized that if I was able to make the function’s peaks broader I’d have more color saturation which would correct that problem. That’s what that $broaden variable and sine function are doing. They’re creating values — with the yin and yang relationship of sine and cosine — that will favor the peaks of cosine and shrink the valleys. I don’t want to get too much into the math here (though if you’re interested I’d be happy to explain further), but just know that the larger the value I passed to $broaden in the first function, the stronger the peak-favoring effect is.

Determining what values to use for $broaden and $shift for red, green, and blue is more an art than a science. It’s where I drew on what aesthetic power I had (and the color accuracy of an uncalibrated old LCD) and where there could be the most room for improvement. To figure out what values to use, I created a page with boxes for each day of the year and fiddled until I felt the basic proportions of red, green, and blue were about right for a given season and day. Had I been using a different monitor in different lighting conditions, I may have settled on different (better) values.

The Darkness Determining Equations

Having gotten a single degree value ($pshift) for each color for a day, we need to make that into a color. That’s what this section does:

	$year_diff = date('Y')-$year;
	$hshift = .08*$year_diff; // to be used for further away years fading
	if ( $hshift > 1 ) { //this assures that the colors are always valid otherwise we could get negative numbers
		$hshift = 1;
	} 

	$HBASE = .82; //the center of the function; set between 0 and 2, lower are more saturated (darker)
	if ( $HBASE > 1 ) {
		$HSAFE = 2-$HBASE; // $hsafe is to ensure no final values greater than 2, which would create invalid colors
	} else {
		$HSAFE = $HBASE;
	}

	/* calced_color ==
	Use Cosine to create a weighted set of results between 0 and 2
	Multiply by 127.5 to get results between 0 and 255
	dechex for results between 0 and FF
	+Change the first (and only the first) +/- to toggle fade/darken
	*/
	$calced_color = dechex(127.5*(($HBASE-($HSAFE*$hshift))+(($HSAFE-($HSAFE*$hshift))*(cos((M_PI*($pshift))/180)))));

It’s important to realize that much of this is preamble. The last line — the one that begins “$calcedColor = ...“ — is the important one. Everything else is just tuning up before the show.

The first part of this related to the year. In addition to deriving a different color for each day, my color function also determines brightness based on age. Two posts from July 5, one from today and one from four years ago, will be noticeably different shades. This means that a quick glance at a color derived from the date can tell not only that a post is from Julyish, but Julyish a few years ago.

To do this we essentially figure out how much the submitted year — passed on from the preliminary function — differs from the current year, and then make an $hshift value for it. Because a post could conceivably be more than 12 years old — which is when they become uniformly black — any value over one that might arise is just adjusted down to uniformly black.

The next block of stuff are a number of constants that I keep around only for the sake of future tuning of the function. $HBASE is essentially what will be the center point of our cosine function, and $HSAFE just assures that no value of $HBASE will break the cosine function. They’re not really doing much here, but if I or anyone else feel like tweaking the function, I’d rather it be easy and obvious to edit than hard. (If you are interested in tweaking, higher values of $HBASE give lighter colors. Setting it to 1.3 gives pastel colors, setting it to .6 gives significantly darker hues.)

Finally we’re to that important final line, which does about twelve different things. The important ones, starting from the right and working left are: uses  multiplication with some $h values and cosine to get a basic value for a given color, and them shifts that around by adding and subtracting more $H values to get a value between 0 and 2. Then it multiplies by 127.5 to get a value between 0 and 255, the limit of two-digit hexadecimal numbers, and converts that number into hexadecimal, yielding a final range between 0 and FF. (Again, vagueness on the math is intentional, because otherwise this thing would be even longer than its current too-long length. I’m happy to provide more detail if desired.)

The Kludge

This final bit is a kludge that I couldn’t find a way around (even while I think there must be one.)

	if ( strlen( $calced_color ) < 2 ) { //single digit calced_color values give invalid colors
	  $calced_color = "0".$calced_color; // so add a zero if it's a single digit
	}	

	return $calced_color;
}

Essentially, after each color’s (red, green, and blue) value was determined between 0 and FF, I had a problem. If the red value was 253 in decimal, that converted to the two digit hexadecimal number FD. That was all well and good, but if the value of red had instead been 3 in decimal I would get 3 in hexadecimal. Because a five-digit color value like 3FDFD isn’t valid, I need to ensure that I instead get 03FDFD, which was assured by this function. Its essential logic is: “Is this number shorter than two digits? If yes, put a zero on the front.” Thus FD stays FD, but 3 becomes 03, and D become 0D.

After that kludge, the function returns its two digit hex number to the primary function, where it’s melded with the two others it derived to give a single six-digit value back to the theme or plugin that asked for a color. Thus given values like 188 (today’s day of the year) and 2011 (this year), it derives this sort of brownish yellow that you’re reading this post on. I think it conveys pretty well the dried out heat that I think of in July. It does this by iterating three time (once each for red, green, and blue) through a function with three steps. Those steps are essentially (1) shift to account for the amount of a given color that’s appropriate for the time of year (2) figure out the two digit hexadecimal value to get the right quantity for that color and (3) ensure success in making a six digit hexadecimal color.

I’ve not cured cancer for you, I know. But I hope I’ve given a new way to look at colors, and some valuable knowledge about one way to play with them. Before I close, it seems appropriate to note that I was turned on to this idea by Shaun Inman, though the implementation is all mine. I’m hoping that if my discussion has gotten you interested in this game, you now have some idea how to start.

4 Responses to “How I Made an Annual Color Algorithm”

    I’ve installed the mini quilt on my site (www.mybeautifulchandelier.com) and think it’s fantastic - a brilliant idea and great fun. The changing seasons is wonderful, but I was wondering if it possible to keep the colours bright.

      david (b) hayes said:  08/20/11

      Keep the colors “bright”? I’m afraid I can think of too many things that might mean to be able to answer what you intended.

      Are you worried about the year-on-year dimming, the drabness (or, alternatively, neon-ness) of many of these colors on certain displays, or specific ones that come up during the year? All of them can be dealt with, but each would be done in different ways.

    Hi David, thanks for getting back to me. The dimming and specific colours that come up is great. It’s the neon-ness that I’d like to change, if possible, so they would remain more like the colours you have on the mini quilt on your site.

      If it’s the difference between the colors on your site and this site, unfortunately there’s not much to do. The color algorithm (as I say a few times above) is meant to look vastly different over the course of a year and not change much day to day. Thus, if you’ve only got posts from a couple months, you won’t get nearly the variety you do if it’s from all around the year.

      The archives quilt on Frozen Toothpaste (http://www.frozentoothpaste.com/archives/) illustrates this point pretty well. The top few rows are really varied because I was posting monthly, but as you go down they look more and more alike because I was posting almost daily. If that is the concern (I’m not 100% sure it is), sadly that’s just the nature of this beast.

Leave a Reply