Sunday, October 26, 2008

Silly cfchart tweaks

Whenever I run the webcharts3d to search for one thing, I invariably end up finding other small tweaks that might come in handy later. So with that in mind, I am writing up these small tweaks for future use.


SkipLabels
For when the Y-Axis labels get too crowded, the skipLabels attribute can be used to reduce the number of labels displayed, without changing the number of gridlines. For example, the chart on the right displays every other label by using skipLabels="1".



Formatting Y-Axis Dates
ColdFusion seems to display Y-Axis dates in MM/d/yy format. I have yet to figure out a way to change the format except using styles. Here are a few attributes that can be useful when working with dates on the Y-Axis.



LabelFormat:
Used to change the display format of Y-Axis dates. Warning, the patterns are case sensitive.
<labelFormat style="DateTimePattern" pattern="MM.dd.yyyy"/>

IsReversed:
Used to reverse the direction of the Y-Axis values. Can also be applied to other types, not just dates.
<yAxis type="DateTime" isReversed="true">

ScaleMin/ScaleMax:
Can be used to force the chart to display a "fixed" date range. The parseFormat pattern tells webcharts the format of the scaleMin/scaleMax dates. Again, the date patterns are case sensitive.
<yAxis type="DateTime" scaleMin="10/01/2008" scaleMax="10/31/2008"> <parseFormat style="DateTimePattern" pattern="MM/dd/yyyy"/> </yAxis>


MajorUnit/MajorStep:
Similar to SkipLabels, but more suitable for date/time ranges
<dateTimeStyle majorUnit="Day" majorStep="1"/>

Choice LabelFormat:
It turns out there is an interesting label format called "Choice". You can use it to display text instead of a numeric value. For example, display "YES" instead of 1. Just supply the number to text translation separated by a "#". Use a "|" to separate each set. Choice seems to require a little more tweaking than other types. But still an interesting option.

<labelFormat style="Choice" pattern="1#YES|0#NO"/>



Orientation/isMultilevel
A combination of orientation and isMultilevel can also be used to create more readable labels. The image on the left shows how the IsMultilevel setting displays the labels on different lines.

<labelstyle ismultilevel="true" orientation="Parallel">




Examples:

The base file was created by copying the default style (ie C:\ColdFusion8\charting\styles\default.xml ) and modifying only the <yAxis> section. For brevity, only the <yAxis> section of the xml is posted below. The {placeholders} to represent the dynamic values, which are inserted when the charts are generated.

SkipLabels


<!---
FILE: skipLabelsStyle.xml
--->
<yAxis scaleMin="0">
<titleStyle font="Arial-12-bold"/>
<dateTimeStyle majorUnit="Year" minorUnit="Month"/>
<labelFormat style="Pattern" pattern="#,##0.########"/>
<groupStyle skipLabels="{skipLabels}"/>
</yAxis>

<!---
SKIP LABELS EXAMPLE
--->
<cfset chartStyle = FileRead( ExpandPath("./skipLabelsStyle.xml") )>
<cfset chartStyle = replaceNoCase(chartStyle, "{skipLabels}", "1")>
<cfchart format="png" style="#chartStyle#">
<cfchartseries type="bar">
<cfchartdata item="A" value="26">
<cfchartdata item="B" value="15">
<cfchartdata item="C" value="75">
<cfchartdata item="D" value="49">
<cfchartdata item="E" value="90">
<cfchartdata item="F" value="25">
<cfchartdata item="G" value="95">
</cfchartseries>
</cfchart>


Y-Axis Dates

<!---
SAMPLE VALUES for line charts
--->
<cfset q1 = queryNew("ChartItem,ChartValue", "varchar,date")>
<cfset q2 = queryNew("ChartItem,ChartValue", "varchar,date")>
<cfloop from="1" to="8" index="x">
<cfloop from="85" to="90" index="y">
<cfset row = queryAddRow(q1, 1)>
<cfset q1["ChartItem"][row] = chr(y)>
<cfset q1["ChartValue"][row] = createDate(2008, 10, randRange(1,25))>

<cfset row = queryAddRow(q2, 1)>
<cfset q2["ChartItem"][row] = chr(y)>
<cfset q2["ChartValue"][row] = createDate(2008, 10, randRange(1,25))>
</cfloop>
</cfloop>

<!---
FILE 1: yAxisDateStyle.xml
--->
<yAxis type="DateTime">
<titleStyle font="Arial-12-bold"/>
<labelFormat style="DateTimePattern" pattern="{labelDateFormat}"/>
</yAxis>



<!---
EXAMPLE 1: FORMAT Y-AXIS DATES (MM.dd.yyy)
--->
<cfset chartStyle = FileRead( ExpandPath("./yAxisDateStyle.xml") )>
<!--- date patterns _are_ case sensitive --->
<cfset chartStyle = ReplaceNoCase( chartStyle, "{labelDateFormat}", "MM.dd.yyyy")>
<cfchart format="png" style="#chartStyle#">
<cfchartseries type="line">
<cfloop query="q1">
<cfchartdata item="#ChartItem#" value="#q1.ChartValue[currentRow].getTime()#">
</cfloop>
</cfchartseries>
<cfchartseries type="line">
<cfloop query="q2">
<cfchartdata item="#ChartItem#" value="#q2.ChartValue[currentRow].getTime()#">
</cfloop>
</cfchartseries>
</cfchart>

<!---
FILE 2: yAxisReverseDateStyle.xml
--->
<yAxis type="DateTime" isReversed="true">
<titleStyle font="Arial-12-bold"/>
<labelFormat style="DateTimePattern" pattern="{labelDateFormat}"/>
</yAxis>


<!---
EXAMPLE 2: REVERSE AND FORMAT Y-AXIS DATES
--->
<cfset chartStyle = FileRead( ExpandPath("./yAxisReverseDateStyle.xml") )>
<!--- date patterns _are_ case sensitive --->
<cfset chartStyle = ReplaceNoCase( chartStyle, "{labelDateFormat}", "MM.dd.yyyy")>
<cfchart format="png" style="#chartStyle#">
<cfchartseries type="line">
<cfloop query="q1">
<cfchartdata item="#ChartItem#" value="#q1.ChartValue[currentRow].getTime()#">
</cfloop>
</cfchartseries>
<cfchartseries type="line">
<cfloop query="q2">
<cfchartdata item="#ChartItem#" value="#q2.ChartValue[currentRow].getTime()#">
</cfloop>
</cfchartseries>
</cfchart>

<!---
FILE 3: yAxisReverseDateStyle.xml
--->
<yAxis type="DateTime" scaleMin="{dateMin}" scaleMax="{dateMax}">
<titleStyle font="Arial-12-bold"/>
<labelFormat style="DateTimePattern" pattern="{labelDateFormat}"/>
<parseFormat style="DateTimePattern" pattern="{inputDateFormat}"/>
<dateTimeStyle majorUnit="{dateUnit}" majorStep="{dateStep}"/>
</yAxis>


<!---
EXAMPLE 3: SET SCALE W/SKIP LABELS
--->
<cfset chartStyle = FileRead( ExpandPath("./yAxisDateRangeStyle2.xml") )>
<!--- date patterns _are_ case sensitive --->
<!--- set the input format of min/max dates --->
<cfset chartStyle = ReplaceNoCase( chartStyle, "{inputDateFormat}", "MM/dd/yyyy")>
<cfset chartStyle = ReplaceNoCase( chartStyle, "{dateMin}", "10/01/2008")>
<cfset chartStyle = ReplaceNoCase( chartStyle, "{dateMax}", "10/31/2008")>
<!--- set the display format of Y-Axis dates --->
<cfset chartStyle = ReplaceNoCase( chartStyle, "{labelDateFormat}", "MM.dd.yyyy")>
<!--- display a date label every three (3) Days --->
<cfset chartStyle = ReplaceNocase( chartStyle, "{dateUnit}", "Day" ) >
<cfset chartStyle = ReplaceNocase( chartStyle, "{dateStep}", "3" ) >

<cfchart format="png" style="#chartStyle#">
<cfchartseries type="line">
<cfloop query="q1">
<cfchartdata item="#ChartItem#" value="#q1.ChartValue[currentRow].getTime()#">
</cfloop>
</cfchartseries>
<cfchartseries type="line">
<cfloop query="q2">
<cfchartdata item="#ChartItem#" value="#q2.ChartValue[currentRow].getTime()#">
</cfloop>
</cfchartseries>
</cfchart>



Choice

<!---
FILE: choiceStyle.xml
--->
<yAxis scaleMin="0">
<titleStyle font="Arial-12-bold"/>
<dateTimeStyle majorUnit="Year" minorUnit="Month"/>
<labelFormat style="Choice" pattern="{choicePattern}"/>
</yAxis>


<!---
CHOICE EXAMPLE
--->

<cfset chartStyle = FileRead( ExpandPath("./choiceStyle.xml") )>
<cfset choiceText = "0##|2##Bored to Tears | 4##Jaded | 6##Intrigued">
<cfset chartStyle = ReplaceNoCase( chartStyle, "{choicePattern}", choiceText)>

<cfchart format="png" style="#chartStyle#" scalefrom="0" scaleto="6">
<cfchartseries type="bar">
<cfchartdata item="Group A" value="2">
<cfchartdata item="Group B" value="2">
<cfchartdata item="Group C" value="4">
<cfchartdata item="Group D" value="6">
<cfchartdata item="Group E" value="2">
</cfchartseries>
</cfchart>

26 comments:

Scot October 27, 2008 at 4:58 AM  

Nice post. Appreciated

If I can tap into your expertise for a sec.

Is it possible to use a image to represent a bar in a bar chart? I have a clustered chart that has 3 groups that can be only printed in black and white. The gray scale isn't good enough to determine which is which.

I was thinking of using a image for the different bars. Is that possible?

Thanks

cfSearching October 27, 2008 at 6:35 AM  

@Scot,

Try taking a look at <elements> and <paint>

<elements>
<series index="0">
<paint image="C:\path\to\image1.gif"/>
</series>
<series index="1">
<paint image="C:\path\to\image2.gif"/>
</series>
... etcetera ...
</elements>

Scot October 28, 2008 at 9:27 AM  

I tried your code example and can't get it to work. Have you ever done this? Just want to be sure it actually works before I spend more time figuring out what i have done wrong.

cfSearching October 28, 2008 at 1:37 PM  

@Scot,

Just proof of concept. I believe you also need the <paint< attribute.

Try this example created from the webcharts utility. It should produce some funky looking bars as it uses these three logos as image:
- webcharts logo
- google logo
- houseoffusion.com logo



<!---
FILE: seriesImage.xml
--->
<?xml version="1.0" encoding="UTF-8"?>
<frameChart is3D="false">
<frame xDepth="12" yDepth="11"/>
<yAxis scaleMin="0">
<labelFormat pattern="#,##0.###"/>
<parseFormat pattern="#,##0.###"/>
</yAxis>
<legend allowSpan="true" equalCols="false" halign="Right" isMultiline="true">
<decoration style="None"/>
</legend>
<elements drawShadow="true">
<morph morph="Grow"/>
<series index="0">
<paint image="http://www.gpoint.com/website/WebCharts50/logo_tran.gif"/>
</series>
<series index="1">
<paint image="http://www.google.com/intl/en_ALL/images/logo.gif"/>
</series>
<series index="2">
<paint image="http://www.houseoffusion.com/_/hof120.gif"/>
</series>
</elements>
<decoration style="RoundShadow"/>
<paint palette="Transluent" paint="Image"/>
<insets right="5"/>
</frameChart>

<!---
SAMPLE CHART
--->
<cfset chartStyle = FileRead( ExpandPath("./seriesImage.xml") )>
<cfchart format="png" style="#chartStyle#" showlegend="false">
<cfchartseries type="bar">
<cfchartdata item="A" value="30">
<cfchartdata item="B" value="20">
<cfchartdata item="C" value="40">
</cfchartseries>
<cfchartseries type="bar">
<cfchartdata item="A" value="45">
<cfchartdata item="B" value="36">
<cfchartdata item="C" value="22">
</cfchartseries>
<cfchartseries type="bar">
<cfchartdata item="A" value="55">
<cfchartdata item="B" value="76">
<cfchartdata item="C" value="30">
</cfchartseries>
</cfchart>

Scot October 28, 2008 at 5:06 PM  

Thanks! Worked liked you said!

Anonymous,  December 9, 2008 at 10:48 AM  

NOT RELATED TO THIS ARTICLE....

Are you aware of the problem Dreamweaver CS3 has with time change and how to fix it? I just thought I would give you a heads up since I just experienced the problem and found the solution on another site. (I'm not sure it's JUST a time change issue, but it fixed my problem)


http://getsatisfaction.com/adobe/topics/dreamweaver_cs3_crashes_a_lot



Vetman replied 11 months ago
From Adobe http://kb.adobe.com/selfservice/viewC...

Issue

Adobe Dreamweaver CS3 crashes when working with certain PHP or ASP files in Code view or Design view after the clock goes back one hour, when Daylight Savings Time ends. The crashes only occur when selecting certain lines in Code view, or selecting certain objects in Design view. The crashes only occur in files that have PHP or ASP code, intermingled with HTML code. The crashes do not occur in Dreamweaver 8 or earlier (Ref. 229536).
Reason

The Dreamweaver CS3 WinFileCache-AD76BB20.dat file has been corrupted by the time change.
Solution
1. If Dreamweaver is open, quit the application.
2. Delete the WinFileCache-AD76BB20.dat file from the Dreamweaver user configuration folder. Note that on Windows, the Application Data and AppData folders are hidden by default, so verify that your Windows Explorer folder options are set to View Hidden Folders. The location of this file is as follows:
* Dreamweaver CS3 on Windows Vista:
C:\Users\[username]\AppData\Roaming\Adobe\Dreamweaver 9\Configuration
* Dreamweaver CS3 on Windows XP:
C:\Documents and Settings\[username]\Application Data\Adobe\Dreamweaver 9\Configuration
3. Restart Dreamweaver.

Ed Gioja
Edward_Gioja@ilnb.uscourts.gov

cfSearching December 16, 2008 at 10:49 AM  

@Ed,

Now that is a strange one. I am not using Dreamweaver at the moment, but thanks for the heads up!

Leigh

Anonymous,  December 17, 2008 at 4:55 PM  

I copied and pasted your choice graph code and it is not working.

Invalid style type: yAxis


The error occurred in TEST GRID\test.cfm: line 10

8 : cfchartdata item="Group C" value="4"
9 : cfchartdata item="Group D" value="6"
10 : cfchartdata item="Group E" value="2"
11 : /cfchartseries
12 : /cfchart

It seems like laberstyle="choice" is no longer supported in coldfusion 8.

I deleted the <> because this site wouldn't allow them.

cfSearching December 17, 2008 at 7:04 PM  

@Anonymous ,

It definitely works with ColdFusion 8. That is what I used to generate the images for the entry.

Are you sure you created the xml file properly? You need copy all of the content from the default file: C:\ColdFusion8\charting\styles\default.xml. Then replace only the

<yAxis>
...
</yAxis>

section with the code above.

Anonymous,  December 17, 2008 at 7:20 PM  

Yea I copied everything exactly as it is on your example.

yAxis
titleStyle font="Arial-12-bold"/
dateTimeStyle majorUnit="Year" minorUnit="Month"/
labelFormat style="Choice" pattern="{choicePattern}"/
/yAxis

cfSearching December 17, 2008 at 8:14 PM  

Yes, but it will not work with just that snippet. You also need the rest of the content from C:\ColdFusion8\charting\styles\default.xml.

Did you copy all of that content to your xml file, and replace only the "yAxis" section?

cfSearching December 17, 2008 at 8:17 PM  

Here is what the complete xml file should look like:

<?xml version="1.0" encoding="UTF-8"?>
<frameChart autoAdjust="false" is3D="false" isInterpolated="true">
<frame xDepth="6" yDepth="6" outline="#333333" lightColor="white"
leftAxisPlacement="Front" rightAxisPlacement="Front" stripColor="#CCCCCC"/>
<xAxis>
<labelStyle isHideOverlapped="true" orientation="Horizontal"/>
<titleStyle font="Arial-12-bold" isMultiline="false"/>
</xAxis>
<yAxis scaleMin="0">
<titleStyle font="Arial-12-bold"/>
<dateTimeStyle majorUnit="Year" minorUnit="Month"/>
<labelFormat style="Choice" pattern="{choicePattern}"/>
</yAxis>
<yAxis2>
<titleStyle font="Arial-12-bold"/>
</yAxis2>
<topYAxis>
<titleStyle font="Arial-12-bold"/>
</topYAxis>
<topYAxis2>
<titleStyle font="Arial-12-bold"/>
</topYAxis2>
<dataLabels foreground="black"/>
<legend isVisible="false" showColumnLegend="true">
<decoration style="None"/>
</legend>
<elements action="" shape="Area" drawOutline="false">
<morph morph="Grow"/>
<series index="0">
<paint color="#E48701"/>
</series>
<series index="1">
<paint color="#A5BC4E"/>
</series>
<series index="2">
<paint color="#1B95D9"/>
</series>
<series index="3">
<paint color="#CACA9E"/>
</series>
<series index="4">
<paint color="#6693B0"/>
</series>
<series index="5">
<paint color="#F05E27"/>
</series>
<series index="6">
<paint color="#86D1E4"/>
</series>
<series index="7">
<paint color="#E4F9A0"/>
</series>
<series index="8">
<paint color="#FFD512"/>
</series>
<series index="9">
<paint color="#75B000"/>
</series>
<series index="10">
<paint color="#0662B0"/>
</series>
<series index="11">
<paint color="#EDE8C6"/>
</series>
<series index="12">
<paint color="#CC3300"/>
</series>
<series index="13">
<paint color="#D1DFE7"/>
</series>
<series index="14">
<paint color="#52D4CA"/>
</series>
<series index="15">
<paint color="#C5E05D"/>
</series>
<series index="16">
<paint color="#E7C174"/>
</series>
<series index="17">
<paint color="#FFF797"/>
</series>
<series index="18">
<paint color="#C5F68F"/>
</series>
<series index="19">
<paint color="#BDF1E6"/>
</series>
<series index="20">
<paint color="#9E987D"/>
</series>
<series index="21">
<paint color="#EB988D"/>
</series>
<series index="22">
<paint color="#91C9E5"/>
</series>
<series index="23">
<paint color="#93DC4A"/>
</series>
<series index="24">
<paint color="#FFB900"/>
</series>
<series index="25">
<paint color="#9EBBCD"/>
</series>
<series index="26">
<paint color="#009797"/>
</series>
<series index="27">
<paint color="#0DB2C2"/>
</series>
</elements>
<popup background="#C8FFFFFF" foreground="#333333"/>
<paint paint="Plain"/>
<insets left="5" top="5" right="5" bottom="5"/>
</frameChart>

Anonymous,  December 19, 2008 at 7:27 PM  

Thank you so much!!!!

If I may ask you how can I put two graphs together, but I would like to have the y axis on the right side with labels for the second graph.

cfSearching December 19, 2008 at 9:01 PM  

@Anonymous,

It depends on what you mean by together. A simple hack would be to capture the chart output with cfsavecontent and output both charts inside a div tag. Of course you may need to adjust the chart sizes to match.

<cfsavecontent variable="firstChart">
<cfchart ...>
...
</cfchart>
</cfsavecontent>
<cfsavecontent variable="secondChart">
<cfchart ...>
...
</cfchart>
</cfsavecontent>

<div>
<cfoutput>#firstChart#</cfoutput>
<cfoutput>#secondChart#</cfoutput>
</div>

You could also run the webcharts utility and look for a format that displays two charts in one image. See (c:\coldfusion8\charting\webcharts.bat). Not all of the formats are supported via cfchart, but Raymond Camden's blog has a great entry on how to get around this.

As far as the yAxis, there is a property of frameChart that determines the position of the yAxis. Just change it to right:

<frameChart autoAdjust="false" is3D="false" isInterpolated="true" primaryYAxisPlacement="Right">

Anonymous,  December 20, 2008 at 7:21 AM  

I am trying to open webcharts.bat and it won't open. I opens a command window and then it disapears. Do I need to download a plug in for this?
I am on Windows Vista.
Installed Java 6.11.

cfSearching December 20, 2008 at 11:35 AM  

@Anonymous,

The only thing you should need is ColdFuion and java, both of which you should have already. It should work unless there is a problem with your paths.

If you open the .bat file with notepad, you will see it is just some simple DOS commands. Try opening a command prompt and running it directly.

First navigate to the ColdFusion jre directory, then run the "java.exe" command from there. The command is "java.exe -jar (path to webcharts jar)

Example:
C:\ColdFusion8\runtime\jre\bin> java -jar c:\coldfusion8\lib\wc50.jar

Anonymous,  May 11, 2009 at 3:46 AM  

I have different tables (product views, added, deleted, sold) that i want to match on datetime, then i want to show all that data from one day scaled on datetime (so also minutes and even seconds).

Before i go any further banging my head against the wall, is this possible in one chart?

How would you do this?

Thanks so much!

Marco.

cfSearching May 11, 2009 at 10:24 AM  

@Marco,

I do not know what kind of chart you are using, but it sounds straightforward enough. What is the issue with it?

Leigh

cfSearching May 28, 2009 at 11:09 AM  

Unfortunately, some recent comments got trashed. So if you submitted a comment recently, but do not see it, feel free to resubmit.

- Leigh

Unknown July 25, 2009 at 1:08 PM  

Hi,
Is there a way to control on how the legends are displayed? I know we can control where there will be displayed(top, bottom, left right). But I want the legends line by line. Basically if I have legends like Legend A - 20%, Legend B - 15%, Legend C - 18%, Legend D - 47%, can I have them displayed like below?
Legend A - 20%
Legend B - 15%
Legend C - 18%
Legend D - 47%

cfSearching July 25, 2009 at 1:50 PM  

@kk,

I am not aware of any ways to control that behavior other than the "placement" you mentioned. ie Webcharts changes this automatically when the placement is "left" or "right".

Look over the legend properties. But at a quick glance it does not seem like webcharts exposes that particular setting.

-- All settings
<legend spacing="5" allowSpan="false" equalCols="true" isVisible="false" showColumnLegend="true"
placement="Top" valign="Middle" halign="Center" useMarkers="false" background="#00000000"
isAntialiased="false" font="null" foreground="null" isMultiline="false">
<insets left="0" top="0" right="0" bottom="0"/>
<decoration style="None" foreColor="black" backColor="null" width="null"/>
</legend>

-Leigh

Mark Hageman March 24, 2010 at 7:13 PM  

hello,

I have a few many issues...

First off thank you for your help,

1) Is there a way to add error bars to a scatter plot in chchart?
2) If not can I manipulate a bar chart to overlay the scatter plot but set the minimum value for the bar to be the lower end of the error bar?

Ok that should be my first issue. Any help in this area would be great.

Thanks again.

cfSearching March 31, 2010 at 1:14 PM  

@Mark,

I am not sure about error bars. IIRC it is mentioned briefly on the webcharts3d site. But I do not recall seeing any examples. So you will probably to have to dig into their pdf documentation and the utility to get a solid answer on that one.

-Leigh

Mark Hageman March 31, 2010 at 5:37 PM  

Thank you for that. I did find that WebCharts3D V5.3 does the error bars that I need but coldfusion uses V5.0 I think. I was hoping that the coding for their trial download coding would work but it does not. Their trial down load coding is as follows...














as you can see I have commented it out the so to use the working code for other things.

One more thing that I would like to do is figure out how to change what the mouse over of the data point says. If this is possible that would be cool. I have been unable to find anything how to do this. Any help would be nice for this one.

Also is it possible to write a sub routine in cold fusion and then refer to it in an . I need to have different items graphed for different users, so the user will select items to graph from the database. Any help would be nice, I am slightly new to this and just keep running into blocks that are just a little bit out of my reach.

Again thank you so much.

cfSearching March 31, 2010 at 9:17 PM  

@Mark,

The code did not quite come through. BTW, you can post html as long as its escaped properly ie &lt; and &gt;.

Regarding the mouse over tool tip. The utility provides some control over tool tips. The documentation is a bit scattered. But they are are covered in the userguide.pdf in the CF charting directory ("annotations", page 22). If you run the utility and click the [Help] tab, the Designer -> Elements -> Parameters section covers some of the parameters you can use in tool tips like $(colLabel), $(value), etecetera.

Regarding the sub routine, it is certainly possible to create a function that will graph the given data/arguments. You could use cfchart's "name" attribute to save output to a variable. Then return it from the cffunction. It all depends on your needs.

-Leigh

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep