Posted in ColdFusion | Posted on 02-07-2008 | 5,370 views
Frank asks:
I have a question about how to use ColdFusion Chart.
I get data from a database table and wanted to show it on the chart. A typical data would be like this:
NAME MONTH COST ---------------------------------------- name1 2 100 name1 3 80 name2 1 60 name3 2 30 ----------------------------------------I would like to use name on X-axis and cost as Y-axis on a barchart. However, since I have two records of name1. There is only one name1 showing up. Do you have any experience of fixing this problem?
First off - what you really have here isn't one simple set of data, but a series of data. For each month, you have a set of users and sales. CFCHART supports multiple series of data per chart, so right away we can support exactly what you want. However you will run into a little issue when you try to use your data. Let me show you the code first, then I'll show you how I fixed it.
First off, I create a query of data:
2
3<cfset queryAddRow(data)>
4<cfset querySetCell(data,"name", "Name1")>
5<cfset querySetCell(data,"month", "2")>
6<cfset querySetCell(data,"cost", "100")>
7
8<cfset queryAddRow(data)>
9<cfset querySetCell(data,"name", "Name1")>
10<cfset querySetCell(data,"month", "3")>
11<cfset querySetCell(data,"cost", "80")>
12
13<cfset queryAddRow(data)>
14<cfset querySetCell(data,"name", "Name2")>
15<cfset querySetCell(data,"month", "1")>
16<cfset querySetCell(data,"cost", "60")>
17
18<cfset queryAddRow(data)>
19<cfset querySetCell(data,"name", "Name3")>
20<cfset querySetCell(data,"month", "2")>
21<cfset querySetCell(data,"cost", "30")>
I know that my series will be by month, so I then ask for all the distinct months:
2<cfquery name="getMonths" dbtype="query">
3select distinct [month]
4from data
5order by [month] asc
6</cfquery>
Notice I escape month since it is a reserved word in query of query. Now I create my chart:
2 <cfloop query="getMonths">
3 <cfquery name="databymonth" dbtype="query">
4 select *
5 from data
6 where [month] = <cfqueryparam cfsqltype="cf_sql_integer" value="#month#">
7 </cfquery>
8 <cfchartseries type="bar" itemColumn="name" valueColumn="cost" query="databymonth" seriesLabel="Sales for Month #month#">
9 </cfchartseries>
10 </cfloop>
11</cfchart>
Notice that I loop over my getMonths query, and for each month, I get a set of data for that month. I then supply that query to the chartseries tag. So far so good, but what happens when you view the chart?

That can't be right. In cases where we don't have data, the bars don't match at all. Unfortunately, I've seen this before. The cfchart support in ColdFusion sometimes seems to get confused by missing values. The only way to fix this is to 'complete' the data and ensure you always have a value for each month and each user. This could be done in SQL, but since my data was fake, I fixed it manually like so:
2 <cfset thisMonth = month>
3 <cfloop query="getNames">
4 <!--- do we have data for name X on month Y? --->
5 <cfquery name="hasData" dbtype="query">
6 select cost
7 from data
8 where [month] = <cfqueryparam cfsqltype="cf_sql_integer" value="#thisMonth#">
9 and name = <cfqueryparam cfsqltype="cf_sql_varchar" value="#name#">
10 </cfquery>
11 <cfif hasData.recordCount is 0>
12 <cfset queryAddRow(data)>
13 <cfset querySetCell(data,"name", name)>
14 <cfset querySetCell(data,"month", thisMonth)>
15 <cfset querySetCell(data,"cost", "0")>
16 </cfif>
17 </cfloop>
18</cfloop>
When run, we now get the correct chart:

And lastly, here is the complete template.
2
3<cfset queryAddRow(data)>
4<cfset querySetCell(data,"name", "Name1")>
5<cfset querySetCell(data,"month", "2")>
6<cfset querySetCell(data,"cost", "100")>
7
8<cfset queryAddRow(data)>
9<cfset querySetCell(data,"name", "Name1")>
10<cfset querySetCell(data,"month", "3")>
11<cfset querySetCell(data,"cost", "80")>
12
13<cfset queryAddRow(data)>
14<cfset querySetCell(data,"name", "Name2")>
15<cfset querySetCell(data,"month", "1")>
16<cfset querySetCell(data,"cost", "60")>
17
18<cfset queryAddRow(data)>
19<cfset querySetCell(data,"name", "Name3")>
20<cfset querySetCell(data,"month", "2")>
21<cfset querySetCell(data,"cost", "30")>
22
23<!--- get months --->
24<cfquery name="getMonths" dbtype="query">
25select distinct [month]
26from data
27order by [month] asc
28</cfquery>
29
30<!--- Begin Fixing Data --->
31<cfquery name="getNames" dbtype="query">
32select distinct name
33from data
34order by name asc
35</cfquery>
36
37<cfloop query="getMonths">
38 <cfset thisMonth = month>
39 <cfloop query="getNames">
40 <!--- do we have data for name X on month Y? --->
41 <cfquery name="hasData" dbtype="query">
42 select cost
43 from data
44 where [month] = <cfqueryparam cfsqltype="cf_sql_integer" value="#thisMonth#">
45 and name = <cfqueryparam cfsqltype="cf_sql_varchar" value="#name#">
46 </cfquery>
47 <cfif hasData.recordCount is 0>
48 <cfset queryAddRow(data)>
49 <cfset querySetCell(data,"name", name)>
50 <cfset querySetCell(data,"month", thisMonth)>
51 <cfset querySetCell(data,"cost", "0")>
52 </cfif>
53 </cfloop>
54</cfloop>
55
56<cfchart title="Sales" show3d="true" showLegend="true">
57 <cfloop query="getMonths">
58 <cfquery name="databymonth" dbtype="query">
59 select *
60 from data
61 where [month] = <cfqueryparam cfsqltype="cf_sql_integer" value="#month#">
62 </cfquery>
63 <cfchartseries type="bar" itemColumn="name" valueColumn="cost" query="databymonth" seriesLabel="Sales for Month #month#">
64 </cfchartseries>
65 </cfloop>
66</cfchart>


I have to admit, it wasn't a crucial need to chart this so I moved on to other problems, but it has sort of bugged me since then. Was I missing something easy?
If you want - send me some data, in the form of a fake query like above, and I'll try to get it working.
Just wanted to state that I think it stinks that CF cant handle a dataset for multiple series unless each set is the same and has values. Anyone know if they evolved in CF8 to solve this problem?
I had to go here
C:\JRun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\cfusion\charting\styles
But just search for the charting folder if you need to.
There you will find the file default.xml which you can open for editing. Find this line :
<frameChart autoAdjust="false" is3D="false" isInterpolated="true"> and change the isInterpolated to false.
http://www.coldfusionjedi.com/index.cfm/2008/9/17/...
<cfchart title="Sales" show3d="true" showLegend="true">
<cfloop query="getNames">
<cfquery name="databyemp" dbtype="query">
select *
from data
where name = <cfqueryparam cfsqltype="cf_sql_varchar" value="#name#">
</cfquery>
<cfdump var="#databyemp#" output="/Users/ray/Desktop/test.html" format="html">
<cfchartseries type="bar" itemColumn="month" valueColumn="cost" query="databyemp" seriesLabel="Sales for Name #name#">
</cfchartseries>
</cfloop>
</cfchart>
i looked in WebChart3D and couldn't figure it out,also one more thing please i see the autoAdjust property there and i don't see it in the xml file ,do you know what is it?
thank you.
I also see autoadjust in the editor too.
and about my second questin autoAdjust ,i see it in the editor but i don't see it in the xml file ,can you please paste a copy of the xml that include the auto adjust in it..
thanks again.
As for alt Text, did you try it? Specify a value for it and it shows up in XML. For me, I saw it like so:
<frameChart is3D="false" altText="mmoo">
about the altText ,i applied it to both my chart and to the WebChart3D chart ,it didn't give an error but it doesn't show up when the mouse is over the chart or over the title box,
does it requir any oth settings?
thank you.
Thank Raymond to your help,i really appreciated.
[Add Comment] [Subscribe to Comments]