How to set format_string dynamically in scope? - scope

I have 3 measures:
[Measures].[Some Count] with FORMAT_STRING="#,0"
[Measures].[Some Amount] with FORMAT_STRING="Currency"
[Measures].[Some Percent] with FORMAT_STRING="Percent"
SCOPE is used to change values of all measures, let's say this way:
SCOPE ([Dimension 1].[Hierarchy 1].[Level 1]);
THIS = IIF(<some condition>,<change>,<not change>);
FORMAT_STRING(THIS) = ???
END SCOPE;
Problem: Measures format is wrong for upper levels of [Dimension 1]. 12345 instead of 12,345 etc.
Possible solution: change to IIF(Measures.CurrentMember is [Measures].[Some Count],"#,0" etc.)
Disadvantages:
Measures lists creation, its support (if smth is changed, not to forget change here and so on)
No opportunity to work with sets of measures (even inside SSAS Browser).
Is there any way to set measures formats dynamically?
UPDATE: Actually, there are several hundreds of measures in real project, so I'm trying to avoid lists of measures.

I'm not sure what you want, but you can try to use:
FORMAT_STRING([Measures].[Cost])='"£"#,0';
after your scope.

You could keep the format in a member attribute and pass it...
format_string(this) = (existing [Dimension 1].[Format].[Format]).item(0).membervalue;

Related

Update a parameter value in Brightway

It seems to be a simple question but I have a hard time to find an answer to it. I already have a project with several parameters (project and database parameters). I would like to obtain the LCA results for several scenarios with my parameters having different values each time. I was thinking of the following simple procedure:
change the parameters' value,
update the exchanges in my project,
calculate the LCA results.
I know that the answer should be in the documentation somewhere, but I have a hard time to understand how I should apply it to my ProjectParameters, DatabaseParameters and ActivityParameters.
Thanks in advance!
EDIT: Thanks to #Nabla, I was able to come up with this:
For ProjectParameter
for pjparam in ProjectParameter.select():
if pjparam.name=='my_param_name':
break
pjparam.amount = 3
pjparam.save()
bw.parameters.recalculate()
For DatabaseParameter
for dbparam in DatabaseParameter.select():
if dbparam.name=='my_param_name':
break
dbparam.amount = 3
dbparam.save()
bw.parameters.recalculate()
For ActivityParameter
for param in ActivityParameter.select():
if param.name=='my_param_name':
break
param.amount = 3
param.save()
param.recalculate_exchanges(param.group)
You could import DatabaseParameter and ActivityParameter iterate until you find the parameter you want to change, update the value, save it and recalculate the exchanges. I think you need to do it in tiers. First you update the project parameters (if any) then the database parameters that may depend on project parameters and then the activity parameters that depend on them.
A simplified case without project parameters:
from bw2data.parameters import ActivityParameter,DatabaseParameter
# find the database parameter to be updated
for dbparam in DatabaseParameter.select():
if (dbparam.database == uncertain_db.name) and (dbparam.name=='foo'):
break
dbparam.amount = 3
dbparam.save()
#there is also this method if foruma depend on something else
#dbparam.recalculate(uncertain_db.name)
# here updating the exchanges of a particular activity (act)
for param in ActivityParameter.select():
if param.group == ":".join(act.key):
param.recalculate_exchanges(param.group)
you may want to update all the activities in the project instead of a single one like in the example. you just need to change the condition when looping through the activity parameters.

Reducing duplicates across arrays in Twig

Essential, due to crappy circumstances, I need to do this in native Twig if possible: (I know this shouldn't be done in a VIEW template language)
loop over object.key
object.key["key1"] = ["val1","val2-a"]
object.key["key2"] = ["val1","val2-b"]
object.key["key3"] = ["val1","val2-c"]
manipulate as needed, into a new array or object or whatever and get
object.key["key1"] = ["val2-a"]
object.key["key2"] = ["val2-b"]
object.key["key3"] = ["val2-c"]
As you can see, I need to reduce duplicates values across different keys.
I'm having hard time finding a way to do this with out adding a custom filter or changing some architecture in the back-end that, basically, a deadline doesn't have time for. Any thoughts?

Exposing the current combo selection index for the CGridCellCombo class

For several years I have been using the CGridCellCombo class. It is designed to be used with the CGridCtrl.
Several years ago I did make a request in the comments section for an enhancement but I got no replies.
The basic concept of the CGridCellCombo is that it works with the text value of the cell. Thus, when you present the drop list it will have that value selected. Under normal circumstances this is fine.
But I have places where I am using the combo as a droplist. In some situations it is perfectly fine to continue to use the text value as the go-between.
But is some situations it would have been ideal to know the actual selected index of the combo. When I have a droplist and it is translated into 30 languages, and I need to know the index, I have no choice but to load the possible options for that translation and then examine the cell value and based on the value found in the array I know the index.
It works, but is not very elegant. I did spend a bit of time trying to keep track of the selected index by adding a variable to CInPlaceList and setting it but. I then added a wrapper method to the CGridCellCombo to return that value. But it didn't work.
I wondered if anyone here has a good understanding of the CGridCellCombo class and might be able to advise me in exposing the CComboCell::GetCurSel value.
I know that the CGridCtrl is very old but I am not away of another flexible grid control that is designed for MFC.
The value that is transfered back to the CGridCtrl is choosen in CInPlaceList::EndEdit. The internal message GVN_ENDLABELEDIT is used, and this message always use a text to set it into the grid.
The value is taken here via GetWindowText from the control. Feel free to overwrite this behaviour.
The handler CGridCtrl::OnEndInPlaceEdit again calls OnEndEditCell. All take a string send from GVN_ENDLABELEDIT.
When you want to make a difference between the internal value and the selected value you have to manage this via rewriting the Drawing and selecting. The value in the grid is the GetCurSel value and you have to show something different... There isn't much handling about this in the current code to change.
More information
The key is CInPlaceList::EndEdit(). There is a call to GetWindowText (CInPlaceList is derived from CComboBox), just get the index here. Also in CGridCellCombo::EndEdit you have access to the m_pEditWnd, that is the CInPlaceList object and derived from CComboBox, so you have access here too.
I have found this to be the simplest solution:
int CGridCellCombo::GetSelectedIndex()
{
int iSelectedIndex = CB_ERR;
CString strText = GetText();
for (int iOption = 0; iOption < m_Strings.GetSize(); iOption++)
{
if (strText.CollateNoCase(m_Strings[iOption]) == 0) // Match
{
iSelectedIndex = iOption;
break;
}
}
return iSelectedIndex;
}

Comparing vertex properties in Gremlin Groovy

I'm asking nearly the same question as you see here, but with the constraint that the groovy, not java, syntax must be used. Ideally the answer to would be very concise.
I have a simple graph of people vertices. Each has an "age" property listing that person's age in years. There are also "worksFor" labeled edges connecting pairs of people vertices. I'd like to see all edges where the people at both ends of the edge have the same age property.
I'd then like a similar query where the two ages differ by less than 3 years.
As mentioned, this should be in groovy, not Java, syntax. Gremlin 3 is preferred, but Gremlin 2 answers are acceptable.
all edges where the people at both ends of the edge have the same age property
g.V().as("a").outE("worksFor").as("e").inV().as("b").select("a","b").by("age").
where("a", eq("b")).select("e")
where the two ages differ by less than 3 years
g.V().as("a").outE("worksFor").as("e").inV().as("b").select("a","b").by("age").
filter {Math.abs(it.get().get("a") - it.get().get("b")) < 3}.select("e")
If we know the target vertex against which all other vertices are compared, the following may work:
t=g.V().has('id', 'target_node_id').values('age').next()
g.V().has('age').filter{it.get().value('age')-t<=3 && it.get().value('age')-t>=-3}
I don't know how to do it in one query. I also don't know if there is a function/step to get the absolute value.
This only partially satisfies your need, but it may be a start.
Comparing two date properties using math step:
g.V().hasLabel('EnterExitDate').limit(10000).as('enter','exit')
.where("enter",lt("exit")).by('enter').by('exit')
.where(math('(exit - enter) / (3600*1000) ')
.by(values('exit').map({ it.get().time }))
.by(values('enter').map({ it.get().time }))
.is(lt(1)))
.valueMap()
This query will find all pairs of enter-exit record of employees that have happened within 1 hour.
EnterExitDate class:
public class EnterExitDate {
private Date enter;
private Date exit;
// getters and setters...
}

Masking answer options in Confirmit (jscript)

I'm trying to mask the answer options that show up in a 3DGrid question item in Confirmit, using the value of a background variable.
E.g. when "background1" ==1, display answer category 1. If "background1" ==0, do not display answer category 1. If "background2" ==1, display category 3, otherwise do not. In any case, display answer category 2.
Hopefully this is easy for someone out there (I'm a psychologist, not a coder...so not so much so for me :/)
Thanks!
In order to access the data inside a question/variable we can use the f function of confirmit.
for instance:
f('my_question_id').get();
When masking a question, we need to pass in a Set object so Confirmit knows what Code's to show and not to show.
Often you will mask using a Set from a previous question. So you pass in the question_id and Confirmit does all the other magic.
Here we have the problem of not having a Set, so we will have to create our own.
For this, there are 2 approaches (can be found in the scripting manual under Working with Sets > Methods of the set Object > add and remove and Working with Sets > User defined functions...)
I'm going to stick to the first one because it is easier to use ;)
What we will do first is create a script node (it doesn't matter where you create it, just somewhere in the survey, I often have a folder Functions with all my script nodes in somewhere at the bottom of my survey)
In that script file we will have our function that crates our set:
function CreateMyAwesomeSet()
{
//create an empty Set
var mySet = new Set();
//if background1 equals 1, add 1 to our Set
if ( f('background1').get() == '1' )
{
mySet.add(1);
}
//return the Set of allowed Codes
return mySet;
}
Here we declare a function that we now can use wherever we want to.
So now, If we want to use this Set, we add a Code Mask to your grid:
CreateMyAwesomeSet()
You can ofcourse change the name of the function, and add extra if statements.
hope this helps

Resources