Focal Point Banner
Community Center Education Summit Technical Support User Groups
Let's Get Social!

Facebook Twitter LinkedIn YouTube
Focal Point    Focal Point Forums  Hop To Forum Categories  WebFOCUS/FOCUS Forum on Focal Point     [SOLVED] Cheating the totalLabel value in HTML5 gauge charts
Go
New
Search
Notify
Tools
Reply
  
[SOLVED] Cheating the totalLabel value in HTML5 gauge charts
 Login/Join
 
Member
posted
Hi everyone,

I'm trying to construct an HTML5 gauge chart that leverages three measures: [1] a count of users as of yesterday rendered as a needle in the gauge, [2] a count of users as of a month ago, rendered as a triangle marker on the gauge, and [3] a count of users as of a year ago, rendered as a house marker on the gauge. I've been successful at crafting that basic design, following IBI's HTML5 Chart coding documentation. Beyond that, though, I'd like the chart to also boldly display the numeric value for the count of users field as of yesterday, but the totalLabel wants to sum all three measures, including the two secondary ones that I've added only to offer visual context. Ouch.

Is there a hack that [A] forces the totalLabel to only consider the count of users as of yesterday (calculated as a SUM CNT.DST.fieldname)? Maybe [B] just suppress totalLabel and push the value of the count of users as of yesterday into a text annotation that occupies the lower/center space of the gauge chart in lieu of the totalLabel? Or [C] (in utter desperation) do some clever chart merging with one gauge chart just having the yesterday count and needle totalLabel -- and another gauge chart overlaid over the top of the first with the markers that provide the other two contextual measures?

I've seen posts to these forums that either give up on altering totalLabel or use prefixes or suffixes to add content before or after the totalLabel value. But no clever workarounds to limit totalLabel to a single measure, or leverage some alternative hack to produce an equivalent result. Any suggestions from the charting experts out there?

Thanks!

Dale Davaz
STCU Research & Development
daled@stcu.org

This message has been edited. Last edited by: FP Mod Chuck,


WebFOCUS 8.2
 
Posts: 9 | Location: Spokane, WA | Registered: December 13, 2016Reply With QuoteReport This Post
Platinum Member
posted Hide Post
Here's an example using the CAR file and creating a PIE chart ... The totalLabel value in the Pie chart is the result of a SUMed value store in amper variable TOTVAL (which can be anything you want).

Not sure if this will help ... but take a look.


-*--------------------------------------------
-* Capture Total Value (TOTVAL) for totalLabel
-*--------------------------------------------
TABLE FILE CAR
SUM
COMPUTE TOTV/A30 = LJUST(30,FTOA(SALES,'(D20.2CM)','A30'), 'A30');
WHERE SALES GT 0;
ON TABLE SET HOLDLIST PRINTONLY
ON TABLE HOLD AS TOTDATA FORMAT ALPHA
END
-RUN
-READ TOTDATA &TOTVAL.A30.
-RUN
-TYPE TOTVAL ----------- &TOTVAL
-RUN
-*--------------------------------------------
-* Example of Pie Chart with Amper Variable
-* TOTVAL as the totalLabel Text Value
-*--------------------------------------------
GRAPH FILE CAR
SUM SALES AS 'Sales By Country'
BY COUNTRY
WHERE SALES GT 0;
ON GRAPH PCHOLD FORMAT JSCHART
ON GRAPH SET LOOKGRAPH PIE
ON GRAPH SET STYLE *
TYPE=DATA, COLUMN=COUNTRY, BUCKET=color, $
TYPE=DATA, COLUMN=SALES, BUCKET=measure, $
*GRAPH_JS
pieProperties: {
totalLabel: {
 visible: true,
 font: 'bold 12pt Sans-Serif',
 color: 'black',
 numberFormat: function(n){ return '&TOTVAL';}
},
holeSize:'50%'
}
*END
ENDSTYLE
END


WebFocus 8.201M, Windows, App Studio
 
Posts: 221 | Location: Lincoln Nebraska | Registered: August 12, 2008Reply With QuoteReport This Post
Member
posted Hide Post
That's helpful insight, jfr99. I do expect using an amper-variable as you suggest is the shortest path to implementing what I want.

Unfortunately, in my instance, doing a summary compute and filtering right within the chart so that it can be implemented in a portal page context complicates some of your other coding -- in particular defining the amper-variable then saving to a hold file before reading it into the chart object in a second step.

Here's the code I'm working with so far:

-* File: IBFS:/TEST/WFC/Repository/STCU/Charts_d3ccb300_dc5f_4440_839c_e5118e9e189c/BI_Analytics/Consumer_Portfolio/Procedure1.fex Created by WebFOCUS AppStudio
-*IA_GRAPH_BEGIN
-*Do not delete or modify the comments below
*-INTERNAL_COMMENT [long GUID]
*-INTERNAL_COMMENT [long GUID]
-*Do not delete or modify the comments above
ENGINE INT CACHE SET ON
SET PAGE-NUM=NOLEAD
SET ARGRAPHENGINE=JSCHART
SET EMBEDHEADING=ON
SET GRAPHDEFAULT=OFF
-DEFAULTH &WF_STYLE_UNITS='PIXELS';
-DEFAULTH &WF_STYLE_HEIGHT='405.0';
-DEFAULTH &WF_STYLE_WIDTH='770.0';
-DEFAULTH &WF_TITLE='WebFOCUS Report';
GRAPH FILE bia_cons_counts
-* Created by Info Assist for Graph
SUM CNT.DST.BIA_CONS_COUNTS.BIA_CONS_COUNTS.ACCT_NUM_PBD AS 'Yesterday'
CNT.DST.BIA_CONS_COUNTS.BIA_CONS_COUNTS.ACCT_NUM_LM AS 'Last Month'
CNT.DST.BIA_CONS_COUNTS.BIA_CONS_COUNTS.ACCT_NUM_LY AS 'Last Year'
WHERE BIA_CONS_COUNTS.BIA_CONS_COUNTS.MBR_AGE10 EQ &MBR_AGE10.(OR(<00-09,00-09>, <10-19,10-19>, <20-29,20-29>, <30-39,30-39>, <40-49,40-49>, <50-59,50-59>, <60-69,60-69>, <70-79,70-79>, <80-89,80-89>, <90-99,90-99>, <OVER 100,OVER 100>, <UNKNOWN,UNKNOWN> |FORMAT=A8V)).Age:.;
WHERE BIA_CONS_COUNTS.BIA_CONS_COUNTS.MBR_GENR EQ &MBR_GENR.(OR(<Gen Z,Gen Z>, <Gen Y,Gen Y>, <Gen X,Gen X>, <Baby Boomer,Baby Boomer>, <Traditionalist,Traditionalist>, <Pre-Traditionalist,Pre-Traditionalist>, <error,error> |FORMAT=A18V)).Generation:.;
WHERE BIA_CONS_COUNTS.BIA_CONS_COUNTS.MBR_TENR EQ &MBR_TENR.(OR(<1 - Under 1 month,1 - Under 1 month>, <2 - 1 to 2 months,2 - 1 to 2 months>, <3 - 2 to 3 months,3 - 2 to 3 months>, <4 - 3 to 12 months,4 - 3 to 12 months>, <5 - 1 to 2 years,5 - 1 to 2 years>, <6 - 2 to 5 years,6 - 2 to 5 years>, <7 - 5 to 10 years,7 - 5 to 10 years>, <8 - 10+ years,8 - 10+ years>, <9 - Unknown,9 - Unknown> |FORMAT=A18V)).Tenure:.;
ON GRAPH PCHOLD FORMAT JSCHART
ON GRAPH SET VZERO OFF
ON GRAPH SET GRWIDTH 1
ON GRAPH SET AUTOFIT ON
ON GRAPH SET UNITS &WF_STYLE_UNITS
ON GRAPH SET HAXIS &WF_STYLE_WIDTH
ON GRAPH SET VAXIS &WF_STYLE_HEIGHT
ON GRAPH SET GRMERGE ADVANCED
ON GRAPH SET GRMULTIGRAPH 0
ON GRAPH SET GRLEGEND 0
ON GRAPH SET GRXAXIS 0
ON GRAPH SET LOOKGRAPH GAUGE1
ON GRAPH SET AUTOFIT ON
ON GRAPH SET STYLE *
*GRAPH_SCRIPT
setPieDepth(0);
setPieTilt(0);
setDepthRadius(0);
setPlace(true);
setCurveFitEquationDisplay(false);
*END
INCLUDE=IBFS:/WFC/Repository/STCU_Shared_Content/Style_Sheets/angular.sty,$
*GRAPH_JS
"legend": {
	"visible": true,
	"position": "right",
	"orientation": "vertical",
	"markerPosition": "left"},
"gaugeProperties": {
	"groupLabel": {"visible": false},
	"outerBorder": {
		"width": 0, "fill": {"color": "white"},
		"border": {"width": 0, "color": "white"}},
	"secondaryNeedlesAsMarkers": true,
	"axisTickLength": "35%"},
"totalLabel": {
	"visible": true,
	"font": "bold 12pt Sans-Serif",
	"color": "black",
	"numberFormat": function(n){ return "CNT.DST.BIA_CONS_COUNTS.BIA_CONS_COUNTS.ACCT_NUM_PBD";}},
"series": [
	{"series": 0, "color": "purple"},
	{"series": 1, "color": "silver", "marker": {
		"shape": "triangle", "size": 12, "border": {"width": 1, "color": "black"}}},
	{"series": 2,"color": "grey", "marker": {
		"shape": "house", "size": 12, "border": {"width": 1, "color": "black"}}},
]
*END
TYPE=REPORT, TITLETEXT=&WF_TITLE.QUOTEDSTRING, $
*GRAPH_SCRIPT
setReportParsingErrors(false);
setSelectionEnableMove(false);
setBorderColor(getGaugeBand1(),new Color(255,163,16));
setFillColor(getGaugeBand1(),new Color(255,163,16));
setBorderColor(getGaugeBand2(),new Color(255,126,29));
setBorderColor(getGaugeBand3(),new Color(255,96,24));
setBorderColor(getGaugeBand4(),new Color(191,48,130));
setBorderColor(getGaugeBand5(),new Color(152,35,113));
setFillColor(getGaugeBand2(),new Color(255,126,29));
setFillColor(getGaugeBand3(),new Color(255,96,24));
setFillColor(getGaugeBand4(),new Color(191,48,130));
setFillColor(getGaugeBand5(),new Color(152,35,113));
setScaleMinAuto(getY1Axis(),true);
setScaleMaxAuto(getY1Axis(),true);
setDisplay(getGaugeValue(),true);
*GRAPH_JS_FINAL
"pieProperties": {
    "holeSize": "0%"
},
"agnosticSettings": {
    "chartTypeFullName": "Special_Gauges"
}
*END
ENDSTYLE
END
-RUN

-*IA_GRAPH_FINISH


The challenge is to set that summary compute SUM CNT.DST.BIA_CONS_COUNTS.BIA_CONS_COUNTS.ACCT_NUM_PBD AS 'Yesterday' as an amper-variable that can then be fed into the totalLabel's numberFormat function. If I wasn't such a hack at this, I'd know better how to do that all within the one chart step. But that's where I'm stuck, even with your helpful direction.

Here's the output I'm getting, with the totalLabel still showing the sum of the measures:



I do appreciate your help getting me the one step closer!

Dale Davaz
daled@stcu.org


WebFOCUS 8.2
 
Posts: 9 | Location: Spokane, WA | Registered: December 13, 2016Reply With QuoteReport This Post
Member
posted Hide Post
Hmmm. That image didn't come through quite like I'd hoped, but this link should display it:
Chart image

-- Dale Smiler


WebFOCUS 8.2
 
Posts: 9 | Location: Spokane, WA | Registered: December 13, 2016Reply With QuoteReport This Post
Platinum Member
posted Hide Post
Sorry Dale ... I can't run your code and our firewall is blocking me from seeing the image. GRRRR

Anyway ... Are you able to do any custom coding or are you only using the GUI?


WebFocus 8.201M, Windows, App Studio
 
Posts: 221 | Location: Lincoln Nebraska | Registered: August 12, 2008Reply With QuoteReport This Post
Member
posted Hide Post
I tend to start with the GUI to get the data and filters into the chart basics, jfr99, but then I open up the resulting code in the text editor to add my *GRAPH_JS refinements. In one way that gives me the best of both worlds in terms of speed to output but, as you can see, it also gives me the worst of both worlds... in particular all the extra spaghetti code from the GUI that I'd omit if I was coding the whole deal by hand.

If there's a way to insert SET or -DEFAULTH values to help me fix the result of the summary compute for the as-of-yesterday value as an amper-variable to leverage in the totalLabel numberFormat function, though, I think I'd be able to manage it. It's just a challenge of doing it in the same pass as the chart data read/filter/display step, which I'm finding daunting. Smiler

--Dale Davaz
daled@stcu.org


WebFOCUS 8.2
 
Posts: 9 | Location: Spokane, WA | Registered: December 13, 2016Reply With QuoteReport This Post
Platinum Member
posted Hide Post
Can you run the code below and show me the results. You will need to supply real data for the ??? in the -DEFAULTH statements.

-DEFAULTH &MBR_AGE10 = '???'
-DEFAULTH &MBR_GENR  = '???'
-DEFAULTH &MBR_TENR  = '???'

TABLE FILE bia_cons_counts
SUM
CNT.DST.ACCT_NUM_PBD AS 'Yesterday'
CNT.DST.ACCT_NUM_LM  AS 'LastMonth'
CNT.DST.ACCT_NUM_LY  AS 'LastYear'
WHERE MBR_AGE10 EQ '&MBR_AGE10.EVAL'
WHERE MBR_GENR  EQ '&MBR_GENR.EVAL'
WHERE MBR_TENR  EQ '&MBR_TENR.EVAL'
ON TABLE SET ASNAMES MIXED
ON TABLE HOLD AS HLD_CNTS
END
? HOLD HLD_CNTS
-RUN
TABLE FILE HLD_CNTS
PRINT *
END


WebFocus 8.201M, Windows, App Studio
 
Posts: 221 | Location: Lincoln Nebraska | Registered: August 12, 2008Reply With QuoteReport This Post
Member
posted Hide Post
Here's the actual code I used (with defaults supplied):

-DEFAULTH &MBR_AGE10 = '20-29'
-DEFAULTH &MBR_GENR  = 'Gen Y'
-DEFAULTH &MBR_TENR  = '5 - 1 to 2 years'

TABLE FILE bia_cons_counts
SUM
CNT.DST.ACCT_NUM_PBD AS 'Yesterday'
CNT.DST.ACCT_NUM_LM  AS 'LastMonth'
CNT.DST.ACCT_NUM_LY  AS 'LastYear'
WHERE MBR_AGE10 EQ '&MBR_AGE10.EVAL'
WHERE MBR_GENR  EQ '&MBR_GENR.EVAL'
WHERE MBR_TENR  EQ '&MBR_TENR.EVAL'
ON TABLE SET ASNAMES MIXED
ON TABLE HOLD AS HLD_CNTS
END
? HOLD HLD_CNTS
-RUN
TABLE FILE HLD_CNTS
PRINT *
END


And here is the output:

Yesterday ACCT_NUM_PBD LastMonth ACCT_NUM_LM LastYear ACCT_NUM_LY
8060 xxxxxx4147 8099 xxxxxx4147 8540 xxxxxx4147

I've masked all but the last four digits of the account number in the output as a customer privacy protection measure. I hope that doesn't complicate anything for you.

Thanks for your ongoing consideration of this challenge, jfr99. I really appreciate the help. Noodling out this label override technique will have lots of downstream benefits for my team. I'll be honest, though... I'm now looking to lean on bullet charts as a more efficient and maybe more natural way to present these "current period versus last month versus last year" data values in my dashboard work, rather than jury-rigging the gauge chart as I've attempted above. I trust once I learn how to code my own WF-extension for bullet charts, exposing just the value for the central (current period) horizontal bar will be a pretty simple matter.

In any case, I'm grateful for all your assistance in this present context.

Dale Davaz
daled@stcu.org


WebFOCUS 8.2
 
Posts: 9 | Location: Spokane, WA | Registered: December 13, 2016Reply With QuoteReport This Post
Platinum Member
posted Hide Post
Sorry ... I didn't mean for it to print your account numbers.

Add this line to it and run again ...

ON TABLE SET HOLDLIST PRINTONLY

Now the output should just be ...

Yesterday LastMonth Lastyear
8060 8099 8540

Here's the new code ...

-DEFAULTH &MBR_AGE10 = '20-29'
-DEFAULTH &MBR_GENR  = 'Gen y'
-DEFAULTH &MBR_TENR  = '5 - 1 to 2 years'

TABLE FILE bia_cons_counts
SUM
CNT.DST.ACCT_NUM_PBD AS 'Yesterday'
CNT.DST.ACCT_NUM_LM  AS 'LastMonth'
CNT.DST.ACCT_NUM_LY  AS 'LastYear'
WHERE MBR_AGE10 EQ '&MBR_AGE10.EVAL'
WHERE MBR_GENR  EQ '&MBR_GENR.EVAL'
WHERE MBR_TENR  EQ '&MBR_TENR.EVAL'
ON TABLE SET ASNAMES MIXED
ON TABLE SET HOLDLIST PRINTONLY
ON TABLE HOLD AS HLD_CNTS
END
? HOLD HLD_CNTS
-RUN
TABLE FILE HLD_CNTS
PRINT *
END


WebFocus 8.201M, Windows, App Studio
 
Posts: 221 | Location: Lincoln Nebraska | Registered: August 12, 2008Reply With QuoteReport This Post
Platinum Member
posted Hide Post
If that works ... then replace this ...

TABLE FILE HLD_CNTS
PRINT *
END

with this ...

TABLE FILE HLD_CNTS
PRINT
Yesterday
LastMonth
LastYear
ON TABLE HOLD AS HLD_VARS
END
? HOLD HLD_VARS
-RUN
-READFILE HLD_VARS
-TYPE --------------------------------
-TYPE Yesterday ------ &Yesterday
-TYPE LastMonth ------ &LastMonth
-TYPE LastYear ------- &LastYear
-TYPE --------------------------------
-RUN


This step puts your three count totals in amper variables


WebFocus 8.201M, Windows, App Studio
 
Posts: 221 | Location: Lincoln Nebraska | Registered: August 12, 2008Reply With QuoteReport This Post
Platinum Member
posted Hide Post
If that works ... then add the graph next ... which creates the graph from the hold file named HLD_CNTS and the totalLabel should be populated by the amper variable named &Yesterday

Let me know how it goes.

Here's the code ...

-DEFAULTH &MBR_AGE10 = '20-29'
-DEFAULTH &MBR_GENR  = 'Gen y'
-DEFAULTH &MBR_TENR  = '5 - 1 to 2 years'

TABLE FILE bia_cons_counts
SUM
CNT.DST.ACCT_NUM_PBD AS 'Yesterday'
CNT.DST.ACCT_NUM_LM  AS 'LastMonth'
CNT.DST.ACCT_NUM_LY  AS 'LastYear'
WHERE MBR_AGE10 EQ '&MBR_AGE10.EVAL'
WHERE MBR_GENR  EQ '&MBR_GENR.EVAL'
WHERE MBR_TENR  EQ '&MBR_TENR.EVAL'
ON TABLE SET ASNAMES MIXED
ON TABLE SET HOLDLIST PRINTONLY
ON TABLE HOLD AS HLD_CNTS
END
? HOLD HLD_CNTS
-RUN
TABLE FILE HLD_CNTS
PRINT
Yesterday
LastMonth
LastYear
ON TABLE HOLD AS HLD_VARS
END
? HOLD HLD_VARS
-RUN
-READFILE HLD_VARS
-TYPE --------------------------------
-TYPE Yesterday ------ &Yesterday
-TYPE LastMonth ------ &LastMonth
-TYPE LastYear ------- &LastYear
-TYPE --------------------------------
-RUN
-* File: IBFS:/TEST/WFC/Repository/STCU/Charts_d3ccb300_dc5f_4440_839c_e5118e9e189c/BI_Analytics/Consumer_Portfolio/Procedure1.fex Created by WebFOCUS AppStudio
-*IA_GRAPH_BEGIN
-*Do not delete or modify the comments below
*-INTERNAL_COMMENT [long GUID]
*-INTERNAL_COMMENT [long GUID]
-*Do not delete or modify the comments above
ENGINE INT CACHE SET ON
SET PAGE-NUM=NOLEAD
SET ARGRAPHENGINE=JSCHART
SET EMBEDHEADING=ON
SET GRAPHDEFAULT=OFF
-DEFAULTH &WF_STYLE_UNITS='PIXELS';
-DEFAULTH &WF_STYLE_HEIGHT='405.0';
-DEFAULTH &WF_STYLE_WIDTH='770.0';
-DEFAULTH &WF_TITLE='WebFOCUS Report';
GRAPH FILE HLD_CNTS
SUM
Yesterday AS 'Yesterday'
LastMonth AS 'Last Month'
LastYear  AS 'Last Year'
ON GRAPH PCHOLD FORMAT JSCHART
ON GRAPH SET VZERO OFF
ON GRAPH SET GRWIDTH 1
ON GRAPH SET AUTOFIT ON
ON GRAPH SET UNITS &WF_STYLE_UNITS
ON GRAPH SET HAXIS &WF_STYLE_WIDTH
ON GRAPH SET VAXIS &WF_STYLE_HEIGHT
ON GRAPH SET GRMERGE ADVANCED
ON GRAPH SET GRMULTIGRAPH 0
ON GRAPH SET GRLEGEND 0
ON GRAPH SET GRXAXIS 0
ON GRAPH SET LOOKGRAPH GAUGE1
ON GRAPH SET AUTOFIT ON
ON GRAPH SET STYLE *
*GRAPH_SCRIPT
setPieDepth(0);
setPieTilt(0);
setDepthRadius(0);
setPlace(true);
setCurveFitEquationDisplay(false);
*END
INCLUDE=IBFS:/WFC/Repository/STCU_Shared_Content/Style_Sheets/angular.sty,$
*GRAPH_JS
"legend": {
	"visible": true,
	"position": "right",
	"orientation": "vertical",
	"markerPosition": "left"},
"gaugeProperties": {
	"groupLabel": {"visible": false},
	"outerBorder": {
		"width": 0, "fill": {"color": "white"},
		"border": {"width": 0, "color": "white"}},
	"secondaryNeedlesAsMarkers": true,
	"axisTickLength": "35%"},
"totalLabel": {
	"visible": true,
	"font": "bold 12pt Sans-Serif",
	"color": "black",
	"numberFormat": function(n){ return '&Yesterday';}},
"series": [
	{"series": 0, "color": "purple"},
	{"series": 1, "color": "silver", "marker": {
		"shape": "triangle", "size": 12, "border": {"width": 1, "color": "black"}}},
	{"series": 2,"color": "grey", "marker": {
		"shape": "house", "size": 12, "border": {"width": 1, "color": "black"}}},
]
*END
TYPE=REPORT, TITLETEXT=&WF_TITLE.QUOTEDSTRING, $
*GRAPH_SCRIPT
setReportParsingErrors(false);
setSelectionEnableMove(false);
setBorderColor(getGaugeBand1(),new Color(255,163,16));
setFillColor(getGaugeBand1(),new Color(255,163,16));
setBorderColor(getGaugeBand2(),new Color(255,126,29));
setBorderColor(getGaugeBand3(),new Color(255,96,24));
setBorderColor(getGaugeBand4(),new Color(191,48,130));
setBorderColor(getGaugeBand5(),new Color(152,35,113));
setFillColor(getGaugeBand2(),new Color(255,126,29));
setFillColor(getGaugeBand3(),new Color(255,96,24));
setFillColor(getGaugeBand4(),new Color(191,48,130));
setFillColor(getGaugeBand5(),new Color(152,35,113));
setScaleMinAuto(getY1Axis(),true);
setScaleMaxAuto(getY1Axis(),true);
setDisplay(getGaugeValue(),true);
*GRAPH_JS_FINAL
"pieProperties": {
    "holeSize": "0%"
},
"agnosticSettings": {
    "chartTypeFullName": "Special_Gauges"
}
*END
ENDSTYLE
END
-RUN

-*IA_GRAPH_FINISH


WebFocus 8.201M, Windows, App Studio
 
Posts: 221 | Location: Lincoln Nebraska | Registered: August 12, 2008Reply With QuoteReport This Post
Member
posted Hide Post
Hi,

Is there a way to change the default needle start position to 180 degrees and place gauge value in the needle base.

Thanks in advance

This message has been edited. Last edited by: rkiran1,
 
Posts: 7 | Registered: April 15, 2019Reply With QuoteReport This Post
  Powered by Social Strata  
 

Focal Point    Focal Point Forums  Hop To Forum Categories  WebFOCUS/FOCUS Forum on Focal Point     [SOLVED] Cheating the totalLabel value in HTML5 gauge charts

Copyright © 1996-2018 Information Builders, leaders in enterprise business intelligence.