Skip to content

Commit

Permalink
#48 calculate ratio for each metabolite and each project
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcellino-Palerme committed Sep 4, 2024
1 parent af805a5 commit 08b736c
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 25 deletions.
3 changes: 3 additions & 0 deletions server/api/AssociateCalibCurves.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-License-Identifier: MIT

import pg from "pg";
import { updateRatio } from "./function/updateRatio";

export default defineEventHandler(async (event) => {
const body = await readBody(event);
Expand All @@ -20,6 +21,8 @@ export default defineEventHandler(async (event) => {
VALUES ${lValues.join(",")}`
)
})
// Update the ratio of the metabolite
.then(() => {updateRatio(body.id_project)})
.catch((err: Error) => {
throw err;
})
Expand Down
2 changes: 2 additions & 0 deletions server/api/DisassociateCalibCurves.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-License-Identifier: MIT

import pg from "pg";
import { updateRatio } from "./function/updateRatio";

export default defineEventHandler((event) => {
return readBody(event)
Expand All @@ -15,6 +16,7 @@ export default defineEventHandler((event) => {
WHERE id_calib_curves IN
(${body.calibCurves.join(",")})
AND id_project = ${body.id_project}`))
.then(() => {updateRatio(body.id_project)})
.finally(() => client.end());
});
});
37 changes: 16 additions & 21 deletions server/api/extract.post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,46 +34,41 @@ async function exportFile(addressFile: {
* @param indexMeta index of name of metabolite in sample
* @param indexArea index of area in sample
*/
function CalculateConcentration(sample: string[], lMolRatio: { [key: string]: number }, indexMeta:number, indexArea:number): string[] {
function CalculateConcentration(sample: string[], lMolRatio: { [key: string]: number[] }, indexMeta:number, indexArea:number): string[] {
const tempSample = sample;
// no metabolites in calibration curves associate of project
if(lMolRatio[tempSample[indexMeta]] === undefined){
return [...tempSample, "0"];
}
// calculate Concentration
tempSample.push((parseFloat(tempSample[indexArea]) * lMolRatio[tempSample[indexMeta]]).toString());
tempSample.push((
parseFloat(tempSample[indexArea]) * lMolRatio[tempSample[indexMeta]][0]
+ lMolRatio[tempSample[indexMeta]][1])
.toString());

return tempSample;
}

async function GetRatio(client: unknown, idProject: string):
Promise<{[key:string]:number}> {
// get all calibration curves of project
return client.query(`SELECT id_calib_curves
FROM proj_calib_curves
// get all ratios of project
return client.query(`SELECT id_mol, coef, ord
FROM ratio
WHERE id_project = ${idProject}`)
.then((respQuery: { rows: { id_calib_curves: string }[] }) => {
.then((respQuery: { rows: {
id_mol: string,
coef: string,
ord: string }[] }
) => {
if (respQuery.rows.length === 0) {
throw new Error("No associated series");
}

const idCalibCurves = respQuery.rows.map(x => x.id_calib_curves);
// get all metabolite of calibration curves
return client.query(`
SELECT id_mol, ratio
FROM ratio
WHERE id_calib_curves IN (${idCalibCurves.join(",")})`
);
})
.then((respQuery: { rows: { id_mol: string, ratio: number }[] }) => {

if (respQuery.rows.length === 0) {
throw new Error("No ratio");
}
// associate one metabolite to one ratio
const lMolRatio:{[key:string]:number} = {};
const lMolRatio:{[key:string]:number[]} = {};
for (const row of respQuery.rows) {
lMolRatio[row.id_mol] = row.ratio;
lMolRatio[row.id_mol] = [parseFloat(row.coef),
parseFloat(row.ord)];
}

return lMolRatio;
Expand Down
49 changes: 45 additions & 4 deletions server/api/function/RegCalibCurve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,39 @@ export async function calculateRatioCalibCurve(arrayIdCalibCurve: string[]): Pro
`)
})
.then((res: { rows: any[] }) => {
console.log("meth", res.rows);

// create array area/concentration for each metabolite
const metaConcentration: { [key: string]: [number, number][] } = {};
// Group the area and concentration of each metabolite
res.rows.map((row) => {metaConcentration[row.id_mol].push([row.area, row.concentration])});
res.rows.forEach((row) => {
if (!metaConcentration[row.id_mol]) {
metaConcentration[row.id_mol] = [];
}
metaConcentration[row.id_mol].push([row.area, row.concentration]);
});
console.log("metaConcentration0", metaConcentration);

// add the first element to 0,0 if we have one point for the
// metabolite
for (const key in metaConcentration) {
if (metaConcentration[key].length === 1) {
// We check after the deletion of the double point
if (deleteDoublePoint(metaConcentration[key]).length === 1) {
metaConcentration[key].push([0, 0]);
}
}

console.log("metaConcentration", metaConcentration);

// caclulate regression of each metabolite in ax + b
const metaRatio: { [key: string]: {a: number, b: number} } = {}
for (const key in metaConcentration) {
// calculate the linear regression
console.log(key, metaConcentration[key]);

const { m, b } = linearRegression(metaConcentration[key]);
metaRatio[key] = {a: m, b: b};
}
console.log("metaRatio", metaRatio);
return metaRatio
})
.catch(() => {
Expand All @@ -50,4 +64,31 @@ export async function calculateRatioCalibCurve(arrayIdCalibCurve: string[]): Pro
// close the connection
client.end();
});
}
}

/**
* Delete double point in the array
* @param array
* @returns array without double point
*/
function deleteDoublePoint(array: [number, number][]): [number, number][] {
// Track Seen Strings: A Set is used to keep track of the
// string representations of sub-arrays that have already been
// encountered.
const seen = new Set();
return array.filter(subArray => {
// Convert Sub-Arrays to Strings:
const stringified = JSON.stringify(subArray);
// Check if the stringified sub-array has already been
// encountered:
if (seen.has(stringified)) {
// If it has been encountered, return false to remove
return false;
} else {
// keep the stringified sub-array in the set:
seen.add(stringified);
// keep the sub-array in the filtered array:
return true;
}
});
}
77 changes: 77 additions & 0 deletions server/api/function/updateRatio.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-FileCopyrightText: 2024 Marcellino Palerme <[email protected]>
//
// SPDX-License-Identifier: MIT

// This file provide function to add or update ratio of metabolite associate to project

import pg from "pg";
import { calculateRatioCalibCurve } from "./RegCalibCurve";

export async function updateRatio(id_project: string): Promise<void> {
const client = new pg.Client();
client.connect()
.then(() => {
// Get all calibration curve associate to the project
return client.query(`
SELECT id_calib_curves
FROM proj_calib_curves
WHERE id_project = '${id_project}'
`)
})
.then((res: { rows: any[] }) => {
// Delete all ratio associate to the project if no
// calibration curve
if (res.rows.length === 0) {
client.query(`
DELETE FROM ratio
WHERE id_project = '${id_project}'
`);
return [];
}

// structure the array of id_calib_curves
return res.rows.map((value : {id_calib_curves:string}) =>
value.id_calib_curves);
})
.then((arrayIdCalibCurve: string[]) => {
console.log(arrayIdCalibCurve);

// Get the ratio of each metabolite of the calibration curve
return calculateRatioCalibCurve(arrayIdCalibCurve);
})
.then((metaRatio: { [key: string]: {a: number, b: number} }) => {
console.log(metaRatio);

// Update the ratio of each metabolite
for (const key in metaRatio) {
updateRatioMetabolite(key, id_project, metaRatio[key].a, metaRatio[key].b);
}
})
.catch((err) => {
console.error("connection error", err.stack);
})
.finally(() => {
client.end();
});

}

async function updateRatioMetabolite(id_mol: string, id_project: string, coef: number, ord: number): Promise<void> {
const client = new pg.Client();
client.connect()
.then(() => {
// Add or Update the ratio of the metabolite
const query = {
text: `INSERT INTO ratio (id_mol, id_project, coef, ord) VALUES ($1, $2, $3, $4)
ON CONFLICT (id_mol, id_project) DO UPDATE SET coef = $3, ord = $4`,
values: [id_mol, id_project, coef, ord],
};
return client.query(query);
})
.catch((err) => {
console.error("connection error", err.stack);
})
.finally(() => {
client.end();
});
}

0 comments on commit 08b736c

Please sign in to comment.