コード例 #1
0
    def make_window(self):
        """Make experiment GUI, defined in children depending on experiments."""
        if self.stim_plot:
            self.window_main = DynamicStimExperimentWindow(self)
            self.window_main.stream_plot.add_stream(self.protocol_runner.dynamic_log)
            self.gui_timer.start(1000 // 60)
        else:
            self.window_main = VisualExperimentWindow(self)

        self.window_main.construct_ui()
        self.window_main.show()
コード例 #2
0
class VisualExperiment(Experiment):
    """General class that runs an experiment.

    Parameters
    ----------
    calibrator : :class:`Calibrator <stytra.calibration.Calibrator>` object
        (optional) Calibrator object to calibrate the stimulus display. If
        not set, a CrossCalibrator will be used.
    display_config: dict
        (optional) Dictionary with specifications for the display. Possible
        key values are "full_screen" and "window_size".
        gl_display : bool (False)
    rec_stim_framerate : int
        (optional) Set to record a movie of the displayed visual stimulus. It
        specifies every how many frames one will be saved (set to 1 to
        record) all displayed frames. The final movie will be saved in the
        directory in an .h5 file.
    offline : bool
        if stytra is used in offline analysis, stimulus is not displayed
    """

    sig_data_saved = pyqtSignal()

    def __init__(
        self,
        *args,
        calibrator=None,
        stim_plot=False,
        stim_movie_format="h5",
        record_stim_framerate=None,
        display=None,
        **kwargs
    ):
        """ """
        if calibrator is None:
            self.calibrator = CrossCalibrator()
        else:
            self.calibrator = calibrator
        self.stim_movie_format = stim_movie_format
        self.stim_plot = stim_plot

        super().__init__(*args, **kwargs)
        self.dc.add(self.calibrator)

        if display is None:
            self.display_config = dict(full_screen=False, gl=True)
        else:
            self.display_config = display
            target_fps = self.display_config.get("framerate", 0)
            if target_fps > 0:
                self.protocol_runner.target_dt = 1000 // target_fps
        if not self.offline:
            self.window_display = StimulusDisplayWindow(
                self.protocol_runner,
                self.calibrator,
                gl=self.display_config.get("gl", True),
                record_stim_framerate=record_stim_framerate,
            )

        self.display_framerate_acc = None
        self.protocol_runner.framerate_acc.goal_framerate = self.display_config.get(
            "min_framerate", None
        )

    def start_experiment(self):
        """Start the experiment creating GUI and initialising metadata.

        Parameters
        ----------

        Returns
        -------

        """
        super().start_experiment()

        if self.display_config.get("window_size", None) is not None:
            self.window_display.size = self.display_config["window_size"]
            self.window_display.set_dims()

        self.show_stimulus_screen(self.display_config.get("full_screen", False))

    def restore_window_state(self):
        if self.gui_params.window_state:
            self.window_main.restoreState(
                QByteArray.fromHex(bytes(self.gui_params.window_state, "ascii"))
            )
            self.window_main.restoreGeometry(
                QByteArray.fromHex(bytes(self.gui_params.geometry, "ascii"))
            )

    def make_window(self):
        """Make experiment GUI, defined in children depending on experiments."""
        if self.stim_plot:
            self.window_main = DynamicStimExperimentWindow(self)
            self.window_main.stream_plot.add_stream(self.protocol_runner.dynamic_log)
            self.gui_timer.start(1000 // 60)
        else:
            self.window_main = VisualExperimentWindow(self)

        self.window_main.construct_ui()
        self.window_main.show()

    def start_protocol(self):
        """Start the protocol from the ProtocolRunner. Before that, send a
        a notification and if required communicate with the microscope to
        synchronize and read configuration.

        Parameters
        ----------

        Returns
        -------

        """
        self.window_display.widget_display.reset()
        super().start_protocol()

    def save_data(self):
        if self.base_dir is not None:
            if self.dc is not None:
                # save the stimulus movie if it is generated
                movie, movie_times = self.window_display.widget_display.get_movie()
                if movie is not None:
                    if self.stim_movie_format == "h5":
                        movie_dict = dict(
                            movie=np.stack(movie, 0), movie_times=movie_times
                        )
                        fl.save(
                            self.filename_base() + "stim_movie.h5",
                            movie_dict,
                            compression="blosc",
                        )
                    elif self.stim_movie_format == "mp4":
                        imageio.mimwrite(
                            self.filename_base() + "stim_movie.mp4",
                            movie,
                            fps=30,
                            quality=None,
                            ffmpeg_params=[
                                "-pix_fmt",
                                "yuv420p",
                                "-profile:v",
                                "baseline",
                                "-level",
                                "3",
                            ],
                        )
                    else:
                        raise Exception(
                            "Tried to write the stimulus video into an unsupported format"
                        )
        super().save_data()

    def show_stimulus_screen(self, full_screen=False):
        """Open window to display the visual stimulus and make it full-screen
        if necessary.

        Parameters
        ----------
        full_screen :
             (Default value = True)

        Returns
        -------

        """
        if self.offline:
            return None
        self.window_display.show()
        if full_screen:
            try:
                self.window_display.windowHandle().setScreen(self.app.screens()[1])
                self.window_display.showFullScreen()
            except IndexError:
                print("Second screen not available")