Skip to content

Fix plot_conditions plotting a single epoch instead of the condition average - #329

Open
adityasingh2400 wants to merge 1 commit into
NeuroTechX:masterfrom
adityasingh2400:fix-plot-conditions-legend
Open

Fix plot_conditions plotting a single epoch instead of the condition average#329
adityasingh2400 wants to merge 1 commit into
NeuroTechX:masterfrom
adityasingh2400:fix-plot-conditions-legend

Conversation

@adityasingh2400

Copy link
Copy Markdown

plot_conditions in eegnb/analysis/analysis_utils.py does not plot the ERP. It plots one arbitrary single epoch per channel. This is the function behind every example in the gallery, so the N170, P300, SSVEP and cueing figures in the published docs are all showing raw single trials rather than condition averages.

The cause is a wide-versus-long data problem. The function builds pd.DataFrame(X[y.isin(cond), ch].T, index=times), whose columns are epochs, and then calls sns.lineplot(data=..., x=times, y=ch). Seaborn reads y=ch as a column key, and column number ch of that frame is epoch number ch. So channel 0 draws epoch 0, channel 1 draws epoch 1, and so on, with no averaging over trials and no confidence interval. I think this is the same regression pellet described on the issue when he noted the plots looked wrong after the seaborn line plotting change, since a single trial looks exactly that noisy.

The legend has a related problem, which is what the issue reports directly. It was built by passing a bare list of labels to axes[-1].legend(...), and matplotlib pairs a bare label list with whatever artists it finds on the axis in draw order. The labels are written difference-waveform-first while the artists are drawn conditions-first, and on current seaborn the confidence band is picked up as a handle as well, so the labels land on the wrong lines and the black difference waveform gets no entry at all. On my machine the legend read 2 - 1 next to the red Non-Target line, NonTarget next to a shaded band, and Target next to the green Target line.

The fix reshapes each condition to long form so seaborn averages across epochs and bootstraps the interval, which is what the original sns.tsplot call did before the migration, and builds the legend from explicit Line2D handles so each label carries its own colour regardless of how many artists the plotting calls add. eegnb/analysis/utils.py already holds a corrected copy of this function, so this brings the module the examples actually import back in line with it.

I added tests/test_analysis_plots.py, which runs on synthetic MNE epochs and needs no hardware and no downloaded dataset. Reverting only the source change and rerunning gives 3 failed, with channel 0: plotted 1.0 but the condition average is 4.0 for the averaging test and legend handles should be lines, not confidence-interval bands for the legend test. With the change applied all 3 pass. As a further check, on synthetic data with 30 epochs per condition and 2 uV of per-trial noise the averaged trace now has a standard deviation of 0.365 uV, matching the 2.0/sqrt(30) you expect from a real average, where before it was the full single-trial 2 uV. mypy is clean on both files.

Fixes #226

plot_conditions built a wide epochs-by-time DataFrame and passed the
channel number as seaborn's `y`. Seaborn read that as a column key, so it
selected column number `ch` of the frame. Those columns are epochs, not
channels, so each subplot showed a single arbitrary epoch with no
averaging and no confidence interval.

The legend had a related problem. It was built from a bare list of labels,
which matplotlib pairs with whatever artists it finds in draw order. The
labels were written difference-first while the artists are drawn
conditions-first, and seaborn's confidence bands are picked up as handles
too, so labels ended up on the wrong lines.

Reshape the data to long form so seaborn averages over epochs, and build
the legend from explicit Line2D handles so every label carries its own
colour.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Legend items order when using diff_waveform in plot_conditions

1 participant