| @@ -14,6 +14,8 @@ | |||
| "d3": "5.9.7", | |||
| "d3-graphviz": "3.0.4", | |||
| "element-ui": "2.11.1", | |||
| "jquery": "3.5.0", | |||
| "slickgrid": "2.4.22", | |||
| "vue": "2.6.11", | |||
| "vue-i18n": "8.15.0", | |||
| "vue-router": "3.1.3", | |||
| @@ -0,0 +1,486 @@ | |||
| <!-- | |||
| Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved. | |||
| Licensed under the Apache License, Version 2.0 (the "License"); | |||
| you may not use this file except in compliance with the License. | |||
| You may obtain a copy of the License at | |||
| http://www.apache.org/licenses/LICENSE-2.0 | |||
| Unless required by applicable law or agreed to in writing, software | |||
| distributed under the License is distributed on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| See the License for the specific language governing permissions and | |||
| limitations under the License. | |||
| --> | |||
| <template> | |||
| <div class="cl-slickgrid-container"> | |||
| <div class="data-show-container"> | |||
| <div v-show="incorrectData" | |||
| class="error-msg-container"> | |||
| {{$t('components.gridIncorrectDataError')}} | |||
| </div> | |||
| <div v-show="!fullData.length && updated && !incorrectData" | |||
| class="error-msg-container"> | |||
| {{$t('components.gridTableNoData')}} | |||
| </div> | |||
| <div :id="itemId" | |||
| v-show="!!fullData.length && !incorrectData" | |||
| class="grid-item"></div> | |||
| </div> | |||
| <div class="operate-container" | |||
| v-if="showOperate && fullData.length"> | |||
| <div class="filter-container" | |||
| @keyup.enter="filterChange"> | |||
| <div v-for="(item, itemIndex) in filterArr" | |||
| :key="itemIndex"> | |||
| <el-input class="filter-input" | |||
| :class="item.showError ? 'error-border' : ''" | |||
| v-model="item.model"></el-input> | |||
| <span class="input-behind" | |||
| v-if="itemIndex === filterArr.length - 1">{{$t('symbols.slashes')}}</span> | |||
| <span class="input-behind" | |||
| v-else>{{$t('symbols.point')}}</span> | |||
| </div> | |||
| <el-button class="filter-check" | |||
| size="mini" | |||
| v-if="!!filterArr.length" | |||
| @click="filterChange"> | |||
| <i class="el-icon-check"></i></el-button> | |||
| <span class="filter-incorrect-text" | |||
| v-if="!filterCorrect">{{$t('components.inCorrectInput')}}</span> | |||
| </div> | |||
| <div class="accuracy-container"> | |||
| {{$t('components.gridAccuracy')}}<el-select v-model="accuracy" | |||
| class="select-item" | |||
| @change="accuracyChange"> | |||
| <el-option v-for="item in accuracyArr" | |||
| :key="item.label" | |||
| :label="item.label" | |||
| :value="item.value"></el-option> | |||
| </el-select> | |||
| <div class="full-screen-icon" | |||
| :title="$t('scalar.fullScreen')" | |||
| @click="toggleFullScreen" | |||
| :class="fullScreen ? 'active-color' : ''"> | |||
| <span><i class="el-icon-full-screen"></i></span> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| import 'slickgrid/css/smoothness/jquery-ui-1.11.3.custom.css'; | |||
| import 'slickgrid/slick.grid.css'; | |||
| import 'slickgrid/lib/jquery-3.1.0'; | |||
| import 'slickgrid/lib/jquery-ui-1.9.2'; | |||
| import 'slickgrid/lib/jquery.event.drag-2.3.0.js'; | |||
| import 'slickgrid/slick.core.js'; | |||
| import 'slickgrid/slick.dataview.js'; | |||
| import 'slickgrid/slick.grid.js'; | |||
| export default { | |||
| props: { | |||
| // Table data | |||
| fullData: { | |||
| type: Array, | |||
| default() { | |||
| return []; | |||
| }, | |||
| }, | |||
| // Display operation Bar | |||
| showOperate: { | |||
| type: Boolean, | |||
| default: true, | |||
| }, | |||
| // Display full screen | |||
| fullScreen: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| itemId: '', // Dom id | |||
| gridObj: null, // slickgrid object | |||
| columnsData: [], // Column information | |||
| filterArr: [], // Dimension selection array | |||
| formateData: [], // formatted data | |||
| formateArr: [], // formatted Array | |||
| statistics: {}, // Object contain maximun and minimun | |||
| accuracy: 5, // accuracy value | |||
| incorrectData: false, // Wheather the dimension is correctly selected | |||
| updated: false, // Updated | |||
| scrollTop: false, // Wheather scroll to the top | |||
| filterCorrect: true, // Wheather the dimension input is correct | |||
| // Accuray options | |||
| accuracyArr: [ | |||
| {label: 0, value: 0}, | |||
| {label: 1, value: 1}, | |||
| {label: 2, value: 2}, | |||
| {label: 3, value: 3}, | |||
| {label: 4, value: 4}, | |||
| {label: 5, value: 5}, | |||
| ], | |||
| // Table configuration items | |||
| optionObj: { | |||
| enableCellNavigation: true, | |||
| frozenColumn: 0, | |||
| frozenRow: 0, | |||
| }, | |||
| }; | |||
| }, | |||
| computed: {}, | |||
| watch: {}, | |||
| mounted() { | |||
| this.init(); | |||
| }, | |||
| methods: { | |||
| /** | |||
| * Initialize | |||
| */ | |||
| init() { | |||
| this.itemId = | |||
| `${new Date().getTime()}` + `${this.$store.state.componentsCount}`; | |||
| this.$store.commit('componentsNum'); | |||
| }, | |||
| /** | |||
| * Initialize dimension selection | |||
| * @param {Array} dimension Dimension array | |||
| * @param {String} filterStr Dimension String | |||
| */ | |||
| initializeFilterArr(dimension, filterStr) { | |||
| if (!filterStr) { | |||
| this.filterArr = []; | |||
| return; | |||
| } | |||
| const tempFilterArr = filterStr.slice(1, filterStr.length - 1).split(','); | |||
| const tempArr = []; | |||
| for (let i = 0; i < tempFilterArr.length; i++) { | |||
| tempArr.push({ | |||
| model: tempFilterArr[i], | |||
| max: dimension[i] - 1, | |||
| showError: false, | |||
| }); | |||
| } | |||
| this.filterArr = tempArr; | |||
| }, | |||
| /** | |||
| * Initialize column information | |||
| */ | |||
| formateColumnsData() { | |||
| this.columnsData = [ | |||
| { | |||
| id: -1, | |||
| name: ' ', | |||
| field: -1, | |||
| width: 100, | |||
| headerCssClass: 'headerStyle', | |||
| }, | |||
| ]; | |||
| const columnSample = this.formateData[0]; | |||
| if (columnSample) { | |||
| columnSample.forEach((num, numIndex) => { | |||
| const order = numIndex; | |||
| this.columnsData.push({ | |||
| id: order, | |||
| name: order, | |||
| field: order, | |||
| width: 100, | |||
| headerCssClass: 'headerStyle', | |||
| formatter: this.formateValueColor, | |||
| }); | |||
| }); | |||
| } else { | |||
| this.columnsData = []; | |||
| } | |||
| }, | |||
| /** | |||
| * Setting the Background color of data | |||
| * @param {Number} row | |||
| * @param {Number} cell | |||
| * @param {String} value, | |||
| * @param {Object} columnDef | |||
| * @param {Object} dataContext | |||
| * @return {String} | |||
| */ | |||
| formateValueColor(row, cell, value, columnDef, dataContext) { | |||
| if ( | |||
| !cell || | |||
| !value || | |||
| isNaN(value) || | |||
| value === Infinity || | |||
| value === -Infinity | |||
| ) { | |||
| return value; | |||
| } else if (value < 0) { | |||
| return `<span class="table-item-span" style="background:rgba(94, 124, 224, ${value / | |||
| this.statistics.min})">${value}</span>`; | |||
| } else { | |||
| return `<span class="table-item-span" style="background:rgba(246, 111, 106, ${value / | |||
| this.statistics.max})">${value}</span>`; | |||
| } | |||
| }, | |||
| /** | |||
| * Convetring raw data into table data | |||
| */ | |||
| formateGridArray() { | |||
| if (this.fullData instanceof Array) { | |||
| if (this.fullData.length) { | |||
| if (this.fullData[0] instanceof Array) { | |||
| this.formateData = this.fullData; | |||
| } else { | |||
| this.formateData = [this.fullData]; | |||
| } | |||
| } else { | |||
| this.formateData = [[]]; | |||
| this.columnsData = []; | |||
| } | |||
| } else { | |||
| this.formateData = [[this.fullData]]; | |||
| } | |||
| const tempArr = []; | |||
| this.formateData.forEach((outerData, outerIndex) => { | |||
| const tempData = { | |||
| '-1': outerIndex, | |||
| }; | |||
| outerData.forEach((innerData, innerIndex) => { | |||
| const innerOrder = innerIndex; | |||
| if (isNaN(innerData)) { | |||
| tempData[innerOrder] = innerData; | |||
| } else { | |||
| tempData[innerOrder] = innerData.toFixed(this.accuracy); | |||
| } | |||
| }); | |||
| tempArr.push(tempData); | |||
| }); | |||
| this.formateArr = tempArr; | |||
| }, | |||
| /** | |||
| * Update the table | |||
| */ | |||
| updateGrid() { | |||
| this.$nextTick(() => { | |||
| if (!this.gridObj) { | |||
| this.gridObj = new Slick.Grid( | |||
| `#${this.itemId}`, | |||
| this.formateArr, | |||
| this.columnsData, | |||
| this.optionObj, | |||
| ); | |||
| } | |||
| this.gridObj.setData(this.formateArr, this.scrollTop); | |||
| this.scrollTop = false; | |||
| this.gridObj.setColumns(this.columnsData); | |||
| this.gridObj.render(); | |||
| }); | |||
| }, | |||
| /** | |||
| * accuracy changed | |||
| * @param {Number} value The value after changed | |||
| */ | |||
| accuracyChange(value) { | |||
| this.formateGridArray(); | |||
| this.updateGrid(); | |||
| }, | |||
| /** | |||
| * Dimension selection changed | |||
| */ | |||
| filterChange() { | |||
| // 校验检索条件 | |||
| let filterCorrect = true; | |||
| let incorrectData = false; | |||
| let limitCount = 2; | |||
| const tempArr = []; | |||
| this.filterArr.forEach((filter) => { | |||
| const value = filter.model.trim(); | |||
| tempArr.push(value); | |||
| if (!isNaN(value)) { | |||
| if (value < -(filter.max + 1) || value > filter.max || value === '') { | |||
| filter.showError = true; | |||
| filterCorrect = false; | |||
| } else { | |||
| filter.showError = false; | |||
| } | |||
| } else if (value === ':') { | |||
| filter.showError = false; | |||
| if (!limitCount) { | |||
| incorrectData = true; | |||
| } else { | |||
| limitCount--; | |||
| } | |||
| } else { | |||
| filter.showError = true; | |||
| filterCorrect = false; | |||
| } | |||
| }); | |||
| this.filterCorrect = filterCorrect; | |||
| if (incorrectData && filterCorrect) { | |||
| this.incorrectData = true; | |||
| return; | |||
| } else { | |||
| this.incorrectData = false; | |||
| } | |||
| if (filterCorrect) { | |||
| this.$emit('martixFilterChange', tempArr); | |||
| } | |||
| }, | |||
| /** | |||
| * Updating Table Data | |||
| * @param {Boolean} newDataFlag Wheather data is updated | |||
| * @param {Array} dimension Array of dimension | |||
| * @param {Object} statistics Object contains maximun and minimun | |||
| * @param {String} filterStr String of dimension selection | |||
| */ | |||
| updateGridData(newDataFlag, dimension, statistics, filterStr) { | |||
| this.updated = true; | |||
| this.$nextTick(() => { | |||
| if (!this.fullData || !this.fullData.length) { | |||
| return; | |||
| } | |||
| if (newDataFlag) { | |||
| this.initializeFilterArr(dimension, filterStr); | |||
| this.scrollTop = true; | |||
| } | |||
| if (newDataFlag || this.statistics.max === undefined) { | |||
| this.statistics = statistics; | |||
| } | |||
| this.formateGridArray(); | |||
| this.formateColumnsData(); | |||
| this.updateGrid(); | |||
| }); | |||
| }, | |||
| /** | |||
| * Update the view Size | |||
| */ | |||
| resizeView() { | |||
| if (this.gridObj) { | |||
| this.$nextTick(() => { | |||
| this.gridObj.resizeCanvas(); | |||
| this.gridObj.render(); | |||
| }); | |||
| } | |||
| }, | |||
| /** | |||
| * Expand/Collapse in full screen | |||
| */ | |||
| toggleFullScreen() { | |||
| this.$emit('toggleFullScreen'); | |||
| }, | |||
| }, | |||
| destroyed() {}, | |||
| }; | |||
| </script> | |||
| <style lang="scss"> | |||
| .cl-slickgrid-container { | |||
| width: 100%; | |||
| height: 100%; | |||
| display: flex; | |||
| flex-direction: column; | |||
| .data-show-container { | |||
| width: 100%; | |||
| flex: 1; | |||
| .grid-item { | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| .error-msg-container { | |||
| width: 100%; | |||
| height: 100%; | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| } | |||
| } | |||
| .info-show-container { | |||
| width: 100%; | |||
| } | |||
| .operate-container { | |||
| width: 100%; | |||
| text-overflow: ellipsis; | |||
| white-space: nowrap; | |||
| overflow: hidden; | |||
| z-index: 99; | |||
| flex-wrap: wrap; | |||
| .full-screen-icon { | |||
| float: right; | |||
| margin-left: 15px; | |||
| height: 100%; | |||
| line-height: 34px; | |||
| cursor: pointer; | |||
| :hover { | |||
| color: #3e98c5; | |||
| } | |||
| } | |||
| .active-color { | |||
| color: #3e98c5; | |||
| } | |||
| .filter-container { | |||
| float: left; | |||
| flex-wrap: wrap; | |||
| display: flex; | |||
| .error-border { | |||
| input { | |||
| border-color: red; | |||
| } | |||
| } | |||
| .filter-input { | |||
| width: 50px; | |||
| text-align: center; | |||
| } | |||
| .input-behind { | |||
| padding: 0 5px; | |||
| } | |||
| .filter-incorrect-text { | |||
| margin-left: 10px; | |||
| line-height: 32px; | |||
| color: red; | |||
| } | |||
| } | |||
| .accuracy-container { | |||
| float: right; | |||
| .select-item { | |||
| width: 60px; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .slick-cell, | |||
| .slick-headerrow-column, | |||
| .slick-footerrow-column { | |||
| padding: 0; | |||
| border-top: none; | |||
| border-left: none; | |||
| text-align: center; | |||
| } | |||
| .grid-canvas-left .slick-cell { | |||
| height: 54px; | |||
| } | |||
| .slick-viewport-left { | |||
| overflow: hidden !important; | |||
| } | |||
| .slick-viewport-left .slick-row { | |||
| background-color: white !important; | |||
| ::-webkit-scrollbar { | |||
| width: 0px; | |||
| } | |||
| } | |||
| .ui-widget-content { | |||
| background: none; | |||
| } | |||
| .headerStyle { | |||
| vertical-align: middle; | |||
| text-align: center; | |||
| } | |||
| .filter-check { | |||
| font-size: 18px; | |||
| color: #00a5a7; | |||
| cursor: pointer; | |||
| } | |||
| .table-item-span { | |||
| display: block; | |||
| width: 100%; | |||
| height: 100%; | |||
| text-align: center; | |||
| } | |||
| </style> | |||
| @@ -40,6 +40,7 @@ limitations under the License. | |||
| v-if="this.$route.path.indexOf('/scalar') > 0 | |||
| || this.$route.path.indexOf('/image') > 0 | |||
| || this.$route.path.indexOf('/histogram') > 0 | |||
| || this.$route.path.indexOf('/tensor') > 0 | |||
| || this.$route.path.indexOf('/training-dashboard') > 0 | |||
| || !this.$route.path.indexOf('/compare-plate')"> | |||
| <!-- automatic refresh switch --> | |||
| @@ -0,0 +1,838 @@ | |||
| <!-- | |||
| Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved. | |||
| Licensed under the Apache License, Version 2.0 (the "License"); | |||
| you may not use this file except in compliance with the License. | |||
| You may obtain a copy of the License at | |||
| http://www.apache.org/licenses/LICENSE-2.0 | |||
| Unless required by applicable law or agreed to in writing, software | |||
| distributed under the License is distributed on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| See the License for the specific language governing permissions and | |||
| limitations under the License. | |||
| --> | |||
| <template> | |||
| <div class="cl-histogram-container"> | |||
| <div class="data-show-container"> | |||
| <div :id="itemId" | |||
| v-show="!!fullData.length" | |||
| class="data-item"></div> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| import echarts from 'echarts'; | |||
| import CommonProperty from '../common/common-property'; | |||
| import {format, precisionRound} from 'd3'; | |||
| const d3 = {format, precisionRound}; | |||
| export default { | |||
| props: { | |||
| // histogram data | |||
| fullData: { | |||
| type: Array, | |||
| default() { | |||
| return []; | |||
| }, | |||
| }, | |||
| // view name | |||
| viewName: { | |||
| type: Number, | |||
| default: 1, | |||
| }, | |||
| // axis name | |||
| axisName: { | |||
| type: Number, | |||
| default: 0, | |||
| }, | |||
| // Display full screen | |||
| fullScreen: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| itemId: '', // Dom id | |||
| oriData: {}, // Original data | |||
| charOption: {}, // Chart configuration | |||
| charObj: null, // chart Object | |||
| updated: false, // Updated | |||
| zrDrawElement: {hoverDots: []}, | |||
| zr: null, | |||
| chartTipFlag: false, // Wheather to display tips of the histogram | |||
| }; | |||
| }, | |||
| computed: {}, | |||
| watch: {}, | |||
| mounted() { | |||
| this.init(); | |||
| }, | |||
| methods: { | |||
| /** | |||
| * Initialize | |||
| */ | |||
| init() { | |||
| this.itemId = | |||
| `${new Date().getTime()}` + `${this.$store.state.componentsCount}`; | |||
| this.$store.commit('componentsNum'); | |||
| }, | |||
| /** | |||
| * Update the view Size | |||
| */ | |||
| resizeView() { | |||
| if (this.charObj) { | |||
| this.charObj.resize(); | |||
| } | |||
| }, | |||
| /** | |||
| * Convert to chart data | |||
| */ | |||
| formatDataToChar() { | |||
| const chartData = this.fullData; | |||
| const seriesData = []; | |||
| let maxX = -Infinity; | |||
| let minX = Infinity; | |||
| let maxZ = -Infinity; | |||
| let minZ = Infinity; | |||
| const gridData = []; | |||
| if (chartData && chartData.length) { | |||
| chartData.forEach((histogram) => { | |||
| const seriesItem = []; | |||
| gridData.push(histogram.step); | |||
| histogram.items.forEach((bucket) => { | |||
| if (this.viewName === 0) { | |||
| seriesItem.push([bucket[2], bucket[3]]); | |||
| } else if (this.viewName === 1) { | |||
| seriesItem.push(bucket[2], histogram.step, bucket[3]); | |||
| } | |||
| maxX = Math.max(maxX, bucket[2]); | |||
| minX = Math.min(minX, bucket[2]); | |||
| minZ = Math.min(minZ, bucket[3]); | |||
| maxZ = Math.max(maxZ, bucket[3]); | |||
| }); | |||
| seriesData.push(seriesItem); | |||
| }); | |||
| } | |||
| this.oriData = { | |||
| seriesData, | |||
| maxX, | |||
| minX, | |||
| maxZ, | |||
| minZ, | |||
| gridData, | |||
| }; | |||
| }, | |||
| /** | |||
| * update sample data | |||
| */ | |||
| updateSampleData() { | |||
| this.charOption = this.formatCharOption(); | |||
| if (!this.charObj) { | |||
| const chartItem = document.getElementById(this.itemId); | |||
| if (!chartItem) { | |||
| return; | |||
| } | |||
| this.charObj = echarts.init(chartItem, null); | |||
| } | |||
| this.removeTooltip(); | |||
| this.charObj.setOption(this.charOption, true); | |||
| }, | |||
| /** | |||
| * Binding interaction event | |||
| */ | |||
| sampleEventBind() { | |||
| if (!this.zr) { | |||
| this.zr = this.charObj.getZr(); | |||
| this.zr.off('mouseout', 'mousemove'); | |||
| this.zr.on('mouseout', (e) => { | |||
| this.removeTooltip(); | |||
| this.chartTipFlag = false; | |||
| this.$emit('chartTipFlagChange', this.chartTipFlag); | |||
| }); | |||
| this.zr.on('mousemove', (e) => { | |||
| this.removeTooltip(); | |||
| this.mousemoveEvent(e); | |||
| }); | |||
| } | |||
| }, | |||
| /** | |||
| * Formate chart option | |||
| * @return {Object} chatr option | |||
| */ | |||
| formatCharOption() { | |||
| const colorMin = '#346E69'; | |||
| const colorMax = '#EBFFFD'; | |||
| const oriData = this.oriData; | |||
| const colorArr = this.getGrientColor( | |||
| colorMin, | |||
| colorMax, | |||
| oriData.seriesData.length, | |||
| ); | |||
| const fullScreenFun = this.toggleFullScreen; | |||
| const axisName = this.axisName; | |||
| const option = { | |||
| grid: { | |||
| left: 24, | |||
| top: 60, | |||
| right: 50, | |||
| bottom: 60, | |||
| }, | |||
| xAxis: { | |||
| max: oriData.maxX, | |||
| min: oriData.minX, | |||
| axisLine: {onZero: false}, | |||
| axisLabel: { | |||
| fontSize: '11', | |||
| formatter: function(value) { | |||
| if (value.toString().length >= 6) { | |||
| return value.toExponential(3); | |||
| } else { | |||
| return Math.round(value * 1000) / 1000; | |||
| } | |||
| }, | |||
| }, | |||
| splitLine: {show: false}, | |||
| }, | |||
| yAxis: { | |||
| position: 'right', | |||
| axisLine: {onZero: false, show: false}, | |||
| splitLine: {show: true}, | |||
| axisTick: {show: false}, | |||
| boundaryGap: false, | |||
| axisLabel: { | |||
| fontSize: '11', | |||
| }, | |||
| }, | |||
| toolbox: { | |||
| top: 20, | |||
| right: 20, | |||
| emphasis: { | |||
| iconStyle: { | |||
| textPosition: 'top', | |||
| }, | |||
| }, | |||
| // toolbox | |||
| feature: { | |||
| // fullScreen | |||
| myToolFullScreen: { | |||
| show: true, | |||
| title: this.$t('histogram.fullScreen'), | |||
| iconStyle: { | |||
| borderColor: this.fullScreen ? '#3E98C5' : '#6D7278', | |||
| }, | |||
| icon: CommonProperty.fullScreenIcon, | |||
| onclick() { | |||
| fullScreenFun(); | |||
| }, | |||
| }, | |||
| }, | |||
| }, | |||
| }; | |||
| if (this.viewName === 1) { | |||
| const seriesData = []; | |||
| oriData.seriesData.forEach((item, dataIndex) => { | |||
| const dataItem = { | |||
| name: item[1], | |||
| value: item, | |||
| itemStyle: { | |||
| color: colorArr[dataIndex], | |||
| }, | |||
| }; | |||
| seriesData.push(dataItem); | |||
| }); | |||
| option.series = [ | |||
| { | |||
| type: 'custom', | |||
| dimensions: ['x', 'y'], | |||
| renderItem: (params, api) => { | |||
| const points = this.makePolyPoints( | |||
| params.dataIndex, | |||
| api.coord, | |||
| params.coordSys.y - 10, | |||
| ); | |||
| return { | |||
| type: 'polyline', | |||
| silent: true, | |||
| shape: { | |||
| points, | |||
| }, | |||
| style: api.style({ | |||
| stroke: '#bbb', | |||
| lineWidth: 1, | |||
| }), | |||
| }; | |||
| }, | |||
| data: seriesData, | |||
| }, | |||
| ]; | |||
| option.yAxis.data = oriData.gridData; | |||
| option.yAxis.type = 'category'; | |||
| option.grid.top = 126; | |||
| if (axisName === 2 && this.fullScreen) { | |||
| option.grid.right = 140; | |||
| } | |||
| option.yAxis.inverse = true; | |||
| const that = this; | |||
| option.yAxis.axisLabel.formatter = function(value) { | |||
| return that.yAxisFormatter(value); | |||
| }; | |||
| } else if (this.viewName === 0) { | |||
| option.color = colorArr; | |||
| option.series = []; | |||
| oriData.seriesData.forEach((k) => { | |||
| option.series.push({ | |||
| type: 'line', | |||
| symbol: 'none', | |||
| lineStyle: { | |||
| width: 1, | |||
| }, | |||
| data: k.slice(1, -1), | |||
| }); | |||
| }); | |||
| } | |||
| return option; | |||
| }, | |||
| /** | |||
| * Expand/Collapse in full screen | |||
| */ | |||
| toggleFullScreen() { | |||
| this.removeTooltip(); | |||
| if (!this.fullScreen) { | |||
| if (this.axisName === 2) { | |||
| // this.charObj.setOption({grid: {right: 140}}); | |||
| this.charOption.grid.right = 140; | |||
| } | |||
| this.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor = | |||
| '#3E98C5'; | |||
| } else { | |||
| // this.charObj.setOption({grid: {right: 40}}); | |||
| this.charOption.grid.right = 40; | |||
| this.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor = | |||
| '#6D7278'; | |||
| } | |||
| this.charObj.setOption(this.charOption); | |||
| this.$emit('toggleFullScreen'); | |||
| }, | |||
| /** | |||
| * remove tooltip | |||
| */ | |||
| removeTooltip() { | |||
| if (this.zr) { | |||
| if (this.zrDrawElement.hoverDots) { | |||
| this.zrDrawElement.hoverDots.forEach((dot) => this.zr.remove(dot)); | |||
| } | |||
| if (this.zrDrawElement.hoverLine) { | |||
| this.zr.remove(this.zrDrawElement.hoverLine); | |||
| } | |||
| if (this.zrDrawElement.tooltip) { | |||
| this.zr.remove(this.zrDrawElement.tooltip); | |||
| } | |||
| if (this.zrDrawElement.tooltipY) { | |||
| this.zr.remove(this.zrDrawElement.tooltipY); | |||
| } | |||
| if (this.zrDrawElement.tooltipX) { | |||
| this.zr.remove(this.zrDrawElement.tooltipX); | |||
| } | |||
| } | |||
| }, | |||
| /** | |||
| * Calculate polygon points | |||
| * @param {Number} dataIndex | |||
| * @param {Object} getCoord | |||
| * @param {Number} yValueMapHeight | |||
| * @return {Array} Array of ploygon points | |||
| */ | |||
| makePolyPoints(dataIndex, getCoord, yValueMapHeight) { | |||
| const points = []; | |||
| const rawData = this.oriData.seriesData; | |||
| const maxZ = this.oriData.maxZ; | |||
| const minZ = this.oriData.minZ; | |||
| for (let i = 0; i < rawData[dataIndex].length; ) { | |||
| const x = this.getValue(rawData, dataIndex, i++); | |||
| const y = this.getValue(rawData, dataIndex, i++); | |||
| const z = this.getValue(rawData, dataIndex, i++); | |||
| const pt = getCoord([x, y]); | |||
| // linear map in z axis | |||
| if (maxZ !== minZ) { | |||
| pt[1] -= ((z - minZ) / (maxZ - minZ)) * yValueMapHeight; | |||
| } | |||
| points.push(pt); | |||
| } | |||
| return points; | |||
| }, | |||
| /** | |||
| * get convert point | |||
| * @param {Array} pt value | |||
| * @return {Array} | |||
| */ | |||
| getCoord(pt) { | |||
| return this.charObj.convertToPixel('grid', pt); | |||
| }, | |||
| /** | |||
| * Formate Y coordinate display | |||
| * @param {Number} value | |||
| * @return {Object} | |||
| */ | |||
| yAxisFormatter(value) { | |||
| let data = ''; | |||
| const filter = this.fullData.filter((k) => k.step === value); | |||
| if (filter.length) { | |||
| if (this.axisName === 2) { | |||
| data = this.fullScreen | |||
| ? this.dealrelativeTime( | |||
| new Date(filter[0].wall_time * 1000).toString(), | |||
| ) | |||
| : []; | |||
| } else if (this.axisName === 1) { | |||
| data = `${(filter[0].relative_time / 3600).toFixed(3)}h`; | |||
| } else { | |||
| data = filter[0].step; | |||
| } | |||
| } | |||
| return data; | |||
| }, | |||
| /** | |||
| * Formate time display | |||
| * @param {Onject} time | |||
| * @return {String} Formatted time | |||
| */ | |||
| dealrelativeTime(time) { | |||
| const arr = time.split(' '); | |||
| const str = arr[0] + ' ' + arr[1] + ' ' + arr[2] + ',' + ' ' + arr[4]; | |||
| return str; | |||
| }, | |||
| /** | |||
| * Mouse move event | |||
| * @param {Object} e Original event | |||
| */ | |||
| mousemoveEvent(e) { | |||
| const unit = 's'; | |||
| const nearestIndex = this.findNearestValue([e.offsetX, e.offsetY]); | |||
| if ( | |||
| nearestIndex && | |||
| nearestIndex.yIndex !== null && | |||
| nearestIndex.binIndex !== null | |||
| ) { | |||
| const {binIndex, yIndex} = nearestIndex; | |||
| const chartData = this.fullData; | |||
| const hoveredItem = chartData[yIndex]; | |||
| const p = Math.max(0, d3.precisionRound(0.01, 1.01) - 1); | |||
| const yValueFormat = d3.format(`.${p}e`); | |||
| const gridRect = this.charObj | |||
| .getModel() | |||
| .getComponent('grid', 0) | |||
| .coordinateSystem.getRect(); | |||
| const gridRectY = gridRect.y - 10; | |||
| let linePoints = []; | |||
| if (!hoveredItem || !hoveredItem.items[binIndex]) { | |||
| return; | |||
| } | |||
| if (!this.chartTipFlag) { | |||
| this.chartTipFlag = true; | |||
| this.$emit('chartTipFlagChange', this.chartTipFlag); | |||
| } | |||
| if (this.viewName === 1 && yIndex !== null) { | |||
| linePoints = this.makePolyPoints(yIndex, this.getCoord, gridRectY); | |||
| } else if (this.viewName === 0 && hoveredItem.items) { | |||
| hoveredItem.items.forEach((item) => { | |||
| linePoints.push(this.getCoord([item[2], item[3]])); | |||
| }); | |||
| } | |||
| this.zrDrawElement.hoverLine = new echarts.graphic.Polyline({ | |||
| silent: true, | |||
| shape: { | |||
| points: linePoints.slice(1, -1), | |||
| }, | |||
| z: 999, | |||
| }); | |||
| this.zr.add(this.zrDrawElement.hoverLine); | |||
| this.zrDrawElement.tooltip = new echarts.graphic.Text({}); | |||
| let itemX; | |||
| const x = hoveredItem.items[binIndex][2]; | |||
| let z = 0; | |||
| chartData.forEach((dataItem, index) => { | |||
| const y = dataItem.step; | |||
| const pt = this.getCoord([x, y]); | |||
| if (index === yIndex) { | |||
| z = hoveredItem.items[binIndex][3]; | |||
| } else { | |||
| const items = dataItem.items; | |||
| for (let k = 1; k < items.length - 1; k++) { | |||
| const nextX = items[k + 1][2]; | |||
| const nextZ = items[k + 1][3]; | |||
| if (items[k][2] === x) { | |||
| z = items[k][3]; | |||
| break; | |||
| } else if (items[k][2] < x && nextX > x) { | |||
| const proportionX = (x - items[k][2]) / (nextX - items[k][2]); | |||
| z = (nextZ - items[k][3]) * proportionX + items[k][3]; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| itemX = pt[0]; | |||
| const circleOption = { | |||
| z: 1000, | |||
| }; | |||
| if (this.viewName === 1) { | |||
| pt[1] -= | |||
| ((z - this.oriData.minZ) / | |||
| (this.oriData.maxZ - this.oriData.minZ)) * | |||
| gridRectY; | |||
| circleOption.shape = { | |||
| cx: itemX, | |||
| cy: pt[1], | |||
| r: 1.5, | |||
| }; | |||
| } else { | |||
| circleOption.shape = { | |||
| cx: 0, | |||
| cy: 0, | |||
| r: 1.5, | |||
| }; | |||
| circleOption.position = this.charObj.convertToPixel('grid', [x, z]); | |||
| } | |||
| const dot = new echarts.graphic.Circle(circleOption); | |||
| this.zr.add(dot); | |||
| this.zrDrawElement.hoverDots.push(dot); | |||
| }); | |||
| this.zrDrawElement.tooltip = new echarts.graphic.Text({}); | |||
| let htmlStr = ''; | |||
| const hoveredAxis = hoveredItem.items[binIndex][3]; | |||
| htmlStr = `<td>${ | |||
| hoveredAxis.toString().length >= 6 | |||
| ? yValueFormat(hoveredAxis) | |||
| : hoveredAxis | |||
| }</td><td style="text-align:center;">${hoveredItem.step}</td><td>${( | |||
| hoveredItem.relative_time / 1000 | |||
| ).toFixed(3)}${unit}</td><td>${this.dealrelativeTime( | |||
| new Date(hoveredItem.wall_time * 1000).toString(), | |||
| )}</td>`; | |||
| const dom = document.querySelector('#tipTr'); | |||
| dom.innerHTML = htmlStr; | |||
| const chartElement = document.getElementById(this.itemId); | |||
| if (chartElement) { | |||
| if (!this.fullScreen) { | |||
| const chartWidth = | |||
| chartElement.parentNode.parentNode.parentNode.parentNode | |||
| .clientWidth; | |||
| const chartHeight = | |||
| chartElement.parentNode.parentNode.parentNode.parentNode | |||
| .clientHeight; | |||
| const left = | |||
| chartElement.parentNode.parentNode.parentNode.parentNode | |||
| .offsetLeft; | |||
| const top = | |||
| chartElement.parentNode.parentNode.parentNode.parentNode | |||
| .offsetTop; | |||
| const echartTip = document.querySelector('#echartTip'); | |||
| echartTip.style.top = `${top + chartHeight - 60}px`; | |||
| if (left > echartTip.clientWidth) { | |||
| echartTip.style.left = `${left - echartTip.clientWidth}px`; | |||
| } else { | |||
| echartTip.style.left = `${left + chartWidth}px`; | |||
| } | |||
| } else { | |||
| const width = document.querySelector('#echartTip').clientWidth; | |||
| const height = document.querySelector('#echartTip').clientHeight; | |||
| const screenWidth = document.body.scrollWidth; | |||
| const screenHeight = document.body.scrollHeight; | |||
| const scrollTop = document.querySelector('.cl-show-data-content') | |||
| .scrollTop; | |||
| const offsetTop = document.querySelector('.cl-show-data-content') | |||
| .offsetTop; | |||
| if ( | |||
| height + e.event.y + 20 > screenHeight && | |||
| screenHeight > height | |||
| ) { | |||
| document.querySelector('#echartTip').style.top = `${e.event.y + | |||
| scrollTop - | |||
| height - | |||
| 20 - | |||
| offsetTop}px`; | |||
| } else { | |||
| document.querySelector('#echartTip').style.top = `${e.event.y + | |||
| scrollTop + | |||
| 20 - | |||
| offsetTop}px`; | |||
| } | |||
| if (width + e.event.x + 50 > screenWidth && screenWidth > width) { | |||
| document.querySelector('#echartTip').style.left = `${e.event.x - | |||
| width - | |||
| 20}px`; | |||
| } else { | |||
| document.querySelector('#echartTip').style.left = `${e.event.x + | |||
| 20}px`; | |||
| } | |||
| } | |||
| } | |||
| this.zrDrawElement.tooltipX = new echarts.graphic.Text({ | |||
| position: [itemX, gridRect.y + gridRect.height], | |||
| style: { | |||
| text: | |||
| x.toString().length >= 6 | |||
| ? x.toExponential(3) | |||
| : Math.round(x * 1000) / 1000, | |||
| textFill: '#fff', | |||
| textAlign: 'center', | |||
| fontSize: 12, | |||
| textBackgroundColor: '#333', | |||
| textBorderWidth: 2, | |||
| textPadding: [5, 7], | |||
| rich: {}, | |||
| }, | |||
| z: 2000, | |||
| }); | |||
| this.zr.add(this.zrDrawElement.tooltipX); | |||
| if (this.viewName === 1 && linePoints && linePoints.length) { | |||
| let text = ''; | |||
| if (yIndex !== null) { | |||
| text = this.yAxisFormatter(hoveredItem.step); | |||
| } | |||
| this.zrDrawElement.tooltipY = new echarts.graphic.Text({ | |||
| position: [ | |||
| gridRect.x + gridRect.width, | |||
| linePoints[linePoints.length - 1][1], | |||
| ], | |||
| style: { | |||
| text: text, | |||
| textFill: '#fff', | |||
| textVerticalAlign: 'middle', | |||
| fontSize: 12, | |||
| textBackgroundColor: '#333', | |||
| textBorderWidth: 2, | |||
| textPadding: [5, 7], | |||
| rich: {}, | |||
| }, | |||
| z: 2000, | |||
| }); | |||
| this.zr.add(this.zrDrawElement.tooltipY); | |||
| } | |||
| } | |||
| }, | |||
| /** | |||
| * find nearest value | |||
| * @param {Array} eventPoint value | |||
| * @return {Object} | |||
| */ | |||
| findNearestValue(eventPoint) { | |||
| if (!eventPoint || !eventPoint.length || !this.charObj || !this.oriData) { | |||
| return; | |||
| } | |||
| const value = this.charObj.convertFromPixel('grid', eventPoint); | |||
| if (!value || !value.length) { | |||
| return; | |||
| } | |||
| let binIndex = null; | |||
| let yIndex = null; | |||
| let nearestX = Infinity; | |||
| let nearestY = -Infinity; | |||
| let nearestYData = Infinity; | |||
| const gridRect = this.charObj | |||
| .getModel() | |||
| .getComponent('grid', 0) | |||
| .coordinateSystem.getRect(); | |||
| const gridRectY = gridRect.y - 10; | |||
| const x = value[0]; | |||
| this.fullData.forEach((dataItem, i) => { | |||
| let distY; | |||
| let yAxis; | |||
| for (let k = 0; k < dataItem.items.length - 1; k++) { | |||
| const item = dataItem.items[k]; | |||
| const itemNext = dataItem.items[k + 1]; | |||
| const nextX = itemNext[2]; | |||
| const nextZ = itemNext[3]; | |||
| if (item.length >= 4) { | |||
| if (item[2] < x && nextX >= x) { | |||
| const proportionX = (x - item[2]) / (nextX - item[2]); | |||
| yAxis = (nextZ - item[3]) * proportionX + item[3]; | |||
| distY = Math.abs(value[1] - yAxis); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| if (this.viewName === 0 && distY < nearestYData) { | |||
| nearestYData = distY; | |||
| yIndex = i; | |||
| } else if (this.viewName === 1) { | |||
| const pt = this.getCoord([x, dataItem.step]); | |||
| const ptStep = pt[1]; | |||
| pt[1] -= | |||
| ((yAxis - this.oriData.minZ) / | |||
| (this.oriData.maxZ - this.oriData.minZ)) * | |||
| gridRectY; | |||
| if ( | |||
| eventPoint[1] > pt[1] && | |||
| eventPoint[1] < ptStep && | |||
| ptStep > nearestY | |||
| ) { | |||
| nearestY = ptStep; | |||
| yIndex = i; | |||
| } | |||
| } | |||
| }); | |||
| if (yIndex === null && this.viewName === 1) { | |||
| this.fullData.forEach((item, index) => { | |||
| if (index > value[1]) { | |||
| yIndex = yIndex === null ? index : Math.min(yIndex, index); | |||
| } | |||
| }); | |||
| } | |||
| if (yIndex !== null) { | |||
| const yData = this.fullData[yIndex].items; | |||
| yData.forEach((ele, index) => { | |||
| const distX = Math.abs(ele[2] - value[0]); | |||
| if (distX < nearestX) { | |||
| nearestX = distX; | |||
| binIndex = index; | |||
| } | |||
| }); | |||
| binIndex = | |||
| binIndex === 0 | |||
| ? 1 | |||
| : binIndex === yData.length - 1 | |||
| ? yData.length - 2 | |||
| : binIndex; | |||
| } | |||
| return { | |||
| binIndex, | |||
| yIndex, | |||
| }; | |||
| }, | |||
| /** | |||
| * Calculate gradient color | |||
| * @param {String} startColor | |||
| * @param {String} endColor | |||
| * @param {Number} step | |||
| * @return {Array} Array of gradient color | |||
| */ | |||
| getGrientColor(startColor, endColor, step) { | |||
| const startRgb = this.formatColor(startColor); | |||
| const endRgb = this.formatColor(endColor); | |||
| const gapRgbR = (endRgb[0] - startRgb[0]) / step; | |||
| const gapRgbG = (endRgb[1] - startRgb[1]) / step; | |||
| const gapRgbB = (endRgb[2] - startRgb[2]) / step; | |||
| const colorResult = []; | |||
| for (let i = 0; i < step; i++) { | |||
| const sR = parseInt(gapRgbR * i + startRgb[0]); | |||
| const sG = parseInt(gapRgbG * i + startRgb[1]); | |||
| const sB = parseInt(gapRgbB * i + startRgb[2]); | |||
| const hex = this.formatColorToHex(`rgb(${sR},${sG},${sB})`); | |||
| colorResult.push(hex); | |||
| } | |||
| return colorResult; | |||
| }, | |||
| /** | |||
| * Converts a color string to recognizable format | |||
| * @param {String} str Color string | |||
| * @return {String} | |||
| */ | |||
| formatColor(str) { | |||
| if (!str) { | |||
| return; | |||
| } | |||
| const colorReg = /^([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/; | |||
| let colorStr = str.toLowerCase().slice(1); | |||
| if (colorReg.test(colorStr)) { | |||
| let colorStrNew = ''; | |||
| if (colorStr.length === 3) { | |||
| for (let i = 0; i < 3; i++) { | |||
| colorStrNew += colorStrNew | |||
| .slice(i, i + 1) | |||
| .concat(colorStrNew.slice(i, i + 1)); | |||
| } | |||
| colorStr = colorStrNew; | |||
| } | |||
| const colorFormat = []; | |||
| for (let i = 0; i < 6; i += 2) { | |||
| colorFormat.push(parseInt(`0x${colorStr.slice(i, i + 2)}`)); | |||
| } | |||
| return colorFormat; | |||
| } else { | |||
| return colorStr; | |||
| } | |||
| }, | |||
| /** | |||
| * Converts rgb color string to hex | |||
| * @param {String} rgb Rgb color | |||
| * @return {String} Hex color | |||
| */ | |||
| formatColorToHex(rgb) { | |||
| const regRgb = /^(rgb|RGB)/g; | |||
| if (regRgb.test(rgb)) { | |||
| const colorSplit = rgb.replace(/(?:(|)|rgb|RGB)*/g, '').split(','); | |||
| let hexStr = ''; | |||
| for (let i = 0; i < colorSplit.length; i++) { | |||
| let hexItem = Number(colorSplit[i]).toString(16); | |||
| hexItem = hexItem < 10 ? `0${hexItem}` : hexItem; | |||
| if (hexItem === '0') { | |||
| hexItem += hexItem; | |||
| } | |||
| hexStr += hexItem; | |||
| } | |||
| if (hexStr.length !== 6) { | |||
| hexStr = rgb; | |||
| } | |||
| return hexStr; | |||
| } | |||
| }, | |||
| /** | |||
| * Get value | |||
| * @param {Object} seriesData | |||
| * @param {Number} dataIndex | |||
| * @param {Number} i | |||
| * @return {Number} | |||
| */ | |||
| getValue(seriesData, dataIndex, i) { | |||
| return seriesData[dataIndex][i]; | |||
| }, | |||
| /** | |||
| * Unbing event | |||
| */ | |||
| clearZrData() { | |||
| if (this.zr) { | |||
| this.removeTooltip(); | |||
| this.zr.off('mouseout', 'mousemove'); | |||
| this.zr = null; | |||
| } | |||
| }, | |||
| /** | |||
| * Update histogram data | |||
| */ | |||
| updateHistogramData() { | |||
| this.$nextTick(() => { | |||
| this.formatDataToChar(); | |||
| this.updateSampleData(); | |||
| this.sampleEventBind(); | |||
| }); | |||
| }, | |||
| }, | |||
| destroyed() { | |||
| this.clearZrData(); | |||
| }, | |||
| }; | |||
| </script> | |||
| <style lang="scss"> | |||
| .cl-histogram-container { | |||
| width: 100%; | |||
| height: 100%; | |||
| display: flex; | |||
| flex-direction: column; | |||
| .data-show-container { | |||
| width: 100%; | |||
| flex: 1; | |||
| .data-item { | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| } | |||
| } | |||
| </style> | |||
| @@ -21,7 +21,9 @@ | |||
| }, | |||
| "symbols": { | |||
| "leftbracket": "(", | |||
| "rightbracket": ")" | |||
| "rightbracket": ")", | |||
| "point": "·", | |||
| "slashes": "/" | |||
| }, | |||
| "header": { | |||
| "refreshData": "刷新数据", | |||
| @@ -166,6 +168,14 @@ | |||
| "dataMap": { | |||
| "titleText": "数据图" | |||
| }, | |||
| "tensors": { | |||
| "titleText": "张量", | |||
| "dimension": "形状:", | |||
| "tensorType": "数据类型:", | |||
| "viewTypeTitle": "视图", | |||
| "chartViewType": "表格", | |||
| "histogramViewType": "直方图" | |||
| }, | |||
| "graph": { | |||
| "titleText": "计算图", | |||
| "downloadPic": "下载", | |||
| @@ -381,7 +391,11 @@ | |||
| "selectAll": "全选", | |||
| "tagFilterPlaceHolder": "请输入需要的标签(支持正则表达式)", | |||
| "open": "展开", | |||
| "close": "折叠" | |||
| "close": "折叠", | |||
| "gridIncorrectDataError": "当前只支持最多二维数组的展示", | |||
| "gridAccuracy": "保留小数位", | |||
| "inCorrectInput": "无效输入", | |||
| "gridTableNoData": "表格无数据" | |||
| }, | |||
| "error": { | |||
| "50540000": "系统错误", | |||
| @@ -22,7 +22,9 @@ import ElementUI from 'element-ui'; | |||
| import './assets/css/element.css'; | |||
| import './assets/css/reset.scss'; | |||
| import i18n from './i18n'; | |||
| import $ from 'jquery'; | |||
| window.$ = window.jQuery = $; | |||
| Vue.use(ElementUI); | |||
| Vue.prototype.$bus = new Vue(); | |||
| @@ -54,6 +54,10 @@ export default new Router({ | |||
| path: '/train-manage/histogram', | |||
| component: () => import('./views/train-manage/histogram.vue'), | |||
| }, | |||
| { | |||
| path: '/train-manage/tensor', | |||
| component: () => import('./views/train-manage/tensor.vue'), | |||
| }, | |||
| { | |||
| path: '/train-manage/graph', | |||
| component: () => import('./views/train-manage/graph.vue'), | |||
| @@ -66,6 +66,18 @@ export default { | |||
| }); | |||
| }, | |||
| // query tensors sample | |||
| getTensorsSample(params) { | |||
| return axios({ | |||
| method: 'get', | |||
| url: 'v1/mindinsight/datavisual/tensors', | |||
| params: params, | |||
| headers: { | |||
| ignoreError: true, | |||
| }, | |||
| }); | |||
| }, | |||
| // query graph data | |||
| queryGraphData(params) { | |||
| return axios({ | |||
| @@ -33,6 +33,7 @@ export default new Vuex.Store({ | |||
| // multiSelevtGroup component count | |||
| multiSelectedGroupCount: 0, | |||
| tableId: 0, | |||
| componentsCount: 0, | |||
| }, | |||
| mutations: { | |||
| // set cancelTokenArr | |||
| @@ -76,6 +77,9 @@ export default new Vuex.Store({ | |||
| increaseTableId(state) { | |||
| state.tableId++; | |||
| }, | |||
| componentsNum(state) { | |||
| state.componentsCount++; | |||
| }, | |||
| }, | |||
| actions: {}, | |||
| }); | |||
| @@ -90,7 +90,8 @@ limitations under the License. | |||
| <div class="chars-container"> | |||
| <div class="char-item-content" | |||
| :id="sampleItem.domId"></div> | |||
| <div class="tag-title">{{sampleItem.tagName}}</div> | |||
| <div class="tag-title" | |||
| :title="sampleItem.tagName">{{sampleItem.tagName}}</div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -1325,16 +1326,17 @@ export default { | |||
| sampleObject.fullScreen = !sampleObject.fullScreen; | |||
| if (sampleObject.fullScreen) { | |||
| if (this.curAxisName === 2) { | |||
| sampleObject.charObj.setOption({grid: {right: 140}}); | |||
| sampleObject.charOption.grid.right = 140; | |||
| } | |||
| sampleObject.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor = | |||
| '#3E98C5'; | |||
| } else { | |||
| sampleObject.charObj.setOption({grid: {right: 40}}); | |||
| sampleObject.charOption.grid.right = 40; | |||
| sampleObject.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor = | |||
| '#6D7278'; | |||
| } | |||
| setTimeout(() => { | |||
| sampleObject.charObj.setOption(sampleObject.charOption); | |||
| sampleObject.charObj.resize(); | |||
| document.getElementById(sampleObject.domId).scrollIntoView(); | |||
| }, 0); | |||
| @@ -146,12 +146,28 @@ limitations under the License. | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="cl-dashboard-con-up no-data-hover"> | |||
| <div class="coming-soon-content"> | |||
| <div class="coming-soon-container"> | |||
| <img :src="require('@/assets/images/coming-soon.png')" /> | |||
| <p class='coming-soon-text'> | |||
| {{$t("public.stayTuned")}} | |||
| <div class="cl-dashboard-con-up" | |||
| :class="!!tensorTag && !wrongPlugin ? '' : 'no-data-hover'" | |||
| @click="viewMoreTensors"> | |||
| <div class="cl-dashboard-title">{{$t("tensors.titleText")}}</div> | |||
| <div class="cl-module"> | |||
| <div class="tensor-char-container" | |||
| v-show="!!tensorTag && !wrongPlugin"> | |||
| <div id="tensor-chart-container"> | |||
| <gridTableComponents ref="tensorChart" | |||
| :showOperate="false" | |||
| :fullData="tensorData"></gridTableComponents> | |||
| </div> | |||
| <div class="tag-text" | |||
| :title="tensorTag">{{tensorTag}}</div> | |||
| </div> | |||
| <div class="no-data-img" | |||
| key="no-chart-data" | |||
| v-show="!tensorTag || wrongPlugin"> | |||
| <img :src="require('@/assets/images/nodata.png')" | |||
| alt="" /> | |||
| <p class='no-data-text'> | |||
| {{$t("public.noData")}} | |||
| </p> | |||
| </div> | |||
| </div> | |||
| @@ -168,6 +184,7 @@ import {select, selectAll, format, precisionRound} from 'd3'; | |||
| import 'd3-graphviz'; | |||
| const d3 = {select, selectAll, format, precisionRound}; | |||
| import echarts from 'echarts'; | |||
| import gridTableComponents from '../../components/gridTableSimple'; | |||
| export default { | |||
| data() { | |||
| return { | |||
| @@ -201,6 +218,8 @@ export default { | |||
| reloadStopTime: 1000, | |||
| wrongPlugin: false, | |||
| fileTag: '', | |||
| tensorData: [], | |||
| tensorTag: '', | |||
| }; | |||
| }, | |||
| computed: { | |||
| @@ -218,6 +237,9 @@ export default { | |||
| return this.$store.state.timeReloadValue; | |||
| }, | |||
| }, | |||
| components: { | |||
| gridTableComponents, | |||
| }, | |||
| watch: { | |||
| isReload(newVal) { | |||
| if (newVal) { | |||
| @@ -282,6 +304,10 @@ export default { | |||
| if (this.histogramObj) { | |||
| this.histogramObj.resize(); | |||
| } | |||
| const elementItem = this.$refs.tensorChart; | |||
| if (elementItem) { | |||
| elementItem.resizeView(); | |||
| } | |||
| }, 500); | |||
| }, | |||
| @@ -330,6 +356,7 @@ export default { | |||
| const imageTags = data.image || []; | |||
| const scalarTags = data.scalar || []; | |||
| const graphIds = data.graph || []; | |||
| const tensorTags = data.tensor || []; | |||
| if (graphIds.length) { | |||
| this.fileTag = graphIds[0]; | |||
| } | |||
| @@ -337,6 +364,7 @@ export default { | |||
| this.getHistogramTag(histogramTags); | |||
| this.dealImageData(imageTags); | |||
| this.getScalarList(scalarTags); | |||
| this.dealTensorData(tensorTags); | |||
| if (!this.firstFloorNodes.length && graphIds.length) { | |||
| this.queryGraphData(); | |||
| } | |||
| @@ -383,6 +411,20 @@ export default { | |||
| }, | |||
| }); | |||
| }, | |||
| /** | |||
| * Viewing more tensors information | |||
| */ | |||
| viewMoreTensors() { | |||
| if (!this.tensorTag) { | |||
| return; | |||
| } | |||
| this.$router.push({ | |||
| path: '/train-manage/tensor', | |||
| query: { | |||
| train_id: this.trainingJobId, | |||
| }, | |||
| }); | |||
| }, | |||
| /** | |||
| * Go to data. | |||
| */ | |||
| @@ -785,6 +827,117 @@ export default { | |||
| this.originImageDataArr = dataList; | |||
| this.getSampleRandomly(); | |||
| }, | |||
| dealTensorData(tags) { | |||
| if (tags.length) { | |||
| this.tensorTag = tags[0]; | |||
| } else { | |||
| this.tensorTag = ''; | |||
| } | |||
| if (this.tensorTag) { | |||
| this.getTensorGridData(); | |||
| } | |||
| }, | |||
| getTensorGridData() { | |||
| const params = { | |||
| train_id: this.trainingJobId, | |||
| tag: this.tensorTag, | |||
| detail: 'stats', | |||
| }; | |||
| RequestService.getTensorsSample(params).then( | |||
| (res) => { | |||
| if (!res || !res.data) { | |||
| return; | |||
| } | |||
| if (!res.data.tensors.length) { | |||
| return; | |||
| } | |||
| const resData = JSON.parse(JSON.stringify(res.data.tensors[0])); | |||
| if (!resData.values.length) { | |||
| this.tensorData = []; | |||
| this.$nextTick(() => { | |||
| const elementItem = this.$refs.tensorChart; | |||
| if (elementItem) { | |||
| elementItem.updateGridData(); | |||
| } | |||
| }); | |||
| return; | |||
| } | |||
| const data = resData.values[resData.values.length - 1]; | |||
| const filterStr = this.initFilterStr(data.value.dims); | |||
| this.freshtMartixData(data.step, filterStr); | |||
| }, | |||
| () => { | |||
| this.tensorData = []; | |||
| this.$nextTick(() => { | |||
| const elementItem = this.$refs.tensorChart; | |||
| if (elementItem) { | |||
| elementItem.updateGridData(); | |||
| } | |||
| }); | |||
| }, | |||
| ); | |||
| }, | |||
| initFilterStr(array) { | |||
| if (!array) { | |||
| return []; | |||
| } | |||
| const countLinit = array.length - 2; | |||
| const tempArr = []; | |||
| for (let i = 0; i < array.length; i++) { | |||
| tempArr.push(i >= countLinit ? ':' : '0'); | |||
| } | |||
| return `[${tempArr.toString()}]`; | |||
| }, | |||
| freshtMartixData(step, filterStr) { | |||
| const params = { | |||
| train_id: this.trainingJobId, | |||
| tag: this.tensorTag, | |||
| detail: 'data', | |||
| step: step, | |||
| dims: filterStr, | |||
| }; | |||
| RequestService.getTensorsSample(params).then( | |||
| (res) => { | |||
| if (!res || !res.data) { | |||
| return; | |||
| } | |||
| if (!res.data.tensors.length) { | |||
| return; | |||
| } | |||
| const resData = res.data.tensors[0]; | |||
| const curStepData = resData.values[0]; | |||
| let statistics = {}; | |||
| if (curStepData) { | |||
| this.tensorData = | |||
| curStepData.value.data instanceof Array | |||
| ? curStepData.value.data | |||
| : [curStepData.value.data]; | |||
| statistics = curStepData.value.statistics; | |||
| } else { | |||
| this.tensorData = [[]]; | |||
| } | |||
| this.$nextTick(() => { | |||
| const elementItem = this.$refs.tensorChart; | |||
| if (elementItem) { | |||
| elementItem.updateGridData( | |||
| true, | |||
| curStepData.value.dims, | |||
| statistics, | |||
| ); | |||
| } | |||
| }); | |||
| }, | |||
| () => { | |||
| this.tensorData = []; | |||
| this.$nextTick(() => { | |||
| const elementItem = this.$refs.tensorChart; | |||
| if (elementItem) { | |||
| elementItem.updateGridData(); | |||
| } | |||
| }); | |||
| }, | |||
| ); | |||
| }, | |||
| getHistogramTag(tagList) { | |||
| if (!tagList) { | |||
| return; | |||
| @@ -1889,20 +2042,6 @@ export default { | |||
| } | |||
| } | |||
| .coming-soon-content { | |||
| width: 100%; | |||
| height: 100%; | |||
| text-align: center; | |||
| .coming-soon-container { | |||
| position: relative; | |||
| top: calc(50% - 88px); | |||
| .coming-soon-text { | |||
| color: #000000; | |||
| font-size: 16px; | |||
| } | |||
| } | |||
| } | |||
| .no-data-hover { | |||
| cursor: not-allowed; | |||
| } | |||
| @@ -1928,13 +2067,15 @@ export default { | |||
| cursor: pointer; | |||
| } | |||
| } | |||
| #distribution-chart { | |||
| #distribution-chart, | |||
| #tensor-chart-container { | |||
| height: calc(100% - 19px); | |||
| canvas { | |||
| cursor: pointer; | |||
| } | |||
| } | |||
| .histogram-char-container { | |||
| .histogram-char-container, | |||
| .tensor-char-container { | |||
| height: 100%; | |||
| width: 100%; | |||
| cursor: pointer; | |||