Spaces:
Sleeping
Sleeping
| <template> | |
| <div class="confusion-matrix"> | |
| <div class="matrix-container"> | |
| <table class="matrix-table"> | |
| <thead> | |
| <tr> | |
| <th></th> | |
| <th v-for="label in labels" :key="label" class="header-cell">{{ label }}</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr v-for="(row, rowIndex) in matrix" :key="rowIndex"> | |
| <td class="row-label">{{ labels[rowIndex] }}</td> | |
| <td | |
| v-for="(cell, colIndex) in row" | |
| :key="colIndex" | |
| class="matrix-cell" | |
| :class="{ 'diagonal': rowIndex === colIndex }" | |
| :style="getCellStyle(cell)" | |
| > | |
| {{ cell }} | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <div v-if="isValidation" class="color-bar"> | |
| <div class="color-scale"> | |
| <span>0</span> | |
| <div class="color-gradient"></div> | |
| <span>100</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| <script setup lang="ts"> | |
| import { computed } from 'vue' | |
| interface Props { | |
| matrix: number[][] | |
| labels?: string[] | |
| isValidation?: boolean | |
| } | |
| const props = withDefaults(defineProps<Props>(), { | |
| labels: () => ['0h', '100h', '20h', '60h'], | |
| isValidation: false | |
| }) | |
| const maxValue = computed(() => { | |
| return Math.max(...props.matrix.flat()) | |
| }) | |
| const getCellStyle = (value: number) => { | |
| if (!props.isValidation) { | |
| return { | |
| backgroundColor: value > 0 ? '#1a1a1a' : '#f6f6f6', | |
| color: value > 0 ? 'white' : '#a0aec0' | |
| } | |
| } | |
| // 验证集使用渐变色 | |
| const intensity = value / maxValue.value | |
| const hue = 210 // 蓝色 | |
| const saturation = 70 | |
| const lightness = 100 - (intensity * 40) // 从浅到深 | |
| return { | |
| backgroundColor: `hsl(${hue}, ${saturation}%, ${lightness}%)`, | |
| color: intensity > 0.5 ? 'white' : '#2d3748' | |
| } | |
| } | |
| </script> | |
| <style scoped> | |
| .confusion-matrix { | |
| width: 100%; | |
| } | |
| .matrix-container { | |
| background: white; | |
| border-radius: 3px; | |
| padding: 1rem; | |
| } | |
| .matrix-table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| margin-bottom: 0.5rem; | |
| } | |
| .header-cell { | |
| padding: 0.5rem; | |
| font-size: 0.85rem; | |
| font-weight: 600; | |
| color: #4a5568; | |
| text-align: center; | |
| border-bottom: 2px solid #e2e8f0; | |
| } | |
| .row-label { | |
| padding: 0.5rem; | |
| font-size: 0.85rem; | |
| font-weight: 600; | |
| color: #4a5568; | |
| text-align: right; | |
| border-right: 2px solid #e2e8f0; | |
| } | |
| .matrix-cell { | |
| padding: 0.75rem; | |
| text-align: center; | |
| font-weight: 600; | |
| font-size: 0.9rem; | |
| border: 1px solid #e2e8f0; | |
| transition: all 0.3s ease; | |
| } | |
| .matrix-cell.diagonal { | |
| font-weight: 700; | |
| } | |
| .color-bar { | |
| margin-top: 0.5rem; | |
| padding-top: 0.5rem; | |
| border-top: 1px solid #e2e8f0; | |
| } | |
| .color-scale { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| font-size: 0.75rem; | |
| color: #718096; | |
| } | |
| .color-gradient { | |
| flex: 1; | |
| height: 8px; | |
| background: linear-gradient(to right, | |
| hsl(210, 70%, 100%), | |
| hsl(210, 70%, 60%) | |
| ); | |
| border-radius: 3px; | |
| } | |
| </style> | |