58 lines
2.8 KiB
JavaScript
58 lines
2.8 KiB
JavaScript
/* ============================================================
|
|
stats.js — Statistics 탭 (논문 + 단백질 카탈로그 통계)
|
|
============================================================ */
|
|
(function () {
|
|
'use strict';
|
|
let charts = {}, rendered = false;
|
|
const C = ['#2f63c8', '#7c3aed', '#0e7490', '#1f8a5b', '#b07a12', '#c8401f', '#c2367f', '#c0561f', '#5b6470', '#9333ea'];
|
|
|
|
function count(arr, key) {
|
|
const m = {};
|
|
arr.forEach(x => { const k = (typeof key === 'function' ? key(x) : x[key]) || '기타'; m[k] = (m[k] || 0) + 1; });
|
|
return m;
|
|
}
|
|
function sorted(obj, n) { return Object.entries(obj).sort((a, b) => b[1] - a[1]).slice(0, n || 99); }
|
|
|
|
function doughnut(id, obj, n) {
|
|
const e = sorted(obj, n);
|
|
mk(id, 'doughnut', {
|
|
labels: e.map(x => x[0]), datasets: [{ data: e.map(x => x[1]), backgroundColor: C, borderColor: '#fbf9f4', borderWidth: 2 }]
|
|
}, { plugins: { legend: { position: 'right', labels: { color: '#4a463d', font: { size: 11 }, boxWidth: 12 } } } });
|
|
}
|
|
function bar(id, obj, n, horizontal) {
|
|
const e = sorted(obj, n);
|
|
mk(id, 'bar', {
|
|
labels: e.map(x => x[0]), datasets: [{ data: e.map(x => x[1]), backgroundColor: C[0], borderRadius: 4 }]
|
|
}, {
|
|
indexAxis: horizontal ? 'y' : 'x', plugins: { legend: { display: false } },
|
|
scales: { x: { ticks: { color: '#6b655a', font: { size: 10 } }, grid: { color: 'rgba(0,0,0,.08)' } },
|
|
y: { ticks: { color: '#6b655a', font: { size: 10 } }, grid: { display: false } } }
|
|
});
|
|
}
|
|
function line(id, obj) {
|
|
const e = Object.entries(obj).filter(([y]) => /^\d{4}$/.test(y)).sort();
|
|
mk(id, 'line', {
|
|
labels: e.map(x => x[0]),
|
|
datasets: [{ data: e.map(x => x[1]), borderColor: '#22d3ee', backgroundColor: 'rgba(34,211,238,.12)', fill: true, tension: .3, pointRadius: 2 }]
|
|
}, { plugins: { legend: { display: false } }, scales: { x: { ticks: { color: '#6b655a' }, grid: { display: false } }, y: { ticks: { color: '#6b655a' }, grid: { color: 'rgba(0,0,0,.08)' } } } });
|
|
}
|
|
function mk(id, type, data, opts) {
|
|
const ctx = document.getElementById(id); if (!ctx) return;
|
|
if (charts[id]) charts[id].destroy();
|
|
charts[id] = new Chart(ctx, { type, data, options: Object.assign({ responsive: true, maintainAspectRatio: false }, opts) });
|
|
}
|
|
|
|
function render() {
|
|
if (rendered) return; rendered = true;
|
|
const papers = (Store.analysis && Store.analysis.papers) || [];
|
|
const proteins = Store.catalog.proteins;
|
|
doughnut('chart-disease', count(papers, 'disease'), 6);
|
|
bar('chart-axis', count(proteins.filter(p => p.twin_node && p.twin_node !== '—'), 'twin_node'), 8, true);
|
|
line('chart-trend', count(papers, 'pubYear'));
|
|
bar('chart-pathway', count(proteins, 'pathway'), 10, true);
|
|
doughnut('chart-modality', count(papers, p => p.modality), 6);
|
|
}
|
|
|
|
window.StatsTab = { render };
|
|
})();
|