seqeyes-python 0.2.12__tar.gz → 0.2.13__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.2.12 → seqeyes_python-0.2.13}/PKG-INFO +2 -2
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/pyproject.toml +1 -1
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/src/seqeyes/__init__.py +1 -1
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/src/seqeyes/resources/pulseq-bundle.js +11 -2
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/src/seqeyes/resources/webview-bundle.js +83 -1
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/.gitignore +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/README.md +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/examples/demo.ipynb +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/examples/demo.py +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/src/seqeyes/_plot.py +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/src/seqeyes/_renderer.py +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/src/seqeyes/resources/viewer.html +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/tests/conftest.py +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/tests/debug_full.html +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/tests/debug_minimal.html +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/tests/debug_viewer.html +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/tests/debug_viewer.py +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/tests/integration_test.py +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/tests/test_plot.py +0 -0
- {seqeyes_python-0.2.12 → seqeyes_python-0.2.13}/tests/test_renderer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: seqeyes-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.13
|
|
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.2.
|
|
7
|
+
version = "0.2.13"
|
|
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"}
|
|
@@ -54,7 +54,7 @@ var Pulseq = (() => {
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
// package.json
|
|
57
|
-
var version = "0.2.
|
|
57
|
+
var version = "0.2.13";
|
|
58
58
|
|
|
59
59
|
// src/pulseq/decompressor.ts
|
|
60
60
|
function decompressShape(compressed, numSamples) {
|
|
@@ -3342,7 +3342,16 @@ var Pulseq = (() => {
|
|
|
3342
3342
|
kspaceRasterSamples: 12e6,
|
|
3343
3343
|
kspaceAdcSamples: 8e6,
|
|
3344
3344
|
kspaceGridCandidates: 18e6,
|
|
3345
|
-
derivedRasterSamples: 2e6
|
|
3345
|
+
derivedRasterSamples: 2e6,
|
|
3346
|
+
/**
|
|
3347
|
+
* Ceiling on the display samples one sequence load may carry to the VS Code
|
|
3348
|
+
* webview, counted as (time, amplitude) pairs across every RF and gradient
|
|
3349
|
+
* waveform. At 12 bytes per pair this bounds the shared binary buffers at
|
|
3350
|
+
* roughly 137 MiB in the extension host and again in the renderer.
|
|
3351
|
+
* Per-waveform detail is reduced uniformly once a sequence would exceed it,
|
|
3352
|
+
* because the alternative is an allocation neither process can satisfy.
|
|
3353
|
+
*/
|
|
3354
|
+
displayTransportSamples: 12e6
|
|
3346
3355
|
});
|
|
3347
3356
|
function derivedDetailViewLimitSec(gradientRaster, trTimeSec, maxRasterSamples = INTERACTIVE_COMPUTE_LIMITS.derivedRasterSamples) {
|
|
3348
3357
|
if (!(gradientRaster > 0) || !(maxRasterSamples > 0)) return 0;
|
|
@@ -1,5 +1,69 @@
|
|
|
1
1
|
/* SeqEyes WebView Bundle — auto-generated, do not edit */
|
|
2
2
|
"use strict";
|
|
3
|
+
/* ══ block-transport.js ══ */
|
|
4
|
+
/* ══════════════════════════════════════════════════════════════════════════
|
|
5
|
+
block-transport.js — rehydrate the packed block payload from the extension.
|
|
6
|
+
|
|
7
|
+
The standalone web app builds BL in this same heap, so its waveform arrays
|
|
8
|
+
cost one copy and nothing more. The VS Code extension has to cross a process
|
|
9
|
+
boundary, and VS Code serialises webview messages with JSON.stringify: every
|
|
10
|
+
sample becomes ~19 characters of text, the extension host and the renderer
|
|
11
|
+
each hold that string alongside the object graph, and V8 refuses to build a
|
|
12
|
+
string longer than 512 MiB at all. Dense arbitrary waveforms reach ~18 KB of
|
|
13
|
+
JSON per block, so a few tens of thousands of them cannot be delivered as
|
|
14
|
+
JSON at any amount of memory.
|
|
15
|
+
|
|
16
|
+
src/editor/blockTransport.ts therefore sends the samples as two shared binary
|
|
17
|
+
buffers — Float64 times, Float32 amplitudes — plus an envelope carrying each
|
|
18
|
+
waveform's offset and count. Restoring the arrays as typed-array views over
|
|
19
|
+
those buffers reproduces the exact block shape the renderer reads, without
|
|
20
|
+
copying a single sample: the renderer only ever indexes these arrays and asks
|
|
21
|
+
for their length, which a typed array answers identically.
|
|
22
|
+
══════════════════════════════════════════════════════════════════════════ */
|
|
23
|
+
|
|
24
|
+
/** Interpret a transferred buffer as `Ctor`, or null if it did not arrive. */
|
|
25
|
+
function asTypedView(buffer,Ctor){
|
|
26
|
+
if(buffer instanceof Ctor)return buffer;
|
|
27
|
+
if(buffer instanceof ArrayBuffer)return new Ctor(buffer);
|
|
28
|
+
// Some hosts hand the transfer back as a byte view rather than the buffer.
|
|
29
|
+
if(buffer&&buffer.buffer instanceof ArrayBuffer&&typeof buffer.byteLength==='number')
|
|
30
|
+
return new Ctor(buffer.buffer,buffer.byteOffset||0,Math.floor(buffer.byteLength/Ctor.BYTES_PER_ELEMENT));
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Attach typed-array views to the envelope in place and return it as BL.
|
|
36
|
+
* Throws rather than returning partial blocks: a viewer that silently draws
|
|
37
|
+
* half a sequence is worse than one that says why it cannot.
|
|
38
|
+
*/
|
|
39
|
+
function unpackSequenceBlocks(envelope,timeBuffer,valueBuffer,sampleCount){
|
|
40
|
+
if(!envelope||!envelope.length)return [];
|
|
41
|
+
var times=asTypedView(timeBuffer,Float64Array),values=asTypedView(valueBuffer,Float32Array);
|
|
42
|
+
if(!times||!values)throw new Error('the waveform sample buffers did not arrive as binary data');
|
|
43
|
+
var available=Math.min(times.length,values.length);
|
|
44
|
+
if(sampleCount>available)
|
|
45
|
+
throw new Error('the waveform sample buffers are short by '+(sampleCount-available)+' samples');
|
|
46
|
+
for(var i=0;i<envelope.length;i++){
|
|
47
|
+
var b=envelope[i];
|
|
48
|
+
if(b.rf){
|
|
49
|
+
b.rf.t=times.subarray(b.rf.o,b.rf.o+b.rf.n);
|
|
50
|
+
b.rf.m=values.subarray(b.rf.o,b.rf.o+b.rf.n);
|
|
51
|
+
b.rf.pt=times.subarray(b.rf.qo,b.rf.qo+b.rf.qn);
|
|
52
|
+
b.rf.p=values.subarray(b.rf.qo,b.rf.qo+b.rf.qn);
|
|
53
|
+
}
|
|
54
|
+
if(b.gx)attachGradientSamples(b.gx,times,values);
|
|
55
|
+
if(b.gy)attachGradientSamples(b.gy,times,values);
|
|
56
|
+
if(b.gz)attachGradientSamples(b.gz,times,values);
|
|
57
|
+
}
|
|
58
|
+
return envelope;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function attachGradientSamples(gradient,times,values){
|
|
62
|
+
gradient.t=times.subarray(gradient.o,gradient.o+gradient.n);
|
|
63
|
+
gradient.w=values.subarray(gradient.o,gradient.o+gradient.n);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
3
67
|
/* ══ state.js ══ */
|
|
4
68
|
/* ═══════════════════════════════════════════════════════════════════════
|
|
5
69
|
Application state & configuration
|
|
@@ -248,6 +312,16 @@ function applySerializedKspace(payload){
|
|
|
248
312
|
}
|
|
249
313
|
}
|
|
250
314
|
|
|
315
|
+
/* Report a load that did not arrive. Clearing the previous sequence matters as
|
|
316
|
+
much as the message: the progress overlay reaches "Ready" either way, so
|
|
317
|
+
leaving stale blocks on screen would read as a successful load. */
|
|
318
|
+
function showSequenceLoadFailure(message){
|
|
319
|
+
BL=[];waveformOverview=null;blockPos=[];mmCache=null;
|
|
320
|
+
setViewerNotice('sequence',message);
|
|
321
|
+
setExportButtonEnabled(false);
|
|
322
|
+
draw();drawMinimap();
|
|
323
|
+
}
|
|
324
|
+
|
|
251
325
|
/* ── Data reception ───────────────────────────────────────────────────── */
|
|
252
326
|
window.addEventListener('message',function(e){
|
|
253
327
|
var m=e.data;
|
|
@@ -270,7 +344,13 @@ window.addEventListener('message',function(e){
|
|
|
270
344
|
return;
|
|
271
345
|
}
|
|
272
346
|
if(m.type==='sequenceData'){
|
|
273
|
-
|
|
347
|
+
try{
|
|
348
|
+
BL=unpackSequenceBlocks(m.blocks,m.sampleTimes,m.sampleValues,m.sampleCount||0);
|
|
349
|
+
}catch(err){
|
|
350
|
+
showSequenceLoadFailure('Failed to load the sequence waveforms: '+(err&&err.message||err)+'.');
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
TD=m.totalDuration||0;GR=m.gradRaster||1e-5;
|
|
274
354
|
setViewerNotice('sequence',m.notices&&m.notices.length?m.notices.join(' '):null);
|
|
275
355
|
setViewerNotice('kspaceOverrideFailure',null);setKspaceSafetyWarning(m.kspaceSafety||null);
|
|
276
356
|
setViewerNotice('m1',null);setViewerNotice('pns',null);setViewerNotice('pnsThreshold',null);
|
|
@@ -288,6 +368,8 @@ window.addEventListener('message',function(e){
|
|
|
288
368
|
if(seqTiming&&seqTiming.trTimeSec>0){fitToFirstTR();}else{fit();}
|
|
289
369
|
draw();drawKs();drawMinimap();
|
|
290
370
|
setExportButtonEnabled(true);
|
|
371
|
+
}else if(m.type==='loadError'){
|
|
372
|
+
showSequenceLoadFailure(m.message||'The sequence could not be loaded.');
|
|
291
373
|
}else if(m.type==='kspaceData'){
|
|
292
374
|
applySerializedKspace(m.kspace);finishDangerousKspaceCalculation(null);drawKs();
|
|
293
375
|
if(typeof kOpen!=='undefined'&&!kOpen)document.getElementById('kbtn').click();
|
|
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
|