From 810b861710e21788db6f6fe15176aed865ce7fc3 Mon Sep 17 00:00:00 2001 From: Gaurav Gupta <47334368+gaugup@users.noreply.github.com> Date: Tue, 15 Feb 2022 11:35:56 -0800 Subject: [PATCH 1/5] Correct falsey to falsely (#1228) Signed-off-by: Gaurav Gupta --- libs/fairness/src/lib/util/calculateFairnessMetric.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/fairness/src/lib/util/calculateFairnessMetric.test.ts b/libs/fairness/src/lib/util/calculateFairnessMetric.test.ts index 1539ecb103..b003f6379a 100644 --- a/libs/fairness/src/lib/util/calculateFairnessMetric.test.ts +++ b/libs/fairness/src/lib/util/calculateFairnessMetric.test.ts @@ -45,7 +45,7 @@ describe("calculateFairnessMetric", () => { }; expect(result).toEqual(expectedResult); }); - it("should return only overall result if binBounds falsey", () => { + it("should return only overall result if binBounds falsely", () => { const mockValue = { binBounds: [], bins: [0.3, 0.7], From 74883261b09877f7ccf59a982b30430935efd91a Mon Sep 17 00:00:00 2001 From: Ilya Matiach Date: Tue, 15 Feb 2022 22:22:09 -0500 Subject: [PATCH 2/5] fix categorical what-if in RAI dashboard (#1225) --- .../__mock_data__/adultCensus.ts | 4 +-- .../modelAssessmentDatasets.ts | 2 +- .../src/lib/CounterfactualChart.tsx | 19 +++++++++++ .../src/lib/CounterfactualList.tsx | 33 ++++++++++++++++--- .../src/lib/CounterfactualPanel.tsx | 8 +++++ ...ensus-classification-model-debugging.ipynb | 2 +- ...using-classification-model-debugging.ipynb | 2 +- 7 files changed, 60 insertions(+), 10 deletions(-) diff --git a/apps/dashboard/src/model-assessment/__mock_data__/adultCensus.ts b/apps/dashboard/src/model-assessment/__mock_data__/adultCensus.ts index 936ab964f3..ebba831025 100644 --- a/apps/dashboard/src/model-assessment/__mock_data__/adultCensus.ts +++ b/apps/dashboard/src/model-assessment/__mock_data__/adultCensus.ts @@ -9908,7 +9908,7 @@ export const adultCounterfactualData: ICounterfactualData = { "occupation", "relationship", "race", - "sex", + "gender", "capital-gain", "capital-loss", "hours-per-week", @@ -9924,7 +9924,7 @@ export const adultCounterfactualData: ICounterfactualData = { "occupation", "relationship", "race", - "sex", + "gender", "capital-gain", "capital-loss", "hours-per-week", diff --git a/apps/widget-e2e/src/describer/modelAssessment/modelAssessmentDatasets.ts b/apps/widget-e2e/src/describer/modelAssessment/modelAssessmentDatasets.ts index c1c8b0729b..84ecfc91ba 100644 --- a/apps/widget-e2e/src/describer/modelAssessment/modelAssessmentDatasets.ts +++ b/apps/widget-e2e/src/describer/modelAssessment/modelAssessmentDatasets.ts @@ -26,7 +26,7 @@ const modelAssessmentDatasets = { }, featureImportanceData: { datapoint: 500, - dropdownRowName: "Row 4", + dropdownRowName: "Row 34", hasCorrectIncorrectDatapoints: true, hasFeatureImportanceComponent: true, newFeatureDropdownValue: "workclass", diff --git a/libs/counterfactuals/src/lib/CounterfactualChart.tsx b/libs/counterfactuals/src/lib/CounterfactualChart.tsx index 7b45feea3c..8b27daca39 100644 --- a/libs/counterfactuals/src/lib/CounterfactualChart.tsx +++ b/libs/counterfactuals/src/lib/CounterfactualChart.tsx @@ -203,6 +203,7 @@ export class CounterfactualChart extends React.PureComponent< closePanel={this.togglePanel} saveAsPoint={this.saveAsPoint} setCustomRowProperty={this.setCustomRowProperty} + setCustomRowPropertyComboBox={this.setCustomRowPropertyComboBox} temporaryPoint={this.temporaryPoint} isPanelOpen={this.state.isPanelOpen} data={this.context.counterfactualData} @@ -845,6 +846,24 @@ export class CounterfactualChart extends React.PureComponent< } }; + private setCustomRowPropertyComboBox = ( + key: string | number, + index?: number, + value?: string + ): void => { + if (!this.temporaryPoint || (!value && !index)) { + return; + } + const editingData = this.temporaryPoint; + if (index !== undefined) { + // User selected/de-selected an existing option + editingData[key] = index; + } + + this.forceUpdate(); + this.fetchData(editingData); + }; + private disableCounterfactualPanel = (): boolean => { return ( this.state.selectedPointsIndexes[0] === undefined || diff --git a/libs/counterfactuals/src/lib/CounterfactualList.tsx b/libs/counterfactuals/src/lib/CounterfactualList.tsx index 0145695a77..fbec169dd0 100644 --- a/libs/counterfactuals/src/lib/CounterfactualList.tsx +++ b/libs/counterfactuals/src/lib/CounterfactualList.tsx @@ -51,6 +51,11 @@ export interface ICounterfactualListProps { isString: boolean, newValue?: string | number ): void; + setCustomRowPropertyComboBox( + key: string | number, + index?: number, + value?: string + ): void; } interface ICounterfactualListState { @@ -270,8 +275,9 @@ export class CounterfactualList extends React.Component< return columns; } - private updateDropdownColValue = ( + private updateComboBoxColValue = ( key: string | number, + options: IComboBoxOption[], _event: React.FormEvent, option?: IComboBoxOption ): void => { @@ -279,10 +285,17 @@ export class CounterfactualList extends React.Component< const keyIndex = this.props.data?.feature_names_including_target.indexOf(id); if (option?.text) { - this.props.setCustomRowProperty(`Data${keyIndex}`, false, option.text); + const optionIndex = options.findIndex( + (feature) => feature.key === option.text + ); + this.props.setCustomRowPropertyComboBox( + `Data${keyIndex}`, + optionIndex, + option.text + ); this.setState((prevState) => { prevState.data[id] = option.text; - return { data: prevState.data }; + return { data: { ...prevState.data } }; }); } }; @@ -298,7 +311,7 @@ export class CounterfactualList extends React.Component< this.props.setCustomRowProperty(`Data${keyIndex}`, false, newValue); this.setState((prevState) => { prevState.data[id] = toNumber(newValue); - return { data: prevState.data }; + return { data: { ...prevState.data } }; }); }; @@ -343,7 +356,17 @@ export class CounterfactualList extends React.Component< allowFreeform selectedKey={`${this.state.data[column.key]}`} options={dropdownOption.data.categoricalOptions} - onChange={this.updateDropdownColValue.bind(this, column.key)} + onChange={( + _event: React.FormEvent, + option?: IComboBoxOption + ) => + this.updateComboBoxColValue( + column.key, + dropdownOption.data.categoricalOptions, + _event, + option + ) + } /> diff --git a/libs/counterfactuals/src/lib/CounterfactualPanel.tsx b/libs/counterfactuals/src/lib/CounterfactualPanel.tsx index 7504c93d37..1d42cc289d 100644 --- a/libs/counterfactuals/src/lib/CounterfactualPanel.tsx +++ b/libs/counterfactuals/src/lib/CounterfactualPanel.tsx @@ -41,6 +41,11 @@ export interface ICounterfactualPanelProps { isString: boolean, newValue?: string ): void; + setCustomRowPropertyComboBox( + key: string | number, + index?: number, + value?: string + ): void; } interface ICounterfactualState { filterText?: string; @@ -84,6 +89,9 @@ export class CounterfactualPanel extends React.Component< data={this.props.data} temporaryPoint={this.props.temporaryPoint} setCustomRowProperty={this.props.setCustomRowProperty} + setCustomRowPropertyComboBox={ + this.props.setCustomRowPropertyComboBox + } sortFeatures={this.state.sortFeatures} /> diff --git a/notebooks/responsibleaidashboard/responsibleaidashboard-census-classification-model-debugging.ipynb b/notebooks/responsibleaidashboard/responsibleaidashboard-census-classification-model-debugging.ipynb index f03e0843fa..d149e84343 100644 --- a/notebooks/responsibleaidashboard/responsibleaidashboard-census-classification-model-debugging.ipynb +++ b/notebooks/responsibleaidashboard/responsibleaidashboard-census-classification-model-debugging.ipynb @@ -173,7 +173,7 @@ "metadata": {}, "outputs": [], "source": [ - "clf = LGBMClassifier(n_estimators=5)\n", + "clf = LGBMClassifier()\n", "model = clf.fit(X_train, y_train)" ] }, diff --git a/notebooks/responsibleaidashboard/responsibleaidashboard-housing-classification-model-debugging.ipynb b/notebooks/responsibleaidashboard/responsibleaidashboard-housing-classification-model-debugging.ipynb index e0a5ec72f9..a1cc535fa4 100644 --- a/notebooks/responsibleaidashboard/responsibleaidashboard-housing-classification-model-debugging.ipynb +++ b/notebooks/responsibleaidashboard/responsibleaidashboard-housing-classification-model-debugging.ipynb @@ -153,7 +153,7 @@ "metadata": {}, "outputs": [], "source": [ - "clf = LGBMClassifier(n_estimators=5)\n", + "clf = LGBMClassifier()\n", "model = clf.fit(X_train, y_train)" ] }, From 28201b8a5198d9ec5cd8b01e1ff2c33422c65a8a Mon Sep 17 00:00:00 2001 From: Ilya Matiach Date: Tue, 15 Feb 2022 22:25:37 -0500 Subject: [PATCH 3/5] fix tree api being called twice on initial load due to uninitialized context being used (#1229) --- .../Controls/TreeViewRenderer/TreeViewRenderer.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libs/error-analysis/src/lib/ErrorAnalysisDashboard/Controls/TreeViewRenderer/TreeViewRenderer.tsx b/libs/error-analysis/src/lib/ErrorAnalysisDashboard/Controls/TreeViewRenderer/TreeViewRenderer.tsx index 08ed1baa58..5398fc4fa9 100644 --- a/libs/error-analysis/src/lib/ErrorAnalysisDashboard/Controls/TreeViewRenderer/TreeViewRenderer.tsx +++ b/libs/error-analysis/src/lib/ErrorAnalysisDashboard/Controls/TreeViewRenderer/TreeViewRenderer.tsx @@ -12,7 +12,8 @@ import { MetricCohortStats, ModelAssessmentContext, defaultModelAssessmentContext, - IErrorAnalysisTreeNode + IErrorAnalysisTreeNode, + IModelAssessmentContext } from "@responsible-ai/core-ui"; import { localization } from "@responsible-ai/localization"; import { Property } from "csstype"; @@ -80,7 +81,10 @@ export class TreeViewRenderer extends React.PureComponent< private static saveStateOnUnmount = true; public context: React.ContextType = defaultModelAssessmentContext; - public constructor(props: ITreeViewRendererProps) { + public constructor( + props: ITreeViewRendererProps, + context: IModelAssessmentContext + ) { super(props); if ( this.props.selectedCohort !== this.props.baseCohort && @@ -88,7 +92,7 @@ export class TreeViewRenderer extends React.PureComponent< ) { this.state = TreeViewRenderer.savedState; } else { - this.state = createInitialTreeViewState(this.context.errorAnalysisData); + this.state = createInitialTreeViewState(context.errorAnalysisData); } TreeViewRenderer.saveStateOnUnmount = true; } From 8292afe66bdaf85e83286a9c50b2bdb17da97584 Mon Sep 17 00:00:00 2001 From: Bo Zhang <71688188+zhb000@users.noreply.github.com> Date: Thu, 17 Feb 2022 01:07:59 +0800 Subject: [PATCH 4/5] scatter e2e (#1226) --- .../src/util/ScatterHighchart.ts | 84 +++++++++---------- apps/widget-e2e/src/util/ScatterHighchart.ts | 84 +++++++++---------- 2 files changed, 78 insertions(+), 90 deletions(-) diff --git a/apps/dashboard-e2e/src/util/ScatterHighchart.ts b/apps/dashboard-e2e/src/util/ScatterHighchart.ts index 481681d756..95a06e8499 100644 --- a/apps/dashboard-e2e/src/util/ScatterHighchart.ts +++ b/apps/dashboard-e2e/src/util/ScatterHighchart.ts @@ -3,15 +3,19 @@ import { Chart, IChartElement } from "./Chart"; -// const dReg = /^M([\d.]+),0A(\1),(\1) 0 1,1 0,-(\1)A(\1),(\1) 0 0,1 (\1),0Z$/; -// const transformReg = /^translate\(([\d.]+),([\d.]+)\)$/; +const dReg = /^M ([\d.]+) ([\d.]+) A 3 3 0 1 1 ([\d.]+) ([\d.]+) Z$/; export interface IHighScatter extends IChartElement { - readonly radius: number; + readonly x?: number; + readonly y1?: number; + readonly y2?: number; + readonly y3?: number; } export class ScatterHighchart extends Chart { - public get Elements(): any[] { - return this.getHighChartHtmlElements("path"); + public get Elements(): IHighScatter[] { + return this.getHighChartHtmlElements("path").map((b, i) => + this.getCoordinate(b, i) + ); } public sortByH(): IHighScatter[] { @@ -42,44 +46,34 @@ export class ScatterHighchart extends Chart { return cy.$$(`.trace.scatter:eq(0) .points path:eq(${idx})`).offset(); } - // private readonly getCoordinate = ( - // element: HTMLElement, - // idx: number - // ): IHighScatter => { - // const d = element.getAttribute("d"); - // if (!d) { - // throw new Error( - // `${idx}th path element in svg does not have "d" attribute` - // ); - // } - // const exec = dReg.exec(d); - // if (!exec) { - // throw new Error( - // `${idx}th path element in svg have invalid "d" attribute` - // ); - // } - // const [, ...strCords] = exec; - // const [radius] = strCords.map((s) => Number(s)); - // const transform = element.getAttribute("transform"); - // if (!transform) { - // throw new Error( - // `${idx}th path element in svg does not have "transform" attribute` - // ); - // } - // const transformExec = transformReg.exec(transform); - // if (!transformExec) { - // throw new Error( - // `${idx}th path element in svg have invalid "transform" attribute ${transform}` - // ); - // } - // const [, ...strTransforms] = transformExec; - // const [x, y] = strTransforms.map((s) => Number(s)); - // return { - // bottom: y + radius, - // left: x - radius, - // radius, - // right: x + radius, - // top: y - radius - // }; - // }; + private readonly getCoordinate = ( + element: HTMLElement, + idx: number + ): IHighScatter => { + const d = element.getAttribute("d"); + if (!d) { + throw new Error( + `${idx}th path element in svg does not have "d" attribute` + ); + } + const exec = dReg.exec(d); + if (!exec) { + throw new Error( + `${idx}th path element in svg have invalid "d" attribute` + ); + } + const [, ...strCords] = exec; + const [x, y1, horTip, vertTip, yChange, height] = strCords.map((s) => + Number(s) + ); + if (horTip === vertTip) { + throw new Error(`Horizontal tip is equal to vertical length`); + } + return { + bottom: x, // x + left: y1, // y1 + right: yChange, // y2 + top: height // y3 + }; + }; } diff --git a/apps/widget-e2e/src/util/ScatterHighchart.ts b/apps/widget-e2e/src/util/ScatterHighchart.ts index 481681d756..95a06e8499 100644 --- a/apps/widget-e2e/src/util/ScatterHighchart.ts +++ b/apps/widget-e2e/src/util/ScatterHighchart.ts @@ -3,15 +3,19 @@ import { Chart, IChartElement } from "./Chart"; -// const dReg = /^M([\d.]+),0A(\1),(\1) 0 1,1 0,-(\1)A(\1),(\1) 0 0,1 (\1),0Z$/; -// const transformReg = /^translate\(([\d.]+),([\d.]+)\)$/; +const dReg = /^M ([\d.]+) ([\d.]+) A 3 3 0 1 1 ([\d.]+) ([\d.]+) Z$/; export interface IHighScatter extends IChartElement { - readonly radius: number; + readonly x?: number; + readonly y1?: number; + readonly y2?: number; + readonly y3?: number; } export class ScatterHighchart extends Chart { - public get Elements(): any[] { - return this.getHighChartHtmlElements("path"); + public get Elements(): IHighScatter[] { + return this.getHighChartHtmlElements("path").map((b, i) => + this.getCoordinate(b, i) + ); } public sortByH(): IHighScatter[] { @@ -42,44 +46,34 @@ export class ScatterHighchart extends Chart { return cy.$$(`.trace.scatter:eq(0) .points path:eq(${idx})`).offset(); } - // private readonly getCoordinate = ( - // element: HTMLElement, - // idx: number - // ): IHighScatter => { - // const d = element.getAttribute("d"); - // if (!d) { - // throw new Error( - // `${idx}th path element in svg does not have "d" attribute` - // ); - // } - // const exec = dReg.exec(d); - // if (!exec) { - // throw new Error( - // `${idx}th path element in svg have invalid "d" attribute` - // ); - // } - // const [, ...strCords] = exec; - // const [radius] = strCords.map((s) => Number(s)); - // const transform = element.getAttribute("transform"); - // if (!transform) { - // throw new Error( - // `${idx}th path element in svg does not have "transform" attribute` - // ); - // } - // const transformExec = transformReg.exec(transform); - // if (!transformExec) { - // throw new Error( - // `${idx}th path element in svg have invalid "transform" attribute ${transform}` - // ); - // } - // const [, ...strTransforms] = transformExec; - // const [x, y] = strTransforms.map((s) => Number(s)); - // return { - // bottom: y + radius, - // left: x - radius, - // radius, - // right: x + radius, - // top: y - radius - // }; - // }; + private readonly getCoordinate = ( + element: HTMLElement, + idx: number + ): IHighScatter => { + const d = element.getAttribute("d"); + if (!d) { + throw new Error( + `${idx}th path element in svg does not have "d" attribute` + ); + } + const exec = dReg.exec(d); + if (!exec) { + throw new Error( + `${idx}th path element in svg have invalid "d" attribute` + ); + } + const [, ...strCords] = exec; + const [x, y1, horTip, vertTip, yChange, height] = strCords.map((s) => + Number(s) + ); + if (horTip === vertTip) { + throw new Error(`Horizontal tip is equal to vertical length`); + } + return { + bottom: x, // x + left: y1, // y1 + right: yChange, // y2 + top: height // y3 + }; + }; } From 11ee5caefedcf774e4e9d4ed81532aed93447933 Mon Sep 17 00:00:00 2001 From: Ilya Matiach Date: Wed, 16 Feb 2022 12:09:49 -0500 Subject: [PATCH 5/5] update several required dependencies (#1219) --- rai_core_flask/requirements.txt | 11 ++++++----- raiwidgets/requirements.txt | 1 - responsibleai/requirements.txt | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rai_core_flask/requirements.txt b/rai_core_flask/requirements.txt index aaefa8094f..596e2bb53b 100644 --- a/rai_core_flask/requirements.txt +++ b/rai_core_flask/requirements.txt @@ -1,5 +1,6 @@ -Flask~=1.0.0 -Flask-Cors==3.0.9 -ipython==7.16.3 -greenlet==0.4.17 -gevent==20.9.0 +Flask~=1.1.0 +Flask-Cors==3.0.10 +ipython==7.16.3; python_version <= '3.6' +ipython==7.31.1; python_version > '3.6' +greenlet==1.1.2 +gevent==21.12.0 diff --git a/raiwidgets/requirements.txt b/raiwidgets/requirements.txt index e2765a0f04..b8ab57cb22 100644 --- a/raiwidgets/requirements.txt +++ b/raiwidgets/requirements.txt @@ -7,4 +7,3 @@ scikit-learn>=0.22.1 lightgbm>=2.0.11 erroranalysis>=0.1.30 fairlearn>=0.7.0 -ipykernel<6.0 \ No newline at end of file diff --git a/responsibleai/requirements.txt b/responsibleai/requirements.txt index 788fc5cc04..c2ae52854c 100644 --- a/responsibleai/requirements.txt +++ b/responsibleai/requirements.txt @@ -13,4 +13,4 @@ semver~=2.13.0 # Pinned dependencies networkx<=2.5 -ipykernel<6.0 +ipykernel<=6.6.0