Skip to content

Commit 3a40e10

Browse files
committed
Merge branch 'process-events' into xfit
2 parents 2434a0e + 052d3d3 commit 3a40e10

5 files changed

Lines changed: 37 additions & 34 deletions

File tree

‎.gitignore‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,5 @@ venv/
104104
.hypothesis/
105105
.ruff_cache/
106106
.ipynb_checkpoints/
107-
/.claude/
107+
/.claude/
108+
uv.lock

‎mne/viz/_brain/_brain.py‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,6 @@ def setup_time_viewer(self, time_viewer=True, show_traces=True):
638638
for hemi in ("lh", "rh"):
639639
for ri, ci, v in self._iter_views(hemi):
640640
self.show_view(view=v, row=ri, col=ci)
641-
self._renderer._process_events()
642641

643642
self._renderer._update()
644643
# finally, show the MplCanvas
@@ -1043,7 +1042,7 @@ def _refresh_colormap_widgets(self):
10431042
fmid=self._data["fmid"],
10441043
fmax=self._data["fmax"],
10451044
)
1046-
self._renderer._process_events()
1045+
self._renderer._update()
10471046

10481047
def _configure_dock_trace_widget(self, name):
10491048
if not self.show_traces:
@@ -1596,7 +1595,7 @@ def _on_time_change(self, event):
15961595
if "current_time" in self.widgets:
15971596
self.widgets["current_time"].set_value(f"{self._current_time: .3f}")
15981597
self.plot_time_line(update=True)
1599-
self._renderer._process_events()
1598+
self._renderer._update()
16001599

16011600
def _on_colormap_range(self, event):
16021601
"""Respond to the colormap_range UI event."""
@@ -1617,7 +1616,7 @@ def _on_colormap_range(self, event):
16171616
self.widgets[entry_key].set_value(val * self._data["fscale"])
16181617
# Update the render.
16191618
self._update_colormap_range(**lims)
1620-
self._renderer._process_events()
1619+
self._renderer._update()
16211620

16221621
def _on_vertex_select(self, event):
16231622
"""Respond to vertex_select UI event."""
@@ -3850,7 +3849,6 @@ def show_view(
38503849
self._set_camera(**view_params, align=align)
38513850
if update:
38523851
self._renderer._update()
3853-
self._renderer._process_events()
38543852

38553853
def _set_camera(
38563854
self,

‎mne/viz/_brain/tests/test_brain.py‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,9 @@ def test_image_screenshot(
916916
"""Test screenshot and image saving."""
917917
size = (300, 300)
918918
brain = _create_testing_brain(hemi="rh", show_traces=False, size=size)
919-
azimuth, elevation = 180.0, 90.0
919+
for mesh in brain.layered_meshes.values():
920+
mesh._actor.SetVisibility(True)
921+
azimuth, elevation = 360.0, 90.0
920922
fname = tmp_path / "test.png"
921923
assert not fname.is_file()
922924
brain.save_image(fname)
@@ -938,6 +940,17 @@ def test_image_screenshot(
938940
div = 2 if np.allclose(img.shape[:2], want_size[:2] / 2.0, atol=15) else 1
939941
want_size[:2] /= div
940942
assert_allclose(img.shape, want_size, atol=15)
943+
944+
# Test whether the renderer has properly updated before the screenshot was taken.
945+
brain.set_time(1)
946+
img1 = brain.screenshot(mode="rgba")
947+
brain.set_time(2)
948+
img2 = brain.screenshot(mode="rgba")
949+
brain.set_time(1)
950+
img3 = brain.screenshot(mode="rgba")
951+
assert not np.array_equal(img1, img2)
952+
assert_array_equal(img1, img3)
953+
941954
brain.close()
942955

943956

‎mne/viz/backends/_pyvista.py‎

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818

1919
import numpy as np
2020
import pyvista
21-
from pyvista import Line, Plotter, PolyData, close_all # noqa: F401 # re-exported
21+
from pyvista import (
22+
Line,
23+
PolyData, # noqa: F401 # re-exported
24+
close_all,
25+
)
2226
from pyvista.plotting.plotter import _ALL_PLOTTERS
2327
from pyvistaqt import BackgroundPlotter
2428
from vtkmodules.util.numpy_support import numpy_to_vtk
@@ -50,12 +54,7 @@
5054
from ...fixes import _compare_version
5155
from ...surface import _vtk_smooth
5256
from ...transforms import _cart_to_sph, _sph_to_cart, apply_trans
53-
from ...utils import (
54-
_check_option,
55-
_require_version,
56-
_validate_type,
57-
warn,
58-
)
57+
from ...utils import _check_option, _require_version, _validate_type, warn
5958
from ._abstract import Figure3D, _AbstractRenderer
6059
from ._utils import (
6160
ALLOWED_QUIVER_MODES,
@@ -156,7 +155,6 @@ def _build(self):
156155
if self.plotter.iren is not None:
157156
self.plotter.iren.initialize()
158157
_process_events(self.plotter)
159-
_process_events(self.plotter)
160158
return self.plotter
161159

162160
def _is_active(self):
@@ -292,14 +290,10 @@ def _hide_axes(self):
292290
def _update(self):
293291
for plotter in self._all_plotters:
294292
# PyVistaQt resolves plotter.update() to QWidget.update(), which only
295-
# schedules a repaint, and it makes Plotter.render() asynchronous (the
296-
# synchronous one being _render()). So render synchronously to update the
297-
# scene, schedule the repaint, then flush it: without the flush the paint
298-
# is delivered whenever events happen to be processed next, which can be
299-
# long after the scene has changed again.
300-
getattr(plotter, "_render", plotter.render)()
301-
plotter.update()
302-
_process_events(plotter)
293+
# schedules a repaint, and it makes Plotter.render() asynchronous. This is
294+
# probably fine for most cases. If you want to synchronously, i.e. wait
295+
# until it has actually gone through, use Plotter._render().
296+
plotter.render()
303297

304298
def _index_to_loc(self, idx):
305299
_ncols = self.figure._ncols
@@ -993,9 +987,9 @@ def _actor(self, mapper=None):
993987
_hide_testing_actor(actor)
994988
return actor
995989

996-
def _process_events(self):
990+
def _process_events(self, level=0):
997991
for plotter in self._all_plotters:
998-
_process_events(plotter)
992+
_process_events(plotter, level=level + 1)
999993

1000994
def _update_picking_callback(
1001995
self, on_mouse_move, on_button_press, on_button_release, on_pick
@@ -1400,7 +1394,6 @@ def _set_3d_view(
14001394

14011395
if update:
14021396
figure.plotter.update()
1403-
_process_events(figure.plotter)
14041397

14051398

14061399
def _set_3d_title(figure, title, size=16, *, color="white", position="upper_left"):
@@ -1412,7 +1405,6 @@ def _set_3d_title(figure, title, size=16, *, color="white", position="upper_left
14121405
name="title",
14131406
)
14141407
figure.plotter.update()
1415-
_process_events(figure.plotter)
14161408
return handle
14171409

14181410

@@ -1422,7 +1414,7 @@ def _check_3d_figure(figure):
14221414

14231415
def _clear_3d_figure(figure):
14241416
figure.plotter.clear() # remove all actors, lights are restored on the next plot
1425-
_process_events(figure.plotter)
1417+
figure.plotter.update()
14261418

14271419

14281420
def _close_3d_figure(figure):
@@ -1434,17 +1426,16 @@ def _close_3d_figure(figure):
14341426
# free memory and deregister from the scraper
14351427
plotter.deep_clean() # remove internal references
14361428
_ALL_PLOTTERS.pop(plotter._id_name, None)
1437-
_process_events(plotter)
14381429

14391430

14401431
def _take_3d_screenshot(figure, mode="rgb", filename=None):
1441-
_process_events(figure.plotter)
1432+
figure.plotter._render() # force the render to happen right now
14421433
return figure.plotter.screenshot(
14431434
transparent_background=(mode == "rgba"), filename=filename
14441435
)
14451436

14461437

1447-
def _process_events(plotter):
1438+
def _process_events(plotter, level=0):
14481439
if hasattr(plotter, "app"):
14491440
with warnings.catch_warnings(record=True):
14501441
warnings.filterwarnings("ignore", "constrained_layout")

‎mne/viz/evoked_field.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ def current_time_func():
248248
current_time_func=current_time_func,
249249
times=evoked.times,
250250
)
251-
if not self._in_brain_figure or "time_slider" not in fig.widgets:
251+
252252
# Draw the time label
253253
self._time_label = time_label
254254
if time_label is not None:
@@ -397,7 +397,7 @@ def _update(self):
397397
x_window=0.01, y_window=0.01, text=time_label, color=self._fg_color
398398
)
399399

400-
self._renderer.plotter.update()
400+
self._renderer._update()
401401

402402
def _configure_dock(self):
403403
"""Configure the widgets shown in the dock on the left."""
@@ -407,7 +407,7 @@ def _configure_dock(self):
407407
r._dock_initialize()
408408

409409
# Fieldline configuration
410-
layout = r._dock_add_group_box("Fieldlines")
410+
layout = r._dock_add_group_box("Fieldlines", collapse=True)
411411

412412
r._dock_add_label(value="max value", align=True, layout=layout)
413413

0 commit comments

Comments
 (0)