Skip to content

Commit

Permalink
Centralise determination and management of chart type properties
Browse files Browse the repository at this point in the history
  • Loading branch information
andrjohns committed Apr 5, 2024
1 parent c361bed commit 1f945ba
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 36 deletions.
17 changes: 17 additions & 0 deletions src/Classes/derivedSettingsClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ import {defaultSettingsType} from "./settingsClass"
export default class derivedSettingsClass {
multiplier: number
percentLabels: boolean
chart_type_props: {
needs_denominator: boolean,
denominator_optional: boolean,
numerator_non_negative: boolean,
numerator_leq_denominator: boolean,
has_control_limits: boolean,
needs_sd: boolean
}

update(inputSettings: defaultSettingsType) {
const chartType: string = inputSettings.spc.chart_type;
Expand All @@ -25,6 +33,15 @@ export default class derivedSettingsClass {
percentLabels = percentSettingString === "Yes";
}

this.chart_type_props = {
needs_denominator: ["p", "pp", "u", "up", "xbar", "s"].includes(chartType),
denominator_optional: ["i", "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)
}

this.multiplier = multiplier
this.percentLabels = percentLabels
}
Expand Down
10 changes: 6 additions & 4 deletions src/Classes/plotPropertiesClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,14 @@ export default class plotPropertiesClass {

const limitMultiplier: number = inputSettings.y_axis.limit_multiplier;
const values: number[] = controlLimits.values;
const upper_limits: number[] = controlLimits.ul99.concat(controlLimits?.speclimits_upper);
const lower_limits: number[] = controlLimits.ll99.concat(controlLimits?.speclimits_lower);
const ul99: number[] = controlLimits?.ul99
const speclimits_upper: number[] = controlLimits?.speclimits_upper;
const ll99: number[] = controlLimits?.ll99;
const speclimits_lower: number[] = controlLimits?.speclimits_lower;
const alt_targets: number[] = controlLimits.alt_targets;
const maxValue: number = max(values);
const maxValueOrLimit: number = max(values.concat(upper_limits).concat(alt_targets));
const minValueOrLimit: number = min(values.concat(lower_limits).concat(alt_targets));
const maxValueOrLimit: number = max(values.concat(ul99).concat(speclimits_upper).concat(alt_targets));
const minValueOrLimit: number = min(values.concat(ll99).concat(speclimits_lower).concat(alt_targets));
const maxTarget: number = max(controlLimits.targets);
const minTarget: number = min(controlLimits.targets);

Expand Down
10 changes: 4 additions & 6 deletions src/Classes/viewModelClass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,7 @@ export default class viewModelClass {
this.controlLimits = calcLimitsGrouped.reduce((all: controlLimitsObject, curr: controlLimitsObject) => {
const allInner: controlLimitsObject = all;
Object.entries(all).forEach((entry, idx) => {
if (this.inputSettings.settings.spc.chart_type !== "run" || !["ll99", "ll95", "ll68", "ul68", "ul95", "ul99"].includes(entry[0])) {
allInner[entry[0]] = entry[1]?.concat(Object.entries(curr)[idx][1]);
}
allInner[entry[0]] = entry[1]?.concat(Object.entries(curr)[idx][1]);
})
return allInner;
})
Expand Down Expand Up @@ -236,7 +234,7 @@ export default class viewModelClass {
if (this.inputSettings.settings.lines.show_specification) {
labels.push("speclimits_lower", "speclimits_upper");
}
if (this.inputSettings.settings.spc.chart_type !== "run") {
if (this.inputSettings.derivedSettings.chart_type_props.has_control_limits) {
if (this.inputSettings.settings.lines.show_99) {
labels.push("ll99", "ul99");
}
Expand Down Expand Up @@ -292,7 +290,7 @@ export default class viewModelClass {
const multiplier: number = this.inputSettings.derivedSettings.multiplier;
let lines_to_scale: string[] = ["values", "targets"];

if (this.inputSettings.settings.spc.chart_type !== "run") {
if (this.inputSettings.derivedSettings.chart_type_props.has_control_limits) {
lines_to_scale = lines_to_scale.concat(["ll99", "ll95", "ll68", "ul68", "ul95", "ul99"]);
}

Expand Down Expand Up @@ -343,7 +341,7 @@ export default class viewModelClass {
const group_values: number[] = this.controlLimits.values.slice(start, end);
const group_targets: number[] = this.controlLimits.targets.slice(start, end);

if (this.inputSettings.settings.spc.chart_type !== "run" || ast_specification || two_in_three_specification) {
if (this.inputSettings.derivedSettings.chart_type_props.has_control_limits || ast_specification || two_in_three_specification) {
const limit_map: Record<string, string> = {
"1 Sigma": "68",
"2 Sigma": "95",
Expand Down
4 changes: 2 additions & 2 deletions src/Functions/buildTooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export default function buildTooltip(index: number,
})
}
}
if (chart_type !== "run") {
if (derivedSettings.chart_type_props.has_control_limits) {
["68", "95", "99"].forEach(limit => {
if (inputSettings.lines[`ttip_show_${limit}`] && inputSettings.lines[`show_${limit}`]) {
tooltip.push({
Expand All @@ -124,7 +124,7 @@ export default function buildTooltip(index: number,
value: (alt_target).toFixed(sig_figs) + suffix
})
}
if (chart_type !== "run") {
if (derivedSettings.chart_type_props.has_control_limits) {
["68", "95", "99"].forEach(limit => {
if (inputSettings.lines[`ttip_show_${limit}`] && inputSettings.lines[`show_${limit}`]) {
tooltip.push({
Expand Down
5 changes: 2 additions & 3 deletions src/Functions/extractInputData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default function extractInputData(inputView: DataViewCategorical, inputSe
.map(d => d.show_specification ? d.specification_upper : null);


const inputValidStatus: ValidationT = validateInputData(keys, numerators, denominators, xbar_sds, groupings, inputSettings.spc.chart_type);
const inputValidStatus: ValidationT = validateInputData(keys, numerators, denominators, xbar_sds, groupings, inputSettingsClass.derivedSettings.chart_type_props);

if (inputValidStatus.status !== 0) {
return invalidInputData(inputValidStatus);
Expand Down Expand Up @@ -112,8 +112,7 @@ export default function extractInputData(inputView: DataViewCategorical, inputSe
}
}

const chart_type: string = inputSettings.spc.chart_type;
if (chart_type === "run") {
if (!inputSettingsClass.derivedSettings.chart_type_props.has_control_limits) {
removalMessages.push("NHS Assurance icon requires chart with control limits.")
}
}
Expand Down
11 changes: 5 additions & 6 deletions src/Functions/validateDataView.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type powerbi from "powerbi-visuals-api";
import { type defaultSettingsType } from "../Classes";
import { settingsClass } from "../Classes";

export default function validateDataView(inputDV: powerbi.DataView[], inputSettings: defaultSettingsType): string {
export default function validateDataView(inputDV: powerbi.DataView[], inputSettingsClass: settingsClass): string {
if (!(inputDV?.[0])) {
return "No data present";
}
Expand All @@ -17,9 +17,8 @@ export default function validateDataView(inputDV: powerbi.DataView[], inputSetti
if (!numeratorsPresent) {
return "No Numerators passed!";
}
const chart_type: string = inputSettings.spc.chart_type;
const denominatorRequired: string[] = ["p", "pp", "u", "up", "xbar", "s"];
if (denominatorRequired.includes(chart_type)) {
const chart_type: string = inputSettingsClass.settings.spc.chart_type;
if (inputSettingsClass.derivedSettings.chart_type_props.needs_denominator) {
const denominatorsPresent: boolean
= inputDV[0].categorical
?.values
Expand All @@ -30,7 +29,7 @@ export default function validateDataView(inputDV: powerbi.DataView[], inputSetti
}
}

if (chart_type === "xbar") {
if (inputSettingsClass.derivedSettings.chart_type_props.needs_sd) {
const xbarSDPresent: boolean
= inputDV[0].categorical
?.values
Expand Down
20 changes: 7 additions & 13 deletions src/Functions/validateInputData.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { derivedSettingsClass } from "../Classes";
import rep from "./rep";

export type ValidationT = { status: number, messages: string[], error?: string };
Expand All @@ -9,16 +10,9 @@ export default function validateInputData(keys: string[],
denominators: number[],
xbar_sds: number[],
groupings: string[],
data_type: string): { status: number, messages: string[], error?: string } {
const denominatorConstraintRequired: string[] = ["p", "pp", "u", "up"];
const denominatorRequired: string[] = ["p", "pp", "u", "up", "xbar", "s"];
const denominatorOptional: string[] = ["i", "run", "mr"];
chart_type_props: derivedSettingsClass["chart_type_props"]): { status: number, messages: string[], error?: string } {

const checkOptionalDenominator: boolean = denominatorOptional.includes(data_type) && !(denominators === null || denominators === undefined);
if (checkOptionalDenominator) {
denominatorRequired.push(data_type);
}
const numeratorNonNegativeRequired: string[] = ["p", "pp", "u", "up", "s", "c", "g", "t"];
const check_optional: boolean = chart_type_props.denominator_optional && !(denominators === null || denominators === undefined);

const validationRtn: ValidationT = { status: 0, messages: rep("", keys.length) };

Expand Down Expand Up @@ -48,7 +42,7 @@ export default function validateInputData(keys: string[],
validationRtn.error = "All numerators are missing or null!";
return validationRtn;
}
if (numeratorNonNegativeRequired.includes(data_type)) {
if (chart_type_props.numerator_non_negative) {
numerators.forEach((d, idx) => {
validationRtn.messages[idx] = validationRtn.messages[idx] === ""
? ((d >= 0) ? "" : "Numerator negative")
Expand All @@ -60,7 +54,7 @@ export default function validateInputData(keys: string[],
}
}

if (denominatorRequired.includes(data_type)) {
if (chart_type_props.needs_denominator || check_optional) {
denominators.forEach((d, idx) => {
validationRtn.messages[idx] = validationRtn.messages[idx] === ""
? ((d != null) ? "" : "Denominator missing")
Expand All @@ -79,7 +73,7 @@ export default function validateInputData(keys: string[],
validationRtn.error = "All denominators are negative!";
return validationRtn;
}
if (denominatorConstraintRequired.includes(data_type)) {
if (chart_type_props.numerator_leq_denominator) {
denominators.forEach((d, idx) => {
validationRtn.messages[idx] = validationRtn.messages[idx] === ""
? ((d >= numerators[idx]) ? "" : "Denominator < numerator")
Expand All @@ -92,7 +86,7 @@ export default function validateInputData(keys: string[],
}
}

if (data_type === "xbar") {
if (chart_type_props.needs_sd) {
xbar_sds.forEach((d, idx) => {
validationRtn.messages[idx] = validationRtn.messages[idx] === ""
? ((d != null) ? "" : "SD missing")
Expand Down
2 changes: 1 addition & 1 deletion src/Outlier Flagging/assuranceIconToDraw.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { viewModelClass } from "../Classes";

export default function assuranceIconToDraw(viewModel: viewModelClass): string {
if (viewModel.inputSettings.settings.spc.chart_type === "run") {
if (!(viewModel.inputSettings.derivedSettings.chart_type_props.has_control_limits)) {
return "none";
}
const imp_direction: string = viewModel.inputSettings.settings.outliers.improvement_direction;
Expand Down
2 changes: 1 addition & 1 deletion src/visual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class Visual implements powerbi.extensibility.IVisual {
}

const checkDV: string = validateDataView(options.dataViews,
this.viewModel.inputSettings.settings);
this.viewModel.inputSettings);
if (checkDV !== "valid") {
if (this.viewModel.inputSettings.settings.canvas.show_errors) {
this.svg.call(drawErrors, options, checkDV);
Expand Down

0 comments on commit 1f945ba

Please sign in to comment.