Home
Analytics
Changing Bar colors dynamically on a Chart
suma
Hi All,
I have created a report with Bar chart,now i need to change the color of the bar dynamically,suppose i have a threshold of 94 .if my series value is greater than 94 bar color will be green,if it is equal to 94 bar color is orange otherwise it should be in red, will it possible to do the same?
Thanks,
Suma
Find more posts tagged with
Comments
mwilliams
Hi Suma,<br />
<br />
In your chart script, you'd do the following:<br />
<br />
<pre class='_prettyXprint _lang-auto _linenums:0'>
function beforeDrawDataPoint( dph, fill, icsc ){
temp = dph.getOrthogonalValue();
if (temp > 94){
fill.set(0,150,0);
}
else if (temp == 94){
fill.set(255,128,0);
}
else{
fill.set(255,0,0);
}
}
</pre>
<br />
Hope this helps. Let me know if you have any questions.
suma
Hi Michael,
Thanks for your reply.I tried the script you have given,But the equal to condition is not working its taking less than condition only.is there any other way to give "Equal to"??
Thanks
Suma
suma
hi ,
In the first chart your code is working fine but in the second 1 ,the equal to condition is not working.could u plz tell wat is the problem???
Thanks
Suma
mwilliams
Suma,
The reason the second chart is not coloring as expected is because the actual value of the data is more than 3 decimal places and you're just checking for the 3 that are displayed. If you knew the exact value of the data, it'd work. You can see this by using the following for your else if:
else if (temp > 70.558 && temp < 70.560)
It works in this case because the small range covers the value of the bar you're wanting to be orange. If you had decimal datapoints that you knew the exact value, this would not be an issue.
suma
Hi Michael,
Thank you very much for your help.it is working fine nw.
Thanks,
Suma
suma
hi,
Is it possible to change the markers according to the condition???
if so which function we have to use??
Thanks,
Suma
mwilliams
Suma,
Are you meaning a marker line on the chart?
suma
yes
Thanks;
Suma
Lazarus33
Michael,
I'm trying to use conditional formatting as well in a bar chart and your code worked great. However, I have a bar chart with 2 different bars on it (as opposed to one) and only want the first bar to change color if it goes over a certain number, as opposed to both bars changing color. The second bar could remain the same color the whole time. Is it possible to do this via scripting or should I do two separate charts side by side?
Sorry if this is an easy question, but I have no experience in Java so any help would be so greatly appreciated. Thank you!
-Laz
mwilliams
Hi Laz,
When you say 2 different bars, you mean you have 2 series in the chart right?
Lazarus33
Yes, that is exactly right. I have two series in the chart and would only like to change the color of one series (bar) if at all possible. Thanks for your reply and for clarification on that!
-Laz
mwilliams
Laz,<br />
<br />
If you check the series with something like the following, you should be able to color them individually.<br />
<br />
<pre class='_prettyXprint _lang-auto _linenums:0'>
function beforeDrawDataPoint( dph, fill, icsc )
{
if (dph.getSeriesValue().toString() == "Series 1"){
fill.set(0,0,255);
}
else if (dph.getSeriesValue().toString() == "Series 2"){
fill.set(0,255,0);
}
}
</pre>
<br />
Hope this helps.
Lazarus33
Thanks so much for your reply, Michael!
I was going to try to implement the code you gave for individual series, but I'm not exactly sure how to integrate that into the original code you gave in an earlier post, which is working for me. Or do I not use that original code? Here's what I'm using in that chart so far:
function beforeDrawDataPoint( dph, fill, icsc ){
temp = dph.getOrthogonalValue();
if (temp > 206){
fill.set(255,0,0);
}
else if (temp == 206){
fill.set(174,174,174);
}
else{
fill.set(0,0,254);
}
}
Now I just don't know how to integrate the code you gave in the post above above (regarding the individual series) into it. Do I combine them or use one rather than the other?
My situation is I have 2 series in the chart, and I always want Series 2 to be gray (174,174,174) no matter what. However, I'd like Series 1 to be blue (0,0,254) if it's less than or equal to the value of Series 2, and red (255,0,0) if it is greater than the value of Series 2. To simplify it for this case I have hard-coded the value of Series 2 to be 206, but if it's at all possible in the future I'd like it to be dynamically based on and compared to the value of Series 2 as opposed to hard-coding it. But right now I'll take what I can get either way!
Does this scenario make sense? Again, sorry to keep asking about this but this forum has been such a great help to us in our BIRT usage. Thanks in advance for any help you may be able to provide!
-Laz
mwilliams
Laz,
You'd put the code you currently have inside the "Series 1" section of the new code in place of the fill.set() line and then in the "Series 2" section of the new code, make the fill.set() line fill with gray.
Lazarus33
Michael,
Sorry for the back and forth on this - I do appreciate your help more than you know! I tried putting the script in as I thought it should be but now my chart doesn't render at all. Here's the code I used:
function beforeDrawDataPoint( dph, fill, icsc ){
temp = dph.getOrthogonalValue();
if (dph.getSeriesValue().toString() == "Series 1"){
if (temp > 206){
fill.set(255,0,0);
}
else if(temp == 206){
fill.set(0,0,254);
}
}
else if (dph.getSeriesValue().toString() == "Series 2"){
fill.set(174,174,174);
}
}
Any thing that sticks out immediately as being incorrect in the code? Again, my apologies as I have no knowledge of Java whatsoever. Thanks again for your help!
-Laz
mwilliams
Laz,
Does it give you an error at all? If so, can you expand it and post it in here?
Lazarus33
Michael,
Quick update: somehow it's now rendering the chart and "works" in that it does show the chart properly, however the bar for Series 1 is always blue (0,0,254) using the code above. In other words, even if it goes above the value of Series 2 (which is hard-coded to 206 in this example), it is still colored blue, and Series 2 is always showing up gray (174,174,174) which is expected. It's almost as if it's ignoring the script altogether since those are the colors in the series palette already, but I could be wrong.
The script does validate with no errors, though. Would it be easier if I sent you the rptdesign file and corresponding data source to match?
Thanks!
-Laz
mwilliams
Laz,
That would be great. What version of BIRT are you using?
mwilliams
Laz,<br />
<br />
I'm using BIRT 2.3.1. The following code works as expected in my sample report.<br />
<br />
<pre class='_prettyXprint _lang-auto _linenums:0'>
function beforeDrawDataPoint( dph, fill, icsc )
{
if (dph.getSeriesValue().toString() == "Series 1"){
if (dph.getOrthogonalValue() > 200000){
fill.set(0,0,255);
}
else {
fill.set(255,0,0);
}
}
else if (dph.getSeriesValue().toString() == "Series 2"){
fill.set(0,255,0);
}
}
</pre>
Lazarus33
Michael,
I tried this code and I get no errors, however the Series 1 bar is always the same color regardless of whether or not it's greater than that value. So on your report, the Series 1 bar changes color if it's greater than your example value of 20000?
Also, to be sure - I keep the actual text "Series 1" on there and don't replace it with a row or dataSetRow name, correct?
I went ahead and emailed the files over to your birt-exchange email address to see if you can spot what I'm overlooking. Which is probably alot!
Thanks for your continued help on this!
-Laz
mwilliams
Laz,<br />
<br />
Since you actually set the series name, rather than keeping the default "Series 1" and "Series 2", you just need to change those to your series names in the code like below.<br />
<br />
<pre class='_prettyXprint _lang-auto _linenums:0'>
function beforeDrawDataPoint( dph, fill, icsc )
{
if (dph.getSeriesValue().toString() == "Student PFT"){
if (dph.getOrthogonalValue() > 206){
fill.set(255,0,0);
}
else {
fill.set(0,0,254);
}
}
else if (dph.getSeriesValue().toString() == "Population Average"){
fill.set(174,174,174);
}
}
</pre>
<br />
You'll also need to change the color of the legend block.
Lazarus33
Michael,
That makes perfect sense! Thanks for noticing that, for some reason I had totally overlooked that.
So now the code works perfectly - thank you so much!!
I also tried to mess around with it a little bit to get it to change colors based off the value of Series 2 instead of the hard-coded value of 206, but I couldn't get it to work. But this will work for now. Is that even possible?
Thanks so much, Michael - you are the man!!
-Laz
mwilliams
Laz,<br />
<br />
Put this in your onFetch script of your dataSet:<br />
<br />
reportContext.setPersistentGlobalVariable("PFTaverage", row["PFT-Score-Population-Average"].toString());<br />
<br />
Then, use this in your chart:<br />
<br />
<pre class='_prettyXprint _lang-auto _linenums:0'>
function beforeDrawDataPoint( dph, fill, icsc )
{
PFTavg = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable("PFTaverage");
if (dph.getSeriesValue().toString() == "Student PFT"){
if (dph.getOrthogonalValue() > PFTavg){
fill.set(255,0,0);
}
else {
fill.set(0,0,254);
}
}
else if (dph.getSeriesValue().toString() == "Population Average"){
fill.set(174,174,174);
}
}
</pre>
<br />
That should do it. Then do the same for the other chart with your other average.
Lazarus33
Michael,<br />
<br />
Your code works great! My only issue is that I actually don't even need it for the PFT chart, but only for the Ruck chart on my report. I used your code and it worked perfectly, but then I tried to change the variables as I thought they would need to be changed and put them in the Ruck chart instead and no values will go red even if they're above the other series. Here is what I put in the OnFetch script of the data set:<br />
<br />
reportContext.setPersistentGlobalVariable("RUCKaverage", row["Ruck-Population-Average"].toString());<br />
<br />
Then here's what I put for the Ruck chart:<br />
<br />
<pre class='_prettyXprint _lang-auto _linenums:0'>function beforeDrawDataPoint( dph, fill, icsc )
{
RUCKavg = icsc.getExternalContext().getScriptable().getPersistentGlobalVariable("RUCKaverage");
if (dph.getSeriesValue().toString() == "Student Ruck"){
if (dph.getOrthogonalValue() > RUCKavg){
fill.set(255,0,0);
}
else {
fill.set(0,0,254);
}
}
else if (dph.getSeriesValue().toString() == "Population Average"){
fill.set(174,174,174);
}
}</pre>
<br />
As you can see, I tried to rename them logically using the same scheme you had used on the PFT chart. Can you see what I may have done wrong?<br />
<br />
Thanks so much for your continued help with this!!<br />
<br />
-Laz
mwilliams
Laz,
That all looks right. The one thing that you need to fix is in your chart, "Series 2" is divided by 60. You'll need to do something like this in your line where you set the global variable as well, to match:
RA = row["Ruck-Population-Average"]/60;
reportContext.setPersistentGlobalVariable("RUCKaverage", RA.toString());
Lazarus33
BINGO!!
Works like a champ! I was wondering if that division might have been an issue but since it didn't throw an error on the script or anything I assumed not. But this is perfect.
Thank you SO much for all your help, Michael!! I'm learning something new every day when it comes to BIRT.
-Laz
mwilliams
Excellent! No problem on the help. Let us know anytime you have a question.
Lazarus33
Michael,<br />
<br />
Sorry to dig this thread out for another issue - but I've had to go another route now for dynamic bar chart coloring and was wondering if you or someone could help out. I have two series in my bar chart - "Student Ruck" and "Population Average",and I'm able to color code the first series by using the following code:<br />
<br />
<pre class='_prettyXprint _lang-auto _linenums:0'>function beforeDrawDataPoint( dph, fill, icsc )
{
if (dph.getSeriesValue().toString() == "Student Ruck"){
if (dph.getOrthogonalValue() > 240){
fill.set(255,0,0);
}
else {
fill.set(0,0,254);
}
}
}</pre>
<br />
Obviously this is looking at a hard-coded value (240) and then coloring that series bar accordingly. My question is this - is it possible to have the series bar only be a certain color PAST that number? In other words, if the value of that series is 280, then only the part of the bar above 240 would be colored red, and it would essentially be two-toned (see attached screenshot). Is that possible? I've thought of trying to use invisible markers or something similar to achieve this result but don't know how that would work either.<br />
<br />
Thanks in advance for any help you may be able to provide!<br />
<br />
-Laz
mwilliams
Laz,
Well, you could add a computed column to your dataset that figures how much the person went over the average for both PFT and Ruck. Those that don't go over would be assigned 0. Then you could make the chart a stacked bar chart and for series1, check for them being above average. If they are, only display the average. If they aren't, display their score. Add another series that stacks on the new computed column for how much they went over the average. In the series section under the format tab of the chart editor, you'd then need to deselect the checkbox for "stacked" for series two to make it stand beside the other bar.
After doing this, the only thing left to do will be figuring out how to display the correct overall value for the stacked bar. Let me know if I need to explain this more.
Lazarus33
Michael,<br />
<br />
Thanks so much for the quick reply! This seems like a great option. I'm trying to carry it out step by step but was wondering how much of this would be done via code as opposed to within the chart builder itself? To get started, I created a computed column in the dataset called "OverRuckTimeStandard" (since I only need this for the Ruck as opposed to both the Ruck and the PFT) and set the expression to be:<br />
<br />
<pre class='_prettyXprint _lang-auto _linenums:0'>row["Ruck-Score"]>=240</pre>
<br />
That gives me a result of all 0's except for those that do go above that 240, which are then 1's. Is that correct? Anyway, I tried to go in and make it a stacked bar chart then but couldn't quite figure it out and didn't know if you meant that it needed to be done via code since that's above my head.
But if not, can you point me in the right direction on how to do this? I've attached both the rptdesign file and the dummy data file (renamed as a txt file) in case that helps. Again - thanks for the help on this and I apologize for my lack of coding skills!<br />
<br />
-Laz