limit x axis for cfchart - coldfusion

I would like to limit the x-axis of my chart that is created by cfchart. I see the attribute scaleFrom and scaleTo that limit the y-axis, but I see nothing that limits the x-axis.
Also, I saw a similar question here:
ColdFusion Chart x-axis label limits
but neither of the answers were appropriate. ScaleMin and ScaleMax do not exists as far as I can tell and the other answer is more complicated than what I'd like to do.

The scaleMin and scaleMax attributes Saul mentioned are only available when using a custom style. Note, using type "scale" means your xAxis values must be numeric. If you want to use strings, you will probably need to use Ben's approach instead.
Here is a quick example that creates a chart with 24 points on the xAxis. Even though the query only contains the first six (6) points.
<!--- bare bones style --->
<cfsavecontent variable="style">
<?xml version="1.0" encoding="UTF-8"?>
<frameChart is3D="false" isInterpolated="true">
<frame xDepth="3" yDepth="1" />
<xAxis type="Scale" scaleMin="0" scaleMax="24" labelCount="25" isBucketed="false" />
</frameChart>
</cfsavecontent>
<!--- sample query --->
<cfset qry = queryNew("")>
<cfset queryAddColumn(qry, "xValue", listToArray("1,2,3,4,5,6"))>
<cfset queryAddColumn(qry, "yValue", listToArray("30,15,22,14,45,5"))>
<!--- chart code --->
<cfchart format="jpg" style="#style#" width="600">
<cfchartseries type="line"
markerstyle="circle"
query="qry"
itemColumn="xValue"
valueColumn="yValue" />
</cfchart>

Related

CFCHART displaying y-axis numbers in whole

I am trying to use cfchart to display numbers of messages and all works well but when I have a small amount of numbers it breaks it into decimals. Is there a way we can make it always set to whole numbers?
Here is the code:
<cfchart format="#display#" type="bar" show3d="no" showlegend="false" chartHeight="300" chartWidth="220">
<cfchartseries colorlist="##E18014,green,red" type="bar">
<cfchartdata item="Calls Made" value="#voice_messages.TotalMessages#">
<cfchartdata item="Successful" value="#voice_messages.ReceiptsReceived#">
<cfif #voice_messages.DeliveryFailures# neq "0">
<cfchartdata item="Bus/No Ans" value="#voice_messages.DeliveryFailures#">
</cfif>
</cfchartseries>
</cfchart>
And here is a pic of the graph
I looked all over on Stack and the web but didn't find anything. Any help would be greatly appreciated.
Thanks!!
<cfchart> has an attribute called yAxisValues. It accepts an array of values. For this situation, once I had my data, I would do something to produce a suitable array to use for this attribute.
Verify whether the chartdata values voice_messages.TotalMessages, voice_messages.ReceiptsReceived and are infact integers. Use something like:
<cfset displayChart=false>
<cfif (isNumeric(voice_messages.TotalMessages) and voice_messages.TotalMessages gte 0)
and (isNumeric(voice_messages.ReceiptsReceived) and voice_messages.ReceiptsReceived gte 0)
and (isNumeric(voice_messages.DeliveryFailures) and voice_messages.DeliveryFailures gte 0)>
<cfset numberOfMessages=int(voice_messages.TotalMessages)>
<cfset numberOfReceipts=int(voice_messages.ReceiptsReceived)>
<cfset numberOfFailures=int(voice_messages.DeliveryFailures)>
<cfset displayChart=true>
</cfif>
<cfif displayChart>
<!--- You may have to increase the chartWidth to make room for all the labels--->
<cfchart format="png" type="bar" show3d="no" showlegend="false" chartHeight="300" chartWidth="300">
<cfchartseries colorlist="##E18014,green,red" type="bar">
<cfchartdata item="Calls Made" value="#numberOfMessages#">
<cfchartdata item="Successful" value="#numberOfReceipts#">
<cfif numberOfFailures neq 0>
<cfchartdata item="Bus/No Ans" value="#numberOfFailures#">
</cfif>
</cfchartseries>
</cfchart>
<cfelse>
Sorry, chart cannot be displayed because chartdata are not all integers.
</cfif>
In any case, you should realize that the labels in the display you have shown do not correspond to those in the code.
I shall now give you another answer. It is an answer of last resort, because it involves a changing ColdFusion server settings. Perhaps the reason you cannot easily find it on the web. Again, please be warned beforehand: it is a change of server setting. So back up your files!
ColdFusion 2018 (my version) uses the settings for ZingCharts to configure style in cfcharts. You will find the relevant files at C:\ColdFusion2018\cfusion\charting\styles. You want to edit the style file for bar charts.
Open in a text editor the file C:\ColdFusion2018\cfusion\charting\styles\bar. It has JSON format.
Locate the element "scale-y". It begins with:
"scale-y" : {
"format" : "%v",
"font-size" : 16,
... and so on.
Prepend to it the key-value pair "decimals" : 0. The result should be:
"scale-y" : {
"decimals" : 0,
"format" : "%v",
"font-size" : 16,
... and so on.
This will ensure that the y-axis will have 0 decimal places.
Save the file and restart ColdFusion for the changes to take effect.
You have now configured the y-axis in cfchart's bar charts to no longer have decimals.
You will have noticed that the element "scale-y" is a sub-element of "graphset". Should you be interested in knowing more about their settings, then go to https://www.zingchart.com/docs/api/json-configuration/graphset

ColdFusion 9 CFCHART CFCHARTSERIES Issue

I'm displaying a chart with one or more line series. The data comes from a query and works correctly if there is more than on series on the chart. However, if only one series is returned it is not displaying correctly.
Here's the code used:
<cfchart format="flash" tipstyle="mouseover" showlegend="yes" xaxistitle="Date" yaxistitle="Hits" chartwidth="1200" chartheight="300">
<cfoutput query="qryReport" group="APP_SYS_NR">
<cfchartseries serieslabel="#qryReport.APP_NA#" type="line">
<cfoutput>
<cfchartdata item="#DateFormat(qryReport.CDR_DT, "mm/dd/yyyy")#" value="#qryReport.TOT_HIT_CNT#">
</cfoutput>
</cfchartseries>
</cfoutput>
</cfchart>
The blacked out area at the top of this chart lists the keys for what the two lines represent:
In this chart (when there is only one APP_SYS_NR returned), instead of only having a single label, all the dates are turned into labels. Obviously not what I want:
Edit: I've traced this to the showlegend attribute of cfchart. According to Adobe, it's whether to display the legend if the chart contains more than one data series. I guess when it contains only one data series, it completely craps itself and does the data points in the legend. I tested on ColdFusion 9 and ColdFusion 10.
The solution here is to set showlegend to no when there is only a single series to display. Instead you should use a chart title in that instance. See the following modified code:
<cfset VARIABLES.blnShowLegend = "no">
<cfset VARIABLES.strChartTitle = "#qryReport.APP_NA#">
<cfif ListLen(URL.lstApps) GT 1>
<cfset VARIABLES.blnShowLegend = "yes">
<cfset VARIABLES.strChartTitle = "">
</cfif>
<cfchart format="flash" title="#VARIABLES.strChartTitle#" tipstyle="mouseover" style="appstats" showlegend="#VARIABLES.blnShowLegend#" xaxistitle="Date" yaxistitle="Hits" chartwidth="1200" chartheight="300">
<cfoutput query="qryReport" group="APP_SYS_NR">
<cfchartseries serieslabel="#qryReport.APP_NA#" type="line">
<cfoutput>
<cfchartdata item="#DateFormat(qryReport.CDR_DT, "mm/dd/yyyy")#" value="#qryReport.TOT_HIT_CNT#">
</cfoutput>
</cfchartseries>
</cfoutput>
</cfchart>

SpreadsheetFormatColumn() Right Border

When I run this code:
<cfscript>
flinstones = "fred,wilma,pebbles";
Workbook = Spreadsheetnew("Workbook");
for (i = 1; i lte listlen(flinstones); i ++) {
ThisFlinstone = ListGetAt(Flinstones, i);
if (ThisFlinstone == "wilma")
SpreadSheetAddRow(Workbook, "#ThisFlinstone#,barney");
else
SpreadSheetAddRow(Workbook, ThisFlinstone);
}
Format = {};
format.rightborder = "thin";
SpreadsheetFormatColumn(WorkBook, Format, 2);
MYfile = "d:\dw\dwtest\dan\abc.xls";
writedump(format);
</cfscript>
<cfspreadsheet action="write" filename="#MYFile#" name="Workbook"
sheet=1 sheetname="flinstones" overwrite=true>
I expect to see a worksheet with three rows. The second row will have two columns, with wilma and barney in the cells. So far, I see what I expect. I also expect to see Column B with a right hand border. I actually see cell B2 with a right hand border.
If I change this:
SpreadSheetAddRow(Workbook, ThisFlinstone);
to this
SpreadSheetAddRow(Workbook, "#ThisFlinstone#, ");
I see a right hand border for the first three rows of Column B.
Is there a way to have the right hand border apply to all of Column B?
Update:
As Dan mentioned in the comments, I misread the question. To clarify, adding a border to an entire column was not supported by POI last I checked. The only way to make the border appear on the entire column is to populate every single cell in that column first. Either by setting a value explicitly or using SpreadsheetFormatCellRange(sheet, format, 1, 2, maxRow, 2) with the maximum row number. While this does work, I would not recommend it as it has some undesirable side effects.
Is there a way to have the right hand border apply to all of Column B?
Short answer:
Yes, by doing what you already discovered: give all of the cells ie B1, B2 and B3 a value first. Even if it is just a blank or an empty string. This will create a border on all three cells.
Update 1: If you are using CF 9.0.1, another option is SpreadsheetFormatCellRange. Unlike most spreadsheet functions, it automatically creates non-existent cells first:
<cfset SpreadsheetFormatCellRange(Workbook, Format, 1, 2, 3, 2)>
Longer answer:
To apply a format, you need what POI calls a Cell object. When you create a new worksheet, it is completely blank, with no "cells" whatsoever. In most cases, CF only creates a Cell object when you set a value with one of the various functions ie SpreadSheetSetCellValue, SpreadSheetAddRow, etcetera. (See example below). Your original code only sets a one value in Column B. Hence it only creates a single Cell, ie B2. SpreadsheetFormatColumn only formats existing cells, that is why the border is only visible in B2.
<!--- blank sheet with no CELLS --->
<cfset Workbook = Spreadsheetnew() />
<cfset SpreadSheetWrite(Workbook, "c:/test.xls", true) />
<cfspreadsheet action="read" src="c:/test.xls" query="qValues" />
<cfdump var="#qValues#" label="No cells exist yet" />
<!--- setting one value, creates one CELL --->
<cfset Workbook = Spreadsheetnew() />
<cfset SpreadSheetAddRow(Workbook, "Fred") />
<cfset SpreadSheetWrite(Workbook, "c:/test.xls", true) />
<cfspreadsheet action="read" src="c:/test.xls" query="qValues" />
<cfdump var="#qValues#" label="Creates a single cell" />
<!--- setting two values, creates two CELL's --->
<cfset Workbook = Spreadsheetnew() />
<cfset SpreadSheetAddRow(Workbook, "Fred, ") />
<cfset SpreadSheetWrite(Workbook, "c:/test.xls", true) />
<cfspreadsheet action="read" src="c:/test.xls" query="qValues" />
<cfdump var="#qValues#" label="Creates two cells" />

cfchart ignores my scalefrom value

I have the following codes in my page.
The style variable holds the custom style.
<cfchart chartheight="450" chartwidth="550" gridlines="9" yaxistitle="Score" scalefrom="20" scaleto="100" style="#style#" format="png" >
<cfchartseries query="variables.chart_query" type="scatter" seriescolor="##000000" itemcolumn="MyItem" valuecolumn="MyScore"/>
</cfchart>
Before I begin, please see chart_good.jpg. This is how I want my report to come up. On the x-axis, there will always be three items as long as at least one of them has values. If an item does not have any values (i.e. 2010), there would not be a marker in the chart.
The problem occurs only when only one item has value. Please see chart_bad.jpg. As you can see, 2008 and 2010 do not have any values; y-axis is now scaled from 0 to 100. I have tried setting one of the items (ex. 2008) a value of 0 or something off the chart; it would scale according to this off-the-chart value and the 2009 value. In short, I have to have at least two items with values between 20 and 100 in order for cfchart to scale from 20 to 100.
My question is, how can I correct the issue so that cfchart would ALWAYS scale from 20 to 100? I am running CF9.
What is inside your style variable?
I would suggest not using scaleFrom="" and scaleTo="" in the cfchart tag as they can be buggy sometimes. I believe that Coldfusion's cfchart tag attempts to scale the chart automatically to what it deems the best fit. Instead I would build the chart's minimum and maximum scales inside a frameChart tag.
Example of a style variable to build a chart
<cfsavecontent variable="style">
<?xml version="1.0" encoding="UTF-8"?>
<frameChart is3D="false" font="Arial-11-bold">
<frame xDepth="0" yDepth="0" outline="black" lightColor="#CCCCCC" darkColor="#CCCCCC"
wallColor="#CCCCCC" frameSize="5" dashSize="3" gridColor="#333333">
<background type="HorizontalGradient" maxColor="#828EB0"/>
</frame>
<!--- THE BREAD AND BUTTER
NOTE: if you use variables for the scaleMin and scaleMax
make sure to surround them with a cfoutput tag
--->
<yAxis scaleMin="20" scaleMax="100">
<!--- --------------------- --->
<labelFormat style="Currency" pattern="#,##0"/>
<parseFormat pattern="#,##0"/>
<titleStyle></titleStyle>
</yAxis>
<legend allowSpan="true" isVisible="false" placement="Bottom" valign="Bottom" foreground="black"
isMultiline="true">
<decoration style="None"/>
</legend>
<elements outline="black" shapeSize="40"/>
<popup background="#748BA6" foreground="white"/>
<paint palette="Modern" paint="Plain" isVertical="true"/>
<insets right="5"/>
</frameChart>
</cfsavecontent>
Then all you have to do is load the variable into the style attribute like you already mentioned.
<cfchart format="png" chartWidth="550" chartHeight="175" style="#style#">
Also a great resource to use, is the Webcharts program that will be in your C:/coldfusion/charting/ directory. Just open webcharts.bat, create your custom chart, copy the xml code into your style variable, and voila!
Make sure to remove the scaleTo= and scaleFrom= from your cfchart tag if you decide to go this route.

CFCHART: reverse Y-axis ordering

I mean that MIN should be on top and MAX on X-axis.
This needed to make chart more intuitive to read and related to object ranking, when 1st place is "better" than 3rd. That's why it'd be better to look this way:
(source: xantea.net) =>
(source: xantea.net)
This can be done using custom XML. I ran the Chart Designer (cfinstall/charting/webcharts.bar (or .sh) and simply worked with the YAxis setting. There is an isReversed setting which does what you want. Consider this code:
<cfset q2 = queryNew("year,employees","integer,integer")>
<!--- generate random sales data --->
<cfloop index="y" from="1994" to="1998">
<cfscript>
queryAddRow(q2);
querySetCell(q2, "year", y);
querySetCell(q2, "employees", randRange(2,8));
</cfscript>
</cfloop>
<cfsavecontent variable="chartxml">
<?xml version="1.0" encoding="UTF-8"?>
<frameChart is3D="false">
<yAxis isReversed="true">
</yAxis>
</frameChart>
</cfsavecontent>
<cfchart chartWidth="400" chartHeight="400" title="Sales" font="arial" style="#chartxml#">
<cfchartseries type="line" query="q2" itemColumn="year" valueColumn="employees" seriesLabel="Employees" />
</cfchart>
The query on top was just used for testing. The XML came from the chart designer. I removed everything but the yAxis stuff that used isReverse. Lastly, note how I specify style in the chart tag.