Gizmo idioms created by our Consultants and Developers

Replace currency symbols

Use Case: Numerical data is often not formatted appropriately when copied into OrgVue. This is because the value pasted from the clipboard is the value you see in a cell in Excel, rather than the underlying number. This can cause issues, especially if your machine is from a non-UK locale (i.e. uses '.' instead of ',' to separate thousands) or when salary data contains currency symbols.

Notes: This expression will replace specified symbols (e.g. '$' in a nominated column with a specified character. Copy the expression into the expression manager and then switch it to macro mode before evaluating.

nodes().setproperty(n => ({'Current Salary': n.currentsalary.value.replace(/\$/g,"")}))

// replace 'Current Salary' with the (case sensitive) key of the property in question
// replace n.currentsalary with the property in question
// change $ in the replace() clause to search for another symbol

Hints: To update multiple properties at once, chain several key:values pairs together within setproperty in the same way as you would with the node.settemporary() method. For more information about the replace() syntax, see the summary of Regular Expressions (Regex) at: https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions

Allocate orphans to potential managers

Use case: Where the organisation has orphans in the dataset and wants to automatically assign them to a likely manager.

Notes: The selection of potential manager is based on the orphan's cost centre, grade and ID value.

view.property('Cost Centre').buckets.map(b => {
                var id = '';
                b.items.fold((agg, nd) => {
                                if(nd.grade.value > agg){
                                                id = nd.ID.value; 
                                                return nd.grade.value
                                }
                                else {
                                                return agg;
                                } 
                }, 0);
                return {ID: id, CC: b.name};
})
// where 'Cost Centre' [line 1], nd.grade.value [lines 4 & 6], and nd.ID.value [line 5]
// need to be updated to reflect the actual properties in the dataset

Group array into a "value:count" list

csv
array(node.resource).groupBy(i=>i).map(g=> [g.key,": ",g.values.count].join('')).join(', ')
node.d
node.d.groupBy(n=>n.businesstitle).map(g=> [g.key,": ",g.values.count].join('')).join(', ')

Allocate a rank to a node based upon an ordering

Use case: Where the user wants to find the rank of a node e.g. by salary within the organisation.

var sortProp = "current salary";
var rankProp = "salary rank";

// when setting only one property:
nodes().sort(sortProp).setvalue(rankProp, (n, i) => i);

// can be integrated into a larger setvalue expression
nodes().sort(sortProp).setvalue((n, i) => ({
  "salary rank": i
}));

Create a logical unique ID for each node in the data-set

"Node.".concat(node.allancestors.reverse().map(n => n.index + 1).concat(node.index + 1).join("."))

Parent = Node.1 Child = Node.1.1 Grandchild = 1.1.1

Use case: When linking multiple nodes together it is sometimes useful to show a summary. This expression allows you to show the grouped sum of the links by category with each group displayed on a separate line:

node.links.map(l=> ({k: l.to._label.value, v: l.Value.value})).groupSum('k','v').format("{key} - {values}").join("\n")

Summarise number of blanks per property

var props = view.properties.filter(p=>!p.isgenerated);


var table = props.map(k=>({name:k.name,score:1-(view.property(k).bucket('(Blank)').count/nodes().count)})).sort('score')

// View overall completeness as
array(table.score.value).sum/props.count

Convert RGB values to Hex

Use case: Where the organisation has a mix of RGB and Hex colours in the dataset and needs to convert them all to Hex for consistency.

Notes: Hexadecimal notation for colours acts as a shorthand for RGB values.


var dd = x=>['0', Number(x).toString(16)].join('').slice(-2);

nodes().map(x=>{
  var rgb = x.rgb.value.split(',');

  return ['0x', dd(rgb[0]), dd(rgb[1]), dd(rgb[2])].join('')
}).join(', ')

// Replace "x.rgb" with x.format('{r},{g},{b}')
// if RGB values are stored in separate properties

Span of control calculator

Use case: Where the organisation wants to estimate the impact of moving to a standard span of control.

Creator: Ben Marshall, 20 Sep 2016

Expression:

global.socModel(targetSoC, costField, splitField) // where splitField is optional

e.g.1 global.socModel(8,'currentsalary','department') // calculates the headcount and salary savings across each department if the average SoC were 8

e.g.2 global.socModel(10,'totalannualcompensation') // calculates the headcount and total annual compensation savings across the whole dataset if the average SoC were 10

Logic: The basic logic behind the ‘model’ is:

• Find the difference between actual SoC and target SoC for each manager.

• Sum these differences, giving the total gap between actual and target, and therefore the number of people who could be re-parented if span of control were on target.

• Divide this total by the target span of control, giving the total number of managers who are assumed to be responsible for the people who would be reparented, and therefore who could be removed from the organisation.

• Cost saving based on the number of managers who could be removed and the average salary (or some other measure) for managers

Copy the script below and Ctrl click on the OrgVue icon to paste into the script editor.

global.socModel = function(targetSoC,costField,splitBy){
var grouping = splitBy == null ? "" : splitBy;
              allnodes().groupBy(grouping).map(g => {

                             var managers = g.values.filter(n => n._is_leaf == false);
                             var headcount = g.values.count;
                             var cost = g.values[costField].sum;
                             var headcountSaving = managers.map(n => targetSoC - n._outgoing_count).sum/targetSoC;
                             var newHeadcount = headcount - headcountSaving;
                             var costSaving = managers[costField].avg*headcountSaving;
                             var newCost = cost - costSaving;

                             return array({
                                           "Group":splitBy == null ? "All" : g.key, 
                                           "HC As-Is": headcount,
                                           "HC To-Be": Math.round(newHeadcount), 
                                           "HC Saving": Math.round(headcountSaving), 
                                           "_Cost As-Is": cost,
                                           "_Cost To-Be": Math.round(newCost),
                                           "_Cost Saving": Math.round(costSaving)
                             })
              })
};

Example image of output:

Appendix

The script takes into account all the existing nodes in the dataset. In order to make it Filter-Sensitive, i.e. so that it reflects the filters applied on the nodes to make the calculations, it is necessary to make few changes in the script:

• Replace allnodes() with nodes()

• Replace _outgoing_count with _span_of_control

These amendments have been applied in the script below.

global.socModel = function(targetSoC,costField,splitBy){
var grouping = splitBy == null ? "" : splitBy;
              nodes().groupBy(grouping).map(g => {

                             var managers = g.values.filter(n => n._is_leaf == false);
                             var headcount = g.values.count;
                             var cost = g.values[costField].sum;
                             var headcountSaving = managers.map(n => targetSoC - n._span_of_control).sum/targetSoC;
                             var newHeadcount = headcount - headcountSaving;
                             var costSaving = managers[costField].avg*headcountSaving;
                             var newCost = cost - costSaving;

                             return array({
                                           "Group":splitBy == null ? "All" : g.key, 
                                           "HC As-Is": headcount,
                                           "HC To-Be": Math.round(newHeadcount), 
                                           "HC Saving": Math.round(headcountSaving), 
                                           "_Cost As-Is": cost,
                                           "_Cost To-Be": Math.round(newCost),
                                           "_Cost Saving": Math.round(costSaving)
                             })
              })
};

results matching ""

    powered by

    No results matching ""