Browse Source

Change the display of searched graphs from list to tree

tags/v1.1.0
fengxuefeng 5 years ago
parent
commit
21a5942c0a
3 changed files with 422 additions and 46 deletions
  1. +12
    -3
      mindinsight/ui/src/mixins/commonGraph.vue
  2. +2
    -10
      mindinsight/ui/src/mixins/debuggerMixin.vue
  3. +408
    -33
      mindinsight/ui/src/views/train-manage/graph.vue

+ 12
- 3
mindinsight/ui/src/mixins/commonGraph.vue View File

@@ -120,9 +120,18 @@ export default {
this.selectNode(false);
}
}
if (pageKey === 'debugger') {
this.nodeCollapseLinkage(this.selectedNode.name);
}
this.nodeCollapseLinkage(this.selectedNode.name);
},
/**
* Tree linkage with graph
* Collapse of current node
* @param {Obejct} name The name of the current node
*/
nodeCollapseLinkage(name) {
const node = this.$refs.tree.getNode(name.replace('_unfold', ''));
node.expanded = false;
node.loaded = false;
node.childNodes = [];
},
/**
* Initializing the graph


+ 2
- 10
mindinsight/ui/src/mixins/debuggerMixin.vue View File

@@ -155,6 +155,8 @@ export default {

if (this.version === 'GPU') {
this.conditions.noValue.push('NAN');
} else {
this.conditions.noValue.push('OVERFLOW');
}

this.conditions.options = this.conditions.noValue
@@ -1119,16 +1121,6 @@ export default {
},
);
},
/**
* Tree linkage with graph Collapse of current node
* @param {Obejct} name The name of the current node
*/
nodeCollapseLinkage(name) {
const node = this.$refs.tree.getNode(name.replace('_unfold', ''));
node.expanded = false;
node.loaded = false;
node.childNodes = [];
},
/**
* Tree linkage with graph Expand of current node
* @param {Obejct} nodes Data of children of current node


+ 408
- 33
mindinsight/ui/src/views/train-manage/graph.vue View File

@@ -131,17 +131,82 @@ limitations under the License.
</el-option>
</el-select>
<!-- Search box -->
<Autocomplete class="search"
v-model="searchBox.value"
:disabled="!fileSearchBox.value"
:fetch-suggestions="searchNodesNames"
:placeholder="$t('graph.inputNodeName')"
:popper-append-to-body="false"
clearable
@select="querySingleNode"
@blur="selectBoxVisibleTriggle"
@focus="selectBoxVisibleTriggle"
select-when-unmatched></Autocomplete>
<div class="search-wrap">
<el-input class="search"
:placeholder="$t('graph.inputNodeName')"
v-model="searchBox.value"
@input="filterChange"
@keyup.enter.native="searchNodesNames"
clearable>
<el-button slot="append"
@click="treeWrapFlag=!treeWrapFlag"
class="collapse_i">
<i class="el-icon-caret-bottom"
v-if="!treeWrapFlag"></i>
<i class="el-icon-caret-top"
v-else></i>
</el-button>
</el-input>
<div class="tree-wrap"
v-show="treeWrapFlag">
<el-tree v-show="treeFlag"
:props="props"
:load="loadNode"
@node-collapse="nodeCollapse"
@node-click="handleNodeClick"
node-key="name"
:expand-on-click-node="false"
:lazy="true"
:highlight-current="true"
ref="tree">
<span class="custom-tree-node"
slot-scope="{ node ,data }">
<span>
<img v-if="data.type ==='name_scope'"
:src="require('@/assets/images/name-scope.svg')"
class="image-type" />
<img v-else-if="data.type ==='Const'"
:src="require('@/assets/images/constant-node.svg')"
class="image-type" />
<img v-else-if="data.type ==='aggregation_scope'"
:src="require('@/assets/images/polymetric.svg')"
class="image-type" />
<img v-else
:src="require('@/assets/images/operator-node.svg')"
class="image-type" />
</span>
<span class="custom-tree-node">{{ node.label }}</span>
</span>
</el-tree>
<el-tree v-show="!treeFlag"
:props="defaultProps"
:load="loadSearchNode"
:lazy="true"
node-key="name"
@node-click="handleNodeClick"
:expand-on-click-node="false"
ref="searchTree">
<span class="custom-tree-node"
slot-scope="{ node ,data }">
<span>
<img v-if="data.type ==='name_scope'"
:src="require('@/assets/images/name-scope.svg')"
class="image-type" />
<img v-else-if="data.type ==='Const'"
:src="require('@/assets/images/constant-node.svg')"
class="image-type" />
<img v-else-if="data.type ==='aggregation_scope'"
:src="require('@/assets/images/polymetric.svg')"
class="image-type" />
<img v-else
:src="require('@/assets/images/operator-node.svg')"
class="image-type" />
</span>
<span class="custom-tree-node">{{ node.label }}</span>
</span>
</el-tree>
</div>
</div>
<!-- Functional Area -->
<div id="small-container">
<div id="small-resize">
@@ -417,7 +482,6 @@ limitations under the License.
</template>

<script>
import Autocomplete from '@/components/autocomplete';
import CommonProperty from '@/common/common-property.js';
import RequestService from '@/services/request-service';
import {select, selectAll, zoom} from 'd3';
@@ -490,6 +554,23 @@ export default {
title: '',
},
language: '',
defaultProps: {
children: 'nodes',
label: 'label',
isLeaf: 'leaf',
},
treeFlag: true,
props: {
label: 'label',
children: 'children',
isLeaf: 'leaf',
},
node: null,
resolve: null,
treeWrapFlag: true,
searchNode: null,
searchResolve: null,
isIntoView: true,
};
},
computed: {},
@@ -553,6 +634,149 @@ export default {
window.onresize = null;
},
methods: {
/**
* Tree linkage with graph Expand of current node
* @param {Obejct} nodes Data of children of current node
* @param {Obejct} name The name of the current node
*/
nodeExpandLinkage(nodes, name) {
const curNodeData = nodes.map((val) => {
return {
label: val.name.split('/').pop(),
...val,
};
});
const node = this.$refs.tree.getNode(name);
curNodeData.forEach((val) => {
this.$refs.tree.append(val, name);
});
node.childNodes.forEach((val) => {
if (
val.data.type !== 'name_scope' &&
val.data.type !== 'aggregation_scope'
) {
val.isLeaf = true;
}
});
node.expanded = true;
node.loading = false;
this.$refs.tree.setCurrentKey(name);
this.$nextTick(() => {
setTimeout(() => {
const dom = document.querySelector(
'.el-tree-node.is-current.is-focusable',
);
if (dom) {
dom.scrollIntoView();
}
}, 800);
});
},
/**
* Collapse node
* @param {Object} _
* @param {Object} node node data
*/
nodeCollapse(_, node) {
node.loaded = false;
if (this.treeFlag) {
this.dealDoubleClick(node.data.name);
}
},
/**
* Draw the tree
* @param {Object} node tree root node
* @param {Function} resolve callback function ,return next node data
*/
loadNode(node, resolve) {
if (node.level === 0) {
node.childNodes = [];
if (!this.node && !this.resolve) {
this.node = node;
this.resolve = resolve;
}
} else if (node.level >= 1) {
this.isIntoView = false;
this.queryGraphData(node.data.name, resolve);
}
},
/**
* Draw the tree
* @param {Object} node tree root node
* @param {Function} resolve callback function ,return next node data
*/
loadSearchNode(node, resolve) {
if (node.level === 0) {
node.childNodes = [];
if (!this.searchNode && !this.searchResolve) {
this.searchNode = node;
this.searchResolve = resolve;
}
} else if (node.level >= 1) {
const params = {
name: node.data.name,
train_id: this.trainJobID,
tag: this.fileSearchBox.value,
};
if (node.childNodes && node.childNodes.length) {
node.expanded = true;
node.loaded = true;
node.loading = false;
return;
}
RequestService.queryGraphData(params).then((res) => {
if (res && res.data && res.data.nodes) {
const data = res.data.nodes.map((val) => {
return {
label: val.name.split('/').pop(),
leaf:
val.type === 'name_scope' || val.type === 'aggregation_scope'
? false
: true,
...val,
};
});
resolve(data);
}
});
}
},
/**
* Deal search data
* @param {Array} arr search tree data
*/
dealSearchResult(arr) {
arr.forEach((val) => {
if (val.nodes) {
this.dealSearchResult(val.nodes);
}
val.label = val.name.split('/').pop();
});
},
filterChange() {
if (this.searchBox.value === '') {
this.treeFlag = true;
this.$nextTick(() => {
setTimeout(() => {
const dom = document.querySelector(
'.el-tree-node.is-current.is-focusable',
);
if (dom) {
dom.scrollIntoView();
}
}, 800);
});
}
},
handleNodeClick(data) {
this.isIntoView = false;
this.selectedNode.name = data.name;
if (this.treeFlag) {
this.selectNode(true);
} else {
this.querySingleNode({value: data.name});
}
},
/**
* Add the location attribute to each node to facilitate the obtaining of node location parameters.
*/
@@ -643,9 +867,9 @@ export default {
/**
* To obtain graph data, initialize and expand the namespace or aggregate nodes.
* @param {String} name Name of the current node.
* @param {String} type Type of the current node.
* @param {Function} resolve Callback function.
*/
queryGraphData(name) {
queryGraphData(name, resolve) {
const namescopeChildLimit = 3500;
const independentLayout = this.allGraphData[name]
? this.allGraphData[name].independent_layout
@@ -703,6 +927,27 @@ export default {
this.initGraphRectData();
this.loading.show = false;
}
const data = response.data.nodes.map((val) => {
return {
label: val.name.split('/').pop(),
leaf:
val.type === 'name_scope' ||
val.type === 'aggregation_scope'
? false
: true,
...val,
};
});
if (name) {
if (resolve) {
resolve(JSON.parse(JSON.stringify(data)));
} else {
this.nodeExpandLinkage(response.data.nodes, name);
}
} else {
this.node.childNodes = [];
this.resolve(JSON.parse(JSON.stringify(data)));
}
}
}
},
@@ -831,6 +1076,20 @@ export default {
.select('polygon, rect, ellipse, path')
.classed('selected', true);
this.highlightProxyNodes(id.replace('_unfold', ''));
this.$refs.tree.setCurrentKey(id.replace('_unfold', ''));
if (this.isIntoView) {
this.$nextTick(() => {
setTimeout(() => {
const dom = document.querySelector(
'.el-tree-node.is-current.is-focusable',
);
if (dom) {
dom.scrollIntoView();
}
}, 800);
});
}
this.isIntoView = true;
this.setNodeData();
},
/**
@@ -1017,6 +1276,7 @@ export default {
d3.select('#graph svg').remove();
this.firstFloorNodes = [];
this.queryGraphData();
this.treeFlag = true;
},
/**
* refresh select list
@@ -1032,13 +1292,9 @@ export default {
* @param {String} content Input parameters
* @param {Object} callback Callback Function
*/
searchNodesNames(content, callback) {
if (!this.trainJobID) {
callback([]);
return;
}
searchNodesNames() {
const params = {
search: content,
search: this.searchBox.value,
train_id: this.trainJobID,
tag: this.fileSearchBox.value,
offset: 0,
@@ -1048,24 +1304,59 @@ export default {
.then(
(response) => {
if (response && response.data) {
const names = response.data.names || response.data;
callback(
names.map((name) => {
return {value: name};
}),
);
this.treeFlag = false;
this.searchNode.childNodes = [];
const data = response.data.nodes.map((val) => {
return {
label: val.name.split('/').pop(),
...val,
};
});
const currentData = JSON.parse(JSON.stringify(data));
currentData.forEach((val) => {
val.nodes = [];
});
this.searchResolve(currentData);
data.forEach((val, key) => {
if (val.nodes && val.nodes.length) {
val.nodes.forEach((value) => {
value.parentName = val.name;
});
this.dealSearchTreeData(val.nodes);
}
});
}
},
(e) => {
callback([]);
this.loading.show = false;
},
)
.catch((e) => {
callback([]);
this.$message.error(this.$t('public.dataError'));
});
},
/**
* Draw the tree
* @param {Object} children child node
*/
dealSearchTreeData(children) {
children.forEach((val) => {
const node = this.$refs.searchTree.getNode(val.parentName);
val.label = val.name.split('/').pop();
val.leaf =
val.type === 'name_scope' || val.type === 'aggregation_scope'
? false
: true;
this.$refs.searchTree.append(val, node);
node.expanded = true;
if (val.nodes && val.nodes.length) {
val.nodes.forEach((value) => {
value.parentName = val.name;
});
this.dealSearchTreeData(val.nodes);
}
});
},
/**
* Search for all data of a specific node and its namespace.
* @param {Object} option Selected node data object
@@ -1138,6 +1429,9 @@ export default {
if (data) {
this.dealAutoUnfoldNamescopesData(data);
}
if (!this.treeFlag && response.data.children) {
this.dealTreeData(response.data.children, option.value);
}
}
},
(e) => {
@@ -1150,6 +1444,61 @@ export default {
});
}
},
/**
* Draw the tree
* @param {Object} children child node
* @param {String} name The name of the node that needs to be highlighted
*/
dealTreeData(children, name) {
if (children.nodes) {
const data = children.nodes.map((val) => {
return {
label: val.name.split('/').pop(),
...val,
};
});
data.forEach((val) => {
const node = this.$refs.tree.getNode(children.scope_name);
if (node.childNodes) {
if (
node.childNodes
.map((value) => value.data.name)
.indexOf(val.name) === -1
) {
this.$refs.tree.append(val, node);
}
} else {
this.$refs.tree.append(val, node);
}
});
const node = this.$refs.tree.getNode(children.scope_name);
node.childNodes.forEach((val) => {
if (
val.data.type !== 'name_scope' &&
val.data.type !== 'aggregation_scope'
) {
val.isLeaf = true;
}
});
node.expanded = true;
node.loading = false;
} else {
this.$refs.tree.setCurrentKey(name);
this.$nextTick(() => {
setTimeout(() => {
const dom = document.querySelector(
'.el-tree-node.is-current.is-focusable',
);
if (dom) {
dom.scrollIntoView();
}
}, 800);
});
}
if (children.children) {
this.dealTreeData(children.children, name);
}
},
/**
* Processes all data of the queried node and the namespace to which the node belongs.
* @param {Object} data All data of the node and the namespace to which the node belongs
@@ -1351,9 +1700,7 @@ export default {
},
},
// Components imported by the page
components: {
Autocomplete,
},
components: {},
};
</script>
<style lang="scss">
@@ -1458,10 +1805,38 @@ export default {
.search {
margin-bottom: 15px;
width: 100%;
.el-autocomplete-suggestion {
}
.search-wrap {
position: relative;
.tree-wrap {
position: absolute;
left: 0;
top: 32px;
z-index: 101;
width: 100%;
z-index: 200;
max-height: 224px;
overflow: auto;
border: 1px solid #dcdfe6;
border-top: none;
.image-type {
width: 20px;
height: 10px;
margin-right: 10px;
}
.el-tree {
overflow-x: auto;
overflow-y: hidden;
& > .el-tree-node {
min-width: 100%;
display: inline-block;
}
.custom-tree-node {
padding-right: 8px;
}
}
}
.collapse_i {
cursor: pointer;
}
}
.cl-graph {


Loading…
Cancel
Save