Conditionally-Colored Flex Charts

February 20th, 2008 by grant · 20 Comments

»Color the columns in a chart depending on the data in Flex 2 or 3!

 

The charting in Flex is a pretty good tool, but there are a few small features that it would be really nice if it had. One of these would be the ability to have a chart series that changed colors depending on it’s value. Conditionally colored charts are something that a lot of us (and our customers) have grown accustomed to and we shouldn’t have to give it up with Flex. If you are like me you have probably been “googling” every variation of “flex colored charts” that you can think of. I couldn’t find an answer anywhere, but hopefully your search will end right here.

I wanted the ability to color charts based on their value, giving them red/yellow/green colors based on if they were lower/equal to/higher than a given value. The ability to use gradients instead of solid colors was also a requirement. I basically wanted to do something like this:

The columns below the line are red, on the line are yellow, and above the line are green. The need might arise to do more colors than this, so the code should be flexible

But almost as important as the final look of the graph itself was the ability to re-use the code without having to rewrite parts of it for each implementation. And I wanted to be able to use it in a flex application using only mxml, but still be able to use it in ActionScript if needed.

In the end I wanted to be able to define the threshold or goal as part of the data that the graph used and the code would color the columns based on that data (if it was greater than/less than/equal to). So the code to use the “coloring object” would look something like this (where we define High/Mid/Low colors):

<mx:series>
  <mx:ColumnSeries xField="Month" yField="Income" displayName="Income2">
    <mx:itemRenderer>
      <mx:Component>
        <utils:ColoredSeriesItemRenderer valueField="Income" thresholdField="Goal">
          <utils:thresholdGradients>
            <mx:Object>
              <mx:High><mx:Object gradient="[0x55dd55,0x005500]" /></mx:High>
              <mx:Mid><mx:Object gradient="[0xdddd55,0x555500]" /></mx:Mid>
              <mx:Low><mx:Object gradient="[0xdd5555,0x550000]" /></mx:Low>
            </mx:Object>
          </utils:thresholdGradients>
        </utils:ColoredSeriesItemRenderer>
      </mx:Component>
    </mx:itemRenderer>
  </mx:ColumnSeries>
 
  <mx:LineSeries xField="Month" yField="Goal" displayName="Goal"/>
</mx:series>

But to be flexible I also wanted to be able to define the goal in the code, where I could give it as many ranges with associated colors as I wanted. This code would look something like this:

<mx:series>
  <mx:ColumnSeries  xField="Month" yField="Income" displayName="Income1">
    <mx:itemRenderer>
      <mx:Component>
        <utils:ColoredSeriesItemRenderer valueField="Income">
          <utils:ranges>
            <mx:Array>
              <mx:Object lowerLimit="280" color="0xFF0000" />
              <mx:Object lowerLimit="240" upperLimit="280" gradient="[0xFFFF00,0x55FF55]" />
              <mx:Object lowerLimit="220" upperLimit="240" gradient="[0x5555FF,0x000099]" />
              <mx:Object lowerLimit="200" upperLimit="220" gradient="[0x0000FF,0x00FF00,0xFF0000]" />
              <mx:Object upperLimit="200" color="0xFFFF00" />
            </mx:Array>
          </utils:ranges>
        </utils:ColoredSeriesItemRenderer>
      </mx:Component>
    </mx:itemRenderer>
  </mx:ColumnSeries>
</mx:series>

Creating a custom item renderer allowed me (and now you too) to change the colors of the columns as they were being created. This works so much better than other solutions I saw (laying a filter on top of the columns) because it automatically changes when the column changes.

I created a new object out of it so you can just drop it in the directory where you keep your other library files (and change the package name if needed) and start using it. I have included it along with some sample files in a handy zip file for you… ;)

I hope this saves you all the time it could have saved me (if I would have found something similar).

Download the ColoredSeriesItemRenderer.as object with two full examples that you can compile and try in a handy zip file.

If you are not familiar with including custom made objects into an mxml file then you’ll need to know about packages. In the sample code I used a package name of “utils”, which means that the actionscript object is defined with an “utils” package declaration and is in an “utils” subdirectory. Also, the example files will require you to define the xml namespace in the Application tag. This is done by adding something like this: xmlns:utils=”utils.*”

Tags: Flex · Free · Programming · Tips

 

20 responses so far ↓

  • 1 graham // May 19, 2008 at 10:49 am

    I’ve used your code to give some of my charts the same feel, but I can’t seem to get the datatips to look the same. Could you give some advise please?

  • 2 Grant // May 19, 2008 at 10:09 pm

    Hi Graham,

    Can you post a little bit of code for me? I’d like to see if I can figure out what you are doing differently.

    Thanks,
    Grant

  • 3 Chuck // Jun 25, 2008 at 2:36 pm

    The code at the bottom of fillgraphics() needs a bit of tweaking.

    You have else { use default color } but no check if d.color is defined.

    //g.beginFill( _defaultColor );
    g.beginFill( d.color );

    works, but it should be something like sudocode

    if( d.color defined )
    g.beginFill( d.color )
    else
    g.beginFill( defaultColor );

  • 4 Chuck // Jun 25, 2008 at 5:56 pm

    by the way, thanks for the great tool, it works great with hard values in the ranges, but I’m trying to use data binding and am not having any success.

    For example, instead of using your lowerLimit=”240″ you use lowerLimit=”{GetLimit( 240 )}”

    GetLimit is defined to return numeric value. I’m having issues with the compiler, it says GetLimit is an undefined method. If I put GetLimit() in the ItemRender class it works fine, but that isn’t ideal.

    —-

    My above comment, I figured out the code to be:

    else
    {
    if( d.hasOwnProperty( “color” ) )
    g.beginFill( d.color );
    else
    g.beginFill( _defaultColor );
    }

  • 5 Chuck // Jul 8, 2008 at 6:04 pm

    Added more to that else {} block.

    var alpha:Number = 1;
    if( d.hasOwnProperty( “alpha” ) )
    alpha = d.alpha;

    if( d.hasOwnProperty( “color” ) )
    g.beginFill( d.color, alpha );
    else
    g.beginFill( _defaultColor, alpha );

  • 6 Grant // Jul 9, 2008 at 5:42 pm

    Chuck,

    Maybe you should be writing the articles and I should be the one learning. hehee.

    Thanks for your additions, I’m sure that someone will be very happy with them.

  • 7 jwopitz // Jul 10, 2008 at 3:42 pm

    I am rather new to charts though have been developing Flash/Flex for a long time.

    I am curious to know if you could achieve the same thing by implementing the fill logic via the fillFunction for the series. Would it enable gradients or just solid colors?

    Thanks,
    Justin

  • 8 Conditionally Colored Flex Charts - simplified « explorers’ club // Jul 14, 2008 at 1:06 pm

    [...] ran across this post (link) where someone had created a ChartItemRenderer subclass.  It seems to work brilliantly, but I had [...]

  • 9 Grant // Jul 14, 2008 at 8:01 pm

    jwopitz,
    Thanks for pointing that out. I created this functionality for a project that I was doing about a year ago, before Flex 3 came out. To my knowledge the fillFunction wasn’t in Flex 2.

    I wish it were, it would have saved me a lot of time (and hair).

    I haven’t used fillFunction yet, but it looks like it will do the same work.

    Great find!

  • 10 Michael Corbridge // Sep 8, 2008 at 8:07 am

    Grant,

    I used (and slightly modified) you columnRenderer class. Thank you for the great work!

    – mike

  • 11 Sana Pathan // Jan 9, 2009 at 9:57 am

    I am very thankful for ending my search of conditionally flex charts.
    THANKS A LOT.

  • 12 Brooks // Mar 25, 2010 at 11:03 am

    Grant, please help! says cant find base class Color..render, but I have it in there???

  • 13 Grant // Mar 30, 2010 at 3:51 pm

    Brooks,

    Can you post some of your code?

    Thanks,
    Grant

  • 14 Brooks // Mar 31, 2010 at 11:59 am

    got it. NOW, i have a better question and you seem like the expert for it. Can I change the actual color of the line? or just the data points??

    please feel free to email me as well!

  • 15 Grant // Mar 31, 2010 at 5:17 pm

    The color of the line can be changed, unless you want it to be a different color at different points on the graph. You might be able to do that, but I’ve never tried so I can’t help you there.

    To change the color of the whole line just add a linestroke tag inside your lineseries tag. Like this:

  • 16 Grant // Mar 31, 2010 at 5:21 pm

    One more try at posting code: ;)

    <mx:LineSeries xField=”Month” yField=”Goal” displayName=”Goal”>
    <mx:lineStroke>
    <mx:Stroke
    color=”0x0099FF”
    weight=”20″
    alpha=”.2″ />
    </mx:lineStroke>
    </mx:LineSeries>

  • 17 Brooks // Apr 1, 2010 at 1:41 pm

    Ah, i see yeh i was wondering if you could change it at different points on the same line series, but no worries what you have here has helped me solve my problem! Thanks a ton man!!

  • 18 Brooks // Apr 5, 2010 at 12:31 pm

    Grant another question… I have found that using an arraycollection i reach the max size pretty quickly for the amount of data im pulling in. Originally I convered my xml data to array collection to use it, but have reached max size apparently. Can you advise me on how to set the threshholdfield=”goal” (in your array collection) how can i do that with xml thresholdfield =”” etc.? Thanks, brooks

  • 19 Brooks // Apr 5, 2010 at 1:11 pm

    nevermind, got it grant! thanks aa

  • 20 Sateesh // Nov 1, 2010 at 1:31 am

    Wonderful efforts… how to use this for LineChart… could you advise please?

Leave a Comment


− 1 = eight