VH-Lab / VH-Lab/vhlab-NewStim-python
What vhlab-library-python and NDI-python actually need from here: five calls, and a .mat object reader under them
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- Avg merge
- 3m
- Merged PRs (30d)
- 1
Description
Companion to #1 and #2. Those cover the convention and the PsychoPy question; this one answers "what should be built first", derived from the callers rather than from the MATLAB folder layout.
The short version: the API surface the downstream ports need is five methods, and four of them are one-line field reads. Essentially all of the work is the layer underneath — turning a MATLAB-written stims.mat back into objects.
The five calls
Verified against vhlab-NewStim-matlab 0ae6822, vhlab-library-matlab cca1cce and NDI-matlab 18ff517:
| call | MATLAB | what it does |
|---|---|---|
numStims(script) |
Scripts/@stimscript/numStims.m |
length(S.Stims) |
get(script, i) |
Scripts/@stimscript/get.m |
S.Stims{i}, 1-based, bounds-checked |
getDisplayOrder(script) |
Scripts/@stimscript/getDisplayOrder.m |
S.displayOrder |
getparameters(stim) |
Stimuli/@<class>/getparameters.m |
a per-class field read: S.PSparams for @periodicstim, S.SGSparams for @stochasticgridstim, … The base @stimulus returns empty; all 19 classes override it |
duration(stim) |
Stimuli/@<class>/duration.m |
stimulus duration in seconds; needed by one caller |
Nothing in that list needs Psychtoolbox, which is why the reader scope in #1 is coherent: the data face of stimscript is pure struct access.
Who is waiting, exactly
NDI-python — one blocker. ndi.daq.metadatareader.NewStimStims (NewStimStims.m:36-37):
for i=1:numStims(ss)
parameters{i} = getparameters(get(ss,i));
end
That is the whole dependency: numStims, get, getparameters. It is also the one with a fidelity requirement attached — those parameter structs become the stimulus parameters stored in NDI documents, so field names and types have to match MATLAB exactly or NDI-python's documents diverge from NDI-matlab's for the same experiment.
A call site that looks blocked and is not: +ndi/+setup/+daq/+reader/+mfdaq/+stimulus/vhlabvisspike2.m:116 calls getstimscript — but it never touches ss afterwards. It uses only mti (mti{i}.stimid, mti{i}.startStopTimes), which are plain structs. vhlib.StimDecode.getstimscript already returns those today, so that reader can be ported now, with no NewStim at all.
vhlab-library-python — six functions, all in StimulusDecoding, listed with what each needs:
| function | needs |
|---|---|
repairoverflow_stimtimes_txt |
getDisplayOrder — already ported but incomplete; it raises without this |
getstimscriptparameters |
numStims, get, getparameters |
getstimscriptproperties |
numStims, get, getparameters, getDisplayOrder |
findtransitionsSGSBL |
numStims, getparameters, getDisplayOrder, plus @stochasticgridstim / @blinkingstim parameter semantics |
stimscriptgraph |
numStims, getDisplayOrder — currently a stub that raises NotImplementedError |
mti_from_stimtimes_txt |
get, duration |
Two corrections while deriving this (both recorded wrongly in vhlib's bridge; I will fix them there):
getstimscriptsyncis not blocked on NewStim. It isgetstimscript+tpcorrectmti, and it makes no stimscript calls at all.tpcorrectmtiis not defined invhlab-library-matlab,vhlab-toolbox-matlab,vhlab-NewStim-matlabor NDI-matlab — the VH-lab equivalentvhlabcorrectmtiis already ported — so it is blocked on locating or replacing that dependency.check_stimtimes_txt_vs_stims_matis not blocked on NewStim either. It readsz.MTI2{j}.stimidand nothing else out ofstims.mat; the stimscript never enters. It is blocked ondirstructplumbing.
So the NewStim-blocked set is six functions plus one NDI reader — smaller than #9 in vhlab-library-python assumed, and pointed at a narrower API.
The actual work: reading the objects
MATLAB stores saveScript as an old-style @stimscript object holding Stims (a cell array of @periodicstim, @stochasticgridstim, … objects), displayOrder, displayMethod and StimTimes. scipy.io.loadmat surfaces old-style class objects as a MATLAB-object wrapper carrying the class name, not as a struct, and the stimulus objects are nested one level down inside it. Everything above is trivial once that is unwrapped into Python objects that know their class.
Two consequences for whoever starts:
scipy.io.savematcannot write a MATLAB object, so tests cannot synthesize fixtures. Realstims.matfiles recorded from MATLAB have to be committed — ideally one per stimulus class that appears in VH lab data.vhlib'sgetstimscripttests stand a plain struct in forsaveScriptfor exactly this reason, and are honest that they check only the directory and error logic.- Class coverage can be driven by data, not by the folder. There are 19 stimulus classes, but the ones that appear in recorded experiments are few —
@periodicstim,@stochasticgridstim,@blinkingstimand@hartleystimcover most of it. Sincegetparametersis a per-class field read, each additional class is roughly one table entry once the loader exists.
Suggested order
- The
.mat→ object reader for@stimscriptand the@stimulussubclasses, with committed MATLAB-written fixtures. Everything else is downstream of this. numStims,get,getparameters— unblocks NDI'sNewStimStims(the only NDI blocker) and threevhlibfunctions.getDisplayOrder— completesrepairoverflow_stimtimes_txtand unblocks three more.duration—mti_from_stimtimes_txt.- Per-class parameter fidelity for whichever classes the lab's data actually contains, checked field-by-field against MATLAB for the NDI document requirement above.
Related: VH-Lab/vhlab-library-python#9, VH-Lab/vhlab-library-python#6.
🤖 Generated with Claude Code
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the scipy.io.loadmat path behind getstimscript and the MATLAB @stimscript and stimulus object shapes described here. Add committed MATLAB-written stims.mat fixtures for representative classes, then implement the object reader and the five calls: numStims, get, getparameters, getDisplayOrder, and duration. Done means downstream callers can read real fixtures with MATLAB-compatible parameter fields and types.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- data
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100