@sjcrh/proteinpaint-server 2.172.0 → 2.174.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/routes/grin2.js +173 -95
- package/routes/termdb.chat.js +718 -107
- package/routes/termdb.cluster.js +2 -1
- package/routes/termdb.runChart.js +34 -28
- package/src/app.js +1013 -301
package/routes/termdb.cluster.js
CHANGED
|
@@ -69,7 +69,7 @@ async function getResult(q, ds) {
|
|
|
69
69
|
({ term2sample2value, byTermId, bySampleId } = await getNumericDictTermAnnotation(q, ds));
|
|
70
70
|
} else {
|
|
71
71
|
;
|
|
72
|
-
({ term2sample2value, byTermId, bySampleId, skippedSexChrGenes } = await ds.queries[q.dataType].get(_q));
|
|
72
|
+
({ term2sample2value, byTermId, bySampleId, skippedSexChrGenes } = await ds.queries[q.dataType].get(_q, ds));
|
|
73
73
|
}
|
|
74
74
|
const noValueTerms = [];
|
|
75
75
|
for (const [term, obj] of term2sample2value) {
|
|
@@ -206,6 +206,7 @@ async function validate_query_geneExpression(ds, genome) {
|
|
|
206
206
|
const q = ds.queries.geneExpression;
|
|
207
207
|
if (!q) return;
|
|
208
208
|
q.geneExpression2bins = {};
|
|
209
|
+
if (typeof q.get == "function") return;
|
|
209
210
|
if (q.src == "gdcapi") {
|
|
210
211
|
gdc_validate_query_geneExpression(ds, genome);
|
|
211
212
|
return;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { runChartPayload } from "#types/checkers";
|
|
2
|
+
import { getNumberFromDate } from "#shared/terms.js";
|
|
2
3
|
const api = {
|
|
3
4
|
endpoint: "termdb/runChart",
|
|
4
5
|
methods: {
|
|
@@ -13,23 +14,9 @@ const api = {
|
|
|
13
14
|
}
|
|
14
15
|
};
|
|
15
16
|
async function getRunChart(q, ds) {
|
|
16
|
-
const terms = [];
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (q.term && q.term2) {
|
|
20
|
-
const tws = [
|
|
21
|
-
{ term: q.term, q: { mode: "continuous" }, $id: q.term.id },
|
|
22
|
-
{ term: q.term2, q: { mode: "continuous" }, $id: q.term2.id }
|
|
23
|
-
];
|
|
24
|
-
terms.push(...tws);
|
|
25
|
-
xTermId = q.term.id;
|
|
26
|
-
yTermId = q.term2.id;
|
|
27
|
-
} else {
|
|
28
|
-
throw new Error("term and term2 must be provided");
|
|
29
|
-
}
|
|
30
|
-
if (!xTermId || !yTermId) {
|
|
31
|
-
throw new Error("Unable to determine term IDs for x and y axes");
|
|
32
|
-
}
|
|
17
|
+
const terms = [q.term, q.term2];
|
|
18
|
+
const xTermId = q.term["$id"];
|
|
19
|
+
const yTermId = q.term2["$id"];
|
|
33
20
|
const { getData } = await import("../src/termdb.matrix.js");
|
|
34
21
|
const data = await getData(
|
|
35
22
|
{
|
|
@@ -81,16 +68,20 @@ function buildRunChartFromData(aggregation, xTermId, yTermId, data) {
|
|
|
81
68
|
month = Math.floor(frac * 12) + 1;
|
|
82
69
|
}
|
|
83
70
|
} else {
|
|
84
|
-
|
|
71
|
+
year = null;
|
|
85
72
|
}
|
|
86
73
|
if (year == null || month == null || Number.isNaN(year) || Number.isNaN(month)) {
|
|
87
|
-
|
|
88
|
-
|
|
74
|
+
skippedSamples++;
|
|
75
|
+
console.log(
|
|
76
|
+
`Skipping sample ${sampleId}: Invalid date value - xTermId=${xTermId}, xRaw=${xRaw}, parsed year=${year}, month=${month}`
|
|
89
77
|
);
|
|
78
|
+
continue;
|
|
90
79
|
}
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
const
|
|
80
|
+
const yearNum = year;
|
|
81
|
+
const monthNum = month;
|
|
82
|
+
const bucketKey = `${yearNum}-${String(monthNum).padStart(2, "0")}`;
|
|
83
|
+
const x = Number(`${yearNum}.${String(monthNum).padStart(2, "0")}`);
|
|
84
|
+
const date = new Date(yearNum, monthNum - 1, 1);
|
|
94
85
|
const xName = date.toLocaleString("en-US", { month: "long", year: "numeric" });
|
|
95
86
|
if (!buckets[bucketKey]) {
|
|
96
87
|
buckets[bucketKey] = {
|
|
@@ -101,7 +92,7 @@ function buildRunChartFromData(aggregation, xTermId, yTermId, data) {
|
|
|
101
92
|
success: 0,
|
|
102
93
|
total: 0,
|
|
103
94
|
countSum: 0,
|
|
104
|
-
sortKey:
|
|
95
|
+
sortKey: yearNum * 100 + monthNum,
|
|
105
96
|
yValues: []
|
|
106
97
|
};
|
|
107
98
|
}
|
|
@@ -162,18 +153,33 @@ function buildRunChartFromData(aggregation, xTermId, yTermId, data) {
|
|
|
162
153
|
if (skippedSamples > 0) {
|
|
163
154
|
console.log(`buildRunChartFromData: Skipped ${skippedSamples} sample(s) due to missing x or y values`);
|
|
164
155
|
}
|
|
156
|
+
function xFromBucket(b) {
|
|
157
|
+
const yearNum = Math.floor(b.sortKey / 100);
|
|
158
|
+
const monthNum = b.sortKey % 100;
|
|
159
|
+
const x = getNumberFromDate(new Date(yearNum, monthNum - 1, 15));
|
|
160
|
+
return Math.round(x * 100) / 100;
|
|
161
|
+
}
|
|
165
162
|
const points = Object.values(buckets).sort((a, b) => a.sortKey - b.sortKey).map((b) => {
|
|
163
|
+
const x = xFromBucket(b);
|
|
166
164
|
if (aggregation === "proportion") {
|
|
167
165
|
const total = b.total || 0;
|
|
168
166
|
const succ = b.success || 0;
|
|
169
167
|
const y = total ? Math.round(succ / total * 1e3) / 1e3 : 0;
|
|
170
|
-
return { x
|
|
168
|
+
return { x, xName: b.xName, y, sampleCount: total };
|
|
171
169
|
} else if (aggregation === "count") {
|
|
172
170
|
const y = Math.round((b.countSum || 0) * 100) / 100;
|
|
173
|
-
return { x
|
|
171
|
+
return { x, xName: b.xName, y, sampleCount: b.count };
|
|
174
172
|
} else {
|
|
175
|
-
|
|
176
|
-
|
|
173
|
+
let y;
|
|
174
|
+
if (aggregation === "median" && (b.yValues?.length ?? 0) > 0) {
|
|
175
|
+
const sorted = [...b.yValues].sort((a, b2) => a - b2);
|
|
176
|
+
const mid = Math.floor(sorted.length / 2);
|
|
177
|
+
y = sorted.length % 2 === 1 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
|
178
|
+
} else {
|
|
179
|
+
y = b.count ? b.ySum / b.count : 0;
|
|
180
|
+
}
|
|
181
|
+
y = Math.round(y * 100) / 100;
|
|
182
|
+
return { x, xName: b.xName, y, sampleCount: b.count };
|
|
177
183
|
}
|
|
178
184
|
});
|
|
179
185
|
const yValues = points.map((p) => p.y).filter((v) => typeof v === "number" && !Number.isNaN(v));
|