 |
Bekend is dat CFCHART niet werkt met de punt als decimaal, maar weer
wel met de komma als decimaal.
Bekend ook is dat je dat kunt afdwingen met de functie DecimalFormal().
Maar dat je toch nog voor raadsels kunt komen te staan, bewijst dit artikel.
Over: 'had ik dat maar eerder geweten'. |
| |
|
CFCHART is mooi om mee te werken, maar kan af en toe tot behoorlijk
wat frustratie leiden (als je de weg niet weet).
Ik had de twijfelachtige eer dat de afgelopen week te mogen meemaken.
Mijn bedoeling was om uit onderstaande query gegevens in CFCHART te verwerken,
zodanig dat in de grafiek - naast de decimale(!) scores en een beschrijving
in de popup - een omschrijving van de items op de Y-as getoond
zou worden.
Om het simpel te houden: de query, gebaseerd op twee tabellen (Table_KVA_AfnameScores en Table_EVC_moduul_input) haalt in principe items (vragen) en
bijbehorende scores uit de database, waarbij de scores met de functie AVG gemiddeld worden:
<cfquery name="RSgetAspectScore" datasource="#dsn#">
SELECT
A.Aspect, A.Moduul_code, E.Moduul_code,
E.Moduul_omschrijving,
AVG (KVAItemScore) AS GemAspectScore
FROM
Table_KVA_AfnameScores AS A, Table_EVC_moduul_input
AS E
WHERE
KVAAfnameID = #URL.KVAAfnameID# AND
A.Moduul_code = E.Moduul_code
<cfif #URL.Selection# EQ "Spe">
AND XtraSubAspect
= '1'
</cfif>
<cfif #URL.Selection# EQ "Reg">
AND XtraSubAspect
= '0'
</cfif>
GROUP BY Aspect, A.Moduul_code, E.Moduul_code, E.Moduul_omschrijving
ORDER BY Aspect ASC
</cfquery>
Dit leek me voldoende om gegevens uit de database en in de CFCHART te kunnen trekken...
Wat in eerste instantie niet zondermeer bleek te gaan.
1. Dat ik uit de query consequent MEER items tevoorschijn kreeg,
dan dat ik in de CFCHART terug zag, was op zich al wonderlijk genoeg.
Terwijl toch het resultaat van de query correct was (en dus als leidend
beschouwd moest worden).
Tot je bemerkt dat het resultaat uit het veld Moduul_omschrijving voor twee verschillende GemAspectScores exact dezelfde
inhoud hebben hebben! En CFCHART maakt - als je een staafdiagram als voorbeeld
neemt - daar één staaf van in plaats van twee (wat eigenlijk
de bedoeling is).
De oplossing: aan iedere Moduul_omschrijving een uniek kenmerk toevoegen,
zodat het door CFCHART als verschillende elementen 'gezien' zou worden.
Om dat mogelijk te maken was het makkelijk genoeg om met een CFLOOP-query
de gegevens in een array zetten. Waarbij en-pasant aan iedere Moduul_omschrijving
een uniek nummer wordt toegekend:
<!---zet gegevens in een ARRAY--->
<cfset GrafiekGegevens=ArrayNew(2)>
<cfset AantRijen=0>
<cfloop query="RSgetAspectScore">
<cfset AantRijen=AantRijen+1>
<cfset GrafiekGegevens[#currentRow#][1]=#RSgetAspectScore.GemAspectScore#>
<cfset GrafiekGegevens[#currentRow#][2]=#RSgetAspectScore.Moduul_omschrijving#&"
["&#AantRijen#&"]">
</cfloop>
Niks mis mee. Resultaat: het zelfde aantal items, dat feitelijk uit de
query getrokken wordt, zie je nu ook weer terug in de grafiek van CFCHART.
Probleem opgelost (dacht ik).
Totdat...
2. Berucht is het feit dat CFCHART pertinent weigert te werken met decimale
scores (7.1, 4.5, 5.8 etc.):
'This value cannot be converted to a number because
it is not a simple value.
Simple values are booleans, numbers, strings en date-time values.'
krijg je dan voor je hoofd geslingerd.
Deze mededeling heeft al menig programmeur naar de afgrond van de wanhoop
gebracht.
Maar, dit vooraf wetend (en wetend dat je dit probleem met DecimalFormat(waarde)
kunt omzeilen - de punt als decimaal teken wordt daarmee omgezet naar
een komma -) klopte ik fluitend de volgende code in.
"HA!, punten en komma's: wie kan mij wat?":
<cfset Grafiekhoogte = #RSgetAspectScore.RecordCount# * 20>
<cfchart
format="flash"
showborder="Yes"
showlegend="Yes"
chartheight="#Grafiekhoogte#"
chartwidth="650"
gridlines="5"
rotated="yes"
scalefrom="4"
scaleto="8"
xaxistitle="Module/SubDomein"
yaxistitle="Score"
show3d="yes"
showygridlines="YES"
xaxistype="score"
yaxistype="score"
xoffset="0.01"
yoffset="0.01"
labelformat="number">
<cfchartseries
type="#URL.grafiek#"
serieslabel="Gemiddelde score
op..."
seriescolor="#URL.Kleur#"
paintstyle="shade">
<cfloop from="1" to="#AantRijen#"
index="i">
<cfset varrealSc=#evaluate(GrafiekGegevens[i][1])#>
<cfchartdata item="#GrafiekGegevens[i][2]#"
value="#DecimalFormat(varrealSc)#">
</cfloop>
</cfchartseries>
</cfchart>
F12.
Mis!
'This value cannot be converted to a number because
it is not a simple value.
Simple values are booleans, numbers, strings en date-time values.'
Wat nou? 'This value cannot be converted to a number'? This value IS a number! Comma included!!
Maar CF denkt daar toch blijkbaar heel anders over.
Ik zal u maar de variaties en bedachte oplossingen van de daarop volgende
twee volle(!) dagen (en avonden) besparen. Niks werkte. 'This value cannot
be converted to a number...'
En wat bij dit soort problemen steekt en dan alsmaar in je achterhoofd
door blijft sudderen is, dat de oplossing er is. Alleen: waar dan?
Surfend over de Macromedia Livedocs (http://livedocs.macromedia.com/coldfusion/6.1/htmldocs/tags-a11.htm),
waar je nog veel meer CHART-ellende tegen komt, en bezoekjes aan verschillende
forums ten spijt: niets mocht helpen. En niks gaf de oplossing.
WAT dan?
Opgeven?
Op je ogen!
Reduceren, reduceren!
Tenminste, zo luidt het credo wanneer iets niet lukt; terug tot de bron
en stap voor stap het zaakje weer opbouwen. Probleemanalyse avant la lettre
dus.
En zie, stond daar niet tussen al die scores een score: 0.0,
'n.v.t.'?
(Maar dat wordt in de code toch omgezet naar 0,0?)
(Maar stel dat het nu niet de code, maar een SCORE is,
die de fout veroorzaakt?)
Test 1:
<cfchartdata item="#test#"
value="#0.0#">
'This value cannot be converted to...'
Ja ja dat weten we.
Test 2:
<cfchartdata item="#test#"
value="#0,0#">
'This value cannot be converted to...'
O? Kennelijk WERKT de waarde 0,0 niet in CFCHART.
Klopt dat?
Nog een test dan. 3:
<cfchartdata item="#test#"
value="#1,0#">
Werkt!
Een laatste check, voor de zekerheid. 4:
<cfchartdata item="#test#"
value="#DecimalFormat(0,0)#">
'This value cannot be converted to...'
Conclusie: niet de code, maar de waarde 0,0 wordt door CFCHART geweigerd en levert een
foutmelding op. |
En 0 dan?
<cfchartdata item="#test#"
value="#DecimalFormat(0)#">
Werkt!
En dat geeft meteen de oplossing voor het probleem: vang de 0,0 af met
een CFIF en vervang hem door een 0 (what's in a name?) en je bent er.
De correcte uitwerking ziet u hieronder:
<cfset Grafiekhoogte = #RSgetAspectScore.RecordCount# * 20>
<cfchart
format="flash"
showborder="Yes"
showlegend="Yes"
chartheight="#Grafiekhoogte#"
chartwidth="650"
gridlines="5"
rotated="yes"
scalefrom="4"
scaleto="8"
xaxistitle="Module/SubDomein"
yaxistitle="Score"
show3d="yes"
showygridlines="YES"
xaxistype="score"
yaxistype="score"
xoffset="0.01"
yoffset="0.01"
labelformat="number">
<cfchartseries
type="#URL.grafiek#"
serieslabel="Gemiddelde score op..."
seriescolor="#URL.Kleur#"
paintstyle="shade">
<cfloop from="1" to="#AantRijen#" index="i">
<cfset varrealSc=#evaluate(GrafiekGegevens[i][1])#>
<cfif varrealSc GT 0>
<cfchartdata item="#GrafiekGegevens[i][2]#" value="#DecimalFormat(varrealSc)#">
<cfelse>
<cfchartdata item="#GrafiekGegevens[i][2]#" value="0">
</cfif>
</cfloop>
</cfchartseries>
</cfchart>
En uiteindelijk stelt 't op zich weer niet eens zo veel voor.
Wat u ziet:
Een normale CFChart zonder buitengewone dingen (of het moet zijn dat met de variabele 'GrafiekHoogte' dynamisch de hoogte van de grafiek wordt bepaald, omdat het aantal items uit de query (en het aantal staven in de staafdiagram) 4, maar makkelijk ook 40 kunnen zijn).
Hetzelfde geldt voor het CFChartSeries-gedeelte: geen toeters en bellen, gewoon recht door het midden.
En eigenlijk geldt dat ook voor het CFChartdata-gedeelte.
Maar dan moet je het wel even van te voren weten...
PS. Hieronder een paar delen uit de uitvoer van de pagina.
Boven de scores, onder de grafische weergave met CFCHART.

Gemiddelde Scores met AVG...(en de gewraakte 'n.v.t.': 0,0)

... en de uitvoer van dezelfde scores met behulp van CFCHART
Have fun!
|