Skip to content

Commit

Permalink
Merge pull request #277 from AUS-DOH-Safety-and-Quality/i-chart-medians
Browse files Browse the repository at this point in the history
Add i-chart with median centerline and median moving-range limits
  • Loading branch information
andrjohns authored Apr 5, 2024
2 parents 327f76e + bfa7005 commit cf205f7
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 42 deletions.
25 changes: 13 additions & 12 deletions capabilities.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,19 @@
"displayName": "Chart Type",
"type" : {
"enumeration" : [
{ "displayName" : "run - Run Chart", "value" : "run" },
{ "displayName" : "i - Individual Measurements", "value" : "i" },
{ "displayName" : "mr - Moving Range of Individual Measurements", "value" : "mr" },
{ "displayName" : "p - Proportions", "value" : "p" },
{ "displayName" : "p prime - Proportions: Large-Sample Corrected", "value" : "pp" },
{ "displayName" : "u - Rates", "value" : "u" },
{ "displayName" : "u prime - Rates: Large-Sample Correction", "value" : "up" },
{ "displayName" : "c - Counts", "value" : "c" },
{ "displayName" : "xbar - Sample Means", "value" : "xbar" },
{ "displayName" : "s - Sample SDs", "value" : "s" },
{ "displayName" : "g - Number of Non-Events Between Events", "value" : "g" },
{ "displayName" : "t - Time Between Events", "value" : "t" }
{ "displayName" : "run - Run Chart", "value" : "run" },
{ "displayName" : "i - Individual Measurements", "value" : "i" },
{ "displayName" : "i_m - Individual Measurements (Median centerline)", "value" : "i_m" },
{ "displayName" : "mr - Moving Range of Individual Measurements", "value" : "mr" },
{ "displayName" : "p - Proportions", "value" : "p" },
{ "displayName" : "p prime - Proportions: Large-Sample Corrected", "value" : "pp" },
{ "displayName" : "u - Rates", "value" : "u" },
{ "displayName" : "u prime - Rates: Large-Sample Correction", "value" : "up" },
{ "displayName" : "c - Counts", "value" : "c" },
{ "displayName" : "xbar - Sample Means", "value" : "xbar" },
{ "displayName" : "s - Sample SDs", "value" : "s" },
{ "displayName" : "g - Number of Non-Events Between Events", "value" : "g" },
{ "displayName" : "t - Time Between Events", "value" : "t" }
]
}
},
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.3.2",
"version":"1.4.3.3",
"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
28 changes: 24 additions & 4 deletions src/Classes/derivedSettingsClass.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
import {defaultSettingsType} from "./settingsClass"
import { defaultSettingsType } from "./settingsClass"

const valueNames: Record<string, string> = {
"i": "Observation",
"i_m": "Observation",
"c": "Count",
"t": "Time",
"xbar": "Group Mean",
"s": "Group SD",
"g": "Non-Events",
"run": "Observation",
"mr": "Moving Range",
"p": "Proportion",
"pp": "Proportion",
"u": "Rate",
"up": "Rate"
}

export default class derivedSettingsClass {
multiplier: number
Expand All @@ -9,7 +25,9 @@ export default class derivedSettingsClass {
numerator_non_negative: boolean,
numerator_leq_denominator: boolean,
has_control_limits: boolean,
needs_sd: boolean
needs_sd: boolean,
integer_num_den: boolean,
value_name: string
}

update(inputSettings: defaultSettingsType) {
Expand All @@ -35,11 +53,13 @@ export default class derivedSettingsClass {

this.chart_type_props = {
needs_denominator: ["p", "pp", "u", "up", "xbar", "s"].includes(chartType),
denominator_optional: ["i", "run", "mr"].includes(chartType),
denominator_optional: ["i", "i_m", "run", "mr"].includes(chartType),
numerator_non_negative: ["p", "pp", "u", "up", "s", "c", "g", "t"].includes(chartType),
numerator_leq_denominator: ["p", "pp", "u", "up"].includes(chartType),
has_control_limits: !(["run"].includes(chartType)),
needs_sd: ["xbar"].includes(chartType)
needs_sd: ["xbar"].includes(chartType),
integer_num_den: ["c", "p", "pp"].includes(chartType),
value_name: valueNames[chartType]
}

this.multiplier = multiplier
Expand Down
3 changes: 2 additions & 1 deletion src/Classes/viewModelClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ export default class viewModelClass {
this.inputData.limitInputArgs.keys[i].id)
.createSelectionId(),
highlighted: this.inputData.highlights?.[index] != null,
tooltip: buildTooltip(i, this.controlLimits, this.outliers, this.inputData, this.inputSettings.settings, this.inputSettings.derivedSettings)
tooltip: buildTooltip(i, this.controlLimits, this.outliers, this.inputData,
this.inputSettings.settings, this.inputSettings.derivedSettings)
})
this.tickLabels.push({x: index, label: this.controlLimits.keys[i].label});
}
Expand Down
25 changes: 3 additions & 22 deletions src/Functions/buildTooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,6 @@ type VisualTooltipDataItem = powerbi.extensibility.VisualTooltipDataItem;
import type { controlLimitsObject, defaultSettingsType, derivedSettingsClass, outliersObject } from "../Classes";
import type { dataObject } from "./extractInputData";

const valueNames: Record<string, string> = {
"i": "Observation",
"c": "Count",
"t": "Time",
"xbar": "Group Mean",
"s": "Group SD",
"g": "Non-Events",
"run": "Observation",
"mr": "Moving Range",
"p": "Proportion",
"pp": "Proportion",
"u": "Rate",
"up": "Rate"
}

const integerParams: string[] = ["c", "p", "pp"];

/**
* Builds the tooltip data for a specific index in the chart.
*
Expand All @@ -39,7 +22,6 @@ export default function buildTooltip(index: number,
inputData: dataObject,
inputSettings: defaultSettingsType,
derivedSettings: derivedSettingsClass): VisualTooltipDataItem[] {
const chart_type: string = inputSettings.spc.chart_type;
const numerator: number = controlLimits.numerators?.[index];
const denominator: number = controlLimits.denominators?.[index];
const target: number = controlLimits.targets[index];
Expand All @@ -61,7 +43,6 @@ export default function buildTooltip(index: number,
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);

const sig_figs: number = inputSettings.spc.sig_figs;
const tooltip: VisualTooltipDataItem[] = new Array<VisualTooltipDataItem>();
Expand All @@ -72,20 +53,20 @@ export default function buildTooltip(index: number,
if (inputSettings.spc.ttip_show_value) {
const ttip_label_value: string = inputSettings.spc.ttip_label_value;
tooltip.push({
displayName: ttip_label_value === "Automatic" ? valueNames[chart_type] : ttip_label_value,
displayName: ttip_label_value === "Automatic" ? derivedSettings.chart_type_props.value_name : ttip_label_value,
value: (controlLimits.values[index]).toFixed(sig_figs) + suffix
})
}
if(inputSettings.spc.ttip_show_numerator && !(numerator === null || numerator === undefined)) {
tooltip.push({
displayName: inputSettings.spc.ttip_label_numerator,
value: (numerator).toFixed(intNumDen ? 0 : sig_figs)
value: (numerator).toFixed(derivedSettings.chart_type_props.integer_num_den ? 0 : sig_figs)
})
}
if(inputSettings.spc.ttip_show_denominator && !(denominator === null || denominator === undefined)) {
tooltip.push({
displayName: inputSettings.spc.ttip_label_denominator,
value: (denominator).toFixed(intNumDen ? 0 : sig_figs)
value: (denominator).toFixed(derivedSettings.chart_type_props.integer_num_den ? 0 : sig_figs)
})
}
if (inputSettings.lines.show_specification && inputSettings.lines.ttip_show_specification) {
Expand Down
32 changes: 32 additions & 0 deletions src/Limit Calculations/i_m.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { abs, diff, divide, rep, median } from "../Functions";
import { type controlLimitsObject, type controlLimitsArgs } from "../Classes";

export default function imLimits(args: controlLimitsArgs): controlLimitsObject {
const useRatio: boolean = (args.denominators && args.denominators.length > 0);
const ratio: number[] = useRatio
? divide(args.numerators, args.denominators)
: args.numerators;

const cl: number = median(ratio);

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

const sigma: number = median(consec_diff_valid) / 1.128;

return {
keys: args.keys,
values: ratio.map(d => isNaN(d) ? 0 : d),
numerators: useRatio ? args.numerators : undefined,
denominators: useRatio ? args.denominators : undefined,
targets: rep(cl, args.keys.length),
ll99: rep(cl - 3 * sigma, args.keys.length),
ll95: rep(cl - 2 * sigma, args.keys.length),
ll68: rep(cl - 1 * sigma, args.keys.length),
ul68: rep(cl + 1 * sigma, args.keys.length),
ul95: rep(cl + 2 * sigma, args.keys.length),
ul99: rep(cl + 3 * sigma, args.keys.length)
};
}
2 changes: 1 addition & 1 deletion src/Limit Calculations/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { default as c } from "./c"
export { default as g } from "./g"
export { default as i } from "./i"
export { default as i_m } from "./i_m"
export { default as mr } from "./mr"
export { default as p } from "./p"
export { default as pp } from "./pprime"
Expand All @@ -11,4 +12,3 @@ export { default as u } from "./u"
export { default as up } from "./uprime"
export { default as xbar } from "./xbar"
export { default as run } from "./run"

2 changes: 1 addition & 1 deletion src/defaultSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const defaultSettings = {
right_padding: { default: 10 }
},
spc: {
chart_type: { default: "i", valid: ["run", "i", "mr", "p", "pp", "u", "up", "c", "xbar", "s", "g", "t"] },
chart_type: { default: "i", valid: ["run", "i", "i_m", "mr", "p", "pp", "u", "up", "c", "xbar", "s", "g", "t"] },
outliers_in_limits: { default: false },
multiplier: { default: 1, valid: { numberRange: { min: 0 } } },
sig_figs: { default: 2, valid: { numberRange: { min: 0, max: 20 } } },
Expand Down

0 comments on commit cf205f7

Please sign in to comment.