Skip to content

ENH: button to save movie #9190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Apr 8, 2021
Merged

Conversation

GuillaumeFavelier
Copy link
Contributor

@GuillaumeFavelier GuillaumeFavelier commented Mar 24, 2021

This PR adds a button to save_movie for the notebook 3d backend.

image

import mne
mne.viz.set_3d_backend('notebook')
import os
from mne.datasets import sample
data_path = sample.data_path()
sample_dir = os.path.join(data_path, 'MEG', 'sample')
subjects_dir = os.path.join(data_path, 'subjects')
fname_stc = os.path.join(sample_dir, 'sample_audvis-meg')
stc = mne.read_source_estimate(fname_stc, subject='sample')
initial_time = 0.13
brain = stc.plot(subjects_dir=subjects_dir, initial_time=initial_time,
                 clim=dict(kind='value', lims=[3, 6, 9]),
                 size=600,
                 background="white",
                 hemi='split',
                 views=['lat', 'med']
)

ToDo:

It's an item of #8704

@GuillaumeFavelier GuillaumeFavelier changed the title ENHsave movie ENH: button to save movie Mar 24, 2021
@GuillaumeFavelier GuillaumeFavelier self-assigned this Mar 24, 2021
@GuillaumeFavelier GuillaumeFavelier changed the title ENH: button to save movie WIP,ENH: button to save movie Mar 24, 2021
@GuillaumeFavelier
Copy link
Contributor Author

Now i get it! The Notebook job actually skips the notebook test 😅

...
mne/viz/_brain/tests/test_notebook.py::test_notebook_3d_backend[notebook] SKIPPED
...

https://dev.azure.com/mne-tools/mne-python/_build/results?buildId=12805&view=logs&j=f8b184f0-8536-5d07-cb2e-df31a09e5d0f&t=7eff19d8-9485-515c-ad38-577dd2e13f81&l=54

@GuillaumeFavelier
Copy link
Contributor Author

The notebook test should fail until the following (naked PyQt5 everywhere) is reworked:

if self.time_viewer:
if filename is None:
try:
from pyvista.plotting.qt_plotting import FileDialog
except ImportError:
from pyvistaqt.plotting import FileDialog
self.status_msg.set_value("Choose movie path ...")
self.status_msg.show()
self.status_progress.set_value(0)
def _post_setup(unused):
del unused
self.status_msg.hide()
self.status_progress.hide()
dialog = FileDialog(
self.plotter.app_window,
callback=partial(self._save_movie, **kwargs)
)
dialog.setDirectory(os.getcwd())
dialog.finished.connect(_post_setup)
return dialog
else:
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor
def frame_callback(frame, n_frames):
if frame == n_frames:
# On the ImageIO step
self.status_msg.set_value(
"Saving with ImageIO: %s"
% filename
)
self.status_msg.show()
self.status_progress.hide()
self._renderer._status_bar_update()
else:
self.status_msg.set_value(
"Rendering images (frame %d / %d) ..."
% (frame + 1, n_frames)
)
self.status_msg.show()
self.status_progress.show()
self.status_progress.forward(
"setRange", 0, n_frames - 1)
self.status_progress.set_value(frame)
self.status_progress.update()
self.status_msg.update()
self._renderer._status_bar_update()
# set cursor to busy
default_cursor = self._renderer._window_get_cursor()
self._renderer._window_set_cursor(QCursor(Qt.WaitCursor))
try:
self._save_movie(
filename=filename,
time_dilation=(1. / self.playback_speed),
callback=frame_callback,
**kwargs
)
except (Exception, KeyboardInterrupt):
warn('Movie saving aborted:\n' + traceback.format_exc())
finally:
self._renderer._window_set_cursor(default_cursor)

@GuillaumeFavelier
Copy link
Contributor Author

I removed the strange and untested use case where no filename is given considering that there are so many ways to input a filename (including generating one automatically). This simplifies save_movie a great deal.

Also this is how it looks for me with the notebook 3d backend after d711b14:

output.mp4

I'll try to fix the notebook CI and double-check the status bar layout.

@GuillaumeFavelier
Copy link
Contributor Author

GuillaumeFavelier commented Mar 26, 2021

When I create server_environment.yml locally and test it manually, it says that it requires PyQt5 🤔

mne/viz/_brain/tests/test_notebook.py::test_notebook_3d_backend[notebook] SKIPPED (Test skipped, requires PyQt5.)

@GuillaumeFavelier
Copy link
Contributor Author

Found it, it probably comes from _check_skip_backend:

mne-python/mne/conftest.py

Lines 341 to 342 in d711b14

if not has_pyqt5():
pytest.skip("Test skipped, requires PyQt5.")

@GuillaumeFavelier
Copy link
Contributor Author

This time it passed:

...
mne/viz/_brain/tests/test_brain.py::test_brain_save_movie[pyvista] SKIPPED [ 16%]
mne/viz/_brain/tests/test_brain.py::test_calculate_lut PASSED            [ 16%]
mne/viz/_brain/tests/test_notebook.py::test_notebook_3d_backend[notebook] Coverage.py warning: --include is ignored because --source is set (include-ignored) 
PASSED [ 17%] 👈
mne/viz/backends/tests/test_renderer.py::test_backend_environment_setup[mayavi] SKIPPED [ 17%]
mne/viz/backends/tests/test_renderer.py::test_backend_environment_setup[pyvista] PASSED [ 18%]
mne/viz/backends/tests/test_renderer.py::test_backend_environment_setup[foo] XFAIL [ 18%]
...

@GuillaumeFavelier
Copy link
Contributor Author

The layout is fixed after 6b6f5d6. I also set the attributes of the status bar and dock to private. It's now ready for reviews @agramfort, @larsoner

@GuillaumeFavelier GuillaumeFavelier changed the title WIP,ENH: button to save movie ENH: button to save movie Mar 26, 2021
@larsoner
Copy link
Member

Pushed a hotfix related to mne-bids branch renaming to our main and restarted the build here

Copy link
Member

@larsoner larsoner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to update the test.ipynb? A quick look suggests there is no save_movie called in there, so we must be relying on the button press to get us there.

It's probably worthwhile to make a _TempDir, and monkey-patch _get_default_file_name to write to some known file like that op.join(tempdir, 'test.png') then assert op.isfile(fname) after clicking all the buttons. Or maybe simpler, figure out how to modify the "screenshot path" widget with this path before clicking all buttons. This text is about screenshots but the same could apply to movies (somehow). WDYT? To me the updated testing infrastructure is important...

self._renderer.screenshot(mode=mode, filename=filename)
default_name = _generate_default_filename(".png")
filename = default_name if filename is None else filename
from ..utils import _save_ndarray_img
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does not need to be nested

Comment on lines 2581 to 2582
default_name = _generate_default_filename(".png")
filename = default_name if filename is None else filename
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
default_name = _generate_default_filename(".png")
filename = default_name if filename is None else filename
if filename is None:
filename = _generate_default_filename(".png")

filename = default_name if filename is None else filename
from ..utils import _save_ndarray_img
_save_ndarray_img(
filename, self.screenshot(mode=mode, time_viewer=True))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we even need a time_viewer op.tion in screenshot anymore? Nothing changes with the 3D rendering with this anymore because all controls are in Qt or ipywidgets, right?

But we probably should add a show_traces argument. But both of these could be in a quick follow-up PR I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I don't think this parameter is necessary anymore in here

@GuillaumeFavelier GuillaumeFavelier changed the title ENH: button to save movie WIP,ENH: button to save movie Apr 6, 2021
@GuillaumeFavelier
Copy link
Contributor Author

we must be relying on the button press to get us there.

Indeed, it is done in :

...
    "    for action in brain._renderer.actions.values():\n",
    "        if isinstance(action, Button):\n",
    "            action.click()\n",
    "            number_of_buttons += 1\n",
...

From:

" for action in brain._renderer.actions.values():\n",
" if isinstance(action, Button):\n",
" action.click()\n",
" number_of_buttons += 1\n",

It's probably worthwhile to make a _TempDir

I'm on it.

@GuillaumeFavelier
Copy link
Contributor Author

I updated test.ipynb in 84296cd to use tempfile. I chose the second approach:

Or maybe simpler, figure out how to modify the "screenshot path" widget with this path before clicking all buttons

@GuillaumeFavelier GuillaumeFavelier changed the title WIP,ENH: button to save movie ENH: button to save movie Apr 6, 2021
@GuillaumeFavelier
Copy link
Contributor Author

I think it's ready now

@GuillaumeFavelier
Copy link
Contributor Author

Actually, I can wait for #9034 and update accordingly.

@GuillaumeFavelier
Copy link
Contributor Author

GuillaumeFavelier commented Apr 7, 2021

The GitHub Actions jobs fail with:

gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now
Error: Process completed with exit code 2.

during the Installation dependencies step:

https://github.com/mne-tools/mne-python/runs/2285850191?check_suite_focus=true#step:5:308

It seems related to:

curl -L https://osf.io/g7dzs/download | tar xz

Or:

curl -L https://osf.io/rjcz4/download | tar xz

But I still have to confirm it.

@GuillaumeFavelier
Copy link
Contributor Author

GuillaumeFavelier commented Apr 7, 2021

Locally I was able to reproduce:

❯ curl -L https://osf.io/rjcz4/download | tar xz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   290  100   290    0     0      2      0  0:02:25  0:02:01  0:00:24    71

gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now

There seem to be something wrong with this link. My web browser cannot process it either:

image

@GuillaumeFavelier
Copy link
Contributor Author

It was only a temporary issue, probably server overload or something 🤔 I restarted the failing jobs.

@GuillaumeFavelier
Copy link
Contributor Author

GuillaumeFavelier commented Apr 8, 2021

I updated testing in d0f71e5 after #9034 got merged, it's ready on my end.

@larsoner larsoner merged commit 176680a into mne-tools:main Apr 8, 2021
@larsoner
Copy link
Member

larsoner commented Apr 8, 2021

Thanks @GuillaumeFavelier

@GuillaumeFavelier GuillaumeFavelier deleted the enh/save_movie branch April 9, 2021 13:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants