Skip to content

Diverging indicators #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Defines the structure and properties of the index
- __max:__ (default `100`) The `max` property specifies the maximum numeric value that an indicator can have. Whilst optional it's a good idea to specify this for clarity and most of the time it will be neccesary for the majority of indicators.That said, on `calculated` indicators it has no meaning or effect.
- __min:__ (default `0`) The minimum value that an indicator can take, this is more oftent han not 0.
- __invert:__ (default `false`) Most indicators contribute positively towards the score of their parent group e.g. high literacy rates are considered a good thing so a big number leads to a big score. Sometimes this is not the case for example a high unemployment rate is usually considered a bad thing so we want high number to contribute negatively to the parent group score. This is achieved by setting the `invert` property to `true`.
- __diverging:__ (default `false`) This can be used when an indicator wants to measure the degree of centrality. For example gender balance of a company might be a value between -100% for all male and +100% for all female so we might consider 0 (representing parity) to be the ideal value, in a diverging indicator a value of -20% will be treated the same as +20%. Typically (e.g. in the preceding example) you also want the indicator to be __invert__ed so that a low value is good. _Note: 0 is always the central value. It's possible to imagine an indicator which, for example, might range between 65mins and 240mins where the ideal value is 90 mins (i.e. the best length for a feature film) but this is not currently supported._

## Data source: Entities
[Data source: Entites]:#data-entities
Expand Down
200 changes: 100 additions & 100 deletions data/inclusiveinternet/indicators.csv

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions data/simple-index-set/entities.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name,1.1,1.2,1.3,1.4,1.5,1.6,2.1,2.2,2.3.1,2.3.2,3.1,3.2
Catan,5,5,5,8,1.5,7,6,4,1,0,35,70
Monopoly,4,4,9,6,2,2,4,4,1,0,19,5
Brass: Birmingham,8,8,3,7,3,6,7,7,4,10,50,100
Treasure Island,7,5,3,7,1.5,8,8,8,6,10,40,20
Tigris and Eurphrates,8,5,4,6,1,7,3,6,1,5,35,100
The Crew,8,4,7,6,.5,7,3,6,0,0,13,30
Twilight Imperium,6,7,4,4,7,8,8,6,1,-5,90,10
17 changes: 17 additions & 0 deletions data/simple-index-set/indicators.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
id,indicatorName,min,max,invert,diverging,weighting,type,
1,approachability,,,,,1,calculated,
2,theme,,,,,1,calculated,
3,value,,,,,1,calculated,
1.1,thinkyness,0,10,,,1,,
1.2,rules complexity,0,10,,,1,,
1.3,mechanical familiarity,0,10,,,1,,
1.4 ,rule book quality,0,10,,,1,,
1.5,play length,0.5,8,,,1,,
1.6,fun,0,10,,,1,,
2.1,theme integration,0,10,,,1,,
2.2,theme novelty,0,10,,,1,,
2.3,inclusivity,,,,,1,calculated,
2.3.1,character gender bias,-10,10,true,true,1,,
2.3.2,character racial bias,-10,10,true,true,1,,
3.1,price,10,100,true,,1,,
3.2,replayablity,1,100,,,1,,
38 changes: 27 additions & 11 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,24 @@ const waterRootDir = 'data/wateroptimisation';
const waterIndicators = csvParse(fs.readFileSync(`${waterRootDir}/indicators.csv`, 'utf-8'));
const waterEntities = csvParse(fs.readFileSync(`${waterRootDir}/entities.csv`, 'utf-8'));

const waterOptimisationIndex = indexCore(waterIndicators, waterEntities);
// const waterOptimisationIndex = indexCore(waterIndicators, waterEntities);

const inclusiveIternetRootDir = 'data/inclusiveinternet';

const inclusiveInternetIndicators = csvParse(fs.readFileSync(`${inclusiveIternetRootDir}/indicators.csv`, 'utf-8'));
const inclusiveInternetEntities = csvParse(fs.readFileSync(`${inclusiveIternetRootDir}/entities.csv`, 'utf-8'));

const inclusiveInternetIndex = indexCore(inclusiveInternetIndicators, inclusiveInternetEntities);


const simpleRootDir = 'data/simple-index-set';

const simpleIndicators = csvParse(fs.readFileSync(`${simpleRootDir}/indicators.csv`, 'utf-8'));
const simpleEntities = csvParse(fs.readFileSync(`${simpleRootDir}/entities.csv`, 'utf-8'));

const simpleIndex = indexCore(simpleIndicators, simpleEntities);

console.log(simpleIndex.indexedData)

// console.log(waterOptimisationIndex.indexedData['Abu Dhabi']['1']);
// console.log(waterOptimisationIndex.indexedData['Abu Dhabi'].value);
Expand All @@ -20,13 +36,13 @@ const waterOptimisationIndex = indexCore(waterIndicators, waterEntities);

// indicator 3.4.4 in the water index has .a and .b sub indicators
// for this indicator abu dhabi has different values for a and b
const before = JSON.stringify(waterOptimisationIndex.getEntity('Abu Dhabi'), null, ' ')
delete before.data;
waterOptimisationIndex.filterIndicators(indicator=>{
return String(indicator.id).indexOf('b')>0; // if the indicator includes "b" in it's id ignore it
})
const after = JSON.stringify(waterOptimisationIndex.getEntity('Abu Dhabi'), null, ' ')
delete after.data; // just for neater output (note data is the original data for an entity used to calculate the index)

console.log('BEFORE', before);
console.log('AFTER', after);
// const before = JSON.stringify(waterOptimisationIndex.getEntity('Abu Dhabi'), null, ' ')
// delete before.data;
// waterOptimisationIndex.filterIndicators(indicator=>{
// return String(indicator.id).indexOf('b')>0; // if the indicator includes "b" in it's id ignore it
// })
// const after = JSON.stringify(waterOptimisationIndex.getEntity('Abu Dhabi'), null, ' ')
// delete after.data; // just for neater output (note data is the original data for an entity used to calculate the index)

// console.log('BEFORE', before);
// console.log('AFTER', after);
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@signal-noise/index-core",
"version": "1.2.0",
"version": "1.3.0",
"description": "",
"main": "src/index-core.js",
"type": "module",
Expand Down
34 changes: 27 additions & 7 deletions src/index-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,39 @@ function indexCore(indicatorsData = [], entitiesData = [], indexMax = 100) {

// format an indicator for passing to the weighted mean function
function formatIndicator(indicator, entity, max) {
const diverging = !!indicator.diverging;
let value = entity.user && entity.user[indicator.id]
? Number(entity.user[indicator.id])
: Number(entity[indicator.id]);

let range = [
indicator.min ? Number(indicator.min) : 0,
indicator.max ? Number(indicator.max) : max,
];

if(diverging){
let centerpoint = 0; // currently no way to set this diffeently included here as a signpost for the future

if (indicator.max){
range = [0, indicator.max];
if(indicator.min){
range = [0, Math.max(Math.abs(indicator.min),indicator.max)];
}
}else{
range = [0, max];
}
value = Math.abs(value - centerpoint);
}


return {
id: indicator.id,
value: entity.user && entity.user[indicator.id]
? Number(entity.user[indicator.id])
: Number(entity[indicator.id]),
value,
weight: indicator.userWeighting
? Number(indicator.userWeighting)
: Number(indicator.weighting),
invert: !!indicator.invert,
range: [
indicator.min ? Number(indicator.min) : 0,
indicator.max ? Number(indicator.max) : max,
],
range
};
}

Expand Down
19 changes: 15 additions & 4 deletions test/index-core.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import { expect } from '@jest/globals';
import fs from 'fs';
import indexCore from '../src/index-core.js';

const rootDir = 'data/wateroptimisation';
const waterRootDir = 'data/wateroptimisation';

const waterIndicators = csvParse(fs.readFileSync(`${rootDir}/indicators.csv`, 'utf-8'));
const waterEntities = csvParse(fs.readFileSync(`${rootDir}/entities.csv`, 'utf-8'));
const waterIndicators = csvParse(fs.readFileSync(`${waterRootDir}/indicators.csv`, 'utf-8'));
const waterEntities = csvParse(fs.readFileSync(`${waterRootDir}/entities.csv`, 'utf-8'));

const simpleRootDir = 'data/simple-index-set';

const simpleIndicators = csvParse(fs.readFileSync(`${simpleRootDir}/indicators.csv`, 'utf-8'));
const simpleEntities = csvParse(fs.readFileSync(`${simpleRootDir}/entities.csv`, 'utf-8'));

test('create index-core', ()=>{
const waterOptimisationIndex = indexCore(waterIndicators, waterEntities);
Expand Down Expand Up @@ -36,4 +41,10 @@ test('filterIndicators index-core', ()=>{
expect(waterOptimisationIndex.getIndexMean('3.1.1').toFixed(1)).toBe('25.0');
expect(waterOptimisationIndex.getIndexMean('2').toFixed(1)).toBe('74.7');
expect(waterOptimisationIndex.getIndexMean().toFixed(1)).toBe('68.7');
});
});

test('diverging indicator index-core', ()=>{
const simpleIndex = indexCore(simpleIndicators, simpleEntities);
expect(simpleIndex.indexedData['Tigris and Eurphrates']['2.3']).toBe(70);
expect(simpleIndex.indexedData['Twilight Imperium']['2.3']).toBe(70);
})