-
Notifications
You must be signed in to change notification settings - Fork 8.5k
[ML] Data Frame Analytics: Fix confusion matrix data grid width. #65818
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
5dd76c8
b5ebbd9
de5e1c0
248bd34
fc67d76
a6fd891
7905eec
5dfeff6
d67b062
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,4 @@ | ||
| @import 'pages/analytics_exploration/components/regression_exploration/index'; | ||
| @import 'pages/analytics_exploration/components/classification_exploration/index'; | ||
| @import 'pages/analytics_management/components/analytics_list/index'; | ||
| @import 'pages/analytics_management/components/create_analytics_form/index'; | ||
| @import 'pages/analytics_management/components/create_analytics_flyout/index'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,35 @@ | ||
| .euiFormRow.mlDataFrameAnalyticsClassification__actualLabel { | ||
| padding-top: $euiSize * 4; | ||
| /* | ||
| Workaround for EuiDataGrid within a Flex Layout, | ||
| this tricks browsers treating the width as a px value instead of % | ||
| */ | ||
| .mlDataFrameAnalyticsClassification { | ||
| width: calc(100% - 0px); | ||
| } | ||
|
|
||
| .mlDataFrameAnalyticsClassification__confusionMatrix { | ||
| padding: 0 5%; | ||
| } | ||
|
|
||
| /* | ||
| The following two classes are a workaround to avoid having EuiDataGrid in a flex layout | ||
| and just uses a legacy approach for a two column layout so we don't break IE11. | ||
| */ | ||
| .mlDataFrameAnalyticsClassification__confusionMatrix:after { | ||
| content: ""; | ||
| display: table; | ||
| clear: both; | ||
| } | ||
|
|
||
| .mlDataFrameAnalyticsClassification__actualLabel { | ||
| float: left; | ||
| width: 70px; | ||
| padding-top: $euiSize * 4.2; | ||
|
||
| } | ||
|
|
||
| /* | ||
| Gives EuiDataGrid a min-width of 480px, otherwise the columns options will disappear if you hide all columns. | ||
| */ | ||
| .mlDataFrameAnalyticsClassification__dataGridMinWidth { | ||
| min-width: 480px; | ||
| width: calc(100% - 0px); | ||
| } | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,8 @@ | |
| * you may not use this file except in compliance with the Elastic License. | ||
| */ | ||
|
|
||
| import './_classification_exploration.scss'; | ||
|
|
||
| import React, { FC, useState, useEffect, Fragment } from 'react'; | ||
| import { i18n } from '@kbn/i18n'; | ||
| import { FormattedMessage } from '@kbn/i18n/react'; | ||
|
|
@@ -12,7 +14,6 @@ import { | |
| EuiDataGrid, | ||
| EuiFlexGroup, | ||
| EuiFlexItem, | ||
| EuiFormRow, | ||
| EuiIconTip, | ||
| EuiPanel, | ||
| EuiSpacer, | ||
|
|
@@ -46,8 +47,6 @@ import { | |
| getTrailingControlColumns, | ||
| } from './column_data'; | ||
|
|
||
| const defaultPanelWidth = 500; | ||
|
|
||
| interface Props { | ||
| jobConfig: DataFrameAnalyticsConfig; | ||
| jobStatus?: DATA_FRAME_TASK_STATE; | ||
|
|
@@ -104,7 +103,6 @@ export const EvaluatePanel: FC<Props> = ({ jobConfig, jobStatus, searchQuery }) | |
| const [docsCount, setDocsCount] = useState<null | number>(null); | ||
| const [error, setError] = useState<null | string>(null); | ||
| const [dataSubsetTitle, setDataSubsetTitle] = useState<SUBSET_TITLE>(SUBSET_TITLE.ENTIRE); | ||
| const [panelWidth, setPanelWidth] = useState<number>(defaultPanelWidth); | ||
| // Column visibility | ||
| const [visibleColumns, setVisibleColumns] = useState(() => | ||
| columns.map(({ id }: { id: string }) => id) | ||
|
|
@@ -168,24 +166,6 @@ export const EvaluatePanel: FC<Props> = ({ jobConfig, jobStatus, searchQuery }) | |
| } | ||
| }; | ||
|
|
||
| const resizeHandler = () => { | ||
| const tablePanelWidth: number = | ||
| document.getElementById('mlDataFrameAnalyticsTableResultsPanel')?.clientWidth || | ||
| defaultPanelWidth; | ||
| // Keep the evaluate panel width slightly smaller than the results table | ||
| // to ensure results table can resize correctly. Temporary workaround DataGrid issue with flex | ||
| const newWidth = tablePanelWidth - 8; | ||
| setPanelWidth(newWidth); | ||
| }; | ||
|
|
||
| useEffect(() => { | ||
| window.addEventListener('resize', resizeHandler); | ||
| resizeHandler(); | ||
| return () => { | ||
| window.removeEventListener('resize', resizeHandler); | ||
| }; | ||
| }, []); | ||
|
|
||
| useEffect(() => { | ||
| if (confusionMatrixData.length > 0) { | ||
| const { columns: derivedColumns, columnData } = getColumnData(confusionMatrixData); | ||
|
|
@@ -310,158 +290,135 @@ export const EvaluatePanel: FC<Props> = ({ jobConfig, jobStatus, searchQuery }) | |
| return ( | ||
| <EuiPanel | ||
| data-test-subj="mlDFAnalyticsClassificationExplorationEvaluatePanel" | ||
| style={{ width: `${panelWidth}px` }} | ||
| className="mlDataFrameAnalyticsClassification" | ||
| > | ||
| <EuiFlexGroup direction="column" gutterSize="s"> | ||
| <EuiFlexItem> | ||
| <EuiFlexGroup alignItems="center" justifyContent="spaceBetween"> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiTitle size="xs"> | ||
| <span> | ||
| {i18n.translate( | ||
| 'xpack.ml.dataframe.analytics.classificationExploration.evaluateJobIdTitle', | ||
| { | ||
| defaultMessage: 'Evaluation of classification job ID {jobId}', | ||
| values: { jobId: jobConfig.id }, | ||
| } | ||
| )} | ||
| </span> | ||
| </EuiTitle> | ||
| </EuiFlexItem> | ||
| {jobStatus !== undefined && ( | ||
| <EuiFlexItem grow={false}> | ||
| <span>{getTaskStateBadge(jobStatus)}</span> | ||
| </EuiFlexItem> | ||
| )} | ||
| <EuiFlexItem> | ||
| <EuiSpacer /> | ||
| </EuiFlexItem> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiButtonEmpty | ||
| target="_blank" | ||
| iconType="help" | ||
| iconSide="left" | ||
| color="primary" | ||
| href={`${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-dfanalytics-evaluate.html#ml-dfanalytics-classification`} | ||
| > | ||
| <div> | ||
| <EuiFlexGroup alignItems="center" justifyContent="spaceBetween"> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiTitle size="xs"> | ||
| <span> | ||
| {i18n.translate( | ||
| 'xpack.ml.dataframe.analytics.classificationExploration.classificationDocsLink', | ||
| 'xpack.ml.dataframe.analytics.classificationExploration.evaluateJobIdTitle', | ||
| { | ||
| defaultMessage: 'Classification evaluation docs ', | ||
| defaultMessage: 'Evaluation of classification job ID {jobId}', | ||
| values: { jobId: jobConfig.id }, | ||
| } | ||
| )} | ||
| </EuiButtonEmpty> | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
| </EuiFlexItem> | ||
| {error !== null && ( | ||
| <EuiFlexItem grow={false}> | ||
| <ErrorCallout error={error} /> | ||
| </span> | ||
| </EuiTitle> | ||
| </EuiFlexItem> | ||
| )} | ||
| {error === null && ( | ||
| <Fragment> | ||
| {jobStatus !== undefined && ( | ||
| <EuiFlexItem grow={false}> | ||
| <EuiFlexGroup gutterSize="xs"> | ||
| <EuiTitle size="xxs"> | ||
| <span>{getHelpText(dataSubsetTitle)}</span> | ||
| </EuiTitle> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiIconTip | ||
| anchorClassName="mlDataFrameAnalyticsClassificationInfoTooltip" | ||
| content={i18n.translate( | ||
| 'xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTooltip', | ||
| { | ||
| defaultMessage: | ||
| 'The multi-class confusion matrix contains the number of occurrences where the analysis classified data points correctly with their actual class as well as the number of occurrences where it misclassified them with another class', | ||
| } | ||
| )} | ||
| /> | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
| <span>{getTaskStateBadge(jobStatus)}</span> | ||
| </EuiFlexItem> | ||
| {docsCount !== null && ( | ||
| )} | ||
| <EuiFlexItem /> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiButtonEmpty | ||
| target="_blank" | ||
| iconType="help" | ||
| iconSide="left" | ||
| color="primary" | ||
| href={`${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-dfanalytics-evaluate.html#ml-dfanalytics-classification`} | ||
| > | ||
| {i18n.translate( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: could be replaced with |
||
| 'xpack.ml.dataframe.analytics.classificationExploration.classificationDocsLink', | ||
| { | ||
| defaultMessage: 'Classification evaluation docs ', | ||
| } | ||
| )} | ||
| </EuiButtonEmpty> | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
| </div> | ||
| {error !== null && <ErrorCallout error={error} />} | ||
| {error === null && ( | ||
| <Fragment> | ||
| <div> | ||
| <EuiFlexGroup gutterSize="xs"> | ||
| <EuiTitle size="xxs"> | ||
| <span>{getHelpText(dataSubsetTitle)}</span> | ||
| </EuiTitle> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiText size="xs" color="subdued"> | ||
| <FormattedMessage | ||
| id="xpack.ml.dataframe.analytics.classificationExploration.generalizationDocsCount" | ||
| defaultMessage="{docsCount, plural, one {# doc} other {# docs}} evaluated" | ||
| values={{ docsCount }} | ||
| /> | ||
| </EuiText> | ||
| <EuiIconTip | ||
| anchorClassName="mlDataFrameAnalyticsClassificationInfoTooltip" | ||
| content={i18n.translate( | ||
| 'xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTooltip', | ||
| { | ||
| defaultMessage: | ||
| 'The multi-class confusion matrix contains the number of occurrences where the analysis classified data points correctly with their actual class as well as the number of occurrences where it misclassified them with another class', | ||
| } | ||
| )} | ||
| /> | ||
| </EuiFlexItem> | ||
| )} | ||
| {/* BEGIN TABLE ELEMENTS */} | ||
| <EuiFlexItem grow={false}> | ||
| <EuiFlexGroup gutterSize="s" style={{ paddingLeft: '5%', paddingRight: '5%' }}> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiFormRow | ||
| className="mlDataFrameAnalyticsClassification__actualLabel" | ||
| helpText={i18n.translate( | ||
| 'xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixActualLabel', | ||
| </EuiFlexGroup> | ||
| </div> | ||
| {docsCount !== null && ( | ||
| <EuiText size="xs" color="subdued"> | ||
| <FormattedMessage | ||
| id="xpack.ml.dataframe.analytics.classificationExploration.generalizationDocsCount" | ||
| defaultMessage="{docsCount, plural, one {# doc} other {# docs}} evaluated" | ||
| values={{ docsCount }} | ||
| /> | ||
| </EuiText> | ||
| )} | ||
| {/* BEGIN TABLE ELEMENTS */} | ||
| <EuiSpacer size="m" /> | ||
| <div className="mlDataFrameAnalyticsClassification__confusionMatrix"> | ||
| <div className="mlDataFrameAnalyticsClassification__actualLabel"> | ||
| <EuiText size="xs" color="subdued"> | ||
| <FormattedMessage | ||
| id="xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixActualLabel" | ||
| defaultMessage="Actual label" | ||
| /> | ||
| </EuiText> | ||
| </div> | ||
| <div className="mlDataFrameAnalyticsClassification__dataGridMinWidth"> | ||
| {columns.length > 0 && columnsData.length > 0 && ( | ||
| <> | ||
| <div> | ||
| <EuiText size="xs" color="subdued"> | ||
| <FormattedMessage | ||
| id="xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixPredictedLabel" | ||
| defaultMessage="Predicted label" | ||
| /> | ||
| </EuiText> | ||
| </div> | ||
| <EuiSpacer size="s" /> | ||
| <EuiDataGrid | ||
| data-test-subj="mlDFAnalyticsClassificationExplorationConfusionMatrix" | ||
| aria-label={i18n.translate( | ||
| 'xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixLabel', | ||
| { | ||
| defaultMessage: 'Actual label', | ||
| defaultMessage: 'Classification confusion matrix', | ||
| } | ||
| )} | ||
| > | ||
| <Fragment /> | ||
| </EuiFormRow> | ||
| </EuiFlexItem> | ||
| <EuiFlexItem grow={false}> | ||
| {columns.length > 0 && columnsData.length > 0 && ( | ||
| <Fragment> | ||
| <EuiFlexGroup direction="column" justifyContent="center" gutterSize="s"> | ||
| <EuiFlexItem grow={false}> | ||
| <EuiFormRow | ||
| helpText={i18n.translate( | ||
| 'xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixPredictedLabel', | ||
| { | ||
| defaultMessage: 'Predicted label', | ||
| } | ||
| )} | ||
| > | ||
| <Fragment /> | ||
| </EuiFormRow> | ||
| </EuiFlexItem> | ||
| <EuiFlexItem grow={false} style={{ width: '90%' }}> | ||
| <EuiDataGrid | ||
| data-test-subj="mlDFAnalyticsClassificationExplorationConfusionMatrix" | ||
| aria-label={i18n.translate( | ||
| 'xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixLabel', | ||
| { | ||
| defaultMessage: 'Classification confusion matrix', | ||
| } | ||
| )} | ||
| columns={shownColumns} | ||
| columnVisibility={{ visibleColumns, setVisibleColumns }} | ||
| rowCount={rowCount} | ||
| renderCellValue={renderCellValue} | ||
| inMemory={{ level: 'sorting' }} | ||
| toolbarVisibility={{ | ||
| showColumnSelector: true, | ||
| showStyleSelector: false, | ||
| showFullScreenSelector: false, | ||
| showSortSelector: false, | ||
| }} | ||
| popoverContents={popoverContents} | ||
| gridStyle={{ rowHover: 'none' }} | ||
| trailingControlColumns={ | ||
| showTrailingColumns === true && showFullColumns === false | ||
| ? getTrailingControlColumns(extraColumns, setShowFullColumns) | ||
| : undefined | ||
| } | ||
| /> | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
| </Fragment> | ||
| )} | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
| </EuiFlexItem> | ||
| </Fragment> | ||
| )} | ||
| {/* END TABLE ELEMENTS */} | ||
| </EuiFlexGroup> | ||
| columns={shownColumns} | ||
| columnVisibility={{ visibleColumns, setVisibleColumns }} | ||
| rowCount={rowCount} | ||
| renderCellValue={renderCellValue} | ||
| inMemory={{ level: 'sorting' }} | ||
| toolbarVisibility={{ | ||
| showColumnSelector: true, | ||
| showStyleSelector: false, | ||
| showFullScreenSelector: false, | ||
| showSortSelector: false, | ||
| }} | ||
| popoverContents={popoverContents} | ||
| gridStyle={{ rowHover: 'none' }} | ||
| trailingControlColumns={ | ||
| showTrailingColumns === true && showFullColumns === false | ||
| ? getTrailingControlColumns(extraColumns, setShowFullColumns) | ||
| : undefined | ||
| } | ||
| /> | ||
| </> | ||
| )} | ||
| </div> | ||
| </div> | ||
| </Fragment> | ||
| )} | ||
| {/* END TABLE ELEMENTS */} | ||
| </EuiPanel> | ||
| ); | ||
| }; | ||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need
calchere? also, keep in mind it's not supported by IE11 properly https://caniuse.com/#feat=calcThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
calcis used to work around an issue withEuiDataGridand percentage based width of the wrapping container when used in flex layouts. The original issue in the EUI repo is here: elastic/eui#2618calcin IE has limitations but this one should work hopefully. I cannot test it at the moment because it seems Kibana is broken for IE11 onmaster. Will try again once I hear back from QA team.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Managed to test in IE. Pushed some fixes in de5e1c0 and updated the PR description with before and after screenshots.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After the refactor to not use flex anymore for the layout, the
calc()is no longer necessary. Removed in 7905eec.