Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions src/component/2d/ft/Contours.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import debounce from 'lodash/debounce';
import get from 'lodash/get';
import { Spectrum2D } from 'nmr-load-save';
import { memo, useMemo, useRef } from 'react';
import { memo, useEffect, useMemo, useRef } from 'react';

import {
drawContours,
Expand All @@ -16,6 +16,8 @@ import { PathBuilder } from '../../utility/PathBuilder';
import { getSpectraByNucleus } from '../../utility/getSpectraByNucleus';
import { useScale2DX, useScale2DY } from '../utilities/scale';

import { ContoursProvider, useContours } from './ContoursContext';

interface ContoursPathsProps {
id: string;
color: string;
Expand Down Expand Up @@ -77,19 +79,19 @@ function ContoursPaths({
const preferences = usePreferences();
const level = useContoursLevel(spectrum, sign);

const contours = useMemo(() => {
const { contours, timeout } = drawContours(
level,
spectrum,
sign === 'negative',
);
if (timeout) {
const contours = useContours();
const signContours = contours?.[spectrumID][sign] || {
contours: [],
timeout: false,
};

useEffect(() => {
if (signContours.timeout) {
onTimeout();
}
return contours;
}, [spectrum, level, onTimeout, sign]);
}, [onTimeout, signContours.timeout]);

const path = usePath(spectrum, contours);
const path = usePath(spectrum, signContours.contours);

const opacity =
activeSpectrum === null || spectrumID === activeSpectrum.id
Expand Down Expand Up @@ -169,5 +171,9 @@ export default function Contours() {
) as Spectrum2D[];
}, [activeTab, spectra]);

return <MemoizedContours {...{ spectra: spectra2d, displayerKey }} />;
return (
<ContoursProvider>
<MemoizedContours {...{ spectra: spectra2d, displayerKey }} />
</ContoursProvider>
);
}
71 changes: 71 additions & 0 deletions src/component/2d/ft/ContoursContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { DrawContourResult } from 'ml-conrec';
import { Spectrum2D } from 'nmr-load-save';
import { createContext, ReactNode, useContext, useMemo } from 'react';

import { drawContours } from '../../../data/data2d/Spectrum2D/contours';
import useSpectraByActiveNucleus from '../../hooks/useSpectraPerNucleus';

interface Contour {
positive: DrawContourResult<'basic'>;
negative: DrawContourResult<'basic'>;
}

type Contours = Record<string, Contour>;

const ContoursContext = createContext<Contours>({});

interface ContoursProviderProps {
children: ReactNode;
}

function getContours(spectrum: Spectrum2D, negative = false) {
//TODO change the static contour options.
return drawContours(
spectrum,
{
contourLevels: [0, 100],
numberOfLayers: 10,
},
negative,
);
}

export function ContoursProvider({ children }: ContoursProviderProps) {
const spectra = useSpectraByActiveNucleus() as Spectrum2D[];

// TODO: Move the contour options from the `display` object within the spectrum object to `view` to prevent recalculating the contours when those options change.
const contours = useMemo(() => {
const contours: Contours = {};
for (const spectrum of spectra) {
const {
id,
info: { isFt },
} = spectrum;

if (!isFt) {
continue;
}

const positive = getContours(spectrum);
const negative = getContours(spectrum, true);
contours[id] = { positive, negative };
}
return contours;
}, [spectra]);

return (
<ContoursContext.Provider value={contours}>
{children}
</ContoursContext.Provider>
);
}

export function useContours() {
const context = useContext(ContoursContext);

if (!context) {
throw new Error('Contours context was not found');
}

return context;
}
16 changes: 16 additions & 0 deletions src/component/hooks/useContourCache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { BasicContour } from 'ml-conrec/lib/BasicContourDrawer';
import { useState } from 'react';

export interface ContourResult {
contours: BasicContour[];
timeout: boolean;
}

export type ContourCache = Record<
string,
{ positive?: ContourResult; negative?: ContourResult }
>;
const initialContourCache: ContourCache = {};
export function useContourCache() {
return useState(initialContourCache);
}
169 changes: 143 additions & 26 deletions src/data/data2d/Spectrum2D/contours.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { Conrec } from 'ml-conrec';
import { xMaxAbsoluteValue } from 'ml-spectra-processing';
import { Spectrum2D } from 'nmr-load-save';

import { calculateSanPlot } from '../../utilities/calculateSanPlot';
// import {
// ContourCache,
// ContourResult,
// } from '../../../component/hooks/useContourCache';
// import { calculateSanPlot } from '../../utilities/calculateSanPlot';

interface Level {
positive: ContourItem;
Expand Down Expand Up @@ -44,6 +48,14 @@ interface ReturnContoursManager {
checkLevel: () => Level;
}

interface ContoursCalcOptions {
boundary: [number, number];
negative?: boolean;
timeout?: number;
nbLevels: number;
data: NmrData2DFt['rr'];
}

function getDefaultContoursLevel(spectrum: Spectrum2D, quadrant = 'rr') {
const { data, info } = spectrum;

Expand Down Expand Up @@ -174,35 +186,11 @@ function range(from: number, to: number, step: number) {
return result;
}

function drawContours(
level: ContourItem,
spectrum: Spectrum2D,
negative = false,
quadrant = 'rr',
) {
const { contourLevels, numberOfLayers } = level;

return getContours({
negative,
boundary: contourLevels,
nbLevels: numberOfLayers,
data: spectrum.data[quadrant],
});
}

interface ContoursCalcOptions {
boundary: [number, number];
negative?: boolean;
timeout?: number;
nbLevels: number;
data: NmrData2DFt['rr'];
}

function getContours(options: ContoursCalcOptions) {
const {
boundary,
negative = false,
timeout = 2000,
timeout = 4000,
nbLevels,
data,
} = options;
Expand Down Expand Up @@ -235,6 +223,135 @@ function getContours(options: ContoursCalcOptions) {
});
}

function drawContours(
spectrum: Spectrum2D,
level: ContourItem,
negative = false,
quadrant = 'rr',
) {
const { contourLevels, numberOfLayers } = level;

return getContours({
boundary: contourLevels,
nbLevels: numberOfLayers,
data: spectrum.data[quadrant],
negative,
});
}

// function drawContours(
// level: ContourItem,
// spectrum: Spectrum2D,
// contourCache: ContourCache,
// sign: 'positive' | 'negative' = 'positive',
// quadrant = 'rr',
// ) {
// const { contourLevels, numberOfLayers } = level;

// const nbLevels = Math.min(
// numberOfLayers,
// contourLevels[1] - contourLevels[0],
// );

// const { id, data } = spectrum;
// if (!contourCache[id]) {
// contourCache[id] = {};
// }

// if (!(sign in contourCache[id])) {
// contourCache[id][sign] = { contours: [], timeout: false };
// }

// const oneSenseContours = (contourCache[id][sign] as ContourResult).contours;
// const selectedLevels = getRange(
// Math.max(0, contourLevels[0]),
// contourLevels[1],
// nbLevels,
// ).map((e) => Math.round(e));

// const levels = selectedLevels.filter((level) => !oneSenseContours[level]);

// if (levels.length > 0 && levels.length < numberOfLayers) {
// const totalSize = data[quadrant].z[0].length * data[quadrant].z.length;
// if (totalSize < 5e6) {
// addAditionalLevels(levels, oneSenseContours, numberOfLayers);
// }
// }

// const { contours, timeout } = getContours({
// levels,
// sign,
// data: data[quadrant],
// });

// if (sign === 'negative') {
// levels.reverse();
// }
// for (const [i, level] of contours.entries()) {
// oneSenseContours[levels[i]] = level;
// }
// contourCache[id][sign] = { contours: oneSenseContours, timeout };

// return {
// contours: selectedLevels.map((level) => oneSenseContours[level]),
// timeout,
// };
// }

// function addAditionalLevels(
// levels: number[],
// oneSenseContours: ContourResult['contours'],
// numberOfLayers: number,
// ) {
// for (let i = 100; levels.length < numberOfLayers && i <= 0; i--) {
// if (!oneSenseContours[i] && !levels[i]) levels.push(i);
// }
// levels.sort((a, b) => a - b);
// }

// interface ContoursCalcOptions {
// levels: number[];
// sign?: 'positive' | 'negative';
// timeout?: number;
// data: NmrData2DFt['rr'];
// }

// function getContours(options: ContoursCalcOptions) {
// const { levels, sign = 'positive', timeout = 4000, data } = options;
// const max = Math.max(Math.abs(data.minZ), Math.abs(data.maxZ));
// let _range = levels.map((level) => calculateValueOfLevel(level, max));

// if (sign === 'negative') {
// _range = _range.map((value) => -value);
// if (_range.filter((value) => value >= data.minZ).length === 0) {
// return emptyResult(_range);
// }
// } else if (_range.filter((value) => value <= data.maxZ).length === 0) {
// return emptyResult(_range);
// }

// if (_range.every((r) => r === 0)) {
// return emptyResult(_range);
// }
// const ys = getRange(data.minY, data.maxY, data.z.length);
// const xs = getRange(data.minX, data.maxX, data.z[0].length);

// const conrec = new Conrec(data.z, { xs, ys, swapAxes: false });
// return conrec.drawContour({
// contourDrawer: 'basic',
// levels: Array.from(_range),
// timeout,
// });
// }

// function emptyResult(_range: number[]) {
// const emptyLine: number[] = [];
// return {
// contours: _range.map((r) => ({ zValue: r, lines: emptyLine })),
// timeout: false,
// };
// }

/**
* calculate the intensity value in the Z matrix based in the max value of Z matrix
* and the contour level (0-100).
Expand Down