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

feat: update

上级 bff4fbe7
......@@ -29,7 +29,7 @@ const generateChart = (data) => {
const height = width;
const minSize = Math.min(width, height);
const titleConfig = {
label: !!ret.title ? ret.title : null,
label: !!ret.title ? ret.title : '',
color: ret.title_font_color || '#333333',
fontSize: ret.title_font_size || 20,
fontStyle: ret.title_font_style ? 'oblique' : 'normal',
......@@ -442,17 +442,11 @@ const setTips = (rect) => {
const tips = d3
.select('.tip')
.style('visibility', 'hidden')
.style('position', 'relative')
.style('left', '0px')
.style('top', '0px')
.style('position', 'absolute')
.style('background-color', 'rgba(0, 0, 0, .8)')
.style('color', '#fff')
.style('border-radius', '5px')
.style('width', '80px')
.style('text-align', 'center')
.style('height', '20px')
.style('line-height', '20px')
.style('padding', '5px');
.style('padding', '10px');
rect.on('mouseover', (event, d) => {
tips.style('visibility', 'visible');
......@@ -460,7 +454,7 @@ const setTips = (rect) => {
.on('mousemove', function (event, d) {
tips.style('visibility', 'visible')
.style('left', event.offsetX + 15 + 'px')
.style('top', event.offsetY + 50 + 'px')
.style('top', event.offsetY + 15 + 'px')
.html(`${d.data.value}`);
})
.on('mouseleave', function () {
......
......@@ -54,7 +54,7 @@ const generateChart = (chartData) => {
const heatHeight = 2 * radius * chartData.length;
const titleConfig = {
label: !!ret.title ? ret.title : null,
label: !!ret.title ? ret.title : '',
color: ret.title_font_color || '#333333',
fontSize: ret.title_font_size || 20,
fontStyle: ret.title_font_style ? 'oblique' : 'normal',
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -100,15 +100,11 @@ export const setTips = (rect) => {
const tips = d3
.select('.tip')
.style('visibility', 'hidden')
.style('position', 'relative')
.style('position', 'absolute')
.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('line-height', '20px')
.style('padding', '5px');
.style('padding', '10px');
rect.on('mouseover', (event, d) => {
tips.style('visibility', 'visible');
......@@ -116,7 +112,7 @@ export const setTips = (rect) => {
.on('mousemove', function (event, d) {
tips.style('visibility', 'visible')
.style('left', event.offsetX + 15 + 'px')
.style('top', event.offsetY + 50 + 'px')
.style('top', event.offsetY + 15 + 'px')
.html(`${d}`);
})
.on('mouseleave', function () {
......
......@@ -52,7 +52,7 @@ const generateChart = () => {
const heatHeight = 2 * radius * chartData.length;
const titleConfig = {
label: !!ret.title ? ret.title : null,
label: !!ret.title ? ret.title : '',
color: ret.title_font_color || '#333333',
fontSize: ret.title_font_size || 20,
fontStyle: ret.title_font_style ? 'oblique' : 'normal',
......
......@@ -100,15 +100,11 @@ export const setTips = (rect) => {
const tips = d3
.select('.tip')
.style('visibility', 'hidden')
.style('position', 'relative')
.style('position', 'absolute')
.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('line-height', '20px')
.style('padding', '5px');
.style('padding', '10px');
rect.on('mouseover', (event, d) => {
tips.style('visibility', 'visible');
......@@ -116,7 +112,7 @@ export const setTips = (rect) => {
.on('mousemove', function (event, d) {
tips.style('visibility', 'visible')
.style('left', event.offsetX + 15 + 'px')
.style('top', event.offsetY + 50 + 'px')
.style('top', event.offsetY + 15 + 'px')
.html(`${d}`);
})
.on('mouseleave', function () {
......
......@@ -40,9 +40,9 @@ const generateChart = (data) => {
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 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;
......@@ -53,7 +53,7 @@ const generateChart = (data) => {
];
const titleConfig = {
label: !!ret.title ? ret.title : null,
label: !!ret.title ? ret.title : '',
color: ret.title_font_color || '#333333',
fontSize: ret.title_font_size || 20,
fontStyle: ret.title_font_style ? 'oblique' : 'normal',
......
......@@ -44,15 +44,11 @@ export const setTips = (rect) => {
const tips = d3
.select('.tip')
.style('visibility', 'hidden')
.style('position', 'relative')
.style('position', 'absolute')
.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')
.style('padding', '10px')
rect.on('mouseover', (event, d) => {
tips.style('visibility', 'visible');
......@@ -60,7 +56,7 @@ export const setTips = (rect) => {
.on('mousemove', function (event, d) {
tips.style('visibility', 'visible')
.style('left', event.offsetX + 15 + 'px')
.style('top', event.offsetY + 55 + 'px')
.style('top', event.offsetY + 15 + 'px')
.html(`${d.count}`);
})
.on('mouseleave', function () {
......
......@@ -44,7 +44,7 @@ const generateChart = () => {
let labels = ['main_cluster_id_0.4', 'celltype', 'sample_id'];
const titleConfig = {
label: !!ret.title ? ret.title : null,
label: !!ret.title ? ret.title : '',
color: ret.title_font_color || '#333333',
fontSize: ret.title_font_size || 20,
fontStyle: ret.title_font_style ? 'oblique' : 'normal',
......
......@@ -61,14 +61,11 @@ export const setTips = (rect) => {
const tips = d3
.select('.tip')
.style('visibility', 'hidden')
.style('position', 'relative')
.style('position', 'absolute')
.style('background-color', 'rgba(0, 0, 0, .8)')
.style('color', '#fff')
.style('border-radius', '5px')
.style('width', '200px')
.style('height', '45px')
.style('text-align', 'left')
.style('padding', '5px')
.style('padding', '10px')
rect.on('mouseover', (event, d) => {
tips.style('visibility', 'visible');
......@@ -76,7 +73,7 @@ export const setTips = (rect) => {
.on('mousemove', function (event, d) {
tips.style('visibility', 'visible')
.style('left', event.offsetX + 15 + 'px')
.style('top', event.offsetY + 90 + 'px')
.style('top', event.offsetY + 15 + 'px')
.html(`
<div>x: ${d.x}</div>
<div>y: ${d.y}</div>`);
......
......@@ -5,7 +5,6 @@
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import * as Plot from '@observablehq/plot';
// import * as d3 from 'd3';
import { chartData } from '../mock';
import PubSub from 'pubsub-js';
......
import * as d3 from 'd3';
export function linearRegression(data) {
let n = data.length, sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
for (let i = 0; i < data.length; ++i) {
const xi = data[i].x;
const yi = data[i].y;
if (!Number.isFinite(xi) || !Number.isFinite(yi)) { --n; continue; }
sumX += xi;
sumY += yi;
sumXY += xi * yi;
sumX2 += xi * xi;
}
const slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
const intercept = (sumY - slope * sumX) / n;
return x => slope * x + intercept;
}
export function confidenceInterval(data, predict) {
const mean = d3.sum(data, (d) => d.x) / data.length;
let a = 0,
b = 0;
for (let i = 0; i < data.length; ++i) {
a += Math.pow(data[i].x - mean, 2);
b += Math.pow(data[i].y - predict(data[i].x), 2);
}
const sy = Math.sqrt(b / (data.length - 2));
const t = inverseT(+0.05, data.length - 2);
return function (x) {
const Y = predict(x);
const se = sy * Math.sqrt(1 / data.length + Math.pow(x - mean, 2) / a);
return { x, left: Y - t * se, right: Y + t * se };
};
}
export function normdev(p) {
if (p < 0 || p > 1) return false;
if (p == 0) return -Infinity;
if (p == 1) return Infinity;
let a0 = 3.3871328727963666080e+0,
a1 = 1.3314166789178437745e+2,
a2 = 1.9715909503065514427e+3,
a3 = 1.3731693765509461125e+4,
a4 = 4.5921953931549871457e+4,
a5 = 6.7265770927008700853e+4,
a6 = 3.3430575583588128105e+4,
a7 = 2.5090809287301226727e+3,
b1 = 4.2313330701600911252e+1,
b2 = 6.8718700749205790830e+2,
b3 = 5.3941960214247511077e+3,
b4 = 2.1213794301586595867e+4,
b5 = 3.9307895800092710610e+4,
b6 = 2.8729085735721942674e+4,
b7 = 5.2264952788528545610e+3,
c0 = 1.42343711074968357734e+0,
c1 = 4.63033784615654529590e+0,
c2 = 5.76949722146069140550e+0,
c3 = 3.64784832476320460504e+0,
c4 = 1.27045825245236838258e+0,
c5 = 2.41780725177450611770e-1,
c6 = 2.27238449892691845833e-2,
c7 = 7.74545014278341407640e-4,
d1 = 2.05319162663775882187e+0,
d2 = 1.67638483018380384940e+0,
d3 = 6.89767334985100004550e-1,
d4 = 1.48103976427480074590e-1,
d5 = 1.51986665636164571966e-2,
d6 = 5.47593808499534494600e-4,
d7 = 1.05075007164441684324e-9,
e0 = 6.65790464350110377720e+0,
e1 = 5.46378491116411436990e+0,
e2 = 1.78482653991729133580e+0,
e3 = 2.96560571828504891230e-1,
e4 = 2.65321895265761230930e-2,
e5 = 1.24266094738807843860e-3,
e6 = 2.71155556874348757815e-5,
e7 = 2.01033439929228813265e-7,
f1 = 5.99832206555887937690e-1,
f2 = 1.36929880922735805310e-1,
f3 = 1.48753612908506148525e-2,
f4 = 7.86869131145613259100e-4,
f5 = 1.84631831751005468180e-5,
f6 = 1.42151175831644588870e-7,
f7 = 2.04426310338993978564e-15;
let q = p - 0.5, r, z;
// p close to 0.5
if (Math.abs(q) <= 0.425) {
r = 0.180625 - q * q;
z = q * (((((((a7 * r + a6) * r + a5) * r + a4) * r + a3) * r + a2) * r + a1) * r + a0)
/ (((((((b7 * r + b6) * r + b5) * r + b4) * r + b3) * r + b2) * r + b1) * r + 1);
return z;
}
if (q > 0) r = 1 - p;
else r = p;
r = Math.sqrt(-Math.log(r));
// p neither close to 0.5 nor 0 or 1
if (r <= 5) {
r += -1.6;
z = (((((((c7 * r + c6) * r + c5) * r + c4) * r + c3) * r + c2) * r + c1) * r + c0)
/ (((((((d7 * r + d6) * r + d5) * r + d4) * r + d3) * r + d2) * r + d1) * r + 1);
}
// p near 0 or 1
else {
r += -5;
z = (((((((e7 * r + e6) * r + e5) * r + e4) * r + e3) * r + e2) * r + e1) * r + e0)
/ (((((((f7 * r + f6) * r + f5) * r + f4) * r + f3) * r + f2) * r + f1) * r + 1);
}
if (q < 0.0) z = -z;
return z;
}
export function inverseT(p, df) {
const { sin, cos, sqrt, pow, exp, PI } = Math;
let a, b, c, d, t, x, y;
if (df == 1) return cos(p * PI / 2) / sin(p * PI / 2);
if (df == 2) return sqrt(2 / (p * (2 - p)) - 2);
a = 1 / (df - 0.5);
b = 48 / (a * a);
c = ((20700 * a / b - 98) * a - 16) * a + 96.36;
d = ((94.5 / (b + c) - 3) / b + 1) * sqrt(a * PI * 0.5) * df;
x = d * p;
y = pow(x, 2 / df);
if (y > 0.05 + a) {
// The procedure normdev(p) is assumed to return a negative normal
// deviate at the lower tail probability level p, e.g. -2.32 for p = 0.01.
x = normdev(p / 2);
y = x * x;
if (df < 5) c = c + 0.3 * (df - 4.5) * (x + 0.6);
c = (((0.05 * d * x - 5) * x - 7) * x - 2) * x + b + c;
y = (((((0.4 * y + 6.3) * y + 36) * y + 94.5) / c - y - 3) / b + 1) * x;
y = a * y * y;
if (y > 0.002) y = exp(y) - 1;
else y = 0.5 * y * y + y;
}
else {
y = ((1 / (((df + 6) / (df * y) - 0.089 * d - 0.822) * (df + 2) * 3) + 0.5 / (df + 4)) * y - 1) *
(df + 1) / (df + 2) + 1 / y;
}
return sqrt(df * y);
}
\ No newline at end of file
......@@ -38,7 +38,7 @@ const generateChart = (data) => {
let legendData = ['Cancer', 'Non-cance'];
const titleConfig = {
label: !!ret.title ? ret.title : null,
label: !!ret.title ? ret.title : '',
color: ret.title_font_color || '#333333',
fontSize: ret.title_font_size || 20,
fontStyle: ret.title_font_style ? 'oblique' : 'normal',
......
......@@ -60,14 +60,11 @@ export const setTips = (rect) => {
const tips = d3
.select('.tip')
.style('visibility', 'hidden')
.style('position', 'relative')
.style('position', 'absolute')
.style('background-color', 'rgba(0, 0, 0, .8)')
.style('color', '#fff')
.style('border-radius', '5px')
.style('width', '200px')
.style('height', '65px')
.style('text-align', 'left')
.style('padding', '5px')
.style('padding', '10px')
rect.on('mouseover', (event, d) => {
tips.style('visibility', 'visible');
......@@ -75,7 +72,7 @@ export const setTips = (rect) => {
.on('mousemove', function (event, d) {
tips.style('visibility', 'visible')
.style('left', event.offsetX + 15 + 'px')
.style('top', event.offsetY + 90 + 'px')
.style('top', event.offsetY + 15 + 'px')
.html(`
<div>${d.group}</div>
<div>x: ${d.x}</div>
......
<template>
<div ref="chartRef" class="chart-box">
<div class="tip"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { chartMockData } from '../mock.js';
import * as d3 from 'https://cdn.jsdelivr.net/npm/d3@7/+esm';
import PubSub from 'pubsub-js';
import { setTips, setColor, setLegend, setScale, setAxis, setPoint, setLabel, setElliptic } from '../utils/index';
const chartRef = ref(null);
// 配置项数据
const options = ref({});
// 图表实例
const svgInstance = ref(null);
// pubsub实例
const pubSubInstance = ref(null);
// 生成图表
const generateChart = (data) => {
const ret = options.value;
let width = Number(ret.chart_width) || 900;
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) || 120;
let marginLeft = Number(ret.margin_left) || 120;
let legendPosition = ret.legend_position?.split(',') || [1, 0];
let colors = ret.data_color_list || ['#FF0000', '#0000FF'];
let legendData = ['M', 'F'];
// 标题配置
const titleConfig = {
label: !!ret.title ? ret.title : '',
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'
};
// 大椭圆
let ellipticOne = {
rx: (width - marginLeft - marginRight) / 2 - 30,
ry: (height - marginTop - marginBottom) / 2 - 70,
cx: (marginLeft + width - marginLeft - marginRight) / 2 + 60,
cy: (marginTop + height - marginTop - marginBottom) / 2 + 60
};
// 椭圆 M
let ellipticM = {
rx: 120,
ry: 90,
cx: (marginLeft + width - marginLeft - marginRight) / 2 + 50,
cy: (marginTop + height - marginTop - marginBottom) / 2 + 90,
rotate: 10,
stroke: colors[0]
};
// 椭圆 F
let ellipticF = {
rx: 120,
ry: 100,
cx: (marginLeft + width - marginLeft - marginRight) / 2 + 150,
cy: (marginTop + height - marginTop - marginBottom) / 2,
rotate: 20,
stroke: colors[1]
};
const svg = d3.create('svg').attr('width', width).attr('height', height);
let configObj = {
...ret,
svg,
width,
height,
marginTop,
marginRight,
marginBottom,
marginLeft,
titleConfig,
colors,
legendData,
legendPosition,
ellipticOne,
ellipticM,
ellipticF
};
setChart(configObj, data);
svgInstance.value = svg.node();
// Append the SVG element.
chartRef.value.appendChild(svgInstance.value);
};
const setChart = (config, data) => {
const color = setColor(config);
const { x, y } = setScale(config, data);
let configObj = {
...config,
color,
x,
y
};
// elliptic
setElliptic(configObj);
// rects
const points = setPoint(configObj, data);
// tips
setTips(points);
// axis
setAxis(configObj);
// legend
setLegend(configObj);
// label
setLabel(configObj);
};
onMounted(() => {
const chartData = chartMockData;
pubSubInstance.value = PubSub.subscribe('options', (m, data) => {
options.value = data;
chartRef.value.removeChild(svgInstance.value);
generateChart(chartData);
});
generateChart(chartData);
});
onUnmounted(() => {
PubSub.unsubscribe(pubSubInstance.value);
});
</script>
<style scoped>
.chart-box {
position: relative;
}
</style>
<template>
<div class="form-container">
<h3 class="type content">画布</h3>
<div class="form-item">
<span>宽:</span>
<input type="text" v-model="dynamic_parameter.chart_width" />
</div>
<div class="form-item">
<span>高:</span>
<input type="text" v-model="dynamic_parameter.chart_height" />
</div>
<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" />
</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" />
</div>
<div class="form-item">
<span>字号:</span>
<input type="text" v-model="dynamic_parameter.title_font_size" />
</div>
<div class="form-item">
<span>字体颜色:</span>
<input type="text" v-model="dynamic_parameter.title_font_color" />
</div>
<div class="form-item">
<span>字体加粗:</span>
<input type="checkbox" v-model="dynamic_parameter.title_font_weight" />
</div>
<div class="form-item">
<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="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>标题展示:</span>
<input type="checkbox" v-model="dynamic_parameter.show_x_title" />
</div>
<div class="form-item">
<span>标题:</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="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>标题展示:</span>
<input type="checkbox" v-model="dynamic_parameter.show_y_title" />
</div>
<div class="form-item">
<span>标题:</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>
</div>
</template>
<script setup>
import { reactive, onMounted } from 'vue';
import PubSub from 'pubsub-js';
//动态图参数,固定参数
const dynamic_parameter = reactive({
//长宽间距
chart_width: 900,
chart_height: 700,
margin_top: 120,
margin_right: 120,
margin_bottom: 120,
margin_left: 120,
//标题配置
title: 'Scores(OPLS-DA)',
title_font_family: 'Arial',
title_font_weight: true,
title_font_size: 20,
title_font_color: '#333333',
title_font_style: false,
//横轴标题
xtitle_font_family: 'Arial',
xtitle_font_weight: false,
xtitle_font_style: false,
xtitle_font_size: 14,
xtitle_font_color: '#333333',
//纵轴标题
ytitle_font_family: 'Arial',
ytitle_font_weight: false,
ytitle_font_style: false,
ytitle_font_size: 14,
ytitle_font_color: '#333333',
//颜色设置
data_color_list: ['#FF0000', '#0000FF'],
point_radius: 5, // 散点图半径
shadow_opacity: 0.5, // 阴影透明度 0~1
//图例
show_legend: true,
legend_position: '1,0',
//坐标轴
show_x_axis: true,
show_x_line: true,
show_x_tickMarks: true,
show_x_gridLine: false,
show_x_title: true,
x_title: 't1(5%)',
x_tickMarks_color: '#333333',
x_tickMarks_length: '5',
show_y_axis: true,
show_y_line: true,
show_y_tickMarks: true,
show_y_gridLine: false,
show_y_title: true,
y_title: 'to1',
y_tickMarks_color: '#333333',
y_tickMarks_length: '5',
//节点相关的参数,可能还会有更多
node_id: null, //节点id
node_color: null, //节点颜色
is_delect_node: false, //是否删除节点
node_search_name: null, //节点名称搜索
node_search_color: '#FF0404', //节点搜索后的颜色
node_edit_name: null, //修改节点名称
node_height: 100, //节点大小
path_id: null
});
const submit = () => {
PubSub.publish('options', dynamic_parameter);
};
onMounted(() => {
submit();
});
</script>
<style scoped>
.form-item span {
display: inline-block;
width: 120px;
text-align: left;
}
.btn {
width: 100%;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
}
</style>
<template>
<div class="chart-container">
<Chart />
<Config />
</div>
</template>
<script setup>
import Chart from './components/chart.vue';
import Config from './components/config.vue';
</script>
<style scoped>
.chart-container {
display: flex;
}
</style>
export const chartMockData = [
{ "sample": "HU_011", "p1": -2.694, "p2": 3.3961, "group": "M" },
{ "sample": "HU_014", "p1": 0.7511, "p2": 2.1861, "group": "F" },
{ "sample": "HU_015", "p1": -4.391, "p2": 0.8546, "group": "M" },
{ "sample": "HU_017", "p1": -3.193, "p2": -0.8985, "group": "M" },
{ "sample": "HU_018", "p1": -2.3968, "p2": -1.7253, "group": "M" },
{ "sample": "HU_019", "p1": -1.5622, "p2": -1.575, "group": "M" },
{ "sample": "HU_020", "p1": -1.4987, "p2": 2.2523, "group": "M" },
{ "sample": "HU_021", "p1": -2.4947, "p2": -1.0498, "group": "M" },
{ "sample": "HU_022", "p1": 0.8717, "p2": 1.0038, "group": "F" },
{ "sample": "HU_023", "p1": -2.9628, "p2": 1.209, "group": "M" },
{ "sample": "HU_024", "p1": -1.1742, "p2": -0.4848, "group": "M" },
{ "sample": "HU_025", "p1": -2.5344, "p2": 0.2522, "group": "M" },
{ "sample": "HU_026", "p1": -1.1101, "p2": 5.6241, "group": "F" },
{ "sample": "HU_027", "p1": -3.4414, "p2": 2.0785, "group": "M" },
{ "sample": "HU_028", "p1": -0.6837, "p2": 2.2982, "group": "F" },
{ "sample": "HU_029", "p1": -5.0231, "p2": -0.9122, "group": "M" },
{ "sample": "HU_030", "p1": -2.3311, "p2": -1.9076, "group": "M" },
{ "sample": "HU_031", "p1": -3.2643, "p2": -3.4599, "group": "M" },
{ "sample": "HU_032", "p1": 3.2836, "p2": -0.0743, "group": "F" },
{ "sample": "HU_033", "p1": 3.1527, "p2": 0.8104, "group": "F" },
{ "sample": "HU_034", "p1": -1.8802, "p2": -1.8398, "group": "M" },
{ "sample": "HU_035", "p1": 2.0869, "p2": 1.1855, "group": "F" },
{ "sample": "HU_036", "p1": 0.444, "p2": -0.204, "group": "M" },
{ "sample": "HU_037", "p1": -3.888, "p2": 1.6282, "group": "M" },
{ "sample": "HU_038", "p1": 0.3607, "p2": 1.3689, "group": "M" },
{ "sample": "HU_039", "p1": -1.6638, "p2": -1.0387, "group": "M" },
{ "sample": "HU_040", "p1": -2.9274, "p2": -0.4632, "group": "M" },
{ "sample": "HU_041", "p1": -1.9937, "p2": 1.1925, "group": "M" },
{ "sample": "HU_042", "p1": -2.8004, "p2": -0.9826, "group": "M" },
{ "sample": "HU_043", "p1": -3.0049, "p2": 0.4318, "group": "M" },
{ "sample": "HU_044", "p1": 0.9173, "p2": 4.3367, "group": "F" },
{ "sample": "HU_045", "p1": 3.2966, "p2": 4.3903, "group": "F" },
{ "sample": "HU_046", "p1": -1.9355, "p2": 0.63, "group": "M" },
{ "sample": "HU_047", "p1": -2.5254, "p2": 7.8368, "group": "F" },
{ "sample": "HU_048", "p1": 0.9981, "p2": 4.0178, "group": "F" },
{ "sample": "HU_049", "p1": -4.1861, "p2": 2.2438, "group": "M" },
{ "sample": "HU_050", "p1": -2.235, "p2": -2.4121, "group": "M" },
{ "sample": "HU_051", "p1": 1.6669, "p2": 7.7918, "group": "F" },
{ "sample": "HU_052", "p1": 3.5993, "p2": 0.3467, "group": "F" },
{ "sample": "HU_053", "p1": -4.0823, "p2": 6.5051, "group": "M" },
{ "sample": "HU_054", "p1": -2.5232, "p2": -0.0491, "group": "M" },
{ "sample": "HU_055", "p1": -0.8239, "p2": 10.2638, "group": "F" },
{ "sample": "HU_056", "p1": -2.9633, "p2": 0.6563, "group": "M" },
{ "sample": "HU_057", "p1": -2.0967, "p2": 0.201, "group": "M" },
{ "sample": "HU_058", "p1": -5.5404, "p2": 1.6177, "group": "M" },
{ "sample": "HU_060", "p1": 1.6519, "p2": 0.4352, "group": "F" },
{ "sample": "HU_061", "p1": 1.0493, "p2": 1.4025, "group": "F" },
{ "sample": "HU_062", "p1": -2.2119, "p2": -0.456, "group": "M" },
{ "sample": "HU_063", "p1": 2.1409, "p2": 3.1914, "group": "F" },
{ "sample": "HU_064", "p1": 2.4929, "p2": 0.3461, "group": "F" },
{ "sample": "HU_065", "p1": -1.6306, "p2": -0.9027, "group": "M" },
{ "sample": "HU_066", "p1": -0.7943, "p2": 1.5956, "group": "F" },
{ "sample": "HU_067", "p1": 0.3045, "p2": 3.3032, "group": "F" },
{ "sample": "HU_068", "p1": 2.0647, "p2": 0.8658, "group": "F" },
{ "sample": "HU_069", "p1": -3.0864, "p2": -1.7673, "group": "M" },
{ "sample": "HU_070", "p1": -1.3931, "p2": -0.6326, "group": "M" },
{ "sample": "HU_072", "p1": -1.4088, "p2": -1.5587, "group": "M" },
{ "sample": "HU_073", "p1": -3.2015, "p2": -0.7017, "group": "M" },
{ "sample": "HU_074", "p1": 0.8579, "p2": 3.0974, "group": "F" },
{ "sample": "HU_075", "p1": -2.4835, "p2": -0.917, "group": "M" },
{ "sample": "HU_076", "p1": 2.17, "p2": -3.5912, "group": "M" },
{ "sample": "HU_077", "p1": -1.2155, "p2": 0.0184, "group": "M" },
{ "sample": "HU_078", "p1": -1.2357, "p2": -3.2847, "group": "M" },
{ "sample": "HU_079", "p1": 0.0268, "p2": -0.3357, "group": "M" },
{ "sample": "HU_080", "p1": 0.9653, "p2": 1.2102, "group": "F" },
{ "sample": "HU_081", "p1": 2.056, "p2": 1.3191, "group": "F" },
{ "sample": "HU_082", "p1": -0.7337, "p2": -4.1567, "group": "M" },
{ "sample": "HU_083", "p1": -0.6749, "p2": -1.9284, "group": "M" },
{ "sample": "HU_084", "p1": 3.7565, "p2": 2.9144, "group": "F" },
{ "sample": "HU_085", "p1": -1.0641, "p2": -0.9107, "group": "M" },
{ "sample": "HU_086", "p1": 3.0943, "p2": -6.0076, "group": "M" },
{ "sample": "HU_087", "p1": 1.6055, "p2": -0.0515, "group": "F" },
{ "sample": "HU_088", "p1": 1.4227, "p2": -1.1189, "group": "F" },
{ "sample": "HU_089", "p1": 0.8992, "p2": -4.1458, "group": "M" },
{ "sample": "HU_090", "p1": 0.2635, "p2": -0.28, "group": "M" },
{ "sample": "HU_091", "p1": -0.9062, "p2": 0.1755, "group": "M" },
{ "sample": "HU_092", "p1": -3.2233, "p2": -1.2836, "group": "M" },
{ "sample": "HU_093", "p1": 5.1131, "p2": -3.8128, "group": "M" },
{ "sample": "HU_094", "p1": -2.9418, "p2": -5.4881, "group": "M" },
{ "sample": "HU_095", "p1": -0.4206, "p2": -4.1905, "group": "M" },
{ "sample": "HU_097", "p1": -2.0808, "p2": 1.677, "group": "M" },
{ "sample": "HU_098", "p1": -1.3052, "p2": -0.0674, "group": "M" },
{ "sample": "HU_099", "p1": -2.165, "p2": 0.6846, "group": "M" },
{ "sample": "HU_100", "p1": 0.2879, "p2": -1.5811, "group": "F" },
{ "sample": "HU_101", "p1": -2.2088, "p2": 1.3091, "group": "M" },
{ "sample": "HU_102", "p1": -0.2787, "p2": 3.8856, "group": "F" },
{ "sample": "HU_103", "p1": -2.2547, "p2": 0.5023, "group": "M" },
{ "sample": "HU_105", "p1": 0.9252, "p2": -0.5704, "group": "M" },
{ "sample": "HU_106", "p1": 0.7901, "p2": -2.1655, "group": "M" },
{ "sample": "HU_107", "p1": -3.8103, "p2": -1.8205, "group": "M" },
{ "sample": "HU_108", "p1": 0.4162, "p2": -1.7355, "group": "M" },
{ "sample": "HU_109", "p1": 0.6149, "p2": -1.6656, "group": "M" },
{ "sample": "HU_110", "p1": 1.8461, "p2": 5.0904, "group": "F" },
{ "sample": "HU_112", "p1": -1.0587, "p2": -3.4511, "group": "M" },
{ "sample": "HU_113", "p1": -2.0481, "p2": -1.2451, "group": "M" },
{ "sample": "HU_114", "p1": 0.299, "p2": -2.6928, "group": "M" },
{ "sample": "HU_115", "p1": -1.5242, "p2": 2.1588, "group": "F" },
{ "sample": "HU_116", "p1": 3.9897, "p2": 0.3828, "group": "F" },
{ "sample": "HU_117", "p1": 0.8195, "p2": -5.2862, "group": "M" },
{ "sample": "HU_118", "p1": 4.3611, "p2": -2.1239, "group": "F" },
{ "sample": "HU_119", "p1": 2.0253, "p2": 2.8263, "group": "F" },
{ "sample": "HU_120", "p1": 4.0386, "p2": 5.6263, "group": "F" },
{ "sample": "HU_121", "p1": 0.9667, "p2": -0.7439, "group": "M" },
{ "sample": "HU_122", "p1": -1.3132, "p2": -2.9375, "group": "M" },
{ "sample": "HU_123", "p1": -0.1384, "p2": -0.3404, "group": "M" },
{ "sample": "HU_124", "p1": -0.9347, "p2": -2.7756, "group": "M" },
{ "sample": "HU_125", "p1": 0.5602, "p2": -4.2009, "group": "M" },
{ "sample": "HU_126", "p1": -0.7276, "p2": -2.7435, "group": "M" },
{ "sample": "HU_127", "p1": -1.0536, "p2": -1.8021, "group": "M" },
{ "sample": "HU_129", "p1": -0.6943, "p2": -3.7267, "group": "M" },
{ "sample": "HU_130", "p1": -5.2532, "p2": 0.1486, "group": "M" },
{ "sample": "HU_131", "p1": -2.4389, "p2": -0.337, "group": "M" },
{ "sample": "HU_132", "p1": 1.6394, "p2": -1.5556, "group": "F" },
{ "sample": "HU_133", "p1": -0.1746, "p2": -1.6395, "group": "M" },
{ "sample": "HU_134", "p1": -0.8844, "p2": -1.0832, "group": "M" },
{ "sample": "HU_135", "p1": -3.2065, "p2": -0.6407, "group": "M" },
{ "sample": "HU_136", "p1": 4.3038, "p2": 2.5598, "group": "F" },
{ "sample": "HU_137", "p1": -4.2203, "p2": 0.8897, "group": "M" },
{ "sample": "HU_138", "p1": -1.3954, "p2": -2.6394, "group": "M" },
{ "sample": "HU_139", "p1": -3.6364, "p2": -2.2381, "group": "M" },
{ "sample": "HU_140", "p1": 1.0704, "p2": -5.0656, "group": "M" },
{ "sample": "HU_142", "p1": -2.7719, "p2": 0.8603, "group": "M" },
{ "sample": "HU_143", "p1": 4.2223, "p2": 0.1294, "group": "F" },
{ "sample": "HU_144", "p1": -1.8954, "p2": -2.9115, "group": "M" },
{ "sample": "HU_145", "p1": -2.8522, "p2": -3.6701, "group": "M" },
{ "sample": "HU_146", "p1": -3.1428, "p2": -2.2155, "group": "M" },
{ "sample": "HU_147", "p1": -1.6001, "p2": -2.0569, "group": "M" },
{ "sample": "HU_148", "p1": 1.5624, "p2": 0.8215, "group": "F" },
{ "sample": "HU_149", "p1": 1.4868, "p2": 0.9387, "group": "F" },
{ "sample": "HU_150", "p1": 1.2278, "p2": 2.5334, "group": "F" },
{ "sample": "HU_152", "p1": 0.4689, "p2": 0.2993, "group": "F" },
{ "sample": "HU_154", "p1": 4.4293, "p2": -0.6724, "group": "F" },
{ "sample": "HU_155", "p1": 5.3259, "p2": -0.2039, "group": "F" },
{ "sample": "HU_156", "p1": 2.0773, "p2": -0.2925, "group": "F" },
{ "sample": "HU_157", "p1": 3.2571, "p2": -1.5152, "group": "F" },
{ "sample": "HU_158", "p1": 3.3489, "p2": 2.8188, "group": "F" },
{ "sample": "HU_159", "p1": 2.6641, "p2": -1.0094, "group": "F" },
{ "sample": "HU_160", "p1": 2.1475, "p2": 5.4831, "group": "F" },
{ "sample": "HU_162", "p1": 3.6139, "p2": 0.1493, "group": "F" },
{ "sample": "HU_163", "p1": 1.9983, "p2": 0.6987, "group": "F" },
{ "sample": "HU_164", "p1": 3.4288, "p2": 0.2784, "group": "F" },
{ "sample": "HU_166", "p1": 1.6014, "p2": 2.5659, "group": "F" },
{ "sample": "HU_167", "p1": 4.6267, "p2": 0.4012, "group": "F" },
{ "sample": "HU_168", "p1": 4.4273, "p2": 1.8695, "group": "F" },
{ "sample": "HU_169", "p1": 6.9281, "p2": 1.5059, "group": "F" },
{ "sample": "HU_170", "p1": 3.7733, "p2": 1.9685, "group": "F" },
{ "sample": "HU_171", "p1": 6.5568, "p2": -5.0527, "group": "F" },
{ "sample": "HU_172", "p1": 0.6661, "p2": 1.8918, "group": "F" },
{ "sample": "HU_173", "p1": 10.8553, "p2": -4.3252, "group": "F" },
{ "sample": "HU_174", "p1": 3.1477, "p2": 0.281, "group": "F" },
{ "sample": "HU_175", "p1": 0.1607, "p2": 2.5216, "group": "F" },
{ "sample": "HU_177", "p1": -1.3722, "p2": -1.4356, "group": "F" },
{ "sample": "HU_179", "p1": -3.129, "p2": 2.5303, "group": "F" },
{ "sample": "HU_180", "p1": 0.9789, "p2": 2.0271, "group": "F" },
{ "sample": "HU_181", "p1": 3.4655, "p2": -2.3871, "group": "F" },
{ "sample": "HU_182", "p1": 3.0047, "p2": -0.8189, "group": "F" },
{ "sample": "HU_183", "p1": 3.2544, "p2": 1.3798, "group": "F" },
{ "sample": "HU_184", "p1": -0.5118, "p2": 4.1538, "group": "F" },
{ "sample": "HU_185", "p1": 3.8487, "p2": 5.202, "group": "F" },
{ "sample": "HU_186", "p1": 4.3468, "p2": -4.1251, "group": "F" },
{ "sample": "HU_187", "p1": 7.8661, "p2": -2.2229, "group": "F" },
{ "sample": "HU_188", "p1": 0.372, "p2": 0.9616, "group": "F" },
{ "sample": "HU_189", "p1": 1.0228, "p2": 1.1824, "group": "F" },
{ "sample": "HU_190", "p1": -3.9281, "p2": -0.7289, "group": "M" },
{ "sample": "HU_191", "p1": -3.4649, "p2": -1.4185, "group": "M" },
{ "sample": "HU_192", "p1": -2.7969, "p2": -0.4768, "group": "M" },
{ "sample": "HU_193", "p1": -1.0186, "p2": 4.6379, "group": "F" },
{ "sample": "HU_194", "p1": -0.9476, "p2": -2.0304, "group": "F" },
{ "sample": "HU_195", "p1": 4.2304, "p2": -3.4866, "group": "F" },
{ "sample": "HU_196", "p1": 2.3967, "p2": 1.1037, "group": "F" },
{ "sample": "HU_197", "p1": -2.5637, "p2": 2.2405, "group": "M" },
{ "sample": "HU_198", "p1": -2.0851, "p2": 0.2653, "group": "M" },
{ "sample": "HU_199", "p1": -2.9985, "p2": 0.704, "group": "M" },
{ "sample": "HU_200", "p1": -2.1708, "p2": -0.7799, "group": "M" },
{ "sample": "HU_201", "p1": -1.9002, "p2": -1.3926, "group": "M" },
{ "sample": "HU_202", "p1": -3.5753, "p2": 0.4489, "group": "M" },
{ "sample": "HU_203", "p1": -0.3197, "p2": 2.0491, "group": "F" },
{ "sample": "HU_204", "p1": -1.5042, "p2": -4.312, "group": "M" },
{ "sample": "HU_205", "p1": -3.6309, "p2": -1.9503, "group": "M" },
{ "sample": "HU_206", "p1": -0.1951, "p2": -1.1371, "group": "F" },
{ "sample": "HU_207", "p1": 6.2953, "p2": 0.4496, "group": "F" },
{ "sample": "HU_208", "p1": 3.8801, "p2": -3.4484, "group": "F" },
{ "sample": "HU_209", "p1": 0.3483, "p2": -2.028, "group": "F" }
]
import * as d3 from 'https://cdn.jsdelivr.net/npm/d3@7/+esm';
// color config
export const setColor = (config) => {
let colors = [];
if (Array.isArray(config.colors)) {
colors = !!config.colors.length ? config.colors : colors;
} else if (!!config.colors) {
colors = config.colors.split(',');
}
return d3.scaleOrdinal(colors).domain(config.legendData);
};
// tips
export const setTips = (rect) => {
const tips = d3
.select('.tip')
.style('visibility', 'hidden')
.style('position', 'absolute')
.style('background-color', 'rgba(0, 0, 0, .8)')
.style('color', '#fff')
.style('border-radius', '5px')
.style('padding', '10px')
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 + 15 + 'px')
.html(`
<div>${d.group}</div>
<div>p1: ${d.p1}</div>
<div>p2: ${d.p2}</div>
`);
})
.on('mouseleave', function () {
tips.style('visibility', 'hidden');
});
};
// legend
export const setLegend = (config) => {
let legendX = config.legendPosition[0] == 0 ? config.marginLeft + 20 : config.legendPosition[0] == 0.5 ? config.width / 2 : config.width - config.marginLeft - 30;
let legendY = config.legendPosition[1] == 0 ? config.marginTop + 20 : config.legendPosition[1] == 0.5 ? config.height / 2 - 50 : config.height - config.marginTop - 110;
config.svg.append('g')
.attr('transform', `translate(${legendX}, ${legendY})`)
.selectAll()
.data(config.legendData)
.join('g')
.attr('transform', (d, i) => `translate(0, ${i * 50})`)
.call((g) => g.append('rect').attr('width', 20).attr('height', 50).attr('fill', d => config.color(d)))
.call((g) =>
g
.append('text')
.attr('x', -10)
.attr('y', 25)
.attr('dy', '0.3em')
.style('font', '10px sans-serif')
.style('text-anchor', 'middle')
.text((d) => d)
);
};
// scale
export const setScale = (config, data) => {
const xMax = d3.max(data, (d) => d.p1)
const xMin = d3.min(data, (d) => d.p1)
const yMax = d3.min(data, (d) => d.p2)
const yMin = d3.min(data, (d) => d.p2)
const xDomain = (Math.abs(xMax) >= Math.abs(xMin) ? Math.abs(xMax) : Math.abs(xMin)) + 6
const yDomain = (Math.abs(yMax) >= Math.abs(yMin) ? Math.abs(yMax) : Math.abs(yMin)) + 5
const x = d3
.scaleLinear()
.domain([-xDomain, xDomain])
.range([config.marginLeft, config.width - config.marginRight])
const y = d3
.scaleLinear()
.domain([-yDomain, yDomain])
.range([config.height - config.marginBottom, config.marginTop])
return { x, y }
}
// axis
export const setAxis = (config) => {
config.show_x_axis && config.svg.append('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("line").clone()
.attr("stroke", d => d == 0 ? 'black' : '#aaa')
.attr("y2", -(config.height - config.marginBottom - config.marginTop))
)
.call((g) => g.selectAll('.domain').remove())
.selectAll('text')
.style('text-anchor', 'middle');
config.show_x_title && config.svg.append('g')
.attr('transform', `translate(${config.width / 2}, ${config.height - config.marginBottom + 50})`)
.append('text')
.style('text-anchor', 'middle')
.text(config.x_title)
config.show_y_axis && config.svg.append('g')
.attr('transform', `translate(${config.marginLeft}, 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.axisLeft(config.y).ticks(null, 's'))
.call(g => g.selectAll("line").clone()
.attr("stroke", d => d == 0 ? 'black' : '#aaa')
.attr("x2", config.width - config.marginLeft - config.marginRight))
.call((g) => g.selectAll('.domain').remove())
config.show_y_title && config.svg.append('g')
.attr('transform', `translate(${config.marginLeft - 50}, ${config.height / 2})`)
.append('text')
.style('text-anchor', 'middle')
.attr('transform', `rotate(-90)`)
.text(config.y_title)
}
// elliptic
export const setElliptic = (config) => {
let rects = config.svg
.append('g')
.attr('width', config.width - config.marginLeft - config.marginRight)
.attr('height', config.height - config.marginTop - config.marginBottom);
rects
.append('rect')
.attr('x', `${config.marginLeft}`)
.attr('y', `${config.marginTop}`)
.attr('width', `${config.width - config.marginLeft - config.marginRight}`)
.attr('height', `${config.height - config.marginTop - config.marginBottom}`)
.attr('stroke', '#000000')
.attr('stroke-width', 2)
.attr('fill', 'white');
rects
.append('ellipse')
.attr('cx', `${config.ellipticOne.cx}`)
.attr('cy', `${config.ellipticOne.cy}`)
.attr('rx', `${config.ellipticOne.rx}`)
.attr('ry', `${config.ellipticOne.ry}`)
.attr('stroke', 'black')
.attr('fill', 'transparent');
rects
.append('ellipse')
.attr('cx', `${config.ellipticM.cx}`)
.attr('cy', `${config.ellipticM.cy}`)
.attr('rx', `${config.ellipticM.rx}`)
.attr('ry', `${config.ellipticM.ry}`)
.attr('transform-origin', 'center')
.attr('fill', 'transparent')
.attr('stroke', config.ellipticM.stroke)
.attr('transform', `rotate(${config.ellipticM.rotate})`)
rects
.append('ellipse')
.attr('cx', `${config.ellipticF.cx}`)
.attr('cy', `${config.ellipticF.cy}`)
.attr('rx', `${config.ellipticF.rx}`)
.attr('ry', `${config.ellipticF.ry}`)
.attr('fill', 'transparent')
.attr('transform-origin', 'center')
.attr('stroke', config.ellipticF.stroke)
.attr('transform', `rotate(${config.ellipticF.rotate})`)
}
// point
export const setPoint = (config, data) => {
return config.svg
.append("g")
.selectAll("text")
.data(data)
.join("text")
.attr("dy", "0.35em")
.attr("x", d => config.x(d.p1) + 7)
.attr("y", d => config.y(d.p2))
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr('cursor', 'default')
.attr('fill', d => config.color(d.group))
.text(d => d.sample)
}
// 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}`);
};
......@@ -29,16 +29,16 @@ const generateChart = (data) => {
let width = Number(ret.chart_width) || 700;
let height = Number(ret.chart_height) || 800;
let marginTop = Number(ret.margin_top) || 120;
let marginRight = Number(ret.margin_Right) || 120;
let marginBottom = Number(ret.margin_Bottom) || 120;
let marginLeft = Number(ret.margin_Left) || 120;
let marginRight = Number(ret.margin_right) || 120;
let marginBottom = Number(ret.margin_bottom) || 120;
let marginLeft = Number(ret.margin_left) || 120;
let legendPosition = ret.legend_position?.split(',') || [0.5, 1];
let colors = ret.data_color_list || ['#155C9C', '#44A79D'];
let legendData = ['AD', 'Non_AD'];
// 标题配置
const titleConfig = {
label: !!ret.title ? ret.title : null,
label: !!ret.title ? ret.title : '',
color: ret.title_font_color || '#333333',
fontSize: ret.title_font_size || 20,
fontStyle: ret.title_font_style ? 'oblique' : 'normal',
......@@ -56,8 +56,8 @@ const generateChart = (data) => {
// 椭圆 AD
let ellipticAD = {
rx: 80,
ry: 350,
rx: 70,
ry: 280,
cx: (marginLeft + width - marginLeft - marginRight) / 2 + 60,
cy: (marginTop + height - marginTop - marginBottom) / 2 + 60,
rotate: 10,
......@@ -67,10 +67,10 @@ const generateChart = (data) => {
// 椭圆 Non_AD
let ellipticNon_AD = {
rx: 350,
ry: 60,
cx: (marginLeft + width - marginLeft - marginRight) / 2 + 60,
cy: (marginTop + height - marginTop - marginBottom) / 2 + 20,
rx: 240,
ry: 50,
cx: (marginLeft + width - marginLeft - marginRight) / 2 + 40,
cy: (marginTop + height - marginTop - marginBottom) / 2 + 10,
rotate: 20,
fill: colors[1],
fillOpacity: 0.2
......
......@@ -16,14 +16,11 @@ export const setTips = (rect) => {
const tips = d3
.select('.tip')
.style('visibility', 'hidden')
.style('position', 'relative')
.style('position', 'absolute')
.style('background-color', 'rgba(0, 0, 0, .8)')
.style('color', '#fff')
.style('border-radius', '5px')
.style('width', '120px')
.style('height', '65px')
.style('text-align', 'left')
.style('padding', '5px 10px')
.style('padding', '10px')
rect.on('mouseover', (event, d) => {
tips.style('visibility', 'visible');
......@@ -31,7 +28,7 @@ export const setTips = (rect) => {
.on('mousemove', function (event, d) {
tips.style('visibility', 'visible')
.style('left', event.offsetX + 15 + 'px')
.style('top', event.offsetY + 55 + 'px')
.style('top', event.offsetY + 15 + 'px')
.html(`
<div>${d.name}</div>
<div>x: ${d.PC1}</div>
......@@ -117,7 +114,7 @@ export const setAxis = (config) => {
.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("line").clone()
.attr("display", d => d == 0 ? 'block' : 'none')
.attr("display", d => d == 0 ? 'black' : 'none')
.attr("stroke-dasharray", '3')
.attr("y2", -(config.height - config.marginBottom - config.marginTop))
)
......@@ -139,7 +136,7 @@ export const setAxis = (config) => {
.style('font-style', `${config.ytitle_font_style ? 'oblique' : 'normal'}`)
.call(d3.axisLeft(config.y).tickSize(Number(config.show_y_tickMarks ? config.y_tickMarks_length : 0)))
.call(g => g.selectAll("line").clone()
.attr("display", d => d == 0 ? 'block' : 'none')
.attr("display", d => d == 0 ? 'black' : 'none')
.attr("stroke-dasharray", '3')
.attr("x2", config.width - config.marginLeft - config.marginRight))
.call((g) => g.selectAll('.domain').remove())
......@@ -162,7 +159,7 @@ export const setSymbol = (type) => {
export const setElliptic = (config) => {
let rects = config.svg
.append('g')
.attr('max-width', config.width - config.marginLeft - config.marginRight)
.attr('width', config.width - config.marginLeft - config.marginRight)
.attr('height', config.height - config.marginTop - config.marginBottom);
rects
......
......@@ -19,19 +19,19 @@ const options = ref({});
const generateChart = (data) => {
const ret = options.value;
let width = 700;
let height = 800;
let width = 900;
let height = 700;
let marginTop = 120;
let marginRight = 120;
let marginBottom = 120;
let marginLeft = 120;
let legendData = ['AD', 'Non_AD'];
let legendPosition = [0.5, 1];
let colors = ['#155C9C', '#44A79D'];
let legendData = ['M', 'F'];
let legendPosition = [1, 0];
let colors = ['#FF0000', '#0000FF'];
// 标题配置
const titleConfig = {
label: !!ret.title ? ret.title : null,
label: !!ret.title ? ret.title : '',
color: ret.title_font_color || '#333333',
fontSize: ret.title_font_size || 20,
fontStyle: ret.title_font_style ? 'oblique' : 'normal',
......@@ -41,27 +41,27 @@ const generateChart = (data) => {
// 大椭圆
let ellipticOne = {
rx: (width - marginLeft - marginRight) / 2 - 20,
ry: (height - marginTop - marginBottom) / 2 - 20,
rx: (width - marginLeft - marginRight) / 2 - 30,
ry: (height - marginTop - marginBottom) / 2 - 70,
cx: (marginLeft + width - marginLeft - marginRight) / 2 + 60,
cy: (marginTop + height - marginTop - marginBottom) / 2 + 60
};
// 椭圆 AD
let ellipticAD = {
rx: 80,
ry: 350,
cx: (marginLeft + width - marginLeft - marginRight) / 2 + 60,
cy: (marginTop + height - marginTop - marginBottom) / 2 + 60,
// 椭圆 M
let ellipticM = {
rx: 120,
ry: 90,
cx: (marginLeft + width - marginLeft - marginRight) / 2 + 50,
cy: (marginTop + height - marginTop - marginBottom) / 2 + 90,
rotate: 10
};
// 椭圆 Non_AD
let ellipticNon_AD = {
rx: 350,
ry: 60,
cx: (marginLeft + width - marginLeft - marginRight) / 2 + 60,
cy: (marginTop + height - marginTop - marginBottom) / 2 + 20,
// 椭圆 F
let ellipticF = {
rx: 120,
ry: 100,
cx: (marginLeft + width - marginLeft - marginRight) / 2 + 150,
cy: (marginTop + height - marginTop - marginBottom) / 2,
rotate: 20
};
......@@ -80,8 +80,8 @@ const generateChart = (data) => {
legendData,
legendPosition,
ellipticOne,
ellipticAD,
ellipticNon_AD
ellipticM,
ellipticF
};
setChart(configObj, data);
......@@ -130,8 +130,4 @@ onMounted(() => {
.chart-box {
position: relative;
}
.main {
width: 500px;
overflow: hidden;
}
</style>
export const chartMockData = [
{
"name": "AD",
"x": -13.6199,
"y": 19.2571
},
{
"name": "AD",
"x": -26.9176,
"y": -83.0864
},
{
"name": "AD",
"x": 10.7576,
"y": 16.4817
},
{
"name": "AD",
"x": -26.8031,
"y": 10.3311
},
{
"name": "Non_AD",
"x": -31.6168,
"y": 11.5461
},
{
"name": "Non_AD",
"x": 122.4475,
"y": -8.1394
},
{
"name": "Non_AD",
"x": -5.0412,
"y": 19.3962
},
{
"name": "Non_AD",
"x": -29.2065,
"y": 14.2135
}
{ "sample": "HU_011", "p1": -2.694, "p2": 3.3961, "group": "M" },
{ "sample": "HU_014", "p1": 0.7511, "p2": 2.1861, "group": "F" },
{ "sample": "HU_015", "p1": -4.391, "p2": 0.8546, "group": "M" },
{ "sample": "HU_017", "p1": -3.193, "p2": -0.8985, "group": "M" },
{ "sample": "HU_018", "p1": -2.3968, "p2": -1.7253, "group": "M" },
{ "sample": "HU_019", "p1": -1.5622, "p2": -1.575, "group": "M" },
{ "sample": "HU_020", "p1": -1.4987, "p2": 2.2523, "group": "M" },
{ "sample": "HU_021", "p1": -2.4947, "p2": -1.0498, "group": "M" },
{ "sample": "HU_022", "p1": 0.8717, "p2": 1.0038, "group": "F" },
{ "sample": "HU_023", "p1": -2.9628, "p2": 1.209, "group": "M" },
{ "sample": "HU_024", "p1": -1.1742, "p2": -0.4848, "group": "M" },
{ "sample": "HU_025", "p1": -2.5344, "p2": 0.2522, "group": "M" },
{ "sample": "HU_026", "p1": -1.1101, "p2": 5.6241, "group": "F" },
{ "sample": "HU_027", "p1": -3.4414, "p2": 2.0785, "group": "M" },
{ "sample": "HU_028", "p1": -0.6837, "p2": 2.2982, "group": "F" },
{ "sample": "HU_029", "p1": -5.0231, "p2": -0.9122, "group": "M" },
{ "sample": "HU_030", "p1": -2.3311, "p2": -1.9076, "group": "M" },
{ "sample": "HU_031", "p1": -3.2643, "p2": -3.4599, "group": "M" },
{ "sample": "HU_032", "p1": 3.2836, "p2": -0.0743, "group": "F" },
{ "sample": "HU_033", "p1": 3.1527, "p2": 0.8104, "group": "F" },
{ "sample": "HU_034", "p1": -1.8802, "p2": -1.8398, "group": "M" },
{ "sample": "HU_035", "p1": 2.0869, "p2": 1.1855, "group": "F" },
{ "sample": "HU_036", "p1": 0.444, "p2": -0.204, "group": "M" },
{ "sample": "HU_037", "p1": -3.888, "p2": 1.6282, "group": "M" },
{ "sample": "HU_038", "p1": 0.3607, "p2": 1.3689, "group": "M" },
{ "sample": "HU_039", "p1": -1.6638, "p2": -1.0387, "group": "M" },
{ "sample": "HU_040", "p1": -2.9274, "p2": -0.4632, "group": "M" },
{ "sample": "HU_041", "p1": -1.9937, "p2": 1.1925, "group": "M" },
{ "sample": "HU_042", "p1": -2.8004, "p2": -0.9826, "group": "M" },
{ "sample": "HU_043", "p1": -3.0049, "p2": 0.4318, "group": "M" },
{ "sample": "HU_044", "p1": 0.9173, "p2": 4.3367, "group": "F" },
{ "sample": "HU_045", "p1": 3.2966, "p2": 4.3903, "group": "F" },
{ "sample": "HU_046", "p1": -1.9355, "p2": 0.63, "group": "M" },
{ "sample": "HU_047", "p1": -2.5254, "p2": 7.8368, "group": "F" },
{ "sample": "HU_048", "p1": 0.9981, "p2": 4.0178, "group": "F" },
{ "sample": "HU_049", "p1": -4.1861, "p2": 2.2438, "group": "M" },
{ "sample": "HU_050", "p1": -2.235, "p2": -2.4121, "group": "M" },
{ "sample": "HU_051", "p1": 1.6669, "p2": 7.7918, "group": "F" },
{ "sample": "HU_052", "p1": 3.5993, "p2": 0.3467, "group": "F" },
{ "sample": "HU_053", "p1": -4.0823, "p2": 6.5051, "group": "M" },
{ "sample": "HU_054", "p1": -2.5232, "p2": -0.0491, "group": "M" },
{ "sample": "HU_055", "p1": -0.8239, "p2": 10.2638, "group": "F" },
{ "sample": "HU_056", "p1": -2.9633, "p2": 0.6563, "group": "M" },
{ "sample": "HU_057", "p1": -2.0967, "p2": 0.201, "group": "M" },
{ "sample": "HU_058", "p1": -5.5404, "p2": 1.6177, "group": "M" },
{ "sample": "HU_060", "p1": 1.6519, "p2": 0.4352, "group": "F" },
{ "sample": "HU_061", "p1": 1.0493, "p2": 1.4025, "group": "F" },
{ "sample": "HU_062", "p1": -2.2119, "p2": -0.456, "group": "M" },
{ "sample": "HU_063", "p1": 2.1409, "p2": 3.1914, "group": "F" },
{ "sample": "HU_064", "p1": 2.4929, "p2": 0.3461, "group": "F" },
{ "sample": "HU_065", "p1": -1.6306, "p2": -0.9027, "group": "M" },
{ "sample": "HU_066", "p1": -0.7943, "p2": 1.5956, "group": "F" },
{ "sample": "HU_067", "p1": 0.3045, "p2": 3.3032, "group": "F" },
{ "sample": "HU_068", "p1": 2.0647, "p2": 0.8658, "group": "F" },
{ "sample": "HU_069", "p1": -3.0864, "p2": -1.7673, "group": "M" },
{ "sample": "HU_070", "p1": -1.3931, "p2": -0.6326, "group": "M" },
{ "sample": "HU_072", "p1": -1.4088, "p2": -1.5587, "group": "M" },
{ "sample": "HU_073", "p1": -3.2015, "p2": -0.7017, "group": "M" },
{ "sample": "HU_074", "p1": 0.8579, "p2": 3.0974, "group": "F" },
{ "sample": "HU_075", "p1": -2.4835, "p2": -0.917, "group": "M" },
{ "sample": "HU_076", "p1": 2.17, "p2": -3.5912, "group": "M" },
{ "sample": "HU_077", "p1": -1.2155, "p2": 0.0184, "group": "M" },
{ "sample": "HU_078", "p1": -1.2357, "p2": -3.2847, "group": "M" },
{ "sample": "HU_079", "p1": 0.0268, "p2": -0.3357, "group": "M" },
{ "sample": "HU_080", "p1": 0.9653, "p2": 1.2102, "group": "F" },
{ "sample": "HU_081", "p1": 2.056, "p2": 1.3191, "group": "F" },
{ "sample": "HU_082", "p1": -0.7337, "p2": -4.1567, "group": "M" },
{ "sample": "HU_083", "p1": -0.6749, "p2": -1.9284, "group": "M" },
{ "sample": "HU_084", "p1": 3.7565, "p2": 2.9144, "group": "F" },
{ "sample": "HU_085", "p1": -1.0641, "p2": -0.9107, "group": "M" },
{ "sample": "HU_086", "p1": 3.0943, "p2": -6.0076, "group": "M" },
{ "sample": "HU_087", "p1": 1.6055, "p2": -0.0515, "group": "F" },
{ "sample": "HU_088", "p1": 1.4227, "p2": -1.1189, "group": "F" },
{ "sample": "HU_089", "p1": 0.8992, "p2": -4.1458, "group": "M" },
{ "sample": "HU_090", "p1": 0.2635, "p2": -0.28, "group": "M" },
{ "sample": "HU_091", "p1": -0.9062, "p2": 0.1755, "group": "M" },
{ "sample": "HU_092", "p1": -3.2233, "p2": -1.2836, "group": "M" },
{ "sample": "HU_093", "p1": 5.1131, "p2": -3.8128, "group": "M" },
{ "sample": "HU_094", "p1": -2.9418, "p2": -5.4881, "group": "M" },
{ "sample": "HU_095", "p1": -0.4206, "p2": -4.1905, "group": "M" },
{ "sample": "HU_097", "p1": -2.0808, "p2": 1.677, "group": "M" },
{ "sample": "HU_098", "p1": -1.3052, "p2": -0.0674, "group": "M" },
{ "sample": "HU_099", "p1": -2.165, "p2": 0.6846, "group": "M" },
{ "sample": "HU_100", "p1": 0.2879, "p2": -1.5811, "group": "F" },
{ "sample": "HU_101", "p1": -2.2088, "p2": 1.3091, "group": "M" },
{ "sample": "HU_102", "p1": -0.2787, "p2": 3.8856, "group": "F" },
{ "sample": "HU_103", "p1": -2.2547, "p2": 0.5023, "group": "M" },
{ "sample": "HU_105", "p1": 0.9252, "p2": -0.5704, "group": "M" },
{ "sample": "HU_106", "p1": 0.7901, "p2": -2.1655, "group": "M" },
{ "sample": "HU_107", "p1": -3.8103, "p2": -1.8205, "group": "M" },
{ "sample": "HU_108", "p1": 0.4162, "p2": -1.7355, "group": "M" },
{ "sample": "HU_109", "p1": 0.6149, "p2": -1.6656, "group": "M" },
{ "sample": "HU_110", "p1": 1.8461, "p2": 5.0904, "group": "F" },
{ "sample": "HU_112", "p1": -1.0587, "p2": -3.4511, "group": "M" },
{ "sample": "HU_113", "p1": -2.0481, "p2": -1.2451, "group": "M" },
{ "sample": "HU_114", "p1": 0.299, "p2": -2.6928, "group": "M" },
{ "sample": "HU_115", "p1": -1.5242, "p2": 2.1588, "group": "F" },
{ "sample": "HU_116", "p1": 3.9897, "p2": 0.3828, "group": "F" },
{ "sample": "HU_117", "p1": 0.8195, "p2": -5.2862, "group": "M" },
{ "sample": "HU_118", "p1": 4.3611, "p2": -2.1239, "group": "F" },
{ "sample": "HU_119", "p1": 2.0253, "p2": 2.8263, "group": "F" },
{ "sample": "HU_120", "p1": 4.0386, "p2": 5.6263, "group": "F" },
{ "sample": "HU_121", "p1": 0.9667, "p2": -0.7439, "group": "M" },
{ "sample": "HU_122", "p1": -1.3132, "p2": -2.9375, "group": "M" },
{ "sample": "HU_123", "p1": -0.1384, "p2": -0.3404, "group": "M" },
{ "sample": "HU_124", "p1": -0.9347, "p2": -2.7756, "group": "M" },
{ "sample": "HU_125", "p1": 0.5602, "p2": -4.2009, "group": "M" },
{ "sample": "HU_126", "p1": -0.7276, "p2": -2.7435, "group": "M" },
{ "sample": "HU_127", "p1": -1.0536, "p2": -1.8021, "group": "M" },
{ "sample": "HU_129", "p1": -0.6943, "p2": -3.7267, "group": "M" },
{ "sample": "HU_130", "p1": -5.2532, "p2": 0.1486, "group": "M" },
{ "sample": "HU_131", "p1": -2.4389, "p2": -0.337, "group": "M" },
{ "sample": "HU_132", "p1": 1.6394, "p2": -1.5556, "group": "F" },
{ "sample": "HU_133", "p1": -0.1746, "p2": -1.6395, "group": "M" },
{ "sample": "HU_134", "p1": -0.8844, "p2": -1.0832, "group": "M" },
{ "sample": "HU_135", "p1": -3.2065, "p2": -0.6407, "group": "M" },
{ "sample": "HU_136", "p1": 4.3038, "p2": 2.5598, "group": "F" },
{ "sample": "HU_137", "p1": -4.2203, "p2": 0.8897, "group": "M" },
{ "sample": "HU_138", "p1": -1.3954, "p2": -2.6394, "group": "M" },
{ "sample": "HU_139", "p1": -3.6364, "p2": -2.2381, "group": "M" },
{ "sample": "HU_140", "p1": 1.0704, "p2": -5.0656, "group": "M" },
{ "sample": "HU_142", "p1": -2.7719, "p2": 0.8603, "group": "M" },
{ "sample": "HU_143", "p1": 4.2223, "p2": 0.1294, "group": "F" },
{ "sample": "HU_144", "p1": -1.8954, "p2": -2.9115, "group": "M" },
{ "sample": "HU_145", "p1": -2.8522, "p2": -3.6701, "group": "M" },
{ "sample": "HU_146", "p1": -3.1428, "p2": -2.2155, "group": "M" },
{ "sample": "HU_147", "p1": -1.6001, "p2": -2.0569, "group": "M" },
{ "sample": "HU_148", "p1": 1.5624, "p2": 0.8215, "group": "F" },
{ "sample": "HU_149", "p1": 1.4868, "p2": 0.9387, "group": "F" },
{ "sample": "HU_150", "p1": 1.2278, "p2": 2.5334, "group": "F" },
{ "sample": "HU_152", "p1": 0.4689, "p2": 0.2993, "group": "F" },
{ "sample": "HU_154", "p1": 4.4293, "p2": -0.6724, "group": "F" },
{ "sample": "HU_155", "p1": 5.3259, "p2": -0.2039, "group": "F" },
{ "sample": "HU_156", "p1": 2.0773, "p2": -0.2925, "group": "F" },
{ "sample": "HU_157", "p1": 3.2571, "p2": -1.5152, "group": "F" },
{ "sample": "HU_158", "p1": 3.3489, "p2": 2.8188, "group": "F" },
{ "sample": "HU_159", "p1": 2.6641, "p2": -1.0094, "group": "F" },
{ "sample": "HU_160", "p1": 2.1475, "p2": 5.4831, "group": "F" },
{ "sample": "HU_162", "p1": 3.6139, "p2": 0.1493, "group": "F" },
{ "sample": "HU_163", "p1": 1.9983, "p2": 0.6987, "group": "F" },
{ "sample": "HU_164", "p1": 3.4288, "p2": 0.2784, "group": "F" },
{ "sample": "HU_166", "p1": 1.6014, "p2": 2.5659, "group": "F" },
{ "sample": "HU_167", "p1": 4.6267, "p2": 0.4012, "group": "F" },
{ "sample": "HU_168", "p1": 4.4273, "p2": 1.8695, "group": "F" },
{ "sample": "HU_169", "p1": 6.9281, "p2": 1.5059, "group": "F" },
{ "sample": "HU_170", "p1": 3.7733, "p2": 1.9685, "group": "F" },
{ "sample": "HU_171", "p1": 6.5568, "p2": -5.0527, "group": "F" },
{ "sample": "HU_172", "p1": 0.6661, "p2": 1.8918, "group": "F" },
{ "sample": "HU_173", "p1": 10.8553, "p2": -4.3252, "group": "F" },
{ "sample": "HU_174", "p1": 3.1477, "p2": 0.281, "group": "F" },
{ "sample": "HU_175", "p1": 0.1607, "p2": 2.5216, "group": "F" },
{ "sample": "HU_177", "p1": -1.3722, "p2": -1.4356, "group": "F" },
{ "sample": "HU_179", "p1": -3.129, "p2": 2.5303, "group": "F" },
{ "sample": "HU_180", "p1": 0.9789, "p2": 2.0271, "group": "F" },
{ "sample": "HU_181", "p1": 3.4655, "p2": -2.3871, "group": "F" },
{ "sample": "HU_182", "p1": 3.0047, "p2": -0.8189, "group": "F" },
{ "sample": "HU_183", "p1": 3.2544, "p2": 1.3798, "group": "F" },
{ "sample": "HU_184", "p1": -0.5118, "p2": 4.1538, "group": "F" },
{ "sample": "HU_185", "p1": 3.8487, "p2": 5.202, "group": "F" },
{ "sample": "HU_186", "p1": 4.3468, "p2": -4.1251, "group": "F" },
{ "sample": "HU_187", "p1": 7.8661, "p2": -2.2229, "group": "F" },
{ "sample": "HU_188", "p1": 0.372, "p2": 0.9616, "group": "F" },
{ "sample": "HU_189", "p1": 1.0228, "p2": 1.1824, "group": "F" },
{ "sample": "HU_190", "p1": -3.9281, "p2": -0.7289, "group": "M" },
{ "sample": "HU_191", "p1": -3.4649, "p2": -1.4185, "group": "M" },
{ "sample": "HU_192", "p1": -2.7969, "p2": -0.4768, "group": "M" },
{ "sample": "HU_193", "p1": -1.0186, "p2": 4.6379, "group": "F" },
{ "sample": "HU_194", "p1": -0.9476, "p2": -2.0304, "group": "F" },
{ "sample": "HU_195", "p1": 4.2304, "p2": -3.4866, "group": "F" },
{ "sample": "HU_196", "p1": 2.3967, "p2": 1.1037, "group": "F" },
{ "sample": "HU_197", "p1": -2.5637, "p2": 2.2405, "group": "M" },
{ "sample": "HU_198", "p1": -2.0851, "p2": 0.2653, "group": "M" },
{ "sample": "HU_199", "p1": -2.9985, "p2": 0.704, "group": "M" },
{ "sample": "HU_200", "p1": -2.1708, "p2": -0.7799, "group": "M" },
{ "sample": "HU_201", "p1": -1.9002, "p2": -1.3926, "group": "M" },
{ "sample": "HU_202", "p1": -3.5753, "p2": 0.4489, "group": "M" },
{ "sample": "HU_203", "p1": -0.3197, "p2": 2.0491, "group": "F" },
{ "sample": "HU_204", "p1": -1.5042, "p2": -4.312, "group": "M" },
{ "sample": "HU_205", "p1": -3.6309, "p2": -1.9503, "group": "M" },
{ "sample": "HU_206", "p1": -0.1951, "p2": -1.1371, "group": "F" },
{ "sample": "HU_207", "p1": 6.2953, "p2": 0.4496, "group": "F" },
{ "sample": "HU_208", "p1": 3.8801, "p2": -3.4484, "group": "F" },
{ "sample": "HU_209", "p1": 0.3483, "p2": -2.028, "group": "F" }
]
......@@ -2,7 +2,7 @@ import * as d3 from 'https://cdn.jsdelivr.net/npm/d3@7/+esm';
// color config
export const setColor = (config) => {
let colors = ['#2265A1', '#44A79D'];
let colors = [];
if (Array.isArray(config.colors)) {
colors = !!config.colors.length ? config.colors : colors;
} else if (!!config.colors) {
......@@ -16,14 +16,12 @@ export const setTips = (rect) => {
const tips = d3
.select('.tip')
.style('visibility', 'hidden')
.style('position', 'relative')
.style('position', 'absolute')
.style('background-color', 'rgba(0, 0, 0, .8)')
.style('color', '#fff')
.style('border-radius', '5px')
.style('width', '120px')
.style('height', '65px')
.style('text-align', 'left')
.style('padding', '5px 10px')
.style('padding', '10px')
rect.on('mouseover', (event, d) => {
tips.style('visibility', 'visible');
......@@ -31,11 +29,11 @@ export const setTips = (rect) => {
.on('mousemove', function (event, d) {
tips.style('visibility', 'visible')
.style('left', event.offsetX + 15 + 'px')
.style('top', event.offsetY + 55 + 'px')
.style('top', event.offsetY + 15 + 'px')
.html(`
<div>${d.name}</div>
<div>x: ${d.x}</div>
<div>y: ${d.y}</div>
<div>${d.group}</div>
<div>p1: ${d.p1}</div>
<div>p2: ${d.p2}</div>
`);
})
.on('mouseleave', function () {
......@@ -46,38 +44,24 @@ export const setTips = (rect) => {
// legend
export const setLegend = (config) => {
const g = config.svg.append('g')
.attr('transform', `translate(${(config.width - 210) * config.legendPosition[0]}, ${(config.height - 35) * config.legendPosition[1]})`)
let legendX = config.legendPosition[0] == 0 ? config.marginLeft + 20 : config.legendPosition[0] == 0.5 ? config.width / 2 : config.width - config.marginLeft - 30;
let legendY = config.legendPosition[1] == 0 ? config.marginTop + 20 : config.legendPosition[1] == 0.5 ? config.height / 2 - 50 : config.height - config.marginTop - 110;
g.append('rect').attr('width', 200)
.attr('height', 30)
.attr('stroke', 'black')
.attr("stroke-width", 2)
.attr('fill', 'transparent')
g.append('g')
.attr('transform', `translate(0, 15)`)
config.svg.append('g')
.attr('transform', `translate(${legendX}, ${legendY})`)
.selectAll()
.data(config.legendData)
.join('g')
.attr('transform', (d, i) => `translate(${i * 90 + 20}, 0)`)
.call((g) =>
g.append("path")
.attr("class", "dot")
.attr("opacity", 1)
.attr("stroke-opacity", 1)
.attr("stroke-width", 2)
.attr("stroke", (d) => config.color(d))
.attr("fill", 'transparent')
.attr("fill-opacity", 1)
.attr("d", (d) => setSymbol(d)))
.attr('transform', (d, i) => `translate(0, ${i * 50})`)
.call((g) => g.append('rect').attr('width', 20).attr('height', 50).attr('fill', d => config.color(d)))
.call((g) =>
g
.append('text')
.attr('x', 15)
.attr('y', 0)
.attr('x', -10)
.attr('y', 25)
.attr('dy', '0.3em')
.style('font', '13px sans-serif')
.style('font', '10px sans-serif')
.style('text-anchor', 'middle')
.text((d) => d)
);
};
......@@ -85,13 +69,13 @@ export const setLegend = (config) => {
// scale
export const setScale = (config, data) => {
const xMax = d3.max(data, (d) => d.x)
const xMin = d3.min(data, (d) => d.x)
const yMax = d3.min(data, (d) => d.y)
const yMin = d3.min(data, (d) => d.y)
const xMax = d3.max(data, (d) => d.p1)
const xMin = d3.min(data, (d) => d.p1)
const yMax = d3.min(data, (d) => d.p2)
const yMin = d3.min(data, (d) => d.p2)
const xDomain = (Math.abs(xMax) >= Math.abs(xMin) ? Math.abs(xMax) : Math.abs(xMin)) + 10
const yDomain = (Math.abs(yMax) >= Math.abs(yMin) ? Math.abs(yMax) : Math.abs(yMin)) + 10
const xDomain = (Math.abs(xMax) >= Math.abs(xMin) ? Math.abs(xMax) : Math.abs(xMin)) + 6
const yDomain = (Math.abs(yMax) >= Math.abs(yMin) ? Math.abs(yMax) : Math.abs(yMin)) + 5
const x = d3
......@@ -114,8 +98,7 @@ export const setAxis = (config) => {
.style('font', '12px verdana')
.call(d3.axisBottom(config.x).tickSizeOuter(0))
.call(g => g.selectAll("line").clone()
.attr("display", d => d == 0 ? 'block' : 'none')
.attr("stroke-dasharray", '3')
.attr("stroke", d => d == 0 ? 'black' : '#aaa')
.attr("y2", -(config.height - config.marginBottom - config.marginTop))
)
.call((g) => g.selectAll('.domain').remove())
......@@ -133,8 +116,7 @@ export const setAxis = (config) => {
.style('font', '12px verdana')
.call(d3.axisLeft(config.y).ticks(null, 's'))
.call(g => g.selectAll("line").clone()
.attr("display", d => d == 0 ? 'block' : 'none')
.attr("stroke-dasharray", '3')
.attr("stroke", d => d == 0 ? 'black' : '#aaa')
.attr("x2", config.width - config.marginLeft - config.marginRight))
.call((g) => g.selectAll('.domain').remove())
config.svg.append('g')
......@@ -174,49 +156,48 @@ export const setElliptic = (config) => {
.attr('cy', `${config.ellipticOne.cy}`)
.attr('rx', `${config.ellipticOne.rx}`)
.attr('ry', `${config.ellipticOne.ry}`)
.attr('stroke', '#ADADAD')
.attr('stroke-width', 3)
.attr('stroke', 'black')
.attr('stroke-width', 1)
.attr('fill', 'transparent');
rects
.append('ellipse')
.attr('cx', `${config.ellipticAD.cx}`)
.attr('cy', `${config.ellipticAD.cy}`)
.attr('rx', `${config.ellipticAD.rx}`)
.attr('ry', `${config.ellipticAD.ry}`)
.attr('cx', `${config.ellipticM.cx}`)
.attr('cy', `${config.ellipticM.cy}`)
.attr('rx', `${config.ellipticM.rx}`)
.attr('ry', `${config.ellipticM.ry}`)
.attr('transform-origin', 'center')
.attr('transform', `rotate(${config.ellipticAD.rotate})`)
.attr('fill', config.colors[0])
.attr('fill-opacity', 0.2);
.attr('transform', `rotate(${config.ellipticM.rotate})`)
.attr('stroke', config.colors[0])
.attr('fill', 'transparent')
rects
.append('ellipse')
.attr('cx', `${config.ellipticNon_AD.cx}`)
.attr('cy', `${config.ellipticNon_AD.cy}`)
.attr('rx', `${config.ellipticNon_AD.rx}`)
.attr('ry', `${config.ellipticNon_AD.ry}`)
.attr('cx', `${config.ellipticF.cx}`)
.attr('cy', `${config.ellipticF.cy}`)
.attr('rx', `${config.ellipticF.rx}`)
.attr('ry', `${config.ellipticF.ry}`)
.attr('transform-origin', 'center')
.attr('transform', `rotate(${config.ellipticNon_AD.rotate})`)
.attr('fill', config.colors[1])
.attr('fill-opacity', 0.2);
.attr('transform', `rotate(${config.ellipticF.rotate})`)
.attr('stroke', config.colors[1])
.attr('fill', 'transparent')
}
// point
export const setPoint = (config, data) => {
return config.svg
.append("g")
.selectAll("path")
.selectAll("text")
.data(data)
.join("path")
.attr("class", "dot")
.attr("opacity", 1)
.attr("stroke-opacity", 1)
.attr("stroke-width", 2)
.attr("stroke", (d) => config.color(d.name))
.attr("fill", 'transparent')
.attr("fill-opacity", 1)
.attr("d", (d) => setSymbol(d.name))
.attr("transform", d => `translate(${config.x(d.x)}, ${config.y(d.y)})`)
.join("text")
.attr("dy", "0.35em")
.attr("x", d => config.x(d.p1) + 7)
.attr("y", d => config.y(d.p2))
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr('cursor', 'default')
.attr('fill', d => config.color(d.group))
.text(d => d.sample)
}
// title
......
......@@ -12,6 +12,7 @@
import { ref, shallowRef } from 'vue';
import LinearFitting from '../../components/LinearFitting/index.vue';
import PcaAnalysis from '../../components/PcaAnalysis/index.vue';
import OplsDa from '../../components/OplsDa/index.vue';
import MsDimplot from '../../components/MsDimplot/index.vue';
import FeaturePlot from '../../components/FeaturePlot/index.vue';
import BeeColonyDiagram from '../../components/BeeColonyDiagram/index.vue';
......@@ -26,13 +27,14 @@ const chartCurrent = ref(0);
const chartList = shallowRef([
{ title: '线性拟合图', value: 1, comName: LinearFitting },
{ title: 'pca分析图', value: 2, comName: PcaAnalysis },
{ title: 'ms-dimplot', value: 3, comName: MsDimplot },
{ title: 'Feature Plot', value: 4, comName: FeaturePlot },
{ title: '蜂群图', value: 5, comName: BeeColonyDiagram },
{ title: '相关性分析', value: 6, comName: CorrelationAnalysis },
{ title: '聚类热图', value: 7, comName: ClusterHeatmap },
{ title: '聚类热图-2', value: 8, comName: ClusterHeatmapSecond },
{ title: '环状热图', value: 9, comName: CircularHeatmap },
{ title: 'opls-da', value: 3, comName: OplsDa },
{ title: 'ms-dimplot', value: 4, comName: MsDimplot },
{ title: 'Feature Plot', value: 5, comName: FeaturePlot },
{ title: '蜂群图', value: 6, comName: BeeColonyDiagram },
{ title: '相关性分析', value: 7, comName: CorrelationAnalysis },
{ title: '聚类热图', value: 8, comName: ClusterHeatmap },
{ title: '聚类热图-2', value: 9, comName: ClusterHeatmapSecond },
{ title: '环状热图', value: 10, comName: CircularHeatmap },
{ title: 'test', value: 0, comName: Test }
]);
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论