Hitachi Vantara Pentaho Community Forums
Results 1 to 15 of 15

Thread: Bar chart colors dynamically changed based on data value. Along with JavaScript vars

  1. #1

    Default Bar chart colors dynamically changed based on data value. Along with JavaScript vars

    Hey Everyone,

    I am sorry if I am asking a question that has been asked before, but I have not been able to get the desired funtionality out of my bar chart.

    First my goal. I would like to change the bar chart individual bars to different colors based on the data that they represent. For example, if they are less than 1 the color would be green, if they are between 1 and 3 they would be yellow, and if they were above 3 they would be red.

    I have seen two approaches to manipulating the charts, one is through using the extension points and putting a function in the value. The second is by using the post execution scripts.

    I have tried some of these, for example with extension points:

    bar_fillStyle | function(a){if(a<99.8){return "red"}else{return "green"}}

    However this always returns green. I added an alert(a); at the beginning to see what my "a" variable returned, and the message I got was "pvc.visual.Scene". This was clearly not the variable I wanted, because I wanted the data for each bar chart.

    I guess this boils down to being new at JavaScript (and CDE), but how do I know what a variable represents? I noticed that a lot of people seem to pass through "d" as a data variable but that also returns "pvc.visual.Scene". Do I need to define the variable somewhere before I can use it, or is there a list of already defined variables? Any help would be appreiated. Thanks!

  2. #2

    Default

    In the latest version i.e. CCC2 you should be able to use the following in post fetch:

    function f() {
    // Series Value : Color
    this.chartDefinition.colorMap = {
    "10": 'red',
    "12": 'green'
    };
    }

    To get access to the actual data, in the same postfetch:

    function f(values)
    {
    console.log(values);
    }

    values has metadata and resultset.

  3. #3

    Default

    When I do this the log describes values as "undefined". Is there anywhere I can go to see all these variables, like values, metadata, or resultset?

  4. #4
    Join Date
    Mar 2012
    Posts
    645

    Default

    Hi decarlo,

    if I understand well, you want to assign colors to bars according to their value being in value bucket A, B, C,...

    See this example for a clean way to do this. It works well with the legend. Basically, you create an auxiliary data dimension (another column...) that calculates the bucket in which the value falls.
    Then, you bind the color role to that new dimension.

    In the future, we might provide a way to configure scales to do the quantization directly, given the value ranges.

  5. #5

    Default

    try the f(values) in postfetch

  6. #6

    Default

    The function f(values) is working, thanks.

    Duarte Leao,

    I have seen this jFiddle before but am not too familiar with it too much. I use the Community Dashboard Editor to create my dashboards, and it seems to hide the javascript from the user. How would I go about using the javascript that you showed me?

    Thanks!

  7. #7
    Join Date
    Mar 2012
    Posts
    645

    Default

    Hi decarlo,

    most CCC options are available directly as CDE properties.
    For the ones that are not, usually complex-valued options, you have to use JavaScript to set them.
    See how here, here and here.

  8. #8

    Default

    Thanks for these links, they are quite usefull.

    So I have been somewhat successful in getting the bars to change colors. I have added this to my post execution

    function f(){
    var bar = this.chart.barChartPanel.pvBar;
    var chart = this.chart;
    var resultset = this.query.lastResults().resultset;

    for(var i = 0; i < resultset.length; i++){
    var dataVal = resultset[i][1];
    var child = bar.childIndex[i];

    if(dataVal > 0 && dataVal <= 2){
    alert('green '+dataVal);
    bar.fillStyle("green").root.render();
    }
    else if(dataVal > 2 && dataVal <= 4){
    alert('yellow '+dataVal);
    bar.fillStyle("yellow").root.render();
    }
    else if(dataVal > 4 && dataVal <= 7){
    alert('red '+dataVal);
    bar.fillStyle("red").root.render();
    }
    else{
    alert('red '+dataVal+" "+bar);
    bar.fillStyle("black").root.render();
    }

    }
    }

    I have two bars one is about 4.5 and the other is 9.8, so in theory I should have one red bar and one black bar. I get the alert for both red and black but at the end of it both of my bars in the chart are black. I assume this is because when I call the bar.fillStyle("black").root.render(); "bar" refers to the entire bar chart and all the bars in the bar chart. Is there any way I can apply the colors to the separate bars? I havent been successful as of yet, but I think I am getting closer.

  9. #9
    Join Date
    Mar 2012
    Posts
    645

    Default

    Hi decarlo,

    it's good that you experiment with CCC and direct access to the underlying protovis marks, that CCC uses.
    But, or I didn't understand what you're trying to do, or you're totally missing the point.

    Your traversing the resultset. This is simply an array. But every time you change fillStyle with a constant value, you're changing it in every instance of the mark, whatever its index is.
    For what you want, just specify the "bar_fillStyle" extension point, directly in the CDE property, or in code, in preExecution or postFetch.
    Pass a function to it that tests the value of this.scene.vars.value.value and returns an appropriate color.

    Anyway, apart from learning and experimenting, please don't go, neither in the "postExecution" way, cause you're re-rendering the chart twice, without any need, neither in the extension point way I just described. You're missing and duplicating things that CCC already does, in other ways.

  10. #10

    Default

    Duarte, you are a life saver, thanks for taking the time to help me figure this out. I got the desired functionality by adding the following to the PreExecution.

    function changeBars(){
    var cccOptions = this.chartDefinition;

    // For changing extension points, a little more work is required:
    var eps = Dashboards.propertiesArrayToObject(cccOptions.extensionPoints);

    // add extension points:
    eps.bar_fillStyle = function getColor(){
    var val = this.scene.vars.value.value;

    if(val > 0 && val <= 2){
    return 'green';
    }
    else if(val > 2 && val <= 4){
    return 'yellow';
    }
    else if(val > 4 && val <= 7){
    return 'red';
    }
    else{
    return 'black';
    }
    };

    // Serialize back eps into cccOptions
    cccOptions.extensionPoints = Dashboards.objectToPropertiesArray(eps);
    }


    Thanks for all the help resolving this!

  11. #11

    Default

    Another question, this is kinda a more in depth usecase for this scenario.

    So I can now return different colors based on the data values, but I just learned that sometimes these are not standard across the board. For instance the bars may have different cuttoffs.

    Bar 1: green = 0-2, yellow = 2.1-4, red = 4.1-6.0
    Bar 2: green = 0-1.5, yellow = 1.6-3.8 red = 3.9-6.0
    Bar 3: green = 6.0-4.0, yellow = 3.9-2.0, green = 1.9-0

    I feel like this would be easy for me to do if I could get the xaxis label for each bar, and than based on the name I would know how to evaluate the data. The problem is that I cannot for the life of me find the variable that would contain these labels. Any ideas?

  12. #12
    Join Date
    Jul 2007
    Posts
    2,498

    Default

    That's in something like this.scene.series
    Pedro Alves
    Meet us on ##pentaho, a FreeNode irc channel

  13. #13

    Default

    thanks for the direction, but am I missing something totally obvious? I am fairly new to Pentaho and saying something like "this.scene.series" means absolutely nothing to me at this point mostly because I dont know where to go from there. Is there any documentation where I could find more information about what this.scene.series contains? Its attributes and stuff, sort of like a javadocs. I feel like many people on this forum know a bunch of different variables to play around with in these things and I am always just lost with them.

  14. #14
    Join Date
    Mar 2012
    Posts
    645

    Default

    Hi,

    you can find some information about the scene structure here.

    Generally, when executing code in an extension point, you have a "scene" argument, that is the same as «this.scene».

    The scene contains a map of variables, named "vars", so you write «this.scene.vars».

    Variables are generally named after the visual roles of each chart type, so you'll have a "series" variable, a "category" variable, a "value" variable, for a typical categorical chart.

    A variable is itself an object cause you have, at the minimum, the variable's "value" and the variable's "label".

    So, summing it all up, for accessing the series value in an extension point, you write: «this.scene.vars.series.value».

    We're working on some sugar functions, accessible from «this» to make your and our wrists type less.

    Edit 2013-10-23: Added to master of CDF and CGG new sugar methods for this end.

    You can now use the following, from the pvc.visual.Context or the pvc.visual.Scene, to obtain the value of scene variables:

    • most charts (except, notably, the Pie chart): getSeries()
    • categorical charts: getCategory()
    • categorical charts and the legend scenes: getValue()
    • metric charts: getX(), getY()
    • cartesian axes panel scenes: getTick()


    There are also getSeriesLabel(), getCategoryLabel(), etc., versions of all these.

    For those variables/visual-roles for which no sugar method exist, or if you prefer/need a more dynamic approach, the new "get" method can be used as in the following example:
    • get("category") <=> getCategory()
    • get("category", "label") <=> getCategoryLabel()
    Last edited by duarte.leao; 04-10-2014 at 01:56 PM.

  15. #15

    Default

    Thanks, this post has been extremely helpful and I was able to get it to work using the vars.category.label. Thanks again!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Privacy Policy | Legal Notices | Safe Harbor Privacy Policy

Copyright © 2005 - 2019 Hitachi Vantara Corporation. All Rights Reserved.