Skip to content

Commit

Permalink
feat(UI): report widget
Browse files Browse the repository at this point in the history
  • Loading branch information
rouk1 committed Feb 3, 2025
1 parent b85b797 commit 6b780a2
Show file tree
Hide file tree
Showing 8 changed files with 757 additions and 0 deletions.
113 changes: 113 additions & 0 deletions skore-ui/src/assets/fixtures/estimator-report.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{
"scalar_results": [
{ "name": "toto", "value": 4.32, "favorability": "greater_is_better" },
{ "name": "tata", "value": 4.32, "favorability": "greater_is_better" },
{ "name": "titi", "value": 4.32, "stddev": 1, "favorability": "greater_is_better" },
{ "name": "tutu", "value": 4.32, "favorability": "greater_is_better" },
{ "name": "stab", "value": 0.4, "label": "Good", "favorability": "greater_is_better" },
{ "name": "titi", "value": 4.32, "stddev": 1, "favorability": "greater_is_better" },
{ "name": "tutu", "value": 4.32, "favorability": "greater_is_better" },
{
"name": "stab",
"value": 0.9,
"label": "Good",
"description": "your blabla is good",
"favorability": "greater_is_better"
}
],
"tabular_results": [
{
"name": "abracadaraabracadaraabracadaraabracadara",
"columns": [0, 1, 2, 3, 4],
"data": [
["0.1234", "0.5678", "0.9012", "0.3456", "0.7890"],
["0.2345", "0.6789", "0.0123", "0.4567", "0.8901"],
["0.3456", "0.7890", "0.1234", "0.5678", "0.9012"],
["0.4567", "0.8901", "0.2345", "0.6789", "0.0123"],
["0.5678", "0.9012", "0.3456", "0.7890", "0.1234"],
["0.6789", "0.0123", "0.4567", "0.8901", "0.2345"]
],
"favorability": [
"greater_is_better",
"lower_is_better",
"greater_is_better",
"lower_is_better"
]
},
{
"name": "b",
"columns": ["Accuracy", "Precision", "Recall", "F1 Score"],
"data": [
[0.8, 0.4, 0.5, 0.6],
[0.8, 0.4, 0.5, 0.6],
[0.8, 0.4, 0.5, 0.6],
[0.8, 0.4, 0.5, 0.6]
],
"favorability": ["greater_is_better", "greater_is_better", "lower_is_better"]
}
],
"plots": [
{
"name": "plot 1",
"value": {
"data": [{ "x": [1, 2, 3], "y": [1, 3, 2], "type": "bar" }],
"layout": {
"title": { "text": "A Figure Specified by a Dictionary" }
}
}
},
{
"name": "plot 2",
"value": {
"data": [{ "x": [4, 5, 6], "y": [7, 8, 9], "type": "bar" }],
"layout": {
"title": { "text": "Another Figure" }
}
}
}
],
"sections": [
{
"title": "Model",
"icon": "icon-square-cursor",
"items": [
{
"name": "Estimator parameters:",
"description": "Core model configuration used for training",
"value": "`RandomForestClassifier` *100* trees, max_depth *10*"
},
{
"name": "Estimator parameters:",
"description": "Core model configuration used for training",
"value": "`RandomForestClassifier` *100* trees, max_depth *10*"
},
{
"name": "Estimator parameters:",
"description": "Core model configuration used for training",
"value": "`RandomForestClassifier` *100* trees, max_depth *10*"
}
]
},
{
"title": "bla bla",
"icon": "icon-text",
"items": [
{
"name": "Estimator parameters:",
"description": "Core model configuration used for training",
"value": "`RandomForestClassifier` *100* trees, max_depth *10*"
},
{
"name": "Estimator parameters:",
"description": "Core model configuration used for training",
"value": "`RandomForestClassifier` *100* trees, max_depth *10*"
},
{
"name": "Estimator parameters:",
"description": "Core model configuration used for training",
"value": "`RandomForestClassifier` *100* trees, max_depth *10*"
}
]
}
]
}
79 changes: 79 additions & 0 deletions skore-ui/src/components/EstimatorReport.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<script lang="ts">
export enum Favorability {
GREATER_IS_BETTER = "greater_is_better",
LOWER_IS_BETTER = "lower_is_better",
UNKNOWN = "unknown",
}
export interface EstimatorReportScalarResult {
name: string;
value: number;
stddev?: number;
label?: string;
description?: string;
favorability: Favorability;
}
export interface EstimatorReportTabularResult {
name: string;
columns: any[];
data: any[][];
favorability: Favorability[];
}
export interface EstimatorReportPrimaryResults {
scalarResults: EstimatorReportScalarResult[];
tabularResults: EstimatorReportTabularResult[];
}
export interface EstimatorReportPlot {
name: string;
value: any;
}
export interface EstimatorReportDetailSectionItem {
name: string;
description: string;
value: string;
}
export interface EstimatorReportDetailSection {
title: string;
icon: string;
items: EstimatorReportDetailSectionItem[];
}
</script>

<script setup lang="ts">
import EstimatorReportDetails from "@/components/EstimatorReportDetails.vue";
import EstimatorReportPlots from "@/components/EstimatorReportPlots.vue";
import EstimatorReportResults from "@/components/EstimatorReportResults.vue";
import TabPanel from "@/components/TabPanel.vue";
import TabPanelContent from "@/components/TabPanelContent.vue";
const props = defineProps<{
scalarResults: EstimatorReportScalarResult[];
tabularResults: EstimatorReportTabularResult[];
plots: EstimatorReportPlot[];
sections: EstimatorReportDetailSection[];
}>();
</script>

<template>
<div class="cross-validation-report">
<TabPanel>
<TabPanelContent name="Primary Results" icon="icon-bar-chart">
<EstimatorReportResults
:scalar-results="props.scalarResults"
:tabular-results="props.tabularResults"
/>
</TabPanelContent>
<TabPanelContent name="Plots" icon="icon-large-bar-chart">
<EstimatorReportPlots :plots="props.plots" />
</TabPanelContent>
<TabPanelContent name="Storage/Details" icon="icon-hard-drive">
<EstimatorReportDetails :sections="props.sections" />
</TabPanelContent>
</TabPanel>
</div>
</template>
97 changes: 97 additions & 0 deletions skore-ui/src/components/EstimatorReportDetails.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<script setup lang="ts">
import MarkdownIt from "markdown-it";
import type { EstimatorReportDetailSection } from "@/components/EstimatorReport.vue";
const props = defineProps<{ sections: EstimatorReportDetailSection[] }>();
const renderer = MarkdownIt({ html: true });
function itemAsHtml(v: string) {
return renderer.render(v);
}
</script>

<template>
<div class="estimator-report-details">
<div class="section" v-for="section in props.sections" :key="section.title">
<div class="title"><i class="icon" :class="section.icon" />{{ section.title }}</div>
<div class="items">
<div class="item" v-for="item in section.items" :key="item.name">
<div class="name-and-description">
<div class="name">{{ item.name }}</div>
<div class="description">{{ item.description }}</div>
</div>
<div class="value" v-html="itemAsHtml(item.value)" />
</div>
</div>
</div>
</div>
</template>

<style>
.estimator-report-details {
padding: var(--spacing-16);
& .section {
display: flex;
flex-direction: column;
padding-bottom: var(--spacing-24);
gap: var(--spacing-16);
& .title {
margin-bottom: var(--spacing-4);
color: var(--color-text-primary);
font-size: var(--font-size-sm);
& .icon {
padding-right: var(--spacing-4);
color: var(--color-text-branding);
}
}
& .items {
display: flex;
flex-direction: column;
font-size: var(--font-size-xs);
gap: var(--spacing-20);
& .item {
display: flex;
flex-direction: row;
justify-content: space-between;
& .name {
color: var(--color-text-primary);
}
& .description {
color: var(--color-text-secondary);
}
& .value {
color: var(--color-text-secondary);
font-family: GeistMono, monospace;
& em,
& code {
color: var(--color-text-branding);
font-style: normal;
font-weight: var(--font-weight-medium);
}
& code {
display: inline-block;
padding: var(--spacing-4);
border-radius: var(--radius-xs);
background-color: rgb(from var(--color-text-branding) r g b / 20%);
}
& ul {
padding-left: 15px;
}
}
}
}
}
}
</style>
43 changes: 43 additions & 0 deletions skore-ui/src/components/EstimatorReportMetricFavorability.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script setup lang="ts">
import { computed } from "vue";
import type { Favorability } from "@/components/EstimatorReport.vue";
import FloatingTooltip from "@/components/FloatingTooltip.vue";
const props = defineProps<{ favorability: Favorability }>();
const icon = computed(() => {
switch (props.favorability) {
case "greater_is_better":
return "icon-ascending-arrow";
case "lower_is_better":
return "icon-descending-arrow";
default:
return "";
}
});
const text = computed(() => {
switch (props.favorability) {
case "greater_is_better":
return "Higher is better";
case "lower_is_better":
return "Lower is better";
default:
return "";
}
});
</script>

<template>
<FloatingTooltip v-if="icon !== ''" placement="bottom" :text="text">
<i class="icon" :class="icon" />
</FloatingTooltip>
</template>

<style scoped>
.icon {
color: var(--color-icon-tertiary);
vertical-align: middle;
}
</style>
Loading

0 comments on commit 6b780a2

Please sign in to comment.