[ML] Data Frame Analytics: Expandable sections for classification and regression (#79414)
Applies the expandable section based layout to the results pages of classification and regression analytics jobs.
This commit is contained in:
parent
4fdf2f1566
commit
c7caac61a2
|
@ -23,7 +23,7 @@
|
|||
.mlDataFrameAnalyticsClassification__actualLabel {
|
||||
float: left;
|
||||
width: 80px;
|
||||
padding-top: $euiSize * 4 + $euiSizeXS;
|
||||
padding-top: $euiSize * 4;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -17,17 +17,19 @@ interface Props {
|
|||
}
|
||||
|
||||
export const ClassificationExploration: FC<Props> = ({ jobId, defaultIsTraining }) => (
|
||||
<ExplorationPageWrapper
|
||||
jobId={jobId}
|
||||
title={i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.classificationExploration.tableJobIdTitle',
|
||||
{
|
||||
defaultMessage: 'Destination index for classification job ID {jobId}',
|
||||
values: { jobId },
|
||||
}
|
||||
)}
|
||||
EvaluatePanel={EvaluatePanel}
|
||||
FeatureImportanceSummaryPanel={FeatureImportanceSummaryPanel}
|
||||
defaultIsTraining={defaultIsTraining}
|
||||
/>
|
||||
<div className="mlDataFrameAnalyticsClassification">
|
||||
<ExplorationPageWrapper
|
||||
jobId={jobId}
|
||||
title={i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.classificationExploration.tableJobIdTitle',
|
||||
{
|
||||
defaultMessage: 'Destination index for classification job ID {jobId}',
|
||||
values: { jobId },
|
||||
}
|
||||
)}
|
||||
EvaluatePanel={EvaluatePanel}
|
||||
FeatureImportanceSummaryPanel={FeatureImportanceSummaryPanel}
|
||||
defaultIsTraining={defaultIsTraining}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import './_classification_exploration.scss';
|
||||
|
||||
import React, { FC, useState, useEffect, Fragment } from 'react';
|
||||
import React, { FC, useState, useEffect } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import {
|
||||
|
@ -15,7 +15,6 @@ import {
|
|||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiIconTip,
|
||||
EuiPanel,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
|
@ -30,7 +29,6 @@ import {
|
|||
DataFrameAnalyticsConfig,
|
||||
} from '../../../../common';
|
||||
import { isKeywordAndTextType } from '../../../../common/fields';
|
||||
import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/use_columns';
|
||||
import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common';
|
||||
import {
|
||||
isResultsSearchBoolQuery,
|
||||
|
@ -39,7 +37,9 @@ import {
|
|||
ResultsSearchQuery,
|
||||
ANALYSIS_CONFIG_TYPE,
|
||||
} from '../../../../common/analytics';
|
||||
import { LoadingPanel } from '../loading_panel';
|
||||
|
||||
import { ExpandableSection, HEADER_ITEMS_LOADING } from '../expandable_section';
|
||||
|
||||
import {
|
||||
getColumnData,
|
||||
ACTUAL_CLASS_ID,
|
||||
|
@ -47,7 +47,7 @@ import {
|
|||
getTrailingControlColumns,
|
||||
} from './column_data';
|
||||
|
||||
interface Props {
|
||||
export interface EvaluatePanelProps {
|
||||
jobConfig: DataFrameAnalyticsConfig;
|
||||
jobStatus?: DATA_FRAME_TASK_STATE;
|
||||
searchQuery: ResultsSearchQuery;
|
||||
|
@ -90,7 +90,7 @@ function getHelpText(dataSubsetTitle: string) {
|
|||
return helpText;
|
||||
}
|
||||
|
||||
export const EvaluatePanel: FC<Props> = ({ jobConfig, jobStatus, searchQuery }) => {
|
||||
export const EvaluatePanel: FC<EvaluatePanelProps> = ({ jobConfig, jobStatus, searchQuery }) => {
|
||||
const {
|
||||
services: { docLinks },
|
||||
} = useMlKibana();
|
||||
|
@ -272,10 +272,6 @@ export const EvaluatePanel: FC<Props> = ({ jobConfig, jobStatus, searchQuery })
|
|||
return <span>{columnId === ACTUAL_CLASS_ID ? cellValue : accuracy}</span>;
|
||||
};
|
||||
|
||||
if (isLoading === true) {
|
||||
return <LoadingPanel />;
|
||||
}
|
||||
|
||||
const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = docLinks;
|
||||
|
||||
const showTrailingColumns = columnsData.length > MAX_COLUMNS;
|
||||
|
@ -288,137 +284,159 @@ export const EvaluatePanel: FC<Props> = ({ jobConfig, jobStatus, searchQuery })
|
|||
showTrailingColumns === true && showFullColumns === false ? MAX_COLUMNS : columnsData.length;
|
||||
|
||||
return (
|
||||
<EuiPanel
|
||||
data-test-subj="mlDFAnalyticsClassificationExplorationEvaluatePanel"
|
||||
className="mlDataFrameAnalyticsClassification"
|
||||
>
|
||||
<div>
|
||||
<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 />
|
||||
<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(
|
||||
'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}>
|
||||
<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>
|
||||
</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',
|
||||
<>
|
||||
<ExpandableSection
|
||||
dataTestId="ClassificationEvaluation"
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.classificationExploration.evaluateSectionTitle"
|
||||
defaultMessage="Model evaluation"
|
||||
/>
|
||||
}
|
||||
docsLink={
|
||||
<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(
|
||||
'xpack.ml.dataframe.analytics.classificationExploration.classificationDocsLink',
|
||||
{
|
||||
defaultMessage: 'Classification evaluation docs ',
|
||||
}
|
||||
)}
|
||||
</EuiButtonEmpty>
|
||||
}
|
||||
headerItems={
|
||||
!isLoading
|
||||
? [
|
||||
...(jobStatus !== undefined
|
||||
? [
|
||||
{
|
||||
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
|
||||
}
|
||||
/>
|
||||
id: 'jobStatus',
|
||||
label: i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.classificationExploration.evaluateJobStatusLabel',
|
||||
{
|
||||
defaultMessage: 'Job status',
|
||||
}
|
||||
),
|
||||
value: jobStatus,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(docsCount !== null
|
||||
? [
|
||||
{
|
||||
id: 'docsEvaluated',
|
||||
label: i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.classificationExploration.generalizationDocsCount',
|
||||
{
|
||||
defaultMessage: '{docsCount, plural, one {doc} other {docs}} evaluated',
|
||||
values: { docsCount },
|
||||
}
|
||||
),
|
||||
value: docsCount,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
]
|
||||
: HEADER_ITEMS_LOADING
|
||||
}
|
||||
contentPadding={true}
|
||||
content={
|
||||
!isLoading ? (
|
||||
<>
|
||||
{error !== null && <ErrorCallout error={error} />}
|
||||
{error === null && (
|
||||
<>
|
||||
<EuiFlexGroup gutterSize="none">
|
||||
<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>
|
||||
{/* 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: '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={{
|
||||
border: 'all',
|
||||
fontSize: 's',
|
||||
cellPadding: 's',
|
||||
stripes: false,
|
||||
rowHover: 'none',
|
||||
header: 'shade',
|
||||
}}
|
||||
trailingControlColumns={
|
||||
showTrailingColumns === true && showFullColumns === false
|
||||
? getTrailingControlColumns(extraColumns, setShowFullColumns)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
)}
|
||||
{/* END TABLE ELEMENTS */}
|
||||
</EuiPanel>
|
||||
{/* END TABLE ELEMENTS */}
|
||||
</>
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
.mlExpandableSection {
|
||||
padding: 0 $euiSizeS $euiSizeS $euiSizeS;
|
||||
}
|
||||
|
||||
.mlExpandableSection-contentPadding {
|
||||
padding: $euiSizeS;
|
||||
}
|
||||
|
|
|
@ -29,9 +29,13 @@ const isHeaderItems = (arg: any): arg is HeaderItem[] => {
|
|||
return Array.isArray(arg);
|
||||
};
|
||||
|
||||
export const HEADER_ITEMS_LOADING = 'header_items_loading';
|
||||
|
||||
export interface ExpandableSectionProps {
|
||||
content: ReactNode;
|
||||
headerItems?: HeaderItem[] | 'loading';
|
||||
contentPadding?: boolean;
|
||||
docsLink?: ReactNode;
|
||||
headerItems?: HeaderItem[] | typeof HEADER_ITEMS_LOADING;
|
||||
isExpanded?: boolean;
|
||||
dataTestId: string;
|
||||
title: ReactNode;
|
||||
|
@ -45,8 +49,10 @@ export const ExpandableSection: FC<ExpandableSectionProps> = ({
|
|||
// callback.
|
||||
isExpanded: isExpandedDefault = true,
|
||||
content,
|
||||
contentPadding = false,
|
||||
dataTestId,
|
||||
title,
|
||||
docsLink,
|
||||
}) => {
|
||||
const [isExpanded, setIsExpanded] = useState(isExpandedDefault);
|
||||
const toggleExpanded = () => {
|
||||
|
@ -56,16 +62,21 @@ export const ExpandableSection: FC<ExpandableSectionProps> = ({
|
|||
return (
|
||||
<EuiPanel paddingSize="none" data-test-subj={`mlDFExpandableSection-${dataTestId}`}>
|
||||
<div className="mlExpandableSection">
|
||||
<EuiButtonEmpty
|
||||
onClick={toggleExpanded}
|
||||
iconType={isExpanded ? 'arrowUp' : 'arrowDown'}
|
||||
size="l"
|
||||
iconSide="right"
|
||||
flush="left"
|
||||
>
|
||||
{title}
|
||||
</EuiButtonEmpty>
|
||||
{headerItems === 'loading' && <EuiLoadingContent lines={1} />}
|
||||
<EuiFlexGroup justifyContent="spaceBetween" gutterSize="none">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
onClick={toggleExpanded}
|
||||
iconType={isExpanded ? 'arrowUp' : 'arrowDown'}
|
||||
size="l"
|
||||
iconSide="right"
|
||||
flush="left"
|
||||
>
|
||||
{title}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
{docsLink !== undefined && <EuiFlexItem grow={false}>{docsLink}</EuiFlexItem>}
|
||||
</EuiFlexGroup>
|
||||
{headerItems === HEADER_ITEMS_LOADING && <EuiLoadingContent lines={1} />}
|
||||
{isHeaderItems(headerItems) && (
|
||||
<EuiFlexGroup>
|
||||
{headerItems.map(({ label, value, id }) => (
|
||||
|
@ -82,13 +93,19 @@ export const ExpandableSection: FC<ExpandableSectionProps> = ({
|
|||
<EuiBadge>{value}</EuiBadge>
|
||||
</>
|
||||
)}
|
||||
{label === undefined && value}
|
||||
{label === undefined && (
|
||||
<EuiText size="xs" color="subdued">
|
||||
{value}
|
||||
</EuiText>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
))}
|
||||
</EuiFlexGroup>
|
||||
)}
|
||||
</div>
|
||||
{isExpanded && content}
|
||||
{isExpanded && (
|
||||
<div className={contentPadding ? 'mlExpandableSection-contentPadding' : ''}>{content}</div>
|
||||
)}
|
||||
</EuiPanel>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState, FC } from 'react';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { EuiHorizontalRule, EuiLoadingSpinner, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
|
||||
import type { DataFrameAnalysisConfigType } from '../../../../../../../common/types/data_frame_analytics';
|
||||
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
|
||||
import { getAnalysisType } from '../../../../common';
|
||||
|
||||
import { isGetDataFrameAnalyticsStatsResponseOk } from '../../../analytics_management/services/analytics_service/get_analytics';
|
||||
import {
|
||||
DataFrameAnalyticsListRow,
|
||||
DATA_FRAME_MODE,
|
||||
} from '../../../analytics_management/components/analytics_list/common';
|
||||
import { ExpandedRow } from '../../../analytics_management/components/analytics_list/expanded_row';
|
||||
|
||||
import {
|
||||
ExpandableSection,
|
||||
ExpandableSectionProps,
|
||||
HEADER_ITEMS_LOADING,
|
||||
} from './expandable_section';
|
||||
|
||||
const getAnalyticsSectionHeaderItems = (
|
||||
expandedRowItem: DataFrameAnalyticsListRow | undefined
|
||||
): ExpandableSectionProps['headerItems'] => {
|
||||
if (expandedRowItem === undefined) {
|
||||
return HEADER_ITEMS_LOADING;
|
||||
}
|
||||
|
||||
const sourceIndex = Array.isArray(expandedRowItem.config.source.index)
|
||||
? expandedRowItem.config.source.index.join()
|
||||
: expandedRowItem.config.source.index;
|
||||
|
||||
return [
|
||||
{
|
||||
id: 'analysisTypeLabel',
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.analysisTypeLabel"
|
||||
defaultMessage="Type"
|
||||
/>
|
||||
),
|
||||
value: expandedRowItem.job_type,
|
||||
},
|
||||
{
|
||||
id: 'analysisSourceIndexLabel',
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.analysisSourceIndexLabel"
|
||||
defaultMessage="Source index"
|
||||
/>
|
||||
),
|
||||
value: sourceIndex,
|
||||
},
|
||||
{
|
||||
id: 'analysisDestinationIndexLabel',
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.analysisDestinationIndexLabel"
|
||||
defaultMessage="Destination index"
|
||||
/>
|
||||
),
|
||||
value: expandedRowItem.config.dest.index,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
interface ExpandableSectionAnalyticsProps {
|
||||
jobId: string;
|
||||
}
|
||||
|
||||
export const ExpandableSectionAnalytics: FC<ExpandableSectionAnalyticsProps> = ({ jobId }) => {
|
||||
const [expandedRowItem, setExpandedRowItem] = useState<DataFrameAnalyticsListRow | undefined>();
|
||||
|
||||
const fetchStats = async () => {
|
||||
const analyticsConfigs = await ml.dataFrameAnalytics.getDataFrameAnalytics(jobId);
|
||||
const analyticsStats = await ml.dataFrameAnalytics.getDataFrameAnalyticsStats(jobId);
|
||||
|
||||
const config = analyticsConfigs.data_frame_analytics[0];
|
||||
const stats = isGetDataFrameAnalyticsStatsResponseOk(analyticsStats)
|
||||
? analyticsStats.data_frame_analytics[0]
|
||||
: undefined;
|
||||
|
||||
if (stats === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newExpandedRowItem: DataFrameAnalyticsListRow = {
|
||||
checkpointing: {},
|
||||
config,
|
||||
id: config.id,
|
||||
job_type: getAnalysisType(config.analysis) as DataFrameAnalysisConfigType,
|
||||
mode: DATA_FRAME_MODE.BATCH,
|
||||
state: stats.state,
|
||||
stats,
|
||||
};
|
||||
|
||||
setExpandedRowItem(newExpandedRowItem);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchStats();
|
||||
}, [jobId]);
|
||||
|
||||
const analyticsSectionHeaderItems = getAnalyticsSectionHeaderItems(expandedRowItem);
|
||||
const analyticsSectionContent = (
|
||||
<>
|
||||
<EuiHorizontalRule size="full" margin="none" />
|
||||
{expandedRowItem === undefined && (
|
||||
<EuiText textAlign="center">
|
||||
<EuiSpacer size="l" />
|
||||
<EuiLoadingSpinner size="l" />
|
||||
<EuiSpacer size="l" />
|
||||
</EuiText>
|
||||
)}
|
||||
{expandedRowItem !== undefined && <ExpandedRow item={expandedRowItem} />}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ExpandableSection
|
||||
dataTestId="analysis"
|
||||
content={analyticsSectionContent}
|
||||
headerItems={analyticsSectionHeaderItems}
|
||||
isExpanded={false}
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.analysisSectionTitle"
|
||||
defaultMessage="Analysis"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { EuiDataGridColumn, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
|
||||
import { IndexPattern } from '../../../../../../../../../../src/plugins/data/public';
|
||||
|
||||
import {
|
||||
isClassificationAnalysis,
|
||||
isRegressionAnalysis,
|
||||
} from '../../../../../../../common/util/analytics_utils';
|
||||
|
||||
import { getToastNotifications } from '../../../../../util/dependency_cache';
|
||||
import { useColorRange, ColorRangeLegend } from '../../../../../components/color_range_legend';
|
||||
import { DataGrid, UseIndexDataReturnType } from '../../../../../components/data_grid';
|
||||
import { SavedSearchQuery } from '../../../../../contexts/ml';
|
||||
|
||||
import { defaultSearchQuery, DataFrameAnalyticsConfig, SEARCH_SIZE } from '../../../../common';
|
||||
|
||||
import {
|
||||
ExpandableSection,
|
||||
ExpandableSectionProps,
|
||||
HEADER_ITEMS_LOADING,
|
||||
} from '../expandable_section';
|
||||
import { IndexPatternPrompt } from '../index_pattern_prompt';
|
||||
|
||||
const showingDocs = i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText',
|
||||
{
|
||||
defaultMessage: 'Showing documents for which predictions exist',
|
||||
}
|
||||
);
|
||||
|
||||
const showingFirstDocs = i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.explorationResults.firstDocumentsShownHelpText',
|
||||
{
|
||||
defaultMessage: 'Showing first {searchSize} documents for which predictions exist',
|
||||
values: { searchSize: SEARCH_SIZE },
|
||||
}
|
||||
);
|
||||
|
||||
const getResultsSectionHeaderItems = (
|
||||
columnsWithCharts: EuiDataGridColumn[],
|
||||
tableItems: Array<Record<string, any>>,
|
||||
rowCount: number,
|
||||
colorRange?: ReturnType<typeof useColorRange>
|
||||
): ExpandableSectionProps['headerItems'] => {
|
||||
return columnsWithCharts.length > 0 && tableItems.length > 0
|
||||
? [
|
||||
{
|
||||
id: 'explorationTableTotalDocs',
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.explorationTableTotalDocsLabel"
|
||||
defaultMessage="Total docs"
|
||||
/>
|
||||
),
|
||||
value: rowCount,
|
||||
},
|
||||
...(colorRange !== undefined
|
||||
? [
|
||||
{
|
||||
id: 'colorRangeLegend',
|
||||
value: (
|
||||
<ColorRangeLegend
|
||||
colorRange={colorRange}
|
||||
title={i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.exploration.colorRangeLegendTitle',
|
||||
{
|
||||
defaultMessage: 'Feature influence score',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
]
|
||||
: HEADER_ITEMS_LOADING;
|
||||
};
|
||||
|
||||
interface ExpandableSectionResultsProps {
|
||||
colorRange?: ReturnType<typeof useColorRange>;
|
||||
indexData: UseIndexDataReturnType;
|
||||
indexPattern?: IndexPattern;
|
||||
jobConfig?: DataFrameAnalyticsConfig;
|
||||
needsDestIndexPattern: boolean;
|
||||
searchQuery: SavedSearchQuery;
|
||||
}
|
||||
|
||||
export const ExpandableSectionResults: FC<ExpandableSectionResultsProps> = ({
|
||||
colorRange,
|
||||
indexData,
|
||||
indexPattern,
|
||||
jobConfig,
|
||||
needsDestIndexPattern,
|
||||
searchQuery,
|
||||
}) => {
|
||||
const { columnsWithCharts, tableItems } = indexData;
|
||||
|
||||
// Results section header items and content
|
||||
const resultsSectionHeaderItems = getResultsSectionHeaderItems(
|
||||
columnsWithCharts,
|
||||
tableItems,
|
||||
indexData.rowCount,
|
||||
colorRange
|
||||
);
|
||||
const resultsSectionContent = (
|
||||
<>
|
||||
{jobConfig !== undefined && needsDestIndexPattern && (
|
||||
<div className="mlExpandableSection-contentPadding">
|
||||
<IndexPatternPrompt destIndex={jobConfig.dest.index} />
|
||||
</div>
|
||||
)}
|
||||
{jobConfig !== undefined &&
|
||||
(isRegressionAnalysis(jobConfig.analysis) ||
|
||||
isClassificationAnalysis(jobConfig.analysis)) && (
|
||||
<EuiText size="xs" color="subdued" className="mlExpandableSection-contentPadding">
|
||||
{tableItems.length === SEARCH_SIZE ? showingFirstDocs : showingDocs}
|
||||
</EuiText>
|
||||
)}
|
||||
{(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) &&
|
||||
indexPattern !== undefined && (
|
||||
<>
|
||||
{columnsWithCharts.length > 0 && tableItems.length > 0 && (
|
||||
<DataGrid
|
||||
{...indexData}
|
||||
dataTestSubj="mlExplorationDataGrid"
|
||||
toastNotifications={getToastNotifications()}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ExpandableSection
|
||||
dataTestId="results"
|
||||
content={resultsSectionContent}
|
||||
headerItems={resultsSectionHeaderItems}
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.explorationTableTitle"
|
||||
defaultMessage="Results"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -4,4 +4,10 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { ExpandableSection, ExpandableSectionProps } from './expandable_section';
|
||||
export {
|
||||
ExpandableSection,
|
||||
ExpandableSectionProps,
|
||||
HEADER_ITEMS_LOADING,
|
||||
} from './expandable_section';
|
||||
export { ExpandableSectionAnalytics } from './expandable_section_analytics';
|
||||
export { ExpandableSectionResults } from './expandable_section_results';
|
||||
|
|
|
@ -4,20 +4,49 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { FC, useState } from 'react';
|
||||
import React, { FC, useEffect, useState } from 'react';
|
||||
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { useResultsViewConfig, DataFrameAnalyticsConfig } from '../../../../common';
|
||||
import { ResultsSearchQuery, defaultSearchQuery } from '../../../../common/analytics';
|
||||
import { useUrlState } from '../../../../../util/url_state';
|
||||
|
||||
import {
|
||||
defaultSearchQuery,
|
||||
getDefaultTrainingFilterQuery,
|
||||
useResultsViewConfig,
|
||||
DataFrameAnalyticsConfig,
|
||||
} from '../../../../common';
|
||||
import { ResultsSearchQuery } from '../../../../common/analytics';
|
||||
|
||||
import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common';
|
||||
|
||||
import { ExpandableSectionAnalytics } from '../expandable_section';
|
||||
import { ExplorationResultsTable } from '../exploration_results_table';
|
||||
import { ExplorationQueryBar } from '../exploration_query_bar';
|
||||
import { JobConfigErrorCallout } from '../job_config_error_callout';
|
||||
import { LoadingPanel } from '../loading_panel';
|
||||
import { FeatureImportanceSummaryPanelProps } from '../total_feature_importance_summary/feature_importance_summary';
|
||||
|
||||
const filters = {
|
||||
options: [
|
||||
{
|
||||
id: 'training',
|
||||
label: i18n.translate('xpack.ml.dataframe.analytics.explorationResults.trainingSubsetLabel', {
|
||||
defaultMessage: 'Training',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 'testing',
|
||||
label: i18n.translate('xpack.ml.dataframe.analytics.explorationResults.testingSubsetLabel', {
|
||||
defaultMessage: 'Testing',
|
||||
}),
|
||||
},
|
||||
],
|
||||
columnId: 'ml.is_training',
|
||||
key: { training: true, testing: false },
|
||||
};
|
||||
|
||||
export interface EvaluatePanelProps {
|
||||
jobConfig: DataFrameAnalyticsConfig;
|
||||
jobStatus?: DATA_FRAME_TASK_STATE;
|
||||
|
@ -50,7 +79,25 @@ export const ExplorationPageWrapper: FC<Props> = ({
|
|||
needsDestIndexPattern,
|
||||
totalFeatureImportance,
|
||||
} = useResultsViewConfig(jobId);
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState<ResultsSearchQuery>(defaultSearchQuery);
|
||||
const [globalState, setGlobalState] = useUrlState('_g');
|
||||
const [defaultQueryString, setDefaultQueryString] = useState<string | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultIsTraining !== undefined && jobConfig !== undefined) {
|
||||
// Apply defaultIsTraining filter
|
||||
setSearchQuery(
|
||||
getDefaultTrainingFilterQuery(jobConfig.dest.results_field, defaultIsTraining)
|
||||
);
|
||||
setDefaultQueryString(`${jobConfig.dest.results_field}.is_training : ${defaultIsTraining}`);
|
||||
// Clear defaultIsTraining from url
|
||||
setGlobalState('ml', {
|
||||
analysisType: globalState.ml.analysisType,
|
||||
jobId: globalState.ml.jobId,
|
||||
});
|
||||
}
|
||||
}, [jobConfig?.dest.results_field]);
|
||||
|
||||
if (jobConfigErrorMessage !== undefined || jobCapsServiceErrorMessage !== undefined) {
|
||||
return (
|
||||
|
@ -61,21 +108,54 @@ export const ExplorationPageWrapper: FC<Props> = ({
|
|||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{typeof jobConfig?.description !== 'undefined' && (
|
||||
<>
|
||||
<EuiText>{jobConfig?.description}</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
)}
|
||||
|
||||
{indexPattern !== undefined && (
|
||||
<>
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
<EuiFlexItem>
|
||||
<ExplorationQueryBar
|
||||
indexPattern={indexPattern}
|
||||
setSearchQuery={setSearchQuery}
|
||||
defaultQueryString={defaultQueryString}
|
||||
filters={filters}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
)}
|
||||
|
||||
{isLoadingJobConfig === true && jobConfig === undefined && <LoadingPanel />}
|
||||
{isLoadingJobConfig === false && jobConfig !== undefined && isInitialized === true && (
|
||||
<EvaluatePanel jobConfig={jobConfig} jobStatus={jobStatus} searchQuery={searchQuery} />
|
||||
<ExpandableSectionAnalytics jobId={jobConfig.id} />
|
||||
)}
|
||||
|
||||
{isLoadingJobConfig === true && totalFeatureImportance === undefined && <LoadingPanel />}
|
||||
{isLoadingJobConfig === false && totalFeatureImportance !== undefined && (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<FeatureImportanceSummaryPanel totalFeatureImportance={totalFeatureImportance} />
|
||||
</>
|
||||
)}
|
||||
|
||||
<EuiSpacer />
|
||||
{isLoadingJobConfig === true && jobConfig === undefined && <LoadingPanel />}
|
||||
{isLoadingJobConfig === false && jobConfig !== undefined && isInitialized === true && (
|
||||
<EvaluatePanel jobConfig={jobConfig} jobStatus={jobStatus} searchQuery={searchQuery} />
|
||||
)}
|
||||
|
||||
{isLoadingJobConfig === true && jobConfig === undefined && <LoadingPanel />}
|
||||
{isLoadingJobConfig === false &&
|
||||
jobConfig !== undefined &&
|
||||
|
@ -86,9 +166,7 @@ export const ExplorationPageWrapper: FC<Props> = ({
|
|||
jobConfig={jobConfig}
|
||||
jobStatus={jobStatus}
|
||||
needsDestIndexPattern={needsDestIndexPattern}
|
||||
setEvaluateSearchQuery={setSearchQuery}
|
||||
title={title}
|
||||
defaultIsTraining={defaultIsTraining}
|
||||
searchQuery={searchQuery}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -4,118 +4,37 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { Fragment, FC, useEffect, useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
import { IndexPattern } from '../../../../../../../../../../src/plugins/data/public';
|
||||
|
||||
import { DataGrid } from '../../../../../components/data_grid';
|
||||
import { SavedSearchQuery } from '../../../../../contexts/ml';
|
||||
import { getToastNotifications } from '../../../../../util/dependency_cache';
|
||||
import { useMlKibana } from '../../../../../contexts/kibana';
|
||||
|
||||
import { DataFrameAnalyticsConfig } from '../../../../common';
|
||||
import { ResultsSearchQuery } from '../../../../common/analytics';
|
||||
|
||||
import {
|
||||
DataFrameAnalyticsConfig,
|
||||
MAX_COLUMNS,
|
||||
SEARCH_SIZE,
|
||||
defaultSearchQuery,
|
||||
getAnalysisType,
|
||||
getDefaultTrainingFilterQuery,
|
||||
} from '../../../../common';
|
||||
import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/use_columns';
|
||||
import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common';
|
||||
import { ExplorationTitle } from '../exploration_title';
|
||||
import { ExplorationQueryBar } from '../exploration_query_bar';
|
||||
import { IndexPatternPrompt } from '../index_pattern_prompt';
|
||||
|
||||
import { ExpandableSectionResults } from '../expandable_section';
|
||||
|
||||
import { useExplorationResults } from './use_exploration_results';
|
||||
import { useMlKibana } from '../../../../../contexts/kibana';
|
||||
import { DataFrameAnalysisConfigType } from '../../../../../../../common/types/data_frame_analytics';
|
||||
import { useUrlState } from '../../../../../util/url_state';
|
||||
|
||||
const showingDocs = i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText',
|
||||
{
|
||||
defaultMessage: 'Showing documents for which predictions exist',
|
||||
}
|
||||
);
|
||||
|
||||
const showingFirstDocs = i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.explorationResults.firstDocumentsShownHelpText',
|
||||
{
|
||||
defaultMessage: 'Showing first {searchSize} documents for which predictions exist',
|
||||
values: { searchSize: SEARCH_SIZE },
|
||||
}
|
||||
);
|
||||
|
||||
const filters = {
|
||||
options: [
|
||||
{
|
||||
id: 'training',
|
||||
label: i18n.translate('xpack.ml.dataframe.analytics.explorationResults.trainingSubsetLabel', {
|
||||
defaultMessage: 'Training',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 'testing',
|
||||
label: i18n.translate('xpack.ml.dataframe.analytics.explorationResults.testingSubsetLabel', {
|
||||
defaultMessage: 'Testing',
|
||||
}),
|
||||
},
|
||||
],
|
||||
columnId: 'ml.is_training',
|
||||
key: { training: true, testing: false },
|
||||
};
|
||||
|
||||
interface Props {
|
||||
indexPattern: IndexPattern;
|
||||
jobConfig: DataFrameAnalyticsConfig;
|
||||
jobStatus?: DATA_FRAME_TASK_STATE;
|
||||
needsDestIndexPattern: boolean;
|
||||
setEvaluateSearchQuery: React.Dispatch<React.SetStateAction<object>>;
|
||||
title: string;
|
||||
defaultIsTraining?: boolean;
|
||||
searchQuery: ResultsSearchQuery;
|
||||
}
|
||||
|
||||
export const ExplorationResultsTable: FC<Props> = React.memo(
|
||||
({
|
||||
indexPattern,
|
||||
jobConfig,
|
||||
jobStatus,
|
||||
needsDestIndexPattern,
|
||||
setEvaluateSearchQuery,
|
||||
title,
|
||||
defaultIsTraining,
|
||||
}) => {
|
||||
({ indexPattern, jobConfig, jobStatus, needsDestIndexPattern, searchQuery }) => {
|
||||
const {
|
||||
services: {
|
||||
mlServices: { mlApiServices },
|
||||
},
|
||||
} = useMlKibana();
|
||||
const [globalState, setGlobalState] = useUrlState('_g');
|
||||
const [searchQuery, setSearchQuery] = useState<SavedSearchQuery>(defaultSearchQuery);
|
||||
const [defaultQueryString, setDefaultQueryString] = useState<string | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
setEvaluateSearchQuery(searchQuery);
|
||||
}, [JSON.stringify(searchQuery)]);
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultIsTraining !== undefined) {
|
||||
// Apply defaultIsTraining filter
|
||||
setSearchQuery(
|
||||
getDefaultTrainingFilterQuery(jobConfig.dest.results_field, defaultIsTraining)
|
||||
);
|
||||
setDefaultQueryString(`${jobConfig.dest.results_field}.is_training : ${defaultIsTraining}`);
|
||||
// Clear defaultIsTraining from url
|
||||
setGlobalState('ml', {
|
||||
analysisType: globalState.ml.analysisType,
|
||||
jobId: globalState.ml.jobId,
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const analysisType = getAnalysisType(jobConfig.analysis);
|
||||
|
||||
const classificationData = useExplorationResults(
|
||||
indexPattern,
|
||||
|
@ -125,83 +44,20 @@ export const ExplorationResultsTable: FC<Props> = React.memo(
|
|||
mlApiServices
|
||||
);
|
||||
|
||||
const docFieldsCount = classificationData.columnsWithCharts.length;
|
||||
const { columnsWithCharts, tableItems, visibleColumns } = classificationData;
|
||||
|
||||
if (jobConfig === undefined || classificationData === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiPanel
|
||||
grow={false}
|
||||
id="mlDataFrameAnalyticsTableResultsPanel"
|
||||
data-test-subj="mlDFAnalyticsExplorationTablePanel"
|
||||
>
|
||||
{needsDestIndexPattern && <IndexPatternPrompt destIndex={jobConfig.dest.index} />}
|
||||
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
<ExplorationTitle title={title} />
|
||||
</EuiFlexItem>
|
||||
{jobStatus !== undefined && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<span>{getTaskStateBadge(jobStatus)}</span>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="xs" responsive={false}>
|
||||
<EuiFlexItem style={{ textAlign: 'right' }}>
|
||||
{docFieldsCount > MAX_COLUMNS && (
|
||||
<EuiText size="s">
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.explorationResults.fieldSelection',
|
||||
{
|
||||
defaultMessage:
|
||||
'{selectedFieldsLength, number} of {docFieldsCount, number} {docFieldsCount, plural, one {field} other {fields}} selected',
|
||||
values: { selectedFieldsLength: visibleColumns.length, docFieldsCount },
|
||||
}
|
||||
)}
|
||||
</EuiText>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
{(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) && (
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
<EuiFlexItem>
|
||||
<ExplorationQueryBar
|
||||
indexPattern={indexPattern}
|
||||
setSearchQuery={setSearchQuery}
|
||||
defaultQueryString={defaultQueryString}
|
||||
filters={filters}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiFormRow
|
||||
helpText={tableItems.length === SEARCH_SIZE ? showingFirstDocs : showingDocs}
|
||||
>
|
||||
<Fragment />
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<DataGrid
|
||||
{...classificationData}
|
||||
dataTestSubj="mlExplorationDataGrid"
|
||||
toastNotifications={getToastNotifications()}
|
||||
analysisType={(analysisType as unknown) as DataFrameAnalysisConfigType}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
)}
|
||||
</EuiPanel>
|
||||
<div data-test-subj="mlDFAnalyticsExplorationTablePanel">
|
||||
<ExpandableSectionResults
|
||||
indexData={classificationData}
|
||||
indexPattern={indexPattern}
|
||||
jobConfig={jobConfig}
|
||||
needsDestIndexPattern={needsDestIndexPattern}
|
||||
searchQuery={searchQuery}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
|
||||
import { EuiTitle } from '@elastic/eui';
|
||||
|
||||
export const ExplorationTitle: FC<{ title: string }> = ({ title }) => (
|
||||
<EuiTitle size="xs">
|
||||
<span>{title}</span>
|
||||
</EuiTitle>
|
||||
);
|
|
@ -1,7 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { ExplorationTitle } from './exploration_title';
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import React, { FC } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiLink, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import { EuiLink, EuiText } from '@elastic/eui';
|
||||
import { useMlKibana } from '../../../../../contexts/kibana';
|
||||
|
||||
interface Props {
|
||||
|
@ -42,7 +42,6 @@ export const IndexPatternPrompt: FC<Props> = ({ destIndex }) => {
|
|||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -10,7 +10,6 @@ import { EuiCallOut, EuiLink, EuiPanel, EuiSpacer } from '@elastic/eui';
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { ExplorationTitle } from '../exploration_title';
|
||||
import { useMlKibana } from '../../../../../contexts/kibana';
|
||||
|
||||
const jobConfigErrorTitle = i18n.translate('xpack.ml.dataframe.analytics.jobConfig.errorTitle', {
|
||||
|
@ -63,7 +62,6 @@ export const JobConfigErrorCallout: FC<Props> = ({
|
|||
|
||||
return (
|
||||
<EuiPanel grow={false}>
|
||||
<ExplorationTitle title={title} />
|
||||
<EuiSpacer />
|
||||
<EuiCallOut
|
||||
title={jobConfigErrorMessage ? jobConfigErrorTitle : jobCapsErrorTitle}
|
||||
|
|
|
@ -5,10 +5,13 @@
|
|||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
import { EuiLoadingSpinner, EuiPanel } from '@elastic/eui';
|
||||
import { EuiLoadingSpinner, EuiPanel, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
export const LoadingPanel: FC = () => (
|
||||
<EuiPanel className="eui-textCenter">
|
||||
<EuiLoadingSpinner size="xl" />
|
||||
</EuiPanel>
|
||||
<>
|
||||
<EuiPanel className="eui-textCenter">
|
||||
<EuiLoadingSpinner size="xl" />
|
||||
</EuiPanel>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -4,124 +4,25 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState, FC } from 'react';
|
||||
import React, { useState, FC } from 'react';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import {
|
||||
EuiDataGridColumn,
|
||||
EuiHorizontalRule,
|
||||
EuiLoadingSpinner,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import type { DataFrameAnalysisConfigType } from '../../../../../../../common/types/data_frame_analytics';
|
||||
import { EuiSpacer, EuiText } from '@elastic/eui';
|
||||
|
||||
import {
|
||||
useColorRange,
|
||||
COLOR_RANGE,
|
||||
COLOR_RANGE_SCALE,
|
||||
} from '../../../../../components/color_range_legend';
|
||||
import { ColorRangeLegend } from '../../../../../components/color_range_legend';
|
||||
import { DataGrid } from '../../../../../components/data_grid';
|
||||
import { SavedSearchQuery } from '../../../../../contexts/ml';
|
||||
import { getToastNotifications } from '../../../../../util/dependency_cache';
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
|
||||
import { getAnalysisType, defaultSearchQuery, useResultsViewConfig } from '../../../../common';
|
||||
import { defaultSearchQuery, useResultsViewConfig } from '../../../../common';
|
||||
|
||||
import { isGetDataFrameAnalyticsStatsResponseOk } from '../../../analytics_management/services/analytics_service/get_analytics';
|
||||
|
||||
import {
|
||||
DataFrameAnalyticsListRow,
|
||||
DATA_FRAME_MODE,
|
||||
} from '../../../analytics_management/components/analytics_list/common';
|
||||
import { ExpandedRow } from '../../../analytics_management/components/analytics_list/expanded_row';
|
||||
|
||||
import { ExpandableSection, ExpandableSectionProps } from '../expandable_section';
|
||||
import { ExpandableSectionAnalytics, ExpandableSectionResults } from '../expandable_section';
|
||||
import { ExplorationQueryBar } from '../exploration_query_bar';
|
||||
import { IndexPatternPrompt } from '../index_pattern_prompt';
|
||||
|
||||
import { getFeatureCount } from './common';
|
||||
import { useOutlierData } from './use_outlier_data';
|
||||
|
||||
const getAnalyticsSectionHeaderItems = (
|
||||
expandedRowItem: DataFrameAnalyticsListRow | undefined
|
||||
): ExpandableSectionProps['headerItems'] => {
|
||||
return expandedRowItem !== undefined
|
||||
? [
|
||||
{
|
||||
id: 'analysisTypeLabel',
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.analysisTypeLabel"
|
||||
defaultMessage="Type"
|
||||
/>
|
||||
),
|
||||
value: expandedRowItem.job_type,
|
||||
},
|
||||
{
|
||||
id: 'analysisSourceIndexLabel',
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.analysisSourceIndexLabel"
|
||||
defaultMessage="Source index"
|
||||
/>
|
||||
),
|
||||
value: expandedRowItem.config.source.index,
|
||||
},
|
||||
{
|
||||
id: 'analysisDestinationIndexLabel',
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.analysisDestinationIndexLabel"
|
||||
defaultMessage="Destination index"
|
||||
/>
|
||||
),
|
||||
value: expandedRowItem.config.dest.index,
|
||||
},
|
||||
]
|
||||
: 'loading';
|
||||
};
|
||||
|
||||
const getResultsSectionHeaderItems = (
|
||||
columnsWithCharts: EuiDataGridColumn[],
|
||||
tableItems: Array<Record<string, any>>,
|
||||
rowCount: number,
|
||||
colorRange: ReturnType<typeof useColorRange>
|
||||
): ExpandableSectionProps['headerItems'] => {
|
||||
return columnsWithCharts.length > 0 && tableItems.length > 0
|
||||
? [
|
||||
{
|
||||
id: 'explorationTableTotalDocs',
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.explorationTableTotalDocsLabel"
|
||||
defaultMessage="Total docs"
|
||||
/>
|
||||
),
|
||||
value: rowCount,
|
||||
},
|
||||
{
|
||||
id: 'colorRangeLegend',
|
||||
value: (
|
||||
<ColorRangeLegend
|
||||
colorRange={colorRange}
|
||||
title={i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.exploration.colorRangeLegendTitle',
|
||||
{
|
||||
defaultMessage: 'Feature influence score',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]
|
||||
: 'loading';
|
||||
};
|
||||
|
||||
export type TableItem = Record<string, any>;
|
||||
|
||||
interface ExplorationProps {
|
||||
|
@ -141,89 +42,14 @@ export const OutlierExploration: FC<ExplorationProps> = React.memo(({ jobId }) =
|
|||
jobConfig !== undefined ? getFeatureCount(jobConfig.dest.results_field, tableItems) : 1
|
||||
);
|
||||
|
||||
const [expandedRowItem, setExpandedRowItem] = useState<DataFrameAnalyticsListRow | undefined>();
|
||||
|
||||
const fetchStats = async () => {
|
||||
const analyticsConfigs = await ml.dataFrameAnalytics.getDataFrameAnalytics(jobId);
|
||||
const analyticsStats = await ml.dataFrameAnalytics.getDataFrameAnalyticsStats(jobId);
|
||||
|
||||
const config = analyticsConfigs.data_frame_analytics[0];
|
||||
const stats = isGetDataFrameAnalyticsStatsResponseOk(analyticsStats)
|
||||
? analyticsStats.data_frame_analytics[0]
|
||||
: undefined;
|
||||
|
||||
if (stats === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newExpandedRowItem: DataFrameAnalyticsListRow = {
|
||||
checkpointing: {},
|
||||
config,
|
||||
id: config.id,
|
||||
job_type: getAnalysisType(config.analysis) as DataFrameAnalysisConfigType,
|
||||
mode: DATA_FRAME_MODE.BATCH,
|
||||
state: stats.state,
|
||||
stats,
|
||||
};
|
||||
|
||||
setExpandedRowItem(newExpandedRowItem);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchStats();
|
||||
}, [jobConfig?.id]);
|
||||
|
||||
// Analytics section header items and content
|
||||
const analyticsSectionHeaderItems = getAnalyticsSectionHeaderItems(expandedRowItem);
|
||||
const analyticsSectionContent = (
|
||||
<>
|
||||
<EuiHorizontalRule size="full" margin="none" />
|
||||
{expandedRowItem === undefined && (
|
||||
<EuiText textAlign="center">
|
||||
<EuiSpacer size="l" />
|
||||
<EuiLoadingSpinner size="l" />
|
||||
<EuiSpacer size="l" />
|
||||
</EuiText>
|
||||
)}
|
||||
{(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) &&
|
||||
indexPattern !== undefined &&
|
||||
jobConfig !== undefined &&
|
||||
columnsWithCharts.length > 0 &&
|
||||
tableItems.length > 0 &&
|
||||
expandedRowItem !== undefined && <ExpandedRow item={expandedRowItem} />}
|
||||
</>
|
||||
);
|
||||
|
||||
// Results section header items and content
|
||||
const resultsSectionHeaderItems = getResultsSectionHeaderItems(
|
||||
columnsWithCharts,
|
||||
tableItems,
|
||||
outlierData.rowCount,
|
||||
colorRange
|
||||
);
|
||||
const resultsSectionContent = (
|
||||
<>
|
||||
{jobConfig !== undefined && needsDestIndexPattern && (
|
||||
<IndexPatternPrompt destIndex={jobConfig.dest.index} />
|
||||
)}
|
||||
{(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) &&
|
||||
indexPattern !== undefined && (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
{columnsWithCharts.length > 0 && tableItems.length > 0 && (
|
||||
<DataGrid
|
||||
{...outlierData}
|
||||
dataTestSubj="mlExplorationDataGrid"
|
||||
toastNotifications={getToastNotifications()}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{typeof jobConfig?.description !== 'undefined' && (
|
||||
<>
|
||||
<EuiText>{jobConfig?.description}</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
)}
|
||||
{(columnsWithCharts.length > 0 || searchQuery !== defaultSearchQuery) &&
|
||||
indexPattern !== undefined && (
|
||||
<>
|
||||
|
@ -231,34 +57,15 @@ export const OutlierExploration: FC<ExplorationProps> = React.memo(({ jobId }) =
|
|||
<EuiSpacer size="m" />
|
||||
</>
|
||||
)}
|
||||
|
||||
<ExpandableSection
|
||||
dataTestId="analysis"
|
||||
content={analyticsSectionContent}
|
||||
headerItems={analyticsSectionHeaderItems}
|
||||
isExpanded={false}
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.analysisSectionTitle"
|
||||
defaultMessage="Analysis"
|
||||
/>
|
||||
}
|
||||
{typeof jobConfig?.id === 'string' && <ExpandableSectionAnalytics jobId={jobConfig?.id} />}
|
||||
<ExpandableSectionResults
|
||||
colorRange={colorRange}
|
||||
indexData={outlierData}
|
||||
indexPattern={indexPattern}
|
||||
jobConfig={jobConfig}
|
||||
needsDestIndexPattern={needsDestIndexPattern}
|
||||
searchQuery={searchQuery}
|
||||
/>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<ExpandableSection
|
||||
dataTestId="results"
|
||||
content={resultsSectionContent}
|
||||
headerItems={resultsSectionHeaderItems}
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.explorationTableTitle"
|
||||
defaultMessage="Results"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
EuiButtonEmpty,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiPanel,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
|
@ -27,9 +26,7 @@ import {
|
|||
Eval,
|
||||
DataFrameAnalyticsConfig,
|
||||
} from '../../../../common';
|
||||
import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/use_columns';
|
||||
import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common';
|
||||
import { EvaluateStat } from './evaluate_stat';
|
||||
import {
|
||||
isResultsSearchBoolQuery,
|
||||
isRegressionEvaluateResponse,
|
||||
|
@ -38,6 +35,10 @@ import {
|
|||
EMPTY_STAT,
|
||||
} from '../../../../common/analytics';
|
||||
|
||||
import { ExpandableSection } from '../expandable_section';
|
||||
|
||||
import { EvaluateStat } from './evaluate_stat';
|
||||
|
||||
interface Props {
|
||||
jobConfig: DataFrameAnalyticsConfig;
|
||||
jobStatus?: DATA_FRAME_TASK_STATE;
|
||||
|
@ -219,30 +220,16 @@ export const EvaluatePanel: FC<Props> = ({ jobConfig, jobStatus, searchQuery })
|
|||
}, [JSON.stringify(searchQuery)]);
|
||||
|
||||
return (
|
||||
<EuiPanel data-test-subj="mlDFAnalyticsRegressionExplorationEvaluatePanel">
|
||||
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="xs">
|
||||
<span>
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.regressionExploration.evaluateJobIdTitle',
|
||||
{
|
||||
defaultMessage: 'Evaluation of regression 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}>
|
||||
<>
|
||||
<ExpandableSection
|
||||
dataTestId="RegressionEvaluation"
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.regressionExploration.evaluateSectionTitle"
|
||||
defaultMessage="Model evaluation"
|
||||
/>
|
||||
}
|
||||
docsLink={
|
||||
<EuiButtonEmpty
|
||||
target="_blank"
|
||||
iconType="help"
|
||||
|
@ -257,195 +244,214 @@ export const EvaluatePanel: FC<Props> = ({ jobConfig, jobStatus, searchQuery })
|
|||
}
|
||||
)}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
headerItems={
|
||||
jobStatus !== undefined
|
||||
? [
|
||||
{
|
||||
id: 'jobStatus',
|
||||
label: i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.classificationExploration.evaluateJobStatusLabel',
|
||||
{
|
||||
defaultMessage: 'Job status',
|
||||
}
|
||||
),
|
||||
value: jobStatus,
|
||||
},
|
||||
]
|
||||
: []
|
||||
}
|
||||
contentPadding={true}
|
||||
content={
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xxs">
|
||||
<span>
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle',
|
||||
{
|
||||
defaultMessage: 'Generalization error',
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
</EuiTitle>
|
||||
{generalizationDocsCount !== null && (
|
||||
<EuiText size="xs" color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.regressionExploration.generalizationDocsCount"
|
||||
defaultMessage="{docsCount, plural, one {# doc} other {# docs}} evaluated"
|
||||
values={{ docsCount: generalizationDocsCount }}
|
||||
/>
|
||||
{isTrainingFilter === true && generalizationDocsCount === 0 && (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.regressionExploration.generalizationFilterText"
|
||||
defaultMessage=". Filtering for training data."
|
||||
/>
|
||||
)}
|
||||
</EuiText>
|
||||
)}
|
||||
<EuiSpacer />
|
||||
<EuiFlexGroup direction="column" gutterSize="none">
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
{/* First row stats */}
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionGenMSEstat'}
|
||||
isLoading={isLoadingGeneralization}
|
||||
title={generalizationEval.mse}
|
||||
statType={REGRESSION_STATS.MSE}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionGenRSquaredStat'}
|
||||
isLoading={isLoadingGeneralization}
|
||||
title={generalizationEval.rSquared}
|
||||
statType={REGRESSION_STATS.R_SQUARED}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{/* Second row stats */}
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionGenMsleStat'}
|
||||
isLoading={isLoadingGeneralization}
|
||||
title={generalizationEval.msle}
|
||||
statType={REGRESSION_STATS.MSLE}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionGenHuberStat'}
|
||||
isLoading={isLoadingGeneralization}
|
||||
title={generalizationEval.huber}
|
||||
statType={REGRESSION_STATS.HUBER}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{generalizationEval.error !== null && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="xs" color="danger">
|
||||
{isTrainingFilter === true &&
|
||||
generalizationDocsCount === 0 &&
|
||||
generalizationEval.error.includes('No documents found')
|
||||
? i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.regressionExploration.evaluateNoTestingDocsError',
|
||||
{
|
||||
defaultMessage: 'No testing documents found',
|
||||
}
|
||||
)
|
||||
: generalizationEval.error}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xxs">
|
||||
<span>
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.regressionExploration.trainingErrorTitle',
|
||||
{
|
||||
defaultMessage: 'Training error',
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
</EuiTitle>
|
||||
{trainingDocsCount !== null && (
|
||||
<EuiText size="xs" color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.regressionExploration.trainingDocsCount"
|
||||
defaultMessage="{docsCount, plural, one {# doc} other {# docs}} evaluated"
|
||||
values={{ docsCount: trainingDocsCount }}
|
||||
/>
|
||||
{isTrainingFilter === false && trainingDocsCount === 0 && (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.regressionExploration.trainingFilterText"
|
||||
defaultMessage=". Filtering for testing data."
|
||||
/>
|
||||
)}
|
||||
</EuiText>
|
||||
)}
|
||||
<EuiSpacer />
|
||||
<EuiFlexGroup direction="column" gutterSize="none">
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
{/* First row stats */}
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionTrainingMSEstat'}
|
||||
isLoading={isLoadingTraining}
|
||||
title={trainingEval.mse}
|
||||
statType={REGRESSION_STATS.MSE}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionTrainingRSquaredStat'}
|
||||
isLoading={isLoadingTraining}
|
||||
title={trainingEval.rSquared}
|
||||
statType={REGRESSION_STATS.R_SQUARED}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{/* Second row stats */}
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionTrainingMsleStat'}
|
||||
isLoading={isLoadingTraining}
|
||||
title={trainingEval.msle}
|
||||
statType={REGRESSION_STATS.MSLE}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionTrainingHuberStat'}
|
||||
isLoading={isLoadingTraining}
|
||||
title={trainingEval.huber}
|
||||
statType={REGRESSION_STATS.HUBER}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{trainingEval.error !== null && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="xs" color="danger">
|
||||
{isTrainingFilter === false &&
|
||||
trainingDocsCount === 0 &&
|
||||
trainingEval.error.includes('No documents found')
|
||||
? i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.regressionExploration.evaluateNoTrainingDocsError',
|
||||
{
|
||||
defaultMessage: 'No training documents found',
|
||||
}
|
||||
)
|
||||
: trainingEval.error}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xxs">
|
||||
<span>
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle',
|
||||
{
|
||||
defaultMessage: 'Generalization error',
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
</EuiTitle>
|
||||
{generalizationDocsCount !== null && (
|
||||
<EuiText size="xs" color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.regressionExploration.generalizationDocsCount"
|
||||
defaultMessage="{docsCount, plural, one {# doc} other {# docs}} evaluated"
|
||||
values={{ docsCount: generalizationDocsCount }}
|
||||
/>
|
||||
{isTrainingFilter === true && generalizationDocsCount === 0 && (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.regressionExploration.generalizationFilterText"
|
||||
defaultMessage=". Filtering for training data."
|
||||
/>
|
||||
)}
|
||||
</EuiText>
|
||||
)}
|
||||
<EuiSpacer />
|
||||
<EuiFlexGroup direction="column" gutterSize="none">
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
{/* First row stats */}
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionGenMSEstat'}
|
||||
isLoading={isLoadingGeneralization}
|
||||
title={generalizationEval.mse}
|
||||
statType={REGRESSION_STATS.MSE}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionGenRSquaredStat'}
|
||||
isLoading={isLoadingGeneralization}
|
||||
title={generalizationEval.rSquared}
|
||||
statType={REGRESSION_STATS.R_SQUARED}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{/* Second row stats */}
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionGenMsleStat'}
|
||||
isLoading={isLoadingGeneralization}
|
||||
title={generalizationEval.msle}
|
||||
statType={REGRESSION_STATS.MSLE}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionGenHuberStat'}
|
||||
isLoading={isLoadingGeneralization}
|
||||
title={generalizationEval.huber}
|
||||
statType={REGRESSION_STATS.HUBER}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{generalizationEval.error !== null && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="xs" color="danger">
|
||||
{isTrainingFilter === true &&
|
||||
generalizationDocsCount === 0 &&
|
||||
generalizationEval.error.includes('No documents found')
|
||||
? i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.regressionExploration.evaluateNoTestingDocsError',
|
||||
{
|
||||
defaultMessage: 'No testing documents found',
|
||||
}
|
||||
)
|
||||
: generalizationEval.error}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xxs">
|
||||
<span>
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.regressionExploration.trainingErrorTitle',
|
||||
{
|
||||
defaultMessage: 'Training error',
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
</EuiTitle>
|
||||
{trainingDocsCount !== null && (
|
||||
<EuiText size="xs" color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.regressionExploration.trainingDocsCount"
|
||||
defaultMessage="{docsCount, plural, one {# doc} other {# docs}} evaluated"
|
||||
values={{ docsCount: trainingDocsCount }}
|
||||
/>
|
||||
{isTrainingFilter === false && trainingDocsCount === 0 && (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.regressionExploration.trainingFilterText"
|
||||
defaultMessage=". Filtering for testing data."
|
||||
/>
|
||||
)}
|
||||
</EuiText>
|
||||
)}
|
||||
<EuiSpacer />
|
||||
<EuiFlexGroup direction="column" gutterSize="none">
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup direction="column" gutterSize="s">
|
||||
{/* First row stats */}
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionTrainingMSEstat'}
|
||||
isLoading={isLoadingTraining}
|
||||
title={trainingEval.mse}
|
||||
statType={REGRESSION_STATS.MSE}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionTrainingRSquaredStat'}
|
||||
isLoading={isLoadingTraining}
|
||||
title={trainingEval.rSquared}
|
||||
statType={REGRESSION_STATS.R_SQUARED}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{/* Second row stats */}
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionTrainingMsleStat'}
|
||||
isLoading={isLoadingTraining}
|
||||
title={trainingEval.msle}
|
||||
statType={REGRESSION_STATS.MSLE}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EvaluateStat
|
||||
dataTestSubj={'mlDFAnalyticsRegressionTrainingHuberStat'}
|
||||
isLoading={isLoadingTraining}
|
||||
title={trainingEval.huber}
|
||||
statType={REGRESSION_STATS.HUBER}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{trainingEval.error !== null && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="xs" color="danger">
|
||||
{isTrainingFilter === false &&
|
||||
trainingDocsCount === 0 &&
|
||||
trainingEval.error.includes('No documents found')
|
||||
? i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.regressionExploration.evaluateNoTrainingDocsError',
|
||||
{
|
||||
defaultMessage: 'No training documents found',
|
||||
}
|
||||
)
|
||||
: trainingEval.error}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,15 +5,7 @@
|
|||
*/
|
||||
|
||||
import React, { FC, useCallback, useMemo } from 'react';
|
||||
import {
|
||||
EuiButtonEmpty,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiIconTip,
|
||||
EuiPanel,
|
||||
EuiSpacer,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { EuiButtonEmpty, EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import {
|
||||
Chart,
|
||||
|
@ -38,6 +30,9 @@ import {
|
|||
} from '../../../../../../../common/types/feature_importance';
|
||||
|
||||
import { useMlKibana } from '../../../../../contexts/kibana';
|
||||
|
||||
import { ExpandableSection } from '../expandable_section';
|
||||
|
||||
const { euiColorMediumShade } = euiVars;
|
||||
const axisColor = euiColorMediumShade;
|
||||
|
||||
|
@ -194,71 +189,67 @@ export const FeatureImportanceSummaryPanel: FC<FeatureImportanceSummaryPanelProp
|
|||
const tickFormatter = useCallback((d) => Number(d.toPrecision(3)).toString(), []);
|
||||
|
||||
return (
|
||||
<EuiPanel>
|
||||
<div>
|
||||
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween">
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup gutterSize="xs">
|
||||
<EuiTitle size="xs">
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.featureImportanceSummaryTitle"
|
||||
defaultMessage="Total feature importance"
|
||||
/>
|
||||
</span>
|
||||
</EuiTitle>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip content={tooltipContent} />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</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-feature-importance.html`}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.featureImportanceDocsLink"
|
||||
defaultMessage="Feature importance docs"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</div>
|
||||
<Chart
|
||||
size={{
|
||||
width: '100%',
|
||||
height: chartHeight,
|
||||
}}
|
||||
>
|
||||
<Settings rotation={90} theme={theme} showLegend={showLegend} />
|
||||
<>
|
||||
<ExpandableSection
|
||||
dataTestId="FeatureImportanceSummary"
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.featureImportanceSummaryTitle"
|
||||
defaultMessage="Total feature importance"
|
||||
/>
|
||||
}
|
||||
docsLink={
|
||||
<EuiButtonEmpty
|
||||
target="_blank"
|
||||
iconType="help"
|
||||
iconSide="left"
|
||||
color="primary"
|
||||
href={`${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-feature-importance.html`}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.analytics.exploration.featureImportanceDocsLink"
|
||||
defaultMessage="Feature importance docs"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
}
|
||||
headerItems={[
|
||||
{
|
||||
id: 'FeatureImportanceSummary',
|
||||
value: tooltipContent,
|
||||
},
|
||||
]}
|
||||
content={
|
||||
<Chart
|
||||
size={{
|
||||
width: '100%',
|
||||
height: chartHeight,
|
||||
}}
|
||||
>
|
||||
<Settings rotation={90} theme={theme} showLegend={showLegend} />
|
||||
|
||||
<Axis
|
||||
id="x-axis"
|
||||
title={i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.exploration.featureImportanceXAxisTitle',
|
||||
{
|
||||
defaultMessage: 'Feature importance average magnitude',
|
||||
}
|
||||
)}
|
||||
position={Position.Bottom}
|
||||
tickFormat={tickFormatter}
|
||||
/>
|
||||
<Axis id="y-axis" title="" position={Position.Left} />
|
||||
<BarSeries
|
||||
id="magnitude"
|
||||
xScaleType={ScaleType.Ordinal}
|
||||
yScaleType={ScaleType.Linear}
|
||||
data={plotData}
|
||||
{...barSeriesSpec}
|
||||
/>
|
||||
</Chart>
|
||||
</EuiPanel>
|
||||
<Axis
|
||||
id="x-axis"
|
||||
title={i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.exploration.featureImportanceXAxisTitle',
|
||||
{
|
||||
defaultMessage: 'Feature importance average magnitude',
|
||||
}
|
||||
)}
|
||||
position={Position.Bottom}
|
||||
tickFormat={tickFormatter}
|
||||
/>
|
||||
<Axis id="y-axis" title="" position={Position.Left} />
|
||||
<BarSeries
|
||||
id="magnitude"
|
||||
xScaleType={ScaleType.Ordinal}
|
||||
yScaleType={ScaleType.Linear}
|
||||
data={plotData}
|
||||
{...barSeriesSpec}
|
||||
/>
|
||||
</Chart>
|
||||
}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,7 +12,6 @@ import {
|
|||
EuiPageContentBody,
|
||||
EuiPageContentHeader,
|
||||
EuiPageContentHeaderSection,
|
||||
EuiSpacer,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
|
@ -42,7 +41,6 @@ export const Page: FC<{
|
|||
</EuiPageContentHeaderSection>
|
||||
</EuiPageContentHeader>
|
||||
<EuiPageContentBody style={{ maxWidth: 'calc(100% - 0px)' }}>
|
||||
<EuiSpacer size="m" />
|
||||
{analysisType === ANALYSIS_CONFIG_TYPE.OUTLIER_DETECTION && (
|
||||
<OutlierExploration jobId={jobId} />
|
||||
)}
|
||||
|
|
|
@ -10550,7 +10550,6 @@
|
|||
"xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTestingHelpText": "データセットをテストするための正規化された混同行列",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTooltip": "マルチクラス混同行列には、分析が実際のクラスで正しくデータポイントを分類した発生数と、別のクラスで誤分類した発生数が含まれます。",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTrainingHelpText": "データセットを学習するための正規化された混同行列",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.evaluateJobIdTitle": "分類ジョブID {jobId}の評価",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.generalizationDocsCount": "{docsCount, plural, one {# doc} other {# docs}}が評価されました",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.showActions": "アクションを表示",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.showAllColumns": "すべての列を表示",
|
||||
|
@ -10753,13 +10752,11 @@
|
|||
"xpack.ml.dataframe.analytics.errorCallout.queryParsingErrorTitle": "クエリをパースできません。",
|
||||
"xpack.ml.dataframe.analytics.exploration.colorRangeLegendTitle": "機能影響スコア",
|
||||
"xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText": "予測があるドキュメントを示す",
|
||||
"xpack.ml.dataframe.analytics.explorationResults.fieldSelection": "{docFieldsCount, number}件中 showing {selectedFieldsLength, number}件の{docFieldsCount, plural, one {フィールド} other {フィールド}}",
|
||||
"xpack.ml.dataframe.analytics.explorationResults.firstDocumentsShownHelpText": "予測がある最初の{searchSize}のドキュメントを示す",
|
||||
"xpack.ml.dataframe.analytics.indexPatternPromptLinkText": "インデックスパターンを作成します",
|
||||
"xpack.ml.dataframe.analytics.indexPatternPromptMessage": "{destIndex}のインデックス{destIndex}. {linkToIndexPatternManagement}にはインデックスパターンが存在しません。",
|
||||
"xpack.ml.dataframe.analytics.jobCaps.errorTitle": "結果を取得できません。インデックスのフィールドデータの読み込み中にエラーが発生しました。",
|
||||
"xpack.ml.dataframe.analytics.jobConfig.errorTitle": "結果を取得できません。ジョブ構成データの読み込み中にエラーが発生しました。",
|
||||
"xpack.ml.dataframe.analytics.regressionExploration.evaluateJobIdTitle": "回帰ジョブID {jobId}の評価",
|
||||
"xpack.ml.dataframe.analytics.regressionExploration.generalizationDocsCount": "{docsCount, plural, one {# doc} other {# docs}}が評価されました",
|
||||
"xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle": "一般化エラー",
|
||||
"xpack.ml.dataframe.analytics.regressionExploration.generalizationFilterText": ".学習データをフィルタリングしています。",
|
||||
|
|
|
@ -10556,7 +10556,6 @@
|
|||
"xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTestingHelpText": "用于测试数据集的标准化混淆矩阵",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTooltip": "多类混淆矩阵包含分析使用数据点的实际类正确分类数据点的次数以及分析使用其他类错误分类这些数据点的次数",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.confusionMatrixTrainingHelpText": "用于训练数据集的标准化混淆矩阵",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.evaluateJobIdTitle": "分类作业 ID {jobId} 的评估",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.generalizationDocsCount": "{docsCount, plural, one {# 个文档} other {# 个文档}}已评估",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.showActions": "显示操作",
|
||||
"xpack.ml.dataframe.analytics.classificationExploration.showAllColumns": "显示所有列",
|
||||
|
@ -10759,13 +10758,11 @@
|
|||
"xpack.ml.dataframe.analytics.errorCallout.queryParsingErrorTitle": "无法解析查询。",
|
||||
"xpack.ml.dataframe.analytics.exploration.colorRangeLegendTitle": "功能影响分数",
|
||||
"xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText": "正在显示有相关预测存在的文档",
|
||||
"xpack.ml.dataframe.analytics.explorationResults.fieldSelection": "已选择 {docFieldsCount, number} 个{docFieldsCount, plural, one {字段} other {字段}}中的 {selectedFieldsLength, number} 个",
|
||||
"xpack.ml.dataframe.analytics.explorationResults.firstDocumentsShownHelpText": "正在显示有相关预测存在的前 {searchSize} 个文档",
|
||||
"xpack.ml.dataframe.analytics.indexPatternPromptLinkText": "创建索引模式",
|
||||
"xpack.ml.dataframe.analytics.indexPatternPromptMessage": "不存在索引 {destIndex} 的索引模式。{destIndex} 的{linkToIndexPatternManagement}。",
|
||||
"xpack.ml.dataframe.analytics.jobCaps.errorTitle": "无法提取结果。加载索引的字段数据时发生错误。",
|
||||
"xpack.ml.dataframe.analytics.jobConfig.errorTitle": "无法提取结果。加载作业配置数据时发生错误。",
|
||||
"xpack.ml.dataframe.analytics.regressionExploration.evaluateJobIdTitle": "回归作业 ID {jobId} 的评估",
|
||||
"xpack.ml.dataframe.analytics.regressionExploration.generalizationDocsCount": "{docsCount, plural, one {# 个文档} other {# 个文档}}已评估",
|
||||
"xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle": "泛化误差",
|
||||
"xpack.ml.dataframe.analytics.regressionExploration.generalizationFilterText": ".筛留训练数据。",
|
||||
|
|
|
@ -15,7 +15,7 @@ export function MachineLearningDataFrameAnalyticsResultsProvider({
|
|||
|
||||
return {
|
||||
async assertRegressionEvaluatePanelElementsExists() {
|
||||
await testSubjects.existOrFail('mlDFAnalyticsRegressionExplorationEvaluatePanel');
|
||||
await testSubjects.existOrFail('mlDFExpandableSection-RegressionEvaluation');
|
||||
await testSubjects.existOrFail('mlDFAnalyticsRegressionGenMSEstat');
|
||||
await testSubjects.existOrFail('mlDFAnalyticsRegressionGenRSquaredStat');
|
||||
await testSubjects.existOrFail('mlDFAnalyticsRegressionTrainingMSEstat');
|
||||
|
@ -27,7 +27,7 @@ export function MachineLearningDataFrameAnalyticsResultsProvider({
|
|||
},
|
||||
|
||||
async assertClassificationEvaluatePanelElementsExists() {
|
||||
await testSubjects.existOrFail('mlDFAnalyticsClassificationExplorationEvaluatePanel');
|
||||
await testSubjects.existOrFail('mlDFExpandableSection-ClassificationEvaluation');
|
||||
await testSubjects.existOrFail('mlDFAnalyticsClassificationExplorationConfusionMatrix');
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in a new issue