Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
chart-project
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
czj
chart-project
Commits
e017baf8
提交
e017baf8
authored
12月 06, 2023
作者:
祖铭松
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 聚类热图
上级
84bed51a
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
1396 行增加
和
416 行删除
+1396
-416
chart.vue
src/components/CircularHeatmap/components/chart.vue
+1
-1
chart.vue
src/components/ClusterHeatmap/components/chart.vue
+167
-42
config.vue
src/components/ClusterHeatmap/components/config.vue
+8
-113
index.vue
src/components/ClusterHeatmap/index.vue
+1
-1
mock.js
src/components/ClusterHeatmap/mock.js
+0
-0
hcluster.js
src/components/ClusterHeatmap/utils/hcluster.js
+10
-9
index.js
src/components/ClusterHeatmap/utils/index.js
+427
-0
index.vue
src/components/Test/index.vue
+110
-214
mock.js
src/components/Test/mock.js
+35
-35
utils.js
src/components/Test/utils.js
+636
-0
index.vue
src/views/home/index.vue
+1
-1
没有找到文件。
src/components/CircularHeatmap/components/chart.vue
浏览文件 @
e017baf8
...
...
@@ -15,7 +15,7 @@ const chartRef = ref(null);
// 配置项数据
const
options
=
ref
({});
// 图
例
实例
// 图
表
实例
const
svgInstance
=
ref
(
null
);
// pubsub实例
...
...
src/components/ClusterHeatmap/components/chart.vue
浏览文件 @
e017baf8
<
template
>
<div
ref=
"chartRef"
></div>
<div
ref=
"chartRef"
class=
"chart-box"
>
<div
class=
"tip"
></div>
</div>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
,
onUnmounted
}
from
'vue'
;
import
{
chartData
,
chartData1
}
from
'../mock'
;
import
{
chartMockData
}
from
'../mock.js'
;
import
*
as
d3
from
'https://cdn.jsdelivr.net/npm/d3@7/+esm'
;
import
PubSub
from
'pubsub-js'
;
// import * as d3 from 'd3';
import
*
as
uv
from
'unipept-visualizations'
;
// 根节点实例
import
{
getRootConfig
,
setColor
,
setTips
,
setMaxMinNumber
,
setHeatmap
,
setTree
,
setLegend
,
setBasisLegend
,
setConsensusLegend
,
setAxisTitle
,
setLabel
,
setBasisHeatmap
,
setConsensusHeatmap
,
setSilhouetteHeatmap
,
setSilhouetteLegend
}
from
'../utils/index'
;
const
chartRef
=
ref
(
null
);
// 配置项数据
const
options
=
ref
({});
// 图表实例
const
svgInstance
=
ref
(
null
);
// pubsub实例
const
pubSubInstance
=
ref
(
null
);
// 生成数据
const
generateData
=
()
=>
{
const
items
=
[];
const
rows
=
[];
const
columns
=
Object
.
keys
(
chartData1
[
0
]).
filter
((
k
)
=>
k
!==
'Family'
);
for
(
const
row
of
chartData1
)
{
const
newRow
=
[];
for
(
const
[
key
,
value
]
of
Object
.
entries
(
row
))
{
if
(
key
===
'Family'
)
{
rows
.
push
(
value
);
}
else
{
newRow
.
push
(
Number
.
parseFloat
(
value
));
}
}
items
.
push
(
newRow
);
}
return
{
items
,
rows
,
columns
// 生成图表
const
generateChart
=
(
chartData
)
=>
{
const
ret
=
options
.
value
;
let
width
=
Number
(
ret
.
chart_width
)
||
1000
;
let
height
=
Number
(
ret
.
chart_height
)
||
1000
;
let
margin
=
10
;
let
radius
=
3
;
let
dendWidth
=
100
;
let
xAxisLength
=
chartData
[
0
].
values
.
length
;
const
heatWidth
=
2
*
radius
*
xAxisLength
;
const
heatHeight
=
2
*
radius
*
chartData
.
length
;
const
titleConfig
=
{
label
:
!!
ret
.
title
?
ret
.
title
:
null
,
color
:
ret
.
title_font_color
||
'#333333'
,
fontSize
:
ret
.
title_font_size
||
20
,
fontStyle
:
ret
.
title_font_style
?
'oblique'
:
'normal'
,
fontFamily
:
ret
.
title_font_family
||
'Arial'
,
fontWeight
:
ret
.
title_font_weight
?
'bold'
:
'normal'
};
const
svg
=
d3
.
create
(
'svg'
)
.
attr
(
'width'
,
width
)
.
attr
(
'height'
,
height
+
100
)
.
attr
(
'viewBox'
,
[
0
,
0
,
width
,
height
])
.
attr
(
'style'
,
'max-width: 100%; height: auto; font: 10px sans-serif;'
);
// 最大值 最小值
const
{
maxNumber
,
minNumber
}
=
setMaxMinNumber
(
chartData
);
// color config
const
colorConfig
=
setColor
(
minNumber
,
maxNumber
);
let
configObj
=
{
svg
,
width
,
height
,
radius
,
margin
,
maxNumber
,
minNumber
,
dendWidth
,
titleConfig
,
xAxisLength
,
heatWidth
,
heatHeight
,
color
:
colorConfig
,
...
ret
};
const
rootConfig
=
getRootConfig
(
configObj
,
chartData
);
configObj
=
{
...
configObj
,
...
rootConfig
};
// heatmap
const
heatmapRect
=
setHeatmap
(
configObj
);
setTips
(
heatmapRect
);
// Tree
setTree
(
configObj
);
// axisLabel
setAxisTitle
(
configObj
);
// legend
ret
.
show_legend
&&
setLegend
(
configObj
);
// label
setLabel
(
configObj
);
// Basis
generageBasis
(
configObj
);
// Consensus
generageConsensus
(
configObj
);
// Silhouette
generageSilhouette
(
configObj
);
svgInstance
.
value
=
svg
.
node
();
// Append the SVG element.
chartRef
.
value
.
appendChild
(
svgInstance
.
value
);
};
// 生成图表
const
generateChart
=
(
data
)
=>
{
const
{
items
,
rows
,
columns
}
=
data
;
new
uv
.
Heatmap
(
chartRef
.
value
,
items
,
rows
,
columns
,
{
width
:
1200
,
height
:
800
,
dendrogramEnabled
:
true
,
squarePadding
:
0
});
// Basis
const
generageBasis
=
(
config
)
=>
{
const
chartData
=
chartMockData
.
slice
(
0
,
2
);
// max/min number
const
{
maxNumber
,
minNumber
}
=
setMaxMinNumber
(
chartData
);
// root config
const
{
root
,
orderingx
}
=
getRootConfig
(
config
,
chartData
);
// color config
const
colors
=
[
'#9D9FFF'
,
'#F57BFF'
,
'#3AB1FF'
,
'#D38BFF'
,
'#00C745'
,
'#F4952C'
];
const
color
=
setColor
(
minNumber
,
maxNumber
,
colors
);
const
configObj
=
{
...
config
,
root
,
orderingx
,
maxNumber
,
minNumber
,
color
};
const
heatmapRect
=
setBasisHeatmap
(
configObj
);
// tips
setTips
(
heatmapRect
);
// legend
config
.
show_legend
&&
setBasisLegend
(
configObj
);
};
onMounted
(()
=>
{
const
mackData
=
generateData
();
// Consensus
const
generageConsensus
=
(
config
)
=>
{
const
chartData
=
chartMockData
.
slice
(
2
,
4
);
// max/min number
const
{
maxNumber
,
minNumber
}
=
setMaxMinNumber
(
chartData
);
// root config
const
{
root
,
orderingx
}
=
getRootConfig
(
config
,
chartData
);
// color config
const
colors
=
[
'#C3AD00'
,
'#6EC000'
,
'#00CC7B'
,
'#00CDC9'
,
'#FF7B9C'
,
'#FF876E'
];
const
color
=
setColor
(
minNumber
,
maxNumber
,
colors
);
const
configObj
=
{
...
config
,
root
,
orderingx
,
maxNumber
,
minNumber
,
color
};
const
heatmapRect
=
setConsensusHeatmap
(
configObj
);
// tips
setTips
(
heatmapRect
);
// legend
config
.
show_legend
&&
setConsensusLegend
(
configObj
);
};
// Silhouette
const
generageSilhouette
=
(
config
)
=>
{
const
chartData
=
chartMockData
.
slice
(
4
,
6
);
// max/min number
const
{
maxNumber
,
minNumber
}
=
setMaxMinNumber
(
chartData
,
false
);
// root config
const
{
root
,
orderingx
}
=
getRootConfig
(
config
,
chartData
);
// color config
const
colors
=
[
'#C3AD00'
,
'#6EC000'
,
'#00CC7B'
,
'#00CDC9'
,
'#FF7B9C'
,
'#FF876E'
];
const
color
=
setColor
(
minNumber
,
maxNumber
,
colors
);
const
configObj
=
{
...
config
,
root
,
orderingx
,
maxNumber
,
minNumber
,
color
};
const
heatmapRect
=
setSilhouetteHeatmap
(
configObj
);
// tips
setTips
(
heatmapRect
);
// legend
config
.
show_legend
&&
setSilhouetteLegend
(
configObj
);
};
onMounted
(()
=>
{
const
chartData
=
chartMockData
;
pubSubInstance
.
value
=
PubSub
.
subscribe
(
'options'
,
(
m
,
data
)
=>
{
options
.
value
=
data
;
generateChart
(
mackData
);
chartRef
.
value
.
removeChild
(
svgInstance
.
value
);
generateChart
(
chartData
);
});
generateChart
(
mack
Data
);
generateChart
(
chart
Data
);
});
onUnmounted
(()
=>
{
...
...
@@ -70,4 +191,8 @@ onUnmounted(() => {
});
</
script
>
<
style
scoped
></
style
>
<
style
scoped
>
.chart-box
{
position
:
relative
;
}
</
style
>
src/components/ClusterHeatmap/components/config.vue
浏览文件 @
e017baf8
...
...
@@ -9,23 +9,11 @@
<span>
高:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.chart_height"
/>
</div>
<h3
class=
"type content"
>
文本
</h3>
<div
class=
"form-item"
>
<span>
上边距:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.margin_top"
/>
</div>
<div
class=
"form-item"
>
<span>
右边距:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.margin_right"
/>
</div>
<div
class=
"form-item"
>
<span>
下边距:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.margin_bottom"
/>
</div>
<div
class=
"form-item"
>
<span>
左边距:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.margin_left"
/>
<span>
标题:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.title"
/>
</div>
<h3
class=
"type content"
>
文本
</h3>
<div
class=
"form-item"
>
<span>
字体:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.title_font_family"
/>
...
...
@@ -46,105 +34,12 @@
<span>
斜体:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.title_font_style"
/>
</div>
<h3
class=
"type content"
>
X轴配置
</h3>
<div
class=
"form-item"
>
<span>
显示坐标轴:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.show_x_axis"
/>
</div>
<div
class=
"form-item"
>
<span>
显示刻度线:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.show_x_tickMarks"
/>
</div>
<div
class=
"form-item"
>
<span>
显示网格:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.show_x_gridLine"
/>
</div>
<div
class=
"form-item"
>
<span>
刻度线颜色:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.x_tickMarks_color"
/>
</div>
<div
class=
"form-item"
>
<span>
刻度线长度:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.x_tickMarks_length"
/>
</div>
<div
class=
"form-item"
>
<span>
字体:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.xtitle_font_family"
/>
</div>
<div
class=
"form-item"
>
<span>
字号:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.xtitle_font_size"
/>
</div>
<div
class=
"form-item"
>
<span>
字体颜色:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.xtitle_font_color"
/>
</div>
<div
class=
"form-item"
>
<span>
字体加粗:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.xtitle_font_weight"
/>
</div>
<div
class=
"form-item"
>
<span>
斜体:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.xtitle_font_style"
/>
</div>
<div
class=
"form-item"
>
<span>
x轴标题:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.x_title"
/>
</div>
<h3
class=
"type content"
>
Y轴配置
</h3>
<div
class=
"form-item"
>
<span>
显示坐标轴:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.show_y_axis"
/>
</div>
<div
class=
"form-item"
>
<span>
显示刻度线:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.show_y_tickMarks"
/>
</div>
<div
class=
"form-item"
>
<span>
显示网格:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.show_y_gridLine"
/>
</div>
<div
class=
"form-item"
>
<span>
刻度线颜色:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.y_tickMarks_color"
/>
</div>
<div
class=
"form-item"
>
<span>
刻度线长度:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.y_tickMarks_length"
/>
</div>
<div
class=
"form-item"
>
<span>
字体:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.ytitle_font_family"
/>
</div>
<div
class=
"form-item"
>
<span>
字号:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.ytitle_font_size"
/>
</div>
<div
class=
"form-item"
>
<span>
字体颜色:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.ytitle_font_color"
/>
</div>
<div
class=
"form-item"
>
<span>
字体加粗:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.ytitle_font_weight"
/>
</div>
<div
class=
"form-item"
>
<span>
斜体:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.ytitle_font_style"
/>
</div>
<div
class=
"form-item"
>
<span>
x轴标题:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.y_title"
/>
</div>
<h3
class=
"type content"
>
图例
</h3>
<div
class=
"form-item"
>
<span>
显示图例:
</span>
<input
type=
"checkbox"
v-model=
"dynamic_parameter.show_legend"
/>
</div>
<div
class=
"form-item"
>
<span>
图例位置:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.legend_position"
/>
</div>
<div
class=
"btn"
>
<button
@
click=
"submit"
>
提交
</button>
</div>
...
...
@@ -158,19 +53,19 @@ import PubSub from 'pubsub-js';
//动态图参数,固定参数
const
dynamic_parameter
=
reactive
({
//长宽间距
chart_width
:
8
00
,
chart_height
:
6
00
,
chart_width
:
10
00
,
chart_height
:
10
00
,
margin_top
:
60
,
margin_right
:
60
,
margin_bottom
:
60
,
margin_left
:
60
,
//标题配置
title
:
''
,
title
:
'
Consensus matrix
'
,
title_font_family
:
'Arial'
,
title_font_weight
:
true
,
title_font_size
:
20
,
title_font_color
:
'#333333'
,
title_font_style
:
tru
e
,
title_font_style
:
fals
e
,
//横轴标题
xtitle_font_family
:
'Arial'
,
xtitle_font_weight
:
false
,
...
...
src/components/ClusterHeatmap/index.vue
浏览文件 @
e017baf8
<
template
>
<div
class=
"chart-container"
>
<Chart
/>
<
!--
<Config
/>
--
>
<
Config
/
>
</div>
</
template
>
...
...
src/components/ClusterHeatmap/mock.js
浏览文件 @
e017baf8
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/components/
Test
/hcluster.js
→
src/components/
ClusterHeatmap/utils
/hcluster.js
浏览文件 @
e017baf8
import
distance
from
'distancejs'
import
extend
from
'extend'
// hcluster
var
hcluster
=
function
()
{
import
distance
from
'distancejs'
;
import
extend
from
'extend'
;
/**
* hcluster
* @returns
*/
export
default
function
()
{
var
data
,
clusters
,
clustersGivenK
,
...
...
@@ -207,7 +210,4 @@ var hcluster = function () {
// };
return
clust
;
};
// module.exports = hcluster;
export
default
hcluster
}
\ No newline at end of file
src/components/ClusterHeatmap/utils/index.js
0 → 100644
浏览文件 @
e017baf8
import
hcluster
from
'./hcluster'
;
import
*
as
d3
from
'https://cdn.jsdelivr.net/npm/d3@7/+esm'
;
// root config
export
const
getRootConfig
=
(
config
,
chartData
)
=>
{
const
normalizedData
=
()
=>
{
let
minmaxes
=
d3
.
range
(
chartData
[
0
].
values
.
length
)
.
map
((
d
)
=>
[
d3
.
min
(
chartData
.
map
((
el
)
=>
el
.
values
[
d
])),
d3
.
max
(
chartData
.
map
((
el
)
=>
el
.
values
[
d
]))]);
return
chartData
.
map
((
el
)
=>
({
...
el
,
normalized
:
el
.
values
.
map
((
n
,
i
)
=>
(
n
-
minmaxes
[
i
][
0
])
/
(
minmaxes
[
i
][
1
]
-
minmaxes
[
i
][
0
]))
}));
};
const
verticalData
=
()
=>
{
return
d3
.
range
(
chartData
[
0
].
values
.
length
).
map
((
d
)
=>
({
normalized
:
normalizedData
().
map
((
el
)
=>
el
.
normalized
[
d
])
}));
};
const
clustering
=
hcluster
().
distance
(
'angular'
).
linkage
(
'avg'
).
posKey
(
'normalized'
).
data
(
normalizedData
());
const
verticalClustering
=
hcluster
().
distance
(
'angular'
).
linkage
(
'avg'
).
posKey
(
'normalized'
).
data
(
verticalData
());
const
tree
=
(
data
)
=>
{
const
root
=
d3
.
hierarchy
(
data
).
sort
((
a
,
b
)
=>
d3
.
ascending
(
a
.
height
,
b
.
height
));
root
.
dx
=
config
.
radius
;
root
.
dy
=
config
.
dendWidth
/
(
root
.
height
+
1
);
return
d3
.
cluster
()
.
size
([
config
.
heatHeight
,
config
.
dendWidth
])
.
separation
(()
=>
2
)(
root
);
};
const
vertTree
=
(
data
)
=>
{
const
root
=
d3
.
hierarchy
(
data
).
sort
((
a
,
b
)
=>
d3
.
ascending
(
a
.
height
,
b
.
height
));
root
.
dy
=
config
.
radius
;
root
.
dx
=
config
.
dendWidth
/
(
root
.
height
+
1
);
return
d3
.
cluster
()
.
size
([
config
.
heatWidth
,
config
.
dendWidth
])
.
separation
(()
=>
2
)(
root
);
};
const
root
=
tree
(
clustering
.
tree
());
const
vertRoot
=
vertTree
(
verticalClustering
.
tree
());
const
orderingx
=
vertRoot
.
leaves
().
map
((
el
)
=>
el
.
data
.
indexes
[
0
]);
return
{
root
,
vertRoot
,
orderingx
}
}
// color config
export
const
setColor
=
(
min
,
max
,
color
)
=>
{
let
colors
=
[
'#313695'
,
'#436FB1'
,
'#6BA2CB'
,
'#9BCCE2'
,
'#F0F9D8'
,
'#F0F9D8'
,
'#FEF0A9'
,
'#FDCD7E'
,
'#FA9C58'
,
'#EE613D'
,
'#D22B26'
,
'#A50026'
];
if
(
Array
.
isArray
(
color
))
{
colors
=
!!
color
.
length
?
color
:
colors
;
}
else
if
(
!!
color
)
{
colors
=
color
.
split
(
','
);
}
return
()
=>
d3
.
scaleQuantize
().
domain
([
min
,
max
]).
range
(
colors
);
};
// maxnumber minNumber
export
const
setMaxMinNumber
=
(
chartData
,
isInteger
=
true
)
=>
{
let
maxNumArr
=
[],
minNumArr
=
[],
maxNumber
=
0
,
minNumber
=
0
;
for
(
let
i
=
0
;
i
<
chartData
.
length
;
i
++
)
{
maxNumArr
.
push
(
d3
.
max
(
chartData
[
i
].
values
));
minNumArr
.
push
(
d3
.
min
(
chartData
[
i
].
values
));
}
// 最大值 最小值
maxNumber
=
isInteger
?
Math
.
round
(
d3
.
max
(
maxNumArr
))
:
d3
.
max
(
maxNumArr
);
minNumber
=
isInteger
?
Math
.
round
(
d3
.
min
(
minNumArr
))
:
d3
.
min
(
minNumArr
);
return
{
maxNumber
,
minNumber
}
}
// tips
export
const
setTips
=
(
rect
)
=>
{
const
tips
=
d3
.
select
(
'.tip'
)
.
style
(
'visibility'
,
'hidden'
)
.
style
(
'position'
,
'relative'
)
.
style
(
'background-color'
,
'rgba(0, 0, 0, .8)'
)
.
style
(
'color'
,
'#fff'
)
.
style
(
'border-radius'
,
'5px'
)
.
style
(
'width'
,
'200px'
)
.
style
(
'text-align'
,
'center'
)
.
style
(
'height'
,
'20px'
)
.
style
(
'padding'
,
'5px'
);
rect
.
on
(
'mouseover'
,
(
event
,
d
)
=>
{
tips
.
style
(
'visibility'
,
'visible'
);
})
.
on
(
'mousemove'
,
function
(
event
,
d
)
{
tips
.
style
(
'visibility'
,
'visible'
)
.
style
(
'left'
,
event
.
offsetX
+
15
+
'px'
)
.
style
(
'top'
,
event
.
offsetY
+
50
+
'px'
)
.
html
(
`
${
d
}
`
);
})
.
on
(
'mouseleave'
,
function
()
{
tips
.
style
(
'visibility'
,
'hidden'
);
});
};
// heatmap
export
const
setHeatmap
=
(
config
)
=>
{
return
config
.
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
+
config
.
dendWidth
}
,
${
config
.
margin
+
config
.
dendWidth
*
2
}
)`
)
.
selectAll
(
'g'
)
.
data
(
config
.
root
.
leaves
())
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(0,
${
d
.
x
-
config
.
radius
}
)`
)
.
selectAll
(
'rect'
)
.
data
((
d
)
=>
d
.
data
.
values
.
map
((
e
,
i
)
=>
d
.
data
.
values
[
config
.
orderingx
[
i
]]))
.
join
(
'rect'
)
.
attr
(
'x'
,
(
d
,
i
)
=>
i
*
2
*
config
.
radius
)
.
attr
(
'y'
,
0
)
.
attr
(
'width'
,
2
*
config
.
radius
)
.
attr
(
'height'
,
2
*
config
.
radius
)
.
attr
(
'fill'
,
config
.
color
());
};
// Basis heatmap
export
const
setBasisHeatmap
=
(
config
)
=>
{
return
config
.
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
+
config
.
dendWidth
}
,
${
config
.
margin
}
)`
)
.
selectAll
(
'g'
)
.
data
(
config
.
root
.
leaves
())
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(0,
${
130
+
config
.
radius
*
2
*
i
}
)`
)
.
selectAll
(
'rect'
)
.
data
((
d
)
=>
d
.
data
.
values
.
map
((
e
,
i
)
=>
d
.
data
.
values
[
config
.
orderingx
[
i
]]))
.
join
(
'rect'
)
.
attr
(
'x'
,
(
d
,
i
)
=>
i
*
2
*
config
.
radius
)
.
attr
(
'y'
,
0
)
.
attr
(
'width'
,
2
*
config
.
radius
)
.
attr
(
'height'
,
2
*
config
.
radius
)
.
attr
(
'fill'
,
config
.
color
());
};
// Consensus heatmap
export
const
setConsensusHeatmap
=
(
config
)
=>
{
return
config
.
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
+
config
.
dendWidth
}
,
${
config
.
margin
}
)`
)
.
selectAll
(
'g'
)
.
data
(
config
.
root
.
leaves
())
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(0,
${
150
+
config
.
radius
*
2
*
i
}
)`
)
.
selectAll
(
'rect'
)
.
data
((
d
)
=>
d
.
data
.
values
.
map
((
e
,
i
)
=>
d
.
data
.
values
[
config
.
orderingx
[
i
]]))
.
join
(
'rect'
)
.
attr
(
'x'
,
(
d
,
i
)
=>
i
*
2
*
config
.
radius
)
.
attr
(
'y'
,
0
)
.
attr
(
'width'
,
2
*
config
.
radius
)
.
attr
(
'height'
,
2
*
config
.
radius
)
.
attr
(
'fill'
,
config
.
color
());
};
// Silhouette heatmap
export
const
setSilhouetteHeatmap
=
(
config
)
=>
{
return
config
.
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
+
config
.
dendWidth
}
,
${
config
.
margin
*
3
}
)`
)
.
selectAll
(
'g'
)
.
data
(
config
.
root
.
leaves
())
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(0,
${
150
+
config
.
radius
*
2
*
i
}
)`
)
.
selectAll
(
'rect'
)
.
data
((
d
)
=>
d
.
data
.
values
.
map
((
e
,
i
)
=>
d
.
data
.
values
[
config
.
orderingx
[
i
]]))
.
join
(
'rect'
)
.
attr
(
'x'
,
(
d
,
i
)
=>
i
*
2
*
config
.
radius
)
.
attr
(
'y'
,
0
)
.
attr
(
'width'
,
2
*
config
.
radius
)
.
attr
(
'height'
,
2
*
config
.
radius
)
.
attr
(
'fill'
,
d
=>
d3
.
interpolateGreens
(
d
));
};
// tree
export
const
setTree
=
(
config
)
=>
{
// left tree
config
.
svg
.
append
(
'g'
)
.
attr
(
'fill'
,
'none'
)
.
attr
(
'stroke'
,
'#000'
)
.
attr
(
'stroke-width'
,
1
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
}
,
${
config
.
margin
+
config
.
dendWidth
*
2
}
)`
)
.
selectAll
(
'path'
)
.
data
(
config
.
root
.
links
())
.
join
(
'path'
)
.
attr
(
'd'
,
(
d
)
=>
`
M
${
d
.
target
.
y
}
,
${
d
.
target
.
x
}
L
${
d
.
source
.
y
}
,
${
d
.
target
.
x
}
${
d
.
source
.
y
}
,
${
d
.
source
.
x
}
${
d
.
source
.
y
}
,
${
d
.
source
.
x
}
`
);
// top tree
config
.
svg
.
append
(
'g'
)
.
attr
(
'fill'
,
'none'
)
.
attr
(
'stroke'
,
'#555'
)
.
attr
(
'stroke-width'
,
1
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
+
config
.
dendWidth
}
,
${
config
.
margin
*
3
}
)`
)
.
selectAll
(
'path'
)
.
data
(
config
.
vertRoot
.
links
())
.
join
(
'path'
)
.
attr
(
'd'
,
(
d
)
=>
`
M
${
d
.
target
.
x
}
,
${
d
.
target
.
y
}
L
${
d
.
target
.
x
}
,
${
d
.
source
.
y
}
${
d
.
source
.
x
}
,
${
d
.
source
.
y
}
${
d
.
source
.
x
}
,
${
d
.
source
.
y
}
`
);
};
// legend
export
const
setLegend
=
(
config
)
=>
{
const
legendData
=
[...
Array
.
from
({
length
:
config
.
maxNumber
},
(
item
,
i
)
=>
i
)];
config
.
svg
.
append
(
'g'
)
.
selectAll
()
.
data
(
legendData
)
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
,
nodes
)
=>
`translate(
${
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
80
}
,
${
config
.
height
/
3
+
(
nodes
.
length
/
2
-
i
-
1
)
*
18
-
60
}
)`
)
.
call
((
g
)
=>
g
.
append
(
'rect'
).
attr
(
'width'
,
18
).
attr
(
'height'
,
18
).
attr
(
'fill'
,
config
.
color
()))
.
call
((
g
)
=>
g
.
append
(
'text'
)
.
attr
(
'x'
,
21
)
.
attr
(
'y'
,
10
)
.
attr
(
'dy'
,
'0.3em'
)
.
style
(
'font'
,
'13px sans-serif'
)
.
text
((
d
)
=>
d
)
);
};
// Basis legend
export
const
setBasisLegend
=
(
config
)
=>
{
const
legendData
=
[...
Array
.
from
({
length
:
config
.
maxNumber
},
(
item
,
i
)
=>
i
)];
const
textX
=
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
180
config
.
svg
.
append
(
'text'
)
.
attr
(
'x'
,
textX
)
.
attr
(
'y'
,
config
.
height
/
3
-
110
)
.
attr
(
'fill'
,
'#333333'
)
.
attr
(
'font-size'
,
'20px'
)
.
attr
(
'font-family'
,
`
${
config
.
titleConfig
.
fontFamily
}
`
)
.
attr
(
'font-style'
,
'normal'
)
.
attr
(
'font-weight'
,
'bold'
)
.
style
(
'text-anchor'
,
'middle'
)
.
text
(
'basis'
);
config
.
svg
.
append
(
'g'
)
.
selectAll
()
.
data
(
legendData
)
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
,
nodes
)
=>
`translate(
${
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
160
}
,
${
config
.
height
/
3
+
(
nodes
.
length
/
2
-
i
-
1
)
*
21
-
50
}
)`
)
.
call
((
g
)
=>
g
.
append
(
'rect'
).
attr
(
'width'
,
15
).
attr
(
'height'
,
15
).
attr
(
'fill'
,
config
.
color
()))
.
call
((
g
)
=>
g
.
append
(
'text'
)
.
attr
(
'x'
,
20
)
.
attr
(
'y'
,
9
)
.
attr
(
'dy'
,
'0.3em'
)
.
style
(
'font'
,
'13px sans-serif'
)
.
text
((
d
)
=>
d
)
);
}
// Consensus legend
export
const
setConsensusLegend
=
(
config
)
=>
{
const
legendData
=
[...
Array
.
from
({
length
:
config
.
maxNumber
},
(
item
,
i
)
=>
i
)];
const
textX
=
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
205
config
.
svg
.
append
(
'text'
)
.
attr
(
'x'
,
textX
)
.
attr
(
'y'
,
config
.
height
/
3
+
50
)
.
attr
(
'fill'
,
'#333333'
)
.
attr
(
'font-size'
,
'20px'
)
.
attr
(
'font-family'
,
`
${
config
.
titleConfig
.
fontFamily
}
`
)
.
attr
(
'font-style'
,
'normal'
)
.
attr
(
'font-weight'
,
'bold'
)
.
style
(
'text-anchor'
,
'middle'
)
.
text
(
'consensus'
);
config
.
svg
.
append
(
'g'
)
.
selectAll
()
.
data
(
legendData
)
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
,
nodes
)
=>
`translate(
${
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
160
}
,
${
config
.
height
/
3
+
(
nodes
.
length
/
2
-
i
-
1
)
*
21
+
110
}
)`
)
.
call
((
g
)
=>
g
.
append
(
'rect'
).
attr
(
'width'
,
15
).
attr
(
'height'
,
15
).
attr
(
'fill'
,
config
.
color
()))
.
call
((
g
)
=>
g
.
append
(
'text'
)
.
attr
(
'x'
,
20
)
.
attr
(
'y'
,
9
)
.
attr
(
'dy'
,
'0.3em'
)
.
style
(
'font'
,
'13px sans-serif'
)
.
text
((
d
)
=>
d
)
);
}
// Silhouette legend
export
const
setSilhouetteLegend
=
(
config
)
=>
{
const
textX
=
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
200
const
legendData
=
[
config
.
maxNumber
,
config
.
minNumber
]
config
.
svg
.
append
(
'text'
)
.
attr
(
'x'
,
textX
)
.
attr
(
'y'
,
config
.
height
/
3
+
210
)
.
attr
(
'fill'
,
'#333333'
)
.
attr
(
'font-size'
,
'20px'
)
.
attr
(
'font-family'
,
`
${
config
.
titleConfig
.
fontFamily
}
`
)
.
attr
(
'font-style'
,
'normal'
)
.
attr
(
'font-weight'
,
'bold'
)
.
style
(
'text-anchor'
,
'middle'
)
.
text
(
'silhouette'
);
config
.
svg
.
append
(
'g'
)
.
selectAll
()
.
data
(
legendData
)
.
join
(
'text'
)
.
attr
(
'x'
,
textX
+
20
)
.
attr
(
'y'
,
(
d
,
i
)
=>
config
.
height
/
3
+
i
*
40
+
240
)
.
attr
(
'fill'
,
config
.
titleConfig
.
color
)
.
attr
(
'font-style'
,
`
${
config
.
titleConfig
.
fontStyle
}
`
)
.
attr
(
'font-weight'
,
`
${
config
.
titleConfig
.
fontWeight
}
`
)
.
style
(
'font'
,
'13px sans-serif'
)
.
style
(
'text-anchor'
,
'middle'
)
.
text
((
d
)
=>
d
);
const
gradient
=
config
.
svg
.
append
(
'defs'
)
.
append
(
'linearGradient'
)
.
attr
(
'id'
,
'mylLnearGradient'
)
.
attr
(
'x1'
,
'0%'
)
.
attr
(
'y1'
,
'0%'
)
.
attr
(
'x2'
,
'0%'
)
.
attr
(
'y2'
,
'100%'
)
.
attr
(
'spreadMethod'
,
'pad'
);
gradient
.
append
(
'stop'
)
.
attr
(
'offset'
,
'0%'
)
.
attr
(
'stop-color'
,
'rgb(0,128,0,1)'
)
.
attr
(
'stop-opacity'
,
1
);
gradient
.
append
(
'stop'
)
.
attr
(
'offset'
,
'100%'
)
.
attr
(
'stop-color'
,
'rgb(0,128,0,0.1)'
)
.
attr
(
'stop-opacity'
,
1
);
config
.
svg
.
append
(
'rect'
)
.
attr
(
'width'
,
'15'
)
.
attr
(
'height'
,
'60'
)
.
attr
(
"fill"
,
"url(#mylLnearGradient)"
)
.
attr
(
"x"
,
`
${
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
160
}
`
)
.
attr
(
"y"
,
`
${
config
.
height
/
3
+
225
}
`
)
}
// 标签
export
const
setAxisTitle
=
(
config
)
=>
{
const
labelList
=
config
.
root
.
leaves
().
map
((
item
)
=>
item
.
data
.
id
);
config
.
svg
.
append
(
'g'
)
.
selectAll
(
'g'
)
.
data
(
labelList
)
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(
${
config
.
margin
+
config
.
dendWidth
+
config
.
xAxisLength
*
2
*
config
.
radius
+
4
}
,
${
config
.
margin
+
config
.
dendWidth
*
2
+
i
*
2
*
config
.
radius
+
4
}
)`
)
.
call
((
g
)
=>
g
.
append
(
'text'
)
.
attr
(
'x'
,
0
)
.
attr
(
'y'
,
0
)
.
attr
(
'dy'
,
'0.35em'
)
.
style
(
'font'
,
`6px sans-serif`
)
.
style
(
'fill'
,
`#000`
)
.
text
((
d
)
=>
d
)
);
};
// 标题
export
const
setLabel
=
(
config
)
=>
{
config
.
svg
.
append
(
'text'
)
.
attr
(
'x'
,
config
.
width
/
3
)
.
attr
(
'y'
,
0
)
.
attr
(
'fill'
,
config
.
titleConfig
.
color
)
.
attr
(
'font-size'
,
`
${
config
.
titleConfig
.
fontSize
}
px`
)
.
attr
(
'font-family'
,
`
${
config
.
titleConfig
.
fontFamily
}
`
)
.
attr
(
'font-style'
,
`
${
config
.
titleConfig
.
fontStyle
}
`
)
.
attr
(
'font-weight'
,
`
${
config
.
titleConfig
.
fontWeight
}
`
)
.
style
(
'text-anchor'
,
'middle'
)
.
text
(
config
.
titleConfig
.
label
);
};
src/components/Test/index.vue
浏览文件 @
e017baf8
...
...
@@ -6,9 +6,25 @@
<
script
setup
>
import
{
ref
,
onMounted
}
from
'vue'
;
import
{
chartM
a
ckData
}
from
'./mock.js'
;
import
{
chartM
o
ckData
}
from
'./mock.js'
;
import
*
as
d3
from
'https://cdn.jsdelivr.net/npm/d3@7/+esm'
;
import
hcluster
from
'./hcluster'
;
import
{
getRootConfig
,
setColor
,
setTips
,
setMaxMinNumber
,
setHeatmap
,
setTree
,
setLegend
,
setBasisLegend
,
setConsensusLegend
,
setAxisTitle
,
setLabel
,
setBasisHeatmap
,
setConsensusHeatmap
,
setSilhouetteHeatmap
,
setSilhouetteLegend
}
from
'./utils'
;
const
chartRef
=
ref
(
null
);
...
...
@@ -18,16 +34,16 @@ const options = ref({});
// 生成图表
const
generateChart
=
(
chartData
)
=>
{
const
ret
=
options
.
value
;
// return;
let
width
=
7
00
;
let
height
=
8
00
;
let
width
=
10
00
;
let
height
=
10
00
;
let
margin
=
10
;
let
radius
=
3
;
let
dendWidth
=
1
5
0
;
let
heatWidth
=
462
;
let
heatHeight
=
600
;
let
n
=
100
;
let
nonMeasurements
=
[
'MouseID'
,
'Genotype'
,
'Treatment'
,
'Behavior'
,
'class'
]
;
let
dendWidth
=
1
0
0
;
let
xAxisLength
=
chartData
[
0
].
values
.
length
;
const
heatWidth
=
2
*
radius
*
xAxisLength
;
const
heatHeight
=
2
*
radius
*
chartData
.
length
;
const
titleConfig
=
{
label
:
!!
ret
.
title
?
ret
.
title
:
null
,
...
...
@@ -37,240 +53,120 @@ const generateChart = (chartData) => {
fontFamily
:
ret
.
title_font_family
||
'Arial'
,
fontWeight
:
ret
.
title_font_weight
?
'bold'
:
'normal'
};
let
maxNumArr
=
[];
for
(
let
i
=
0
;
i
<
chartData
.
length
;
i
++
)
{
maxNumArr
.
push
(
d3
.
max
(
chartData
[
i
].
values
));
}
// 最大值
const
maxNumber
=
Math
.
round
(
d3
.
max
(
maxNumArr
));
const
color_ls
=
setColorConfig
();
const
color
=
(
max
,
range_count
,
d
)
=>
{
return
d3
.
scaleQuantize
().
domain
([
0
,
max
]).
range
(
color_ls
);
};
const
normalizedData
=
()
=>
{
let
minmaxes
=
d3
.
range
(
chartData
[
0
].
values
.
length
)
.
map
((
d
)
=>
[
d3
.
min
(
chartData
.
map
((
el
)
=>
el
.
values
[
d
])),
d3
.
max
(
chartData
.
map
((
el
)
=>
el
.
values
[
d
]))]);
return
chartData
.
map
((
el
)
=>
({
...
el
,
normalized
:
el
.
values
.
map
((
n
,
i
)
=>
(
n
-
minmaxes
[
i
][
0
])
/
(
minmaxes
[
i
][
1
]
-
minmaxes
[
i
][
0
]))
}));
};
const
verticalData
=
()
=>
{
return
d3
.
range
(
chartData
[
0
].
values
.
length
).
map
((
d
)
=>
({
normalized
:
normalizedData
().
map
((
el
)
=>
el
.
normalized
[
d
])
}));
};
const
clustering
=
hcluster
().
distance
(
'angular'
).
linkage
(
'avg'
).
posKey
(
'normalized'
).
data
(
normalizedData
());
const
verticalClustering
=
hcluster
().
distance
(
'angular'
).
linkage
(
'avg'
).
posKey
(
'normalized'
).
data
(
verticalData
());
const
tree
=
(
data
)
=>
{
const
root
=
d3
.
hierarchy
(
data
).
sort
((
a
,
b
)
=>
d3
.
ascending
(
a
.
height
,
b
.
height
));
root
.
dx
=
radius
;
root
.
dy
=
dendWidth
/
(
root
.
height
+
1
);
return
d3
.
cluster
()
.
size
([
heatHeight
,
dendWidth
])
.
separation
(()
=>
2
)(
root
);
};
const
vertTree
=
(
data
)
=>
{
const
root
=
d3
.
hierarchy
(
data
).
sort
((
a
,
b
)
=>
d3
.
ascending
(
a
.
height
,
b
.
height
));
root
.
dy
=
radius
;
root
.
dx
=
dendWidth
/
(
root
.
height
+
1
);
return
d3
.
cluster
()
.
size
([
heatWidth
,
dendWidth
])
.
separation
(()
=>
2
)(
root
);
};
const
root
=
tree
(
clustering
.
tree
());
const
vertRoot
=
vertTree
(
verticalClustering
.
tree
());
const
svg
=
d3
.
create
(
'svg'
)
.
attr
(
'width'
,
width
)
.
attr
(
'height'
,
height
+
5
0
)
.
attr
(
'height'
,
height
+
10
0
)
.
attr
(
'viewBox'
,
[
0
,
0
,
width
,
height
])
.
attr
(
'style'
,
'max-width: 100%; height: auto; font: 10px sans-serif;'
);
// left tree
svg
.
append
(
'g'
)
.
attr
(
'fill'
,
'none'
)
.
attr
(
'stroke'
,
'#000'
)
.
attr
(
'stroke-width'
,
1
)
.
attr
(
'transform'
,
`translate(
${
margin
}
,
${
margin
+
dendWidth
}
)`
)
.
selectAll
(
'path'
)
.
data
(
root
.
links
())
.
join
(
'path'
)
.
attr
(
'd'
,
(
d
)
=>
`
M
${
d
.
target
.
y
}
,
${
d
.
target
.
x
}
L
${
d
.
source
.
y
}
,
${
d
.
target
.
x
}
${
d
.
source
.
y
}
,
${
d
.
source
.
x
}
${
d
.
source
.
y
}
,
${
d
.
source
.
x
}
`
);
// top tree
svg
.
append
(
'g'
)
.
attr
(
'fill'
,
'none'
)
.
attr
(
'stroke'
,
'#555'
)
.
attr
(
'stroke-width'
,
1
)
.
attr
(
'transform'
,
`translate(
${
margin
+
dendWidth
}
,
${
margin
}
)`
)
.
selectAll
(
'path'
)
.
data
(
vertRoot
.
links
())
.
join
(
'path'
)
.
attr
(
'd'
,
(
d
)
=>
`
M
${
d
.
target
.
x
}
,
${
d
.
target
.
y
}
L
${
d
.
target
.
x
}
,
${
d
.
source
.
y
}
${
d
.
source
.
x
}
,
${
d
.
source
.
y
}
${
d
.
source
.
x
}
,
${
d
.
source
.
y
}
`
);
let
orderingx
=
vertRoot
.
leaves
().
map
((
el
)
=>
el
.
data
.
indexes
[
0
]);
let
fcolors
=
color
(
maxNumber
,
orderingx
.
length
);
const
rects
=
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${
margin
+
dendWidth
}
,
${
margin
+
dendWidth
}
)`
)
.
selectAll
(
'g'
)
.
data
(
root
.
leaves
())
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(0,
${
d
.
x
-
radius
}
)`
)
.
selectAll
(
'rect'
)
.
data
((
d
)
=>
d
.
data
.
values
.
map
((
e
,
i
)
=>
d
.
data
.
values
[
orderingx
[
i
]]))
.
join
(
'rect'
)
.
attr
(
'x'
,
(
d
,
i
)
=>
i
*
2
*
radius
)
.
attr
(
'y'
,
0
)
.
attr
(
'width'
,
2
*
radius
)
.
attr
(
'height'
,
2
*
radius
)
.
attr
(
'fill'
,
(
d
)
=>
fcolors
(
d
));
// 最大值 最小值
const
{
maxNumber
,
minNumber
}
=
setMaxMinNumber
(
chartData
);
setTips
(
rects
);
// color config
const
colorConfig
=
setColor
(
minNumber
,
maxNumber
);
const
configObj
=
{
let
configObj
=
{
svg
,
width
,
height
,
radius
,
margin
,
maxNumber
,
minNumber
,
dendWidth
,
titleConfig
,
rootData
:
root
.
leaves
(),
vertRootLength
:
orderingx
.
length
xAxisLength
,
heatWidth
,
heatHeight
,
color
:
colorConfig
};
const
rootConfig
=
getRootConfig
(
configObj
,
chartData
);
configObj
=
{
...
configObj
,
...
rootConfig
};
// heatmap
const
heatmapRect
=
setHeatmap
(
configObj
);
setTips
(
heatmapRect
);
// Tree
setTree
(
configObj
);
// axisLabel
setAxisTitle
(
configObj
,
svg
);
setAxisTitle
(
configObj
);
// l
abel
setL
abel
(
configObj
,
svg
);
// l
egend
setL
egend
(
configObj
);
chartRef
.
value
.
append
(
svg
.
node
());
}
;
// label
setLabel
(
configObj
)
;
// 标签
const
setAxisTitle
=
(
config
,
svg
)
=>
{
const
labelList
=
config
.
rootData
.
map
((
item
)
=>
item
.
data
.
id
);
// Basis
generageBasis
(
configObj
);
// Consensus
generageConsensus
(
configObj
);
// Silhouette
generageSilhouette
(
configObj
);
svg
.
append
(
'g'
)
.
selectAll
(
'g'
)
.
data
(
labelList
)
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(
${
config
.
margin
+
config
.
dendWidth
+
config
.
vertRootLength
*
2
*
config
.
radius
+
3
}
,
${
config
.
margin
+
config
.
dendWidth
+
i
*
2
*
config
.
radius
+
3
}
)`
)
.
call
((
g
)
=>
g
.
append
(
'text'
)
.
attr
(
'x'
,
0
)
.
attr
(
'y'
,
0
)
.
attr
(
'dy'
,
'0.35em'
)
.
style
(
'font'
,
`6px sans-serif`
)
.
style
(
'fill'
,
`#000`
)
.
text
((
d
)
=>
d
)
);
return
svg
.
node
();
// setEl
chartRef
.
value
.
append
(
svg
.
node
());
};
// 标题
const
setLabel
=
(
config
,
svg
)
=>
{
svg
.
append
(
'text'
)
.
attr
(
'x'
,
200
)
.
attr
(
'y'
,
0
)
.
attr
(
'fill'
,
config
.
titleConfig
.
color
)
.
attr
(
'font-size'
,
`
${
config
.
titleConfig
.
fontSize
}
px`
)
.
attr
(
'font-family'
,
`
${
config
.
titleConfig
.
fontFamily
}
`
)
.
attr
(
'font-style'
,
`
${
config
.
titleConfig
.
fontStyle
}
`
)
.
attr
(
'font-weight'
,
`
${
config
.
titleConfig
.
fontWeight
}
`
)
.
style
(
'text-anchor'
,
'middle'
)
.
text
(
'热图热图热图热图热图热图热图热图热图'
);
// Basis
const
generageBasis
=
(
config
)
=>
{
const
chartData
=
chartMockData
.
slice
(
0
,
2
);
// max/min number
const
{
maxNumber
,
minNumber
}
=
setMaxMinNumber
(
chartData
);
// root config
const
{
root
,
orderingx
}
=
getRootConfig
(
config
,
chartData
);
// color config
const
colors
=
[
'#9D9FFF'
,
'#F57BFF'
,
'#3AB1FF'
,
'#D38BFF'
,
'#00C745'
,
'#F4952C'
];
const
color
=
setColor
(
minNumber
,
maxNumber
,
colors
);
const
configObj
=
{
...
config
,
root
,
orderingx
,
maxNumber
,
minNumber
,
color
};
const
heatmapRect
=
setBasisHeatmap
(
configObj
);
// tips
setTips
(
heatmapRect
);
// legend
setBasisLegend
(
configObj
);
};
// 提示
const
setTips
=
(
rect
)
=>
{
const
tips
=
d3
.
select
(
'.tip'
)
.
style
(
'visibility'
,
'hidden'
)
.
style
(
'position'
,
'relative'
)
.
style
(
'background-color'
,
'rgba(0, 0, 0, .8)'
)
.
style
(
'color'
,
'#fff'
)
.
style
(
'border-radius'
,
'5px'
)
.
style
(
'width'
,
'200px'
)
.
style
(
'text-align'
,
'center'
)
.
style
(
'height'
,
'20px'
)
.
style
(
'padding'
,
'5px'
);
rect
.
on
(
'mouseover'
,
(
event
,
d
)
=>
{
tips
.
style
(
'visibility'
,
'visible'
);
})
.
on
(
'mousemove'
,
function
(
event
,
d
)
{
tips
.
style
(
'visibility'
,
'visible'
)
.
style
(
'left'
,
event
.
offsetX
+
15
+
'px'
)
.
style
(
'top'
,
event
.
offsetY
+
50
+
'px'
)
.
html
(
`
${
d
}
`
);
})
.
on
(
'mouseleave'
,
function
()
{
tips
.
style
(
'visibility'
,
'hidden'
);
});
// Consensus
const
generageConsensus
=
(
config
)
=>
{
const
chartData
=
chartMockData
.
slice
(
2
,
4
);
// max/min number
const
{
maxNumber
,
minNumber
}
=
setMaxMinNumber
(
chartData
);
// root config
const
{
root
,
orderingx
}
=
getRootConfig
(
config
,
chartData
);
// color config
const
colors
=
[
'#C3AD00'
,
'#6EC000'
,
'#00CC7B'
,
'#00CDC9'
,
'#FF7B9C'
,
'#FF876E'
];
const
color
=
setColor
(
minNumber
,
maxNumber
,
colors
);
const
configObj
=
{
...
config
,
root
,
orderingx
,
maxNumber
,
minNumber
,
color
};
const
heatmapRect
=
setConsensusHeatmap
(
configObj
);
// tips
setTips
(
heatmapRect
);
// legend
setConsensusLegend
(
configObj
);
};
const
setColorConfig
=
(
color
)
=>
{
let
colors
=
[
'#313695'
,
'#436FB1'
,
'#6BA2CB'
,
'#9BCCE2'
,
'#F0F9D8'
,
'#F0F9D8'
,
'#FEF0A9'
,
'#FDCD7E'
,
'#FA9C58'
,
'#EE613D'
,
'#D22B26'
,
'#A50026'
];
if
(
Array
.
isArray
(
color
))
{
colors
=
!!
color
.
length
?
color
:
colors
;
}
else
if
(
!!
color
)
{
colors
=
color
.
split
(
','
);
}
return
colors
;
// Silhouette
const
generageSilhouette
=
(
config
)
=>
{
const
chartData
=
chartMockData
.
slice
(
4
,
6
);
// max/min number
const
{
maxNumber
,
minNumber
}
=
setMaxMinNumber
(
chartData
,
false
);
// root config
const
{
root
,
orderingx
}
=
getRootConfig
(
config
,
chartData
);
// color config
const
colors
=
[
'#C3AD00'
,
'#6EC000'
,
'#00CC7B'
,
'#00CDC9'
,
'#FF7B9C'
,
'#FF876E'
];
const
color
=
setColor
(
minNumber
,
maxNumber
,
colors
);
const
configObj
=
{
...
config
,
root
,
orderingx
,
maxNumber
,
minNumber
,
color
};
const
heatmapRect
=
setSilhouetteHeatmap
(
configObj
);
// tips
setTips
(
heatmapRect
);
// legend
setSilhouetteLegend
(
configObj
);
};
onMounted
(()
=>
{
const
chartData
=
[...
chartMackData
]
;
const
chartData
=
chartMockData
;
generateChart
(
chartData
);
});
</
script
>
...
...
src/components/Test/mock.js
浏览文件 @
e017baf8
export
const
chartM
a
ckData
=
[
export
const
chartM
o
ckData
=
[
{
"id"
:
"3478_7"
,
"cls"
:
"c-CS-s"
,
...
...
@@ -338,35 +338,35 @@ export const chartMackData = [
0.627634368
,
0.78077067
,
0.331712184
,
2
.299912707
,
3
.990896621
,
0
.299912707
,
0
.990896621
,
0.211497693
,
0.161740865
,
2
.580995137
,
0
.580995137
,
0.208380097
,
1
.391445317
,
0
.391445317
,
0.624392069
,
0.297293927
,
0.325227584
,
0.280209502
,
0.747474747
,
0.597580746
,
1
.540965208
,
1
.976929792
,
0
.540965208
,
0
.976929792
,
0.442823295
,
0.639481232
,
0.400922808
,
0.401421624
,
0.15538097
,
1
.306646714
,
2
.87916199
,
1
.298540965
,
0
.306646714
,
0
.87916199
,
0
.298540965
,
0.2410525
,
0.309265494
,
0.751964085
,
0.153510413
,
0.496071829
,
2
.208005986
,
0
.208005986
,
0.323606435
,
0.384836014
,
0.291682255
,
...
...
@@ -381,10 +381,10 @@ export const chartMackData = [
0.23615096
,
0.984845141
,
0.175163687
,
2
.266460678
,
0
.266460678
,
0.3534172
,
0.615684544
,
1
.58471272
,
0
.58471272
,
0.319208416
,
0.158316781
,
0.2088575
,
...
...
@@ -397,10 +397,10 @@ export const chartMackData = [
0.133083205
,
0.521003458
,
0.335172515
,
1
.650849702
,
2
.406238505
,
0
.650849702
,
0
.406238505
,
0.15699257
,
1
.332744795
,
0
.332744795
,
0.936143603
,
0.233502538
,
0.156109762
,
...
...
@@ -411,7 +411,7 @@ export const chartMackData = [
0.187596557
,
0.171264621
,
0.204958434
,
1
.80004414
0
.80004414
]
},
{
...
...
@@ -421,35 +421,35 @@ export const chartMackData = [
0.715018037
,
0.925954054
,
0.338902601
,
2
.373457376
,
3
.55686349
,
0
.373457376
,
0
.55686349
,
0.250806911
,
0.194797798
,
5
.544902221
,
0
.544902221
,
0.223087146
,
1
.599012721
,
0
.599012721
,
0.936016708
,
0.32789064
,
0.420732865
,
0.271122081
,
0.832921967
,
0.645528764
,
1
.50806911
,
2
.932409341
,
0
.50806911
,
0
.932409341
,
0.632618189
,
0.588380482
,
0.601480919
,
0.362825138
,
0.185114866
,
1
.134042149
,
1
.986709702
,
1
.402885893
,
0
.134042149
,
0
.986709702
,
0
.402885893
,
0.270172774
,
0.274729448
,
0.745965445
,
0.1815075
,
0.505031327
,
2
.080121511
,
0
.080121511
,
0.332067591
,
0.459464591
,
0.386937536
,
...
...
@@ -464,10 +464,10 @@ export const chartMackData = [
0.181637914
,
0.949038271
,
0.165377751
,
3
.10668253
,
0
.10668253
,
0.30705929
,
0.627900059
,
1
.073765616
,
0
.073765616
,
0.311620067
,
0.155463018
,
0.168451319
,
...
...
@@ -480,10 +480,10 @@ export const chartMackData = [
0.125024787
,
0.464207813
,
0.282272457
,
1
.528356137
,
2
.087051358
,
0
.528356137
,
0
.087051358
,
0.149910767
,
1
.187487607
,
0
.187487607
,
0.938132064
,
0.211580408
,
0.172912949
,
...
...
@@ -494,7 +494,7 @@ export const chartMackData = [
0.186496133
,
0.183819155
,
0.202260559
,
1
.579317866
0
.579317866
]
},
{
...
...
@@ -8299,4 +8299,5 @@ export const chartMackData = [
1.144377729
]
}
]
\ No newline at end of file
]
src/components/Test/utils.js
0 → 100644
浏览文件 @
e017baf8
import
distance
from
'distancejs'
;
import
extend
from
'extend'
;
import
*
as
d3
from
'https://cdn.jsdelivr.net/npm/d3@7/+esm'
;
// hcluster
export
const
hcluster
=
()
=>
{
var
data
,
clusters
,
clustersGivenK
,
treeRoot
,
posKey
=
'position'
,
distanceName
=
'angular'
,
distanceFn
=
distance
.
angular
,
linkage
=
'avg'
,
verbose
=
false
;
//
// simple constructor
function
clust
()
{
}
//
// getters, setters a la D3
// return data or set data and build tree
clust
.
data
=
function
(
value
)
{
if
(
!
arguments
.
length
)
return
data
;
// dataset will be mutated
data
=
value
;
clust
.
_buildTree
();
return
clust
;
};
clust
.
posKey
=
function
(
value
)
{
if
(
!
arguments
.
length
)
return
posKey
;
posKey
=
value
;
return
clust
;
};
clust
.
linkage
=
function
(
value
)
{
if
(
!
arguments
.
length
)
return
linkage
;
linkage
=
value
;
return
clust
;
};
clust
.
verbose
=
function
(
value
)
{
if
(
!
arguments
.
length
)
return
verbose
;
verbose
=
value
;
return
clust
;
};
clust
.
distance
=
function
(
value
)
{
if
(
!
arguments
.
length
)
return
distanceName
;
distanceName
=
value
;
distanceFn
=
{
angular
:
distance
.
angular
,
euclidean
:
distance
.
euclidean
}[
value
]
||
distance
.
angular
;
return
clust
;
}
//
// get tree properties
clust
.
orderedNodes
=
function
()
{
if
(
!
treeRoot
)
throw
new
Error
(
'Need to passin data and build tree first.'
);
return
treeRoot
.
indexes
.
map
(
function
(
ndx
)
{
return
data
[
ndx
];
});
};
clust
.
tree
=
function
()
{
if
(
!
treeRoot
)
throw
new
Error
(
'Need to passin data and build tree first.'
);
return
treeRoot
;
};
clust
.
getClusters
=
function
(
n
)
{
if
(
!
treeRoot
)
throw
new
Error
(
'Need to passin data and build tree first.'
);
if
(
n
>
data
.
length
)
throw
new
Error
(
'n must be less than the size of the dataset'
);
return
clustersGivenK
[
data
.
length
-
n
]
.
map
(
function
(
indexes
)
{
return
indexes
.
map
(
function
(
ndx
)
{
return
data
[
ndx
];
});
});
};
//
// math, matrix utility fn's
// return unique pairs of indexes on n x n matrix above the diagonal
clust
.
_squareMatrixPairs
=
function
(
n
)
{
var
pairs
=
[];
for
(
var
row
=
0
;
row
<
n
;
row
++
)
{
for
(
var
col
=
row
+
1
;
col
<
n
;
col
++
)
{
pairs
.
push
([
row
,
col
]);
}
}
return
pairs
;
};
// average distance between set of cluster indexes
clust
.
_avgDistance
=
function
(
setA
,
setB
)
{
var
distance
=
0
;
for
(
var
ndxA
=
0
;
ndxA
<
setA
.
length
;
ndxA
++
)
{
for
(
var
ndxB
=
0
;
ndxB
<
setB
.
length
;
ndxB
++
)
{
distance
+=
data
[
setA
[
ndxA
]].
_distances
[
setB
[
ndxB
]];
}
}
return
distance
/
setA
.
length
/
setB
.
length
;
};
// min distance between set of cluster indexes
clust
.
_minDistance
=
function
(
setA
,
setB
)
{
var
distances
=
[];
for
(
var
ndxA
=
0
;
ndxA
<
setA
.
length
;
ndxA
++
)
{
for
(
var
ndxB
=
0
;
ndxB
<
setB
.
length
;
ndxB
++
)
{
distances
.
push
(
data
[
setA
[
ndxA
]].
_distances
[
setB
[
ndxB
]]);
}
}
return
distances
.
sort
()[
0
];
};
// max distance between set of cluster indexes
clust
.
_maxDistance
=
function
(
setA
,
setB
)
{
var
distances
=
[];
for
(
var
ndxA
=
0
;
ndxA
<
setA
.
length
;
ndxA
++
)
{
for
(
var
ndxB
=
0
;
ndxB
<
setB
.
length
;
ndxB
++
)
{
distances
.
push
(
data
[
setA
[
ndxA
]].
_distances
[
setB
[
ndxB
]]);
}
}
return
distances
.
sort
()[
distances
.
length
-
1
];
};
//
// tree construction
//
clust
.
_buildTree
=
function
()
{
if
(
!
data
||
!
data
.
length
)
throw
new
Error
(
'Need `data` to build tree'
);
//
var
node
,
clusterPairs
,
nearestPair
,
newCluster
;
clusters
=
[];
clustersGivenK
=
[];
treeRoot
=
{};
// calculate distances and build single datum clusters
data
.
forEach
(
function
(
d
,
ndx
)
{
d
.
_distances
=
data
.
map
(
function
(
compareTo
)
{
return
distanceFn
(
d
[
posKey
],
compareTo
[
posKey
]);
});
clusters
.
push
(
extend
(
d
,
{
height
:
0
,
indexes
:
[
ndx
]
}));
});
// for tree of n leafs, n-1 linkages
for
(
var
iter
=
0
;
iter
<
data
.
length
-
1
;
iter
++
)
{
verbose
&&
console
.
log
(
iter
+
': '
+
clusters
.
map
(
function
(
c
)
{
return
c
.
indexes
;
}).
join
(
'|'
));
// find closest pair of clusters, pair[2] is distance
clusterPairs
=
clust
.
_squareMatrixPairs
(
clusters
.
length
);
clusterPairs
.
forEach
(
function
(
pair
)
{
pair
[
2
]
=
clust
[
'_'
+
linkage
+
'Distance'
](
clusters
[
pair
[
0
]].
indexes
,
clusters
[
pair
[
1
]].
indexes
);
});
nearestPair
=
clusterPairs
.
reduce
(
function
(
pairA
,
pairB
)
{
return
pairA
[
2
]
<=
pairB
[
2
]
?
pairA
:
pairB
;
},
[
0
,
0
,
Infinity
]);
newCluster
=
{
name
:
'Node '
+
iter
,
height
:
nearestPair
[
2
],
indexes
:
clusters
[
nearestPair
[
0
]].
indexes
.
concat
(
clusters
[
nearestPair
[
1
]].
indexes
),
children
:
[
clusters
[
nearestPair
[
0
]],
clusters
[
nearestPair
[
1
]]],
};
verbose
&&
console
.
log
(
newCluster
);
clustersGivenK
.
push
(
clusters
.
map
(
function
(
c
)
{
return
c
.
indexes
;
}));
// remove merged nodes and push new node
clusters
.
splice
(
Math
.
max
(
nearestPair
[
0
],
nearestPair
[
1
]),
1
);
clusters
.
splice
(
Math
.
min
(
nearestPair
[
0
],
nearestPair
[
1
]),
1
);
clusters
.
push
(
newCluster
);
}
treeRoot
=
clusters
[
0
];
// clust._rebalanceTree(treeRoot);
};
// TODO: better rebalancing algo? ... this is just for presentation
// rebalance after tree is built (b/c it is top down operation)
// clust._rebalanceTree = function(node) {
// if(node.parent && node.parent.children && node.parent.children.length &&
// node.children && node.children.length) {
// var rightDistance = clust['_'+linkage+'Distance'](
// node.parent.children[1].indexes,
// node.children[0].indexes);
// var leftDistance = clust['_'+linkage+'Distance'](
// node.parent.children[1].indexes,
// node.children[1].indexes);
// // switch order of node.children
// if(leftDistance > rightDistance) {
// node.children = [ node.children[1], node.children[0] ];
// node.indexes = node.children[0].indexes.concat(node.children[1].indexes);
// }
// }
// if(node.children) {
// clust._rebalanceTree(node.children[0]);
// clust._rebalanceTree(node.children[1]);
// }
// };
return
clust
;
};
// root config
export
const
getRootConfig
=
(
config
,
chartData
)
=>
{
const
normalizedData
=
()
=>
{
let
minmaxes
=
d3
.
range
(
chartData
[
0
].
values
.
length
)
.
map
((
d
)
=>
[
d3
.
min
(
chartData
.
map
((
el
)
=>
el
.
values
[
d
])),
d3
.
max
(
chartData
.
map
((
el
)
=>
el
.
values
[
d
]))]);
return
chartData
.
map
((
el
)
=>
({
...
el
,
normalized
:
el
.
values
.
map
((
n
,
i
)
=>
(
n
-
minmaxes
[
i
][
0
])
/
(
minmaxes
[
i
][
1
]
-
minmaxes
[
i
][
0
]))
}));
};
const
verticalData
=
()
=>
{
return
d3
.
range
(
chartData
[
0
].
values
.
length
).
map
((
d
)
=>
({
normalized
:
normalizedData
().
map
((
el
)
=>
el
.
normalized
[
d
])
}));
};
const
clustering
=
hcluster
().
distance
(
'angular'
).
linkage
(
'avg'
).
posKey
(
'normalized'
).
data
(
normalizedData
());
const
verticalClustering
=
hcluster
().
distance
(
'angular'
).
linkage
(
'avg'
).
posKey
(
'normalized'
).
data
(
verticalData
());
const
tree
=
(
data
)
=>
{
const
root
=
d3
.
hierarchy
(
data
).
sort
((
a
,
b
)
=>
d3
.
ascending
(
a
.
height
,
b
.
height
));
root
.
dx
=
config
.
radius
;
root
.
dy
=
config
.
dendWidth
/
(
root
.
height
+
1
);
return
d3
.
cluster
()
.
size
([
config
.
heatHeight
,
config
.
dendWidth
])
.
separation
(()
=>
2
)(
root
);
};
const
vertTree
=
(
data
)
=>
{
const
root
=
d3
.
hierarchy
(
data
).
sort
((
a
,
b
)
=>
d3
.
ascending
(
a
.
height
,
b
.
height
));
root
.
dy
=
config
.
radius
;
root
.
dx
=
config
.
dendWidth
/
(
root
.
height
+
1
);
return
d3
.
cluster
()
.
size
([
config
.
heatWidth
,
config
.
dendWidth
])
.
separation
(()
=>
2
)(
root
);
};
const
root
=
tree
(
clustering
.
tree
());
const
vertRoot
=
vertTree
(
verticalClustering
.
tree
());
const
orderingx
=
vertRoot
.
leaves
().
map
((
el
)
=>
el
.
data
.
indexes
[
0
]);
return
{
root
,
vertRoot
,
orderingx
}
}
// color config
export
const
setColor
=
(
min
,
max
,
color
)
=>
{
let
colors
=
[
'#313695'
,
'#436FB1'
,
'#6BA2CB'
,
'#9BCCE2'
,
'#F0F9D8'
,
'#F0F9D8'
,
'#FEF0A9'
,
'#FDCD7E'
,
'#FA9C58'
,
'#EE613D'
,
'#D22B26'
,
'#A50026'
];
if
(
Array
.
isArray
(
color
))
{
colors
=
!!
color
.
length
?
color
:
colors
;
}
else
if
(
!!
color
)
{
colors
=
color
.
split
(
','
);
}
return
()
=>
d3
.
scaleQuantize
().
domain
([
min
,
max
]).
range
(
colors
);
};
// maxnumber minNumber
export
const
setMaxMinNumber
=
(
chartData
,
isInteger
=
true
)
=>
{
let
maxNumArr
=
[],
minNumArr
=
[],
maxNumber
=
0
,
minNumber
=
0
;
for
(
let
i
=
0
;
i
<
chartData
.
length
;
i
++
)
{
maxNumArr
.
push
(
d3
.
max
(
chartData
[
i
].
values
));
minNumArr
.
push
(
d3
.
min
(
chartData
[
i
].
values
));
}
// 最大值 最小值
maxNumber
=
isInteger
?
Math
.
round
(
d3
.
max
(
maxNumArr
))
:
d3
.
max
(
maxNumArr
);
minNumber
=
isInteger
?
Math
.
round
(
d3
.
min
(
minNumArr
))
:
d3
.
min
(
minNumArr
);
return
{
maxNumber
,
minNumber
}
}
// tips
export
const
setTips
=
(
rect
)
=>
{
const
tips
=
d3
.
select
(
'.tip'
)
.
style
(
'visibility'
,
'hidden'
)
.
style
(
'position'
,
'relative'
)
.
style
(
'background-color'
,
'rgba(0, 0, 0, .8)'
)
.
style
(
'color'
,
'#fff'
)
.
style
(
'border-radius'
,
'5px'
)
.
style
(
'width'
,
'200px'
)
.
style
(
'text-align'
,
'center'
)
.
style
(
'height'
,
'20px'
)
.
style
(
'padding'
,
'5px'
);
rect
.
on
(
'mouseover'
,
(
event
,
d
)
=>
{
tips
.
style
(
'visibility'
,
'visible'
);
})
.
on
(
'mousemove'
,
function
(
event
,
d
)
{
tips
.
style
(
'visibility'
,
'visible'
)
.
style
(
'left'
,
event
.
offsetX
+
15
+
'px'
)
.
style
(
'top'
,
event
.
offsetY
+
50
+
'px'
)
.
html
(
`
${
d
}
`
);
})
.
on
(
'mouseleave'
,
function
()
{
tips
.
style
(
'visibility'
,
'hidden'
);
});
};
// heatmap
export
const
setHeatmap
=
(
config
)
=>
{
return
config
.
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
+
config
.
dendWidth
}
,
${
config
.
margin
+
config
.
dendWidth
*
2
}
)`
)
.
selectAll
(
'g'
)
.
data
(
config
.
root
.
leaves
())
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(0,
${
d
.
x
-
config
.
radius
}
)`
)
.
selectAll
(
'rect'
)
.
data
((
d
)
=>
d
.
data
.
values
.
map
((
e
,
i
)
=>
d
.
data
.
values
[
config
.
orderingx
[
i
]]))
.
join
(
'rect'
)
.
attr
(
'x'
,
(
d
,
i
)
=>
i
*
2
*
config
.
radius
)
.
attr
(
'y'
,
0
)
.
attr
(
'width'
,
2
*
config
.
radius
)
.
attr
(
'height'
,
2
*
config
.
radius
)
.
attr
(
'fill'
,
config
.
color
());
};
// Basis heatmap
export
const
setBasisHeatmap
=
(
config
)
=>
{
return
config
.
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
+
config
.
dendWidth
}
,
${
config
.
margin
}
)`
)
.
selectAll
(
'g'
)
.
data
(
config
.
root
.
leaves
())
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(0,
${
130
+
config
.
radius
*
2
*
i
}
)`
)
.
selectAll
(
'rect'
)
.
data
((
d
)
=>
d
.
data
.
values
.
map
((
e
,
i
)
=>
d
.
data
.
values
[
config
.
orderingx
[
i
]]))
.
join
(
'rect'
)
.
attr
(
'x'
,
(
d
,
i
)
=>
i
*
2
*
config
.
radius
)
.
attr
(
'y'
,
0
)
.
attr
(
'width'
,
2
*
config
.
radius
)
.
attr
(
'height'
,
2
*
config
.
radius
)
.
attr
(
'fill'
,
config
.
color
());
};
// Consensus heatmap
export
const
setConsensusHeatmap
=
(
config
)
=>
{
return
config
.
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
+
config
.
dendWidth
}
,
${
config
.
margin
}
)`
)
.
selectAll
(
'g'
)
.
data
(
config
.
root
.
leaves
())
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(0,
${
150
+
config
.
radius
*
2
*
i
}
)`
)
.
selectAll
(
'rect'
)
.
data
((
d
)
=>
d
.
data
.
values
.
map
((
e
,
i
)
=>
d
.
data
.
values
[
config
.
orderingx
[
i
]]))
.
join
(
'rect'
)
.
attr
(
'x'
,
(
d
,
i
)
=>
i
*
2
*
config
.
radius
)
.
attr
(
'y'
,
0
)
.
attr
(
'width'
,
2
*
config
.
radius
)
.
attr
(
'height'
,
2
*
config
.
radius
)
.
attr
(
'fill'
,
config
.
color
());
};
// Silhouette heatmap
export
const
setSilhouetteHeatmap
=
(
config
)
=>
{
return
config
.
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
+
config
.
dendWidth
}
,
${
config
.
margin
*
3
}
)`
)
.
selectAll
(
'g'
)
.
data
(
config
.
root
.
leaves
())
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(0,
${
150
+
config
.
radius
*
2
*
i
}
)`
)
.
selectAll
(
'rect'
)
.
data
((
d
)
=>
d
.
data
.
values
.
map
((
e
,
i
)
=>
d
.
data
.
values
[
config
.
orderingx
[
i
]]))
.
join
(
'rect'
)
.
attr
(
'x'
,
(
d
,
i
)
=>
i
*
2
*
config
.
radius
)
.
attr
(
'y'
,
0
)
.
attr
(
'width'
,
2
*
config
.
radius
)
.
attr
(
'height'
,
2
*
config
.
radius
)
.
attr
(
'fill'
,
d
=>
d3
.
interpolateGreens
(
d
));
};
// tree
export
const
setTree
=
(
config
)
=>
{
// left tree
config
.
svg
.
append
(
'g'
)
.
attr
(
'fill'
,
'none'
)
.
attr
(
'stroke'
,
'#000'
)
.
attr
(
'stroke-width'
,
1
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
}
,
${
config
.
margin
+
config
.
dendWidth
*
2
}
)`
)
.
selectAll
(
'path'
)
.
data
(
config
.
root
.
links
())
.
join
(
'path'
)
.
attr
(
'd'
,
(
d
)
=>
`
M
${
d
.
target
.
y
}
,
${
d
.
target
.
x
}
L
${
d
.
source
.
y
}
,
${
d
.
target
.
x
}
${
d
.
source
.
y
}
,
${
d
.
source
.
x
}
${
d
.
source
.
y
}
,
${
d
.
source
.
x
}
`
);
// top tree
config
.
svg
.
append
(
'g'
)
.
attr
(
'fill'
,
'none'
)
.
attr
(
'stroke'
,
'#555'
)
.
attr
(
'stroke-width'
,
1
)
.
attr
(
'transform'
,
`translate(
${
config
.
margin
+
config
.
dendWidth
}
,
${
config
.
margin
*
3
}
)`
)
.
selectAll
(
'path'
)
.
data
(
config
.
vertRoot
.
links
())
.
join
(
'path'
)
.
attr
(
'd'
,
(
d
)
=>
`
M
${
d
.
target
.
x
}
,
${
d
.
target
.
y
}
L
${
d
.
target
.
x
}
,
${
d
.
source
.
y
}
${
d
.
source
.
x
}
,
${
d
.
source
.
y
}
${
d
.
source
.
x
}
,
${
d
.
source
.
y
}
`
);
};
// legend
export
const
setLegend
=
(
config
)
=>
{
const
legendData
=
[...
Array
.
from
({
length
:
config
.
maxNumber
},
(
item
,
i
)
=>
i
)];
config
.
svg
.
append
(
'g'
)
.
selectAll
()
.
data
(
legendData
)
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
,
nodes
)
=>
`translate(
${
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
80
}
,
${
config
.
height
/
3
+
(
nodes
.
length
/
2
-
i
-
1
)
*
18
-
60
}
)`
)
.
call
((
g
)
=>
g
.
append
(
'rect'
).
attr
(
'width'
,
18
).
attr
(
'height'
,
18
).
attr
(
'fill'
,
config
.
color
()))
.
call
((
g
)
=>
g
.
append
(
'text'
)
.
attr
(
'x'
,
20
)
.
attr
(
'y'
,
10
)
.
attr
(
'dy'
,
'0.3em'
)
.
style
(
'font'
,
'13px sans-serif'
)
.
text
((
d
)
=>
d
)
);
};
// Basis legend
export
const
setBasisLegend
=
(
config
)
=>
{
const
legendData
=
[...
Array
.
from
({
length
:
config
.
maxNumber
},
(
item
,
i
)
=>
i
)];
const
textX
=
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
180
config
.
svg
.
append
(
'text'
)
.
attr
(
'x'
,
textX
)
.
attr
(
'y'
,
config
.
height
/
3
-
110
)
.
attr
(
'fill'
,
config
.
titleConfig
.
color
)
.
attr
(
'font-size'
,
`
${
config
.
titleConfig
.
fontSize
}
px`
)
.
attr
(
'font-family'
,
`
${
config
.
titleConfig
.
fontFamily
}
`
)
.
attr
(
'font-style'
,
`
${
config
.
titleConfig
.
fontStyle
}
`
)
.
attr
(
'font-weight'
,
`
${
config
.
titleConfig
.
fontWeight
}
`
)
.
style
(
'text-anchor'
,
'middle'
)
.
text
(
'basis'
);
config
.
svg
.
append
(
'g'
)
.
selectAll
()
.
data
(
legendData
)
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
,
nodes
)
=>
`translate(
${
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
160
}
,
${
config
.
height
/
3
+
(
nodes
.
length
/
2
-
i
-
1
)
*
21
-
50
}
)`
)
.
call
((
g
)
=>
g
.
append
(
'rect'
).
attr
(
'width'
,
15
).
attr
(
'height'
,
15
).
attr
(
'fill'
,
config
.
color
()))
.
call
((
g
)
=>
g
.
append
(
'text'
)
.
attr
(
'x'
,
20
)
.
attr
(
'y'
,
9
)
.
attr
(
'dy'
,
'0.3em'
)
.
style
(
'font'
,
'13px sans-serif'
)
.
text
((
d
)
=>
d
)
);
}
// Consensus legend
export
const
setConsensusLegend
=
(
config
)
=>
{
const
legendData
=
[...
Array
.
from
({
length
:
config
.
maxNumber
},
(
item
,
i
)
=>
i
)];
const
textX
=
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
205
config
.
svg
.
append
(
'text'
)
.
attr
(
'x'
,
textX
)
.
attr
(
'y'
,
config
.
height
/
3
+
50
)
.
attr
(
'fill'
,
config
.
titleConfig
.
color
)
.
attr
(
'font-size'
,
`
${
config
.
titleConfig
.
fontSize
}
px`
)
.
attr
(
'font-family'
,
`
${
config
.
titleConfig
.
fontFamily
}
`
)
.
attr
(
'font-style'
,
`
${
config
.
titleConfig
.
fontStyle
}
`
)
.
attr
(
'font-weight'
,
`
${
config
.
titleConfig
.
fontWeight
}
`
)
.
style
(
'text-anchor'
,
'middle'
)
.
text
(
'consensus'
);
config
.
svg
.
append
(
'g'
)
.
selectAll
()
.
data
(
legendData
)
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
,
nodes
)
=>
`translate(
${
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
160
}
,
${
config
.
height
/
3
+
(
nodes
.
length
/
2
-
i
-
1
)
*
21
+
110
}
)`
)
.
call
((
g
)
=>
g
.
append
(
'rect'
).
attr
(
'width'
,
15
).
attr
(
'height'
,
15
).
attr
(
'fill'
,
config
.
color
()))
.
call
((
g
)
=>
g
.
append
(
'text'
)
.
attr
(
'x'
,
20
)
.
attr
(
'y'
,
9
)
.
attr
(
'dy'
,
'0.3em'
)
.
style
(
'font'
,
'13px sans-serif'
)
.
text
((
d
)
=>
d
)
);
}
// Silhouette legend
export
const
setSilhouetteLegend
=
(
config
)
=>
{
const
textX
=
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
200
const
legendData
=
[
config
.
maxNumber
,
config
.
minNumber
]
config
.
svg
.
append
(
'text'
)
.
attr
(
'x'
,
textX
)
.
attr
(
'y'
,
config
.
height
/
3
+
210
)
.
attr
(
'fill'
,
config
.
titleConfig
.
color
)
.
attr
(
'font-size'
,
`
${
config
.
titleConfig
.
fontSize
}
px`
)
.
attr
(
'font-family'
,
`
${
config
.
titleConfig
.
fontFamily
}
`
)
.
attr
(
'font-style'
,
`
${
config
.
titleConfig
.
fontStyle
}
`
)
.
attr
(
'font-weight'
,
`
${
config
.
titleConfig
.
fontWeight
}
`
)
.
style
(
'text-anchor'
,
'middle'
)
.
text
(
'silhouette'
);
config
.
svg
.
append
(
'g'
)
.
selectAll
()
.
data
(
legendData
)
.
join
(
'text'
)
.
attr
(
'x'
,
textX
+
20
)
.
attr
(
'y'
,
(
d
,
i
)
=>
config
.
height
/
3
+
i
*
40
+
240
)
.
attr
(
'fill'
,
config
.
titleConfig
.
color
)
.
attr
(
'font-style'
,
`
${
config
.
titleConfig
.
fontStyle
}
`
)
.
attr
(
'font-weight'
,
`
${
config
.
titleConfig
.
fontWeight
}
`
)
.
style
(
'font'
,
'13px sans-serif'
)
.
style
(
'text-anchor'
,
'middle'
)
.
text
((
d
)
=>
d
);
const
gradient
=
config
.
svg
.
append
(
'defs'
)
.
append
(
'linearGradient'
)
.
attr
(
'id'
,
'mylLnearGradient'
)
.
attr
(
'x1'
,
'0%'
)
.
attr
(
'y1'
,
'0%'
)
.
attr
(
'x2'
,
'0%'
)
.
attr
(
'y2'
,
'100%'
)
.
attr
(
'spreadMethod'
,
'pad'
);
gradient
.
append
(
'stop'
)
.
attr
(
'offset'
,
'0%'
)
.
attr
(
'stop-color'
,
'rgb(0,128,0,1)'
)
.
attr
(
'stop-opacity'
,
1
);
gradient
.
append
(
'stop'
)
.
attr
(
'offset'
,
'100%'
)
.
attr
(
'stop-color'
,
'rgb(0,128,0,0.1)'
)
.
attr
(
'stop-opacity'
,
1
);
config
.
svg
.
append
(
'rect'
)
.
attr
(
'width'
,
'15'
)
.
attr
(
'height'
,
'60'
)
.
attr
(
"fill"
,
"url(#mylLnearGradient)"
)
.
attr
(
"x"
,
`
${
config
.
dendWidth
+
config
.
xAxisLength
*
(
config
.
radius
*
2
)
+
160
}
`
)
.
attr
(
"y"
,
`
${
config
.
height
/
3
+
225
}
`
)
}
// 标签
export
const
setAxisTitle
=
(
config
)
=>
{
const
labelList
=
config
.
root
.
leaves
().
map
((
item
)
=>
item
.
data
.
id
);
config
.
svg
.
append
(
'g'
)
.
selectAll
(
'g'
)
.
data
(
labelList
)
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
)
=>
`translate(
${
config
.
margin
+
config
.
dendWidth
+
config
.
xAxisLength
*
2
*
config
.
radius
+
4
}
,
${
config
.
margin
+
config
.
dendWidth
*
2
+
i
*
2
*
config
.
radius
+
4
}
)`
)
.
call
((
g
)
=>
g
.
append
(
'text'
)
.
attr
(
'x'
,
0
)
.
attr
(
'y'
,
0
)
.
attr
(
'dy'
,
'0.35em'
)
.
style
(
'font'
,
`6px sans-serif`
)
.
style
(
'fill'
,
`#000`
)
.
text
((
d
)
=>
d
)
);
};
// 标题
export
const
setLabel
=
(
config
)
=>
{
config
.
svg
.
append
(
'text'
)
.
attr
(
'x'
,
config
.
width
/
3
)
.
attr
(
'y'
,
0
)
.
attr
(
'fill'
,
config
.
titleConfig
.
color
)
.
attr
(
'font-size'
,
`
${
config
.
titleConfig
.
fontSize
}
px`
)
.
attr
(
'font-family'
,
`
${
config
.
titleConfig
.
fontFamily
}
`
)
.
attr
(
'font-style'
,
`
${
config
.
titleConfig
.
fontStyle
}
`
)
.
attr
(
'font-weight'
,
`
${
config
.
titleConfig
.
fontWeight
}
`
)
.
style
(
'text-anchor'
,
'middle'
)
.
text
(
'Consensus matrix'
);
};
src/views/home/index.vue
浏览文件 @
e017baf8
...
...
@@ -19,7 +19,7 @@ import ClusterHeatmap from '../../components/ClusterHeatmap/index.vue';
import
CircularHeatmap
from
'../../components/CircularHeatmap/index.vue'
;
import
Test
from
'../../components/Test/index.vue'
;
const
chartCurrent
=
ref
(
0
);
const
chartCurrent
=
ref
(
6
);
const
chartList
=
shallowRef
([
{
title
:
'线性拟合图'
,
value
:
1
,
comName
:
LinearFitting
},
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论