seqeyes-python 0.3.6__tar.gz → 0.3.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/PKG-INFO +1 -1
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/pyproject.toml +1 -1
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/src/seqeyes/__init__.py +1 -1
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/src/seqeyes/resources/pulseq-bundle.js +47 -22
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/.gitignore +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/README.md +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/examples/demo.ipynb +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/examples/demo.py +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/src/seqeyes/_plot.py +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/src/seqeyes/_renderer.py +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/src/seqeyes/resources/viewer.html +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/src/seqeyes/resources/webview-bundle.js +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/tests/conftest.py +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/tests/debug_full.html +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/tests/debug_minimal.html +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/tests/debug_viewer.html +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/tests/debug_viewer.py +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/tests/integration_test.py +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/tests/test_plot.py +0 -0
- {seqeyes_python-0.3.6 → seqeyes_python-0.3.7}/tests/test_renderer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: seqeyes-python
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: Interactive Pulseq MRI sequence viewer for Jupyter — lightweight, beautiful, replaces seq.plot() in pypulseq.
|
|
5
5
|
Project-URL: Homepage, https://github.com/bughht/seqeyes_plugin
|
|
6
6
|
Project-URL: Repository, https://github.com/bughht/seqeyes_plugin
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "seqeyes-python"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.7"
|
|
8
8
|
description = "Interactive Pulseq MRI sequence viewer for Jupyter — lightweight, beautiful, replaces seq.plot() in pypulseq."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -23,31 +23,24 @@ var Pulseq = (() => {
|
|
|
23
23
|
// web/pulseq-browser.ts
|
|
24
24
|
var pulseq_browser_exports = {};
|
|
25
25
|
__export(pulseq_browser_exports, {
|
|
26
|
-
BAND_DETAIL_SAMPLES: () => BAND_DETAIL_SAMPLES,
|
|
27
|
-
EXACT_DETAIL_SAMPLES: () => EXACT_DETAIL_SAMPLES,
|
|
28
26
|
INTERACTIVE_COMPUTE_LIMITS: () => INTERACTIVE_COMPUTE_LIMITS,
|
|
29
|
-
MAX_DETAIL_PTS: () => MAX_DETAIL_PTS,
|
|
30
|
-
MAX_DISPLAY_PTS: () => MAX_DISPLAY_PTS,
|
|
31
|
-
MAX_ENVELOPE_COLUMNS: () => MAX_ENVELOPE_COLUMNS,
|
|
32
27
|
MAX_RF_RESPONSE_BANDS: () => MAX_RF_RESPONSE_BANDS,
|
|
33
28
|
MAX_RF_RESPONSE_FFT_POINTS: () => MAX_RF_RESPONSE_FFT_POINTS,
|
|
34
29
|
MAX_RF_RESPONSE_SAMPLES: () => MAX_RF_RESPONSE_SAMPLES,
|
|
35
30
|
PACKAGE_VERSION: () => PACKAGE_VERSION,
|
|
36
31
|
analyzeRfResponse: () => analyzeRfResponse,
|
|
37
32
|
audioBudgetRefusal: () => audioBudgetRefusal,
|
|
33
|
+
buildWaveformDetailReply: () => buildWaveformDetailReply,
|
|
38
34
|
calculateKspace: () => calculateKspace,
|
|
39
35
|
calculateM1: () => calculateM1,
|
|
40
36
|
calculateM1Coarse: () => calculateM1Coarse,
|
|
41
37
|
calculatePns: () => calculatePns,
|
|
42
38
|
calculatePnsCoarse: () => calculatePnsCoarse,
|
|
43
39
|
computeGradSpectrumParity: () => computeGradSpectrumParity,
|
|
44
|
-
computeGradientEnvelope: () => computeGradientEnvelope,
|
|
45
40
|
computeGradientSpectrogram: () => computeGradientSpectrogram,
|
|
46
41
|
computeGradientSpectrumAverage: () => computeGradientSpectrumAverage,
|
|
47
42
|
computeGradientSpectrumSlice: () => computeGradientSpectrumSlice,
|
|
48
43
|
countBandsOutsideRange: () => countBandsOutsideRange,
|
|
49
|
-
countExactDetailSamples: () => countExactDetailSamples,
|
|
50
|
-
countGradientSamples: () => countGradientSamples,
|
|
51
44
|
createSequenceDecodeContext: () => createSequenceDecodeContext,
|
|
52
45
|
decodeAllBlocks: () => decodeAllBlocks,
|
|
53
46
|
decodeBlockRange: () => decodeBlockRange,
|
|
@@ -72,8 +65,6 @@ var Pulseq = (() => {
|
|
|
72
65
|
hasPulseqBinaryMagic: () => hasPulseqBinaryMagic,
|
|
73
66
|
isEmptyAscProfile: () => isEmptyAscProfile,
|
|
74
67
|
kspaceExceedsInteractiveBudget: () => kspaceExceedsInteractiveBudget,
|
|
75
|
-
packGradientEnvelope: () => packGradientEnvelope,
|
|
76
|
-
packSequenceBlockRange: () => packSequenceBlockRange,
|
|
77
68
|
packSequenceBlocks: () => packSequenceBlocks,
|
|
78
69
|
parseAcousticResonancesAsc: () => parseAcousticResonancesAsc,
|
|
79
70
|
parseAscProfile: () => parseAscProfile,
|
|
@@ -84,7 +75,6 @@ var Pulseq = (() => {
|
|
|
84
75
|
parseSequenceText: () => parseSequenceText,
|
|
85
76
|
physicalGradientValueAt: () => physicalGradientValueAt,
|
|
86
77
|
resamplePhysicalGradients: () => resamplePhysicalGradients,
|
|
87
|
-
resolveDetailBlockRange: () => resolveDetailBlockRange,
|
|
88
78
|
resolveSpectrogramParams: () => resolveSpectrogramParams,
|
|
89
79
|
rotateGradient: () => rotateGradient,
|
|
90
80
|
safePnsModel: () => safePnsModel,
|
|
@@ -97,7 +87,7 @@ var Pulseq = (() => {
|
|
|
97
87
|
});
|
|
98
88
|
|
|
99
89
|
// package.json
|
|
100
|
-
var version = "0.3.
|
|
90
|
+
var version = "0.3.7";
|
|
101
91
|
|
|
102
92
|
// src/pulseq/decompressor.ts
|
|
103
93
|
function decompressShape(compressed, numSamples) {
|
|
@@ -2862,16 +2852,6 @@ var Pulseq = (() => {
|
|
|
2862
2852
|
}
|
|
2863
2853
|
return { startSec, endSec, columns: width, channels };
|
|
2864
2854
|
}
|
|
2865
|
-
function countGradientSamples(blocks) {
|
|
2866
|
-
let total = 0;
|
|
2867
|
-
for (const block of blocks) {
|
|
2868
|
-
for (const key of GRADIENT_CHANNELS) {
|
|
2869
|
-
const grad = block[key];
|
|
2870
|
-
if (grad && grad.type !== "none") total += grad.timePoints.length;
|
|
2871
|
-
}
|
|
2872
|
-
}
|
|
2873
|
-
return total;
|
|
2874
|
-
}
|
|
2875
2855
|
function packGradientEnvelope(envelope) {
|
|
2876
2856
|
const { columns } = envelope;
|
|
2877
2857
|
const out = new Float32Array(columns * 6);
|
|
@@ -2886,6 +2866,51 @@ var Pulseq = (() => {
|
|
|
2886
2866
|
return { startSec: envelope.startSec, endSec: envelope.endSec, columns, values: out.buffer };
|
|
2887
2867
|
}
|
|
2888
2868
|
|
|
2869
|
+
// src/editor/waveformDetailReply.ts
|
|
2870
|
+
var WINDOW_DETAIL_BLOCK_LIMIT = 2e4;
|
|
2871
|
+
function buildWaveformDetailReply(seq, context, request, generation = 0, lookup, blockLimit = WINDOW_DETAIL_BLOCK_LIMIT) {
|
|
2872
|
+
const startSec = Number(request.startSec);
|
|
2873
|
+
const endSec = Number(request.endSec);
|
|
2874
|
+
const { start, end } = resolveDetailBlockRange(
|
|
2875
|
+
context.blockStartTimes,
|
|
2876
|
+
seq.blocks.length,
|
|
2877
|
+
startSec,
|
|
2878
|
+
endSec
|
|
2879
|
+
);
|
|
2880
|
+
if (!(endSec > startSec)) {
|
|
2881
|
+
return { kind: "error", message: "This waveform detail window is empty." };
|
|
2882
|
+
}
|
|
2883
|
+
const columns = Math.max(1, Math.min(
|
|
2884
|
+
MAX_ENVELOPE_COLUMNS,
|
|
2885
|
+
Math.floor(Number(request.columns) || 0) || 1
|
|
2886
|
+
));
|
|
2887
|
+
const cacheKey = `${generation}:${start}:${end}:${startSec}:${endSec}`;
|
|
2888
|
+
const cached = lookup?.(cacheKey);
|
|
2889
|
+
if (cached && end - start <= blockLimit) {
|
|
2890
|
+
return { kind: "samples", startBlock: start, endBlock: end, startSec, endSec, packed: cached, cacheKey };
|
|
2891
|
+
}
|
|
2892
|
+
const decoded = decodeBlockRange(seq, start, end, context);
|
|
2893
|
+
const windowSamples = countExactDetailSamples(decoded, { startSec, endSec });
|
|
2894
|
+
if (windowSamples > EXACT_DETAIL_SAMPLES) {
|
|
2895
|
+
if (windowSamples > BAND_DETAIL_SAMPLES) return { kind: "unavailable", startSec, endSec };
|
|
2896
|
+
const band = packGradientEnvelope(computeGradientEnvelope(decoded, startSec, endSec, columns));
|
|
2897
|
+
return { kind: "band", startSec: band.startSec, endSec: band.endSec, columns: band.columns, values: band.values };
|
|
2898
|
+
}
|
|
2899
|
+
if (end - start > blockLimit) {
|
|
2900
|
+
return { kind: "error", message: "This waveform detail window is too large. Zoom in further." };
|
|
2901
|
+
}
|
|
2902
|
+
const packed = packSequenceBlockRange(
|
|
2903
|
+
seq,
|
|
2904
|
+
start,
|
|
2905
|
+
end,
|
|
2906
|
+
context,
|
|
2907
|
+
MAX_DETAIL_PTS,
|
|
2908
|
+
void 0,
|
|
2909
|
+
{ startSec, endSec }
|
|
2910
|
+
);
|
|
2911
|
+
return { kind: "samples", startBlock: start, endBlock: end, startSec, endSec, packed, cacheKey };
|
|
2912
|
+
}
|
|
2913
|
+
|
|
2889
2914
|
// src/pulseq/physicalGradients.ts
|
|
2890
2915
|
var GRADIENT_ENDPOINT_TOLERANCE_SEC = 1e-12;
|
|
2891
2916
|
function rotateGradient(block, gx, gy, gz) {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|