Raymond Camden's Blog Rss

Ask a Jedi: Two Y Axis for ColdFusion Charts

21

Posted in ColdFusion | Posted on 11-11-2008 | 5,865 views

Danny asks:

I basically want to know if it's possible to have two different y-axis units/values and title? Let's say series #1 is random from 1-10 and then series #2 is random from 1000-10000. If you put those two series onto the same graph having only one y-axis, then the first series will not be readable. So, left y-axis would feature the first series and the right y-axis would feature the second series.

I have to admit - I wasn't sure what he meant at first. Then he provided a nice sample graph:

This made sense to me. Basically he has two sets of data with different ranges of Y values. Danny said he tried the chart editor, which as my readers know is the first place I always suggest folks to look. I tried as well and like Danny, I wasn't able to get it working. I did some quick Googling and came across this example. I played around with the source code, did some tests back in the chart editor, and finally figured it out.

In the style XML you can define a series as using a different y axis. For example:

view plain print about
1<elements place="Default" shape="Line" drawShadow="true">
2<series index="0" shape="Line" isSecondAxis="true"/>
3</elements>

This says that the first series (remember, it is 0 based, since lord forbid people start counting with 1 like sane folks) represents the second axis. The shape should match the type of graph you want of course. You can use index="1" to specify the second series as well.

Ok, so let's do a demo. First, I'll create two queries of data:

view plain print about
1<cfset q = queryNew("year,sales","integer,integer")>
2<!--- generate random sales data --->
3<cfloop index="y" from="1994" to="1998">
4    <cfscript>
5    queryAddRow(q);
6    querySetCell(q, "year", y);
7    querySetCell(q, "sales", randRange(80,220));
8    
</cfscript>
9</cfloop>
10<cfset q2 = queryNew("year,employees","integer,integer")>
11<!--- generate random sales data --->
12<cfloop index="y" from="1994" to="1998">
13    <cfscript>
14    queryAddRow(q2);
15    querySetCell(q2, "year", y);
16    querySetCell(q2, "employees", randRange(2,8));
17    
</cfscript>
18</cfloop>

The first query represents sales figures over a 5 year period. The second query represents how many employees they had during those years.

Next up is the XML I'll use for the style:

view plain print about
1<!--- style from webcharts --->
2<cfsavecontent variable="style">
3<?xml version="1.0" encoding="UTF-8"?>
4<frameChart is3d="false">
5<elements place="Default" shape="Line" drawShadow="true">
6<series index="0" shape="Line" isSecondAxis="true"/>
7</elements>
8</frameChart>
9</cfsavecontent>

Notice there my elements and series tags. Now lets render the charts:

view plain print about
1<cfchart chartWidth="400" chartHeight="400" title="Sales" style="#style#">
2    <cfchartseries type="line" query="q" itemColumn="year" valueColumn="sales" serieslabel="Sales" />
3    <cfchartseries type="line" query="q2" itemColumn="year" valueColumn="employees" seriesLabel="Employees" />
4</cfchart>

The important thing to note is that the first chart series, sales, is what will be on the right side of the chart. Here is the result:

There ya go. Hope this helps others, and here is the complete template if folks want to quickly test it.

view plain print about
1<cfset q = queryNew("year,sales","integer,integer")>
2<!--- generate random sales data --->
3<cfloop index="y" from="1994" to="1998">
4    <cfscript>
5    queryAddRow(q);
6    querySetCell(q, "year", y);
7    querySetCell(q, "sales", randRange(80,220));
8    
</cfscript>
9</cfloop>
10<cfdump var="#q#">
11<cfset q2 = queryNew("year,employees","integer,integer")>
12<!--- generate random sales data --->
13<cfloop index="y" from="1994" to="1998">
14    <cfscript>
15    queryAddRow(q2);
16    querySetCell(q2, "year", y);
17    querySetCell(q2, "employees", randRange(2,8));
18    
</cfscript>
19</cfloop>
20<cfdump var="#q2#">
21
22<!--- style from webcharts --->
23<cfsavecontent variable="style">
24<?xml version="1.0" encoding="UTF-8"?>
25<frameChart is3d="false">
26<elements place="Default" shape="Line" drawShadow="true">
27<series index="0" shape="Line" isSecondAxis="true"/>
28</elements>
29</frameChart>
30</cfsavecontent>
31
32<cfchart chartWidth="400" chartHeight="400" title="Sales" style="#style#">
33    <cfchartseries type="line" query="q" itemColumn="year" valueColumn="sales" serieslabel="Sales" />
34    <cfchartseries type="line" query="q2" itemColumn="year" valueColumn="employees" seriesLabel="Employees" />
35</cfchart>

Comments

[Add Comment] [Subscribe to Comments]

Well, whadduya know... I knew you could do this in Flex, but I never knew it was possible with CF charts.
Nice example. I thought the random graph (now static) deserves some explanatory remarks:

Company X (withheld) started with 6 people in 1994 and had sales of $150k. There were a few bad eggs not carrying their weight that were summarily dismissed. As expected, profits rose to a record high of $200k in 1995 with only two remaining people. The bad eggs, after begging for their jobs back, were re-hired in 1996 (along with some clerical support). Company X's sales then plummeted as the bad eggs insulted customers. The clerical staff had to be let go in 1997 and then the rest of the bad eggs were fired by 1998. Sales started to increase with the two original people in Company X but it was not good enough. The company declared bankruptsy in 1998 after only having sales of just over $100k.
@Jeremy: Awesome. :)
I'm wondering is there an XSD file for this style xml?

I'm trying to create a graph with two axises but it's more complicated than the examples above and having an XSD file that would show me what attributes and elements I can place in a "Style.XML" would be really helpful.
Why not use the chart editor?
Wow, I just opened the chart editor for the first time...that's another world of its own. I'm now planning to invest some time reading the documentation on this stuff.

With that said I'm not going to ask "how do you do this?" without putting in the time myself to learn how to use the chart editor but I do want to share what I'm trying to do just to see if you think it is hypothetically possible (I believe it should be after checking out the chart editor).

I'm creating a CFChart with a variable number of series. Based on a users input I use a CFLoop/query that creates CFChartSeries on the fly. My chart also has line and bar graphs; I want the bar graphs to use the left axis and the line charts to use the right.

I realize that my style also has to be created on the fly to account for each additional series created in the chart but this led to strange behavior. The series using bar charts became stacked even when I specified that the CFChart placement parameter as "default" or "cluster".

Obviously, this is why I will have to play around with the chart editor. Like I said I'm not looking for a "how to guide" but rather I'd like to know for sanity/encouragement if it is possible to achieve my desired results.
One thing I have found is that - sometimes - there are some odd collisions between attributes sent via the tag and stuff sent in via XML. You may want to remove the stacked attribute and try to set it in XML instead.
This is exactly what I need. But instead of line, I want two bars side by side and a line for the second y axis. But the bars are stacked instead of next to each other. Is there a way in xml to get the bars side by side ?
Did you try the seriesPlacement argument?
This tip has been very useful to me, but I'm still having problems with the placement argument. My chart is similar to what Asaf was working on, it has two bar series using the left axis and two line series using the right. Got that to work, but unfortunately the bars are stacked instead of clustered. Tried doing the placement in the xml file as well as back in the cfchart definition, but can't get it to cooperate.
Will, I went into the chart editor, found a stacked chart, switched to clustered, and back and forth. This XML was used for stacked:

<elements place="Stacked" drawShadow="true">
<morph morph="Grow"/>
</elements>

This for clustered

<elements drawShadow="true">
<morph morph="Grow"/>
</elements>

Notice no place attribute. Try the XML above. (You should be able to leave off morph and dropShadow I think.)
Thanks, that helped as well. If anyone else runs into this problem, note that in the XML attributes for place are a little different than cfchart seriesPlacement, (i.e. elements place="clustered" , as oppose to using the cfchart seriesPlacement="cluster").

Got one more issue to resolve and I think I'll be done messing with this chart for a while. Is there a way to get a "title" on the secondary (right) axis?

Sure wish I had access to that/any web chart editor.
You do have access. It comes with ColdFusion.
I'm using Eclipse to code, I've searched high and low and it can't be found on my pc. I think my organization has Coldfusion on a server, but I think it's locked down.
You do know you can run CF for free on your own machine, right? :)
I'm back. I did find where my company was hiding CF/webcharts3d editor, and it has helped some but it'seems a little buggy. I'm having 2 format/style issues.

1. The title labels for my 2 y-scales are appearing different even though I haven't specified any style for either of them (i.e. the left axis title appears to be in plain text, while the right axis tile is bold and possible a little bigger in size).

2. I haven't set any scale max or min values for either y-axis, so they should default to the max/min of chartdata values (respectively) with a default rounding depending on the data values. Unfortunately, when the data values pulled have min of 0, yaxis2 (right axis) is rounding down into negative values instead of min'ing out at 0.

Has anyone else encountered these issues?
Found a work around for my first issue. I set a style for both axis titles and had to code the size of yaxis2 smaller than yaxis so that they would appear the same in an IE browser.

<yAxis>
<titleStyle font="Arial Narrow-14">Monthly</titleStyle>
</yAxis>
<yAxis2>
<titleStyle font="Arial Narrow-11">Cumulative</titleStyle>
</yAxis2>
Hi Ray

I have a normal chart ( type="horizontalbar") Is there any way by which I could put the X axis on the top ? Sort of like primaryXAxisplacement = Top|Bottom. I didn't find this setting in CF 8 / WebCharts3D 5.1. Any Idea how this could be done? Please help me

Thanks in Advance
Like you, I checked the charts editor. From what I see, there is no way of doing this.
Please can you guide to generate dual axis cf graph with stacked type. I need the xml style code for that.
I don't think it makes sense for a stack type - does it? Since the values are the same index, hence the stack.

[Add Comment] [Subscribe to Comments]