Skip to content

Commit

Permalink
Merge pull request #137 from AUS-DOH-Safety-and-Quality/variation-ico…
Browse files Browse the repository at this point in the history
…n-bugfixes

Variation icon bugfixes, optional retention of outliers in limit calcs
  • Loading branch information
andrjohns authored Jul 10, 2023
2 parents f2165ac + f9904af commit 85c184a
Show file tree
Hide file tree
Showing 18 changed files with 82 additions and 27 deletions.
8 changes: 8 additions & 0 deletions capabilities.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@
]
}
},
"outliers_in_limits": {
"displayName": "Keep Outliers in Limit Calcs.",
"type": { "bool": true }
},
"multiplier": {
"displayName": "Multiplier",
"type": {
Expand Down Expand Up @@ -293,6 +297,10 @@
"displayName": "Show Variation Icons",
"type" : { "bool" : true }
},
"flag_variation_last": {
"displayName": "Flag Only Last Point",
"type" : { "bool" : true }
},
"variation_icons_locations": {
"displayName": "Variation Icon Locations",
"type": {
Expand Down
12 changes: 9 additions & 3 deletions src/Classes/chartObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ type chartObjectConstructor = {
splitIndexes: number[];
}

type LimitArgs = {
inputData: dataObject;
inputSettings: settingsObject;
}

class chartObject {
inputData: dataObject;
inputSettings: settingsObject;
splitIndexes: number[];
limitFunction: (x: dataObject) => controlLimits;
limitFunction: (x: LimitArgs) => controlLimits;

getLimits(): controlLimits {
let calcLimits: controlLimits;
Expand All @@ -40,7 +45,7 @@ class chartObject {
return data;
})

const calcLimitsGrouped: controlLimits[] = groupedData.map(d => this.limitFunction(d));
const calcLimitsGrouped: controlLimits[] = groupedData.map(d => this.limitFunction({inputData: d, inputSettings: this.inputSettings}));
calcLimits = calcLimitsGrouped.reduce((all: controlLimits, curr: controlLimits) => {
const allInner: controlLimits = all;
Object.entries(all).forEach((entry, idx) => {
Expand All @@ -52,7 +57,7 @@ class chartObject {
})
} else {
// Calculate control limits using user-specified type
calcLimits = this.limitFunction(this.inputData);
calcLimits = this.limitFunction({inputData: this.inputData, inputSettings: this.inputSettings});
}

calcLimits.flagOutliers(this.inputSettings);
Expand Down Expand Up @@ -86,4 +91,5 @@ class chartObject {
}
}

export { LimitArgs }
export default chartObject;
4 changes: 4 additions & 0 deletions src/Classes/settingsGroups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class datesSettings {

class spcSettings {
chart_type: settingsPair<string>;
outliers_in_limits: settingsPair<boolean>;
multiplier: settingsPair<number>;
sig_figs: settingsPair<number>;
perc_labels: settingsPair<string>;
Expand All @@ -59,6 +60,7 @@ class spcSettings {

constructor() {
this.chart_type = new settingsPair("i");
this.outliers_in_limits = new settingsPair(false);
this.perc_labels = new settingsPair("Automatic");
this.multiplier = new settingsPair(1);
this.sig_figs = new settingsPair(2);
Expand Down Expand Up @@ -243,11 +245,13 @@ class outliersSettings {

class nhsIconSettings {
show_variation_icons: settingsPair<boolean>;
flag_variation_last: settingsPair<boolean>;
variation_icons_locations: settingsPair<string>;
variation_icons_scaling: settingsPair<number>;

constructor() {
this.show_variation_icons = new settingsPair(false);
this.flag_variation_last = new settingsPair(true);
this.variation_icons_locations = new settingsPair("Top Right");
this.variation_icons_scaling = new settingsPair(1.0);
}
Expand Down
17 changes: 14 additions & 3 deletions src/Classes/svgIconClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,28 @@ class svgIconClass {
"decrease" : "Low",
"neutral" : ""
}
const invert_suffix_map: Record<string, string> = {
"High" : "Low",
"Low" : "High",
"" : ""
}
const suffix: string = suffix_map[imp_direction];
const allFlags: string[]
= currLimits.astpoint.concat(currLimits.shift, currLimits.trend, currLimits.two_in_three);
const flag_last: boolean = viewModel.inputSettings.nhs_icons.flag_variation_last.value;
let allFlags: string[];
if (flag_last) {
const N: number = currLimits.astpoint.length - 1;
allFlags = [currLimits.astpoint[N], currLimits.shift[N], currLimits.trend[N], currLimits.two_in_three[N]];
} else {
allFlags = currLimits.astpoint.concat(currLimits.shift, currLimits.trend, currLimits.two_in_three);
}

const iconsPresent: string[] = new Array<string>();

if (allFlags.includes("improvement")) {
iconsPresent.push("improvement" + suffix)
}
if (allFlags.includes("deterioration")) {
iconsPresent.push("concern" + suffix)
iconsPresent.push("concern" + invert_suffix_map[suffix])
}
if (allFlags.includes("neutral_low")) {
iconsPresent.push("neutralLow")
Expand Down
1 change: 0 additions & 1 deletion src/Classes/viewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ class viewModelObject {
// Extract input data, filter out invalid values, and identify any settings passed as data
this.inputData = new dataObject(dv[0].categorical, this.inputSettings)


// Initialise a new chartObject class which can be used to calculate the control limits
this.chartBase = new chartObject({ inputData: this.inputData,
inputSettings: this.inputSettings,
Expand Down
4 changes: 3 additions & 1 deletion src/Limit Calculations/c.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import * as d3 from "d3";
import rep from "../Functions/rep";
import dataObject from "../Classes/dataObject"
import controlLimits from "../Classes/controlLimits"
import { LimitArgs } from "../Classes/chartObject";

function cLimits(inputData: dataObject): controlLimits {
function cLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
const cl: number = d3.mean(inputData.numerators);
const sigma: number = Math.sqrt(cl);

Expand Down
4 changes: 3 additions & 1 deletion src/Limit Calculations/g.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { sqrt } from "../Functions/UnaryFunctions";
import rep from "../Functions/rep";
import dataObject from "../Classes/dataObject";
import controlLimits from "../Classes/controlLimits";
import { LimitArgs } from "../Classes/chartObject";

function gLimits(inputData: dataObject): controlLimits {
function gLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
const cl: number = d3.mean(inputData.numerators);
const sigma: number = sqrt(cl * (cl + 1));

Expand Down
7 changes: 5 additions & 2 deletions src/Limit Calculations/i.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { abs } from "../Functions/UnaryFunctions"
import { divide } from "../Functions/BinaryFunctions";
import dataObject from "../Classes/dataObject";
import controlLimits from "../Classes/controlLimits";
import { LimitArgs } from "../Classes/chartObject";

function iLimits(inputData: dataObject): controlLimits {
function iLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
const useRatio: boolean = (inputData.denominators && inputData.denominators.length > 0);
const ratio: number[] = useRatio
? divide(inputData.numerators, inputData.denominators)
Expand All @@ -16,7 +18,8 @@ function iLimits(inputData: dataObject): controlLimits {

const consec_diff: number[] = abs(diff(ratio));
const consec_diff_ulim: number = d3.mean(consec_diff) * 3.267;
const consec_diff_valid: number[] = consec_diff.filter(d => d < consec_diff_ulim);
const outliers_in_limits: boolean = args.inputSettings.spc.outliers_in_limits.value;
const consec_diff_valid: number[] = outliers_in_limits ? consec_diff : consec_diff.filter(d => d < consec_diff_ulim);

const sigma: number = d3.mean(consec_diff_valid) / 1.128;

Expand Down
4 changes: 3 additions & 1 deletion src/Limit Calculations/mr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { abs } from "../Functions/UnaryFunctions"
import { divide } from "../Functions/BinaryFunctions";
import dataObject from "../Classes/dataObject";
import controlLimits from "../Classes/controlLimits";
import { LimitArgs } from "../Classes/chartObject";

function mrLimits(inputData: dataObject): controlLimits {
function mrLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
const useRatio: boolean = (inputData.denominators && inputData.denominators.length > 0);
const ratio: number[] = useRatio
? divide(inputData.numerators, inputData.denominators)
Expand Down
4 changes: 3 additions & 1 deletion src/Limit Calculations/p.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { subtract, add, divide, multiply } from "../Functions/BinaryFunctions";
import controlLimits from "../Classes/controlLimits";
import dataObject from "../Classes/dataObject";
import truncate from "../Functions/truncate"
import {LimitArgs} from "../Classes/chartObject";

function pLimits(inputData: dataObject): controlLimits {
function pLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
const cl: number = d3.sum(inputData.numerators) / d3.sum(inputData.denominators);
const sigma: number[] = sqrt(divide(cl * (1 - cl), inputData.denominators));

Expand Down
7 changes: 5 additions & 2 deletions src/Limit Calculations/pprime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ import { subtract, add, divide, multiply } from "../Functions/BinaryFunctions";
import controlLimits from "../Classes/controlLimits";
import dataObject from "../Classes/dataObject";
import truncate from "../Functions/truncate";
import {LimitArgs} from "../Classes/chartObject";

function pprimeLimits(inputData: dataObject): controlLimits {
function pprimeLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
const val: number[] = divide(inputData.numerators, inputData.denominators);
const cl: number = d3.sum(inputData.numerators) / d3.sum(inputData.denominators);
const sd: number[] = sqrt(divide(cl * (1 - cl), inputData.denominators));
const zscore: number[] = divide(subtract(val, cl), sd);

const consec_diff: number[] = abs(diff(zscore));
const consec_diff_ulim: number = d3.mean(consec_diff) * 3.267;
const consec_diff_valid: number[] = consec_diff.filter(d => d < consec_diff_ulim);
const outliers_in_limits: boolean = args.inputSettings.spc.outliers_in_limits.value;
const consec_diff_valid: number[] = outliers_in_limits ? consec_diff : consec_diff.filter(d => d < consec_diff_ulim);
const sigma: number[] = multiply(sd, d3.mean(consec_diff_valid) / 1.128);

return new controlLimits({
Expand Down
4 changes: 3 additions & 1 deletion src/Limit Calculations/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import rep from "../Functions/rep";
import { divide } from "../Functions/BinaryFunctions";
import controlLimits from "../Classes/controlLimits";
import dataObject from "../Classes/dataObject";
import {LimitArgs} from "../Classes/chartObject";

function runLimits(inputData: dataObject): controlLimits {
function runLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
const useRatio: boolean = (inputData.denominators && inputData.denominators.length > 0);
const ratio: number[] = useRatio
? divide(inputData.numerators, inputData.denominators)
Expand Down
4 changes: 3 additions & 1 deletion src/Limit Calculations/s.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { sqrt } from "../Functions/UnaryFunctions";
import { subtract, pow, multiply } from "../Functions/BinaryFunctions";
import controlLimits from "../Classes/controlLimits";
import dataObject from "../Classes/dataObject";
import {LimitArgs} from "../Classes/chartObject";

function sLimits(inputData: dataObject): controlLimits {
function sLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
const group_sd: number[] = inputData.numerators;
const count_per_group: number[] = inputData.denominators;

Expand Down
12 changes: 7 additions & 5 deletions src/Limit Calculations/t.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import { pow } from "../Functions/BinaryFunctions";
import controlLimits from "../Classes/controlLimits";
import dataObject from "../Classes/dataObject";
import truncate from "../Functions/truncate";
import {LimitArgs} from "../Classes/chartObject";

function tLimits(inputData: dataObject): controlLimits {
function tLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
const val: number[] = pow(inputData.numerators, 1 / 3.6);
const inputDataCopy = inputData;
inputDataCopy.numerators = val;
inputDataCopy.denominators = null;
const limits: controlLimits = iLimits(inputDataCopy);
const argsDataCopy: LimitArgs = args;
argsDataCopy.inputData.numerators = val;
argsDataCopy.inputData.denominators = null;
const limits: controlLimits = iLimits(argsDataCopy);
limits.targets = pow(limits.targets, 3.6);
limits.values = pow(limits.values, 3.6);
limits.ll99 = truncate(pow(limits.ll99, 3.6), {lower: 0});
Expand Down
4 changes: 3 additions & 1 deletion src/Limit Calculations/u.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { subtract, add, divide, multiply } from "../Functions/BinaryFunctions";
import controlLimits from "../Classes/controlLimits";
import dataObject from "../Classes/dataObject";
import truncate from "../Functions/truncate";
import {LimitArgs} from "../Classes/chartObject";

function uLimits(inputData: dataObject): controlLimits {
function uLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
const cl: number = divide(d3.sum(inputData.numerators),d3.sum(inputData.denominators));
const sigma: number[] = sqrt(divide(cl,inputData.denominators));

Expand Down
7 changes: 5 additions & 2 deletions src/Limit Calculations/uprime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ import { subtract, add, divide, multiply } from "../Functions/BinaryFunctions";
import controlLimits from "../Classes/controlLimits";
import dataObject from "../Classes/dataObject";
import truncate from "../Functions/truncate";
import {LimitArgs} from "../Classes/chartObject";

function uprimeLimits(inputData: dataObject): controlLimits {
function uprimeLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
const val: number[] = divide(inputData.numerators, inputData.denominators);
const cl: number = d3.sum(inputData.numerators) / d3.sum(inputData.denominators);
const sd: number[] = sqrt(divide(cl,inputData.denominators));
const zscore: number[] = divide(subtract(val,cl), sd);

const consec_diff: number[] = abs(diff(zscore));
const consec_diff_ulim: number = d3.mean(consec_diff) * 3.267;
const consec_diff_valid: number[] = consec_diff.filter(d => d < consec_diff_ulim);
const outliers_in_limits: boolean = args.inputSettings.spc.outliers_in_limits.value;
const consec_diff_valid: number[] = outliers_in_limits ? consec_diff : consec_diff.filter(d => d < consec_diff_ulim);
const sigma: number[] = multiply(sd, d3.mean(consec_diff_valid) / 1.128);

return new controlLimits({
Expand Down
4 changes: 3 additions & 1 deletion src/Limit Calculations/xbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { sqrt } from "../Functions/UnaryFunctions"
import { pow, subtract, add, multiply, divide } from "../Functions/BinaryFunctions";
import controlLimits from "../Classes/controlLimits";
import dataObject from "../Classes/dataObject";
import {LimitArgs} from "../Classes/chartObject";

function xbarLimits(inputData: dataObject): controlLimits {
function xbarLimits(args: LimitArgs): controlLimits {
const inputData: dataObject = args.inputData;
// Calculate number of observations in each group
const count_per_group: number[] = inputData.denominators;

Expand Down
2 changes: 1 addition & 1 deletion src/visual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ export class Visual implements IVisual {
objectName: "split_indexes_storage",
selector: undefined,
properties: {
split_indexes: JSON.stringify(this.viewModel.splitIndexes)
split_indexes: this.viewModel.splitIndexes ? JSON.stringify(this.viewModel.splitIndexes) : JSON.stringify(new Array<number>())
}
}

Expand Down

0 comments on commit 85c184a

Please sign in to comment.