diff --git a/capabilities.json b/capabilities.json index 0422900..71cf09f 100644 --- a/capabilities.json +++ b/capabilities.json @@ -423,6 +423,10 @@ "displayName": "Show Alt. Target Line", "type" : { "bool" : true } }, + "show_specification": { + "displayName": "Show Specification Lines", + "type" : { "bool" : true } + }, "width_99": { "displayName": "99.8% Line Width", "type": { "numeric": true } @@ -447,6 +451,10 @@ "displayName": "Alt. Target Line Width", "type": { "numeric": true } }, + "width_specification": { + "displayName": "Specification Line Width", + "type": { "numeric": true } + }, "type_99": { "displayName": "99.8% Line Type", "type": { @@ -507,6 +515,16 @@ ] } }, + "type_specification": { + "displayName": "Specification Line Type", + "type": { + "enumeration" : [ + { "displayName" : "Solid", "value" : "10 0" }, + { "displayName" : "Dashed", "value" : "10 10" }, + { "displayName" : "Dotted", "value" : "2 5" } + ] + } + }, "colour_99":{ "displayName": "99.8% Line Colour", "type": { "fill": { "solid": { "color": true } } } @@ -531,6 +549,10 @@ "displayName": "Alt. Target Line Colour", "type": { "fill": { "solid": { "color": true } } } }, + "colour_specification":{ + "displayName": "Specification Line Colour", + "type": { "fill": { "solid": { "color": true } } } + }, "ttip_show_99": { "displayName": "Show value in tooltip", "type" : { "bool" : true } @@ -551,6 +573,10 @@ "displayName": "Show value in tooltip", "type" : { "bool" : true } }, + "ttip_show_specification": { + "displayName": "Show value in tooltip", + "type" : { "bool" : true } + }, "ttip_label_99": { "displayName": "Tooltip Label", "type": { "text": true } @@ -571,9 +597,21 @@ "displayName": "Tooltip Label", "type": { "text": true } }, + "ttip_label_specification": { + "displayName": "Tooltip Label", + "type": { "text": true } + }, "alt_target": { "displayName": "Additional Target Value:", "type": { "numeric": true } + }, + "specification_upper": { + "displayName": "Upper Specification Limit:", + "type": { "numeric": true } + }, + "specification_lower": { + "displayName": "Lower Specification Limit:", + "type": { "numeric": true } } } }, diff --git a/pbiviz.json b/pbiviz.json index 098fd0a..3edd3fc 100644 --- a/pbiviz.json +++ b/pbiviz.json @@ -4,7 +4,7 @@ "displayName":"SPC Charts", "guid":"PBISPC", "visualClassName":"Visual", - "version":"1.4.1.4", + "version":"1.4.2.0", "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" diff --git a/src/Classes/viewModelClass.ts b/src/Classes/viewModelClass.ts index c96f7dd..8e694b9 100644 --- a/src/Classes/viewModelClass.ts +++ b/src/Classes/viewModelClass.ts @@ -41,6 +41,8 @@ export type controlLimitsObject = { ul99?: number[]; count?: number[]; alt_targets?: number[]; + speclimits_lower?: number[]; + speclimits_upper?: number[]; }; export type controlLimitsArgs = { @@ -154,6 +156,8 @@ export default class viewModelClass { } this.controlLimits.alt_targets = this.inputData.alt_targets; + this.controlLimits.speclimits_lower = this.inputData.speclimits_lower; + this.controlLimits.speclimits_upper = this.inputData.speclimits_upper; } initialisePlotData(host: IVisualHost): void { @@ -206,6 +210,9 @@ export default class viewModelClass { if (this.inputSettings.settings.lines.show_alt_target) { labels.push("alt_targets"); } + if (this.inputSettings.settings.lines.show_specification) { + labels.push("speclimits_lower", "speclimits_upper"); + } if (this.inputSettings.settings.spc.chart_type !== "run") { if (this.inputSettings.settings.lines.show_99) { labels.push("ll99", "ul99"); @@ -261,6 +268,12 @@ export default class viewModelClass { // Scale limits using provided multiplier const multiplier: number = this.inputSettings.derivedSettings.multiplier; let lines_to_scale: string[] = ["values", "targets"]; + if (this.inputSettings.settings.lines.show_alt_target) { + lines_to_scale = lines_to_scale.concat(["alt_targets"]); + } + if (this.inputSettings.settings.lines.show_specification) { + lines_to_scale = lines_to_scale.concat(["speclimits_lower", "speclimits_upper"]); + } if (this.inputSettings.settings.spc.chart_type !== "run") { lines_to_scale = lines_to_scale.concat(["ll99", "ll95", "ll68", "ul68", "ul95", "ul99"]); diff --git a/src/Functions/buildTooltip.ts b/src/Functions/buildTooltip.ts index 8be1210..5420c38 100644 --- a/src/Functions/buildTooltip.ts +++ b/src/Functions/buildTooltip.ts @@ -44,6 +44,8 @@ export default function buildTooltip(index: number, const denominator: number = controlLimits.denominators?.[index]; const target: number = controlLimits.targets[index]; const alt_target: number = controlLimits?.alt_targets?.[index]; + const speclimits_lower: number = controlLimits?.speclimits_lower?.[index]; + const speclimits_upper: number = controlLimits?.speclimits_upper?.[index]; const limits = { ll99: controlLimits?.ll99?.[index], ll95: controlLimits?.ll95?.[index], @@ -86,6 +88,20 @@ export default function buildTooltip(index: number, value: (denominator).toFixed(intNumDen ? 0 : sig_figs) }) } + if (inputSettings.lines.show_specification && inputSettings.lines.ttip_show_specification) { + if (speclimits_upper !== null && speclimits_upper !== undefined) { + tooltip.push({ + displayName: `Upper ${inputSettings.lines.ttip_label_specification}`, + value: (speclimits_upper).toFixed(sig_figs) + suffix + }) + } + if (speclimits_lower !== null && speclimits_lower !== undefined) { + tooltip.push({ + displayName: `Lower ${inputSettings.lines.ttip_label_specification}`, + value: (speclimits_lower).toFixed(sig_figs) + suffix + }) + } + } if (chart_type !== "run") { ["68", "95", "99"].forEach(limit => { if (inputSettings.lines[`ttip_show_${limit}`] && inputSettings.lines[`show_${limit}`]) { diff --git a/src/Functions/extractInputData.ts b/src/Functions/extractInputData.ts index 15d3dae..ead1cee 100644 --- a/src/Functions/extractInputData.ts +++ b/src/Functions/extractInputData.ts @@ -18,6 +18,8 @@ export type dataObject = { tooltips: VisualTooltipDataItem[][]; warningMessage: string; alt_targets: number[]; + speclimits_lower: number[]; + speclimits_upper: number[]; validationStatus: ValidationT; } @@ -32,6 +34,11 @@ export default function extractInputData(inputView: DataViewCategorical, inputSe const highlights: powerbi.PrimitiveValue[] = inputView.values[0].highlights; const alt_targets: number[] = extractConditionalFormatting(inputView, "lines", inputSettings) .map(d => inputSettings.lines.show_alt_target ? d.alt_target : null); + const speclimits_lower: number[] = extractConditionalFormatting(inputView, "lines", inputSettings) + .map(d => d.show_specification ? d.specification_lower : null); + const speclimits_upper: number[] = extractConditionalFormatting(inputView, "lines", inputSettings) + .map(d => d.show_specification ? d.specification_upper : null); + const inputValidStatus: ValidationT = validateInputData(keys, numerators, denominators, xbar_sds, groupings, inputSettings.spc.chart_type); @@ -47,6 +54,8 @@ export default function extractInputData(inputView: DataViewCategorical, inputSe tooltips: null, warningMessage: inputValidStatus.error, alt_targets: null, + speclimits_lower: null, + speclimits_upper: null, validationStatus: inputValidStatus } } @@ -93,6 +102,8 @@ export default function extractInputData(inputView: DataViewCategorical, inputSe scatter_formatting: extractValues(scatter_cond, valid_ids), warningMessage: removalMessages.length >0 ? removalMessages.join("\n") : "", alt_targets: extractValues(alt_targets, valid_ids), + speclimits_lower: extractValues(speclimits_lower, valid_ids), + speclimits_upper: extractValues(speclimits_upper, valid_ids), validationStatus: inputValidStatus } } diff --git a/src/Functions/getAesthetic.ts b/src/Functions/getAesthetic.ts index f9afc02..0cd1102 100644 --- a/src/Functions/getAesthetic.ts +++ b/src/Functions/getAesthetic.ts @@ -9,7 +9,9 @@ const lineNameMap: Record = { "ul99" : "99", "targets" : "target", "values" : "main", - "alt_targets" : "alt_target" + "alt_targets" : "alt_target", + "speclimits_lower" : "specification", + "speclimits_upper" : "specification" } export default function getAesthetic(type: string, group: string, aesthetic: string, inputSettings: defaultSettingsType): string | number { diff --git a/src/defaultSettings.ts b/src/defaultSettings.ts index e17b806..268ce7d 100644 --- a/src/defaultSettings.ts +++ b/src/defaultSettings.ts @@ -108,35 +108,43 @@ const defaultSettings = { show_main: { default: true }, show_target: { default: true }, show_alt_target: { default: false }, + show_specification: { default: false }, width_99: { default: 2, valid: { numberRange: { min: 0, max: 100 }}}, width_95: { default: 2, valid: { numberRange: { min: 0, max: 100 }}}, width_68: { default: 2, valid: { numberRange: { min: 0, max: 100 }}}, width_main: { default: 1, valid: { numberRange: { min: 0, max: 100 }}}, width_target: { default: 1.5, valid: { numberRange: { min: 0, max: 100 }}}, width_alt_target: { default: 1.5, valid: { numberRange: { min: 0, max: 100 }}}, + width_specification: { default: 2, valid: { numberRange: { min: 0, max: 100 }}}, type_99: { default: "10 10", valid: validLineTypes}, type_95: { default: "2 5", valid: validLineTypes}, type_68: { default: "2 5", valid: validLineTypes}, type_main: { default: "10 0", valid: validLineTypes}, type_target: { default: "10 0", valid: validLineTypes}, type_alt_target: { default: "10 0", valid: validLineTypes}, + type_specification: { default: "10 10", valid: validLineTypes}, colour_99: { default: "#6495ED" }, colour_95: { default: "#6495ED" }, colour_68: { default: "#6495ED" }, colour_main: { default: "#000000" }, colour_target: { default: "#000000" }, colour_alt_target: { default: "#000000" }, + colour_specification: { default: "#6495ED" }, ttip_show_99: { default: true }, ttip_show_95: { default: false }, ttip_show_68: { default: false }, ttip_show_target: { default: true }, ttip_show_alt_target: { default: true }, + ttip_show_specification: { default: true }, ttip_label_99: { default: "99% Limit" }, ttip_label_95: { default: "95% Limit" }, ttip_label_68: { default: "68% Limit" }, ttip_label_target: { default: "Centerline" }, - ttip_label_alt_target: { default: "Additional Target" }, - alt_target: { default: null } + ttip_label_alt_target: { default: "Specification Limit" }, + ttip_label_specification: { default: "Specification Limit" }, + alt_target: { default: null }, + specification_upper: { default: null }, + specification_lower: { default: null } }, x_axis: { xlimit_colour: { default: "#000000" }, @@ -202,7 +210,8 @@ export const settingsPaneGroupings = { "Alt. Target": ["show_alt_target", "alt_target", "width_alt_target", "type_alt_target", "colour_alt_target", "ttip_show_alt_target", "ttip_label_alt_target"], "68% Limits": ["show_68", "width_68", "type_68", "colour_68", "ttip_show_68", "ttip_label_68"], "95% Limits": ["show_95", "width_95", "type_95", "colour_95", "ttip_show_95", "ttip_label_95"], - "99% Limits": ["show_99", "width_99", "type_99", "colour_99", "ttip_show_99", "ttip_label_99"] + "99% Limits": ["show_99", "width_99", "type_99", "colour_99", "ttip_show_99", "ttip_label_99"], + "Specification Limits": ["show_specification", "specification_upper", "specification_lower", "width_specification", "type_specification", "colour_specification", "ttip_show_specification", "ttip_label_specification"] }, x_axis: { "Axis": ["xlimit_colour", "xlimit_l", "xlimit_u"], @@ -263,6 +272,10 @@ export const settingsPaneToggles = { "99% Limits": { "show_99": ["width_99", "type_99", "colour_99", "ttip_show_99", "ttip_label_99"], "ttip_show_99": ["ttip_label_99"] + }, + "Specification Limits": { + "show_specification": ["specification_upper", "specification_lower", "width_specification", "type_specification", "colour_specification", "ttip_show_specification", "ttip_label_specification"], + "ttip_show_specification": ["ttip_label_specification"] } } }