How to use MDX constants/functions in icCube Reporting? - iccube

I have several functions/constants defined in the schema. An example is:
_latestPeriodWithData() which returns a date.
Goal: I want to use this value in the Reporting to set a Guide in a chart, using the demo example 'On Widget Options':
This is what I tried so far:
I have assigned this function as 'MDX / Value' for a Report Constant _lastDate and obtained the value for this constant using the java script function: context.eventValue('_lastDate'); but that just gives me the caption. The function context.eventObject("_lastDate").options.asMdx gives me _latestPeriodWithData(), but not its value.
On Widget Options
/**
* Result will be used while rendering.
*/
function(context, options, $box) {
// for debugging purpose
console.log(context.eventObject("_lastDate").options.asMdx);
options.guides[0].value = context.eventObject("_lastDate").options.asMdx; // <-- gives me _latestPeriodeWith data
// but not its value
options.guides[0].toValue = context.eventObject("_lastDate").options.asMdx;
options.guides[0].lineAlpha = 1;
options.guides[0].lineColor = "#c44";
return options;
}

Related

Using non-scalar variables in BuildMaster otter-script plans

I'm pulling my hair out trying to get some very basic iteration working using non-execution set variables (ie setting things at Global with potential to override at lower scope).
Setting a $variable to some value works fine but I need to do something like...
foreach $DeployConfigKey in #MapKeys(%DeployConfigs)
{
...
}
So far I'm getting nowhere fast with execution errors saying "Invalid value for property Map; expected map."
Further doing something like set %executionvar = %DeployConfigs complains that a map cannot be set to a scaler value.
The variable, DeployConfigs looks like ...
%{"Web.config": ["Web.Beta.config", "Web.Release.config"]}
and is defined at Global scope.
What am I doing wrong?
I'm using buildmaster 5.7.3
Maps are specified as %(key: value), here is an example plan that should help:
set %map = %(Web.config: #("Web.Beta.config", "Web.Release.config"));
foreach $key in #MapKeys(%map)
{
set #values = %map[$key];
Log-Information `$key = $key;
Log-Information `#values = $Join(", ", #values);
}
Sleep 3;

xBestIndex malfunction (passing non-literal parameters to table valued function)

I'm trying to implement a table valued function (as a SQLite virtual table).
It's a function that would take a string and return a table with all the words of the string.
If I call it with literal values like below, it works fine.
SELECT word FROM splitstring("abc def ghi")
If, however, I call it with a column from another table it doesn't work:
SELECT a.Name, word FROM article a, splitstring(a.Text)
The xBestIndex method gets called all right, but right after that, I get an exception from the ExecuteReader method. The exception message is "xBestIndex malfunction". The xFilter method does not get called because of the exception.
My xBestIndex implementation is simple, it just marks the parameter so I can see it in xFilter:
public override SQLiteErrorCode BestIndex(SQLiteVirtualTable table, SQLiteIndex index)
{
index.Outputs.ConstraintUsages.ElementAt(0).argvIndex = 1;
index.Outputs.ConstraintUsages.ElementAt(0).omit = 1;
return SQLiteErrorCode.Ok;
}
Am I'm doing something wrong or is it impossible to pass non-literal parameters to table valued functions?
Found the issue! I was using constraints that had usable=0. The BestIndex method gets called multiple times by SQLite, the second time with a non-usable constraint.
Here is the fixed body of the BestIndex method.
public override SQLiteErrorCode BestIndex(SQLiteVirtualTable table, SQLiteIndex index)
{
if (index.Inputs.Constraints.Count() != 2)
throw new ArgumentException("The generate_series function requires two integer (long) parameters!");
if (index.Inputs.Constraints.All(c=>c.usable == 1))
{
index.Outputs.ConstraintUsages.ElementAt(0).argvIndex = 1;
index.Outputs.ConstraintUsages.ElementAt(0).omit = 1;
index.Outputs.ConstraintUsages.ElementAt(1).argvIndex = 2;
index.Outputs.ConstraintUsages.ElementAt(1).omit = 1;
}
else
{
index.Outputs.IndexNumber = -1;
index.Outputs.EstimatedCost = double.MaxValue;
}
return SQLiteErrorCode.Ok;
}
Now I check the usable flag. When BestIndex gets called with a constraint with usable=0 I skip it i.e. return a high estimated cost for that index so it doesn't get used.

How to define a slider with dynamic range min/max of data to filter rows

I am trying to define a filter on rows based on a slider filter where its range is min/max of a given measure instead of the beginning and end of the data (the default behaviour).
slider widget was designed to select ranges of level members, so it doesn't support selection over measure values. You can either try to create own widget based on slider or use statical defined data as in How to use a static range and display members according a TOP(x) style query, just change:
function consumeEvent( context, event ) {
if (event.name == 'ic3-report-init') {
// Following code will replace a data provider for Slider
// with generated numbers. But to do so, you'll need UID of
// the Slider widget, in this example it's "w1"
var widget = event.value.widgetMgr().getItemById("w1");
_.assign(widget.builder().guts_, {
items:_.times(STEPS_COUNT, function(idx){
return {
name:MIN_VALUE + idx * STEP_SIZE,
uniqueName:idx
}
})})
}
}
define STEPS_COUNT, MIN_VALUE, STEP_SIZE.
After that you can try to apply event value as the filter to your MDX

Using GraphView Library for functions to display multiple graphs

I'm currently developing an android app for reading out multiple sensor values via Bluetooth and display them in a graph. When I stumbled upon jjoe64's GraphViewLibrary, I knew this would fit my purposes perfectly. But now I'm kind of stuck. Basically, I wrote a little function that would generate and display the values of three sensors in 3 different graphs one under the other. This works just fine when the activity is started first, all three graphs a nicely rendered and displayed. But when I want to update the graphs with different values using the resetData()-method to render the new values in each graph, only the last of the three graphs is updated. Obviously, because it's the last graph generated using this rather simple function. My question is: Is there any other elegant way to use a function like mine for generating and updating all three graphs one after the other? I already tried to set the GraphView variable back to null and different combinations of removing and adding the view. Passing the function a individual GraphView-variable like graphView1, graphView2... does also not work.
Here is the function:
private GraphView graphView;
private GraphViewSeries graphViewSerie;
private Boolean graphExisting = false;
...
public void makeGraphs (float[] valueArray, String heading, int graphId) {
String graphNumber = "graph"+graphId;
int resId = getResources().getIdentifier(graphNumber,"id", getPackageName());
LinearLayout layout = (LinearLayout) findViewById(resId);
int numElements = valueArray.length;
GraphViewData[] data = new GraphViewData[numElements];
for (int c = 0; c<numElements; c++) {
data[c] = new GraphViewData(c+1, valueArray[c]);
Log.i(tag, "GraphView Graph"+graphId+": ["+(c+1)+"] ["+valueArray[c]+"].");
}
if (!graphExisting) {
// init temperature series data
graphView = new LineGraphView(
this // context
, heading // heading
);
graphViewSerie = new GraphViewSeries(data);
graphView.addSeries(graphViewSerie);
((LineGraphView) graphView).setDrawBackground(true);
graphView.getGraphViewStyle().setNumHorizontalLabels(numElements);
graphView.getGraphViewStyle().setNumVerticalLabels(5);
graphView.getGraphViewStyle().setTextSize(10);
layout.addView(graphView);
}
else {
//graphViewSerie = new GraphViewSeries(data);
//graphViewSerie.resetData(data);
graphViewSerie.resetData(new GraphViewData[] {
new GraphViewData(1, 1.2f)
, new GraphViewData(2, 1.4f)
, new GraphViewData(2.5, 1.5f) // another frequency
, new GraphViewData(3, 1.7f)
, new GraphViewData(4, 1.3f)
, new GraphViewData(5, 1.0f)
});
}
And this is the function-call depending on an previously generated array (which is being monitored to be filled with the right values):
makeGraphs(graphData[0], "TempHistory", 1);
makeGraphs(graphData[1], "AirHistory", 2);
makeGraphs(graphData[2], "SensHistory", 3);
graphExisting = true;
Any help and / or any feedback in general is greatly appreciated! Lots of thanks in advance!
EDIT / UPDATE:
Thanks to jjoe64's answer I was able to modify the function to work properly. I was clearly having a mistake in my thinking, since I thought I'd also be changing a GraphViewSeries-object I would handle my function as additional parameter (which I tried before). Of course this does not work. However, with this minor Improvements I managed to make this work using a Graphviewseries Array. To give people struggling with a similar problem an idea of what I had to change, here the quick-and-dirty draft of the solution.
I just changed
private GraphViewSeries graphViewSerie;
to
private GraphViewSeries graphViewSerie[] = new GraphViewSeries[3];
and access the right Series using the already given parameter graphId within the function (if-clause) like this:
int graphIndex = graphId - 1;
graphViewSerie[graphIndex] = new GraphViewSeries(data);
In the else-clause I'm updating the series likewise by calling
graphViewSerie[graphIndex].resetData(data);
So, once again many thanks for your support, jjoe64. I'm sorry I wasn't able to update the question earlier, but I did not find time for it.
of course it is not working correct, because you save always the latest graphseries-object in the member graphViewSerie.
First you have to store the 3 different graphviewseries (maybe via array or map) and then you have to access the correct graphviewseries-object in the else clause.

Using Per Item Fills in Flex/Actionscript

I am creating a chart using mxml. The mxml tags only create a chart with a horizontal axis and vertical axis.
My result event handler has actionscript code that loops through the xml result set and creates all the series (line series and stacked bar). This part of the code works fine.
Now I need to use the functionfill function to set individual colors to each series. All the examples I have found call the functionfill from within an MXML tag, like so:
<mx:ColumnSeries id="salesGoalSeries"
xField="Name"
yField="SalesGoal"
fillFunction="myFillFunction"
displayName="Sales Goal">
I am having trouble calling functionfill from actionscript.
A portion of the code that build the data series is below:
if (node.attribute("ConfidenceStatus")=="Backlog"
|| node.attribute("ConfidenceStatus")=="Billings") {
// Create the new column series and set its properties.
var localSeries:ColumnSeries = new ColumnSeries();
localSeries.dataProvider = dataArray;
localSeries.yField = node.attribute("ConfidenceStatus");
localSeries.xField = "TimebyDay";
localSeries.displayName = node.attribute("ConfidenceStatus");
localSeries.setStyle("showDataEffect", ChangeEffect);
localSeries.fillFunction(setSeriesColor(xxx));
// Back up the current series on the chart.
var currentSeries:Array = chart.series;
// Add the new series to the current Array of series.
currentSeries.push(localSeries);
//Add Array of series to columnset
colSet.series.push(localSeries);
//assign columnset to chart
chart.series = [colSet];
My setSeriesColor function is:
private function setSeriesColor(element:ChartItem, index:Number):IFill {
var c:SolidColor = new SolidColor(0x00CC00);
var item:ColumnSeriesItem = ColumnSeriesItem(element);
//will put in logic here
return c;
}
What parameters do I put in the line localSeries.fillFunction(setSeriesColor(xxx)) ?
I tried localSeries as the first argument but I get an implicit coercion error telling me localSeries can't be cast as ChartItem.
How do I call the function correctly?
localSeries.fillFunction = setSeriesColor;
The code you have right now is actually CALLING setSeriesColor the way you have it set up. You only want it to refer to a reference of the function, not calling it, so just send it "setSeriesColor" as a variable.

Resources