提交 e017baf8 authored 作者: 祖铭松's avatar 祖铭松

feat: 聚类热图

上级 84bed51a
......@@ -15,7 +15,7 @@ const chartRef = ref(null);
// 配置项数据
const options = ref({});
// 图例实例
// 图表实例
const svgInstance = ref(null);
// pubsub实例
......
<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(mackData);
generateChart(chartData);
});
onUnmounted(() => {
......@@ -70,4 +191,8 @@ onUnmounted(() => {
});
</script>
<style scoped></style>
<style scoped>
.chart-box {
position: relative;
}
</style>
......@@ -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: 800,
chart_height: 600,
chart_width: 1000,
chart_height: 1000,
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: true,
title_font_style: false,
//横轴标题
xtitle_font_family: 'Arial',
xtitle_font_weight: false,
......
<template>
<div class="chart-container">
<Chart />
<!-- <Config /> -->
<Config />
</div>
</template>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论