2024-11-26 14:47:01 +08:00

388 lines
15 KiB
Vue

<template>
<Card style="width: 100%;">
<p slot="title" style="font-size: 18px; font-weight: bold; color: #464c5b;">
<Icon type="md-stats" size="20" style="color: #464c5b;" />
Inference Result: <span style="color: green;">{{ name }}</span>
</p>
<Alert show-icon><span style="font-weight: bold;">Success Rate(SR)</span> = Predicted Final Coverage Rate / Max
GT Final Coverage Rate</Alert>
<Row>
<!-- 左侧展示条形图 -->
<Col span="12">
<Card>
<p slot="title" style="font-size: 16px; font-weight: bold;">Success Rate Histogram</p>
<div ref="histogramChart" style="height: 600px; width: 100%;"></div>
</Card>
</Col>
<!-- 右侧展示饼状图 -->
<Col span="12">
<Card>
<p slot="title" style="font-size: 16px; font-weight: bold;">Success Rate Pie Chart</p>
<div ref="pieChart" style="height: 600px; width: 100%;"></div>
</Card>
</Col>
</Row>
<Row style="margin-top: 10px;">
<Card style="width: 100%; height: 600px;">
<p slot="title" style="font-size: 16px; font-weight: bold;">Single Object Analysis</p>
<Row>
<Col span="8">
<Row style="margin-bottom: 10px; margin-left: 10px; margin-right: 10px;">
<Col span="8">
<p style="font-size: 16px; color: #464c5b; font-weight: bold;">Select Scene:</p>
</Col>
<Col span="14">
<Select v-model="sceneName" style="width: 100%;" @on-change="handleSceneChange"
placeholder="please select..." filterable>
<Option v-for="(value, key) in result" :value="key" :key="key" :label="key"><span>{{ key
}}</span>
<span style="float:right;color:#ccc">(SR=<span
:style="{ color: getSuccessRateColor(result[key]['pred_max_coverage_rate']) }">{{
(result[key]["pred_max_coverage_rate"] * 100).toFixed(2) }}%</span>)</span>
</Option>
</Select>
</Col>
</Row>
</Col>
<Col span="1">
<Divider type="vertical" style="height: 100%;" />
</Col>
<Col span="14">
<Divider type="vertical" style="height: 100%;" />
<span style="font-weight: bold;">Pred Coverage Rate: <span style="color: green;">{{
result[sceneName]
? (result[sceneName]["pred_max_coverage_rate"]*100).toFixed(2) : 0 }}%</span></span>
<Divider type="vertical" style="height: 100%;" />
<span style="font-weight: bold;">Success Rate: <span style="color: green;">{{ result[sceneName] ?
(result[sceneName]["success_rate"] * 100).toFixed(2) : 0 }}%</span></span>
<Divider type="vertical" style="height: 100%;" />
<span style="font-weight: bold;">Pred Length/GT Length:
<span style="color: red;">{{ result[sceneName] ? (result[sceneName]["pred_seq_len"]) : 0
}}</span>/<span style="color: green;">?</span>
</span>
</Col>
</Row>
<Divider />
<Row>
<Card style="height: 400px; width: 100%;">
<p slot="title" style="font-size: 16px; font-weight: bold;">Prediction Curve</p>
<div ref="predictionCurve" style="height: 350px; width: 100%;"></div>
</Card>
</Row>
</Card>
</Row>
</Card>
</template>
<script>
import * as echarts from 'echarts';
import { Divider } from 'view-design';
export default {
name: "StatResultAnalysis",
props: {
result: Object,
name: String,
},
mounted() {
console.log(this.result);
this.drawCharts();
},
data() {
return {
sceneName: null,
};
},
methods: {
getSuccessRateColor(rate) {
if (rate >= 0.7) {
return 'green';
} else if (rate >= 0.4) {
return 'orange';
} else {
return 'red';
}
},
handleSceneChange(val) {
if (val) {
this.sceneName = val;
console.log("Selected scene name:", this.sceneName);
this.drawLines(); // 选择场景后绘制折线图
}
},
drawLines() {
if (!this.sceneName || !this.result[this.sceneName]) return;
const coverageRateSeq = this.result[this.sceneName]["coverage_rate_seq"];
const maxCoverageRate = this.result[this.sceneName]["pred_max_coverage_rate"];
const successRateSeq = coverageRateSeq.map(rate => (rate * 100 / maxCoverageRate).toFixed(2)); // 计算成功率序列
// 初始化折线图
const predictionCurve = echarts.init(this.$refs.predictionCurve);
const lineOption = {
tooltip: {
trigger: 'axis',
formatter: (params) => {
let tooltip = params[0].name + '<br>';
params.forEach(item => {
tooltip += `${item.seriesName}: ${item.data}%<br>`;
});
return tooltip;
}
},
xAxis: {
type: 'category',
data: coverageRateSeq.map((_, index) => `${index + 1}`), // x轴标签
},
yAxis: {
type: 'value',
name: 'Coverage Rate',
axisLabel: {
formatter: '{value}%'
}
},
series: [
{
name: 'Coverage Rate',
type: 'line',
data: coverageRateSeq.map(rate => (rate * 100).toFixed(2)),
itemStyle: {
color: '#3399ff'
},
smooth: false // 曲线平滑
},
{
name: 'Success Rate',
type: 'line',
data: successRateSeq,
itemStyle: {
color: '#ff5733' // 另一种颜色
},
smooth: false // 曲线平滑
},
{
name: 'Max Coverage Rate',
type: 'line',
lineStyle: {
type: 'dashed' // 设置为虚线
},
markLine: {
data: [
{
name: 'GT Max Coverage Rate',
yAxis: (maxCoverageRate * 100).toFixed(2),
label: {
formatter: '{c}%' // 在标记线上显示百分号
}
}
],
},
}
]
};
predictionCurve.setOption(lineOption);
},
drawCharts() {
// 提取成功率数据
console.log("result", this.result);
const successRates = Object.values(this.result).map(item => item.pred_max_coverage_rate);
// 计算平均数
const avgSuccessRate = parseFloat((successRates.reduce((sum, rate) => sum + rate, 0) / successRates.length).toFixed(4));
console.log("avg", avgSuccessRate);
// 计算中位数
const sortedRates = [...successRates].sort((a, b) => a - b);
const mid = Math.floor(sortedRates.length / 2);
const medianSuccessRate = parseFloat((sortedRates.length % 2 !== 0 ? sortedRates[mid] : ((sortedRates[mid - 1] + sortedRates[mid]) / 2)).toFixed(4));
// 定义区间
const intervals = ['0-10%', '10-20%', '20-30%', '30-40%', '40-50%', '50-60%', '60-70%', '70-80%', '80-90%', '90-99%', '99-100%'];
const intervalCounts = new Array(intervals.length).fill(0);
// 将成功率分类到对应的区间
successRates.forEach(rate => {
if (rate >= 0.99) {
intervalCounts[10]++; // 99-100%的区间
} else {
let index = Math.floor(rate * 10);
intervalCounts[index]++;
}
});
// 生成条形图数据
const histogramData = intervalCounts.map((count, index) => ({
name: intervals[index],
value: count
}));
const histogramChart = echarts.init(this.$refs.histogramChart);
const seriesData = [
{
name: 'Number of Objects',
type: 'bar',
data: histogramData.map(item => item.value),
itemStyle: {
color: '#3399ff'
},
markPoint: {
data: [
{
name: 'Median',
coord: [medianSuccessRate * 10 - 1, histogramData[Math.floor(medianSuccessRate * 10)].value],
label: {
formatter: `Median: \n${(medianSuccessRate * 100).toFixed(2)}%`,
position: 'top'
},
itemStyle: {
color: 'green'
}
},
{
name: 'Avg',
coord: [avgSuccessRate * 10 - 1, histogramData[Math.floor(avgSuccessRate * 10)].value],
label: {
formatter: `Average: \n${(avgSuccessRate * 100).toFixed(2)}%`,
position: 'top'
},
itemStyle: {
color: 'orange'
}
},
]
}
}
];
const histogramOption = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'category',
data: intervals,
name: 'SR (%)'
},
yAxis: {
type: 'value',
name: 'Number of Objects'
},
series: seriesData
};
histogramChart.setOption(histogramOption);
const pieIntervals = ['0-40%', '40-70%', '70-100%', '>=100%'];
const pieIntervalCounts = new Array(intervals.length).fill(0);
successRates.forEach(rate => {
if (rate <= 0.4) {
pieIntervalCounts[0]++;
} else if (rate <= 0.7) {
pieIntervalCounts[1]++;
} else if (rate < 1.0) {
pieIntervalCounts[2]++;
} else {
pieIntervalCounts[3]++;
}
});
// 生成内环饼图数据
const innerPieData = pieIntervals.map((interval, index) => ({
name: interval,
value: pieIntervalCounts[index]
}));
// 生成外环饼图数据
const outerPieData = histogramData.map(item => ({
name: item.name,
value: item.value
}));
// 初始化饼状图
const pieChart = echarts.init(this.$refs.pieChart);
const pieOption = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
data: outerPieData.map(item => item.name) // 使用内环数据的名称
},
series: [
{
name: 'Success Rate',
type: 'pie',
selectedMode: 'single',
radius: [0, '30%'],
label: {
position: 'inner',
fontSize: 14
},
labelLine: {
show: false
},
data: innerPieData // 内环数据
},
{
name: 'Success Rate',
type: 'pie',
radius: ['45%', '60%'],
labelLine: {
length: 30
},
label: {
formatter: '{a|{a}}{abg|}\n{hr|}\n {b|{b}:}{c} {per|{d}%} ',
backgroundColor: '#F6F8FC',
borderColor: '#8C8D8E',
borderWidth: 1,
borderRadius: 4,
rich: {
a: {
color: '#6E7079',
lineHeight: 22,
align: 'center'
},
hr: {
borderColor: '#8C8D8E',
width: '100%',
borderWidth: 1,
height: 0
},
b: {
color: '#4C5058',
fontSize: 14,
fontWeight: 'bold',
lineHeight: 33
},
per: {
color: '#fff',
backgroundColor: '#4C5058',
padding: [3, 4],
borderRadius: 4
}
}
},
data: outerPieData // 外环数据
}
]
};
pieChart.setOption(pieOption);
}
}
};
</script>
<style scoped>
/* 添加必要的样式 */
</style>