Skip to content
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

Add Compare Runs metric section #2798

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions frontend/src/concepts/pipelines/apiHooks/mlmd/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Artifact, Context, ContextType, Event } from '~/third_party/mlmd';
import { Artifact, Context, ContextType, Event, Execution } from '~/third_party/mlmd';
import { PipelineRunKFv2 } from '~/concepts/pipelines/kfTypes';

export type MlmdContext = Context;

Expand All @@ -8,9 +9,20 @@ export enum MlmdContextTypes {
RUN = 'system.PipelineRun',
}

// An artifact which has associated event.
// You can retrieve artifact name from event.path.steps[0].key
export interface LinkedArtifact {
// each artifact is linked to an event
export type LinkedArtifact = {
event: Event;
artifact: Artifact;
}
};

// each execution can have multiple output artifacts
export type ExecutionArtifact = {
execution: Execution;
linkedArtifacts: LinkedArtifact[];
};

// each run has multiple executions, each execution can have multiple artifacts
export type RunArtifact = {
run: PipelineRunKFv2;
executionArtifacts: ExecutionArtifact[];
};
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import React from 'react';
import { usePipelinesAPI } from '~/concepts/pipelines/context';
import { GetArtifactTypesRequest } from '~/third_party/mlmd';
import { ArtifactType, GetArtifactTypesRequest } from '~/third_party/mlmd';
import useFetchState, { FetchState, FetchStateCallbackPromise } from '~/utilities/useFetchState';

export const useGetArtifactTypeMap = (): FetchState<Record<number, string>> => {
export const useGetArtifactTypes = (): FetchState<ArtifactType[]> => {
const { metadataStoreServiceClient } = usePipelinesAPI();

const call = React.useCallback<FetchStateCallbackPromise<Record<number, string>>>(async () => {
const call = React.useCallback<FetchStateCallbackPromise<ArtifactType[]>>(async () => {
const request = new GetArtifactTypesRequest();

const res = await metadataStoreServiceClient.getArtifactTypes(request);

const artifactTypeMap: Record<number, string> = {};
res.getArtifactTypesList().forEach((artifactType) => {
artifactTypeMap[artifactType.getId()] = artifactType.getName();
});
return artifactTypeMap;
return res.getArtifactTypesList();
}, [metadataStoreServiceClient]);

return useFetchState(call, {});
return useFetchState(call, []);
};
23 changes: 17 additions & 6 deletions frontend/src/concepts/pipelines/apiHooks/mlmd/useMlmdContext.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
import React from 'react';
import { MlmdContext, MlmdContextTypes } from '~/concepts/pipelines/apiHooks/mlmd/types';
import { usePipelinesAPI } from '~/concepts/pipelines/context';
import { GetContextByTypeAndNameRequest } from '~/third_party/mlmd';
import {
GetContextByTypeAndNameRequest,
MetadataStoreServicePromiseClient,
} from '~/third_party/mlmd';
import useFetchState, {
FetchState,
FetchStateCallbackPromise,
NotReadyError,
} from '~/utilities/useFetchState';

export const getMlmdContext = async (
client: MetadataStoreServicePromiseClient,
name: string,
type: MlmdContextTypes,
): Promise<MlmdContext | undefined> => {
const request = new GetContextByTypeAndNameRequest();
request.setTypeName(type);
request.setContextName(name);
const res = await client.getContextByTypeAndName(request);
return res.getContext();
};

/**
* A hook used to use the MLMD service and fetch the MLMD context
* If being used without name/type, this hook will throw an error
Expand All @@ -28,11 +43,7 @@ export const useMlmdContext = (
return Promise.reject(new NotReadyError('No context name'));
}

const request = new GetContextByTypeAndNameRequest();
request.setTypeName(type);
request.setContextName(name);
const res = await metadataStoreServiceClient.getContextByTypeAndName(request);
const context = res.getContext();
const context = await getMlmdContext(metadataStoreServiceClient, name, type);
if (!context) {
return Promise.reject(new Error('Cannot find specified context'));
}
Expand Down
121 changes: 121 additions & 0 deletions frontend/src/concepts/pipelines/content/artifacts/charts/ROCCurve.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React from 'react';
import {
Chart,
ChartAxis,
ChartGroup,
ChartLine,
ChartVoronoiContainer,
} from '@patternfly/react-charts';
import {
chart_color_blue_100 as chartColorBlue100,
chart_color_blue_200 as chartColorBlue200,
chart_color_blue_300 as chartColorBlue300,
chart_color_blue_400 as chartColorBlue400,
chart_color_blue_500 as chartColorBlue500,
chart_color_cyan_100 as chartColorCyan100,
chart_color_cyan_200 as chartColorCyan200,
chart_color_cyan_300 as chartColorCyan300,
chart_color_cyan_400 as chartColorCyan400,
chart_color_cyan_500 as chartColorCyan500,
chart_color_black_100 as chartColorBlack100,
} from '@patternfly/react-tokens';

export type ROCCurveConfig = {
index: number;
data: {
name: string;
x: number;
y: number;
index: number;
}[];
};

export const RocCurveChartColorScale = [
chartColorBlue100.value,
chartColorBlue200.value,
chartColorBlue300.value,
chartColorBlue400.value,
chartColorBlue500.value,
chartColorCyan100.value,
chartColorCyan200.value,
chartColorCyan300.value,
chartColorCyan400.value,
chartColorCyan500.value,
];

type ROCCurveProps = {
configs: ROCCurveConfig[];
maxDimension?: number;
};

const ROCCurve: React.FC<ROCCurveProps> = ({ configs, maxDimension }) => {
const width = Math.min(maxDimension || 800, 500);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this was added just to test out 500 px? Won't this always return 500?

const height = width;
const baseLineData = Array.from(Array(100).keys()).map((x) => ({ x: x / 100, y: x / 100 }));

return (
<div style={{ width }}>
<Chart
ariaDesc="ROC Curve"
ariaTitle="ROC Curve"
containerComponent={
<ChartVoronoiContainer
constrainToVisibleArea
voronoiBlacklist={['baseline']}
labels={({ datum }) => `threshold (Series #${datum.index + 1}): ${datum.name}`}
/>
}
height={height}
width={width}
padding={{ bottom: 100, left: 100, right: 50, top: 50 }}
legendAllowWrap
legendPosition="bottom-left"
legendData={configs.map((config) => ({
name: `Series #${config.index + 1}`,
symbol: {
fill: RocCurveChartColorScale[config.index % RocCurveChartColorScale.length],
type: 'square',
},
}))}
>
<ChartAxis
showGrid
dependentAxis
label="True positive rate"
tickValues={Array.from(Array(11).keys()).map((x) => x / 10)}
/>
<ChartAxis
showGrid
label="False positive rate"
tickValues={Array.from(Array(21).keys()).map((x) => x / 20)}
/>
<ChartGroup>
<ChartLine
name="baseline"
data={baseLineData}
style={{
data: {
strokeDasharray: '3,3',
stroke: chartColorBlack100.value,
},
}}
/>
{configs.map((config, idx) => (
<ChartLine
key={idx}
data={config.data}
interpolation="basis"
style={{
data: {
stroke: RocCurveChartColorScale[config.index % RocCurveChartColorScale.length],
},
}}
/>
))}
</ChartGroup>
</Chart>
</div>
);
};

export default ROCCurve;
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
.confusionMatrix {
margin: 20px;
margin-right: 75px;
display: flex;
}

.confusionMatrix-table {
border-collapse: collapse;
}

.confusionMatrix-cell {
border: solid 1px white;
position: relative;
text-align: center;
vertical-align: middle;
}

.confusionMatrix-labelCell {
text-align: right;
white-space: nowrap;
padding-right: 10px;
}

.confusionMatrix-gradientLegendOuter {
display: flex;
flex-direction: column;
justify-content: space-between;
}

.confusionMatrix-gradientLegend {
border-right: solid 1px #777;
margin-left: 30px;
min-width: 10px;
position: relative;
width: 10px;
}

.confusionMatrix-gradientLegendMaxOuter {
top: 0;
border-top: solid 1px #777;
left: 100%;
padding-left: 5px;
position: absolute;
width: 5px;
}

.confusionMatrix-gradientLegendMaxLabel {
left: 15px;
position: absolute;
top: -7px;
}

.confusionMatrix-verticalMarker {
writing-mode: vertical-lr;
white-space: nowrap;
}

.confusionMatrix-markerLabel {
border-top: solid 1px #777;
left: 100%;
padding-left: 5px;
position: absolute;
width: 5px;
}

.confusionMatrix-trueLabel {
font-weight: bold;
padding-left: 20px;
}

Loading
Loading