-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Maps][ML] Integration part 1: Create anomalies layer in maps #122862
[Maps][ML] Integration part 1: Create anomalies layer in maps #122862
Conversation
3c5fbc9
to
2273e4d
Compare
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.
This looks really great from Maps-perspective.
It will be really useful to users to easily map results from spatial anomaly detection.
Below some UX suggestions mostly, but nothing blocking AFAIC.
style: { | ||
type: 'VECTOR', | ||
properties: { | ||
fillColor: { |
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.
consider setting this same property for lineColor
. That way, when users select "connected", they see the same symbology:
properties: {
fillColor: {
type: STYLE_TYPE.DYNAMIC,
options: {
customColorRamp: SEVERITY_COLOR_RAMP,
field: {
name: 'record_score',
origin: FIELD_ORIGIN.SOURCE,
},
useCustomColorRamp: true,
},
},
lineColor: {
type: STYLE_TYPE.DYNAMIC,
options: {
customColorRamp: SEVERITY_COLOR_RAMP,
field: {
name: 'record_score',
origin: FIELD_ORIGIN.SOURCE,
},
useCustomColorRamp: true,
},
},
} as unknown as VectorStylePropertiesDescriptor,
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.
Added in e121d6724193fd765c79cc6fb03af95cb4377510
}), | ||
icon: 'outlierDetectionJob', | ||
getIsDisabled: () => { | ||
// return false by default |
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.
Consider having this check for enterprise license. For an example, see the track layer wizard.
kibana/x-pack/plugins/maps/public/classes/sources/es_geo_line_source/layer_wizard.tsx
Lines 25 to 29 in 0675a6a
disabledReason: REQUIRES_GOLD_LICENSE_MSG, | |
icon: TracksLayerIcon, | |
getIsDisabled: () => { | |
return !getIsGoldPlus(); | |
}, |
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.
This is checked in the plugin setup and passed through to the layer wizard https://github.com/elastic/kibana/pull/122862/files#diff-9658f57fcb39c79f75a675c515053ccb46c515a7e9f9eac7ecb200d21c3af09aR172
This default is just a placeholder.
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.
ah makes sense, thx! (I missed that)
fwiw: you could still register the card, but in "disabled" state. That way the card is still visible (but in disabled grayed-out state) . The advantage is that this feature would still be advertized for non-enterprise users.
return ( | ||
<EuiFormRow | ||
label={i18n.translate('xpack.ml.maps.jobIdLabel', { | ||
defaultMessage: 'JobId', |
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.
nit: consider Job Id
.
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.
extra nit - we tend to use Job ID
in ML
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.
Updated in e121d6724193fd765c79cc6fb03af95cb4377510
selectedOptions={ | ||
this.state.jobId ? [{ value: this.state.jobId, label: this.state.jobId }] : [] | ||
} | ||
/> |
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.
nit: consider adding some explanatory text.
e.g. a little help box about what this is.
e.g.: something along the lines of:
Select anomaly detection job using spatial outlier detection. These use the lon_lat_detector function. LinkToDoc, LinkToMLApp
.
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.
Added to follow-ups as I'll need to craft a good explanation message. 👍
import type { LayerWizard } from '../../../maps/public'; | ||
|
||
export const anomalyLayerWizard: Partial<LayerWizard> = { | ||
categories: [LAYER_WIZARD_CATEGORY.SOLUTIONS], |
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.
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.
Added in e121d6724193fd765c79cc6fb03af95cb4377510
typicalActual={this.props.typicalActual} | ||
/> | ||
</EuiPanel> | ||
<EuiSpacer size="s" /> |
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.
Would it be useful to add a switch here to turn on/off "time-awareness".
E.g. something along the lines of:
E.g. add another property applyGlobalTime
to the source-descriptor.
export interface AnomalySourceDescriptor extends AbstractSourceDescriptor {
jobId: string;
typicalActual: MlAnomalyLayers;
applyGlobalTime: boolean;
}
The switch controls the value of applyGlobalTime
.
Then implement AnomalySource#isTimeAware
as:
async isTimeAware(): Promise<boolean> {
return this._descriptor.applyGlobalTime;
}
This way you can turn on/off whether users will see all the data (regardless of time-selection), or only a cut of the data.
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.
Sounds like a good one to discuss for a follow-up 👍
defaultMessage: 'Job Id', | ||
}), | ||
value: this._descriptor.jobId, | ||
}, |
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.
Consider adding second object with hyperlink to the anomaly-explorer page in ML based on the job-Id.
e.g. this is some sample code.
kibana/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.tsx
Lines 156 to 162 in 6a3d194
{ | |
label: i18n.translate('xpack.maps.source.emsFile.layerLabel', { | |
defaultMessage: `Layer`, | |
}), | |
value: this._descriptor.id, | |
link: emsLink, | |
}, |
So for ML, it'd be something like:
return [
{
label: i18n.translate('xpack.ml.maps.anomalySourcePropLabel', {
defaultMessage: 'Job Id',
}),
value: this._descriptor.jobId,
link: `http://localhost:5601/hen/app/ml/explorer?_g={jobIds:[%22${this._jobId}%22]` // todo: this link should be constructed with `core.http.basePath.prepend()` and utilities there are on ML-side to derive this URL
},
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.
Added for a follow up 👍
Pinging @elastic/kibana-gis (Team:Geo) |
Pinging @elastic/ml-ui (:ml) |
x-pack/plugins/ml/public/application/services/ml_api_service/jobs.ts
Outdated
Show resolved
Hide resolved
private getStartServices: StartServicesAccessor<MlStartDependencies, MlPluginStart>, | ||
private canGetJobs: boolean | ||
) { | ||
this.canGetJobs = canGetJobs; |
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.
this line seems redundant
this.canGetJobs = canGetJobs; |
x-pack/plugins/ml/public/plugin.ts
Outdated
@@ -113,6 +114,7 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> { | |||
licenseManagement: pluginsSetup.licenseManagement, | |||
home: pluginsSetup.home, | |||
embeddable: { ...pluginsSetup.embeddable, ...pluginsStart.embeddable }, | |||
// @ts-ignore |
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.
can we remove this ts-ignore?
|
||
if (pluginsSetup.maps) { | ||
// Pass capabilites.ml.canGetJobs as minimum permission to show anomalies card in maps layers | ||
const canGetJobs = capabilities.ml?.canGetJobs === true || false; |
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.
nit:
const canGetJobs = capabilities.ml?.canGetJobs === true || false; | |
const canGetJobs = !!capabilities.ml?.canGetJobs; |
onChange={this.onSelect} | ||
options={[ | ||
{ value: 'typical', label: 'typical' }, | ||
{ value: 'actual', label: 'actual' }, |
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.
I wonder if it makes more sense for actual
to be the top, default option?
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.
Good call - updated in c88762c614ab8c03be504dbde24242d5bacf1107
import { ITooltipProperty } from '../../../maps/public'; | ||
import { Filter } from '../../../../../src/plugins/data/public'; | ||
|
||
export const ANOMALY_SOURCE_FIELDS: Record<string, Record<string, string>> = { |
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.
Are these strings used for the tooltip text? If so, I think they need to be internationalized.
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.
Updated in c88762c614ab8c03be504dbde24242d5bacf1107
timestamp: { label: 'Timestamp', type: 'string' }, | ||
fieldName: { label: 'Field label', type: 'string' }, | ||
functionDescription: { label: 'Function description', type: 'string' }, | ||
actual: { label: 'Actual', type: 'string' }, |
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.
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.
Updated in c88762c614ab8c03be504dbde24242d5bacf1107
import { ITooltipProperty } from '../../../maps/public'; | ||
import { Filter } from '../../../../../src/plugins/data/public'; | ||
|
||
export const ANOMALY_SOURCE_FIELDS: Record<string, Record<string, string>> = { |
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.
Could we get the partitioning field names and values in the tooltip too?
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.
Added to follow up 👍
export const anomalyLayerWizard: Partial<LayerWizard> = { | ||
categories: [LAYER_WIZARD_CATEGORY.SOLUTIONS], | ||
description: i18n.translate('xpack.ml.maps.anomalyLayerDescription', { | ||
defaultMessage: 'Create anomalies layers', |
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.
This message needs editing I think - something like Display anomalies from a machine learning job
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.
Updated in c88762c614ab8c03be504dbde24242d5bacf1107
}), | ||
disabledReason: i18n.translate('xpack.ml.maps.anomalyLayerUnavailableMessage', { | ||
defaultMessage: | ||
'Whatever reason the user cannot see ML card (likely because no enterprise license or no ML privileges)', |
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.
This message needs some work
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.
Updated in c88762c614ab8c03be504dbde24242d5bacf1107
const typicalActual: MlAnomalyLayers = selectedOptions[0].value! as | ||
| 'typical' | ||
| 'actual' | ||
| 'connected'; |
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.
I assume this shows a line from the typical position to the actual? If so, I'm not sure connected
is the most intuitive label. Can't think of an alternative though!
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.
It is - I also couldn't think of anything more intuitive but am super open to suggestions 🙏
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.
gis code owners changes LGTM
code review
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.
🚀 This is a great integration. It makes the geo-anomaly-detection capabilities of ML more visible in Maps, and it allows "mashing-up" of these anomaly-layers with other contextual data. Also adds embeddability of maps with anomaly-layers, something which was not possible before It also sets the stage for better cross-linking of Maps/ML (e.g. open in Maps-button from the ML-UX).
7cd7abb
to
f66f8a6
Compare
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.
LGTM
💚 Build Succeeded
Metrics [docs]Module Count
Public APIs missing comments
Async chunks
Public APIs missing exports
Page load bundle
Unknown metric groupsAPI count
async chunk count
ESLint disabled line counts
References to deprecated APIs
Total ESLint disabled count
History
To update your PR or re-run it, just comment with: |
Follow ups tracked in meta issue #123492 |
Summary
Related draft PR: #113857
Extends and updates #90497
Incorporates latest maps changes (#112465, #112333) into initial draft PR (#111228)
getResultsForJobId
needs a unit test and can be converted to service (for follow up)Nice to have:
Screenshots
Anomalies layer card in maps:
Job selection for jobs that contain supported geo data:
Layers available:
Tooltip:
Checklist
Delete any items that are not applicable to this PR.