Slicing tool scales 1D slices with the global 2D maximum instead of the zoomed region

オープン
#4,428 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 3 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
39/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
停滞
技術スタック
react, typescript

調査の方向性

Read src/component/2d/utilities/scale.ts and the horizontal and vertical slice chart callers named in the issue; compare how SlicingView.tsx gets the pointer position with how the current zoom domains are available. Check the related issue #3432 and the phase correction trace callers before choosing the scope. Done means slices in a zoomed region scale to visible intensities, with the maximum calculation and per render cost checked.

索引モデルが issue の本文から書いたものです。

説明

Summary

When a 2D spectrum is zoomed, the 1D slices drawn by the slicing tool keep a y-scale computed from the global maximum of the whole 2D data set, ignoring the current zoom region. Peaks inside the zoomed region are therefore rendered flat / almost invisible, which makes the tool useless for weak regions.

The slice should be scaled against the visible (zoomed) region.

Evidence

slicing tool keeps the global y-scale after zooming

How to reproduce

  1. Open a 2D spectrum.
  2. Zoom into a region whose intensities are much lower than the global maximum.
  3. Activate the slicing tool and move the pointer over the zoomed region.

Actual: the 1D slices are flat lines (or barely visible bumps), because their y-scale still spans the global maximum.

Expected: the 1D slices are scaled against the visible region, so peaks inside the zoom are clearly resolved.

Root cause

src/component/2d/utilities/scale.ts (line 95):

function getMax(data: NmrData2D): number {
  let max;

  for (const { minZ, maxZ } of Object.values(data)) {
    const innerMax = Math.max(Math.abs(minZ), Math.abs(maxZ));
    if (max === undefined || max > innerMax) {
      max = innerMax;
    }
  }

  assert(typeof max === 'number');
  return max;
}

function getSliceYScale(
  data: NmrData2D,
  size: number,
  mode: SpectraDirection,
  options: SliceYScaleOptions = {},
) {
  const { margin = 10, scaleRatio = 1 } = options;
  const max = getMax(data);   // <-- whole data set, zoom is never taken into account
  size = mode === 'RTL' ? size : size / 2;
  return scaleLinear([0, max * scaleRatio] as number[], [size - margin, margin]);
}

getMax only reads minZ / maxZ, which are precomputed over the entire matrix, and none of the callers pass the current xDomain / yDomain:

  • src/component/2d/1d-tracer/HorizontalSliceChart.tsx:31
  • src/component/2d/1d-tracer/VerticalSliceChart.tsx:34

The same helper is also used by the phase-correction traces (src/component/2d/1d-tracer/phase-correction-traces/SpectrumPhaseTrace.tsx:41,56), so they share the behaviour.

SlicingView.tsx already computes the slice for the pointed position (getSlice(spectrum, { x: scale2dX.invert(x), y: scale2dY.invert(y) })) but the y-scale of the rendered slice is still global.

Suggested fix

Make the slice y-scale aware of the visible region, e.g. pass the current zoom domain (or the displayed sub-matrix) into getSliceYScale and compute the max from that window instead of from minZ / maxZ of the whole data set.

Two related details worth checking while in there:

  • if (max === undefined || max > innerMax) keeps the smallest of the per-block maxima (max > innerMax looks inverted if a true maximum is intended).
  • getSliceYScale is called on every render with data from spectrum.data; deriving the zoomed max will need to be memoized to avoid recomputing it per pointer move.

Related

Same defect as #3432 ("slicing tool should adapt the slice with respect to the zoom region", opened 2025-04-15). Recorded separately with fresh evidence and the root cause above; feel free to close one of them as a duplicate.

Environment

  • nmrium 3.1.0, commit 5989ec6d
主要言語
TypeScript
スター
84
フォーク
35
平均マージ
4日 23時間
マージ済み PR(30日)
7

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

cheminfo/nmrium のほかの issue

cheminfo/nmrium の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。