@@ -812,7 +812,9 @@ def test_plot_topomap_opm():
812812 fig_evoked = evoked .plot_topomap (
813813 times = [- 0.1 , 0 , 0.1 , 0.2 ], ch_type = "mag" , show = False
814814 )
815- assert len (fig_evoked .axes ) == 5
815+ # Biaxial OPM pairs trigger grouped rendering
816+ # (4 radial + 4 tangential + 2 colorbars)
817+ assert len (fig_evoked .axes ) == 10
816818
817819
818820def test_prepare_topomap_plot_opm_non_quspin_coils ():
@@ -869,6 +871,102 @@ def test_split_opm_overlaps(triaxial_evoked):
869871 assert tangential == ["OPM002" , "OPM003" , "OPM005" , "OPM006" ]
870872
871873
874+ def test_opm_tangential_rms_unsigned (triaxial_evoked ):
875+ """Test that tangential OPM data is RMS magnitude and unsigned."""
876+ picks , pos , merge_channels , names , * _ = topomap ._prepare_topomap_plot (
877+ triaxial_evoked , "mag"
878+ )
879+ data = triaxial_evoked .data [picks ]
880+ grouped = topomap ._compute_orientation_group_data (
881+ data ,
882+ names ,
883+ pos ,
884+ ch_type = "mag" ,
885+ modality = "opm" ,
886+ merge_channels = merge_channels ,
887+ use_opm_orientation_groups = True ,
888+ )
889+ tangential = [group for group in grouped if group [0 ] == "tangential" ][0 ]
890+ assert np .all (tangential [1 ] >= 0 )
891+ assert tangential [4 ]
892+
893+
894+ def test_should_use_opm_orientation_groups_only_for_triaxial ():
895+ """Test that OPM orientation grouping works for biaxial and triaxial overlaps."""
896+ ch_names = [f"OPM{ k :03} " for k in range (1 , 7 )]
897+ info = create_info (ch_names , 1000.0 , ch_types = "mag" )
898+ with info ._unlock ():
899+ for ch in info ["chs" ]:
900+ ch ["coil_type" ] = FIFF .FIFFV_COIL_FIELDLINE_OPM_MAG_GEN1
901+
902+ pair_overlaps = [
903+ np .array (["OPM001" , "OPM002" ]),
904+ np .array (["OPM003" , "OPM004" ]),
905+ ]
906+ triax_overlaps = [
907+ np .array (["OPM001" , "OPM002" , "OPM003" ]),
908+ np .array (["OPM004" , "OPM005" , "OPM006" ]),
909+ ]
910+
911+ # Both biaxial and triaxial overlaps should trigger grouping
912+ assert topomap ._should_use_opm_orientation_groups (pair_overlaps , "mag" )
913+ assert topomap ._should_use_opm_orientation_groups (triax_overlaps , "mag" )
914+
915+
916+ def test_plot_evoked_topomap_opm_triaxial_groups (triaxial_evoked ):
917+ """Test grouped radial/tangential topomap rendering for triaxial OPM."""
918+ fig = triaxial_evoked .plot_topomap (
919+ times = [0.0 ],
920+ ch_type = "mag" ,
921+ contours = 0 ,
922+ res = 8 ,
923+ sensors = False ,
924+ show = False ,
925+ )
926+ assert len (fig .axes ) == 4
927+ titles = [ax .get_title () for ax in fig .axes ]
928+ assert any ("radial" in title for title in titles )
929+ assert any ("tangential" in title for title in titles )
930+
931+
932+ def test_plot_projs_topomap_opm (triaxial_evoked ):
933+ """Test plot_projs_topomap does not crash on colocated OPM channels (gh-13866)."""
934+ from mne import compute_proj_evoked
935+
936+ projs = compute_proj_evoked (triaxial_evoked , n_mag = 2 )
937+ # Should not raise a shape mismatch between data and pos
938+ fig = plot_projs_topomap (projs , triaxial_evoked .info , show = False )
939+ assert len (fig .axes ) >= 1
940+
941+
942+ @pytest .mark .filterwarnings ("ignore:.*No contour levels.*:UserWarning" )
943+ def test_animate_topomap_opm (triaxial_evoked ):
944+ """Test animate_topomap does not crash on colocated OPM channels (gh-13866)."""
945+ fig , anim = triaxial_evoked .animate_topomap (ch_type = "mag" , times = [0.0 ], show = False )
946+ anim ._func (0 )
947+ assert len (fig .axes ) >= 1
948+
949+
950+ def test_plot_arrowmap_opm ():
951+ """Test plot_arrowmap does not crash on colocated OPM channels (gh-13866)."""
952+ from mne .viz import plot_arrowmap
953+
954+ # Need at least 3 unique sensor locations for Delaunay triangulation
955+ ch_names = [f"OPM{ k :03d} " for k in range (1 , 10 )]
956+ info = create_info (ch_names , 1000.0 , ch_types = "mag" )
957+ positions = np .array (
958+ [[0.03 , 0.0 , 0.05 ]] * 3 + [[- 0.03 , 0.0 , 0.05 ]] * 3 + [[0.0 , 0.03 , 0.05 ]] * 3
959+ )
960+ with info ._unlock ():
961+ for idx , ch in enumerate (info ["chs" ]):
962+ ch ["coil_type" ] = FIFF .FIFFV_COIL_FIELDLINE_OPM_MAG_GEN1
963+ ch ["loc" ][:3 ] = positions [idx ]
964+ rng = np .random .default_rng (0 )
965+ data_snap = rng .standard_normal (9 )
966+ fig = plot_arrowmap (data_snap , info , show = False )
967+ assert len (fig .axes ) == 1
968+
969+
872970def test_plot_topomap_nirs_overlap (fnirs_epochs ):
873971 """Test plotting nirs topomap with overlapping channels (gh-7414)."""
874972 fig = fnirs_epochs ["A" ].average (picks = "hbo" ).plot_topomap ()
0 commit comments