Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
chart-project
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
czj
chart-project
Commits
ad01d3f6
提交
ad01d3f6
authored
12月 11, 2023
作者:
祖铭松
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 相关性分析
上级
02b21257
全部展开
显示空白字符变更
内嵌
并排
正在显示
15 个修改的文件
包含
449 行增加
和
430 行删除
+449
-430
chart.vue
src/components/CircularHeatmap/components/chart.vue
+1
-0
chart.vue
src/components/ClusterHeatmap/components/chart.vue
+0
-1
index.js
src/components/ClusterHeatmap/utils/index.js
+2
-1
hcluster.js
src/components/ClusterHeatmapSecond/utils/hcluster.js
+0
-214
index.js
src/components/ClusterHeatmapSecond/utils/index.js
+2
-1
chart.vue
src/components/CorrelationAnalysis/components/chart.vue
+115
-131
config.vue
src/components/CorrelationAnalysis/components/config.vue
+13
-33
mock.js
src/components/CorrelationAnalysis/mock.js
+0
-0
index.js
src/components/CorrelationAnalysis/utils/index.js
+262
-0
config.vue
src/components/MsDimplot/components/config.vue
+5
-1
index.vue
src/components/Test/index.vue
+49
-48
mock.js
src/components/Test/mock.js
+0
-0
utils.js
src/components/Test/utils.js
+0
-0
hcluster.js
src/utils/hcluster.js
+0
-0
index.vue
src/views/home/index.vue
+0
-0
没有找到文件。
src/components/CircularHeatmap/components/chart.vue
浏览文件 @
ad01d3f6
...
...
@@ -451,6 +451,7 @@ const setTips = (rect) => {
.
style
(
'width'
,
'80px'
)
.
style
(
'text-align'
,
'center'
)
.
style
(
'height'
,
'20px'
)
.
style
(
'line-height'
,
'20px'
)
.
style
(
'padding'
,
'5px'
);
rect
.
on
(
'mouseover'
,
(
event
,
d
)
=>
{
...
...
src/components/ClusterHeatmap/components/chart.vue
浏览文件 @
ad01d3f6
...
...
@@ -27,7 +27,6 @@ import {
setSilhouetteHeatmap
,
setSilhouetteLegend
}
from
'../utils/index'
;
import
{
config
}
from
'plotly.js-dist'
;
const
chartRef
=
ref
(
null
);
...
...
src/components/ClusterHeatmap/utils/index.js
浏览文件 @
ad01d3f6
import
hcluster
from
'./hcluster'
;
import
hcluster
from
'.
./../../utils
/hcluster'
;
import
*
as
d3
from
'https://cdn.jsdelivr.net/npm/d3@7/+esm'
;
// root config
...
...
@@ -107,6 +107,7 @@ export const setTips = (rect) => {
.
style
(
'width'
,
'200px'
)
.
style
(
'text-align'
,
'center'
)
.
style
(
'height'
,
'20px'
)
.
style
(
'line-height'
,
'20px'
)
.
style
(
'padding'
,
'5px'
);
rect
.
on
(
'mouseover'
,
(
event
,
d
)
=>
{
...
...
src/components/ClusterHeatmapSecond/utils/hcluster.js
deleted
100644 → 0
浏览文件 @
02b21257
import
distance
from
'distancejs'
;
import
extend
from
'extend'
;
/**
* hcluster
* @returns
*/
export
default
function
()
{
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
;
}
\ No newline at end of file
src/components/ClusterHeatmapSecond/utils/index.js
浏览文件 @
ad01d3f6
import
hcluster
from
'./hcluster'
;
import
hcluster
from
'.
./../../utils
/hcluster'
;
import
*
as
d3
from
'https://cdn.jsdelivr.net/npm/d3@7/+esm'
;
// root config
...
...
@@ -107,6 +107,7 @@ export const setTips = (rect) => {
.
style
(
'width'
,
'200px'
)
.
style
(
'text-align'
,
'center'
)
.
style
(
'height'
,
'20px'
)
.
style
(
'line-height'
,
'20px'
)
.
style
(
'padding'
,
'5px'
);
rect
.
on
(
'mouseover'
,
(
event
,
d
)
=>
{
...
...
src/components/CorrelationAnalysis/components/chart.vue
浏览文件 @
ad01d3f6
<
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
}
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
Plotly
from
'plotly.js-dist'
;
import
{
setTips
,
setMaxMinNumber
,
setLegend
,
setScale
,
setAxis
,
setRect
,
setTopLeftColor
,
getRootConfig
,
setTree
,
setLabel
}
from
'../utils/index'
;
// 根节点实例
const
chartRef
=
ref
(
null
);
// 配置项数据
const
options
=
ref
({});
// 图表实例
const
svgInstance
=
ref
(
null
);
// pubsub实例
const
pubSubInstance
=
ref
(
null
);
// const mackData = [
// {
// z: [
// [1, null, 30, 50, 1],
// [20, 1, 60, 80, 30],
// [30, 60, 1, -10, 20]
// ],
// x: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
// y: ['Morning', 'Afternoon', 'Evening'],
// type: 'heatmap',
// hoverongaps: false
// }
// ];
// 配色
const
generateColorConfig
=
(
color
)
=>
{
if
(
!
color
)
return
false
;
let
colors
=
[];
if
(
Array
.
isArray
(
color
))
{
colors
=
color
;
}
else
{
colors
=
color
.
split
(
','
);
}
return
colors
;
};
// 生成图表
const
generateChart
=
(
data
)
=>
{
const
ret
=
options
.
value
;
// 生成数据
const
generateData
=
()
=>
{
let
z
=
[],
x
=
[],
y
=
[];
let
width
=
Number
(
ret
.
chart_width
)
||
1000
;
let
height
=
Number
(
ret
.
chart_height
)
||
700
;
let
marginTop
=
Number
(
ret
.
margin_top
)
||
120
;
let
marginRight
=
Number
(
ret
.
margin_Right
)
||
120
;
let
marginBottom
=
Number
(
ret
.
margin_Bottom
)
||
60
;
let
marginLeft
=
Number
(
ret
.
margin_Left
)
||
120
;
let
legendPosition
=
ret
.
legend_position
?.
split
(
','
)
||
[
0
,
0
];
let
legendData
=
[
0.8
,
0.85
,
0.9
,
0.95
,
1
];
let
dendWidth
=
100
;
let
heatWidth
=
width
-
marginLeft
-
marginRight
;
let
colorList
=
[
[
'#3DD378'
,
'#EC0B88'
,
'#444444'
,
'#5E35B1'
,
'#F9791E'
,
'#C6C6C6'
,
'#F7DC05'
,
'#3D98D3'
],
[
'#017A4A'
,
'#FFCE4E'
,
'#3D98D3'
,
'#FF363C'
,
'#794924'
,
'#8CDB5E'
,
'#D6D6D6'
,
'#FB8C00'
]
];
chartData
.
forEach
((
r
)
=>
{
z
.
push
([
r
.
CD4N_1
,
r
.
CD4N_2
,
r
.
CD4N_3
,
r
.
CD4P_1
,
r
.
CD4P_2
,
r
.
CD4P_3
]);
});
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'
};
x
=
Object
.
keys
(
chartData
[
0
]);
y
=
Object
.
keys
(
chartData
[
0
]);
const
svg
=
d3
.
create
(
'svg'
).
attr
(
'width'
,
width
).
attr
(
'height'
,
height
);
let
configObj
=
{
...
ret
,
svg
,
width
,
height
,
marginTop
,
marginRight
,
marginBottom
,
marginLeft
,
dendWidth
,
titleConfig
,
legendData
,
colorList
,
heatWidth
,
legendPosition
};
return
[
{
z
,
x
,
y
,
type
:
'heatmap'
,
hoverongaps
:
false
}
];
setChart
(
configObj
,
data
);
svgInstance
.
value
=
svg
.
node
();
// Append the SVG element.
chartRef
.
value
.
appendChild
(
svgInstance
.
value
);
};
// 生成图表
const
generateChart
=
(
data
)
=>
{
const
ret
=
options
.
value
;
//图例位置数组
const
legend_position
=
ret
.
legend_position
?.
split
(
','
)
||
'0,0'
;
const
color_ls
=
generateColorConfig
(
ret
.
data_color_list
);
const
layout
=
{
width
:
ret
.
chart_width
,
height
:
ret
.
chart_height
,
showlegend
:
ret
.
show_legend
,
legend
:
{
x
:
Number
(
legend_position
[
0
]),
// 设置图例水平位置,范围从0到1,0表示左侧,1表示右侧,0.5表示水平居中
y
:
Number
(
legend_position
[
1
]),
// 设置图例垂直位置,范围从0到1,0表示底部,1表示顶部,0.5表示垂直居中
font
:
{
family
:
'Arial, sans-serif'
,
// 设置图例字体样式
size
:
16
,
// 设置图例字体大小(以像素为单位)
color
:
'green'
// 设置图例字体颜色
}
},
title
:
{
text
:
ret
.
title
,
font
:
{
family
:
ret
.
title_font_family
,
// 设置字体家族
size
:
ret
.
title_font_size
,
// 设置字体大小(以像素为单位)
color
:
ret
.
title_font_color
,
// 设置字体颜色
weight
:
ret
.
title_font_weight
//字体粗细
},
// xanchor: 'center', // 设置标题在水平中央
// yanchor: 'center' // 设置标题在垂直顶部
x
:
0.5
,
// 设置水平位置,0表示左侧,0.5表示居中,1表示右侧
y
:
0.99
// 设置垂直位置,0表示底部,0.5表示居中,1表示顶部
},
margin
:
{
t
:
Number
(
ret
.
margin_top
),
b
:
Number
(
ret
.
margin_bottom
),
l
:
Number
(
ret
.
margin_left
),
r
:
Number
(
ret
.
margin_right
)
},
xaxis
:
{
visible
:
ret
.
show_x_axis
,
title
:
{
text
:
ret
.
show_x_title
?
ret
.
x_title
:
''
,
font
:
{
family
:
ret
.
xtitle_font_family
,
// 设置字体家族
size
:
Number
(
ret
.
xtitle_font_size
),
// 设置字体大小(以像素为单位)
color
:
ret
.
xtitle_font_color
,
// 设置字体颜色
weight
:
'bold'
//字体粗细
},
// xanchor: 'left', // 设置标题在水平中央
// yanchor: 'center', // 设置标题在垂直顶部
x
:
0.1
},
showgrid
:
ret
.
show_x_gridLine
,
// 显示 x 轴网格线
showline
:
ret
.
show_x_line
,
// 显示 x 轴线
showticklabels
:
true
,
ticks
:
ret
.
show_x_tickMarks
?
'outside'
:
''
// 将刻度线朝外显示\inside 向内
},
yaxis
:
{
visible
:
ret
.
show_y_axis
,
title
:
{
text
:
ret
.
show_y_title
?
ret
.
y_title
:
''
,
font
:
{
family
:
ret
.
ytitle_font_family
,
// 设置字体家族
size
:
Number
(
ret
.
ytitle_font_size
),
// 设置字体大小(以像素为单位)
color
:
ret
.
ytitle_font_color
,
// 设置字体颜色
weight
:
ret
.
ytitle_font_weight
//字体粗细
},
xanchor
:
'center'
,
// 设置标题在水平中央
yanchor
:
'center'
// 设置标题在垂直顶部
},
showgrid
:
ret
.
show_y_gridLine
,
// 隐藏 y 轴网格线
showline
:
ret
.
show_y_line
,
// 隐藏 y 轴线
showticklabels
:
true
,
// 显示 x 轴上的刻度标签
ticks
:
ret
.
show_y_tickMarks
?
'outside'
:
''
// 将刻度线朝外显示/inside 向内
}
const
setChart
=
(
config
,
data
)
=>
{
const
{
maxNumber
,
minNumber
}
=
setMaxMinNumber
(
data
);
const
color
=
d3
.
scaleSequential
([
minNumber
,
maxNumber
],
d3
.
interpolateMagma
);
const
categories
=
data
.
map
((
d
)
=>
d
.
index
);
const
{
x
,
y
}
=
setScale
(
config
,
categories
);
const
newArr
=
data
.
map
((
d
)
=>
Object
.
keys
(
d
).
map
((
e
)
=>
d
[
e
])).
map
((
item
)
=>
({
index
:
item
[
0
],
values
:
item
.
slice
(
1
)
}));
const
{
root
}
=
getRootConfig
(
config
,
newArr
);
let
configObj
=
{
...
config
,
root
,
categories
,
color
,
x
,
y
};
Plotly
.
newPlot
(
chartRef
.
value
,
data
,
layout
,
{
displayModeBar
:
false
,
showSendToCloud
:
true
});
// rects
const
rects
=
setRect
(
configObj
,
data
);
// tips
setTips
(
rects
);
// axis
setAxis
(
configObj
);
// topLeftColor
setTopLeftColor
(
configObj
,
data
);
// legend
config
.
show_legend
&&
setLegend
(
configObj
);
// tree
setTree
(
configObj
);
// label
setLabel
(
configObj
);
};
onMounted
(()
=>
{
const
mackData
=
generateData
(
chartData
);
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
(()
=>
{
...
...
@@ -164,4 +144,8 @@ onUnmounted(() => {
});
</
script
>
<
style
scoped
></
style
>
<
style
scoped
>
.chart-box
{
position
:
relative
;
}
</
style
>
src/components/CorrelationAnalysis/components/config.vue
浏览文件 @
ad01d3f6
...
...
@@ -26,6 +26,10 @@
<input
type=
"text"
v-model=
"dynamic_parameter.margin_left"
/>
</div>
<h3
class=
"type content"
>
文本
</h3>
<div
class=
"form-item"
>
<span>
标题:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.title"
/>
</div>
<div
class=
"form-item"
>
<span>
字体:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.title_font_family"
/>
...
...
@@ -55,14 +59,6 @@
<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"
/>
...
...
@@ -87,10 +83,6 @@
<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>
...
...
@@ -100,14 +92,6 @@
<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"
/>
...
...
@@ -132,10 +116,6 @@
<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>
...
...
@@ -158,30 +138,30 @@ import PubSub from 'pubsub-js';
//动态图参数,固定参数
const
dynamic_parameter
=
reactive
({
//长宽间距
chart_width
:
8
00
,
chart_height
:
6
00
,
margin_top
:
6
0
,
margin_right
:
6
0
,
chart_width
:
10
00
,
chart_height
:
7
00
,
margin_top
:
18
0
,
margin_right
:
12
0
,
margin_bottom
:
60
,
margin_left
:
6
0
,
margin_left
:
12
0
,
//标题配置
title
:
''
,
title
:
'
相关性分析
'
,
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
,
xtitle_font_style
:
false
,
xtitle_font_size
:
1
6
,
xtitle_font_size
:
1
1
,
xtitle_font_color
:
'#333333'
,
//纵轴标题
ytitle_font_family
:
'Arial'
,
ytitle_font_weight
:
false
,
ytitle_font_style
:
false
,
ytitle_font_size
:
1
6
,
ytitle_font_size
:
1
1
,
ytitle_font_color
:
'#333333'
,
//颜色设置
...
...
src/components/CorrelationAnalysis/mock.js
浏览文件 @
ad01d3f6
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/components/CorrelationAnalysis/utils/index.js
0 → 100644
浏览文件 @
ad01d3f6
import
*
as
d3
from
'https://cdn.jsdelivr.net/npm/d3@7/+esm'
;
import
hcluster
from
'../../../utils/hcluster'
;
// max min
export
const
setMaxMinNumber
=
(
data
)
=>
{
const
newArr
=
data
.
map
((
d
)
=>
Object
.
keys
(
d
).
map
((
e
)
=>
d
[
e
])).
map
((
f
)
=>
f
.
slice
(
1
))
let
maxNumArr
=
[],
minNumArr
=
[],
maxNumber
=
0
,
minNumber
=
0
;
for
(
let
i
=
0
;
i
<
newArr
.
length
;
i
++
)
{
maxNumArr
.
push
(
d3
.
max
(
newArr
[
i
]));
minNumArr
.
push
(
d3
.
min
(
newArr
[
i
]));
}
// 最大值 最小值
maxNumber
=
d3
.
max
(
maxNumArr
);
minNumber
=
d3
.
min
(
minNumArr
);
return
{
maxNumber
,
minNumber
}
}
// scale
export
const
coordinateScale
=
(
config
,
data
)
=>
{
const
x
=
d3
.
scaleLinear
()
.
domain
([
config
.
paddedMin
,
config
.
paddedMax
])
.
range
([
config
.
marginLeft
,
config
.
width
-
config
.
marginRight
]);
const
y
=
d3
.
scaleLinear
()
.
domain
(
d3
.
extent
(
data
,
(
d
)
=>
d
.
y
))
.
range
([
config
.
rectHeight
,
config
.
marginTop
+
30
]);
return
{
x
,
y
}
}
// 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'
,
'80px'
)
.
style
(
'height'
,
'25px'
)
.
style
(
'line-height'
,
'25px'
)
.
style
(
'text-align'
,
'center'
)
.
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
+
55
+
'px'
)
.
html
(
`
${
d
.
count
}
`
);
})
.
on
(
'mouseleave'
,
function
()
{
tips
.
style
(
'visibility'
,
'hidden'
);
});
};
// legend
export
const
setLegend
=
(
config
)
=>
{
config
.
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${(
config
.
width
-
100
)
*
config
.
legendPosition
[
0
]}
,
${(
config
.
height
-
100
)
*
config
.
legendPosition
[
1
]}
)`
)
.
selectAll
()
.
data
(
config
.
legendData
)
.
join
(
'g'
)
.
attr
(
'transform'
,
(
d
,
i
,
nodes
)
=>
`translate(0,
${(
nodes
.
length
-
i
)
*
20
-
20
}
)`
)
.
call
((
g
)
=>
g
.
append
(
'rect'
).
attr
(
'width'
,
40
).
attr
(
'height'
,
20
).
attr
(
'fill'
,
d
=>
config
.
color
(
d
)))
.
call
((
g
)
=>
g
.
append
(
'text'
)
.
attr
(
'x'
,
45
)
.
attr
(
'y'
,
11
)
.
attr
(
'dy'
,
'0.3em'
)
.
style
(
'font'
,
'13px sans-serif'
)
.
text
((
d
)
=>
d
)
);
};
// topLeft Color
export
const
setTopLeftColor
=
(
config
,
data
)
=>
{
config
.
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${
config
.
marginLeft
}
,
${
config
.
marginTop
-
20
}
)`
)
.
selectAll
()
.
data
(
data
)
.
join
(
'g'
)
.
append
(
'rect'
)
.
attr
(
'x'
,
(
d
,
i
)
=>
config
.
x
.
bandwidth
()
*
i
)
.
attr
(
'y'
,
0
)
.
attr
(
'width'
,
config
.
x
.
bandwidth
())
.
attr
(
'height'
,
20
)
.
style
(
'fill'
,
(
d
,
i
)
=>
config
.
colorList
[
0
][
i
]);
config
.
svg
.
append
(
'g'
)
.
attr
(
'transform'
,
`translate(
${
config
.
marginLeft
-
20
}
,
${
config
.
marginTop
}
)`
)
.
selectAll
()
.
data
(
data
)
.
join
(
'g'
)
.
append
(
'rect'
)
.
attr
(
'x'
,
(
d
,
i
)
=>
0
)
.
attr
(
'y'
,
(
d
,
i
)
=>
config
.
y
.
bandwidth
()
*
i
)
.
attr
(
'width'
,
20
)
.
attr
(
'height'
,
config
.
y
.
bandwidth
())
.
style
(
'fill'
,
(
d
,
i
)
=>
config
.
colorList
[
1
][
i
]);
}
// scale
export
const
setScale
=
(
config
,
categories
)
=>
{
const
x
=
d3
.
scaleBand
()
.
domain
(
categories
)
.
range
([
config
.
marginLeft
,
config
.
width
-
config
.
marginRight
]);
const
y
=
d3
.
scaleBand
()
.
domain
([...
categories
].
reverse
())
.
range
([
config
.
height
-
config
.
marginBottom
,
config
.
marginTop
]);
return
{
x
,
y
}
}
// axis
export
const
setAxis
=
(
config
)
=>
{
const
xAxis
=
(
g
)
=>
g
.
attr
(
'transform'
,
`translate(0,
${
config
.
height
-
config
.
marginBottom
}
)`
)
.
style
(
'font'
,
`
${
config
.
xtitle_font_size
}
px
${
config
.
xtitle_font_family
}
`
)
.
style
(
'color'
,
`
${
config
.
xtitle_font_color
}
`
)
.
style
(
'font-weight'
,
`
${
config
.
xtitle_font_weight
?
'bold'
:
'normal'
}
`
)
.
style
(
'font-style'
,
`
${
config
.
xtitle_font_style
?
'oblique'
:
'normal'
}
`
)
.
call
(
d3
.
axisBottom
(
config
.
x
).
tickSize
(
Number
(
config
.
show_x_tickMarks
?
config
.
x_tickMarks_length
:
0
)))
.
call
((
g
)
=>
g
.
selectAll
(
'.domain'
).
remove
())
.
selectAll
(
'text'
)
.
style
(
'text-anchor'
,
'middle'
);
const
yAxis
=
(
g
)
=>
g
.
attr
(
'transform'
,
`translate(
${
config
.
width
-
config
.
marginRight
}
, 0)`
)
.
style
(
'font'
,
`
${
config
.
ytitle_font_size
}
px
${
config
.
ytitle_font_family
}
`
)
.
style
(
'color'
,
`
${
config
.
ytitle_font_color
}
`
)
.
style
(
'font-weight'
,
`
${
config
.
ytitle_font_weight
?
'bold'
:
'normal'
}
`
)
.
style
(
'font-style'
,
`
${
config
.
ytitle_font_style
?
'oblique'
:
'normal'
}
`
)
.
call
(
d3
.
axisRight
(
config
.
y
).
tickSize
(
Number
(
config
.
show_y_tickMarks
?
config
.
y_tickMarks_length
:
0
)))
.
call
((
g
)
=>
g
.
selectAll
(
'.domain'
).
remove
())
.
selectAll
(
'text'
)
.
style
(
'text-anchor'
,
'start'
)
config
.
show_x_axis
&&
config
.
svg
.
append
(
'g'
).
call
(
xAxis
);
config
.
show_y_axis
&&
config
.
svg
.
append
(
'g'
).
call
(
yAxis
);
}
// rect
export
const
setRect
=
(
config
,
data
)
=>
{
const
rects
=
config
.
svg
.
append
(
'g'
)
.
selectAll
(
'g'
)
.
data
(
data
)
.
enter
()
.
append
(
'g'
)
.
attr
(
'class'
,
(
d
,
i
)
=>
`
${
i
}
bar`
)
.
selectAll
(
'g'
)
.
data
((
d
)
=>
config
.
categories
.
map
((
e
)
=>
{
return
{
xval
:
d
.
index
,
yval
:
e
,
count
:
d
[
e
]
};
})
)
.
enter
()
.
append
(
'g'
);
rects
.
append
(
'rect'
)
.
attr
(
'x'
,
(
d
)
=>
config
.
x
(
d
.
xval
))
.
attr
(
'y'
,
(
d
)
=>
config
.
y
(
d
.
yval
))
.
attr
(
'width'
,
config
.
x
.
bandwidth
())
.
attr
(
'height'
,
config
.
y
.
bandwidth
())
.
style
(
'fill'
,
(
d
)
=>
config
.
color
(
d
.
count
));
return
rects
}
// 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
clustering
=
hcluster
().
distance
(
'angular'
).
linkage
(
'avg'
).
posKey
(
'normalized'
).
data
(
normalizedData
());
const
tree
=
(
data
)
=>
{
const
root
=
d3
.
hierarchy
(
data
).
sort
((
a
,
b
)
=>
d3
.
ascending
(
a
.
height
,
b
.
height
));
root
.
dx
=
0
;
root
.
dy
=
config
.
dendWidth
/
(
root
.
height
+
1
);
return
d3
.
cluster
()
.
size
([
config
.
heatWidth
,
config
.
dendWidth
])
.
separation
(()
=>
2
)(
root
);
};
const
root
=
tree
(
clustering
.
tree
());
return
{
root
,
}
}
// tree
export
const
setTree
=
(
config
)
=>
{
// top tree
config
.
svg
.
append
(
'g'
)
.
attr
(
'fill'
,
'none'
)
.
attr
(
'stroke'
,
'#555'
)
.
attr
(
'stroke-width'
,
1
)
.
attr
(
'transform'
,
`translate(
${
config
.
dendWidth
+
20
}
,
${
60
}
)`
)
.
selectAll
(
'path'
)
.
data
(
config
.
root
.
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
}
`
);
};
// title
export
const
setLabel
=
(
config
)
=>
{
config
.
svg
.
append
(
'text'
)
.
attr
(
'x'
,
config
.
width
/
2
)
.
attr
(
'y'
,
30
)
.
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/MsDimplot/components/config.vue
浏览文件 @
ad01d3f6
...
...
@@ -26,6 +26,10 @@
<input
type=
"text"
v-model=
"dynamic_parameter.margin_left"
/>
</div>
<h3
class=
"type content"
>
文本
</h3>
<div
class=
"form-item"
>
<span>
标题:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.title"
/>
</div>
<div
class=
"form-item"
>
<span>
字体:
</span>
<input
type=
"text"
v-model=
"dynamic_parameter.title_font_family"
/>
...
...
@@ -76,7 +80,7 @@ const dynamic_parameter = reactive({
margin_bottom
:
60
,
margin_left
:
60
,
//标题配置
title
:
''
,
title
:
'
group
'
,
title_font_family
:
'Arial'
,
title_font_weight
:
true
,
title_font_size
:
30
,
...
...
src/components/Test/index.vue
浏览文件 @
ad01d3f6
...
...
@@ -8,7 +8,7 @@
import
{
ref
,
onMounted
}
from
'vue'
;
import
{
chartMockData
}
from
'./mock.js'
;
import
*
as
d3
from
'https://cdn.jsdelivr.net/npm/d3@7/+esm'
;
import
{
setTips
,
setMaxMinNumber
,
coordinateScale
,
setColor
,
setCluster
,
setLegend
,
setLabel
}
from
'./utils'
;
import
{
setTips
,
setMaxMinNumber
,
setLegend
,
setScale
,
setAxis
,
setRect
,
setTopLeftColor
,
getRootConfig
,
setTree
}
from
'./utils'
;
const
chartRef
=
ref
(
null
);
...
...
@@ -19,20 +19,20 @@ const options = ref({});
const
generateChart
=
(
data
)
=>
{
const
ret
=
options
.
value
;
let
width
=
500
;
let
height
=
1200
;
let
marginTop
=
30
;
let
marginRight
=
30
;
let
marginBottom
=
30
;
let
marginLeft
=
30
;
let
rectHeight
=
300
;
let
width
=
1000
;
let
height
=
700
;
let
marginTop
=
120
;
let
marginRight
=
120
;
let
marginBottom
=
60
;
let
marginLeft
=
120
;
let
dendWidth
=
100
;
let
legendData
=
[
0.8
,
0.85
,
0.9
,
0.95
,
1
];
let
colorList
=
[
[
'#E53935'
,
'#1E88E5'
],
[
'#AA40FC'
,
'#FFBB78'
],
[
'#17BECF'
,
'#E377C2'
]
[
'#3DD378'
,
'#EC0B88'
,
'#444444'
,
'#5E35B1'
,
'#F9791E'
,
'#C6C6C6'
,
'#F7DC05'
,
'#3D98D3'
],
[
'#017A4A'
,
'#FFCE4E'
,
'#3D98D3'
,
'#FF363C'
,
'#794924'
,
'#8CDB5E'
,
'#D6D6D6'
,
'#FB8C00'
]
];
let
titles
=
[
'UMAP1'
,
'UMAP2'
];
let
labels
=
[
'main_cluster_id_0.4'
,
'celltype'
,
'sample_id'
]
;
let
legendPosition
=
[
0
,
0
];
let
heatWidth
=
width
-
marginLeft
-
marginRight
;
const
titleConfig
=
{
label
:
!!
ret
.
title
?
ret
.
title
:
null
,
...
...
@@ -53,59 +53,60 @@ const generateChart = (data) => {
marginRight
,
marginBottom
,
marginLeft
,
rectHeight
,
dendWidth
,
titleConfig
,
titles
,
labels
,
colorList
legendData
,
colorList
,
heatWidth
,
legendPosition
};
for
(
let
i
=
0
;
i
<
3
;
i
++
)
{
setChart
(
configObj
,
data
,
i
);
}
setChart
(
configObj
,
data
);
// setEl
chartRef
.
value
.
append
(
svg
.
node
());
};
const
setChart
=
(
config
,
data
,
index
)
=>
{
let
position
=
{
rect
:
[
config
.
marginLeft
,
(
config
.
rectHeight
+
80
)
*
index
+
config
.
marginTop
],
cluster
:
[
0
,
(
config
.
rectHeight
+
80
)
*
index
],
titleTop
:
[
config
.
width
/
2
,
(
config
.
rectHeight
+
80
)
*
index
+
20
],
titleBottom
:
[
config
.
width
/
2
,
(
config
.
rectHeight
+
80
)
*
index
+
config
.
rectHeight
+
50
],
titleLeft
:
[
-
config
.
rectHeight
/
2
-
(
config
.
rectHeight
+
80
)
*
index
,
20
]
};
config
.
svg
.
append
(
'rect'
)
.
attr
(
'x'
,
position
.
rect
[
0
])
.
attr
(
'y'
,
position
.
rect
[
1
])
.
attr
(
'width'
,
config
.
width
-
config
.
marginTop
-
config
.
marginRight
)
.
attr
(
'height'
,
config
.
rectHeight
)
.
attr
(
'stroke'
,
'#111111'
)
.
attr
(
'fill'
,
'white'
);
const
setChart
=
(
config
,
data
)
=>
{
const
categories
=
data
.
map
((
d
)
=>
d
.
index
);
const
newArr
=
data
.
map
((
d
)
=>
Object
.
keys
(
d
).
map
((
e
)
=>
d
[
e
])).
map
((
item
)
=>
({
index
:
item
[
0
],
values
:
item
.
slice
(
1
)
}));
const
{
maxNumber
,
minNumber
}
=
setMaxMinNumber
(
data
);
const
{
paddedMin
,
paddedMax
}
=
setMaxMinNumber
(
data
);
const
color
=
d3
.
scaleSequential
([
minNumber
,
maxNumber
],
d3
.
interpolateMagma
);
let
configObj
=
{
...
config
,
categories
,
color
};
let
label
=
config
.
labels
[
index
]
;
const
{
x
,
y
}
=
setScale
(
config
,
categories
)
;
let
colors
=
config
.
colorList
[
index
]
;
const
{
root
}
=
getRootConfig
(
config
,
newArr
)
;
let
configObj
=
{
...
config
,
paddedMin
,
paddedMax
,
position
,
label
,
colors
};
configObj
=
{
...
configObj
,
root
,
x
,
y
};
const
{
x
,
y
}
=
coordinateScale
(
configObj
,
data
);
// rects
const
rects
=
setRect
(
configObj
,
data
);
const
color
=
setColor
(
configObj
);
// tips
setTips
(
rects
);
configObj
=
{
...
configObj
,
x
,
y
,
color
};
// axis
setAxis
(
configObj
);
const
cluster
=
setCluster
(
configObj
,
data
);
// topLeftColor
setTopLeftColor
(
configObj
,
data
);
setTips
(
cluster
);
// legend
setLegend
(
configObj
);
//
label
set
Label
(
configObj
);
//
tree
set
Tree
(
configObj
);
};
onMounted
(()
=>
{
...
...
src/components/Test/mock.js
浏览文件 @
ad01d3f6
差异被折叠。
点击展开。
src/components/Test/utils.js
浏览文件 @
ad01d3f6
差异被折叠。
点击展开。
src/
components/ClusterHeatmap/
utils/hcluster.js
→
src/utils/hcluster.js
浏览文件 @
ad01d3f6
File moved
src/views/home/index.vue
浏览文件 @
ad01d3f6
差异被折叠。
点击展开。
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论