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

feat: 聚类热图

上级 84bed51a
...@@ -15,7 +15,7 @@ const chartRef = ref(null); ...@@ -15,7 +15,7 @@ const chartRef = ref(null);
// 配置项数据 // 配置项数据
const options = ref({}); const options = ref({});
// 图例实例 // 图表实例
const svgInstance = ref(null); const svgInstance = ref(null);
// pubsub实例 // pubsub实例
......
<template> <template>
<div ref="chartRef"></div> <div ref="chartRef" class="chart-box">
<div class="tip"></div>
</div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted, onUnmounted } from 'vue'; 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 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 chartRef = ref(null);
// 配置项数据 // 配置项数据
const options = ref({}); const options = ref({});
// 图表实例
const svgInstance = ref(null);
// pubsub实例 // pubsub实例
const pubSubInstance = ref(null); const pubSubInstance = ref(null);
// 生成数据 // 生成图表
const generateData = () => { const generateChart = (chartData) => {
const items = []; const ret = options.value;
const rows = [];
const columns = Object.keys(chartData1[0]).filter((k) => k !== 'Family'); let width = Number(ret.chart_width) || 1000;
let height = Number(ret.chart_height) || 1000;
for (const row of chartData1) { let margin = 10;
const newRow = []; let radius = 3;
for (const [key, value] of Object.entries(row)) { let dendWidth = 100;
if (key === 'Family') {
rows.push(value); let xAxisLength = chartData[0].values.length;
} else { const heatWidth = 2 * radius * xAxisLength;
newRow.push(Number.parseFloat(value)); const heatHeight = 2 * radius * chartData.length;
}
} const titleConfig = {
items.push(newRow); label: !!ret.title ? ret.title : null,
} color: ret.title_font_color || '#333333',
fontSize: ret.title_font_size || 20,
return { fontStyle: ret.title_font_style ? 'oblique' : 'normal',
items, fontFamily: ret.title_font_family || 'Arial',
rows, fontWeight: ret.title_font_weight ? 'bold' : 'normal'
columns
}; };
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);
}; };
// 生成图表 // Basis
const generateChart = (data) => { const generageBasis = (config) => {
const { items, rows, columns } = data; const chartData = chartMockData.slice(0, 2);
// max/min number
new uv.Heatmap(chartRef.value, items, rows, columns, { const { maxNumber, minNumber } = setMaxMinNumber(chartData);
width: 1200, // root config
height: 800, const { root, orderingx } = getRootConfig(config, chartData);
dendrogramEnabled: true, // color config
squarePadding: 0 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(() => { // Consensus
const mackData = generateData(); 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) => { pubSubInstance.value = PubSub.subscribe('options', (m, data) => {
options.value = data; options.value = data;
generateChart(mackData); chartRef.value.removeChild(svgInstance.value);
generateChart(chartData);
}); });
generateChart(mackData); generateChart(chartData);
}); });
onUnmounted(() => { onUnmounted(() => {
...@@ -70,4 +191,8 @@ onUnmounted(() => { ...@@ -70,4 +191,8 @@ onUnmounted(() => {
}); });
</script> </script>
<style scoped></style> <style scoped>
.chart-box {
position: relative;
}
</style>
...@@ -9,23 +9,11 @@ ...@@ -9,23 +9,11 @@
<span>高:</span> <span>高:</span>
<input type="text" v-model="dynamic_parameter.chart_height" /> <input type="text" v-model="dynamic_parameter.chart_height" />
</div> </div>
<h3 class="type content">文本</h3>
<div class="form-item"> <div class="form-item">
<span>上边距:</span> <span>标题:</span>
<input type="text" v-model="dynamic_parameter.margin_top" /> <input type="text" v-model="dynamic_parameter.title" />
</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" />
</div> </div>
<h3 class="type content">文本</h3>
<div class="form-item"> <div class="form-item">
<span>字体:</span> <span>字体:</span>
<input type="text" v-model="dynamic_parameter.title_font_family" /> <input type="text" v-model="dynamic_parameter.title_font_family" />
...@@ -46,105 +34,12 @@ ...@@ -46,105 +34,12 @@
<span>斜体:</span> <span>斜体:</span>
<input type="checkbox" v-model="dynamic_parameter.title_font_style" /> <input type="checkbox" v-model="dynamic_parameter.title_font_style" />
</div> </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> <h3 class="type content">图例</h3>
<div class="form-item"> <div class="form-item">
<span>显示图例:</span> <span>显示图例:</span>
<input type="checkbox" v-model="dynamic_parameter.show_legend" /> <input type="checkbox" v-model="dynamic_parameter.show_legend" />
</div> </div>
<div class="form-item">
<span>图例位置:</span>
<input type="text" v-model="dynamic_parameter.legend_position" />
</div>
<div class="btn"> <div class="btn">
<button @click="submit">提交</button> <button @click="submit">提交</button>
</div> </div>
...@@ -158,19 +53,19 @@ import PubSub from 'pubsub-js'; ...@@ -158,19 +53,19 @@ import PubSub from 'pubsub-js';
//动态图参数,固定参数 //动态图参数,固定参数
const dynamic_parameter = reactive({ const dynamic_parameter = reactive({
//长宽间距 //长宽间距
chart_width: 800, chart_width: 1000,
chart_height: 600, chart_height: 1000,
margin_top: 60, margin_top: 60,
margin_right: 60, margin_right: 60,
margin_bottom: 60, margin_bottom: 60,
margin_left: 60, margin_left: 60,
//标题配置 //标题配置
title: '', title: 'Consensus matrix',
title_font_family: 'Arial', title_font_family: 'Arial',
title_font_weight: true, title_font_weight: true,
title_font_size: 20, title_font_size: 20,
title_font_color: '#333333', title_font_color: '#333333',
title_font_style: true, title_font_style: false,
//横轴标题 //横轴标题
xtitle_font_family: 'Arial', xtitle_font_family: 'Arial',
xtitle_font_weight: false, xtitle_font_weight: false,
......
<template> <template>
<div class="chart-container"> <div class="chart-container">
<Chart /> <Chart />
<!-- <Config /> --> <Config />
</div> </div>
</template> </template>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论