Skip to content

Commit

Permalink
feat: phase correction traces for both directions
Browse files Browse the repository at this point in the history
  • Loading branch information
hamed-musallam committed Oct 20, 2023
1 parent ab7248e commit c625982
Show file tree
Hide file tree
Showing 19 changed files with 557 additions and 16 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -147,4 +147,4 @@
"vite": "^4.4.9",
"vitest": "^0.34.5"
}
}
}
1 change: 1 addition & 0 deletions src/component/1d-2d/tools/BrushXY.tsx
Expand Up @@ -21,6 +21,7 @@ const allowTools = new Set([
options.peakPicking.id,
options.integral.id,
options.phaseCorrection.id,
options.phaseCorrectionTwoDimension.id,
options.baselineCorrection.id,
options.rangePicking.id,
options.zonePicking.id,
Expand Down
1 change: 1 addition & 0 deletions src/component/1d-2d/tools/CrossLinePointer.tsx
Expand Up @@ -20,6 +20,7 @@ const allowTools = new Set([
options.apodization.id,
options.equalizer.id,
options.baselineCorrection.id,
options.phaseCorrectionTwoDimension.id,
options.zonePicking.id,
options.slicing.id,
options.integral.id,
Expand Down
@@ -0,0 +1,49 @@
import { Spectrum2D } from 'nmr-load-save';
import { getSlice } from '../../../../data/data2d/Spectrum2D';
import { useMouseTracker } from '../../../EventsTrackers/MouseTracker';
import { useChartData } from '../../../context/ChartContext';
import { useActiveSpectrum } from '../../../hooks/useActiveSpectrum';
import { SpectrumPhaseTrace } from './SpectrumPhaseTrace';
import { get2DXScale, get2DYScale } from '../../utilities/scale';
import { useActivePhaseTraces } from './useActivePhaseTraces';

export function PhaseTraceWithMouse() {
const {
width,
margin,
height,
xDomain,
data: spectra,
yDomain,
} = useChartData();
const activeSpectrum = useActiveSpectrum();
const { activeTraceDirection, color } = useActivePhaseTraces();
const position = useMouseTracker();

if (!position || !width || !height || !activeSpectrum?.id) {
return null;
}
const spectrum = spectra[activeSpectrum.index] as Spectrum2D;

const scale2dX = get2DXScale({ margin, width, xDomain });
const scale2dY = get2DYScale({ margin, height, yDomain });

const sliceData = getSlice(spectrum, {
x: scale2dX.invert(position.x),
y: scale2dY.invert(position.y),
});

const data = sliceData?.[activeTraceDirection]?.data;
if (!data) {
return null;
}

return (
<SpectrumPhaseTrace
data={data}
yShift={position.y}
color={color}
direction={activeTraceDirection}
/>
);
}
41 changes: 41 additions & 0 deletions src/component/2d/1d-tracer/phace-correction-traces/PhaseTraces.tsx
@@ -0,0 +1,41 @@
import { useChartData } from '../../../context/ChartContext';
import { useActiveSpectrum } from '../../../hooks/useActiveSpectrum';
import { PhaseTraceWithMouse } from './PhaseTraceWithMouse';
import { SpectraPhaseTraces } from './SpectraPhaseTraces';

export function PhaseTraces() {
const { width, height, margin, displayerKey } = useChartData();
const activeSpectrum = useActiveSpectrum();

if (!activeSpectrum?.id) return null;

const clipWidth = width - margin.left - margin.right;
const clipHeight = height - margin.top - margin.bottom;

return (
<svg
viewBox={`0 0 ${width} ${height}`}
width={width}
height={height}
style={{
position: 'absolute',
zIndex: 9,
}}
>
<defs>
<clipPath id={`${displayerKey}-clip-phase-traces`}>
<rect
width={clipWidth}
height={clipHeight}
x={margin.left}
y={margin.top}
/>
</clipPath>
</defs>
<g clipPath={`url(#${displayerKey}-clip-phase-traces)`}>
<PhaseTraceWithMouse />
<SpectraPhaseTraces />
</g>
</svg>
);
}
@@ -0,0 +1,31 @@
import { useChartData } from '../../../context/ChartContext';
import { SpectrumPhaseTrace } from './SpectrumPhaseTrace';
import { get2DYScale } from '../../utilities/scale';
import { useActivePhaseTraces } from './useActivePhaseTraces';

export function SpectraPhaseTraces() {
const { width, height, margin, yDomain } = useChartData();
const { spectra = [], color, activeTraceDirection } = useActivePhaseTraces();

if (!width || !height) {
return null;
}

const scale2dY = get2DYScale({ margin, height, yDomain });

if (spectra.length === 0) {
return null;
}

return spectra.map(({ id, data, y }) => {
return (
<SpectrumPhaseTrace
key={id}
data={data}
yShift={scale2dY(y)}
color={color}
direction={activeTraceDirection}
/>
);
});
}
@@ -0,0 +1,45 @@
import { useChartData } from '../../../context/ChartContext';
import { TraceDirection } from '../../../reducer/Reducer';
import { PathBuilder } from '../../../utility/PathBuilder';
import { get2DXScale } from '../../utilities/scale';
import { getYScale } from '../../utilities/SliceScale';

interface SpectrumPhaseTraceProps {
data: { x: Float64Array; re: Float64Array };
yShift: number;
color: string;
direction: TraceDirection;
}

export function SpectrumPhaseTrace(props: SpectrumPhaseTraceProps) {
const { data, yShift, color, direction } = props;
const { width, margin, height, xDomain, yDomain } = useChartData();

const { x, re: y } = data;
const scaleX = get2DXScale(
{ margin, width, xDomain: direction === 'horizontal' ? xDomain : yDomain },
direction === 'vertical',
);
const scaleY = getYScale(height, y, margin.top + margin.bottom);

const pathBuilder = new PathBuilder();
pathBuilder.moveTo(scaleX(x[0]), scaleY(y[0]));
for (let i = 1; i < x.length; i++) {
pathBuilder.lineTo(scaleX(x[i]), scaleY(y[i]));
}

const clipHeight = height - margin.top - margin.bottom;

return (
<path
className="line"
stroke={color}
strokeWidth="1"
fill="transparent"
d={pathBuilder.toString()}
style={{
transform: `translate(0px,${yShift - clipHeight}px)`,
}}
/>
);
}
@@ -0,0 +1 @@
export { PhaseTraces } from './PhaseTraces';
@@ -0,0 +1,18 @@
import { COLORS } from '../../../../data/utilities/generateColor';
import { useChartData } from '../../../context/ChartContext';

export function useActivePhaseTraces() {
const {
toolOptions: {
data: {
twoDimensionPhaseCorrection: { traces, activeTraceDirection },
},
},
} = useChartData();
const color = activeTraceDirection === 'horizontal' ? COLORS[0] : COLORS[1];
return {
spectra: traces[activeTraceDirection].spectra,
activeTraceDirection,
color,
};
}
1 change: 1 addition & 0 deletions src/component/2d/Chart2D.tsx
Expand Up @@ -40,6 +40,7 @@ function chart2DInner({
height={height}
id="nmrSVG"
shapeRendering={SpectraRendering}
style={{ position: 'absolute' }}
>
<defs>
<clipPath id={`${displayerKey}clip-chart-2d`}>
Expand Down
12 changes: 10 additions & 2 deletions src/component/2d/Viewer2D.tsx
Expand Up @@ -22,6 +22,7 @@ import SlicingView from './SlicingView';
import XYLabelPointer from './tools/XYLabelPointer';
import { get2DDimensionLayout, getLayoutID } from './utilities/DimensionLayout';
import { get2DXScale, get2DYScale } from './utilities/scale';
import { PhaseTraces } from './1d-tracer/phace-correction-traces';

interface Viewer2DProps {
emptyText: ReactNode;
Expand Down Expand Up @@ -155,11 +156,14 @@ function Viewer2D({ emptyText = undefined }: Viewer2DProps) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { x, y } = position;
switch (selectedTool) {
case 'phaseCorrectionTwoDimension':
dispatch({ type: 'ADD_PHASE_CORRECTION_TRACE', payload: { x, y } });
break;
default:
break;
}
},
[selectedTool],
[selectedTool, dispatch],
);

return (
Expand All @@ -183,11 +187,15 @@ function Viewer2D({ emptyText = undefined }: Viewer2DProps) {
}}
>
<MouseTracker
style={{ width: '100%', height: `100%`, position: 'absolute' }}
style={{ width: '100%', height: `100%`, position: 'relative' }}
>
{selectedTool && selectedTool === options.slicing.id && (
<SlicingView />
)}
{selectedTool &&
selectedTool === options.phaseCorrectionTwoDimension.id && (
<PhaseTraces />
)}

<CrossLinePointer />
<XYLabelPointer data1D={spectrumData} layout={DIMENSION} />
Expand Down
3 changes: 3 additions & 0 deletions src/component/header/Header.tsx
Expand Up @@ -35,6 +35,7 @@ import PhaseCorrectionPanel from './PhaseCorrectionPanel';
import RangesPickingOptionPanel from './RangesPickingOptionPanel';
import ZeroFillingOptionsPanel from './ZeroFillingOptionsPanel';
import Zones2DOptionPanel from './Zones2DOptionPanel';
import PhaseCorrectionTwoDimensionsPanel from './PhaseCorrectionTwoDimensionsPanel';

export const headerLabelStyle: LabelStyle = {
label: {
Expand Down Expand Up @@ -112,6 +113,8 @@ function HeaderInner(props: HeaderInnerProps) {
return <ZeroFillingOptionsPanel />;
case options.phaseCorrection.id:
return <PhaseCorrectionPanel />;
case options.phaseCorrectionTwoDimension.id:
return <PhaseCorrectionTwoDimensionsPanel />;
case options.peakPicking.id:
return <AutoPeakPickingOptionPanel />;
case options.rangePicking.id:
Expand Down

0 comments on commit c625982

Please sign in to comment.