์ง๋ ํ๋ ์์ฝ
์ง๋ ํ๋์ ๋ฐํ์ผ๋ก ์ด๋ฒ์๋ ์ด๋ค ์์ ์ ํ ์ง ์ ํด๋ณด์๋ค
์ง๋ ๋ฒ์ Cytoscape์๋ ์ด๋ค ๋ ์ด์์๋ค์ด ์กด์ฌํ๋์ง ํ์ ํ๊ณ , ๊ฐ ๋ ์ด์์๋ค์ ์ฑ๋ฅ์ ๊ฐ๋ณ๊ฒ ์ธก์ ํด๋ณด์๋ค.
๊ทธ ๊ฒฐ๊ณผ fcose ๋ ์ด์์์ด ์ฐ๋ฆฌ์ ์ฃผ์ ์ ๊ฐ์ฅ ์ ํฉํ๋ค๊ณ ์๊ฐํ๊ณ , ์ฑ๋ฅ๋ ๋์์ง ์์๋ค.
=> fcose ๋ ์ด์์์ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ๊ณ , ๋ค๋ฅธ ๋ ์ด์์๋ค์ ์ ์ ๊ฐ ์ ํ์ ๋ณด์ฌ์ค ์ ์๋๋ก ํ๋ ๋ฐฉํฅ์ผ๋ก ๊ฒฐ์ ์ ๋ด๋ ธ๋ค.
์ด๋ฒ ํ๋ ์์ฝ
์ด๋ฒ์ ํด์ผ ํ ์์ ์ ํฌ๊ฒ 2๊ฐ์ง๋ก ์ ํ๋ค
1. ๊ฐ ์ปค๋ฎค๋ํฐ ๋ณ๋ก ๋ค๋ฅธ ์ ์ผ๋ก ๋ํ๋ด๊ณ ,
2. Degree๊ฐ ํฐ ๋ ธ๋์ผ์๋ก ๋ ธ๋์ ํฌ๊ธฐ๋ฅผ ํฌ๊ฒ ํํํ๋ ๊ฒ์ด๋ค.
Degree์ ๋ฐ๋ผ ํฌ๊ธฐ ์กฐ์ ํ๊ธฐ
Degree๊ฐ ํฐ ๋ ธ๋๋ ํฌ๊ธฐ๋ฅผ ํฌ๊ฒ ํํํด์ ์ธ์ํ๊ธฐ ์ฝ๊ฒ ํ๊ธฐ ์ํจ
๋น๊ต์ ์ฌ์๋ณด์ด๋ ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ๋ ๊ธฐ๋ฅ๋ถํฐ ๋์ ํ๋ค.
์ฌ์๋ณด์๋ ์ด์ ๋ Cytoscape.js ์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณตํ๋ ๊ธฐ๋ฅ ์ค์ degree๋ฅผ ์ธก์ ํด์ฃผ๋ ๊ธฐ๋ฅ์ด ์๊ธฐ ๋๋ฌธ์ด๋ค.
export const styleSheet: StyleType[] = [
{
selector: "node",
style: {
backgroundColor: (ele): string => ele._private.data.color,
width: (ele) => {
const degree = ele.degree();
const scalingFactor = degree >= 30 ? 10 : 20; // ์ค์ผ์ผ๋ง ํฉํฐ ์กฐ์
const minSize = 20; // ์ต์ ํฌ๊ธฐ
const maxSize = 80; // ์ต๋ ํฌ๊ธฐ
// Degree์ ๋น๋กํ์ฌ ํฌ๊ธฐ๋ฅผ ๋์ ์ผ๋ก ๊ณ์ฐ
const size = degree * scalingFactor;
// ์ต์ ๋ฐ ์ต๋ ํฌ๊ธฐ ์ ์ฉ
return Math.max(minSize, Math.min(size, maxSize)) as number;
},
height: (ele) => {
const degree = ele.degree();
const scalingFactor = degree >= 30 ? 10 : 20;
const minSize = 20;
const maxSize = 80;
const size = degree * scalingFactor;
return Math.max(minSize, Math.min(size, maxSize));
},
// Adjust the scaling factor as needed
label: "data(label)",
...
}
๊ทธ๋ํ์ ์คํ์ผ์ ์ค์ ํ ์ ์๋ styleSheet์์ width, height ๋ถ๋ถ์ ์์ ํด์ฃผ์๋ค.
์ด์ ์๋ width, height๋ฅผ ์์๊ฐ์ผ๋ก ๊ณ ์ ํ์์ง๋ง, ์ด์ ๋ degree๊ฐ์ ์ด์ฉํด์ ๋์ ์ผ๋ก ์ค์ ํ๋ค.
๋จ์ํ degree์ ๋น๋กํด์ ์ฌ์ด์ฆ๊ฐ ์ปค์ง๋๋ก ํ๋ฉด degree๊ฐ ์๋์ ์ผ๋ก ํฐ ๋ ธ๋๊ฐ ์กด์ฌํ๋ฉด ๋๋จธ์ง ๋ ธ๋๋ค์ด ๋๋ฌด ์์์ง๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด์ ์ต๋ ์ต์ ์ฌ์ด์ฆ๋ฅผ ์ง์ ํ๋ค.
๊ทธ ๊ฒฐ๊ณผ ์ด๋ ๊ฒ degree์ ๋ฐ๋ผ ํฌ๊ธฐ๊ฐ ๋ณํ๋ ๋ ธ๋๋ฅผ ๋ง๋ค ์ ์์๋ค.
์ปค๋ฎค๋ํฐ๋ณ๋ก ๋ ธ๋ ์์ ๋ค๋ฅด๊ฒ ํ๊ธฐ
์ปค๋ฎค๋ํฐ๋ฅผ Detectionํด์ ๊ฐ ์ปค๋ฎค๋ํฐ๋ง๋ค ๋ค๋ฅธ ์์์ ๋ถ์ฌํ๋ค
๋ฌธ์ ๋ ์ปค๋ฎค๋ํฐ๋ฅผ detectionํด์ ๋ ธ๋์ ์์์ ๋ค๋ฅด๊ฒ ์ง์ ํ๋ ๊ฒ์ด์๋ค.
์ฌ์ ์ ์ปค๋ฎค๋ํฐ๋ฅผ ๋ฏธ๋ฆฌ ์ ์ ์๋ค๋ฉด ๊ทธ ์ปค๋ฎค๋ํฐ์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ์์์ ์ง์ ํ๋ฉด ๋๊ฒ ์ง๋ง, ๋ค์ด์ค๋ ๋ฐ์ดํฐ์๋ Node์ Edge ์ ๋ณด๋ง ์กด์ฌํ ๋ฟ ์ปค๋ฎค๋ํฐ์ ๋ํ ์ ๋ณด๋ ์์๋ค.
๋จผ์ Cytosacpe์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ปค๋ฎค๋ํฐ๋ฅผ ํ์งํด์ฃผ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋์ง๋ฅผ ์ดํด๋ณด์์ง๋ง, ๋ด๋ถ์ ์ผ๋ก ์ปค๋ฎค๋ํฐ๋ฅผ ํ์งํ๋ค๊ณ ํ๋๋ผ๋ ๊ทธ๊ฑธ ์ด์ฉํด์ ๋ด๊ฐ ์์์ ์ ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ฐพ์ง ๋ชปํ๋ค.
์ฑ์งํผํฐ์๊ฒ๋ ๋ฌผ์ด๋ดค์ง๋ง, ๋ฏธ๋ฆฌ ์๊ณ ์๋ ์ปค๋ฎค๋ํฐ ์ ๋ณด์ ๋ฐ๋ผ ๋ค๋ฅธ ์์์ ์ง์ ํ๋ ๋ฐฉ๋ฒ๋ง์ ์๋ ค์ค ๋ฟ, ์ปค๋ฎค๋ํฐ๋ฅผ ๋จผ์ detectionํ๊ณ ๊ทธ ์ปค๋ฎค๋ํฐ์ ๋ฐ๋ผ ๋ค๋ฅธ ์์์ ์ง์ ํ๋ ๋ฐฉ๋ฒ์ ์๋ ค์ฃผ์ง ์์๋ค.
์คํ ์ค๋ฒํ๋ก์ฐ์์ ๋์ ๊ฐ์ ์์ ์ ํ๊ธฐ๋ฅผ ์ํ๋ ์ฌ๋์ ์ฐพ์์ง๋ง, ์ด ์ฌ๋์ ๋ถ๋ชจ ๋ ธ๋์ ๊ฐ์ ์์์ ์น ํ๋ ๋ฐฉ๋ฒ์ ์ ํํ๋ค.
๊ทธ๋ฐ๋ฐ ์ฐ๋ฆฌ์ ๋ฐ์ดํฐ๋ ์๋ฐฉํฅ ๊ฐ์ ์ด๊ธฐ ๋๋ฌธ์ ๋ถ๋ชจ ๋
ธ๋๋ผ๋ ๊ฐ๋
์ด ์กด์ฌํ์ง ์์๋ค.
๊ทธ๋ ์ง๋ง ์ด ๊ธ์ ๋ณด๊ณ ์๊ฐ์ ์ป์ ์ ์์๋ค.
์ด๋ป๊ฒ ํ๋ฉด ๊ฐ ๋ ธ๋๊ฐ ๊ฐ์ ์ปค๋ฎคํฐ๋์ ์ํด์๋์ง ๊ตฌ๋ถํ ์ ์์๊น?
๊ณ ๋ฏผ๋์ ์ ๋์จ ํ์ธ๋ ์๊ณ ๋ฆฌ์ฆ ์ด ๋ ์ฌ๋๋ค.
๊ฐ์ ์งํฉ์ ์์๋ ๋ ธ๋๋ผ๋ฉด ๋น์ฐํ๊ฒ ๊ฐ์ ์ปค๋ฎค๋ํฐ์ ์ํ ๋ ธ๋์ผ ๊ฒ์ด๋ค.
//๋
ธ๋ ์์ ๋ชฉ๋ก
{
...
const colors: string[] = [
"#ff6961",
"#77dd77",
"#e79eff",
"#84b6f4",
"#b0f2c2",
"#ffda9e",
];
let colorIdx = 0;
const parent: { [key: string]: Node } = {};
const Find = (nowNode: Node): Node => {
const parentNode = parent[nowNode.node];
if (nowNode.node === parentNode.node) return parentNode;
else return (parent[nowNode.node] = Find(parentNode));
};
const Union = (nodeA: Node, nodeB: Node): void => {
const parentA = parent[nodeA.node];
const parentB = parent[nodeB.node];
parent[parentA.node] = parentB;
};
lines.forEach((line) => {
const parts = line.split("\t");
const sourceId = `${parts[0]}`;
const targetId = `${parts[1]}`;
const sourceNode = {
node: sourceId,
color:
parent[sourceId] === undefined
? colors[colorIdx++ % colors.length]
: parent[sourceId].color,
};
const targetNode = {
node: targetId,
color:
parent[targetId] === undefined
? colors[colorIdx++ % colors.length]
: parent[targetId].color,
};
//๋ง์ฝ ๋ถ๋ชจ ๋
ธ๋๊ฐ ์๋ค๋ฉด ์๊ธฐ ์์ ์ผ๋ก ์ธํ
if (parent[sourceNode.node] === undefined) {
parent[sourceId] = sourceNode;
}
if (parent[targetNode.node] === undefined) {
parent[targetId] = targetNode;
}
//๊ฐ์ ํด๋ฌ์คํฐ๊ฐ ์๋๋ผ๋ฉด Union
if (Find(sourceNode).node !== Find(targetNode).node) {
Union(sourceNode, targetNode);
}
...
}
data.nodes.map((nowNode) => {
const coloredNode = {
...nowNode.data,
color: Find({ node: nowNode.data.id as string, color: "" }).color,
};
nowNode.data = coloredNode;
});
๋ฌผ๋ก ์๋ฐฉํฅ ๊ฐ์ ์ด์ง๋ง, ํ์ชฝ์ด ๋ถ๋ชจ๊ฐ ๋๋ค๊ณ ์๊ฐํ๊ณ ์งํํ๋ค.
=> ์ด์งํผ ๊ฐ์ ์งํฉ์ ์ํ๋์ง๋ง ์์๋ด๋ฉด ๋๊ธฐ ๋๋ฌธ
๊ทธ๋ ๊ฒ ํด์ ์ต์ข ์ ์ผ๋ก ์ต์์ ๋ถ๋ชจ๋ ธ๋์ ์์์ ๋ฐ๋ฅด๋๋ก ์์์ ์ค์ ํ๋ค.
๋
ธ๋์ ์๊ฐ ๋ง์๋ ์์ฒ๊ฐ์ผ ๊ฒ์ด๋ผ ์๊ฐํ๊ณ ,
๊ฒฝ๋ก ์์ถ์ ํ์ ๋ Find์ ์๊ฐ ๋ณต์ก๋๋ ์์์๊ฐ์ด๊ธฐ ๋๋ฌธ์ ๋ ๋๋ง ์๋์ ํฐ ์ํฅ์ ๋ฏธ์น์ง ์์ ๊ฒ์ด๋ผ ์๊ฐํ๋ค.
๊ทธ ๊ฒฐ๊ณผ ์ด๋ ๊ฒ ์ปค๋ฎค๋ํฐ์ ๋ฐ๋ผ ๋ค๋ฅธ ์์์ ๋ ๋๋ก ํ ์ ์์๋ค.
์กฐ๊ธ ๋ ๊ตฌ๋ถ์ด ์๋๋ ์์๋ค๋ก ์ง์ ํ๋ฉด ๋ ์ ๋ช
ํ๊ฒ ํด๋ฌ์คํฐ๋ง์ด ๊ฐ๋ฅํ ๊ฒ ๊ฐ๋ค.
์ ๋์จ ํ์ธ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ด๋ฐ ๊ณณ์์ ์ฌ์ฉํ๊ฒ ๋ ์ค์ ๋ชฐ๋๋ค.
์ด๋ฐ ๋ฐฉ๋ฒ์ด ๋ ์ฌ๋๋ค๋ ๊ฒ์ด ๋ฟ๋ฏํ๊ณ , ์ค์ ์ ์ฉ์ด ๋์๋ค๋ ๊ฒ๋ ์ ๊ธฐํ๋ค.
์ด๋ฒ ํ๋ก์ ํธ๋ฅผ ํตํด ์ ์๊ณ ๋ฆฌ์ฆ์ ๊ทธ๋ ๊ฒ ๊ฐ์กฐํ๊ณ , ์ค์ํ๊ฒ ์๊ฐํ๋์ง ์กฐ๊ธ์ด๋๋ง ์๊ฒ ๋์๋ค.
๋ค์ ๋ชฉํ
1. ๊ธฐ์กด์ ์กด์ฌํ๋ ์น ํ์ด์ง๋ฅผ ์ด๋ป๊ฒ ์ ์ฎ์ด์ migration ํ ๊ฒ์ธ์ง ๊ณ ๋ฏผ
2. ์ด๋ค ์์ผ๋ก ๋์์ธ ์ ํด์ผ ์ฐ๋ฆฌ๊ฐ ๊ตฌํํ๋ ๊ธฐ๋ฅ์ ์ ์ฌ์ฉํ ์ ์์์ง ๊ณ ๋ฏผ
'HYU > ์กธ์ ํ๋ก์ ํธ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
5. ์ ์ , ๊ฐ์ ์ถ๊ฐ ๋ฐ ์ญ์ (0) | 2024.03.04 |
---|---|
4. ํ์ด์ง ๋ ์ด์์ ๋์์ธ ๋ฐ ๋ณ๊ฒฝ (0) | 2024.02.26 |
2. Layout ํ์ ๋ฐ ์ฑ๋ฅ ์ธก์ (0) | 2024.01.31 |
1. ๋คํธ์ํฌ ์๊ฐํ ํด ํ์ (0) | 2024.01.25 |
0. ์ฃผ์ ํ์ธ ๋ฐ ๊ณํ (0) | 2024.01.24 |