Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
VisualDL
提交
7bdb74b1
V
VisualDL
项目概览
PaddlePaddle
/
VisualDL
接近 2 年 前同步成功
通知
89
Star
4655
Fork
642
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
5
Wiki
分析
仓库
DevOps
项目成员
Pages
V
VisualDL
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
5
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
7bdb74b1
编写于
6月 19, 2020
作者:
P
Peter Pan
提交者:
GitHub
6月 19, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Histogram (#670)
* doc: update readme * feat: histogram
上级
69c90307
变更
52
隐藏空白更改
内联
并排
Showing
52 changed file
with
1852 addition
and
710 deletion
+1852
-710
README.md
README.md
+5
-3
frontend/README.md
frontend/README.md
+1
-0
frontend/README_cn.md
frontend/README_cn.md
+2
-0
frontend/packages/core/components/HighDimensionalPage/HighDimensionalChart.tsx
...e/components/HighDimensionalPage/HighDimensionalChart.tsx
+3
-6
frontend/packages/core/components/HistogramPage/HistogramChart.tsx
...packages/core/components/HistogramPage/HistogramChart.tsx
+170
-0
frontend/packages/core/components/LineChart.tsx
frontend/packages/core/components/LineChart.tsx
+51
-69
frontend/packages/core/components/ScalarsPage/ScalarChart.tsx
...tend/packages/core/components/ScalarsPage/ScalarChart.tsx
+30
-22
frontend/packages/core/components/StackChart.tsx
frontend/packages/core/components/StackChart.tsx
+186
-0
frontend/packages/core/hooks/useECharts.ts
frontend/packages/core/hooks/useECharts.ts
+14
-1
frontend/packages/core/hooks/useNavItems.ts
frontend/packages/core/hooks/useNavItems.ts
+2
-1
frontend/packages/core/package.json
frontend/packages/core/package.json
+2
-1
frontend/packages/core/pages/histogram.tsx
frontend/packages/core/pages/histogram.tsx
+87
-0
frontend/packages/core/pages/scalars.tsx
frontend/packages/core/pages/scalars.tsx
+4
-9
frontend/packages/core/public/locales/en/common.json
frontend/packages/core/public/locales/en/common.json
+5
-4
frontend/packages/core/public/locales/en/errors.json
frontend/packages/core/public/locales/en/errors.json
+7
-7
frontend/packages/core/public/locales/en/graphs.json
frontend/packages/core/public/locales/en/graphs.json
+34
-34
frontend/packages/core/public/locales/en/histogram.json
frontend/packages/core/public/locales/en/histogram.json
+10
-0
frontend/packages/core/public/locales/zh/common.json
frontend/packages/core/public/locales/zh/common.json
+5
-4
frontend/packages/core/public/locales/zh/errors.json
frontend/packages/core/public/locales/zh/errors.json
+7
-7
frontend/packages/core/public/locales/zh/graphs.json
frontend/packages/core/public/locales/zh/graphs.json
+34
-34
frontend/packages/core/public/locales/zh/high-dimensional.json
...end/packages/core/public/locales/zh/high-dimensional.json
+3
-3
frontend/packages/core/public/locales/zh/histogram.json
frontend/packages/core/public/locales/zh/histogram.json
+10
-0
frontend/packages/core/public/locales/zh/samples.json
frontend/packages/core/public/locales/zh/samples.json
+5
-5
frontend/packages/core/public/locales/zh/scalars.json
frontend/packages/core/public/locales/zh/scalars.json
+15
-15
frontend/packages/core/resource/high-dimensional/index.ts
frontend/packages/core/resource/high-dimensional/index.ts
+12
-3
frontend/packages/core/resource/high-dimensional/types.ts
frontend/packages/core/resource/high-dimensional/types.ts
+0
-7
frontend/packages/core/resource/histogram/chart.ts
frontend/packages/core/resource/histogram/chart.ts
+59
-0
frontend/packages/core/resource/histogram/data.ts
frontend/packages/core/resource/histogram/data.ts
+94
-0
frontend/packages/core/resource/histogram/index.ts
frontend/packages/core/resource/histogram/index.ts
+7
-0
frontend/packages/core/resource/histogram/types.ts
frontend/packages/core/resource/histogram/types.ts
+32
-0
frontend/packages/core/resource/scalars/chart.ts
frontend/packages/core/resource/scalars/chart.ts
+150
-0
frontend/packages/core/resource/scalars/data.ts
frontend/packages/core/resource/scalars/data.ts
+108
-0
frontend/packages/core/resource/scalars/index.ts
frontend/packages/core/resource/scalars/index.ts
+8
-247
frontend/packages/core/resource/scalars/types.ts
frontend/packages/core/resource/scalars/types.ts
+5
-18
frontend/packages/core/tsconfig.json
frontend/packages/core/tsconfig.json
+2
-1
frontend/packages/core/types/index.d.ts
frontend/packages/core/types/index.d.ts
+5
-0
frontend/packages/core/utils/chart.ts
frontend/packages/core/utils/chart.ts
+10
-6
frontend/packages/core/utils/index.ts
frontend/packages/core/utils/index.ts
+0
-1
frontend/packages/core/utils/worker.ts
frontend/packages/core/utils/worker.ts
+4
-0
frontend/packages/core/worker/high-dimensional/divide.worker.ts
...nd/packages/core/worker/high-dimensional/divide.worker.ts
+3
-5
frontend/packages/core/worker/histogram/transform.worker.ts
frontend/packages/core/worker/histogram/transform.worker.ts
+4
-0
frontend/packages/core/worker/scalars/range.worker.ts
frontend/packages/core/worker/scalars/range.worker.ts
+3
-5
frontend/packages/core/worker/scalars/smooth.worker.ts
frontend/packages/core/worker/scalars/smooth.worker.ts
+3
-5
frontend/packages/mock/data/components.ts
frontend/packages/mock/data/components.ts
+1
-1
frontend/packages/mock/data/histogram/list.ts
frontend/packages/mock/data/histogram/list.ts
+235
-0
frontend/packages/mock/data/histogram/tags.ts
frontend/packages/mock/data/histogram/tags.ts
+4
-0
frontend/packages/wasm/src/high_dimensional.rs
frontend/packages/wasm/src/high_dimensional.rs
+53
-0
frontend/packages/wasm/src/histogram.rs
frontend/packages/wasm/src/histogram.rs
+197
-0
frontend/packages/wasm/src/main.rs
frontend/packages/wasm/src/main.rs
+25
-176
frontend/packages/wasm/src/scalar.rs
frontend/packages/wasm/src/scalar.rs
+126
-0
frontend/yarn.lock
frontend/yarn.lock
+6
-6
visualdl/server/api.py
visualdl/server/api.py
+4
-4
未找到文件。
README.md
浏览文件 @
7bdb74b1
...
...
@@ -11,7 +11,7 @@
</p>
<p
align=
"center"
>
<a
href=
"
javascript:void(0)
"
><img
src=
"https://img.shields.io/badge/QQ_Group-1045783368-52B6EF?style=social&logo=tencent-qq&logoColor=000&logoWidth=20"
alt=
"QQ Group"
/></a>
<a
href=
"
https://jq.qq.com/?_wv=1027&k=TyzyVT4C"
target=
"_blank"
rel=
"noreferrer
"
><img
src=
"https://img.shields.io/badge/QQ_Group-1045783368-52B6EF?style=social&logo=tencent-qq&logoColor=000&logoWidth=20"
alt=
"QQ Group"
/></a>
</p>
## 介绍
...
...
@@ -245,7 +245,9 @@ app.run(logdir="./log")
## 开源贡献
VisualDL 是由
[
PaddlePaddle
](
https://www.paddlepaddle.org/
)
和
[
ECharts
](
https://echarts.apache.org/
)
合作推出的开源项目。欢迎所有人使用,提意见以及贡献代码。
VisualDL 是由
[
PaddlePaddle
](
https://www.paddlepaddle.org/
)
和
[
ECharts
](
https://echarts.apache.org/
)
合作推出的开源项目。
Graph 相关功能由
[
Netron
](
https://github.com/lutzroeder/netron
)
提供技术支持。
欢迎所有人使用,提意见以及贡献代码。
## 更多细节
...
...
@@ -254,7 +256,7 @@ VisualDL 是由 [PaddlePaddle](https://www.paddlepaddle.org/) 和 [ECharts](http
## 技术交流
欢迎您加入VisualDL官方
qq
群:1045783368 与飞桨团队以及其他用户共同针对VisualDL进行讨论与交流。
欢迎您加入VisualDL官方
QQ
群:1045783368 与飞桨团队以及其他用户共同针对VisualDL进行讨论与交流。
<p
align=
"center"
>
<img
src=
"https://user-images.githubusercontent.com/48054808/82522691-c2758680-9b5c-11ea-9aee-fca994aba175.png"
width=
"20%"
/>
...
...
frontend/README.md
浏览文件 @
7bdb74b1
...
...
@@ -113,6 +113,7 @@ This project is based on following projects:
-
[
React
](
https://reactjs.org/
)
-
[
ECharts
](
https://echarts.apache.org/
)
-
[
wasm-pack
](
https://rustwasm.github.io/wasm-pack/
)
-
[
Netron
](
https://github.com/lutzroeder/netron
)
## Author
<table><tr><td
align=
"center"
><a
href=
"https://github.com/PeterPanZH"
><img
src=
"https://avatars0.githubusercontent.com/u/3366499?s=460&v=4"
width=
"120px;"
alt=
"PeterPanZH"
/><br
/><sub><b>
PeterPanZH
</b></sub></a></td><td
align=
"center"
><a
href=
"https://github.com/Niandalu"
><img
src=
"https://avatars1.githubusercontent.com/u/6406875?s=460&v=4"
width=
"120px;"
alt=
"Niandalu"
/><br
/><sub><b>
Niandalu
</b></sub></a></td></tr></table>
...
...
frontend/README_cn.md
浏览文件 @
7bdb74b1
...
...
@@ -112,6 +112,8 @@ VisualDL 支持最新版本的 [Google Chrome](https://www.google.com/chrome/)
-
[
Next.js
](
https://nextjs.org/
)
-
[
React
](
https://reactjs.org/
)
-
[
ECharts
](
https://echarts.apache.org/
)
-
[
wasm-pack
](
https://rustwasm.github.io/wasm-pack/
)
-
[
Netron
](
https://github.com/lutzroeder/netron
)
## 作者
<table><tr><td
align=
"center"
><a
href=
"https://github.com/PeterPanZH"
><img
src=
"https://avatars0.githubusercontent.com/u/3366499?s=460&v=4"
width=
"120px;"
alt=
"PeterPanZH"
/><br
/><sub><b>
PeterPanZH
</b></sub></a></td><td
align=
"center"
><a
href=
"https://github.com/Niandalu"
><img
src=
"https://avatars1.githubusercontent.com/u/6406875?s=460&v=4"
width=
"120px;"
alt=
"Niandalu"
/><br
/><sub><b>
Niandalu
</b></sub></a></td></tr></table>
...
...
frontend/packages/core/components/HighDimensionalPage/HighDimensionalChart.tsx
浏览文件 @
7bdb74b1
import
{
Dimension
,
DivideParams
,
Point
,
Reduction
,
divide
}
from
'
~/resource/high-dimensional
'
;
import
{
Dimension
,
Reduction
,
divide
}
from
'
~/resource/high-dimensional
'
;
import
React
,
{
FunctionComponent
,
useMemo
}
from
'
react
'
;
import
{
contentHeight
,
primaryColor
,
rem
}
from
'
~/utils/style
'
;
...
...
@@ -10,11 +10,8 @@ import {useRunningRequest} from '~/hooks/useRequest';
import
{
useTranslation
}
from
'
~/utils/i18n
'
;
const
divideWasm
=
()
=>
import
(
'
@visualdl/wasm
'
).
then
(({
divide
})
=>
(
params
:
DivideParams
)
=>
(
divide
(
params
.
points
,
params
.
labels
,
!!
params
.
visibility
,
params
.
keyword
??
''
)
as
unknown
)
as
[
Point
[],
Point
[]
]
import
(
'
@visualdl/wasm
'
).
then
(({
high_dimensional_divide
}):
typeof
divide
=>
params
=>
high_dimensional_divide
(
params
.
points
,
params
.
labels
,
!!
params
.
visibility
,
params
.
keyword
??
''
)
);
const
divideWorker
=
()
=>
new
Worker
(
'
~/worker/high-dimensional/divide.worker.ts
'
,
{
type
:
'
module
'
});
...
...
frontend/packages/core/components/HistogramPage/HistogramChart.tsx
0 → 100644
浏览文件 @
7bdb74b1
import
{
HistogramData
,
Modes
,
OffsetData
,
OverlayData
,
options
as
chartOptions
,
transform
}
from
'
~/resource/histogram
'
;
import
LineChart
,
{
LineChartRef
}
from
'
~/components/LineChart
'
;
import
React
,
{
FunctionComponent
,
useCallback
,
useMemo
,
useRef
,
useState
}
from
'
react
'
;
import
StackChart
,
{
StackChartRef
}
from
'
~/components/StackChart
'
;
import
{
rem
,
size
}
from
'
~/utils/style
'
;
import
ChartToolbox
from
'
~/components/ChartToolbox
'
;
import
{
EChartOption
}
from
'
echarts
'
;
import
{
Run
}
from
'
~/types
'
;
import
ee
from
'
~/utils/event
'
;
import
queryString
from
'
query-string
'
;
import
styled
from
'
styled-components
'
;
import
useHeavyWork
from
'
~/hooks/useHeavyWork
'
;
import
{
useRunningRequest
}
from
'
~/hooks/useRequest
'
;
import
{
useTranslation
}
from
'
~/utils/i18n
'
;
const
transformWasm
=
()
=>
import
(
'
@visualdl/wasm
'
).
then
(({
histogram_transform
}):
typeof
transform
=>
params
=>
histogram_transform
(
params
.
data
,
params
.
mode
)
);
const
transformWorker
=
()
=>
new
Worker
(
'
~/worker/histogram/transform.worker.ts
'
,
{
type
:
'
module
'
});
const
Wrapper
=
styled
.
div
`
${
size
(
'
100%
'
,
'
100%
'
)}
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: space-between;
`
;
const
StyledLineChart
=
styled
(
LineChart
)
`
flex-grow: 1;
`
;
const
StyledStackChart
=
styled
(
StackChart
)
`
flex-grow: 1;
`
;
const
Toolbox
=
styled
(
ChartToolbox
)
`
margin-left:
${
rem
(
20
)}
;
margin-right:
${
rem
(
20
)}
;
margin-bottom:
${
rem
(
18
)}
;
`
;
const
Error
=
styled
.
div
`
${
size
(
'
100%
'
,
'
100%
'
)}
display: flex;
justify-content: center;
align-items: center;
`
;
type
HistogramChartProps
=
{
cid
:
symbol
;
run
:
Run
;
tag
:
string
;
mode
:
Modes
;
running
?:
boolean
;
onToggleMaximized
?:
(
maximized
:
boolean
)
=>
void
;
};
const
HistogramChart
:
FunctionComponent
<
HistogramChartProps
>
=
({
cid
,
run
,
tag
,
mode
,
running
})
=>
{
const
{
t
}
=
useTranslation
([
'
histogram
'
,
'
common
'
]);
const
echart
=
useRef
<
LineChartRef
|
StackChartRef
>
(
null
);
const
{
data
:
dataset
,
error
,
loading
}
=
useRunningRequest
<
HistogramData
>
(
`/histogram/list?
${
queryString
.
stringify
({
run
:
run
.
label
,
tag
})}
`
,
!!
running
);
const
[
maximized
,
setMaximized
]
=
useState
<
boolean
>
(
false
);
const
toggleMaximized
=
useCallback
(()
=>
{
ee
.
emit
(
'
toggle-chart-size
'
,
cid
,
!
maximized
);
setMaximized
(
m
=>
!
m
);
},
[
cid
,
maximized
]);
const
title
=
useMemo
(()
=>
`
${
tag
}
(
${
run
.
label
}
)`
,
[
tag
,
run
.
label
]);
const
params
=
useMemo
(
()
=>
({
data
:
dataset
??
[],
mode
}),
[
dataset
,
mode
]
);
const
data
=
useHeavyWork
(
transformWasm
,
transformWorker
,
transform
,
params
);
const
chartData
=
useMemo
(()
=>
{
type
Optional
<
T
>
=
T
|
undefined
;
if
(
mode
===
Modes
.
Overlay
)
{
return
(
data
as
Optional
<
OverlayData
>
)?.
data
.
map
(
items
=>
({
name
:
`step
${
items
[
0
][
1
]}
`
,
data
:
items
,
encode
:
{
x
:
[
2
],
y
:
[
3
]
}
}));
}
if
(
mode
===
Modes
.
Offset
)
{
return
{
...((
data
as
Optional
<
OffsetData
>
)
??
{})
};
}
},
[
data
,
mode
]);
const
options
=
useMemo
(
()
=>
({
...
chartOptions
[
mode
],
color
:
[
run
.
colors
[
0
]]
}),
[
mode
,
run
]
);
const
chart
=
useMemo
(()
=>
{
if
(
mode
===
Modes
.
Overlay
)
{
return
(
<
StyledLineChart
ref
=
{
echart
as
React
.
RefObject
<
LineChartRef
>
}
title
=
{
title
}
data
=
{
chartData
as
EChartOption
<
EChartOption
.
SeriesLine
>
[
'
series
'
]
}
options
=
{
options
}
loading
=
{
loading
}
/>
);
}
if
(
mode
===
Modes
.
Offset
)
{
return
(
<
StyledStackChart
ref
=
{
echart
as
React
.
RefObject
<
StackChartRef
>
}
title
=
{
title
}
data
=
{
chartData
as
EChartOption
<
EChartOption
.
SeriesCustom
>
[
'
series
'
]
&
OffsetData
}
options
=
{
options
}
loading
=
{
loading
}
/>
);
}
return
null
;
},
[
chartData
,
loading
,
mode
,
options
,
title
]);
// display error only on first fetch
if
(
!
data
&&
error
)
{
return
<
Error
>
{
t
(
'
common:error
'
)
}
</
Error
>;
}
return
(
<
Wrapper
>
{
chart
}
<
Toolbox
items
=
{
[
{
icon
:
'
maximize
'
,
activeIcon
:
'
minimize
'
,
tooltip
:
t
(
'
histogram:maximize
'
),
activeTooltip
:
t
(
'
histogram:minimize
'
),
toggle
:
true
,
onClick
:
toggleMaximized
},
{
icon
:
'
download
'
,
tooltip
:
t
(
'
histogram:download-image
'
),
onClick
:
()
=>
echart
.
current
?.
saveAsImage
()
}
]
}
/>
</
Wrapper
>
);
};
export
default
HistogramChart
;
frontend/packages/core/components/LineChart.tsx
浏览文件 @
7bdb74b1
import
*
as
chart
from
'
~/utils/chart
'
;
import
React
,
{
use
Callback
,
use
Effect
,
useImperativeHandle
}
from
'
react
'
;
import
React
,
{
useEffect
,
useImperativeHandle
}
from
'
react
'
;
import
{
WithStyled
,
position
,
primaryColor
,
size
}
from
'
~/utils/style
'
;
import
{
EChartOption
}
from
'
echarts
'
;
import
GridLoader
from
'
react-spinners/GridLoader
'
;
import
{
dataURL2Blob
}
from
'
~/utils/image
'
;
import
defaultsDeep
from
'
lodash/defaultsDeep
'
;
import
{
formatTime
}
from
'
~/utils
'
;
import
{
saveAs
}
from
'
file-saver
'
;
import
styled
from
'
styled-components
'
;
import
useECharts
from
'
~/hooks/useECharts
'
;
import
{
useTranslation
}
from
'
~/utils/i18n
'
;
...
...
@@ -28,23 +27,12 @@ const Wrapper = styled.div`
}
`
;
type
Range
=
{
min
:
EChartOption
.
BasicComponents
.
CartesianAxis
[
'
min
'
];
max
:
EChartOption
.
BasicComponents
.
CartesianAxis
[
'
max
'
];
};
type
LineChartProps
=
{
options
?:
EChartOption
;
title
?:
string
;
legend
?:
string
[];
data
?:
Partial
<
NonNullable
<
EChartOption
<
EChartOption
.
SeriesLine
>
[
'
series
'
]
>>
;
xAxis
?:
string
;
yAxis
?:
string
;
xType
?:
EChartOption
.
BasicComponents
.
CartesianAxis
.
Type
;
yType
?:
EChartOption
.
BasicComponents
.
CartesianAxis
.
Type
;
xRange
?:
Range
;
yRange
?:
Range
;
tooltip
?:
string
|
EChartOption
.
Tooltip
.
Formatter
;
loading
?:
boolean
;
zoom
?:
boolean
;
};
export
type
LineChartRef
=
{
...
...
@@ -53,12 +41,12 @@ export type LineChartRef = {
};
const
LineChart
=
React
.
forwardRef
<
LineChartRef
,
LineChartProps
&
WithStyled
>
(
({
title
,
legend
,
data
,
xAxis
,
yAxis
,
xType
,
yType
,
xRange
,
yRange
,
tooltip
,
loading
,
className
},
ref
)
=>
{
({
options
,
data
,
title
,
loading
,
zoom
,
className
},
ref
)
=>
{
const
{
i18n
}
=
useTranslation
();
const
{
ref
:
echartRef
,
echart
,
wrapper
}
=
useECharts
<
HTMLDivElement
>
({
const
{
ref
:
echartRef
,
echart
,
wrapper
,
saveAsImage
}
=
useECharts
<
HTMLDivElement
>
({
loading
:
!!
loading
,
zoom
:
true
,
zoom
,
autoFit
:
true
});
...
...
@@ -69,68 +57,62 @@ const LineChart = React.forwardRef<LineChartRef, LineChartProps & WithStyled>(
});
},
saveAsImage
:
()
=>
{
if
(
echart
)
{
const
blob
=
dataURL2Blob
(
echart
.
getDataURL
({
type
:
'
png
'
,
pixelRatio
:
2
,
backgroundColor
:
'
#FFF
'
}));
saveAs
(
blob
,
`
${
title
?.
replace
(
/
[/\\
?%*:|"<>
]
/g
,
'
_
'
)
||
'
scalar
'
}
.png`
);
}
saveAsImage
(
title
);
}
}));
const
xAxisFormatter
=
useCallback
(
(
value
:
number
)
=>
(
xType
===
'
time
'
?
formatTime
(
value
,
i18n
.
language
,
'
LTS
'
)
:
value
),
[
xType
,
i18n
.
language
]
);
useEffect
(()
=>
{
if
(
process
.
browser
)
{
echart
?.
setOption
(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const
{
color
,
colorAlt
,
...
defaults
}
=
chart
;
let
chartOptions
:
EChartOption
=
defaultsDeep
(
{
color
:
chart
.
color
,
title
:
{
...
chart
.
title
,
text
:
title
??
''
},
tooltip
:
{
...
chart
.
tooltip
,
...(
tooltip
?
{
formatter
:
tooltip
}
:
{})
}
,
toolbox
:
chart
.
toolbox
,
legend
:
{
...
chart
.
legend
,
data
:
legend
??
[]
}
,
grid
:
chart
.
grid
,
xAxis
:
{
...
chart
.
xAxis
,
name
:
xAxis
||
''
,
type
:
xType
||
'
value
'
,
axisLabel
:
{
...
chart
.
xAxis
.
axisLabel
,
formatter
:
xAxisFormatter
},
...(
xRange
||
{})
series
:
data
?.
map
(
item
=>
defaultsDeep
(
{
// show symbol if there is only one point
showSymbol
:
(
item
?.
data
?.
length
??
0
)
<=
1
,
type
:
'
line
'
},
item
,
chart
.
series
)
)
},
options
,
defaults
);
if
((
chartOptions
?.
xAxis
as
EChartOption
.
XAxis
).
type
===
'
time
'
)
{
chartOptions
=
defaultsDeep
(
{
xAxis
:
{
axisLabel
:
{
formatter
:
(
value
:
number
)
=>
formatTime
(
value
,
i18n
.
language
,
'
LTS
'
)
}
}
},
yAxis
:
{
...
chart
.
yAxis
,
name
:
yAxis
||
''
,
type
:
yType
||
'
value
'
,
...(
yRange
||
{})
chartOptions
);
}
if
((
chartOptions
?.
yAxis
as
EChartOption
.
YAxis
).
type
===
'
time
'
)
{
chartOptions
=
defaultsDeep
(
{
yAxis
:
{
axisLabel
:
{
formatter
:
(
value
:
number
)
=>
formatTime
(
value
,
i18n
.
language
,
'
LTS
'
)
}
}
},
series
:
data
?.
map
(
item
=>
({
...
chart
.
series
,
// show symbol if there is only one point
showSymbol
:
(
item
?.
data
?.
length
??
0
)
<=
1
,
...
item
}))
}
as
EChartOption
,
{
notMerge
:
true
}
);
chartOptions
);
}
echart
?.
setOption
(
chartOptions
,
{
notMerge
:
true
});
}
},
[
data
,
title
,
legend
,
xAxis
,
yAxis
,
xType
,
yType
,
xAxisFormatter
,
xRange
,
yRange
,
tooltip
,
echart
]);
},
[
options
,
data
,
title
,
i18n
.
language
,
echart
]);
return
(
<
Wrapper
ref
=
{
wrapper
}
className
=
{
className
}
>
...
...
frontend/packages/core/components/ScalarsPage/ScalarChart.tsx
浏览文件 @
7bdb74b1
import
{
Dataset
,
Range
,
RangeParams
,
TransformParam
s
,
SortingMethod
,
XAxi
s
,
chartData
,
options
as
chartOptions
,
nearestPoint
,
range
,
singlePointRange
,
...
...
@@ -28,12 +29,12 @@ import {useRunningRequest} from '~/hooks/useRequest';
import
{
useTranslation
}
from
'
~/utils/i18n
'
;
const
smoothWasm
=
()
=>
import
(
'
@visualdl/wasm
'
).
then
(({
transform
})
=>
(
params
:
TransformParams
)
=>
(
transform
(
params
.
datasets
,
params
.
smoothing
)
as
unknown
)
as
Dataset
[]
import
(
'
@visualdl/wasm
'
).
then
(({
scalar_transform
}):
typeof
transform
=>
params
=>
scalar_transform
(
params
.
datasets
,
params
.
smoothing
)
);
const
rangeWasm
=
()
=>
import
(
'
@visualdl/wasm
'
).
then
(({
range
})
=>
(
params
:
RangeParams
)
=>
(
range
(
params
.
datasets
,
params
.
outlier
)
as
unknown
)
as
Range
import
(
'
@visualdl/wasm
'
).
then
(({
scalar_range
}):
typeof
range
=>
params
=>
scalar_range
(
params
.
datasets
,
params
.
outlier
)
);
const
smoothWorker
=
()
=>
new
Worker
(
'
~/worker/scalars/smooth.worker.ts
'
,
{
type
:
'
module
'
});
...
...
@@ -88,8 +89,8 @@ type ScalarChartProps = {
runs
:
Run
[];
tag
:
string
;
smoothing
:
number
;
xAxis
:
keyof
typeof
xAxisMap
;
sortingMethod
:
keyof
typeof
sortingMethodMap
;
xAxis
:
XAxis
;
sortingMethod
:
SortingMethod
;
outlier
?:
boolean
;
running
?:
boolean
;
onToggleMaximized
?:
(
maximized
:
boolean
)
=>
void
;
...
...
@@ -115,7 +116,6 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
(...
urls
)
=>
cycleFetcher
(
urls
)
);
const
smooth
=
false
;
const
[
maximized
,
setMaximized
]
=
useState
<
boolean
>
(
false
);
const
toggleMaximized
=
useCallback
(()
=>
{
ee
.
emit
(
'
toggle-chart-size
'
,
cid
,
!
maximized
);
...
...
@@ -166,10 +166,9 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
chartData
({
data
:
smoothedDatasets
.
slice
(
0
,
runs
.
length
),
runs
,
smooth
,
xAxis
}),
[
smoothedDatasets
,
runs
,
smooth
,
xAxis
]
[
smoothedDatasets
,
runs
,
xAxis
]
);
const
formatter
=
useCallback
(
...
...
@@ -183,6 +182,25 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
[
smoothedDatasets
,
runs
,
sortingMethod
,
i18n
]
);
const
options
=
useMemo
(
()
=>
({
...
chartOptions
,
tooltip
:
{
...
chartOptions
.
tooltip
,
formatter
},
xAxis
:
{
type
:
xAxisType
,
...
ranges
.
x
},
yAxis
:
{
type
:
yAxisType
,
...
ranges
.
y
}
}),
[
formatter
,
ranges
,
xAxisType
,
yAxisType
]
);
// display error only on first fetch
if
(
!
data
&&
error
)
{
return
<
Error
>
{
t
(
'
common:error
'
)
}
</
Error
>;
...
...
@@ -190,17 +208,7 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
return
(
<
Wrapper
>
<
StyledLineChart
ref
=
{
echart
}
title
=
{
tag
}
xRange
=
{
ranges
.
x
}
yRange
=
{
ranges
.
y
}
xType
=
{
xAxisType
}
yType
=
{
yAxisType
}
tooltip
=
{
formatter
}
data
=
{
data
}
loading
=
{
loading
}
/>
<
StyledLineChart
ref
=
{
echart
}
title
=
{
tag
}
options
=
{
options
}
data
=
{
data
}
loading
=
{
loading
}
zoom
/>
<
Toolbox
items
=
{
[
{
...
...
frontend/packages/core/components/StackChart.tsx
0 → 100644
浏览文件 @
7bdb74b1
import
*
as
chart
from
'
~/utils/chart
'
;
import
React
,
{
useCallback
,
useEffect
,
useImperativeHandle
}
from
'
react
'
;
import
{
WithStyled
,
position
,
primaryColor
,
size
}
from
'
~/utils/style
'
;
import
{
EChartOption
}
from
'
echarts
'
;
import
GridLoader
from
'
react-spinners/GridLoader
'
;
import
{
dataURL2Blob
}
from
'
~/utils/image
'
;
import
defaultsDeep
from
'
lodash/defaultsDeep
'
;
import
{
saveAs
}
from
'
file-saver
'
;
import
styled
from
'
styled-components
'
;
import
useECharts
from
'
~/hooks/useECharts
'
;
import
{
useTranslation
}
from
'
~/utils/i18n
'
;
const
Wrapper
=
styled
.
div
`
position: relative;
> .echarts {
height: 100%;
}
> .loading {
${
size
(
'
100%
'
)}
${
position
(
'
absolute
'
,
0
,
null
,
null
,
0
)}
display: flex;
justify-content: center;
align-items: center;
}
`
;
type
renderItem
=
NonNullable
<
EChartOption
.
SeriesCustom
[
'
renderItem
'
]
>
;
type
renderItemArguments
=
NonNullable
<
renderItem
[
'
arguments
'
]
>
;
type
RenderItem
=
(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
params
:
any
,
api
:
Required
<
NonNullable
<
renderItemArguments
[
'
api
'
]
>>
)
=>
NonNullable
<
renderItem
[
'
return
'
]
>
;
type
GetValue
=
(
i
:
number
)
=>
number
;
type
GetCoord
=
(
p
:
[
number
,
number
])
=>
[
number
,
number
];
type
StackChartProps
=
{
options
?:
EChartOption
;
title
?:
string
;
data
?:
Partial
<
NonNullable
<
EChartOption
<
EChartOption
.
SeriesCustom
>
[
'
series
'
]
>
[
number
]
>
&
{
minZ
:
number
;
maxZ
:
number
;
minX
:
number
;
maxX
:
number
;
minStep
:
number
;
maxStep
:
number
;
};
loading
?:
boolean
;
zoom
?:
boolean
;
};
export
type
StackChartRef
=
{
saveAsImage
():
void
;
};
const
StackChart
=
React
.
forwardRef
<
StackChartRef
,
StackChartProps
&
WithStyled
>
(
({
options
,
data
,
title
,
loading
,
zoom
,
className
},
ref
)
=>
{
const
{
i18n
}
=
useTranslation
();
const
{
ref
:
echartRef
,
echart
,
wrapper
,
saveAsImage
}
=
useECharts
<
HTMLDivElement
>
({
loading
:
!!
loading
,
zoom
,
autoFit
:
true
});
useImperativeHandle
(
ref
,
()
=>
({
saveAsImage
:
()
=>
{
saveAsImage
(
title
);
}
}));
const
{
minZ
,
maxZ
,
minStep
,
maxStep
,
minX
,
maxX
,
...
seriesData
}
=
data
??
{
minZ
:
0
,
maxZ
:
0
,
minStep
:
0
,
maxStep
:
0
,
minX
:
0
,
maxX
:
0
,
data
:
null
};
const
rawData
=
(
seriesData
.
data
as
number
[][])
??
[];
const
getPoint
=
useCallback
(
(
x
:
number
,
y
:
number
,
z
:
number
,
getCoord
:
GetCoord
,
yValueMapHeight
:
number
)
=>
{
const
pt
=
getCoord
([
x
,
y
]);
// linear map in z axis
pt
[
1
]
-=
((
z
-
minZ
)
/
(
maxZ
-
minZ
))
*
yValueMapHeight
;
return
pt
;
},
[
minZ
,
maxZ
]
);
const
makePolyPoints
=
useCallback
(
(
dataIndex
:
number
,
getValue
:
GetValue
,
getCoord
:
GetCoord
,
yValueMapHeight
:
number
)
=>
{
const
points
=
[];
let
i
=
0
;
while
(
rawData
[
dataIndex
]
&&
i
<
rawData
[
dataIndex
].
length
)
{
const
x
=
getValue
(
i
++
);
const
y
=
getValue
(
i
++
);
const
z
=
getValue
(
i
++
);
points
.
push
(
getPoint
(
x
,
y
,
z
,
getCoord
,
yValueMapHeight
));
}
return
points
;
},
[
getPoint
,
rawData
]
);
useEffect
(()
=>
{
if
(
process
.
browser
)
{
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const
{
color
,
colorAlt
,
...
defaults
}
=
chart
;
const
chartOptions
:
EChartOption
=
defaultsDeep
(
{
title
:
{
text
:
title
??
''
},
visualMap
:
{
min
:
minStep
,
max
:
maxStep
},
xAxis
:
{
min
:
minX
,
max
:
maxX
},
grid
:
{
top
:
'
40%
'
},
tooltip
:
{
axisPointer
:
{
axis
:
'
y
'
,
snap
:
false
}
},
series
:
[
{
type
:
'
custom
'
,
dimensions
:
[
'
x
'
,
'
y
'
],
data
:
rawData
as
number
[][],
renderItem
:
((
params
,
api
)
=>
{
const
points
=
makePolyPoints
(
params
.
dataIndex
as
number
,
api
.
value
as
GetValue
,
api
.
coord
as
GetCoord
,
(
params
.
coordSys
.
y
as
number
)
-
10
);
return
{
type
:
'
polygon
'
,
silent
:
true
,
shape
:
{
points
},
style
:
api
.
style
({
stroke
:
chart
.
xAxis
.
axisLine
.
lineStyle
.
color
,
lineWidth
:
1
})
};
})
as
RenderItem
}
]
},
options
,
defaults
);
echart
?.
setOption
(
chartOptions
,
{
notMerge
:
true
});
}
},
[
options
,
data
,
title
,
i18n
.
language
,
echart
,
rawData
,
minX
,
maxX
,
minStep
,
maxStep
,
makePolyPoints
]);
return
(
<
Wrapper
ref
=
{
wrapper
}
className
=
{
className
}
>
{
!
echart
&&
(
<
div
className
=
"loading"
>
<
GridLoader
color
=
{
primaryColor
}
size
=
"10px"
/>
</
div
>
)
}
<
div
className
=
"echarts"
ref
=
{
echartRef
}
></
div
>
</
Wrapper
>
);
}
);
export
default
StackChart
;
frontend/packages/core/hooks/useECharts.ts
浏览文件 @
7bdb74b1
...
...
@@ -2,6 +2,8 @@ import {MutableRefObject, useCallback, useEffect, useLayoutEffect, useRef, useSt
import
{
maskColor
,
primaryColor
,
textColor
}
from
'
~/utils/style
'
;
import
{
ECharts
}
from
'
echarts
'
;
import
{
dataURL2Blob
}
from
'
~/utils/image
'
;
import
{
saveAs
}
from
'
file-saver
'
;
const
useECharts
=
<
T
extends
HTMLElement
,
W
extends
HTMLElement
=
HTMLDivElement
>
(
options
:
{
loading
?:
boolean
;
...
...
@@ -12,6 +14,7 @@ const useECharts = <T extends HTMLElement, W extends HTMLElement = HTMLDivElemen
ref
:
MutableRefObject
<
T
|
null
>
;
wrapper
:
MutableRefObject
<
W
|
null
>
;
echart
:
ECharts
|
null
;
saveAsImage
:
(
filename
?:
string
)
=>
void
;
}
=>
{
const
ref
=
useRef
<
T
|
null
>
(
null
);
const
echartInstance
=
useRef
<
ECharts
|
null
>
(
null
);
...
...
@@ -82,7 +85,17 @@ const useECharts = <T extends HTMLElement, W extends HTMLElement = HTMLDivElemen
}
},
[
options
.
autoFit
]);
return
{
ref
,
echart
,
wrapper
};
const
saveAsImage
=
useCallback
(
(
filename
?:
string
)
=>
{
if
(
echart
)
{
const
blob
=
dataURL2Blob
(
echart
.
getDataURL
({
type
:
'
png
'
,
pixelRatio
:
2
,
backgroundColor
:
'
#FFF
'
}));
saveAs
(
blob
,
`
${
filename
?.
replace
(
/
[/\\
?%*:|"<>
]
/g
,
'
_
'
)
||
'
chart
'
}
.png`
);
}
},
[
echart
]
);
return
{
ref
,
echart
,
wrapper
,
saveAsImage
};
};
export
default
useECharts
;
frontend/packages/core/hooks/useNavItems.ts
浏览文件 @
7bdb74b1
...
...
@@ -5,9 +5,10 @@ import {fetcher} from '~/utils/fetch';
import
intersection
from
'
lodash/intersection
'
;
import
useRequest
from
'
~/hooks/useRequest
'
;
const
allNavItems
=
[
'
scalars
'
,
'
samples
'
,
'
graphs
'
,
'
high-dimensional
'
];
const
allNavItems
=
[
'
scalars
'
,
'
histogram
'
,
'
samples
'
,
'
graphs
'
,
'
high-dimensional
'
];
export
const
navMap
=
{
scalar
:
'
scalars
'
,
histogram
:
'
histogram
'
,
image
:
'
samples
'
,
graph
:
'
graphs
'
,
embeddings
:
'
high-dimensional
'
...
...
frontend/packages/core/package.json
浏览文件 @
7bdb74b1
...
...
@@ -37,6 +37,7 @@
"@visualdl/netron"
:
"2.0.0-beta.43"
,
"@visualdl/wasm"
:
"2.0.0-beta.43"
,
"bignumber.js"
:
"9.0.0"
,
"d3-format"
:
"1.4.4"
,
"echarts"
:
"4.8.0"
,
"echarts-gl"
:
"1.1.1"
,
"eventemitter3"
:
"4.0.4"
,
...
...
@@ -52,7 +53,6 @@
"query-string"
:
"6.13.1"
,
"react"
:
"16.13.1"
,
"react-dom"
:
"16.13.1"
,
"react-hooks-worker"
:
"0.9.0"
,
"react-input-range"
:
"1.3.0"
,
"react-is"
:
"16.13.1"
,
"react-spinners"
:
"0.8.3"
,
...
...
@@ -64,6 +64,7 @@
},
"devDependencies"
:
{
"@babel/core"
:
"7.10.2"
,
"@types/d3-format"
:
"1.3.1"
,
"@types/echarts"
:
"4.6.1"
,
"@types/file-saver"
:
"2.0.1"
,
"@types/lodash"
:
"4.14.155"
,
...
...
frontend/packages/core/pages/histogram.tsx
0 → 100644
浏览文件 @
7bdb74b1
import
ChartPage
,
{
WithChart
}
from
'
~/components/ChartPage
'
;
import
{
Modes
,
modes
}
from
'
~/resource/histogram
'
;
import
{
NextI18NextPage
,
useTranslation
}
from
'
~/utils/i18n
'
;
import
React
,
{
useCallback
,
useMemo
,
useState
}
from
'
react
'
;
import
{
AsideSection
}
from
'
~/components/Aside
'
;
import
Content
from
'
~/components/Content
'
;
import
Error
from
'
~/components/Error
'
;
import
Field
from
'
~/components/Field
'
;
import
HistogramChart
from
'
~/components/HistogramPage/HistogramChart
'
;
import
Preloader
from
'
~/components/Preloader
'
;
import
RadioButton
from
'
~/components/RadioButton
'
;
import
RadioGroup
from
'
~/components/RadioGroup
'
;
import
RunAside
from
'
~/components/RunAside
'
;
import
{
TagWithSingleRun
}
from
'
~/types
'
;
import
Title
from
'
~/components/Title
'
;
import
useTagFilter
from
'
~/hooks/useTagFilter
'
;
const
Histogram
:
NextI18NextPage
=
()
=>
{
const
{
t
}
=
useTranslation
([
'
histogram
'
,
'
common
'
]);
const
[
running
,
setRunning
]
=
useState
(
true
);
const
{
runs
,
tags
,
selectedRuns
,
onChangeRuns
,
loadingRuns
,
loadingTags
}
=
useTagFilter
(
'
histogram
'
,
running
);
const
tagsWithSingleRun
=
useMemo
(
()
=>
tags
.
reduce
<
(
TagWithSingleRun
&
{
id
:
string
})[]
>
((
result
,
tag
)
=>
{
result
.
push
(...
tag
.
runs
.
map
(
run
=>
({
id
:
`
${
tag
.
label
}
-
${
run
.
label
}
`
,
label
:
tag
.
label
,
run
})));
return
result
;
},
[]),
[
tags
]
);
const
[
mode
,
setMode
]
=
useState
<
Modes
>
(
Modes
.
Offset
);
const
aside
=
useMemo
(
()
=>
runs
.
length
?
(
<
RunAside
runs
=
{
runs
}
selectedRuns
=
{
selectedRuns
}
onChangeRuns
=
{
onChangeRuns
}
running
=
{
running
}
onToggleRunning
=
{
setRunning
}
>
<
AsideSection
>
<
Field
label
=
{
t
(
'
histogram:mode
'
)
}
>
<
RadioGroup
value
=
{
mode
}
onChange
=
{
setMode
}
>
{
modes
.
map
(
value
=>
(
<
RadioButton
key
=
{
value
}
value
=
{
value
}
>
{
t
(
`histogram:mode-value.
${
value
}
`
)
}
</
RadioButton
>
))
}
</
RadioGroup
>
</
Field
>
</
AsideSection
>
</
RunAside
>
)
:
null
,
[
t
,
mode
,
onChangeRuns
,
running
,
runs
,
selectedRuns
]
);
const
withChart
=
useCallback
<
WithChart
<
TagWithSingleRun
>>
(
({
label
,
run
,
...
args
})
=>
<
HistogramChart
run
=
{
run
}
tag
=
{
label
}
{
...
args
}
mode
=
{
mode
}
running
=
{
running
}
/>,
[
running
,
mode
]
);
return
(
<>
<
Preloader
url
=
"/runs"
/>
<
Preloader
url
=
"/histogram/tags"
/>
<
Title
>
{
t
(
'
common:histogram
'
)
}
</
Title
>
<
Content
aside
=
{
aside
}
loading
=
{
loadingRuns
}
>
{
!
loadingRuns
&&
!
runs
.
length
?
(
<
Error
/>
)
:
(
<
ChartPage
items
=
{
tagsWithSingleRun
}
withChart
=
{
withChart
}
loading
=
{
loadingRuns
||
loadingTags
}
/>
)
}
</
Content
>
</>
);
};
Histogram
.
getInitialProps
=
()
=>
({
namespacesRequired
:
[
'
histogram
'
,
'
common
'
]
});
export
default
Histogram
;
frontend/packages/core/pages/scalars.tsx
浏览文件 @
7bdb74b1
import
ChartPage
,
{
WithChart
}
from
'
~/components/ChartPage
'
;
import
{
NextI18NextPage
,
useTranslation
}
from
'
~/utils/i18n
'
;
import
React
,
{
useCallback
,
useMemo
,
useState
}
from
'
react
'
;
import
{
sortingMethodMap
,
xAxisMap
}
from
'
~/resource/scalars
'
;
import
{
SortingMethod
,
XAxis
,
sortingMethod
as
toolTipSortingValues
,
xAxis
as
xAxisValues
}
from
'
~/resource/scalars
'
;
import
{
AsideSection
}
from
'
~/components/Aside
'
;
import
Checkbox
from
'
~/components/Checkbox
'
;
...
...
@@ -21,11 +21,6 @@ import {rem} from '~/utils/style';
import
styled
from
'
styled-components
'
;
import
useTagFilter
from
'
~/hooks/useTagFilter
'
;
type
XAxis
=
keyof
typeof
xAxisMap
;
const
xAxisValues
=
[
'
step
'
,
'
relative
'
,
'
wall
'
]
as
const
;
type
TooltipSorting
=
keyof
typeof
sortingMethodMap
;
const
toolTipSortingValues
=
[
'
default
'
,
'
descending
'
,
'
ascending
'
,
'
nearest
'
]
as
const
;
const
TooltipSortingDiv
=
styled
.
div
`
margin-top:
${
rem
(
20
)}
;
display: flex;
...
...
@@ -49,7 +44,7 @@ const Scalars: NextI18NextPage = () => {
const
[
xAxis
,
setXAxis
]
=
useState
<
XAxis
>
(
xAxisValues
[
0
]);
const
[
tooltipSorting
,
setTooltipSorting
]
=
useState
<
TooltipSorting
>
(
toolTipSortingValues
[
0
]);
const
[
tooltipSorting
,
setTooltipSorting
]
=
useState
<
SortingMethod
>
(
toolTipSortingValues
[
0
]);
const
[
ignoreOutliers
,
setIgnoreOutliers
]
=
useState
(
false
);
...
...
@@ -71,7 +66,7 @@ const Scalars: NextI18NextPage = () => {
<
span
>
{
t
(
'
scalars:tooltip-sorting
'
)
}
</
span
>
<
Select
list
=
{
toolTipSortingValues
.
map
(
value
=>
({
label
:
t
(
`tooltip-sorting-value.
${
value
}
`
),
label
:
t
(
`
scalars:
tooltip-sorting-value.
${
value
}
`
),
value
}))
}
value
=
{
tooltipSorting
}
...
...
@@ -89,7 +84,7 @@ const Scalars: NextI18NextPage = () => {
<
RadioGroup
value
=
{
xAxis
}
onChange
=
{
setXAxis
}
>
{
xAxisValues
.
map
(
value
=>
(
<
RadioButton
key
=
{
value
}
value
=
{
value
}
>
{
t
(
`x-axis-value.
${
value
}
`
)
}
{
t
(
`
scalars:
x-axis-value.
${
value
}
`
)
}
</
RadioButton
>
))
}
</
RadioGroup
>
...
...
frontend/packages/core/public/locales/en/common.json
浏览文件 @
7bdb74b1
...
...
@@ -6,6 +6,7 @@
"error"
:
"Error occurred"
,
"graphs"
:
"Graphs"
,
"high-dimensional"
:
"High Dimensional"
,
"histogram"
:
"Histogram"
,
"loading"
:
"Please wait while loading data"
,
"next-page"
:
"Next Page"
,
"previous-page"
:
"Prev Page"
,
...
...
@@ -14,19 +15,19 @@
"runs"
:
"Runs"
,
"samples"
:
"Samples"
,
"scalars"
:
"Scalars"
,
"search"
:
"Search"
,
"search-empty"
:
"Nothing found. Please try again with another word. <1/>Or you can <3>see all charts</3>."
,
"search-result"
:
"Search Result"
,
"search-runs"
:
"Search runs"
,
"search-tags"
:
"Search tags in RegExp"
,
"se
arch"
:
"Search
"
,
"se
lect"
:
"Please Select
"
,
"select-all"
:
"Select All"
,
"select-runs"
:
"Select Runs"
,
"select"
:
"Please Select"
,
"start-realtime-refresh"
:
"Start realtime refresh"
,
"stop-realtime-refresh"
:
"Stop realtime refresh"
,
"stop"
:
"Stop"
,
"stop-realtime-refresh"
:
"Stop realtime refresh"
,
"stopped"
:
"Stopped"
,
"total-page_plural"
:
"{{count}} pages, jump to"
,
"total-page"
:
"{{count}} page, jump to"
,
"total-page_plural"
:
"{{count}} pages, jump to"
,
"unselected-empty"
:
"Nothing selected. <1/>Please select display data from right side."
}
frontend/packages/core/public/locales/en/errors.json
浏览文件 @
7bdb74b1
{
"error-with-status"
:
"A {{statusCode}} error occurred on server"
,
"error-without-status"
:
"An error occurred on the server"
,
"page-not-found"
:
"Page Not Found"
,
"common"
:
{
"title"
:
"No visualized data."
,
"description"
:
"Possible reasons are:"
,
"1"
:
"Log files are not generated. Please refer to <1>README</1> to create log files."
,
"2"
:
"Log files are generated but data is not written yet. Please refer to <1>VisualDL User Guide</1> to write visualized data."
,
"3"
:
"Log files are generated and data is writte. Please try to <1>Refresh</1>."
,
"4"
:
"Log files are generated but path to log directory is wrong. Please check your directory and try again."
}
"4"
:
"Log files are generated but path to log directory is wrong. Please check your directory and try again."
,
"description"
:
"Possible reasons are:"
,
"title"
:
"No visualized data."
},
"error-with-status"
:
"A {{statusCode}} error occurred on server"
,
"error-without-status"
:
"An error occurred on the server"
,
"page-not-found"
:
"Page Not Found"
}
frontend/packages/core/public/locales/en/graphs.json
浏览文件 @
7bdb74b1
{
"change-model"
:
"Change Model"
,
"model-properties"
:
"Model Properties"
,
"node-properties"
:
"Node Properties"
,
"node-documentation"
:
"Documentation"
,
"nothing-matched"
:
"Nothing matched"
,
"display-data"
:
"Select Display Data"
,
"show-attributes"
:
"Show Attributes"
,
"show-initializers"
:
"Show Initializers"
,
"show-node-names"
:
"Show Node Names"
,
"documentation"
:
{
"attributes"
:
"Attributes"
,
"examples"
:
"Examples"
,
"inputs"
:
"Inputs"
,
"outputs"
:
"Outputs"
,
"references"
:
"References"
,
"support"
:
"Support"
,
"support-info"
:
"In domain <1>{{domain}}</1> since version <3>{{since_version}}</3> at support level <5>{{support_level}}</5>."
,
"type-constraints"
:
"Type Constraints"
},
"experimental-supported-model"
:
"Experimental supported models: "
,
"experimental-supported-model-list"
:
"TorchScript, PyTorch, Torch, ArmNN, BigDL, Chainer, CNTK, Deeplearning4j, MediaPipe, ML.NET, MNN, OpenVINO, Scikit-learn, Tengine, TensorFlow.js, TensorFlow"
,
"export-file"
:
"Export File"
,
"export-png"
:
"PNG"
,
"export-svg"
:
"SVG"
,
"upload-tip"
:
"Click or Drop file here to view neural network models"
,
"upload-model"
:
"Upload Model"
,
"supported-model"
:
"Supported models: "
,
"experimental-supported-model"
:
"Experimental supported models: "
,
"supported-model-list"
:
"PaddlePaddle, ONNX, Keras, Core ML, Caffe, Caffe2, Darknet, MXNet, ncnn, TensorFlow Lite"
,
"experimental-supported-model-list"
:
"TorchScript, PyTorch, Torch, ArmNN, BigDL, Chainer, CNTK, Deeplearning4j, MediaPipe, ML.NET, MNN, OpenVINO, Scikit-learn, Tengine, TensorFlow.js, TensorFlow"
,
"model-properties"
:
"Model Properties"
,
"node-documentation"
:
"Documentation"
,
"node-properties"
:
"Node Properties"
,
"nothing-matched"
:
"Nothing matched"
,
"properties"
:
{
"format"
:
"Format"
,
"producer"
:
"Producer"
,
"source"
:
"Source"
,
"name"
:
"Name"
,
"version"
:
"Version"
,
"description"
:
"Description"
,
"attributes"
:
"Attributes"
,
"author"
:
"Author"
,
"company"
:
"Company"
,
"
license"
:
"License
"
,
"
description"
:
"Description
"
,
"domain"
:
"Domain"
,
"format"
:
"Format"
,
"imports"
:
"Imports"
,
"runtime"
:
"Runtime"
,
"type"
:
"Type"
,
"tags"
:
"Tags"
,
"inputs"
:
"Inputs"
,
"outputs"
:
"Outputs"
,
"attributes"
:
"Attributes"
},
"documentation"
:
{
"attributes"
:
"Attributes"
,
"inputs"
:
"Inputs"
,
"license"
:
"License"
,
"name"
:
"Name"
,
"outputs"
:
"Outputs"
,
"type-constraints"
:
"Type Constraints"
,
"examples"
:
"Examples"
,
"references"
:
"References"
,
"support"
:
"Support"
,
"support-info"
:
"In domain <1>{{domain}}</1> since version <3>{{since_version}}</3> at support level <5>{{support_level}}</5>."
"producer"
:
"Producer"
,
"runtime"
:
"Runtime"
,
"source"
:
"Source"
,
"tags"
:
"Tags"
,
"type"
:
"Type"
,
"version"
:
"Version"
},
"restore-size"
:
"Restore Size"
,
"show-attributes"
:
"Show Attributes"
,
"show-initializers"
:
"Show Initializers"
,
"show-node-names"
:
"Show Node Names"
,
"supported-model"
:
"Supported models: "
,
"supported-model-list"
:
"PaddlePaddle, ONNX, Keras, Core ML, Caffe, Caffe2, Darknet, MXNet, ncnn, TensorFlow Lite"
,
"upload-model"
:
"Upload Model"
,
"upload-tip"
:
"Click or Drop file here to view neural network models"
,
"zoom-in"
:
"Zoom In"
,
"zoom-out"
:
"Zoom Out"
}
frontend/packages/core/public/locales/en/histogram.json
0 → 100644
浏览文件 @
7bdb74b1
{
"download-image"
:
"Download image"
,
"maximize"
:
"Maximize"
,
"minimize"
:
"Minimize"
,
"mode"
:
"Mode"
,
"mode-value"
:
{
"offset"
:
"Offset"
,
"overlay"
:
"Overlay"
}
}
frontend/packages/core/public/locales/zh/common.json
浏览文件 @
7bdb74b1
...
...
@@ -6,6 +6,7 @@
"error"
:
"发生错误"
,
"graphs"
:
"网络结构"
,
"high-dimensional"
:
"高维数据映射"
,
"histogram"
:
"直方图"
,
"loading"
:
"数据载入中,请稍等"
,
"next-page"
:
"下一页"
,
"previous-page"
:
"上一页"
,
...
...
@@ -14,19 +15,19 @@
"runs"
:
"数据流"
,
"samples"
:
"样本数据"
,
"scalars"
:
"标量数据"
,
"search"
:
"搜索"
,
"search-empty"
:
"没有找到您期望的内容,你可以尝试其他搜索词<1/>或者点击<3>查看全部图表</3>"
,
"search-result"
:
"搜索结果"
,
"search-runs"
:
"搜索数据流"
,
"search-tags"
:
"搜索标签(支持正则)"
,
"se
arch"
:
"搜索
"
,
"se
lect"
:
"请选择
"
,
"select-all"
:
"全选"
,
"select-runs"
:
"选择数据流"
,
"select"
:
"请选择"
,
"start-realtime-refresh"
:
"运行实时数据刷新"
,
"stop-realtime-refresh"
:
"停止实时数据刷新"
,
"stop"
:
"停止"
,
"stop-realtime-refresh"
:
"停止实时数据刷新"
,
"stopped"
:
"已停止"
,
"total-page_plural"
:
"共 {{count}} 页,跳转至"
,
"total-page"
:
"共 {{count}} 页,跳转至"
,
"total-page_plural"
:
"共 {{count}} 页,跳转至"
,
"unselected-empty"
:
"未选中任何数据<1/>请在右侧操作栏选择要展示的数据"
}
frontend/packages/core/public/locales/zh/errors.json
浏览文件 @
7bdb74b1
{
"error-with-status"
:
"服务器发生了一个 {{statusCode}} 错误"
,
"error-without-status"
:
"服务器发生了一个错误"
,
"page-not-found"
:
"页面不存在"
,
"common"
:
{
"title"
:
"无可视化结果展示"
,
"description"
:
"有以下几种可能原因,请您参考相应解决方案:"
,
"1"
:
"未生成日志文件。请参考 <1>README</1> 创建日志文件。"
,
"2"
:
"已生成日志文件,但尚未打点数据。请参考 <1>VisualDL使用指南</1> ,对需要进行可视化的数据进行打点记录。"
,
"3"
:
"已生成文件并打点数据,请尝试 <1>刷新</1> 。"
,
"4"
:
"已生成文件,但日志文件路径错误,请确保文件路径正确。"
}
"4"
:
"已生成文件,但日志文件路径错误,请确保文件路径正确。"
,
"description"
:
"有以下几种可能原因,请您参考相应解决方案:"
,
"title"
:
"无可视化结果展示"
},
"error-with-status"
:
"服务器发生了一个 {{statusCode}} 错误"
,
"error-without-status"
:
"服务器发生了一个错误"
,
"page-not-found"
:
"页面不存在"
}
frontend/packages/core/public/locales/zh/graphs.json
浏览文件 @
7bdb74b1
{
"change-model"
:
"更换模型"
,
"model-properties"
:
"模型属性"
,
"node-properties"
:
"节点属性"
,
"node-documentation"
:
"文档"
,
"nothing-matched"
:
"无匹配的内容"
,
"display-data"
:
"选择展示数据"
,
"show-attributes"
:
"显示参数"
,
"show-initializers"
:
"显示初始化参数"
,
"show-node-names"
:
"显示节点名称"
,
"documentation"
:
{
"attributes"
:
"属性"
,
"examples"
:
"示例"
,
"inputs"
:
"输入"
,
"outputs"
:
"输出"
,
"references"
:
"参考"
,
"support"
:
"支持"
,
"support-info"
:
"从 <3>{{since_version}}</3> 版本起域名 <1>{{domain}}</1> 的支持等级为 <5>{{support_level}}</5>。"
,
"type-constraints"
:
"类型约束"
},
"experimental-supported-model"
:
"VisualDL实验性支持:"
,
"experimental-supported-model-list"
:
"TorchScript、PyTorch、Torch、 ArmNN、BigDL、Chainer、CNTK、Deeplearning4j、MediaPipe、ML.NET、MNN、OpenVINO、Scikit-learn、Tengine、TensorFlow.js、TensorFlow"
,
"export-file"
:
"导出文件"
,
"export-png"
:
"PNG"
,
"export-svg"
:
"SVG"
,
"upload-tip"
:
"点击或拖拽文件到页面上传模型,进行结构展示"
,
"upload-model"
:
"上传模型"
,
"supported-model"
:
"VisualDL支持:"
,
"experimental-supported-model"
:
"VisualDL实验性支持:"
,
"supported-model-list"
:
"PaddlePaddle、ONNX、Keras、Core ML、Caffe、Caffe2、Darknet、MXNet、ncnn、TensorFlow Lite"
,
"experimental-supported-model-list"
:
"TorchScript、PyTorch、Torch、 ArmNN、BigDL、Chainer、CNTK、Deeplearning4j、MediaPipe、ML.NET、MNN、OpenVINO、Scikit-learn、Tengine、TensorFlow.js、TensorFlow"
,
"model-properties"
:
"模型属性"
,
"node-documentation"
:
"文档"
,
"node-properties"
:
"节点属性"
,
"nothing-matched"
:
"无匹配的内容"
,
"properties"
:
{
"format"
:
"格式"
,
"producer"
:
"框架"
,
"source"
:
"源"
,
"name"
:
"名称"
,
"version"
:
"版本"
,
"description"
:
"描述"
,
"attributes"
:
"属性"
,
"author"
:
"作者"
,
"company"
:
"公司"
,
"
license"
:
"许可证
"
,
"
description"
:
"描述
"
,
"domain"
:
"域名"
,
"format"
:
"格式"
,
"imports"
:
"导入"
,
"runtime"
:
"运行时"
,
"type"
:
"类型"
,
"tags"
:
"标签"
,
"inputs"
:
"输入"
,
"outputs"
:
"输出"
,
"attributes"
:
"属性"
},
"documentation"
:
{
"attributes"
:
"属性"
,
"inputs"
:
"输入"
,
"license"
:
"许可证"
,
"name"
:
"名称"
,
"outputs"
:
"输出"
,
"type-constraints"
:
"类型约束"
,
"examples"
:
"示例"
,
"references"
:
"参考"
,
"support"
:
"支持"
,
"support-info"
:
"从 <3>{{since_version}}</3> 版本起域名 <1>{{domain}}</1> 的支持等级为 <5>{{support_level}}</5>。"
"producer"
:
"框架"
,
"runtime"
:
"运行时"
,
"source"
:
"源"
,
"tags"
:
"标签"
,
"type"
:
"类型"
,
"version"
:
"版本"
},
"restore-size"
:
"重置大小"
,
"show-attributes"
:
"显示参数"
,
"show-initializers"
:
"显示初始化参数"
,
"show-node-names"
:
"显示节点名称"
,
"supported-model"
:
"VisualDL支持:"
,
"supported-model-list"
:
"PaddlePaddle、ONNX、Keras、Core ML、Caffe、Caffe2、Darknet、MXNet、ncnn、TensorFlow Lite"
,
"upload-model"
:
"上传模型"
,
"upload-tip"
:
"点击或拖拽文件到页面上传模型,进行结构展示"
,
"zoom-in"
:
"放大"
,
"zoom-out"
:
"缩小"
}
frontend/packages/core/public/locales/zh/high-dimensional.json
浏览文件 @
7bdb74b1
{
"display-all-label"
:
"展示所有标签"
,
"dimension"
:
"维度"
,
"2d"
:
"二维"
,
"3d"
:
"三维"
,
"reduction-method"
:
"降维方法"
,
"dimension"
:
"维度"
,
"display-all-label"
:
"展示所有标签"
,
"pca"
:
"PCA"
,
"reduction-method"
:
"降维方法"
,
"tsne"
:
"T-SNE"
}
frontend/packages/core/public/locales/zh/histogram.json
0 → 100644
浏览文件 @
7bdb74b1
{
"download-image"
:
"下载图片"
,
"maximize"
:
"最大化"
,
"minimize"
:
"最小化"
,
"mode"
:
"直方图模式"
,
"mode-value"
:
{
"offset"
:
"Offset"
,
"overlay"
:
"Overlay"
}
}
frontend/packages/core/public/locales/zh/samples.json
浏览文件 @
7bdb74b1
{
"image"
:
"图片"
,
"audio"
:
"音频"
,
"text"
:
"文本"
,
"brightness"
:
"亮度"
,
"contrast"
:
"对比度"
,
"download-image"
:
"下载$t(image)"
,
"image"
:
"图片"
,
"show-actual-size"
:
"按真实大小展示"
,
"step"
:
"Step"
,
"download-image"
:
"下载$t(image)"
,
"brightness"
:
"亮度"
,
"contrast"
:
"对比度"
"text"
:
"文本"
}
frontend/packages/core/public/locales/zh/scalars.json
浏览文件 @
7bdb74b1
{
"smoothing"
:
"平滑度"
,
"value"
:
"Value"
,
"axis"
:
"坐标轴"
,
"download-image"
:
"下载图片"
,
"ignore-outliers"
:
"图表缩放时忽略极端值"
,
"maximize"
:
"最大化"
,
"minimize"
:
"最小化"
,
"restore"
:
"还原"
,
"smoothed"
:
"Smoothed"
,
"x-axis"
:
"X轴"
,
"x-axis-value"
:
{
"step"
:
"Step"
,
"relative"
:
"Relative"
,
"wall"
:
"Wall Time"
},
"smoothing"
:
"平滑度"
,
"tooltip-sorting"
:
"标签排序方法"
,
"tooltip-sorting-value"
:
{
"ascending"
:
"升序"
,
"default"
:
"默认"
,
"descending"
:
"降序"
,
"ascending"
:
"升序"
,
"nearest"
:
"最近"
},
"ignore-outliers"
:
"图表缩放时忽略极端值"
,
"maximize"
:
"最大化"
,
"minimize"
:
"最小化"
,
"restore"
:
"还原"
,
"axis"
:
"坐标轴"
,
"download-image"
:
"下载图片"
"value"
:
"Value"
,
"x-axis"
:
"X轴"
,
"x-axis-value"
:
{
"relative"
:
"Relative"
,
"step"
:
"Step"
,
"wall"
:
"Wall Time"
}
}
frontend/packages/core/resource/high-dimensional/index.ts
浏览文件 @
7bdb74b1
import
{
DivideParams
,
Point
}
from
'
./types
'
;
import
{
Point
}
from
'
./types
'
;
export
*
from
'
./types
'
;
...
...
@@ -30,5 +30,14 @@ const combineLabel = (points: Point['value'][], labels: string[], visibility?: b
};
});
export
const
divide
=
({
points
,
keyword
,
labels
,
visibility
}:
DivideParams
)
=>
dividePoints
(
combineLabel
(
points
,
labels
,
visibility
),
keyword
);
export
const
divide
=
({
points
,
keyword
,
labels
,
visibility
}:
{
points
:
Point
[
'
value
'
][];
keyword
?:
string
;
labels
:
string
[];
visibility
?:
boolean
;
})
=>
dividePoints
(
combineLabel
(
points
,
labels
,
visibility
),
keyword
);
frontend/packages/core/resource/high-dimensional/types.ts
浏览文件 @
7bdb74b1
...
...
@@ -6,10 +6,3 @@ export type Point = {
value
:
[
number
,
number
]
|
[
number
,
number
,
number
];
showing
:
boolean
;
};
export
type
DivideParams
=
{
points
:
Point
[
'
value
'
][];
keyword
?:
string
;
labels
:
string
[];
visibility
?:
boolean
;
};
frontend/packages/core/resource/histogram/chart.ts
0 → 100644
浏览文件 @
7bdb74b1
import
{
EChartOption
,
VisualMap
}
from
'
echarts
'
;
import
{
Modes
}
from
'
./types
'
;
const
baseOptions
:
EChartOption
=
{
legend
:
{
data
:
[]
},
tooltip
:
{
showContent
:
false
}
};
export
const
options
:
Record
<
Modes
,
EChartOption
>
=
{
overlay
:
{
...
baseOptions
,
axisPointer
:
{
link
:
[
{
xAxisIndex
:
'
all
'
}
],
show
:
true
,
snap
:
true
,
triggerTooltip
:
true
},
yAxis
:
{
axisLine
:
{
onZero
:
false
}
}
},
offset
:
{
...
baseOptions
,
visualMap
:
({
type
:
'
continuous
'
,
show
:
false
,
dimension
:
1
,
inRange
:
{
colorLightness
:
[
0.5
,
0.8
],
colorSaturation
:
[
0.5
,
0.8
]
}
}
as
unknown
)
as
VisualMap
.
Continuous
[],
// Fix echarts type bug
xAxis
:
{
axisLine
:
{
onZero
:
false
}
},
yAxis
:
{
axisLine
:
{
onZero
:
false
},
inverse
:
true
,
splitLine
:
{
show
:
false
}
}
}
};
frontend/packages/core/resource/histogram/data.ts
0 → 100644
浏览文件 @
7bdb74b1
import
{
HistogramData
,
Modes
,
OffsetData
,
OffsetDataItem
,
OverlayData
,
OverlayDataItem
}
from
'
./types
'
;
function
computeHistogram
(
data
:
{
left
:
number
;
right
:
number
;
count
:
number
}[],
min
:
number
,
max
:
number
,
binsNum
=
30
)
{
if
(
min
===
max
)
{
// Create bins even if all the data has a single value.
max
=
min
*
1.1
+
1
;
min
=
min
/
1.1
-
1
;
}
const
stepWidth
=
(
max
-
min
)
/
binsNum
;
const
range
:
number
[]
=
[];
for
(
let
i
=
min
;
i
<
max
;
i
+=
stepWidth
)
{
range
.
push
(
i
);
}
let
itemIndex
=
0
;
return
range
.
map
(
binLeft
=>
{
const
binRight
=
binLeft
+
stepWidth
;
let
yValue
=
0
;
while
(
itemIndex
<
data
.
length
)
{
const
itemRight
=
Math
.
min
(
max
,
data
[
itemIndex
].
right
);
const
itemLeft
=
Math
.
max
(
min
,
data
[
itemIndex
].
left
);
const
overlap
=
Math
.
min
(
itemRight
,
binRight
)
-
Math
.
max
(
itemLeft
,
binLeft
);
const
count
=
(
overlap
/
(
itemRight
-
itemLeft
))
*
data
[
itemIndex
].
count
;
if
(
overlap
>
0
)
{
yValue
+=
count
;
}
// If `itemRight` is bigger than `binRight`, then this bin is
// finished and there also has data for the next bin, so don't increment
// `itemIndex`.
if
(
itemRight
>
binRight
)
{
break
;
}
itemIndex
++
;
}
return
{
x
:
binLeft
,
dx
:
stepWidth
,
y
:
yValue
};
});
}
export
function
transform
({
data
,
mode
}:
{
data
:
HistogramData
;
mode
:
Modes
})
{
const
temp
=
data
.
map
(([
time
,
step
,
items
])
=>
({
time
,
step
,
min
:
Math
.
min
(...
items
.
map
(
item
=>
item
[
0
])),
max
:
Math
.
max
(...
items
.
map
(
item
=>
item
[
1
])),
items
:
items
.
map
(([
left
,
right
,
count
])
=>
({
left
,
right
,
count
}))
}));
const
min
=
Math
.
min
(...
temp
.
map
(({
min
})
=>
min
));
const
max
=
Math
.
max
(...
temp
.
map
(({
max
})
=>
max
));
const
overlay
=
temp
.
map
(({
time
,
step
,
items
})
=>
computeHistogram
(
items
,
min
,
max
).
map
<
OverlayDataItem
>
(({
x
,
dx
,
y
})
=>
[
time
,
step
,
x
+
dx
/
2
,
Math
.
floor
(
y
)])
);
if
(
mode
===
Modes
.
Overlay
)
{
return
{
min
,
max
,
data
:
overlay
}
as
OverlayData
;
}
if
(
mode
===
Modes
.
Offset
)
{
let
minStep
=
Infinity
;
let
maxStep
=
-
Infinity
;
let
minZ
=
Infinity
;
let
maxZ
=
-
Infinity
;
const
offset
=
overlay
.
map
(
items
=>
{
const
step
=
items
[
0
][
1
];
step
>
maxStep
&&
(
maxStep
=
step
);
step
<
minStep
&&
(
minStep
=
step
);
return
items
.
reduce
<
OffsetDataItem
[]
>
((
m
,
[,
,
x
,
y
])
=>
{
y
>
maxZ
&&
(
maxZ
=
y
);
y
<
minZ
&&
(
minZ
=
y
);
return
[...
m
,
x
,
step
,
y
];
},
[]);
});
return
{
minX
:
min
,
maxX
:
max
,
minZ
,
maxZ
,
minStep
,
maxStep
,
data
:
offset
}
as
OffsetData
;
}
return
undefined
as
never
;
}
frontend/packages/core/resource/histogram/index.ts
0 → 100644
浏览文件 @
7bdb74b1
import
{
Modes
}
from
'
./types
'
;
export
const
modes
=
[
Modes
.
Offset
,
Modes
.
Overlay
]
as
const
;
export
*
from
'
./types
'
;
export
*
from
'
./chart
'
;
export
*
from
'
./data
'
;
frontend/packages/core/resource/histogram/types.ts
0 → 100644
浏览文件 @
7bdb74b1
export
enum
Modes
{
Offset
=
'
offset
'
,
Overlay
=
'
overlay
'
}
type
Time
=
number
;
type
Step
=
number
;
type
Left
=
number
;
type
Right
=
number
;
type
Count
=
number
;
type
Item
=
[
Left
,
Right
,
Count
];
export
type
HistogramDataItem
=
[
Time
,
Step
,
Item
[]];
export
type
HistogramData
=
HistogramDataItem
[];
export
type
OverlayDataItem
=
[
Time
,
Step
,
number
,
number
];
export
type
OverlayData
=
{
min
:
number
;
max
:
number
;
data
:
OverlayDataItem
[][];
};
export
type
OffsetDataItem
=
number
;
export
type
OffsetData
=
{
minX
:
number
;
maxX
:
number
;
minZ
:
number
;
maxZ
:
number
;
minStep
:
number
;
maxStep
:
number
;
data
:
OffsetDataItem
[][];
};
frontend/packages/core/resource/scalars/chart.ts
0 → 100644
浏览文件 @
7bdb74b1
import
{
Dataset
,
TooltipData
,
XAxis
}
from
'
./types
'
;
import
{
I18n
}
from
'
@visualdl/i18n
'
;
import
{
Run
}
from
'
~/types
'
;
import
{
format
}
from
'
d3-format
'
;
import
{
formatTime
}
from
'
~/utils
'
;
import
{
xAxisMap
}
from
'
./index
'
;
const
valueFormatter
=
format
(
'
.5
'
);
export
const
options
=
{
legend
:
{
data
:
[]
},
tooltip
:
{
position
:
[
'
10%
'
,
'
100%
'
]
}
};
export
const
chartData
=
({
data
,
runs
,
xAxis
}:
{
data
:
Dataset
[];
runs
:
Run
[];
xAxis
:
XAxis
})
=>
data
.
map
((
dataset
,
i
)
=>
{
// smoothed data:
// [0] wall time
// [1] step
// [2] orginal value
// [3] smoothed value
// [4] relative
const
name
=
runs
[
i
].
label
;
const
color
=
runs
[
i
].
colors
[
0
];
const
colorAlt
=
runs
[
i
].
colors
[
1
];
return
[
{
name
,
z
:
i
,
itemStyle
:
{
color
:
colorAlt
},
lineStyle
:
{
color
:
colorAlt
},
data
:
dataset
,
encode
:
{
x
:
[
xAxisMap
[
xAxis
]],
y
:
[
2
]
}
},
{
name
,
z
:
runs
.
length
+
i
,
itemStyle
:
{
color
},
lineStyle
:
{
color
},
data
:
dataset
,
encode
:
{
x
:
[
xAxisMap
[
xAxis
]],
y
:
[
3
]
}
}
];
})
.
flat
();
// TODO: make it better, don't concat html
export
const
tooltip
=
(
data
:
TooltipData
[],
i18n
:
I18n
)
=>
{
const
indexPropMap
=
{
time
:
0
,
step
:
1
,
value
:
2
,
smoothed
:
3
,
relative
:
4
}
as
const
;
const
widthPropMap
=
{
run
:
[
60
,
180
]
as
[
number
,
number
],
time
:
150
,
step
:
40
,
value
:
60
,
smoothed
:
70
,
relative
:
60
}
as
const
;
const
translatePropMap
=
{
run
:
'
common:runs
'
,
time
:
'
scalars:x-axis-value.wall
'
,
step
:
'
scalars:x-axis-value.step
'
,
value
:
'
scalars:value
'
,
smoothed
:
'
scalars:smoothed
'
,
relative
:
'
scalars:x-axis-value.relative
'
}
as
const
;
const
transformedData
=
data
.
map
(
item
=>
{
const
data
=
item
.
item
;
return
{
run
:
item
.
run
,
smoothed
:
valueFormatter
(
data
[
indexPropMap
.
smoothed
]
??
Number
.
NaN
),
value
:
valueFormatter
(
data
[
indexPropMap
.
value
]
??
Number
.
NaN
),
step
:
data
[
indexPropMap
.
step
],
time
:
formatTime
(
data
[
indexPropMap
.
time
],
i18n
.
language
),
// 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
'
}
as
const
;
});
const
renderContent
=
(
content
:
string
,
width
:
number
|
[
number
,
number
])
=>
`<div style="overflow: hidden;
${
Array
.
isArray
(
width
)
?
`min-width:
${(
width
as
[
number
,
number
])[
0
]}
;max-width:
${(
width
as
[
number
,
number
])[
1
]}
;`
:
`width:
${
width
as
number
}
px;`
}
">
${
content
}
</div>`
;
let
headerHtml
=
'
<tr style="font-size:14px;">
'
;
headerHtml
+=
(
Object
.
keys
(
transformedData
[
0
])
as
(
keyof
typeof
transformedData
[
0
])[])
.
map
(
key
=>
{
return
`<th style="padding: 0 4px; font-weight: bold;" class="
${
key
}
">
${
renderContent
(
i18n
.
t
(
translatePropMap
[
key
]),
widthPropMap
[
key
]
)}
</th>`
;
})
.
join
(
''
);
headerHtml
+=
'
</tr>
'
;
const
content
=
transformedData
.
map
(
item
=>
{
let
str
=
'
<tr style="font-size:12px;">
'
;
str
+=
Object
.
keys
(
item
)
.
map
(
key
=>
{
let
content
=
''
;
if
(
key
===
'
run
'
)
{
content
+=
`<span class="run-indicator" style="background-color:
${
item
[
key
].
colors
?.[
0
]
??
'
transpanent
'
}
"></span>`
;
content
+=
`<span title="
${
item
[
key
].
label
}
">
${
item
[
key
].
label
}
</span>`
;
}
else
{
content
+=
item
[
key
as
keyof
typeof
item
];
}
return
`<td style="padding: 0 4px;" class="
${
key
}
">
${
renderContent
(
content
,
widthPropMap
[
key
as
keyof
typeof
item
]
)}
</td>`
;
})
.
join
(
''
);
str
+=
'
</tr>
'
;
return
str
;
})
.
join
(
''
);
return
`<table style="text-align: left;table-layout: fixed;"><thead>
${
headerHtml
}
</thead><tbody>
${
content
}
</tbody><table>`
;
};
frontend/packages/core/resource/scalars/data.ts
0 → 100644
浏览文件 @
7bdb74b1
import
BigNumber
from
'
bignumber.js
'
;
import
{
Dataset
}
from
'
./types
'
;
import
{
Run
}
from
'
~/types
'
;
import
cloneDeep
from
'
lodash/cloneDeep
'
;
import
compact
from
'
lodash/compact
'
;
import
maxBy
from
'
lodash/maxBy
'
;
import
minBy
from
'
lodash/minBy
'
;
import
{
quantile
}
from
'
~/utils
'
;
export
const
transform
=
({
datasets
,
smoothing
}:
{
datasets
:
Dataset
[];
smoothing
:
number
})
=>
// https://en.wikipedia.org/wiki/Moving_average
datasets
.
map
(
seriesData
=>
{
const
data
=
cloneDeep
(
seriesData
);
let
last
=
new
BigNumber
(
data
.
length
>
0
?
0
:
Number
.
NaN
);
let
numAccum
=
0
;
let
startValue
=
0
;
const
bigSmoothing
=
new
BigNumber
(
smoothing
);
data
.
forEach
((
d
,
i
)
=>
{
const
nextVal
=
new
BigNumber
(
d
[
2
]);
// second to millisecond.
const
millisecond
=
(
d
[
0
]
=
Math
.
floor
(
d
[
0
]
*
1000
));
if
(
i
===
0
)
{
startValue
=
millisecond
;
}
// relative time, millisecond to hours.
d
[
4
]
=
Math
.
floor
(
millisecond
-
startValue
)
/
(
60
*
60
*
1000
);
if
(
!
nextVal
.
isFinite
())
{
d
[
3
]
=
nextVal
.
toNumber
();
}
else
{
// last = last * smoothing + (1 - smoothing) * nextVal;
last
=
last
.
multipliedBy
(
bigSmoothing
).
plus
(
bigSmoothing
.
minus
(
1
).
negated
().
multipliedBy
(
nextVal
));
numAccum
++
;
let
debiasWeight
=
new
BigNumber
(
1
);
if
(
!
bigSmoothing
.
isEqualTo
(
1
))
{
//debiasWeight = 1.0 - Math.pow(smoothing, numAccum);
debiasWeight
=
bigSmoothing
.
exponentiatedBy
(
numAccum
).
minus
(
1
).
negated
();
}
// d[3] = last / debiasWeight;
d
[
3
]
=
last
.
dividedBy
(
debiasWeight
).
toNumber
();
}
});
return
data
;
});
export
const
singlePointRange
=
(
value
:
number
)
=>
({
min
:
value
?
Math
.
min
(
value
*
2
,
0
)
:
-
0.5
,
max
:
value
?
Math
.
max
(
value
*
2
,
0
)
:
0.5
});
export
const
range
=
({
datasets
,
outlier
}:
{
datasets
:
Dataset
[];
outlier
:
boolean
})
=>
{
const
ranges
=
compact
(
datasets
?.
map
(
dataset
=>
{
if
(
dataset
.
length
==
0
)
return
;
const
values
=
dataset
.
map
(
v
=>
v
[
2
]);
if
(
!
outlier
)
{
// Get the orgin data range.
return
{
min
:
Math
.
min
(...
values
)
??
0
,
max
:
Math
.
max
(...
values
)
??
0
};
}
else
{
// Get the quantile range.
const
sorted
=
dataset
.
map
(
v
=>
v
[
2
]).
sort
();
return
{
min
:
quantile
(
sorted
,
0.05
),
max
:
quantile
(
values
,
0.95
)
};
}
})
);
const
min
=
minBy
(
ranges
,
range
=>
range
.
min
)?.
min
??
0
;
const
max
=
maxBy
(
ranges
,
range
=>
range
.
max
)?.
max
??
0
;
if
(
!
(
min
===
0
&&
max
===
0
))
{
return
{
min
:
min
>
0
?
min
*
0.9
:
min
*
1.1
,
max
:
max
>
0
?
max
*
1.1
:
max
*
0.9
};
}
};
export
const
nearestPoint
=
(
data
:
Dataset
[],
runs
:
Run
[],
step
:
number
)
=>
data
.
map
((
series
,
index
)
=>
{
let
nearestItem
;
if
(
step
===
0
)
{
nearestItem
=
series
[
0
];
}
else
{
for
(
let
i
=
0
;
i
<
series
.
length
;
i
++
)
{
const
item
=
series
[
i
];
if
(
item
[
1
]
===
step
)
{
nearestItem
=
item
;
break
;
}
if
(
item
[
1
]
>
step
)
{
nearestItem
=
series
[
i
-
1
>=
0
?
i
-
1
:
0
];
break
;
}
if
(
!
nearestItem
)
{
nearestItem
=
series
[
series
.
length
-
1
];
}
}
}
return
{
run
:
runs
[
index
],
item
:
nearestItem
||
[]
};
});
frontend/packages/core/resource/scalars/index.ts
浏览文件 @
7bdb74b1
import
*
as
chart
from
'
~/utils/chart
'
;
import
{
ChartDataParams
,
Dataset
,
RangeParams
,
TooltipData
,
TransformParams
}
from
'
./types
'
;
import
{
formatTime
,
quantile
}
from
'
~/utils
'
;
import
BigNumber
from
'
bignumber.js
'
;
import
{
I18n
}
from
'
@visualdl/i18n
'
;
import
{
Run
}
from
'
~/types
'
;
import
cloneDeep
from
'
lodash/cloneDeep
'
;
import
compact
from
'
lodash/compact
'
;
import
maxBy
from
'
lodash/maxBy
'
;
import
minBy
from
'
lodash/minBy
'
;
import
{
TooltipData
}
from
'
./types
'
;
import
sortBy
from
'
lodash/sortBy
'
;
BigNumber
.
config
({
EXPONENTIAL_AT
:
[
-
6
,
7
]});
export
*
from
'
./types
'
;
export
const
xAxis
=
[
'
step
'
,
'
relative
'
,
'
wall
'
]
as
const
;
export
const
xAxisMap
=
{
step
:
1
,
relative
:
4
,
wall
:
0
};
}
as
const
;
export
const
sortingMethod
=
[
'
default
'
,
'
descending
'
,
'
ascending
'
,
'
nearest
'
]
as
const
;
export
const
sortingMethodMap
=
{
default
:
null
,
descending
:
(
points
:
TooltipData
[])
=>
sortBy
(
points
,
point
=>
point
.
item
[
3
]).
reverse
(),
ascending
:
(
points
:
TooltipData
[])
=>
sortBy
(
points
,
point
=>
point
.
item
[
3
]),
// Compare other ponts width the trigger point, caculate the nearest sort.
nearest
:
(
points
:
TooltipData
[],
data
:
number
[])
=>
sortBy
(
points
,
point
=>
point
.
item
[
3
]
-
data
[
2
])
};
export
const
transform
=
({
datasets
,
smoothing
}:
TransformParams
)
=>
// https://en.wikipedia.org/wiki/Moving_average
datasets
.
map
(
seriesData
=>
{
const
data
=
cloneDeep
(
seriesData
);
let
last
=
new
BigNumber
(
data
.
length
>
0
?
0
:
Number
.
NaN
);
let
numAccum
=
0
;
let
startValue
=
0
;
const
bigSmoothing
=
new
BigNumber
(
smoothing
);
data
.
forEach
((
d
,
i
)
=>
{
const
nextVal
=
new
BigNumber
(
d
[
2
]);
// second to millisecond.
const
millisecond
=
(
d
[
0
]
=
Math
.
floor
(
d
[
0
]
*
1000
));
if
(
i
===
0
)
{
startValue
=
millisecond
;
}
// relative time, millisecond to hours.
d
[
4
]
=
Math
.
floor
(
millisecond
-
startValue
)
/
(
60
*
60
*
1000
);
if
(
!
nextVal
.
isFinite
())
{
d
[
3
]
=
nextVal
.
toNumber
();
}
else
{
// last = last * smoothing + (1 - smoothing) * nextVal;
last
=
last
.
multipliedBy
(
bigSmoothing
).
plus
(
bigSmoothing
.
minus
(
1
).
negated
().
multipliedBy
(
nextVal
));
numAccum
++
;
let
debiasWeight
=
new
BigNumber
(
1
);
if
(
!
bigSmoothing
.
isEqualTo
(
1
))
{
//debiasWeight = 1.0 - Math.pow(smoothing, numAccum);
debiasWeight
=
bigSmoothing
.
exponentiatedBy
(
numAccum
).
minus
(
1
).
negated
();
}
// d[3] = last / debiasWeight;
d
[
3
]
=
last
.
dividedBy
(
debiasWeight
).
toNumber
();
}
});
return
data
;
});
export
const
chartData
=
({
data
,
runs
,
smooth
,
xAxis
}:
ChartDataParams
)
=>
data
.
map
((
dataset
,
i
)
=>
{
// smoothed data:
// [0] wall time
// [1] step
// [2] orginal value
// [3] smoothed value
// [4] relative
const
name
=
runs
[
i
].
label
;
const
color
=
runs
[
i
].
colors
[
0
];
const
colorAlt
=
runs
[
i
].
colors
[
1
];
return
[
{
name
,
z
:
i
,
lineStyle
:
{
color
:
colorAlt
,
width
:
chart
.
series
.
lineStyle
.
width
},
data
:
dataset
,
encode
:
{
x
:
[
xAxisMap
[
xAxis
]],
y
:
[
2
]
},
smooth
},
{
name
,
z
:
runs
.
length
+
i
,
itemStyle
:
{
color
},
data
:
dataset
,
encode
:
{
x
:
[
xAxisMap
[
xAxis
]],
y
:
[
3
]
},
smooth
}
];
})
.
flat
();
export
const
singlePointRange
=
(
value
:
number
)
=>
({
min
:
value
?
Math
.
min
(
value
*
2
,
0
)
:
-
0.5
,
max
:
value
?
Math
.
max
(
value
*
2
,
0
)
:
0.5
});
export
const
range
=
({
datasets
,
outlier
}:
RangeParams
)
=>
{
const
ranges
=
compact
(
datasets
?.
map
(
dataset
=>
{
if
(
dataset
.
length
==
0
)
return
;
const
values
=
dataset
.
map
(
v
=>
v
[
2
]);
if
(
!
outlier
)
{
// Get the orgin data range.
return
{
min
:
Math
.
min
(...
values
)
??
0
,
max
:
Math
.
max
(...
values
)
??
0
};
}
else
{
// Get the quantile range.
const
sorted
=
dataset
.
map
(
v
=>
v
[
2
]).
sort
();
return
{
min
:
quantile
(
sorted
,
0.05
),
max
:
quantile
(
values
,
0.95
)
};
}
})
);
}
as
const
;
const
min
=
minBy
(
ranges
,
range
=>
range
.
min
)?.
min
??
0
;
const
max
=
maxBy
(
ranges
,
range
=>
range
.
max
)?.
max
??
0
;
if
(
!
(
min
===
0
&&
max
===
0
))
{
return
{
min
:
min
>
0
?
min
*
0.9
:
min
*
1.1
,
max
:
max
>
0
?
max
*
1.1
:
max
*
0.9
};
}
};
export
const
nearestPoint
=
(
data
:
Dataset
[],
runs
:
Run
[],
step
:
number
)
=>
data
.
map
((
series
,
index
)
=>
{
let
nearestItem
;
if
(
step
===
0
)
{
nearestItem
=
series
[
0
];
}
else
{
for
(
let
i
=
0
;
i
<
series
.
length
;
i
++
)
{
const
item
=
series
[
i
];
if
(
item
[
1
]
===
step
)
{
nearestItem
=
item
;
break
;
}
if
(
item
[
1
]
>
step
)
{
nearestItem
=
series
[
i
-
1
>=
0
?
i
-
1
:
0
];
break
;
}
if
(
!
nearestItem
)
{
nearestItem
=
series
[
series
.
length
-
1
];
}
}
}
return
{
run
:
runs
[
index
],
item
:
nearestItem
||
[]
};
});
// TODO: make it better, don't concat html
export
const
tooltip
=
(
data
:
TooltipData
[],
i18n
:
I18n
)
=>
{
const
indexPropMap
=
{
time
:
0
,
step
:
1
,
value
:
2
,
smoothed
:
3
,
relative
:
4
}
as
const
;
const
widthPropMap
=
{
run
:
[
60
,
180
]
as
[
number
,
number
],
time
:
150
,
step
:
40
,
value
:
60
,
smoothed
:
70
,
relative
:
60
}
as
const
;
const
translatePropMap
=
{
run
:
'
common:runs
'
,
time
:
'
scalars:x-axis-value.wall
'
,
step
:
'
scalars:x-axis-value.step
'
,
value
:
'
scalars:value
'
,
smoothed
:
'
scalars:smoothed
'
,
relative
:
'
scalars:x-axis-value.relative
'
}
as
const
;
const
transformedData
=
data
.
map
(
item
=>
{
const
data
=
item
.
item
;
return
{
run
:
item
.
run
,
// use precision then toString to remove trailling 0
smoothed
:
new
BigNumber
(
data
[
indexPropMap
.
smoothed
]
??
Number
.
NaN
).
precision
(
5
).
toString
(),
value
:
new
BigNumber
(
data
[
indexPropMap
.
value
]
??
Number
.
NaN
).
precision
(
5
).
toString
(),
step
:
data
[
indexPropMap
.
step
],
time
:
formatTime
(
data
[
indexPropMap
.
time
],
i18n
.
language
),
// 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
'
}
as
const
;
});
const
renderContent
=
(
content
:
string
,
width
:
number
|
[
number
,
number
])
=>
`<div style="overflow: hidden;
${
Array
.
isArray
(
width
)
?
`min-width:
${(
width
as
[
number
,
number
])[
0
]}
;max-width:
${(
width
as
[
number
,
number
])[
1
]}
;`
:
`width:
${
width
as
number
}
px;`
}
">
${
content
}
</div>`
;
let
headerHtml
=
'
<tr style="font-size:14px;">
'
;
headerHtml
+=
(
Object
.
keys
(
transformedData
[
0
])
as
(
keyof
typeof
transformedData
[
0
])[])
.
map
(
key
=>
{
return
`<th style="padding: 0 4px; font-weight: bold;" class="
${
key
}
">
${
renderContent
(
i18n
.
t
(
translatePropMap
[
key
]),
widthPropMap
[
key
]
)}
</th>`
;
})
.
join
(
''
);
headerHtml
+=
'
</tr>
'
;
const
content
=
transformedData
.
map
(
item
=>
{
let
str
=
'
<tr style="font-size:12px;">
'
;
str
+=
Object
.
keys
(
item
)
.
map
(
key
=>
{
let
content
=
''
;
if
(
key
===
'
run
'
)
{
content
+=
`<span class="run-indicator" style="background-color:
${
item
[
key
].
colors
?.[
0
]
??
'
transpanent
'
}
"></span>`
;
content
+=
`<span title="
${
item
[
key
].
label
}
">
${
item
[
key
].
label
}
</span>`
;
}
else
{
content
+=
item
[
key
as
keyof
typeof
item
];
}
return
`<td style="padding: 0 4px;" class="
${
key
}
">
${
renderContent
(
content
,
widthPropMap
[
key
as
keyof
typeof
item
]
)}
</td>`
;
})
.
join
(
''
);
str
+=
'
</tr>
'
;
return
str
;
})
.
join
(
''
);
return
`<table style="text-align: left;table-layout: fixed;"><thead>
${
headerHtml
}
</thead><tbody>
${
content
}
</tbody><table>`
;
};
export
*
from
'
./types
'
;
export
*
from
'
./chart
'
;
export
*
from
'
./data
'
;
frontend/packages/core/resource/scalars/types.ts
浏览文件 @
7bdb74b1
import
{
sortingMethodMap
,
xAxisMap
}
from
'
./index
'
;
import
{
Run
}
from
'
~/types
'
;
import
{
xAxisMap
}
from
'
./index
'
;
export
type
Dataset
=
number
[][];
export
type
XAxis
=
keyof
typeof
xAxisMap
;
export
type
SortingMethod
=
keyof
typeof
sortingMethodMap
;
export
type
Range
=
{
min
:
number
;
max
:
number
;
...
...
@@ -12,20 +16,3 @@ export type TooltipData = {
run
:
Run
;
item
:
number
[];
};
export
type
TransformParams
=
{
datasets
:
Dataset
[];
smoothing
:
number
;
};
export
type
ChartDataParams
=
{
data
:
Dataset
[];
runs
:
Run
[];
smooth
:
boolean
;
xAxis
:
keyof
typeof
xAxisMap
;
};
export
type
RangeParams
=
{
datasets
:
Dataset
[];
outlier
:
boolean
;
};
frontend/packages/core/tsconfig.json
浏览文件 @
7bdb74b1
...
...
@@ -7,7 +7,8 @@
"lib"
:
[
"esnext"
,
"esnext.asynciterable"
,
"dom"
"dom"
,
"webworker"
],
"esModuleInterop"
:
true
,
"allowJs"
:
true
,
...
...
frontend/packages/core/types/index.d.ts
浏览文件 @
7bdb74b1
...
...
@@ -7,3 +7,8 @@ export interface Tag {
runs
:
Run
[];
label
:
string
;
}
export
interface
TagWithSingleRun
{
label
:
string
;
run
:
Run
;
}
frontend/packages/core/utils/chart.ts
浏览文件 @
7bdb74b1
import
{
format
}
from
'
d3-format
'
;
import
{
primaryColor
}
from
'
~/utils/style
'
;
export
const
color
=
[
'
#2932E1
'
,
'
#00CC88
'
,
...
...
@@ -50,14 +53,14 @@ export const title = {
export
const
tooltip
=
{
trigger
:
'
axis
'
,
position
:
[
'
10%
'
,
'
100%
'
],
backgroundColor
:
'
rgba(0, 0, 0, 0.75)
'
,
hideDelay
:
100
,
enterable
:
false
,
axisPointer
:
{
type
:
'
cross
'
,
label
:
{
show
:
true
show
:
true
,
formatter
:
({
value
}:
{
value
:
number
})
=>
format
(
'
.4
'
)(
value
)
},
lineStyle
:
{
color
:
'
#2932E1
'
,
...
...
@@ -101,7 +104,7 @@ export const legend = {
};
export
const
grid
=
{
left
:
5
0
,
left
:
6
0
,
top
:
60
,
right
:
30
,
bottom
:
30
...
...
@@ -124,7 +127,8 @@ export const xAxis = {
},
axisLabel
:
{
fontSize
:
12
,
color
:
'
#666
'
color
:
'
#666
'
,
formatter
:
format
(
'
.4
'
)
},
splitLine
:
{
show
:
false
...
...
@@ -147,7 +151,7 @@ export const yAxis = {
axisLabel
:
{
fontSize
:
12
,
color
:
'
#666
'
,
formatter
:
(
v
:
number
)
=>
(
v
<
0.0001
?
v
.
toExponential
(
1
)
:
Number
.
parseFloat
(
v
.
toFixed
(
4
))
)
formatter
:
format
(
'
.4
'
)
},
splitLine
:
{
lineStyle
:
{
...
...
@@ -157,10 +161,10 @@ export const yAxis = {
};
export
const
series
=
{
type
:
'
line
'
,
hoverAnimation
:
false
,
animationDuration
:
100
,
lineStyle
:
{
color
:
primaryColor
,
width
:
1.5
}
};
frontend/packages/core/utils/index.ts
浏览文件 @
7bdb74b1
...
...
@@ -19,6 +19,5 @@ export const quantile = (values: number[], p: number) => {
const
i0
=
i
.
integerValue
().
toNumber
();
const
value0
=
new
BigNumber
(
values
[
i0
]);
const
value1
=
new
BigNumber
(
values
[
i0
+
1
]);
// return value0 + (value1 - value0) * (i - i0);
return
value0
.
plus
(
value1
.
minus
(
value0
).
multipliedBy
(
i
.
minus
(
i0
))).
toNumber
();
};
frontend/packages/core/utils/worker.ts
0 → 100644
浏览文件 @
7bdb74b1
export
default
<
P
=
unknown
,
R
=
unknown
>
(
handler
:
(
data
:
P
)
=>
R
):
void
=>
self
.
addEventListener
(
'
message
'
,
({
data
}:
MessageEvent
&
{
data
:
P
})
=>
{
self
.
postMessage
(
handler
(
data
));
});
frontend/packages/core/worker/high-dimensional/divide.worker.ts
浏览文件 @
7bdb74b1
import
{
DivideParams
,
divide
}
from
'
~/resource/high-dimensional
'
;
import
{
divide
}
from
'
~/resource/high-dimensional
'
;
import
worker
from
'
~/utils/worker
'
;
import
{
exposeWorker
}
from
'
react-hooks-worker
'
;
// exposeWorker can only handle Promise
exposeWorker
((
data
:
DivideParams
)
=>
Promise
.
resolve
(
divide
(
data
)));
worker
(
divide
);
frontend/packages/core/worker/histogram/transform.worker.ts
0 → 100644
浏览文件 @
7bdb74b1
import
{
transform
}
from
'
~/resource/histogram
'
;
import
worker
from
'
~/utils/worker
'
;
worker
(
transform
);
frontend/packages/core/worker/scalars/range.worker.ts
浏览文件 @
7bdb74b1
import
{
RangeParams
,
range
}
from
'
~/resource/scalars
'
;
import
{
range
}
from
'
~/resource/scalars
'
;
import
worker
from
'
~/utils/worker
'
;
import
{
exposeWorker
}
from
'
react-hooks-worker
'
;
// exposeWorker can only handle Promise
exposeWorker
((
data
:
RangeParams
)
=>
Promise
.
resolve
(
range
(
data
)));
worker
(
range
);
frontend/packages/core/worker/scalars/smooth.worker.ts
浏览文件 @
7bdb74b1
import
{
TransformParams
,
transform
}
from
'
~/resource/scalars
'
;
import
{
transform
}
from
'
~/resource/scalars
'
;
import
worker
from
'
~/utils/worker
'
;
import
{
exposeWorker
}
from
'
react-hooks-worker
'
;
// exposeWorker can only handle Promise
exposeWorker
((
data
:
TransformParams
)
=>
Promise
.
resolve
(
transform
(
data
)));
worker
(
transform
);
frontend/packages/mock/data/components.ts
浏览文件 @
7bdb74b1
export
default
[
'
embeddings
'
,
'
scalar
'
,
'
image
'
,
'
graph
'
];
export
default
[
'
embeddings
'
,
'
scalar
'
,
'
image
'
,
'
graph
'
,
'
histogram
'
];
frontend/packages/mock/data/histogram/list.ts
0 → 100644
浏览文件 @
7bdb74b1
export
default
[
[
1515224840.945252
,
0
,
[
[
-
4.826786994934082
,
-
5.099814079160488
,
0.0
],
[
-
5.099814079160488
,
-
4.636194617418625
,
1.0
],
[
-
3.8315657995195243
,
-
3.48324163592684
,
125.0
],
[
-
3.48324163592684
,
-
3.1665833053880363
,
436.0
],
[
-
2.6170109961884593
,
-
2.379100905625872
,
5362.0
],
[
-
2.379100905625872
,
-
2.1628190051144287
,
9589.0
],
[
-
1.47723448201245
,
-
1.3429404381931362
,
54279.0
],
[
-
1.3429404381931362
,
-
1.220854943811942
,
64480.0
],
[
-
1.0089710279437536
,
-
0.917246389039776
,
89844.0
],
[
-
0.917246389039776
,
-
0.8338603536725235
,
93854.0
],
[
-
0.8338603536725235
,
-
0.7580548669750213
,
96552.0
],
[
-
0.7580548669750213
,
-
0.6891407881591103
,
96980.0
],
[
-
0.6891407881591103
,
-
0.6264916255991911
,
97035.0
],
[
-
0.6264916255991911
,
-
0.56953784145381
,
94798.0
],
[
-
1.316866795643118
e
-
5
,
-
1.1971516324028345
e
-
5
,
8.0
],
[
-
1.1971516324028345
e
-
5
,
-
1.0883196658207586
e
-
5
,
1.0
],
[
-
1.0883196658207586
e
-
5
,
-
9.893815143825077
e
-
6
,
1.0
],
[
-
9.893815143825077
e
-
6
,
-
8.994377403477343
e
-
6
,
2.0
],
[
-
8.994377403477343
e
-
6
,
-
8.176706730433948
e
-
6
,
2.0
],
[
-
8.176706730433948
e
-
6
,
-
7.4333697549399525
e
-
6
,
2.0
],
[
-
7.4333697549399525
e
-
6
,
-
6.757608868127229
e
-
6
,
1.0
],
[
-
6.757608868127229
e
-
6
,
-
6.143280789206572
e
-
6
,
4.0
],
[
-
6.143280789206572
e
-
6
,
-
5.077091561327744
e
-
6
,
0.0
],
[
-
5.077091561327744
e
-
6
,
-
4.615537783025222
e
-
6
,
1.0
],
[
-
4.615537783025222
e
-
6
,
-
4.1959434391138375
e
-
6
,
0.0
],
[
-
4.1959434391138375
e
-
6
,
-
3.8144940355580335
e
-
6
,
2.0
],
[
-
3.8144940355580335
e
-
6
,
-
3.467721850507303
e
-
6
,
1.0
],
[
-
3.467721850507303
e
-
6
,
-
2.865885826865539
e
-
6
,
0.0
],
[
-
2.865885826865539
e
-
6
,
-
2.605350751695944
e
-
6
,
1.0
],
[
-
2.605350751695944
e
-
6
,
-
2.153182439418135
e
-
6
,
0.0
],
[
-
1.2154153537011338
e
-
6
,
-
1.1049230488192125
e
-
6
,
1.0
],
[
-
1.1049230488192125
e
-
6
,
-
5.670002325218022
e
-
7
,
0.0
],
[
2.5662008430919505
e
-
5
,
2.822820927401146
e
-
5
,
8.0
],
[
2.822820927401146
e
-
5
,
3.1051030201412604
e
-
5
,
4.0
],
[
3.1051030201412604
e
-
5
,
3.415613322155387
e
-
5
,
4.0
],
[
3.415613322155387
e
-
5
,
3.757174654370926
e
-
5
,
6.0
],
[
3.757174654370926
e
-
5
,
4.132892119808019
e
-
5
,
7.0
],
[
4.132892119808019
e
-
5
,
4.546181331788821
e
-
5
,
8.0
],
[
4.546181331788821
e
-
5
,
5.000799464967703
e
-
5
,
19.0
],
[
5.000799464967703
e
-
5
,
5.500879411464474
e
-
5
,
18.0
],
[
5.500879411464474
e
-
5
,
6.050967352610922
e
-
5
,
10.0
],
[
6.050967352610922
e
-
5
,
6.656064087872014
e
-
5
,
12.0
],
[
6.656064087872014
e
-
5
,
7.321670496659217
e
-
5
,
13.0
],
[
7.321670496659217
e
-
5
,
8.053837546325138
e
-
5
,
14.0
],
[
8.053837546325138
e
-
5
,
8.859221300957652
e
-
5
,
18.0
],
[
8.859221300957652
e
-
5
,
9.745143431053419
e
-
5
,
22.0
],
[
9.745143431053419
e
-
5
,
0.00010719657774158762
,
23.0
],
[
0.00010719657774158762
,
0.00011791623551574639
,
34.0
],
[
0.917246389039776
,
1.0089710279437536
,
124200.0
],
[
1.0089710279437536
,
1.109868130738129
,
119511.0
],
[
1.109868130738129
,
1.220854943811942
,
111589.0
],
[
1.220854943811942
,
1.3429404381931362
,
101296.0
],
[
2.8787120958073054
,
3.1665833053880363
,
3382.0
],
[
3.1665833053880363
,
3.48324163592684
,
1351.0
],
[
3.48324163592684
,
3.8315657995195243
,
468.0
],
[
3.8315657995195243
,
4.214722379471477
,
105.0
]
]
],
[
1515224846.83122
,
70
,
[
[
-
5.609264373779297
,
-
5.609795487076537
,
0.0
],
[
-
5.609795487076537
,
-
5.099814079160488
,
5.0
],
[
-
5.099814079160488
,
-
4.636194617418625
,
26.0
],
[
-
4.636194617418625
,
-
4.214722379471477
,
114.0
],
[
-
4.214722379471477
,
-
3.8315657995195243
,
379.0
],
[
-
3.8315657995195243
,
-
3.48324163592684
,
1072.0
],
[
-
3.48324163592684
,
-
3.1665833053880363
,
2542.0
],
[
-
3.1665833053880363
,
-
2.8787120958073054
,
5260.0
],
[
-
2.8787120958073054
,
-
2.6170109961884593
,
9568.0
],
[
-
2.6170109961884593
,
-
2.379100905625872
,
15632.0
],
[
-
2.379100905625872
,
-
2.1628190051144287
,
23154.0
],
[
-
2.1628190051144287
,
-
1.9661990955585713
,
31489.0
],
[
-
1.9661990955585713
,
-
1.7874537232350647
,
41367.0
],
[
-
1.7874537232350647
,
-
1.624957930213695
,
50809.0
],
[
-
0.052566063576589855
,
-
0.04778733052417259
,
10183.0
],
[
-
0.04778733052417259
,
-
0.043443027749247805
,
9196.0
],
[
-
0.01143990698806325
,
-
0.010399915443693864
,
2264.0
],
[
-
0.010399915443693864
,
-
0.00945446858517624
,
2012.0
],
[
0.0007211649713244094
,
0.0007932814684568504
,
152.0
],
[
0.0007932814684568504
,
0.0008726096153025355
,
168.0
],
[
0.0008726096153025355
,
0.0009598705768327891
,
179.0
],
[
0.0009598705768327891
,
0.001055857634516068
,
198.0
],
[
0.47069243095356195
,
0.5177616740489182
,
96395.0
],
[
0.5177616740489182
,
0.56953784145381
,
103088.0
],
[
0.56953784145381
,
0.6264916255991911
,
110245.0
],
[
0.6264916255991911
,
0.6891407881591103
,
116777.0
],
[
0.6891407881591103
,
0.7580548669750213
,
123501.0
],
[
0.7580548669750213
,
0.8338603536725235
,
127806.0
],
[
0.8338603536725235
,
0.917246389039776
,
132276.0
],
[
0.917246389039776
,
1.0089710279437536
,
134169.0
],
[
1.0089710279437536
,
1.109868130738129
,
133209.0
],
[
1.109868130738129
,
1.220854943811942
,
129736.0
],
[
2.6170109961884593
,
2.8787120958073054
,
14814.0
],
[
2.8787120958073054
,
3.1665833053880363
,
8284.0
],
[
3.8315657995195243
,
4.214722379471477
,
699.0
],
[
4.214722379471477
,
4.636194617418625
,
245.0
],
[
4.636194617418625
,
5.099814079160488
,
64.0
],
[
5.099814079160488
,
5.609795487076537
,
22.0
],
[
5.609795487076537
,
6.1707750357841915
,
2.0
],
[
6.1707750357841915
,
6.077327728271484
,
0.0
]
]
],
[
1515224850.414384
,
100
,
[
[
-
5.622415065765381
,
-
6.1707750357841915
,
0.0
],
[
-
6.1707750357841915
,
-
5.609795487076537
,
1.0
],
[
-
4.636194617418625
,
-
4.214722379471477
,
130.0
],
[
-
4.214722379471477
,
-
3.8315657995195243
,
364.0
],
[
-
3.8315657995195243
,
-
3.48324163592684
,
1063.0
],
[
-
3.48324163592684
,
-
3.1665833053880363
,
2440.0
],
[
-
2.6170109961884593
,
-
2.379100905625872
,
15079.0
],
[
-
2.379100905625872
,
-
2.1628190051144287
,
22447.0
],
[
-
1.0089710279437536
,
-
0.917246389039776
,
89632.0
],
[
-
0.917246389039776
,
-
0.8338603536725235
,
91513.0
],
[
-
0.8338603536725235
,
-
0.7580548669750213
,
91158.0
],
[
-
0.7580548669750213
,
-
0.6891407881591103
,
89568.0
],
[
-
0.6891407881591103
,
-
0.6264916255991911
,
88244.0
],
[
-
0.6264916255991911
,
-
0.56953784145381
,
84929.0
],
[
-
4.757441129747921
e
-
8
,
5.15454756838002
e
-
7
,
0.0
],
[
5.15454756838002
e
-
7
,
5.670002325218022
e
-
7
,
1.0
],
[
5.670002325218022
e
-
7
,
6.237002557739824
e
-
7
,
0.0
],
[
6.237002557739824
e
-
7
,
6.860702813513807
e
-
7
,
1.0
],
[
6.860702813513807
e
-
7
,
8.301450404351707
e
-
7
,
0.0
],
[
8.301450404351707
e
-
7
,
9.131595444786879
e
-
7
,
1.0
],
[
9.131595444786879
e
-
7
,
1.0044754989265568
e
-
6
,
1.0
],
[
1.0044754989265568
e
-
6
,
1.6177178357762093
e
-
6
,
0.0
],
[
6.757608868127229
e
-
6
,
7.4333697549399525
e
-
6
,
1.0
],
[
7.4333697549399525
e
-
6
,
8.176706730433948
e
-
6
,
2.0
],
[
8.176706730433948
e
-
6
,
8.994377403477343
e
-
6
,
1.0
],
[
8.994377403477343
e
-
6
,
9.893815143825077
e
-
6
,
0.0
],
[
9.893815143825077
e
-
6
,
1.0883196658207586
e
-
5
,
3.0
],
[
1.0883196658207586
e
-
5
,
1.1971516324028345
e
-
5
,
2.0
],
[
1.1971516324028345
e
-
5
,
1.316866795643118
e
-
5
,
3.0
],
[
1.316866795643118
e
-
5
,
1.44855347520743
e
-
5
,
4.0
],
[
3.757174654370926
e
-
5
,
4.132892119808019
e
-
5
,
8.0
],
[
4.132892119808019
e
-
5
,
4.546181331788821
e
-
5
,
8.0
],
[
4.546181331788821
e
-
5
,
5.000799464967703
e
-
5
,
7.0
],
[
5.000799464967703
e
-
5
,
5.500879411464474
e
-
5
,
10.0
],
[
5.500879411464474
e
-
5
,
6.050967352610922
e
-
5
,
13.0
],
[
6.050967352610922
e
-
5
,
6.656064087872014
e
-
5
,
11.0
],
[
6.656064087872014
e
-
5
,
7.321670496659217
e
-
5
,
15.0
],
[
7.321670496659217
e
-
5
,
8.053837546325138
e
-
5
,
16.0
],
[
8.053837546325138
e
-
5
,
8.859221300957652
e
-
5
,
27.0
],
[
8.859221300957652
e
-
5
,
9.745143431053419
e
-
5
,
17.0
],
[
0.8338603536725235
,
0.917246389039776
,
130481.0
],
[
0.917246389039776
,
1.0089710279437536
,
133238.0
],
[
1.0089710279437536
,
1.109868130738129
,
131855.0
],
[
1.109868130738129
,
1.220854943811942
,
129006.0
],
[
2.6170109961884593
,
2.8787120958073054
,
14697.0
],
[
2.8787120958073054
,
3.1665833053880363
,
8234.0
],
[
3.1665833053880363
,
3.48324163592684
,
4187.0
],
[
3.48324163592684
,
3.8315657995195243
,
1800.0
],
[
4.636194617418625
,
5.099814079160488
,
67.0
],
[
5.099814079160488
,
5.609795487076537
,
22.0
],
[
5.609795487076537
,
6.1707750357841915
,
3.0
],
[
6.1707750357841915
,
6.0968852043151855
,
0.0
]
]
],
[
1515224852.17382
,
120
,
[
[
-
5.641714572906494
,
-
6.1707750357841915
,
0.0
],
[
-
6.1707750357841915
,
-
5.609795487076537
,
1.0
],
[
-
5.609795487076537
,
-
5.099814079160488
,
8.0
],
[
-
5.099814079160488
,
-
4.636194617418625
,
23.0
],
[
-
4.636194617418625
,
-
4.214722379471477
,
134.0
],
[
-
4.214722379471477
,
-
3.8315657995195243
,
325.0
],
[
-
3.8315657995195243
,
-
3.48324163592684
,
980.0
],
[
-
3.48324163592684
,
-
3.1665833053880363
,
2241.0
],
[
-
3.1665833053880363
,
-
2.8787120958073054
,
4732.0
],
[
-
2.8787120958073054
,
-
2.6170109961884593
,
8511.0
],
[
-
2.6170109961884593
,
-
2.379100905625872
,
14412.0
],
[
-
2.379100905625872
,
-
2.1628190051144287
,
21324.0
],
[
-
2.1628190051144287
,
-
1.9661990955585713
,
30265.0
],
[
-
1.9661990955585713
,
-
1.7874537232350647
,
39939.0
],
[
-
1.7874537232350647
,
-
1.624957930213695
,
49754.0
],
[
-
1.624957930213695
,
-
1.47723448201245
,
59029.0
],
[
-
1.47723448201245
,
-
1.3429404381931362
,
67624.0
],
[
-
1.3429404381931362
,
-
1.220854943811942
,
75809.0
],
[
-
1.220854943811942
,
-
1.109868130738129
,
82164.0
],
[
-
1.109868130738129
,
-
1.0089710279437536
,
86962.0
],
[
-
1.0089710279437536
,
-
0.917246389039776
,
90354.0
],
[
-
0.917246389039776
,
-
0.8338603536725235
,
91382.0
],
[
-
0.8338603536725235
,
-
0.7580548669750213
,
91667.0
],
[
-
0.7580548669750213
,
-
0.6891407881591103
,
90086.0
],
[
-
0.6891407881591103
,
-
0.6264916255991911
,
88401.0
],
[
-
0.6264916255991911
,
-
0.56953784145381
,
85407.0
],
[
3.1051030201412604
e
-
5
,
3.415613322155387
e
-
5
,
8.0
],
[
8.053837546325138
e
-
5
,
8.859221300957652
e
-
5
,
11.0
],
[
0.012583897686869577
,
0.013842287455556535
,
2645.0
],
[
0.013842287455556535
,
0.01522651620111219
,
3037.0
],
[
0.01522651620111219
,
0.01674916782122341
,
3297.0
],
[
0.01674916782122341
,
0.018424084603345752
,
3686.0
],
[
0.018424084603345752
,
0.02026649306368033
,
3954.0
],
[
0.02026649306368033
,
0.022293142370048362
,
4388.0
],
[
0.022293142370048362
,
0.0245224566070532
,
4888.0
],
[
0.0245224566070532
,
0.026974702267758523
,
5350.0
],
[
0.026974702267758523
,
0.02967217249453438
,
5800.0
],
[
0.02967217249453438
,
0.03263938974398782
,
6459.0
],
[
0.03263938974398782
,
0.035903328718386605
,
7217.0
],
[
0.035903328718386605
,
0.03949366159022527
,
7816.0
],
[
0.03949366159022527
,
0.043443027749247805
,
8647.0
],
[
0.043443027749247805
,
0.04778733052417259
,
9398.0
],
[
0.04778733052417259
,
0.052566063576589855
,
10457.0
],
[
0.052566063576589855
,
0.057822669934248845
,
11420.0
],
[
0.057822669934248845
,
0.06360493692767373
,
12728.0
],
[
0.06360493692767373
,
0.06996543062044111
,
13975.0
],
[
0.06996543062044111
,
0.07696197368248522
,
15413.0
],
[
0.07696197368248522
,
0.08465817105073375
,
17143.0
],
[
0.08465817105073375
,
0.09312398815580714
,
19025.0
],
[
0.09312398815580714
,
0.10243638697138786
,
20509.0
],
[
0.10243638697138786
,
0.11268002566852665
,
22060.0
],
[
0.11268002566852665
,
0.12394802823537933
,
24938.0
],
[
0.12394802823537933
,
0.13634283105891729
,
27263.0
],
[
1.7874537232350647
,
1.9661990955585713
,
68215.0
],
[
1.9661990955585713
,
2.1628190051144287
,
51944.0
],
[
2.1628190051144287
,
2.379100905625872
,
36899.0
],
[
2.379100905625872
,
2.6170109961884593
,
23872.0
],
[
4.636194617418625
,
5.099814079160488
,
68.0
],
[
5.099814079160488
,
5.609795487076537
,
22.0
],
[
5.609795487076537
,
6.1707750357841915
,
3.0
],
[
6.1707750357841915
,
6.084466934204102
,
0.0
]
]
]
];
frontend/packages/mock/data/histogram/tags.ts
0 → 100644
浏览文件 @
7bdb74b1
export
default
{
test
:
[
'
layer2/biases/summaries/mean
'
],
train
:
[
'
layer2/biases/summaries/mean
'
,
'
layer2/biases/summaries/accuracy
'
,
'
layer2/biases/summaries/cost
'
]
};
frontend/packages/wasm/src/high_dimensional.rs
0 → 100644
浏览文件 @
7bdb74b1
#[derive(Serialize,
Deserialize)]
pub
struct
Point
{
name
:
String
,
value
:
Vec
<
f64
>
,
showing
:
bool
,
}
impl
Point
{
pub
fn
new
(
name
:
String
,
value
:
Vec
<
f64
>
,
showing
:
bool
)
->
Self
{
Point
{
name
,
value
,
showing
,
}
}
}
#[derive(Serialize,
Deserialize)]
pub
struct
DividedPoints
(
Vec
<
Point
>
,
Vec
<
Point
>
);
impl
DividedPoints
{
pub
fn
new
(
matched
:
Vec
<
Point
>
,
missing
:
Vec
<
Point
>
)
->
Self
{
DividedPoints
(
matched
,
missing
)
}
}
pub
fn
divide
(
points
:
Vec
<
Vec
<
f64
>>
,
labels
:
Vec
<
String
>
,
visibility
:
bool
,
keyword
:
String
,
)
->
DividedPoints
{
let
mut
matched
:
Vec
<
Point
>
=
vec!
[];
let
mut
missing
:
Vec
<
Point
>
=
vec!
[];
for
(
i
,
point
)
in
points
.iter
()
.enumerate
()
{
let
mut
name
:
String
=
String
::
from
(
""
);
let
ptr
:
*
const
String
=
&
labels
[
i
];
if
!
ptr
.is_null
()
{
name
=
labels
[
i
]
.clone
();
}
let
point_with_label
:
Point
=
Point
::
new
(
name
.clone
(),
point
.to_vec
(),
visibility
);
if
keyword
==
String
::
from
(
""
)
{
missing
.push
(
point_with_label
);
}
else
{
if
name
.contains
(
&
keyword
)
{
matched
.push
(
point_with_label
);
}
else
{
missing
.push
(
point_with_label
);
}
}
}
return
DividedPoints
::
new
(
matched
,
missing
);
}
frontend/packages/wasm/src/histogram.rs
0 → 100644
浏览文件 @
7bdb74b1
use
std
::
f64
;
trait
FloatIterExt
{
fn
float_min
(
&
mut
self
)
->
f64
;
fn
float_max
(
&
mut
self
)
->
f64
;
}
impl
<
T
>
FloatIterExt
for
T
where
T
:
Iterator
<
Item
=
f64
>
,
{
fn
float_max
(
&
mut
self
)
->
f64
{
self
.fold
(
f64
::
NAN
,
f64
::
max
)
}
fn
float_min
(
&
mut
self
)
->
f64
{
self
.fold
(
f64
::
NAN
,
f64
::
min
)
}
}
struct
Histogram
{
left
:
f64
,
right
:
f64
,
count
:
f64
,
}
struct
Coordinates
{
x
:
f64
,
dx
:
f64
,
y
:
f64
,
}
impl
Coordinates
{
pub
fn
new
(
x
:
f64
,
dx
:
f64
,
y
:
f64
)
->
Self
{
Coordinates
{
x
,
dx
,
y
}
}
}
#[derive(Serialize,
Deserialize)]
struct
Item
(
f64
,
f64
,
f64
);
#[derive(Serialize,
Deserialize)]
pub
struct
Data
(
f64
,
f64
,
Vec
<
Item
>
);
#[derive(Serialize,
Deserialize)]
struct
OverlayItem
(
f64
,
f64
,
f64
,
f64
);
#[derive(Serialize,
Deserialize)]
pub
struct
Overlay
{
min
:
f64
,
max
:
f64
,
data
:
Vec
<
Vec
<
OverlayItem
>>
,
}
#[allow(non_snake_case)]
#[derive(Serialize,
Deserialize)]
pub
struct
Offset
{
minX
:
f64
,
maxX
:
f64
,
minZ
:
f64
,
maxZ
:
f64
,
minStep
:
f64
,
maxStep
:
f64
,
data
:
Vec
<
Vec
<
f64
>>
,
}
fn
compute_histogram
(
data
:
&
Vec
<
Histogram
>
,
mut
min
:
f64
,
mut
max
:
f64
,
bins_num
:
i64
,
)
->
Vec
<
Coordinates
>
{
if
min
==
max
{
max
=
min
*
1.1
+
1
.
;
min
=
min
/
1.1
-
1
.
;
}
let
step_width
:
f64
=
(
max
-
min
)
/
bins_num
as
f64
;
let
mut
range
:
Vec
<
f64
>
=
vec!
[];
let
mut
optional
=
Some
(
min
);
while
let
Some
(
i
)
=
optional
{
if
i
>
max
{
optional
=
None
;
}
else
{
range
.push
(
i
);
optional
=
Some
(
i
+
step_width
);
}
}
let
mut
item_index
:
usize
=
0
;
let
mut
result
:
Vec
<
Coordinates
>
=
vec!
[];
for
bin_left
in
range
{
let
bin_right
:
f64
=
bin_left
+
step_width
;
let
mut
y
:
f64
=
1
.
;
let
n
:
usize
=
data
.len
();
while
item_index
<
n
{
let
item_right
:
f64
=
max
.min
(
data
[
item_index
]
.right
);
let
item_left
:
f64
=
min
.max
(
data
[
item_index
]
.left
);
let
overlap
:
f64
=
item_right
.min
(
bin_right
)
-
item_left
.max
(
bin_left
);
let
count
:
f64
=
(
overlap
/
(
item_right
-
item_left
))
*
data
[
item_index
]
.count
;
if
overlap
>
0
.
{
y
+=
count
;
}
if
item_right
>
bin_right
{
break
;
}
item_index
+=
1
;
}
result
.push
(
Coordinates
::
new
(
bin_left
,
step_width
,
y
));
}
return
result
;
}
pub
fn
transform_overlay
(
data
:
Vec
<
Data
>
)
->
Overlay
{
struct
Temp
{
time
:
f64
,
step
:
f64
,
min
:
f64
,
max
:
f64
,
}
let
mut
temp
:
Vec
<
Temp
>
=
vec!
[];
let
mut
items
:
Vec
<
Vec
<
Histogram
>>
=
vec!
[];
for
item
in
data
{
temp
.push
(
Temp
{
time
:
item
.0
,
step
:
item
.1
,
min
:
item
.2
.iter
()
.map
(|
x
|
x
.0
)
.float_min
(),
max
:
item
.2
.iter
()
.map
(|
x
|
x
.1
)
.float_max
(),
});
items
.push
(
item
.2
.iter
()
.map
(|
x
|
Histogram
{
left
:
x
.0
,
right
:
x
.1
,
count
:
x
.2
,
})
.collect
(),
);
}
let
min
:
f64
=
temp
.iter
()
.map
(|
x
|
x
.min
)
.float_min
();
let
max
:
f64
=
temp
.iter
()
.map
(|
x
|
x
.max
)
.float_max
();
let
mut
overlay
:
Vec
<
Vec
<
OverlayItem
>>
=
vec!
[];
for
(
i
,
item
)
in
temp
.iter
()
.enumerate
()
{
let
computed
:
Vec
<
Coordinates
>
=
compute_histogram
(
&
items
[
i
],
min
,
max
,
30
);
overlay
.push
(
computed
.iter
()
.map
(|
x
|
OverlayItem
(
item
.time
,
item
.step
,
x
.x
+
x
.dx
/
2.0_f64
,
x
.y
.floor
()))
.collect
(),
);
}
return
Overlay
{
min
,
max
,
data
:
overlay
,
};
}
pub
fn
transform_offset
(
data
:
Vec
<
Data
>
)
->
Offset
{
let
overlay
:
Overlay
=
transform_overlay
(
data
);
let
mut
min_step
:
f64
=
std
::
f64
::
INFINITY
;
let
mut
max_step
:
f64
=
std
::
f64
::
NEG_INFINITY
;
let
mut
min_z
:
f64
=
std
::
f64
::
INFINITY
;
let
mut
max_z
:
f64
=
std
::
f64
::
NEG_INFINITY
;
let
mut
offset
:
Vec
<
Vec
<
f64
>>
=
vec!
[];
for
items
in
overlay
.data
{
let
step
:
f64
=
items
[
0
]
.1
;
if
step
>
max_step
{
max_step
=
step
;
}
if
step
<
min_step
{
min_step
=
step
;
}
let
mut
res
:
Vec
<
f64
>
=
vec!
[];
for
item
in
items
{
let
x
:
f64
=
item
.2
;
let
y
:
f64
=
item
.3
;
if
y
>
max_z
{
max_z
=
y
;
}
if
y
<
min_z
{
min_z
=
y
;
}
res
.push
(
x
);
res
.push
(
step
);
res
.push
(
y
);
}
offset
.push
(
res
);
}
return
Offset
{
minX
:
overlay
.min
,
maxX
:
overlay
.max
,
minZ
:
min_z
,
maxZ
:
max_z
,
minStep
:
min_step
,
maxStep
:
max_step
,
data
:
offset
,
};
}
frontend/packages/wasm/src/main.rs
浏览文件 @
7bdb74b1
mod
utils
;
use
wasm_bindgen
::
prelude
::
*
;
mod
high_dimensional
;
mod
histogram
;
mod
scalar
;
mod
utils
;
#[macro_use]
extern
crate
serde_derive
;
pub
fn
main
()
{}
#[derive(Serialize,
Deserialize)]
struct
Dataset
(
f64
,
i64
,
f64
);
#[derive(Serialize,
Deserialize)]
struct
Smoothed
(
i64
,
i64
,
f64
,
f64
,
f64
);
#[wasm_bindgen]
pub
fn
transform
(
js_datasets
:
&
JsValue
,
smoothing
:
f64
)
->
JsValue
{
pub
fn
scalar_
transform
(
js_datasets
:
&
JsValue
,
smoothing
:
f64
)
->
JsValue
{
utils
::
set_panic_hook
();
let
datasets
:
Vec
<
Vec
<
Dataset
>>
=
js_datasets
.into_serde
()
.unwrap
();
let
mut
result
:
Vec
<
Vec
<
Smoothed
>>
=
vec!
[];
for
dataset
in
datasets
.iter
()
{
let
mut
row
:
Vec
<
Smoothed
>
=
vec!
[];
let
mut
last
:
f64
=
std
::
f64
::
NAN
;
if
dataset
.len
()
>
0
{
last
=
0_f64
;
}
let
mut
num_accum
:
i32
=
0
;
let
mut
start_value
:
i64
=
0
;
for
(
i
,
d
)
in
dataset
.iter
()
.enumerate
()
{
let
mut
r
:
Smoothed
=
Smoothed
(
0
,
d
.1
,
d
.2
,
0.0
,
0.0
);
let
next_val
:
f64
=
d
.2
;
// second to millisecond.
let
millisecond
:
i64
=
((
d
.0
as
f64
)
*
1000_f64
)
.floor
()
as
i64
;
r
.0
=
millisecond
;
if
i
==
0
{
start_value
=
millisecond
;
}
// Relative time, millisecond to hours.
r
.4
=
((
millisecond
-
start_value
)
as
f64
)
/
(
60
*
60
*
1000
)
as
f64
;
if
next_val
.is_infinite
()
{
r
.3
=
next_val
;
}
else
{
last
=
last
*
smoothing
+
(
1.0
-
smoothing
)
*
next_val
;
num_accum
+=
1
;
let
mut
debias_weight
:
f64
=
1.0_f64
;
if
smoothing
!=
1.0
{
debias_weight
=
(
1.0_f64
-
smoothing
.powi
(
num_accum
))
.into
();
}
r
.3
=
last
/
debias_weight
;
}
row
.push
(
r
);
}
result
.push
(
row
);
}
let
datasets
:
Vec
<
Vec
<
scalar
::
Dataset
>>
=
js_datasets
.into_serde
()
.unwrap
();
let
result
:
Vec
<
Vec
<
scalar
::
Smoothed
>>
=
scalar
::
transform
(
datasets
,
smoothing
);
return
JsValue
::
from_serde
(
&
result
)
.unwrap
();
}
#[derive(Serialize,
Deserialize)]
struct
Range
{
min
:
f64
,
max
:
f64
,
}
impl
Range
{
pub
fn
new
(
min
:
f64
,
max
:
f64
)
->
Self
{
Range
{
min
,
max
}
}
}
fn
quantile
(
values
:
Vec
<
f64
>
,
p
:
f64
)
->
f64
{
let
n
:
usize
=
values
.len
();
if
n
==
0
{
return
std
::
f64
::
NAN
;
}
if
p
<=
0
.
||
n
<
2
{
return
values
[
0
];
}
if
p
>=
1
.
{
return
values
[
n
-
1
];
}
let
i
:
f64
=
((
n
-
1
)
as
f64
)
*
p
;
let
i0
:
usize
=
i
.floor
()
as
usize
;
let
value0
:
f64
=
values
[
i0
];
let
value1
:
f64
=
values
[
i0
+
1
];
return
value0
+
(
value1
-
value0
)
*
(
i
-
(
i0
as
f64
));
}
#[wasm_bindgen]
pub
fn
range
(
js_datasets
:
&
JsValue
,
outlier
:
bool
)
->
JsValue
{
pub
fn
scalar_
range
(
js_datasets
:
&
JsValue
,
outlier
:
bool
)
->
JsValue
{
utils
::
set_panic_hook
();
let
datasets
:
Vec
<
Vec
<
Smoothed
>>
=
js_datasets
.into_serde
()
.unwrap
();
let
mut
ranges
:
Vec
<
Range
>
=
vec!
[];
for
data
in
datasets
.iter
()
{
let
n
:
usize
=
data
.len
();
if
n
==
0
{
continue
;
}
let
values
:
Vec
<
f64
>
=
data
.iter
()
.map
(|
x
|
x
.2
)
.collect
();
let
mut
sorted
:
Vec
<
f64
>
=
values
.clone
();
sorted
.sort_by
(|
a
,
b
|
a
.partial_cmp
(
b
)
.unwrap
());
if
!
outlier
{
ranges
.push
(
Range
::
new
(
sorted
[
0
],
sorted
[
n
-
1
]));
}
else
{
ranges
.push
(
Range
::
new
(
quantile
(
sorted
,
0.05_f64
),
quantile
(
values
,
0.95
),
));
}
}
let
mut
min
:
f64
=
0
.
;
let
mut
max
:
f64
=
1
.
;
if
ranges
.len
()
!=
0
{
min
=
ranges
.iter
()
.min_by
(|
x
,
y
|
x
.min
.partial_cmp
(
&
y
.max
)
.unwrap
())
.unwrap
()
.min
;
max
=
ranges
.iter
()
.max_by
(|
x
,
y
|
x
.max
.partial_cmp
(
&
y
.max
)
.unwrap
())
.unwrap
()
.max
;
if
min
>
0
.
{
min
*=
0.9
;
}
else
{
min
*=
1.1
;
}
if
max
>
0
.
{
max
*=
1.1
;
}
else
{
max
*=
0.9
;
}
}
let
result
=
Range
::
new
(
min
,
max
);
let
datasets
:
Vec
<
Vec
<
scalar
::
Smoothed
>>
=
js_datasets
.into_serde
()
.unwrap
();
let
result
=
scalar
::
range
(
datasets
,
outlier
);
return
JsValue
::
from_serde
(
&
result
)
.unwrap
();
}
#[derive(Serialize,
Deserialize)]
struct
Point
{
name
:
String
,
value
:
Vec
<
f64
>
,
showing
:
bool
,
}
#[derive(Serialize,
Deserialize)]
struct
DividedPoints
(
Vec
<
Point
>
,
Vec
<
Point
>
);
impl
Point
{
pub
fn
new
(
name
:
String
,
value
:
Vec
<
f64
>
,
showing
:
bool
)
->
Self
{
Point
{
name
,
value
,
showing
,
}
#[wasm_bindgen]
pub
fn
histogram_transform
(
js_data
:
&
JsValue
,
mode
:
String
)
->
JsValue
{
utils
::
set_panic_hook
();
let
data
:
Vec
<
histogram
::
Data
>
=
js_data
.into_serde
()
.unwrap
();
if
mode
==
String
::
from
(
"overlay"
)
{
let
result
=
histogram
::
transform_overlay
(
data
);
return
JsValue
::
from_serde
(
&
result
)
.unwrap
();
}
}
impl
DividedPoints
{
pub
fn
new
(
matched
:
Vec
<
Point
>
,
missing
:
Vec
<
Point
>
)
->
Self
{
DividedPoints
(
matched
,
missing
)
if
mode
==
String
::
from
(
"offset"
)
{
let
result
=
histogram
::
transform_offset
(
data
);
return
JsValue
::
from_serde
(
&
result
)
.unwrap
();
}
return
JsValue
::
null
();
}
#[wasm_bindgen]
pub
fn
divide
(
pub
fn
high_dimensional_
divide
(
js_points
:
&
JsValue
,
js_labels
:
&
JsValue
,
visibility
:
bool
,
keyword
:
String
,
)
->
JsValue
{
utils
::
set_panic_hook
();
let
points
:
Vec
<
Vec
<
f64
>>
=
js_points
.into_serde
()
.unwrap
();
let
labels
:
Vec
<
String
>
=
js_labels
.into_serde
()
.unwrap
();
let
mut
matched
:
Vec
<
Point
>
=
vec!
[];
let
mut
missing
:
Vec
<
Point
>
=
vec!
[];
for
(
i
,
point
)
in
points
.iter
()
.enumerate
()
{
let
mut
name
:
String
=
String
::
from
(
""
);
let
ptr
:
*
const
String
=
&
labels
[
i
];
if
!
ptr
.is_null
()
{
name
=
labels
[
i
]
.clone
();
}
let
point_with_label
:
Point
=
Point
::
new
(
name
.clone
(),
point
.to_vec
(),
visibility
);
if
keyword
==
String
::
from
(
""
)
{
missing
.push
(
point_with_label
);
}
else
{
if
name
.contains
(
&
keyword
)
{
matched
.push
(
point_with_label
);
}
else
{
missing
.push
(
point_with_label
);
}
}
}
let
result
:
DividedPoints
=
DividedPoints
::
new
(
matched
,
missing
);
let
result
:
high_dimensional
::
DividedPoints
=
high_dimensional
::
divide
(
points
,
labels
,
visibility
,
keyword
);
return
JsValue
::
from_serde
(
&
result
)
.unwrap
();
}
frontend/packages/wasm/src/scalar.rs
0 → 100644
浏览文件 @
7bdb74b1
#[derive(Serialize,
Deserialize)]
pub
struct
Dataset
(
f64
,
i64
,
f64
);
#[derive(Serialize,
Deserialize)]
pub
struct
Smoothed
(
i64
,
i64
,
f64
,
f64
,
f64
);
#[derive(Serialize,
Deserialize)]
pub
struct
Range
{
min
:
f64
,
max
:
f64
,
}
impl
Range
{
pub
fn
new
(
min
:
f64
,
max
:
f64
)
->
Self
{
Range
{
min
,
max
}
}
}
fn
quantile
(
values
:
Vec
<
f64
>
,
p
:
f64
)
->
f64
{
let
n
:
usize
=
values
.len
();
if
n
==
0
{
return
std
::
f64
::
NAN
;
}
if
p
<=
0
.
||
n
<
2
{
return
values
[
0
];
}
if
p
>=
1
.
{
return
values
[
n
-
1
];
}
let
i
:
f64
=
((
n
-
1
)
as
f64
)
*
p
;
let
i0
:
usize
=
i
.floor
()
as
usize
;
let
value0
:
f64
=
values
[
i0
];
let
value1
:
f64
=
values
[
i0
+
1
];
return
value0
+
(
value1
-
value0
)
*
(
i
-
(
i0
as
f64
));
}
pub
fn
transform
(
datasets
:
Vec
<
Vec
<
Dataset
>>
,
smoothing
:
f64
)
->
Vec
<
Vec
<
Smoothed
>>
{
let
mut
result
:
Vec
<
Vec
<
Smoothed
>>
=
vec!
[];
for
dataset
in
datasets
.iter
()
{
let
mut
row
:
Vec
<
Smoothed
>
=
vec!
[];
let
mut
last
:
f64
=
std
::
f64
::
NAN
;
if
dataset
.len
()
>
0
{
last
=
0_f64
;
}
let
mut
num_accum
:
i32
=
0
;
let
mut
start_value
:
i64
=
0
;
for
(
i
,
d
)
in
dataset
.iter
()
.enumerate
()
{
let
mut
r
:
Smoothed
=
Smoothed
(
0
,
d
.1
,
d
.2
,
0.0
,
0.0
);
let
next_val
:
f64
=
d
.2
;
// second to millisecond.
let
millisecond
:
i64
=
((
d
.0
as
f64
)
*
1000_f64
)
.floor
()
as
i64
;
r
.0
=
millisecond
;
if
i
==
0
{
start_value
=
millisecond
;
}
// Relative time, millisecond to hours.
r
.4
=
((
millisecond
-
start_value
)
as
f64
)
/
(
60
*
60
*
1000
)
as
f64
;
if
next_val
.is_infinite
()
{
r
.3
=
next_val
;
}
else
{
last
=
last
*
smoothing
+
(
1.0
-
smoothing
)
*
next_val
;
num_accum
+=
1
;
let
mut
debias_weight
:
f64
=
1.0_f64
;
if
smoothing
!=
1.0
{
debias_weight
=
(
1.0_f64
-
smoothing
.powi
(
num_accum
))
.into
();
}
r
.3
=
last
/
debias_weight
;
}
row
.push
(
r
);
}
result
.push
(
row
);
}
return
result
;
}
pub
fn
range
(
datasets
:
Vec
<
Vec
<
Smoothed
>>
,
outlier
:
bool
)
->
Range
{
let
mut
ranges
:
Vec
<
Range
>
=
vec!
[];
for
data
in
datasets
.iter
()
{
let
n
:
usize
=
data
.len
();
if
n
==
0
{
continue
;
}
let
values
:
Vec
<
f64
>
=
data
.iter
()
.map
(|
x
|
x
.2
)
.collect
();
let
mut
sorted
:
Vec
<
f64
>
=
values
.clone
();
sorted
.sort_by
(|
a
,
b
|
a
.partial_cmp
(
b
)
.unwrap
());
if
!
outlier
{
ranges
.push
(
Range
::
new
(
sorted
[
0
],
sorted
[
n
-
1
]));
}
else
{
ranges
.push
(
Range
::
new
(
quantile
(
sorted
,
0.05_f64
),
quantile
(
values
,
0.95
),
));
}
}
let
mut
min
:
f64
=
0
.
;
let
mut
max
:
f64
=
1
.
;
if
ranges
.len
()
!=
0
{
min
=
ranges
.iter
()
.min_by
(|
x
,
y
|
x
.min
.partial_cmp
(
&
y
.max
)
.unwrap
())
.unwrap
()
.min
;
max
=
ranges
.iter
()
.max_by
(|
x
,
y
|
x
.max
.partial_cmp
(
&
y
.max
)
.unwrap
())
.unwrap
()
.max
;
if
min
>
0
.
{
min
*=
0.9
;
}
else
{
min
*=
1.1
;
}
if
max
>
0
.
{
max
*=
1.1
;
}
else
{
max
*=
0.9
;
}
}
return
Range
::
new
(
min
,
max
);
}
frontend/yarn.lock
浏览文件 @
7bdb74b1
...
...
@@ -2334,6 +2334,11 @@
dependencies:
"@types/node" "*"
"@types/d3-format@1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-1.3.1.tgz#35bf88264bd6bcda39251165bb827f67879c4384"
integrity sha512-KAWvReOKMDreaAwOjdfQMm0HjcUMlQG47GwqdVKgmm20vTd2pucj0a70c3gUSHrnsmo6H2AMrkBsZU2UhJLq8A==
"@types/echarts@4.6.1":
version "4.6.1"
resolved "https://registry.yarnpkg.com/@types/echarts/-/echarts-4.6.1.tgz#de6ede6b8069123150d53f3350f9e38533f1970e"
...
...
@@ -4955,7 +4960,7 @@ d3-force@1:
d3-quadtree "1"
d3-timer "1"
d3-format@1:
d3-format@1
, d3-format@1.4.4
:
version "1.4.4"
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.4.tgz#356925f28d0fd7c7983bfad593726fce46844030"
integrity sha512-TWks25e7t8/cqctxCmxpUuzZN11QxIA7YrMbram94zMQ0PXjE4LVIMe/f6a4+xxL8HQ3OsAFULOINQi1pE62Aw==
...
...
@@ -10794,11 +10799,6 @@ react-dom@16.13.1:
prop-types "^15.6.2"
scheduler "^0.19.1"
react-hooks-worker@0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/react-hooks-worker/-/react-hooks-worker-0.9.0.tgz#cf6e481711045d539368c83ba0fa42bd97c71a09"
integrity sha512-aDKlrc9Dh8O0Wag2mWbNpuXbTB/kX1tGzq74bFdxSfKg6KHvF9ft789WpatmCBQbszdgXEi3pS/BCj698JXCJQ==
react-i18next@11.5.0:
version "11.5.0"
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.5.0.tgz#84a9bb535d44c0c1b336b94de164515c2cc2a714"
...
...
visualdl/server/api.py
浏览文件 @
7bdb74b1
...
...
@@ -147,9 +147,9 @@ class Api(object):
return
self
.
_get_with_retry
(
'data/plugin/histogram/tags'
,
lib
.
get_histogram_tags
)
@
result
()
def
histogram_
histogram
(
self
,
run
,
tag
):
key
=
os
.
path
.
join
(
'data/plugin/
embeddings/embeddings
'
,
run
,
tag
)
return
self
.
_get_with_retry
(
key
,
lib
.
get_
embeddings
,
run
,
tag
)
def
histogram_
list
(
self
,
run
,
tag
):
key
=
os
.
path
.
join
(
'data/plugin/
histogram/histogram
'
,
run
,
tag
)
return
self
.
_get_with_retry
(
key
,
lib
.
get_
histogram
,
run
,
tag
)
@
result
(
'application/octet-stream'
,
lambda
s
:
{
"Content-Disposition"
:
'attachment; filename="%s"'
%
s
.
model_name
}
if
len
(
s
.
model_name
)
else
None
)
def
graphs_graph
(
self
):
...
...
@@ -175,7 +175,7 @@ def create_api_call(logdir, model, cache_timeout):
'audio/list'
:
(
api
.
audio_list
,
[
'run'
,
'tag'
]),
'audio/audio'
:
(
api
.
audio_audio
,
[
'run'
,
'tag'
,
'index'
]),
'embeddings/embedding'
:
(
api
.
embeddings_embedding
,
[
'run'
,
'tag'
,
'reduction'
,
'dimension'
]),
'histogram/
histogram'
:
(
api
.
histogram_histogram
,
[
'run'
,
'tag'
]),
'histogram/
list'
:
(
api
.
histogram_list
,
[
'run'
,
'tag'
]),
'graphs/graph'
:
(
api
.
graphs_graph
,
[])
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录