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

Enhancement one #45

Merged
merged 12 commits into from
Jul 21, 2020
26 changes: 0 additions & 26 deletions lightsheet/boost.py

This file was deleted.

13 changes: 6 additions & 7 deletions lightsheet/gui/camera_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,16 +146,15 @@ def update_roi_info(self, width, height):
"Current frame dimensions are:\nHeight: {}\nWidth: {}".format(int(height), int(width)))

def update_camera_info(self):
triggered_frame_rate = self.state.get_triggered_frame_rate()
if triggered_frame_rate is not None:
frame_rate = self.state.get_triggered_frame_rate()
if frame_rate is not None:
if self.state.global_state == GlobalState.PAUSED:
self.lbl_camera_info.hide()
else:
self.lbl_camera_info.setStyleSheet("color: white")
expected_frame_rate = None
if self.state.global_state == GlobalState.PREVIEW:
frame_rate = self.state.current_camera_status.internal_frame_rate
self.lbl_camera_info.setText("Internal frame rate: {} Hz".format(round(frame_rate, 2)))
self.lbl_camera_info.setText("Camera frame rate: {} Hz".format(round(frame_rate, 2)))
if self.state.global_state == GlobalState.VOLUME_PREVIEW:
planes = self.state.volume_setting.n_planes - \
self.state.volume_setting.n_skip_start - self.state.volume_setting.n_skip_end
Expand All @@ -168,19 +167,19 @@ def update_camera_info(self):
self.lbl_camera_info.setText(
"\n".join(
[
"Camera frame rate: {} Hz".format(round(triggered_frame_rate, 2))
"Camera frame rate: {} Hz".format(round(frame_rate, 2))
]
+ (
["Camera is lagging behind. Decrease exposure, number of planes or frequency"]
if expected_frame_rate > (triggered_frame_rate * 1.1)
if expected_frame_rate > (frame_rate * 1.1)
else [
"Seems to follow well current speed"
]
)
)
)

if expected_frame_rate > (triggered_frame_rate * 1.1):
if expected_frame_rate > (frame_rate * 1.1):
Copy link
Member

Choose a reason for hiding this comment

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

this is all just a variable rename, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes just some code refactoring to make it less confusing

self.lbl_camera_info.setStyleSheet("color: red")
else:
self.lbl_camera_info.setStyleSheet("color: green")
Expand Down
11 changes: 6 additions & 5 deletions lightsheet/gui/main_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,26 +91,27 @@ def closeEvent(self, a0) -> None:
self.st.wrap_up()
a0.accept()

def refresh_param_values(self):
def refresh_param_values(self, omit_wid_camera=False):
# TODO should be possible with lightparam, when it's implemented there remove here
self.wid_laser.wid_settings.refresh_widgets()
self.wid_scan.wid_planar.refresh_widgets()
self.wid_status.wid_volume.wid_volume.refresh_widgets()
self.wid_status.wid_calibration.refresh_widgets()
self.wid_status.wid_single_plane.wid_singleplane.refresh_widgets()
self.wid_display.wid_display_settings.refresh_widgets()
self.wid_camera.wid_camera_settings.refresh_widgets()
if not omit_wid_camera:
self.wid_camera.wid_camera_settings.refresh_widgets()
self.wid_camera.set_roi()
self.wid_save_options.wid_save_options.refresh_widgets()
self.wid_camera.set_roi()
self.wid_save_options.set_locationbutton()

def check_end_experiment(self):
if self.st.saver.saver_stopped_signal.is_set():
self.st.toggle_experiment_state()
if self.st.pause_after:
self.wid_status.setCurrentIndex(0)
self.st.laser.set_current(0)
self.refresh_param_values()
self.wid_laser.btn_off.click()
self.refresh_param_values(omit_wid_camera=True)
self.wid_display.experiment_progress.hide()
self.st.saver.saver_stopped_signal.clear()

Expand Down
2 changes: 2 additions & 0 deletions lightsheet/gui/save_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ def set_locationbutton(self):
self.save_location_button.setStyleSheet(
"background-color:#b5880d; border-color:#fcc203"
)
self.state.save_settings.overwrite_save_folder = 1
else:
self.save_location_button.setText("Save in " + pathtext)
self.save_location_button.setStyleSheet("")
self.state.save_settings.overwrite_save_folder = 0
23 changes: 18 additions & 5 deletions lightsheet/gui/save_settings_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
QVBoxLayout,
QWidget,
QPushButton,
QFileDialog
QFileDialog,
QDialog,
QTextEdit
)
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtCore import pyqtSignal, Qt
from lightsheet.state import State
from pathlib import Path
from datetime import datetime
import markdown

DEFAULT_SETTIGNS_PATH = "C:/Users/portugueslab/lightsheet_settings"
DEFAULT_SETTINGS_PATH = "C:/Users/portugueslab/lightsheet_settings"


class SavingSettingsWidget(QWidget):
Expand All @@ -21,18 +24,28 @@ def __init__(self, st: State):
self.setLayout(QVBoxLayout())
self.btn_load = QPushButton("Load settings")
self.btn_save = QPushButton("Save settings")
self.btn_instructions = QPushButton("User guide")
f = open(r"../lightsheet_procedure.md")
self.html_markdown = markdown.markdown(f.read())
self.instructions = QTextEdit(self.html_markdown)
Copy link
Member

Choose a reason for hiding this comment

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

make sure this is not editable, so people don't get the mistaken impression that they can update the instructions from the GUI :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Indeed

self.instructions.setReadOnly(True)
self.popup_window = QDialog(None, Qt.WindowSystemMenuHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint)
self.layout().addWidget(self.btn_load)
self.layout().addWidget(self.btn_save)
self.layout().addWidget(self.btn_instructions)
self.popup_window.setLayout(QVBoxLayout())
self.popup_window.layout().addWidget(self.instructions)
self.btn_load.clicked.connect(self.load)
self.btn_save.clicked.connect(self.save)
self.btn_instructions.clicked.connect(self.popup_window.show)

def load(self):
file, _ = QFileDialog.getOpenFileName(None, "Open settings file", DEFAULT_SETTIGNS_PATH, "*.json")
file, _ = QFileDialog.getOpenFileName(None, "Open settings file", DEFAULT_SETTINGS_PATH, "*.json")
if Path(file).is_file():
self.state.restore_tree(file)
self.sig_params_loaded.emit()

def save(self):
pth = Path(DEFAULT_SETTIGNS_PATH)
pth = Path(DEFAULT_SETTINGS_PATH)
filename = datetime.now().strftime("%y%m%d %H%M%S.json")
self.state.save_tree(pth/filename)
26 changes: 24 additions & 2 deletions lightsheet/gui/scanning_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
QVBoxLayout,
QPushButton,
QLabel,
QCheckBox
QCheckBox,
QMessageBox
)
from PyQt5.QtCore import QTimer
from lightparam.gui import ParameterGui
Expand Down Expand Up @@ -56,13 +57,17 @@ def __init__(self, state, timer):
self.lbl_interplane_distance.setStyleSheet("color: yellow")

self.wid_wave = WaveformWidget(
waveform_queue=self.state.scanner.waveform_queue,
timer=self.timer,
state=self.state
)
self.wid_collapsible_wave = CollapsibleWidget(child=self.wid_wave, name="Piezo impulse-response waveform")
self.wid_collapsible_wave.toggle_collapse()

self.dialog_box = QMessageBox()
self.dialog_ok_button = self.dialog_box.addButton(self.dialog_box.Ok)
self.dialog_abort_button = self.dialog_box.addButton(self.dialog_box.Abort)
self.override_overwrite = False

self.layout().addWidget(self.wid_volume)
self.layout().addWidget(self.btn_start)
self.layout().addWidget(self.chk_pause)
Expand All @@ -77,6 +82,7 @@ def __init__(self, state, timer):

self.timer_scope_info.timeout.connect(self.update_alignment)
self.chk_pause.clicked.connect(self.change_pause_status)
self.dialog_ok_button.clicked.connect(self.overwrite_anyway)

self.chk_pause.click()

Expand Down Expand Up @@ -109,5 +115,21 @@ def change_experiment_state(self):
if self.state.experiment_state == ExperimentPrepareState.EXPERIMENT_STARTED:
# Here what happens if experiment is aborted
self.state.saver.saving_signal.clear()
elif self.state.save_settings.overwrite_save_folder == 1 and not self.override_overwrite:
self.overwrite_alert_popup()
self.override_overwrite = False
else:
self.state.toggle_experiment_state()

def overwrite_alert_popup(self):
self.dialog_box.setIcon(QMessageBox.Warning)
self.dialog_box.setWindowTitle("Overwrite alert!")
self.dialog_box.setText(
"You are overwriting an existing folder with data. \n\n "
"Press ok to start the experiment anyway or abort to change saving folder."
)
self.dialog_box.show()

def overwrite_anyway(self):
self.override_overwrite = True
self.change_experiment_state()
38 changes: 22 additions & 16 deletions lightsheet/gui/waveform_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
from queue import Empty
import numpy as np

color_plane = (166, 196, 240, 100)
color_current_plane = (100, 100, 240, 100)


class WaveformWidget(QWidget):
def __init__(self, waveform_queue, timer, state):
def __init__(self, timer, state):
super().__init__()
self.state = state
self.sample_rate = self.state.sample_rate
self.timer = timer
self.waveform_queue = waveform_queue
self.pulse_regions = []

self.plot_widget = pg.PlotWidget()
Expand All @@ -25,29 +27,33 @@ def __init__(self, waveform_queue, timer, state):
self.state.camera_settings.sig_param_changed.connect(self.update_pulses)

def update_pulses(self):
pulse_times = np.arange(
self.state.volume_setting.n_skip_start,
self.state.volume_setting.n_planes - self.state.volume_setting.n_skip_end
) / (self.state.volume_setting.frequency * self.state.volume_setting.n_planes)
pulse_times = self.state.calculate_pulse_times()

for region in range(len(self.pulse_regions)):
self.plot_widget.removeItem(self.pulse_regions[region])
self.pulse_regions = [None] * len(pulse_times)
for i_pulse, pulse in enumerate(pulse_times):
self.pulse_regions[i_pulse] = pg.LinearRegionItem(
values=(pulse, pulse + self.state.camera_settings.exposure / 1000),
movable=False,
brush=pg.mkBrush(
166, 196, 240, 100
if self.state.volume_setting.i_freeze - 1 == i_pulse:
self.pulse_regions[i_pulse] = pg.LinearRegionItem(
values=(pulse, pulse + self.state.camera_settings.exposure / 1000),
movable=False,
brush=pg.mkBrush(
*color_current_plane
)
)
else:
self.pulse_regions[i_pulse] = pg.LinearRegionItem(
values=(pulse, pulse + self.state.camera_settings.exposure / 1000),
movable=False,
brush=pg.mkBrush(
*color_plane
)
)
)
for line in self.pulse_regions[i_pulse].lines:
line.hide()
self.plot_widget.addItem(self.pulse_regions[i_pulse])

def update(self):
try:
current_waveform = self.waveform_queue.get(timeout=0.001)
current_waveform = self.state.get_waveform()
if current_waveform is not None:
self.plot_curve.setData(np.arange(len(current_waveform)) / self.sample_rate, current_waveform)
except Empty:
pass
24 changes: 23 additions & 1 deletion lightsheet/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ def __init__(self):
self.save_dir = Param(r"F:/Vilim", gui=False)
self.experiment_duration = Param(0, (0, 100_000), gui=False)
self.notification_email = Param("")
self.overwrite_save_folder = Param(0, (0, 1), gui=False, loadable=False)



class ScanningSettings(ParametrizedQt):
Expand Down Expand Up @@ -294,6 +296,7 @@ class State:
def __init__(self, sample_rate):
self.sample_rate = sample_rate
self.calibration_ref = None
self.waveform = None
self.stop_event = Event()
self.experiment_start_event = Event()
self.experiment_state = ExperimentPrepareState.PREVIEW
Expand Down Expand Up @@ -410,9 +413,15 @@ def send_scan_settings(self):
params = convert_volume_params(
self.planar_setting, self.volume_setting, self.calibration
)
if self.waveform is not None:
pulses = self.calculate_pulse_times() * self.sample_rate
try:
pulse_log = self.waveform[pulses.astype(int)]
self.all_settings["piezo_log"] = {"trigger": pulse_log.tolist()}
except IndexError:
pass

params.experiment_state = self.experiment_state

self.all_settings["scanning"] = params

self.scanner.parameter_queue.put(params)
Expand Down Expand Up @@ -502,6 +511,19 @@ def get_triggered_frame_rate(self):
except Empty:
return None

def get_waveform(self):
try:
self.waveform = self.scanner.waveform_queue.get(timeout=0.001)
return self.waveform
except Empty:
return None

def calculate_pulse_times(self):
return np.arange(
self.volume_setting.n_skip_start,
self.volume_setting.n_planes - self.volume_setting.n_skip_end
) / (self.volume_setting.frequency * self.volume_setting.n_planes)

def wrap_up(self):
self.stop_event.set()
self.laser.close()
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ pyvisa==1.10.1
pyzmq==18.1.0
QDarkStyle==2.7
yagmail==0.11.224
markdown==3.2.2
click