未验证 提交 c6928456 编写于 作者: A abigale Li 提交者: GitHub

resolve the histogram hover circle problem and adjust code (#141)

* modify overlay and offset chart view interplay problem

* resolve frontend fecs problem

* resolve the hover circle problem for histogram

* modify the color of multiple lines in scalar

* adjust the frontend code

* modify san template

* adjust histogramHelper code

* reslove fecs code style problem
上级 7b3e837b
{
"name": "front",
"name": "VisualDL",
"version": "1.0.0",
"description": "Visualization toolkit for deep learning",
"scripts": {
......
......@@ -37,8 +37,8 @@ export default {
location.hash = '#/scalars';
}
},
menuChange({value, url, title}) {
routeTo(url);
menuChange(dataItem) {
routeTo(dataItem.url);
}
};
......
......@@ -3,7 +3,7 @@
<san-appbar title="VisualDL">
<san-menu slot="right">
<san-menu-item
san-for="item in items"
s-for="item in items"
class="{{selected === item.name ? 'sm-menu-item-selected' : ''}}"
on-click="handleItemClick(item)"
title="{{item.title}}" />
......
......@@ -3,7 +3,7 @@
<label class="label">{{label}}</label>
<div class="group-box">
<san-checkbox
san-if="showAll"
s-if="showAll"
class="checkbox-all"
label="全选"
value="all"
......@@ -12,7 +12,7 @@
></san-checkbox>
<div class="san-form-check-group">
<san-checkbox
san-for="item in items"
s-for="item in items"
label="{{item.name}}"
value="{{item.value}}"
disabled="{{item.disabled}}"
......
......@@ -11,7 +11,7 @@
</span>
</h3>
<div
san-if="{{isShow}}"
s-if="{{isShow}}"
class="visaul-dl-expand-panel-content"
>
<slot></slot>
......
......@@ -6,16 +6,16 @@
```san Notification
<template>
<div>
<san-button
<s-button
variants="raised info"
on-click="handleClick01">
auto close
</san-button>
<san-button
</s-button>
<s-button
variants="raised info"
on-click="handleClick02">
no auto close
</san-button>
</s-button>
</div>
</template>
......@@ -53,31 +53,31 @@ export default {
```san Notification
<template>
<div>
<san-button
<s-button
variants="raised info"
on-click="handleClick01">
success
</san-button>
<san-button
</s-button>
<s-button
variants="raised info"
on-click="handleClick02">
warning
</san-button>
<san-button
</s-button>
<s-button
variants="raised info"
on-click="handleClick03">
info
</san-button>
<san-button
</s-button>
<s-button
variants="raised info"
on-click="handleClick04">
error
</san-button>
<san-button
</s-button>
<s-button
variants="raised info"
on-click="handleClick05">
simplify
</san-button>
</s-button>
</div>
</template>
......@@ -130,11 +130,11 @@ export default {
```san Notification
<template>
<div>
<san-button
<s-button
variants="raised info"
on-click="handleClick01">
width offset
</san-button>
</s-button>
</div>
</template>
......
......@@ -16,15 +16,15 @@ export default class NotificationItem extends Component {
on-mouseenter="clearTimer"
on-mouseleave="startTimer"
on-click="handleClick">
<san-icon
san-if="type"
<s-icon
s-if="type"
class="sm-notification-type type-{{type}}"
size="50">{{iconType}}</san-icon>
size="50">{{iconType}}</s-icon>
<div class="sm-notification-group" >
<p class="sm-notification-title">{{title}}</p>
<div class="sm-notification-content">{{message}}</div>
<div on-click="close($event)" class="sm-notification-close">
<san-icon size="20" class="sm-notification-close-btn">close</san-icon>
<s-icon size="20" class="sm-notification-close-btn">close</s-icon>
</div>
</div>
</div>
......
......@@ -4,7 +4,7 @@
<div class="group-box">
<san-radio
on-change="handleChange($event)"
san-for="item in items"
s-for="item in items"
label="{{item.name}}"
value="{{item.value}}"
disabled="{{item.disabled}}"
......
......@@ -10,16 +10,6 @@
step="{{step}}"
/>
<span>{{value}}</span>
<!--
<san-input-number
min="{{min}}"
max="{{max}}"
step="{{step}}"
value="{=value=}"
on-change="handlerChange($event)"
size="small">
</san-input-number>
-->
</div>
</div>
</template>
......
......@@ -21,7 +21,6 @@
</template>
<script>
import {getPluginGraphsGraph} from '../service';
import autoAdjustHeight from '../common/util/autoAdjustHeight';
import config from './ui/config';
import chart from './ui/chart';
......
<template>
<div class="visual-dl-graph-charts">
<!--
<div class="visual-dl-chart-box">
</div>
-->
<div san-if="graphUrl" class="visual-dl-img-box">
<div s-if="graphUrl" class="visual-dl-img-box">
<div class="small-img-box">
<img class="small-img" width="30" src="{{graphUrl}}" />
<div class="screen-handler"></div>
......@@ -48,9 +44,6 @@ export default {
},
inited() {
this.watch('filtScreen', filtScreen => {
// this.myChart.clear();
// let data = this.data.get('originData');
// this.initChartChartOption(data);
this.clearDragedTransform(this.getBigImgEl());
this.clearDragedTransform(this.getSmallImgDragHandler());
});
......@@ -67,11 +60,6 @@ export default {
this.getOriginChartsData();
},
// initCharts(tagInfo) {
// this.createChart();
// this.getOriginChartsData();
// },
createChart() {
let el = this.el.getElementsByClassName('visual-dl-chart-box')[0];
this.myChart = echarts.init(el);
......@@ -113,8 +101,6 @@ export default {
addDragEventForImg() {
let that = this;
// this.initCharts();
// target elements with the "draggable" class
interact('.draggable').draggable({
// enable inertial throwing
......
......@@ -14,13 +14,6 @@
<ui-icon style="margin-right: 6px">file_download</ui-icon>
Download image
</ui-button>
<!--
<ui-dropdown-menu
label="Session runs"
items="{{sessionItems}}"
value="{=config.session=}"
/>
-->
<ui-slider
label="Scale"
value="{=config.scale=}"
......
......@@ -9,7 +9,7 @@
title="Tags matching {{config.groupNameReg}}"
></ui-chart-page>
<ui-chart-page
san-for="item in groupedTags"
s-for="item in groupedTags"
config="{{config}}"
runsItems="{{runsItems}}"
tagList="{{item.tags}}"
......@@ -94,16 +94,6 @@ export default {
};
});
}
// ,
// filteredConfig() {
// let config = this.data.get('config') || {};
// let filteredConfig = {};
// Object.keys(config).forEach(key => {
// let val = config[key];
// filteredConfig[key] = val;
// });
// return filteredConfig;
// }
},
initData() {
return {
......@@ -131,7 +121,7 @@ export default {
this.data.set('config.runs', data);
});
// need debounce, can't use computed
// Need debounce, can't use computed
this.watch('config.groupNameReg', debounce(this.filterTagsList, 300));
},
......
import {min, max, range} from 'lodash';
export const tansformBackendData = histogramData => {
export function tansformBackendData(histogramData) {
let [time, step, items] = histogramData;
return {
time,
......@@ -9,9 +9,9 @@ export const tansformBackendData = histogramData => {
max: max(items.map(([left, right, count]) => right)),
items: items.map(([left, right, count]) => ({left, right, count}))
};
};
}
export const computeNewHistogram = (histogram, min, max, binsNum = 30) => {
export function computeNewHistogram(histogram, min, max, binsNum = 30) {
if (max === min) {
// Create bins even if all the data has a single value.
max = min * 1.1 + 1;
......@@ -38,16 +38,19 @@ export const computeNewHistogram = (histogram, min, max, binsNum = 30) => {
}
return {x: binLeft, dx: stepWidth, y: yValue};
});
};
}
export const tansformToVisData
= (tempData, time, step) => tempData.map(({x, dx, y}) => [time, step, x + dx / 2, Math.floor(y)]);
export function tansformToVisData(tempData, time, step) {
return tempData.map(function (dataItem) {
return [time, step, dataItem.x + dataItem.dx / 2, Math.floor(dataItem.y)];
});
}
export const originDataToChartData = originData => {
let tempDatas = originData.map(tansformBackendData);
let globalMin = min(tempDatas.map(({min}) => min));
let globalMax = max(tempDatas.map(({max}) => max));
let chartData = tempDatas.map(item => {
export function originDataToChartData(originData) {
let tempData = originData.map(tansformBackendData);
let globalMin = min(tempData.map(({min}) => min));
let globalMax = max(tempData.map(({max}) => max));
let chartData = tempData.map(function (item) {
let histoBins = computeNewHistogram(item, globalMin, globalMax);
let {time, step} = item;
return {
......@@ -61,4 +64,4 @@ export const originDataToChartData = originData => {
max: globalMax,
chartData
};
};
}
......@@ -4,7 +4,7 @@
</div>
<div class="visual-dl-chart-actions">
<san-button on-click="expandArea">
<san-icon size="20">settings_overscan</san-icon>
<san-icon size="20">settings_overscan</s-icon>
</san-button>
</div>
</div>
......@@ -17,7 +17,6 @@ import Icon from 'san-mui/Icon';
// libs
import echarts from 'echarts';
import {maxBy} from 'lodash';
import {originDataToChartData} from '../histogramHelper';
import {format, precisionRound} from 'd3-format';
......@@ -60,8 +59,6 @@ export default {
attached() {
let tagInfo = this.data.get('tagInfo');
this.initChart(tagInfo);
// this.initChartEvent();
if (this.data.get('running')) {
this.startInterval();
}
......@@ -86,6 +83,11 @@ export default {
initChartOption() {
this.myChart.clear();
let zr = this.myChart.getZr();
let hoverDots = zrDrawElement.hoverDots;
if (hoverDots != null && hoverDots.length !== 0) {
hoverDots.forEach(dot => zr.remove(dot));
}
let chartType = this.data.get('chartType');
let data = this.data.get('originData');
let visData = originDataToChartData(data);
......@@ -126,7 +128,6 @@ export default {
animationDuration: 100,
lineStyle: {
normal: {
// opacity: originLinesOpacity,
width: 1,
color: '#008c99'
}
......@@ -204,8 +205,6 @@ export default {
rawData.push(lineData);
});
// Max point in every polygon.
// let maxValuePoints = [];
let option = {
title,
color: ['#006069'],
......@@ -263,17 +262,7 @@ export default {
};
},
data: rawData
}
// {
// type: 'custom',
// dimension: ['x', 'y'],
// renderItem: function (params, api) {
// },
// data: rawData
// }
]
}]
};
function makePolyPoints(dataIndex, getValue, getCoord, yValueMapHeight) {
......@@ -349,7 +338,7 @@ export default {
let x = dataItem[binIndex * 3];
let y = dataItem[binIndex * 3 + 1];
let z = dataItem[binIndex * 3 + 2];
let pt = getPoint(x, y, z, getCoord);
let pt = getPoint(x, y, z, getCoord, gridRect.y - 10);
itemX = pt[0];
let dot = new echarts.graphic.Circle({
shape: {
......@@ -456,9 +445,7 @@ export default {
}
}
}
ecChart.setOption(option, {notMerge: true});
},
// get origin data per 60 seconds
......@@ -485,33 +472,6 @@ export default {
});
},
// lightHoveredLine({seriesIndex}) {
// let series = this.myChart.getOption().series;
// let newSeries = series.map((item, index) => {
// if (seriesIndex === index) {
// item.lineStyle.normal.color = highlightLineColor;
// item.zlevel = 1;
// }
// else {
// item.lineStyle.normal.color = defaultLineColor;
// item.zlevel = 0;
// }
// return item;
// });
// this.myChart.setOption({
// series: newSeries
// });
// },
// initChartEvent() {
// this.myChart.on('mousemove', params => {
// let chartType = this.data.get('chartType');
// if (chartType === 'overlay') {
// this.lightHoveredLine(params);
// }
// });
// },
expandArea() {
let isExpand = this.data.get('isExpand');
let pageBoxWidth = document.getElementsByClassName('visual-dl-chart-page')[0].offsetWidth;
......
<template>
<!-- className visual-dl-chart-page used in chart.san, change they all if you need!-->
<!-- ClassName visual-dl-chart-page used in chart.san, change they all if you need!-->
<div class="visual-dl-chart-page">
<ui-expand-panel isShow="{{expand}}" info="{{total}}" title="{{title}}">
<ui-chart
san-for="tag in filteredPageList"
s-for="tag in filteredPageList"
tagInfo="{{tag}}"
runs="{{config.runs}}"
chartType="{{config.chartType}}"
......@@ -11,7 +11,7 @@
runsItems="{{runsItems}}"
></ui-chart>
<ui-pagination
san-if="total > pageSize"
s-if="total > pageSize"
on-pageChange="handlePageChange($event)"
current="{{currentPage}}"
pageSize="{{pageSize}}"
......
......@@ -10,13 +10,6 @@
value="{=config.chartType=}"
items="{{charTypeItems}}"
/>
<!--
<ui-radio-group
label="Horizontal"
value="{=config.horizontal=}"
items="{{horizontalItems}}"
/>
-->
<ui-checkbox-group
value="{=config.runs=}"
label="Runs"
......
<template>
<article>
<h1>
{{text}}
</h1>
</article>
</template>
<script>
export default {
initData() {
......@@ -18,5 +14,4 @@
};
}
};
</script>
import {router} from 'san-router';
import HomePage from './Home';
router.add({
......
......@@ -9,7 +9,7 @@
title="Tags matching {{config.groupNameReg}}"
></ui-chart-page>
<ui-chart-page
san-for="item in groupedTags"
s-for="item in groupedTags"
config="{{filteredConfig}}"
runsItems="{{runsItems}}"
tagList="{{item.tags}}"
......
......@@ -3,7 +3,7 @@
<ui-expand-panel isShow="{{expand}}" info="{{total}}" title="{{title}}">
<ui-image
class="visual-dl-chart-image"
san-for="tag in filteredPageList"
s-for="tag in filteredPageList"
tagInfo="{{tag}}"
isActualImageSize="{{config.isActualImageSize}}"
runs="{{config.runs}}"
......@@ -12,7 +12,7 @@
></ui-image>
<ui-pagination
class="visual-dl-sm-pagination"
san-if="total > pageSize"
s-if="total > pageSize"
on-pageChange="handlePageChange($event)"
current="{{currentPage}}"
pageSize="{{pageSize}}"
......
......@@ -8,7 +8,7 @@
<span>{{imgData.step}};</span>
<span>{{imgData.wall_time | formatTime}}</span>
</p>
<san-slider
<s-slider
on-change="handleSlideChange($event)"
value="{{currentIndex}}"
min="{{slider.min}}"
......@@ -109,7 +109,7 @@ export default {
clearInterval(this.getOringDataInterval);
},
// get origin data per {{intervalTime}} seconds
// get origin data per {{intervalTime}} seconds
startInterval() {
this.getOringDataInterval = setInterval(() => {
this.getOriginChartsData();
......
......@@ -9,7 +9,7 @@
title="Tags matching {{config.groupNameReg}}"
></ui-chart-page>
<ui-chart-page
san-for="item in groupedTags"
s-for="item in groupedTags"
config="{{filteredConfig}}"
runsItems="{{runsItems}}"
tagList="{{item.tags}}"
......@@ -139,7 +139,7 @@ export default {
this.data.set('config.runs', data);
});
// need debounce can't use computed
// need debounce, can't use computed
this.watch('config.groupNameReg', debounce(this.filterTagsList, 300));
},
attached() {
......
......@@ -7,14 +7,14 @@
<san-icon size="20">settings_overscan</san-icon>
</san-button>
<ui-dropdown-menu
san-if="downloadLink"
s-if="downloadLink"
stlye="width:100px;"
hintText="download type"
items="{{runsItems}}"
value="{=downloadType=}"
/>
<san-button
san-if="downloadLink"
s-if="downloadLink"
on-click="handleDownLoad">
<san-icon size="20">file_download</san-icon>
</san-button>
......@@ -122,11 +122,11 @@ export default {
},
initDownloadType() {
let runsItems = this.data.get('runsItems') || [];
let runsItems = this.data.get('runsItems');
if (runsItems.length === 0) {
return;
}
this.data.set('downloadType', runsItems.find((item, index) => index === 0).value);
this.data.set('downloadType', runsItems[0].value);
},
initChart(tagInfo) {
......@@ -178,16 +178,22 @@ export default {
let that = this;
let option = {
color: [
'#c23531',
'#61a0a8',
'#d48265',
'#91c7ae',
'#749f83',
'#ca8622',
'#bda29a',
'#6e7074',
'#546570',
'#c4ccd3'
'#C3D769',
'#A2D168',
'#F6E753',
'#DFDE53',
'#89C864',
'#6FC16E',
'#5FAE7C',
'#54957D',
'#458C8D',
'#4B7C8A',
'#3E7586',
'#42638E',
'#405288',
'#464887',
'#3D3168',
'#391E57'
],
title: {
text: tag,
......@@ -234,7 +240,7 @@ export default {
yAxis: {
type: 'value',
axisLabel: {
formatter(value, index) {
formatter(value) {
return value.toString().slice(0, 5);
}
}
......@@ -244,7 +250,7 @@ export default {
this.myChart.setOption(option);
},
// get origin data per 60 seconds
// Get origin data per 60 seconds
startInterval() {
this.getOringDataInterval = setInterval(() => {
let tagInfo = this.data.get('tagInfo');
......@@ -280,18 +286,19 @@ export default {
{
data: lineData,
encode: {
// map 1 to xAixs
// map 1 dimension to xAixs.
x: [1],
// map 2 to yAixs
// map 2 dimension to yAixs.
y: [2]
}
},
{
data: lineData,
encode: {
// map 1 to xAixs
// Map 1 dimension to xAixs.
x: [1],
// map 3 to yAixs, the third number is smoothed value
// Map 3 dimension to yAixs,
// the third number is smoothed value.
y: [3]
}
}
......@@ -323,7 +330,7 @@ export default {
/**
* @desc 1、add smooth data depend on smoothingWeight. see https://en.wikipedia.org/wiki/Moving_average for detail
* 2、add relative data
* 2、add relative data
* @param {Object} echarts series Object
* @param {number} smoothingWeight smooth weight, between 0 ~ 1
*/
......@@ -334,12 +341,12 @@ export default {
let startValue;
data.forEach((d, i) => {
let nextVal = d[2];
// second to millisecond
// second to millisecond.
let millisecond = Math.floor(d[0] * 1000);
if (i === 0) {
startValue = millisecond;
}
// relative time, millisecond to hours
// Relative time, millisecond to hours.
d[4] = Math.floor(millisecond - startValue) / (60 * 60 * 1000);
if (!isFinite(nextVal)) {
d[3] = nextVal;
......@@ -355,40 +362,39 @@ export default {
});
},
// chart outlier options methods and functions ---- start
// compute Y domain from originData
// Chart outlier options methods and functions ---- start.
// Compute Y domain from originData.
setChartsOutlier(seriesData) {
let outlier = this.data.get('outlier');
let originData = this.data.get('originData');
let domainRangeArray = originData.map(seriesData => this.computeDataRange(seriesData, outlier));
// compare,get the best Y domain。
// Compare, get the best Y domain.
let flattenNumbers = flatten(domainRangeArray);
let finalMax = max(flattenNumbers);
let finalMin = min(flattenNumbers);
// add padding
// Add padding.
let PaddedYDomain = this.paddedYDomain(finalMin, finalMax);
this.setChartOutlierOptions(PaddedYDomain);
// store Y domain,if originData is not change,Y domain keep same.
// Store Y domain, if originData is not change, Y domain keep same.
},
// compute max and min from array, if outlier is true, return quantile range
// Compute max and min from array, if outlier is true, return quantile range.
computeDataRange(arr, isQuantile) {
// get data range
// Get data range.
let max;
let min;
if (!isQuantile) {
// get the orgin data range
// Get the orgin data range.
max = maxBy(arr, item => item[2])[2];
min = minBy(arr, item => item[2])[2];
}
else {
// get the quantile range
// Get the quantile range.
let sorted = sortBy(arr, [item => item[2]]);
min = quantile(sorted, minQuantile, item => item[2]);
max = quantile(arr, maxQuantile, item => item[2]);
......@@ -412,7 +418,7 @@ export default {
});
},
// chart horizontal options methods and functions ---- start
// Chart horizontal options methods and functions ---- start.
setChartHorizon() {
let horizontal = this.data.get('horizontal');
let seriesOption = this.myChart.getOption().series;
......@@ -523,7 +529,7 @@ export default {
sortedPoints = sortBy(points, one => one.item[3]);
break;
case 'nearest':
// compare other ponts width the trigger point, caculate the nearest sort.
// Compare other ponts width the trigger point, caculate the nearest sort.
sortedPoints = sortBy(points, one => one.item[3] - triggerValue);
break;
default:
......@@ -552,13 +558,13 @@ export default {
let data = item.item;
return {
Run: item.run,
// keep six number for easy-read
// Keep six number for easy-read.
Smoothed: data[indexPropMap.Smoothed].toString().slice(0, 6),
Value: data[indexPropMap.Value].toString().slice(0, 6),
Step: data[indexPropMap.Step],
Time: moment(Math.floor(data[indexPropMap.Time] * 1000), 'X').format('YYYY-MM-DD HH:mm:ss'),
// relative display value should take easy-read into consideration.
// better to tranform data to 'day:hour', 'hour:minutes', 'minute: seconds' and second only.
// Relative display value should take easy-read into consideration.
// Better to tranform data to 'day:hour', 'hour:minutes', 'minute: seconds' and second only.
Relative: Math.floor(data[indexPropMap.Relative] * 60 * 60) + 's'
};
});
......@@ -580,20 +586,6 @@ export default {
return '<table style="text-align: left;table-layout: fixed;width: 480px;"><thead>' + headerHtml + '</thead>'
+ '<tbody>' + content + '</tbody><table>';
},
setChartsRuns() {
// let tagInfo = this.data.get('tagInfo');
// let runs = this.data.get('config.runs');
// let seriesOption = [
// {
// lineStyle: {
// normal: {
// opacity: originLinesOpacity
// }
// }
// }
// ];
}
};
</script>
......
......@@ -3,7 +3,7 @@
<ui-expand-panel isShow="{{expand}}" info="{{tagList.length}}" title="{{title}}">
<div class="visual-dl-chart-page-box">
<ui-chart
san-for="tag in filteredTagList"
s-for="tag in filteredTagList"
tagInfo="{{tag}}"
groupNameReg="{{config.groupNameReg}}"
smoothing="{{config.smoothing}}"
......@@ -17,7 +17,7 @@
></ui-chart>
</div>
<ui-pagination
san-if="total > pageSize"
s-if="total > pageSize"
on-pageChange="handlePageChange($event)"
current="{{currentPage}}"
pageSize="{{pageSize}}"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册