Skip to content

Commit

Permalink
simplify data saving
Browse files Browse the repository at this point in the history
  • Loading branch information
nulinspiratie committed Oct 7, 2024
1 parent af95bbe commit 120a259
Showing 1 changed file with 52 additions and 47 deletions.
99 changes: 52 additions & 47 deletions qualang_tools/control_panel/video_mode/video_mode.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from datetime import datetime
from pathlib import Path
from time import sleep
from typing import Optional, Union
from dash import dcc, html, Input, Output
from dash_extensions.enrich import DashProxy, dcc, html, Output, Input, BlockingCallbackTransform
Expand All @@ -15,16 +14,27 @@


class VideoMode:
"""
A class for visualizing and controlling data acquisition in video mode.
This class provides a dashboard interface for visualizing and controlling data acquisition in video mode.
It uses Dash for the web interface and Plotly for the heatmap visualization.
Attributes:
data_acquirer (BaseDataAcquirer): The data acquirer object that provides the data to be visualized.
save_path (Union[str, Path]): The path where data and images will be saved.
update_interval (float): The interval at which the data is updated in the dashboard (in seconds).
If the previous update was not finished in the given interval, the update will be skipped.
"""

def __init__(
self,
data_acquirer: BaseDataAcquirer,
image_save_path: Union[str, Path] = "./images",
data_save_path: Union[str, Path] = "./data",
update_interval: Optional[float] = 0.1,
save_path: Union[str, Path] = "./video_mode_output",
update_interval: float = 0.1,
):
self.data_acquirer = data_acquirer
self.image_save_path = Path(image_save_path)
self.data_save_path = Path(data_save_path)
self.save_path = Path(save_path)
self.paused = False
self._last_update_clicks = 0
self._last_save_clicks = 0
Expand Down Expand Up @@ -105,6 +115,24 @@ def _create_axis_layout(self, axis: str):
)

def create_layout(self):
"""
Create the layout for the video mode dashboard.
This method sets up the Dash layout for the video mode control panel. It includes:
- A graph to display the heatmap of acquired data
- Controls for X and Y parameters (offset, span, points)
- Buttons for pausing/resuming data acquisition and saving data
- Display for the current iteration count
- Input for setting the number of averages
The layout is designed to be responsive and user-friendly, with aligned input fields
and clear labeling. It uses a combination of Dash core components and HTML elements
to create an intuitive interface for controlling and visualizing the data acquisition
process.
Returns:
None: The method sets up the `self.app.layout` attribute but doesn't return anything.
"""
self.fig = xarray_to_plotly(self.data_acquirer.data_array)

# Modify the layout with CSS to left-align and adjust input size
Expand Down Expand Up @@ -138,35 +166,6 @@ def create_layout(self):
),
html.Div( # Integration + Averages
[
# html.Div( # Integration
# [
# html.Label(
# "Integration Time:",
# style={
# "text-align": "right",
# "white-space": "nowrap",
# "margin-right": "5px",
# },
# ),
# dcc.Input(
# id="integration-time",
# type="number",
# value=self.data_acquirer.integration_time * 1e6,
# min=1,
# debounce=True,
# style={"width": "40px", "text-align": "right"},
# ), # Integration time in microseconds
# html.Label(
# "µs",
# style={
# "text-align": "left",
# "white-space": "nowrap",
# "margin-left": "3px",
# },
# ),
# ],
# style={"display": "flex", "margin-bottom": "10px"},
# ),
html.Div(
[
html.Label(
Expand Down Expand Up @@ -341,20 +340,23 @@ def save_data(self, idx: Optional[int] = None):
- The data save path is created if it doesn't exist.
- The filename format is 'data_XXXX.h5', where XXXX is a four-digit index.
"""
if not self.data_save_path.exists():
self.data_save_path.mkdir(parents=True)
logging.info(f"Created directory: {self.data_save_path}")
data_save_path = self.save_path / "data"
logging.info(f"Attempting to save data to folder: {data_save_path}")

if not data_save_path.exists():
data_save_path.mkdir(parents=True)
logging.info(f"Created directory: {data_save_path}")

if idx is None:
idx = 1
while idx <= 9999 and (self.data_save_path / f"data_{idx}.h5").exists():
while idx <= 9999 and (data_save_path / f"data_{idx}.h5").exists():
idx += 1

if idx > 9999:
raise ValueError("Maximum number of data files (9999) reached. Cannot save more.")

filename = f"data_{idx}.h5"
filepath = self.data_save_path / filename
filepath = data_save_path / filename

if filepath.exists():
raise FileExistsError(f"File {filepath} already exists.")
Expand All @@ -380,17 +382,18 @@ def save_image(self):
- The image save path is created if it doesn't exist.
- The filename format is 'data_image_XXXX.png', where XXXX is a four-digit index.
"""
logging.info("Attempting to save image...")
if not self.image_save_path.exists():
self.image_save_path.mkdir(parents=True)
logging.info(f"Created directory: {self.image_save_path}")
image_save_path = self.save_path / "images"
logging.info(f"Attempting to save image to folder: {image_save_path}")
if not image_save_path.exists():
image_save_path.mkdir(parents=True)
logging.info(f"Created directory: {image_save_path}")

idx = 1
while idx <= 9999 and (self.image_save_path / f"data_image_{idx}.png").exists():
while idx <= 9999 and (image_save_path / f"data_image_{idx}.png").exists():
idx += 1
if idx <= 9999:
filename = f"data_image_{idx}.png"
filepath = self.image_save_path / filename
filepath = image_save_path / filename
self.fig.write_image(filepath)
logging.info(f"Image saved successfully: {filepath}")
else:
Expand All @@ -416,7 +419,9 @@ def save(self):
- The image is saved first, followed by the data.
- If data saving fails due to a FileExistsError, a warning is logged instead of raising an exception.
"""
logging.info("Attempting to save image and data...")
if not self.save_path.exists():
self.save_path.mkdir(parents=True)
logging.info(f"Created directory: {self.save_path}")

# Save image first
idx = self.save_image()
Expand Down

0 comments on commit 120a259

Please sign in to comment.