|
30 | 30 | QStatusBar, |
31 | 31 | QToolButton, |
32 | 32 | QWidget, |
| 33 | + QGraphicsItemGroup |
33 | 34 | ) |
34 | 35 | from scipy.stats import skew, zscore |
35 | | - |
36 | 36 | from facemap import process, roi, utils |
37 | 37 | from facemap.gui import ( |
38 | 38 | guiparts, |
@@ -265,6 +265,7 @@ def __init__( |
265 | 265 | self.cframe = 0 |
266 | 266 | self.traces1 = None |
267 | 267 | self.traces2 = None |
| 268 | + self.saccade_data = None |
268 | 269 |
|
269 | 270 | ## Pose plot |
270 | 271 | self.pose_scatterplot = pg.ScatterPlotItem(hover=True) |
@@ -939,6 +940,7 @@ def reset(self): |
939 | 940 | self.keypoints_vtick = None |
940 | 941 | self.svd_plot_vtick = None |
941 | 942 | self.neural_win = None |
| 943 | + self.saccade_data = None |
942 | 944 |
|
943 | 945 | def pupil_sigma_change(self): |
944 | 946 | self.pupil_sigma = float(self.sigma_box.text()) |
@@ -2012,9 +2014,59 @@ def plot_trace(self, wplot, proctype, wroi, color, keypoints_group_selected=None |
2012 | 2014 | pen=pg.mkPen(color=(255, 255, 255), width=2, movable=True), |
2013 | 2015 | ) |
2014 | 2016 | selected_plot.addItem(self.keypoints_vtick) |
| 2017 | + if self.saccade_data is not None: |
| 2018 | + self.plot_saccade_data() |
2015 | 2019 | selected_plot.setLimits(xMin=0, xMax=self.nframes) |
2016 | 2020 | return tr |
2017 | 2021 |
|
| 2022 | + def plot_saccade_data(self): |
| 2023 | + """ |
| 2024 | + Plot saccade data on the SVD traces plot as a single toggleable item. |
| 2025 | + """ |
| 2026 | + if self.saccade_data is not None: |
| 2027 | + # Extract saccade data |
| 2028 | + saccade = self.saccade_data['Saccade'][0, 0].squeeze() |
| 2029 | + |
| 2030 | + # Check if saccade data matches the number of frames |
| 2031 | + if saccade.shape[0] != self.nframes: |
| 2032 | + print("Saccade data shape does not match the number of frames.") |
| 2033 | + return |
| 2034 | + |
| 2035 | + # Find start and end indices for saccades |
| 2036 | + sac_start_idx = np.where(np.diff(saccade) == 1)[0] + 1 |
| 2037 | + sac_end_idx = np.where(np.diff(saccade) == -1)[0] + 1 |
| 2038 | + |
| 2039 | + # Remove any existing saccade overlays to avoid duplication |
| 2040 | + if hasattr(self, 'saccade_vspan_items') and self.saccade_vspan_items: |
| 2041 | + for item in self.saccade_vspan_items: |
| 2042 | + self.svd_traces_plot.removeItem(item) |
| 2043 | + |
| 2044 | + # Create a list to store the saccade region items |
| 2045 | + self.saccade_vspan_items = [] |
| 2046 | + |
| 2047 | + # Add vertical spans for each saccade |
| 2048 | + for start, end in zip(sac_start_idx, sac_end_idx): |
| 2049 | + if start < end and end < self.nframes: |
| 2050 | + # Create a LinearRegionItem for the saccade |
| 2051 | + vspan = pg.LinearRegionItem( |
| 2052 | + values=(start, end), # Start and end positions |
| 2053 | + brush=pg.mkBrush(255, 255, 255, 50), # Semi-transparent white |
| 2054 | + movable=False, # Non-movable |
| 2055 | + ) |
| 2056 | + |
| 2057 | + # Add the region to the plot |
| 2058 | + self.svd_traces_plot.addItem(vspan) |
| 2059 | + |
| 2060 | + # Keep track of added items for later removal |
| 2061 | + self.saccade_vspan_items.append(vspan) |
| 2062 | + else: |
| 2063 | + print("No saccade data available.") |
| 2064 | + |
| 2065 | + def toggle_saccade_vspans(self, show): |
| 2066 | + # Toggles visibility of the saccade vspans group |
| 2067 | + if hasattr(self, 'saccade_vspan_group'): # Check if the group exists |
| 2068 | + self.saccade_vspan_group.setVisible(show) |
| 2069 | + |
2018 | 2070 | def on_click_svd_plot(self, event): |
2019 | 2071 | """ |
2020 | 2072 | Update vtick position of svd plot when user clicks |
|
0 commit comments