Skip to content
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

Fix default data description #783

Merged
merged 13 commits into from
Oct 17, 2024
Merged
40 changes: 36 additions & 4 deletions src/foraging_gui/Calibration.ui
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<y>0</y>
<width>330</width>
<height>60</height>
<height>80</height>
</rect>
</property>
<property name="title">
Expand All @@ -138,7 +138,7 @@
<property name="geometry">
<rect>
<x>40</x>
<y>20</y>
<y>15</y>
<width>100</width>
<height>25</height>
</rect>
Expand All @@ -154,7 +154,7 @@
<property name="geometry">
<rect>
<x>180</x>
<y>20</y>
<y>15</y>
<width>100</width>
<height>25</height>
</rect>
Expand All @@ -166,6 +166,38 @@
<bool>true</bool>
</property>
</widget>
<widget class="QPushButton" name="OpenLeft5ml">
<property name="geometry">
<rect>
<x>40</x>
<y>50</y>
<width>100</width>
<height>25</height>
</rect>
</property>
<property name="text">
<string>Open left 5ml</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
<widget class="QPushButton" name="OpenRight5ml">
<property name="geometry">
<rect>
<x>180</x>
<y>50</y>
<width>100</width>
<height>25</height>
</rect>
</property>
<property name="text">
<string>Open right 5ml</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</widget>
<widget class="QPushButton" name="EmergencyStop">
<property name="geometry">
Expand Down
121 changes: 74 additions & 47 deletions src/foraging_gui/Dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import numpy as np
import pandas as pd
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from PyQt5.QtWidgets import QApplication, QDialog, QVBoxLayout, QHBoxLayout, QMessageBox
from PyQt5.QtWidgets import QApplication, QDialog, QVBoxLayout, QHBoxLayout, QMessageBox
from PyQt5.QtWidgets import QLabel, QDialogButtonBox,QFileDialog,QInputDialog, QLineEdit
from PyQt5 import QtWidgets, uic, QtGui
from PyQt5.QtCore import QThreadPool,Qt, QAbstractTableModel, QItemSelectionModel, QObject, QTimer
Expand Down Expand Up @@ -332,16 +332,39 @@ def __init__(self, MainWindow,parent=None):
child.setDefault(False)
child.setAutoDefault(False)

# setup flags to keep lines open
self.left_valve_open_timer = QTimer(timeout=lambda: self.reopen_valve('Left'), interval=10000)
self.right_valve_open_timer = QTimer(timeout=lambda: self.reopen_valve('Right'), interval=10000)
# setup QTimers to keep lines open
self.left_open_timer = QTimer(timeout=lambda: self.reopen_valve('Left'), interval=10000)
self.right_open_timer = QTimer(timeout=lambda: self.reopen_valve('Right'), interval=10000)

# setup QTimers to keep close lines after 5ml
self.left_close_timer = QTimer(timeout=lambda: self.OpenLeft5ml.setChecked(False)) # trigger _ToggleValve call
self.right_close_timer = QTimer(timeout=lambda: self.OpenRight5ml.setChecked(False))

# setup Qtimers for updating text countdown
self.left_text_timer = QTimer(timeout=lambda:
self.OpenLeft5ml.setText(f'Open left 5ml: {round(self.left_close_timer.remainingTime()/1000)}s'),
interval=1000)
self.right_text_timer = QTimer(timeout=lambda:
self.OpenRight5ml.setText(f'Open right 5ml: {round(self.right_close_timer.remainingTime()/1000)}s'),
interval=1000)

def _connectSignalsSlots(self):
self.SpotCheckLeft.clicked.connect(self._SpotCheckLeft)
self.SpotCheckRight.clicked.connect(self._SpotCheckRight)
self.OpenLeftForever.clicked.connect(self._OpenLeftForever)
self.OpenRightForever.clicked.connect(self._OpenRightForever)

# Set up OpenLeftForever button
self.OpenLeftForever.clicked.connect(lambda: self._ToggleValve(self.OpenLeftForever, 'Left'))
self.OpenLeftForever.clicked.connect(lambda: self.OpenLeft5ml.setDisabled(self.OpenLeftForever.isChecked()))
# Set up OpenRightForever button
self.OpenRightForever.clicked.connect(lambda: self._ToggleValve(self.OpenRightForever, 'Right'))
self.OpenRightForever.clicked.connect(lambda: self.OpenRight5ml.setDisabled(self.OpenRightForever.isChecked()))
# Set up OpenLeft5ml button
self.OpenLeft5ml.toggled.connect(lambda val: self._ToggleValve(self.OpenLeft5ml, 'Left'))
self.OpenLeft5ml.toggled.connect(lambda val: self.OpenLeftForever.setDisabled(val))
# Set up OpenRight5ml button
self.OpenRight5ml.toggled.connect(lambda val: self._ToggleValve(self.OpenRight5ml, 'Right'))
self.OpenRight5ml.toggled.connect(lambda val: self.OpenRightForever.setDisabled(val))

self.SaveLeft.clicked.connect(self._SaveLeft)
self.SaveRight.clicked.connect(self._SaveRight)
self.StartCalibratingLeft.clicked.connect(self._StartCalibratingLeft)
Expand Down Expand Up @@ -877,53 +900,52 @@ def _UpdateFigure(self):
self.ToInitializeVisual=0
self.PlotM._Update()

def _OpenLeftForever(self):
'''Open the left valve forever'''
self.MainWindow._ConnectBonsai()
if self.MainWindow.InitializeBonsaiSuccessfully==0:
return
if self.OpenLeftForever.isChecked():
# change button color
self.OpenLeftForever.setStyleSheet("background-color : green;")
self.MainWindow.Channel.LeftValue(float(1000) * 1000) # set the valve open time
self.MainWindow.Channel3.ManualWater_Left(int(1)) # set valve initially open
self.left_valve_open_timer.start()
else:
# change button color
self.OpenLeftForever.setStyleSheet("background-color : none")
self.left_valve_open_timer.stop()
# close the valve
self.MainWindow.Channel.LeftValue(float(0.001)*1000)
time.sleep(0.01)
self.MainWindow.Channel3.ManualWater_Left(int(1))
# set the default valve open time
time.sleep(0.01)
self.MainWindow.Channel.LeftValue(float(self.MainWindow.LeftValue.text())*1000)
def _ToggleValve(self, button, valve: Literal['Left', 'Right']):
"""
Toggle open/close state of specified valve and set up logic based on button pressed
:param button: button that was pressed
:param valve: which valve to open. Restricted to Right or Left
"""

def _OpenRightForever(self):
'''Open the right valve forever'''
self.MainWindow._ConnectBonsai()
if self.MainWindow.InitializeBonsaiSuccessfully==0:
return
if self.OpenRightForever.isChecked():
# change button color
self.OpenRightForever.setStyleSheet("background-color : green;")
self.MainWindow.Channel.RightValue(float(1000) * 1000) # set the valve open time
self.MainWindow.Channel3.ManualWater_Right(int(1)) # set valve initially open
self.right_valve_open_timer.start()

else:
set_valve_time = getattr(self.MainWindow.Channel, f'{valve}Value')
toggle_valve_state = getattr(self.MainWindow.Channel3, f'ManualWater_{valve}')
open_timer = getattr(self, f'{valve.lower()}_open_timer')
close_timer = getattr(self, f'{valve.lower()}_close_timer')
text_timer = getattr(self, f'{valve.lower()}_text_timer')

if button.isChecked(): # open valve
button.setStyleSheet("background-color : green;")
set_valve_time(float(1000) * 1000) # set the valve open time to max value
toggle_valve_state(int(1)) # set valve initially open

if button.text() == f'Open {valve.lower()} 5ml': # set up additional logic to only open for 5ml
five_ml_time_ms = round(self._VolumeToTime(5000, valve) * 1000) # calculate time for valve to stay open
close_timer.setInterval(five_ml_time_ms) # set interval of valve close time to be five_ml_time_ms
close_timer.setSingleShot(True) # only trigger once when 5ml has been expelled
text_timer.start() # start timer to update text
close_timer.start()

open_timer.start()

else: # close open valve
# change button color
self.OpenRightForever.setStyleSheet("background-color : none")
self.right_valve_open_timer.stop()
button.setStyleSheet("background-color : none")
open_timer.stop()
if f'Open {valve.lower()} 5ml' in button.text():
close_timer.stop()
text_timer.stop()
button.setText(f'Open {valve.lower()} 5ml')

# close the valve
self.MainWindow.Channel.RightValue(float(0.001)*1000)
time.sleep(0.01)
self.MainWindow.Channel3.ManualWater_Right(int(1))
# set the default valve open time
toggle_valve_state(int(1))

# reset the default valve open time
time.sleep(0.01)
self.MainWindow.Channel.RightValue(float(self.MainWindow.RightValue.text())*1000)
set_valve_time(float(getattr(self.MainWindow, f'{valve}Value').text())*1000)

def reopen_valve(self, valve: Literal['Left', 'Right']):
"""Function to reopen the right or left water line open. Valve must be open prior to calling this function.
Expand All @@ -940,9 +962,14 @@ def _TimeRemaining(self,i, cycles, opentime, interval):
seconds = int(np.ceil(np.mod(total_seconds,60)))
return '{}:{:02}'.format(minutes, seconds)

def _VolumeToTime(self,volume,valve):
# x = (y-b)/m
if hasattr(self.MainWindow, 'latest_fitting'):
def _VolumeToTime(self, volume, valve: Literal['Left', 'Right'] ):
"""
Function to return the amount of time(s) it takes for water line to flush specified volume of water (mg)
:param volume: volume to flush in mg
:param valve: string specifying right or left valve
"""
# x = (y-b)/m
if hasattr(self.MainWindow, 'latest_fitting') and self.MainWindow.latest_fitting != {}:
fit = self.MainWindow.latest_fitting[valve]
m = fit[0]
b = fit[1]
Expand Down
50 changes: 29 additions & 21 deletions src/foraging_gui/Foraging.py
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,7 @@ def _GetSettings(self):
'manifest'),
'auto_engage':True,
'clear_figure_after_save':True,
'add_default_project_name':True
}

# Try to load Settings_box#.csv
Expand Down Expand Up @@ -1186,6 +1187,7 @@ def _GetSettings(self):
self.save_each_trial = self.Settings['save_each_trial']
self.auto_engage = self.Settings['auto_engage']
self.clear_figure_after_save = self.Settings['clear_figure_after_save']
self.add_default_project_name = self.Settings['add_default_project_name']
if not is_absolute_path(self.project_info_file):
self.project_info_file = os.path.join(self.SettingFolder,self.project_info_file)
# Also stream log info to the console if enabled
Expand Down Expand Up @@ -3701,6 +3703,28 @@ def _set_metadata_enabled(self, enable: bool):
self.ID.setEnabled(enable)
self.Experimenter.setEnabled(enable)

def _set_default_project(self):
'''Set default project information'''
project_name = 'Behavior Platform'
logging.info('Setting Project name: {}'.format('Behavior Platform'))
projects = [self.Metadata_dialog.ProjectName.itemText(i)
for i in range(self.Metadata_dialog.ProjectName.count())]
index = np.where(np.array(projects) == 'Behavior Platform')[0]
if len(index) > 0:
index = index[0]
self.Metadata_dialog.ProjectName.setCurrentIndex(index)
self.Metadata_dialog._show_project_info()
else:
project_info = {
'Funding Institution': ['Allen Institute'],
'Grant Number': ['nan'],
'Investigators': ['Jeremiah Cohen'],
'Fundee': ['nan'],
}
self.Metadata_dialog.project_info = project_info
self.Metadata_dialog.ProjectName.addItems([project_name])
return project_name

def _Start(self):
'''start trial loop'''

Expand Down Expand Up @@ -3906,8 +3930,8 @@ def _Start(self):
logging.info('Setting IACUC Protocol: {}'.format(protocol))

# Set Project Name in metadata based on schedule
add_default=True
project_name = self._GetInfoFromSchedule(mouse_id, 'Project Name')
add_default = True
if project_name is not None:
projects = [self.Metadata_dialog.ProjectName.itemText(i)
for i in range(self.Metadata_dialog.ProjectName.count())]
Expand All @@ -3918,27 +3942,11 @@ def _Start(self):
self.Metadata_dialog._show_project_info()
logging.info('Setting Project name: {}'.format(project_name))
add_default = False
if add_default:
project_name = 'Behavior Platform'
logging.info('Setting Project name: {}'.format('Behavior Platform'))
projects = [self.Metadata_dialog.ProjectName.itemText(i)
for i in range(self.Metadata_dialog.ProjectName.count())]
index = np.where(np.array(projects) == 'Behavior Platform')[0]
if len(index) > 0:
index = index[0]
self.Metadata_dialog.ProjectName.setCurrentIndex(index)
self.Metadata_dialog._show_project_info()
else:
project_info = {
'Funding Institution': ['Allen Institute'],
'Grant Number': ['nan'],
'Investigators': ['Jeremiah Cohen'],
'Fundee': ['nan'],
}
self.Metadata_dialog.project_info = project_info
self.Metadata_dialog.ProjectName.addItems([project_name])
self.project_name = project_name

if self.add_default_project_name and add_default:
project_name=self._set_default_project()

self.project_name = project_name
self.session_run = True # session has been started

self.keyPressEvent(allow_reset=True)
Expand Down
2 changes: 1 addition & 1 deletion src/foraging_gui/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = "1.6.2"
__version__ = "1.6.4"

3 changes: 2 additions & 1 deletion src/setting_templates/ForagingSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
"go_cue_decibel_box1":73,
"go_cue_decibel_box2":73,
"go_cue_decibel_box3":73,
"go_cue_decibel_box4":73
"go_cue_decibel_box4":73,
"add_default_project_name":false
XX-Yin marked this conversation as resolved.
Show resolved Hide resolved
}