123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- <template>
- <div style="width: 100%; height: 500px">
- <!-- 时间范围选择器 -->
- <el-date-picker
- size="mini"
- v-model="dateRange"
- type="daterange"
- align="right"
- unlink-panels
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- @change="onDateRangeChange"
- style="margin: 20px 0 0 0"
- ></el-date-picker>
- <div
- v-loading="loading"
- :ref="`plotlyChart-${index}`"
- style="width: 100%; height: 450px"
- >
- <el-empty v-if="isError" description="请求失败"></el-empty>
- </div>
- </div>
- </template>
- <script>
- import Plotly from "plotly.js-dist-min";
- import axios from "axios";
- import { myMixin } from "@/mixins/chartRequestMixin";
- export default {
- name: "BoxPlotWithMedians",
- mixins: [myMixin],
- props: {
- fileAddr: {
- default: "",
- type: String,
- },
- index: {
- type: String,
- },
- setUpImgData: {
- default: () => [],
- type: Array,
- },
- },
- data() {
- return {
- chartData: {}, // 存储从 API 获取的原始数据
- dateRange: [], // 日期范围选择器的值
- loading: false,
- isError: false,
- };
- },
- mounted() {
- this.getData(); // 获取数据
- },
- watch: {
- setUpImgData: {
- handler(newType) {
- this.drawBoxPlot();
- },
- deep: true,
- },
- },
- methods: {
- // 获取数据
- async getData() {
- if (this.fileAddr !== "") {
- try {
- this.loading = true;
- this.cancelToken = axios.CancelToken.source();
- const resultChartsData = await axios.get(this.fileAddr, {
- cancelToken: this.cancelToken.token,
- });
- this.chartData = resultChartsData.data;
- this.drawBoxPlot(); // 绘制图表
- this.isError = false;
- this.loading = false;
- } catch (error) {
- this.isError = true;
- this.loading = false;
- }
- }
- },
- // 处理日期范围变化
- onDateRangeChange() {
- this.drawBoxPlot(); // 日期变化时重新绘制图表
- },
- // 判断时间戳是否在选择的日期范围内
- isInDateRange(timestamp) {
- const [startDate, endDate] = this.dateRange;
- if (!startDate || !endDate) return true;
- const date = new Date(timestamp);
- return date >= new Date(startDate) && date <= new Date(endDate);
- },
- // 过滤数据
- filterData(group) {
- const filteredXData = [];
- const filteredYData = [];
- const filteredMedians = group.medians ? { x: [], y: [] } : null;
- group.medians.x.forEach((timestamp, index) => {
- if (this.isInDateRange(timestamp)) {
- filteredMedians.x.push(timestamp);
- filteredMedians.y.push(group.medians.y[index]);
- }
- });
- group.xData.forEach((timestamp, index) => {
- if (this.isInDateRange(timestamp)) {
- filteredXData.push(timestamp);
- filteredYData.push(group.yData[index]);
- }
- });
- return {
- ...group,
- xData: filteredXData,
- yData: filteredYData,
- medians: filteredMedians,
- };
- },
- // 绘制箱线图
- drawBoxPlot() {
- const chartContainer = this.$refs[`plotlyChart-${this.index}`];
- const { data, xaixs, yaixs, analysisTypeCode } = this.chartData;
- // 过滤数据,根据选定的日期范围
- const filteredData = data.map(this.filterData);
- // 创建图表数据
- const traces = [];
- const medianMarkers = [];
- filteredData.forEach((group) => {
- traces.push({
- x: group.xData,
- y: group.yData,
- type: "box",
- name: group.title,
- marker: {
- color: group.color,
- },
- boxpoints: false, // 是否显示异常值
- boxmean: true, // 是否显示均值
- hovertemplate: (data) => {
- // 获取箱线图的统计数据
- const max = data.max; // 最大值
- const min = data.min; // 最小值
- const q1 = data.q1; // 下四分位数
- const q3 = data.q3; // 上四分位数
- const median = data.median; // 中位数
- const mean = data.mean; // 均值
- const iqr = q3 - q1; // 四分位距(IQR)
- const outliers = data.outliers || "无"; // 异常值(如果没有异常值,则显示“无”)
- return (
- `${xaixs}: %{x}<br>` + // 显示类别
- `<b>最大值</b>: ${max}<br>` + // 最大值
- `<b>最小值</b>: ${min}<br>` + // 最小值
- `<b>上四分位数 (Q3)</b>: ${q3}<br>` + // 上四分位数
- `<b>中位数 (Median)</b>: ${median}<br>` + // 中位数
- `<b>下四分位数 (Q1)</b>: ${q1}<br>` + // 下四分位数
- `<b>四分位距 (IQR)</b>: ${iqr}<br>` + // 四分位距
- `<b>均值 (Mean)</b>: ${mean}<br>` + // 均值
- `<b>异常值</b>: ${outliers}<br>` + // 异常值
- "<extra></extra>" // 额外的文本(可以留空)
- );
- },
- });
- // 如果有中位点数据且中位点数据不为空,添加中位点
- if (group.medians && group.medians.x.length > 0) {
- medianMarkers.push({
- x: group.medians.x,
- y: group.medians.y,
- mode: "markers",
- marker: {
- color: "#406DAB",
- size: 3,
- },
- name: `${group.title} - 中位点`,
- type: "scatter",
- hovertemplate: `${xaixs}: %{x} <br> ${yaixs}: %{y} <br><b>中位点</b>: %{y}<br><extra></extra>`,
- });
- }
- });
- const layout = {
- title: analysisTypeCode + data[0].engineName,
- xaxis: {
- title: xaixs,
- type: "date",
- tickformat: "%Y-%m-%d",
- },
- yaxis: {
- title: yaixs,
- },
- showlegend: true,
- };
- const getChartSetUp = (axisTitle) => {
- return this.setUpImgData.find((item) => item.text.includes(axisTitle));
- };
- // 更新x轴和y轴的范围与步长
- const xChartSetUp = getChartSetUp(layout.xaxis.title);
- if (xChartSetUp) {
- layout.xaxis.dtick = xChartSetUp.dtick;
- layout.xaxis.range = [xChartSetUp.min, xChartSetUp.max];
- }
- const yChartSetUp = getChartSetUp(layout.yaxis.title);
- if (yChartSetUp) {
- layout.yaxis.dtick = yChartSetUp.dtick;
- layout.yaxis.range = [yChartSetUp.min, yChartSetUp.max];
- }
- Plotly.newPlot(chartContainer, [...traces, ...medianMarkers], layout);
- },
- },
- };
- </script>
- <style scoped>
- /* 可根据需要自定义样式 */
- </style>
|