Skip to content

Commit

Permalink
feat: importation and exportation of nmredata (#989)
Browse files Browse the repository at this point in the history
* fix: nmredata exportation of 2D signals

close #980

* feat: prepare to import nmredata

* feat: nmredata importation and ranges assigned

* feat(nmredata): 2D signals assign completed

* feat: use nmredata 0.2.0

* chore: fix eslint

* chore: use node 14
  • Loading branch information
jobo322 committed Apr 23, 2021
1 parent b38d51e commit 7ae8c8c
Show file tree
Hide file tree
Showing 10 changed files with 1,726 additions and 1,293 deletions.
2,852 changes: 1,566 additions & 1,286 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -74,6 +74,7 @@
"nmr-correlation": "^1.2.0",
"nmr-parser": "^1.0.1",
"nmr-processing": "^1.2.0",
"nmredata": "^0.2.0",
"numeral": "^2.0.6",
"openchemlib": "^7.4.0",
"openchemlib-utils": "^1.0.0",
Expand Down
9 changes: 4 additions & 5 deletions src/component/loader/DropZone.jsx
Expand Up @@ -15,6 +15,7 @@ import {
SET_LOADING_FLAG,
LOAD_ZIP_FILE,
LOAD_JDF_FILE,
LOAD_NMREDATA_FILE,
} from '../reducer/types/Types';
import {
FILES_TYPES,
Expand Down Expand Up @@ -71,7 +72,6 @@ function DropZone(props) {
loadFilesFromZip(selectedFilesByExtensions).then((files) =>
dispatch({ type: LOAD_MOL_FILE, files }),
);

break;
case FILES_TYPES.NMRIUM:
case FILES_TYPES.JSON:
Expand All @@ -85,7 +85,6 @@ function DropZone(props) {
}
});
break;

case FILES_TYPES.JDX:
case FILES_TYPES.DX:
loadFilesFromZip(selectedFilesByExtensions).then((files) =>
Expand All @@ -98,7 +97,9 @@ function DropZone(props) {
asBuffer: true,
}).then((files) => dispatch({ type: LOAD_JDF_FILE, files }));
break;

case FILES_TYPES.SDF:
dispatch({ type: LOAD_NMREDATA_FILE, files: extractedfiles });
break;
default:
break;
}
Expand Down Expand Up @@ -185,12 +186,10 @@ function DropZone(props) {
),
),
];

const isNotZip = uniqueFileExtensions.some(
(ex) =>
FILES_TYPES[ex.toUpperCase()] && ex !== FILES_TYPES.ZIP,
);

if (isNotZip) {
loadsubFilesfromZip(
Object.values(unzipResult.files),
Expand Down
10 changes: 10 additions & 0 deletions src/component/reducer/Reducer.ts
Expand Up @@ -7,6 +7,7 @@ import * as SpectraManager from '../../data/SpectraManager';
import { Spectra } from '../NMRium';
import { DefaultTolerance } from '../panels/SummaryPanel/CorrelationTable/Constants';
import { options } from '../toolbar/ToolTypes';
import { nmredataToNmrium } from '../utility/nmredataToNmrium';

import * as CorrelationsActions from './actions/CorrelationsActions';
import { setWidth, handleSetDimensions } from './actions/DimensionsActions';
Expand Down Expand Up @@ -174,6 +175,13 @@ export function dispatchMiddleware(dispatch) {
}
break;
}
case types.LOAD_NMREDATA_FILE: {
void nmredataToNmrium(action.files).then((data) => {
action.payload = data;
dispatch(action);
});
break;
}
case types.PREDICT_SPECTRA: {
const molecule = OCL.Molecule.fromMolfile(action.payload.mol.molfile);
void predictionProton(molecule, {}).then((result) => {
Expand Down Expand Up @@ -209,6 +217,8 @@ function innerSpectrumReducer(draft, action) {
return LoadActions.handleLoadMOLFile(draft, action.files);
case types.LOAD_ZIP_FILE:
return LoadActions.handleLoadZIPFile(draft, action);
case types.LOAD_NMREDATA_FILE:
return LoadActions.handleLoadNmredata(draft, action);
case types.ADD_PEAK:
return PeaksActions.addPeak(draft, action.mouseCoordinates);
case types.ADD_PEAKS:
Expand Down
10 changes: 10 additions & 0 deletions src/component/reducer/actions/LoadActions.ts
Expand Up @@ -131,12 +131,22 @@ function handleLoadZIPFile(draft: Draft<State>, action) {
draft.isLoading = false;
}

function handleLoadNmredata(draft: Draft<State>, action) {
setData(draft, action.payload);
const alignCenter = lodashGet(draft.preferences, 'display.center', null);
changeSpectrumVerticalAlignment(draft, alignCenter, true);
setActiveTab(draft);
initZoom1DHandler(draft.data);
draft.isLoading = false;
}

export {
setIsLoading,
initiate,
loadJcampFile,
loadJDFFile,
handleLoadJsonFile,
handleLoadNmredata,
handleLoadMOLFile,
handleLoadZIPFile,
};
1 change: 1 addition & 0 deletions src/component/reducer/types/Types.js
Expand Up @@ -2,6 +2,7 @@ export const INITIATE = 'INITIATE';
export const SAVE_DATA_AS_JSON = 'SAVE_DATA_AS_JSON';
export const LOAD_JSON_FILE = 'LOAD_JSON_FILE';
export const LOAD_JCAMP_FILE = 'LOAD_JCAMP_FILE';
export const LOAD_NMREDATA_FILE = 'LOAD_NMREDATA_FILE';
export const LOAD_MOL_FILE = 'LOAD_MOL_FILE';
export const LOAD_ZIP_FILE = 'LOAD_ZIP_FILE';
export const LOAD_JDF_FILE = 'LOAD_JDF_FILE';
Expand Down
1 change: 1 addition & 0 deletions src/component/utility/FileUtility.js
Expand Up @@ -6,6 +6,7 @@ export const FILES_TYPES = {
JDX: 'jdx',
JDF: 'jdf',
ZIP: 'zip',
SDF: 'sdf',
};

async function loadFile(file) {
Expand Down
132 changes: 132 additions & 0 deletions src/component/utility/nmredataToNmrium.js
@@ -0,0 +1,132 @@
import { NmrRecord, parseSDF } from 'nmredata';

import { addBruker, addJcamp } from '../../data/SpectraManager';
import { detectRanges, mapRanges } from '../../data/data1d/Datum1D';
import { detectZones } from '../../data/data2d/Datum2D';

const computeDistance = (s1, s2) =>
['x', 'y'].reduce(
(dist, axis) => Math.pow(s2[axis].delta - s1[axis].delta, 2) + dist,
0,
);

export async function nmredataToNmrium(zipFilesValues) {
let files = {};
for (const file of zipFilesValues) files[file.name] = file;
const sdfFiles = await getSDF(files);
const jsonData = await NmrRecord.toJSON({
sdf: sdfFiles[0],
zipFiles: files,
});

let { spectra, molecules = [] } = jsonData;

let nmrium = {
spectra: [],
molecules,
};

for (const data of spectra) {
const { zip, jcamp } = data.source;

let spectrum = zip
? await addBruker({ xy: true, noContours: true }, zip)
: (spectrum = addJcamp({}, jcamp));

const { info } = spectrum[0];
if (info.dimension > 1) {
detectZones(spectrum[0], {});
assignZones(spectrum[0], data.signals);
} else {
detectRanges(spectrum[0], {});
assignRanges(spectrum[0], data.signals);
}
nmrium.spectra.push(...spectrum);
}

return nmrium;
}

async function getSDF(zipFiles) {
let result = [];
for (const file in zipFiles) {
const pathFile = file.split('/');
if (pathFile[pathFile.length - 1].match(/^[^.].+sdf$/)) {
const filename = pathFile[pathFile.length - 1].replace(/\.sdf/, '');
const root = pathFile.slice(0, pathFile.length - 1).join('/');
const sdf = await zipFiles[file].async('string');
let parserResult = parseSDF(`${sdf}`, { mixedEOL: true });
parserResult.filename = filename;
parserResult.root = root !== '' ? `${root}/` : '';
result.push(parserResult);
}
}
return result;
}

function assignZones(datum, eSignals) {
let zones = datum.zones.values;
let signals = eSignals.slice();
for (let zone of zones) {
let signalsInside = [];
for (let i = 0; i < signals.length; i++) {
let isInside = 0;
let signal = signals[i];
for (let axis of ['x', 'y']) {
let { from, to } = zone[axis];
let deltaIn = signal[axis].delta;
if (deltaIn >= from && deltaIn <= to) isInside++;
}
if (isInside > 1) {
signalsInside.push(signal);
signals.splice(i, 1);
i--;
}
}
if (signalsInside.length > 0) {
for (let signal of signalsInside) {
for (let axis of ['x', 'y']) {
if (!signal[axis].diaID) continue;
let index = closeSignalIndex(signal, zone);
zone.signal[index][axis].diaID = signal[axis].diaID;
}
}
}
}
}

function closeSignalIndex(signal, zone) {
const signals = zone.signal;
if (signals.length === 1) return 0;

let index = 0;
let distance = computeDistance(signals[0], signal);
for (let i = 0; i < signals.length; i++) {
let currentDistance = computeDistance(signals[i], signal);
if (currentDistance < distance) {
index = i;
distance = currentDistance;
}
}
return index;
}

function assignRanges(datum, signals) {
let ranges = datum.ranges.values.slice();
ranges.sort((a, b) => a.from - b.from);
signals.sort((a, b) => a.delta - b.delta);
for (let range of ranges) {
let { from, to } = range;
let signalsInside = [];
for (let signal of signals) {
if (signal.delta >= from && signal.delta <= to) {
let { jCoupling: j, delta, diaID = [], multiplicity } = signal;
signalsInside.push({ j, delta, diaID, multiplicity });
}
if (signal.delta > to) break;
}
if (signalsInside.length > 0) range.signal = signalsInside;
}
datum.ranges.values = [];
datum.ranges.values = mapRanges(ranges, datum);
}
2 changes: 1 addition & 1 deletion src/component/utility/util/get2DSignals.js
Expand Up @@ -58,7 +58,7 @@ function getAssignment(axis, labels, toFix) {
let { diaID, delta } = axis;
if (diaID) {
if (!isArray(diaID)) diaID = [diaID];
if (diaID.length < 1) Number(delta).toFixed(toFix);
if (diaID.length < 1) return Number(delta).toFixed(toFix);
let label = diaID.map((diaID) => labels[diaID].label).join(',');
return diaID.length > 1 ? `(${label})` : label;
}
Expand Down
1 change: 0 additions & 1 deletion src/data/data1d/Datum1D.ts
Expand Up @@ -361,7 +361,6 @@ export function mapRanges(ranges, datum) {
{ x, y: re },
{ from: newRange.from, to: newRange.to, reverse: true },
);

const signal = newRange.signal.map((_signal) => {
return {
kind: 'signal',
Expand Down

0 comments on commit 7ae8c8c

Please sign in to comment.