Skip to content

Commit

Permalink
Merge pull request #247 from AUS-DOH-Safety-and-Quality/limit-flag-op…
Browse files Browse the repository at this point in the history
…tions

Fix two-in-three series highlighting, add option for limit to use when flagging astronomical points and two-in-three
  • Loading branch information
andrjohns authored Feb 6, 2024
2 parents 55c5d87 + 5b74720 commit 1e6b759
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 49 deletions.
28 changes: 24 additions & 4 deletions capabilities.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,20 @@
]
}
},
"flag_series": {
"displayName": "Highlight all in Pattern",
"type" : { "bool" : true }
},
"astronomical": {
"displayName": "Highlight Astronomical Points",
"type" : { "bool" : true }
},
"astronomical_limit": {
"displayName": "Limit for Astronomical Points",
"type": {
"enumeration" : [
{ "displayName" : "1 Sigma", "value" : "1 Sigma" },
{ "displayName" : "2 Sigma", "value" : "2 Sigma" },
{ "displayName" : "3 Sigma", "value" : "3 Sigma" }
]
}
},
"ast_colour_improvement":{
"displayName": "Imp. Ast. Colour",
"type": { "fill": { "solid": { "color": true } } }
Expand Down Expand Up @@ -209,6 +215,20 @@
"displayName": "Highlight Two-in-Three",
"type" : { "bool" : true }
},
"two_in_three_highlight_series": {
"displayName": "Highlight all in Pattern",
"type" : { "bool" : true }
},
"two_in_three_limit": {
"displayName": "Warning Limit for Two-in-Three",
"type": {
"enumeration" : [
{ "displayName" : "1 Sigma", "value" : "1 Sigma" },
{ "displayName" : "2 Sigma", "value" : "2 Sigma" },
{ "displayName" : "3 Sigma", "value" : "3 Sigma" }
]
}
},
"twointhree_colour_improvement":{
"displayName": "Imp. Two-in-Three Colour",
"type": { "fill": { "solid": { "color": true } } }
Expand Down
2 changes: 1 addition & 1 deletion pbiviz.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"displayName":"SPC Charts",
"guid":"PBISPC",
"visualClassName":"Visual",
"version":"1.4.1.1",
"version":"1.4.1.2",
"description":"A PowerBI custom visual for SPC charts",
"supportUrl":"https://github.com/AUS-DOH-Safety-and-Quality/PowerBI-SPC",
"gitHubUrl":"https://github.com/AUS-DOH-Safety-and-Quality/PowerBI-SPC"
Expand Down
25 changes: 16 additions & 9 deletions src/Classes/viewModelClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,6 @@ export default class viewModelClass {
flagOutliers() {
const process_flag_type: string = this.inputSettings.settings.outliers.process_flag_type;
const improvement_direction: string = this.inputSettings.settings.outliers.improvement_direction;
const flag_series: boolean = this.inputSettings.settings.outliers.flag_series;
const trend_n: number = this.inputSettings.settings.outliers.trend_n;
const shift_n: number = this.inputSettings.settings.outliers.shift_n;
this.outliers = {
Expand All @@ -293,27 +292,35 @@ export default class viewModelClass {
const end: number = this.groupStartEndIndexes[i][1];
const group_values: number[] = this.controlLimits.values.slice(start, end);
const group_targets: number[] = this.controlLimits.targets.slice(start, end);
const group_ll99: number[] = this.controlLimits?.ll99?.slice(start, end);
const group_ll95: number[] = this.controlLimits?.ll95?.slice(start, end);
const group_ul95: number[] = this.controlLimits?.ul95?.slice(start, end);
const group_ul99: number[] = this.controlLimits?.ul99?.slice(start, end);

if (this.inputSettings.settings.spc.chart_type !== "run") {
const limit_map: Record<string, number> = {
"1 Sigma": 68,
"2 Sigma": 95,
"3 Sigma": 99
};
if (this.inputSettings.settings.outliers.astronomical) {
astronomical(group_values, group_ll99, group_ul99)
const ast_limit: number = limit_map[this.inputSettings.settings.outliers.astronomical_limit];
const lower_limits: number[] = this.controlLimits?.[`ll${ast_limit}`]?.slice(start, end);
const upper_limits: number[] = this.controlLimits?.[`ul${ast_limit}`]?.slice(start, end);
astronomical(group_values, lower_limits, upper_limits)
.forEach((flag, idx) => this.outliers.astpoint[start + idx] = flag)
}
if (this.inputSettings.settings.outliers.two_in_three) {
twoInThree(group_values, group_ll95, group_ul95, flag_series)
const highlight_series: boolean = this.inputSettings.settings.outliers.two_in_three_highlight_series;
const two_in_three_limit: number = limit_map[this.inputSettings.settings.outliers.two_in_three_limit];
const lower_warn_limits: number[] = this.controlLimits?.[`ll${two_in_three_limit}`]?.slice(start, end);
const upper_warn_limits: number[] = this.controlLimits?.[`ul${two_in_three_limit}`]?.slice(start, end);
twoInThree(group_values, lower_warn_limits, upper_warn_limits, highlight_series)
.forEach((flag, idx) => this.outliers.two_in_three[start + idx] = flag)
}
}
if (this.inputSettings.settings.outliers.trend) {
trend(group_values, trend_n, flag_series)
trend(group_values, trend_n)
.forEach((flag, idx) => this.outliers.trend[start + idx] = flag)
}
if (this.inputSettings.settings.outliers.shift) {
shift(group_values, group_targets, shift_n, flag_series)
shift(group_values, group_targets, shift_n)
.forEach((flag, idx) => this.outliers.shift[start + idx] = flag)
}
}
Expand Down
23 changes: 21 additions & 2 deletions src/Functions/buildTooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const integerParams: string[] = ["c", "p", "pp"];
* @param derivedSettings - The derived settings object.
* @returns An array of VisualTooltipDataItem objects representing the tooltip data.
*/
// ESLint errors due to number of lines in function, but would reduce readability to separate further
/* eslint-disable max-lines-per-function */
export default function buildTooltip(index: number,
controlLimits: controlLimitsObject,
outliers: outliersObject,
Expand All @@ -54,6 +56,8 @@ export default function buildTooltip(index: number,
const trend: string = outliers.trend[index];
const shift: string = outliers.shift[index];
const two_in_three: string = outliers.two_in_three[index];
const ast_limit: string = inputSettings.outliers.astronomical_limit;
const two_in_three_limit: string = inputSettings.outliers.two_in_three_limit;
const suffix: string = derivedSettings.percentLabels ? "%" : "";
const intNumDen: boolean = integerParams.includes(chart_type);

Expand Down Expand Up @@ -117,10 +121,24 @@ export default function buildTooltip(index: number,

if (astpoint !== "none" || trend !== "none" || shift !== "none" || two_in_three !== "none") {
const patterns: string[] = new Array<string>();
if (astpoint !== "none") { patterns.push("Astronomical Point") }
if (astpoint !== "none") {
// Note if flagged according to non-default limit
let flag_text: string = "Astronomical Point";
if (ast_limit !== "3 Sigma") {
flag_text = `${flag_text} (${ast_limit})`;
}
patterns.push(flag_text)
}
if (trend !== "none") { patterns.push("Trend") }
if (shift !== "none") { patterns.push("Shift") }
if (two_in_three !== "none") { patterns.push("Two-in-Three") }
if (two_in_three !== "none") {
// Note if flagged according to non-default limit
let flag_text: string = "Two-in-Three";
if (two_in_three_limit !== "2 Sigma") {
flag_text = `${flag_text} (${two_in_three_limit})`;
}
patterns.push(flag_text)
}
tooltip.push({
displayName: "Pattern(s)",
value: patterns.join("\n")
Expand All @@ -133,3 +151,4 @@ export default function buildTooltip(index: number,

return tooltip;
}
/* eslint-enable max-lines-per-function */
13 changes: 6 additions & 7 deletions src/Outlier Flagging/shift.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { abs, sum } from "../Functions";

export default function shift(val: number[], targets: number[], n: number, flag_series: boolean): string[] {
export default function shift(val: number[], targets: number[], n: number): string[] {
const lagged_sign: number[] = val.map((d, i) => {
return Math.sign(d - targets[i]);
});
Expand All @@ -14,12 +14,11 @@ export default function shift(val: number[], targets: number[], n: number, flag_
return "none";
}
})
if (flag_series) {
for (let i: number = 0; i < shift_detected.length; i++) {
if (shift_detected[i] !== "none") {
for (let j: number = (i - 1); j >= (i - (n - 1)); j--) {
shift_detected[j] = shift_detected[i];
}

for (let i: number = 0; i < shift_detected.length; i++) {
if (shift_detected[i] !== "none") {
for (let j: number = (i - 1); j >= (i - (n - 1)); j--) {
shift_detected[j] = shift_detected[i];
}
}
}
Expand Down
12 changes: 5 additions & 7 deletions src/Outlier Flagging/trend.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { abs, sum } from "../Functions";

export default function trend(val: number[], n: number, flag_series: boolean): string[] {
export default function trend(val: number[], n: number): string[] {
const lagged_sign: number[] = val.map((d, i) => {
return (i == 0) ? i : Math.sign(d - val[i - 1]);
});
Expand All @@ -15,12 +15,10 @@ export default function trend(val: number[], n: number, flag_series: boolean): s
}
})

if (flag_series) {
for (let i: number = 0; i < trend_detected.length; i++) {
if (trend_detected[i] !== "none") {
for (let j: number = (i - 1); j >= (i - (n - 1)); j--) {
trend_detected[j] = trend_detected[i];
}
for (let i: number = 0; i < trend_detected.length; i++) {
if (trend_detected[i] !== "none") {
for (let j: number = (i - 1); j >= (i - (n - 1)); j--) {
trend_detected[j] = trend_detected[i];
}
}
}
Expand Down
22 changes: 10 additions & 12 deletions src/Outlier Flagging/twoInThree.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { abs, sum } from "../Functions";

export default function twoInThree(val: number[], ll95: number[], ul95: number[], flag_series: boolean): string[] {
export default function twoInThree(val: number[], ll95: number[], ul95: number[], highlight_series: boolean): string[] {
const outside95: number[] = val.map((d, i) => {
return d > ul95[i] ? 1 : (d < ll95[i] ? -1 : 0);
});
Expand All @@ -15,19 +15,17 @@ export default function twoInThree(val: number[], ll95: number[], ul95: number[]
}
})

if (flag_series) {
for (let i: number = 0; i < two_in_three_detected.length; i++) {
if (two_in_three_detected[i] !== "none") {
for (let j: number = (i - 1); j >= (i - 2); j--) {
// Only highlight points exceeding the 95% limits
if (outside95[j] !== 0) {
two_in_three_detected[j] = two_in_three_detected[i];
}
}
if (outside95[i] === 0) {
two_in_three_detected[i] = "none";
for (let i: number = 0; i < two_in_three_detected.length; i++) {
if (two_in_three_detected[i] !== "none") {
for (let j: number = (i - 1); j >= (i - 2); j--) {
// Only highlight points exceeding the 95% limits (unless requested)
if (outside95[j] !== 0 || highlight_series) {
two_in_three_detected[j] = two_in_three_detected[i];
}
}
if (outside95[i] === 0 && !highlight_series) {
two_in_three_detected[i] = "none";
}
}
}

Expand Down
16 changes: 9 additions & 7 deletions src/defaultSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ const defaultSettings = {
outliers: {
process_flag_type: "both",
improvement_direction: "increase",
flag_series: true,
astronomical: false,
astronomical_limit: "3 Sigma",
ast_colour_improvement: "#00B0F0",
ast_colour_deterioration: "#E46C0A",
ast_colour_neutral_low: "#490092",
Expand All @@ -44,6 +44,8 @@ const defaultSettings = {
trend_colour_neutral_low: "#490092",
trend_colour_neutral_high: "#490092",
two_in_three: false,
two_in_three_highlight_series: false,
two_in_three_limit: "2 Sigma",
twointhree_colour_improvement: "#00B0F0",
twointhree_colour_deterioration: "#E46C0A",
twointhree_colour_neutral_low: "#490092",
Expand Down Expand Up @@ -144,10 +146,10 @@ const defaultSettings = {

export const settingsPaneGroupings = {
outliers: {
"Astronomical Points": ["process_flag_type", "improvement_direction", "flag_series", "astronomical", "ast_colour_improvement", "ast_colour_deterioration", "ast_colour_neutral_low", "ast_colour_neutral_high"],
"Shifts": ["process_flag_type", "improvement_direction", "flag_series", "shift", "shift_n", "shift_colour_improvement", "shift_colour_deterioration", "shift_colour_neutral_low", "shift_colour_neutral_high"],
"Trends": ["process_flag_type", "improvement_direction", "flag_series", "trend", "trend_n", "trend_colour_improvement", "trend_colour_deterioration", "trend_colour_neutral_low", "trend_colour_neutral_high"],
"Two-In-Three": ["process_flag_type", "improvement_direction", "flag_series", "two_in_three", "twointhree_colour_improvement", "twointhree_colour_deterioration", "twointhree_colour_neutral_low", "twointhree_colour_neutral_high"]
"Astronomical Points": ["process_flag_type", "improvement_direction", "astronomical", "astronomical_limit", "ast_colour_improvement", "ast_colour_deterioration", "ast_colour_neutral_low", "ast_colour_neutral_high"],
"Shifts": ["process_flag_type", "improvement_direction", "shift", "shift_n", "shift_colour_improvement", "shift_colour_deterioration", "shift_colour_neutral_low", "shift_colour_neutral_high"],
"Trends": ["process_flag_type", "improvement_direction", "trend", "trend_n", "trend_colour_improvement", "trend_colour_deterioration", "trend_colour_neutral_low", "trend_colour_neutral_high"],
"Two-In-Three": ["process_flag_type", "improvement_direction", "two_in_three", "two_in_three_highlight_series", "two_in_three_limit", "twointhree_colour_improvement", "twointhree_colour_deterioration", "twointhree_colour_neutral_low", "twointhree_colour_neutral_high"]
},
lines: {
"Main": ["show_main", "width_main", "type_main", "colour_main"],
Expand Down Expand Up @@ -177,7 +179,7 @@ export const settingsPaneToggles = {
},
outliers: {
"Astronomical Points": {
"astronomical": ["ast_colour_improvement", "ast_colour_deterioration", "ast_colour_neutral_low", "ast_colour_neutral_high"]
"astronomical": ["astronomical_limit", "ast_colour_improvement", "ast_colour_deterioration", "ast_colour_neutral_low", "ast_colour_neutral_high"]
},
"Shifts": {
"shift": ["shift_n", "shift_colour_improvement", "shift_colour_deterioration", "shift_colour_neutral_low", "shift_colour_neutral_high"]
Expand All @@ -186,7 +188,7 @@ export const settingsPaneToggles = {
"trend": ["trend_n", "trend_colour_improvement", "trend_colour_deterioration", "trend_colour_neutral_low", "trend_colour_neutral_high"]
},
"Two-In-Three": {
"two_in_three": ["twointhree_colour_improvement", "twointhree_colour_deterioration", "twointhree_colour_neutral_low", "twointhree_colour_neutral_high"]
"two_in_three": ["two_in_three_limit", "two_in_three_highlight_series", "twointhree_colour_improvement", "twointhree_colour_deterioration", "twointhree_colour_neutral_low", "twointhree_colour_neutral_high"]
}
},
nhs_icons: {
Expand Down

0 comments on commit 1e6b759

Please sign in to comment.