Skip to content

Commit 2e38cb2

Browse files
authored
Register CLEM data in ISPyB (#689)
CLEM workflow changes * Broke 'register_preprocessing_results' workflow down into smaller functions for the sake of readability * Request for additional fluorescent-only and bright field-only composite images after data registration * Added logic to create data collection group, atlas, and grid square table entries for CLEM workflow * Included calculation of image dimensions (in pixels) as displayed on atlas * Removed registration of composite image file path from 'register_align_and_merge_results' workflow Other workflow changes * Added new optional fields into 'GridSquareParameters' Pydantic model to stored scaled down information about the grid squares being registered * Migrated logic for rescaling grid square values into the 'flush_spa_preprocess' workflow instead, so that the grid square registration and updating functions just register the values as-is Database changes * Linked 'CLEMImageSeries' to 'DataCollectionGroup' and 'GridSquare' * Added new columns to 'CLEMImageSeries' to store glob search string for image stacks and composite images; information on data collection group, grid square, and atlas; and resolution, shape, size scale, and location information * Removed deprecated columns from 'CLEMImageSeries' Tests * Added tests for the 'register_preprocessing_results' workflow
1 parent f91762e commit 2e38cb2

File tree

7 files changed

+825
-153
lines changed

7 files changed

+825
-153
lines changed

src/murfey/server/ispyb.py

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,11 @@ def do_insert_atlas(self, record: Atlas):
153153
return {"success": False, "return_value": None}
154154

155155
def do_update_atlas(
156-
self, atlas_id: int, atlas_image: str, pixel_size: float, slot: int
156+
self,
157+
atlas_id: int,
158+
atlas_image: str,
159+
pixel_size: float,
160+
slot: int | None,
157161
):
158162
try:
159163
with ISPyBSession() as db:
@@ -190,34 +194,14 @@ def do_insert_grid_square(
190194
grid_square_parameters.readout_area_x
191195
/ grid_square_parameters.thumbnail_size_x
192196
)
193-
grid_square_parameters.height = (
194-
int(grid_square_parameters.height / 7.8)
195-
if grid_square_parameters.height
196-
else None
197-
)
198-
grid_square_parameters.width = (
199-
int(grid_square_parameters.width / 7.8)
200-
if grid_square_parameters.width
201-
else None
202-
)
203-
grid_square_parameters.x_location = (
204-
int(grid_square_parameters.x_location / 7.8)
205-
if grid_square_parameters.x_location
206-
else None
207-
)
208-
grid_square_parameters.y_location = (
209-
int(grid_square_parameters.y_location / 7.8)
210-
if grid_square_parameters.y_location
211-
else None
212-
)
213197
record = GridSquare(
214198
atlasId=atlas_id,
215199
gridSquareLabel=grid_square_id,
216200
gridSquareImage=grid_square_parameters.image,
217-
pixelLocationX=grid_square_parameters.x_location,
218-
pixelLocationY=grid_square_parameters.y_location,
219-
height=grid_square_parameters.height,
220-
width=grid_square_parameters.width,
201+
pixelLocationX=grid_square_parameters.x_location_scaled,
202+
pixelLocationY=grid_square_parameters.y_location_scaled,
203+
height=grid_square_parameters.height_scaled,
204+
width=grid_square_parameters.width_scaled,
221205
angle=grid_square_parameters.angle,
222206
stageLocationX=grid_square_parameters.x_stage_position,
223207
stageLocationY=grid_square_parameters.y_stage_position,
@@ -242,7 +226,7 @@ def do_update_grid_square(
242226
):
243227
try:
244228
with ISPyBSession() as db:
245-
grid_square = (
229+
grid_square: GridSquare = (
246230
db.query(GridSquare)
247231
.filter(GridSquare.gridSquareId == grid_square_id)
248232
.one()
@@ -258,18 +242,18 @@ def do_update_grid_square(
258242
)
259243
if grid_square_parameters.image:
260244
grid_square.gridSquareImage = grid_square_parameters.image
261-
if grid_square_parameters.x_location:
262-
grid_square.pixelLocationX = int(
263-
grid_square_parameters.x_location / 7.8
245+
if grid_square_parameters.x_location_scaled:
246+
grid_square.pixelLocationX = (
247+
grid_square_parameters.x_location_scaled
264248
)
265-
if grid_square_parameters.y_location:
266-
grid_square.pixelLocationY = int(
267-
grid_square_parameters.y_location / 7.8
249+
if grid_square_parameters.y_location_scaled:
250+
grid_square.pixelLocationY = (
251+
grid_square_parameters.y_location_scaled
268252
)
269-
if grid_square_parameters.height is not None:
270-
grid_square.height = int(grid_square_parameters.height / 7.8)
271-
if grid_square_parameters.width is not None:
272-
grid_square.width = int(grid_square_parameters.width / 7.8)
253+
if grid_square_parameters.height_scaled is not None:
254+
grid_square.height = grid_square_parameters.height_scaled
255+
if grid_square_parameters.width_scaled is not None:
256+
grid_square.width = grid_square_parameters.width_scaled
273257
if grid_square_parameters.angle:
274258
grid_square.angle = grid_square_parameters.angle
275259
if grid_square_parameters.x_stage_position:

src/murfey/util/db.py

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ class CLEMImageMetadata(SQLModel, table=True): # type: ignore
230230

231231
class CLEMImageSeries(SQLModel, table=True): # type: ignore
232232
"""
233-
Database recording the individual files associated with a series, which are to be
233+
Database recording the files and metadata associated with a series, which are to be
234234
processed together as a group. These files could stem from a parent LIF file, or
235235
have been compiled together from individual TIFF files.
236236
"""
@@ -239,6 +239,7 @@ class CLEMImageSeries(SQLModel, table=True): # type: ignore
239239
series_name: str = Field(
240240
index=True
241241
) # Name of the series, as determined from the metadata
242+
search_string: Optional[str] = Field(default=None) # Path for globbing with
242243

243244
session: Optional["Session"] = Relationship(
244245
back_populates="image_series"
@@ -247,6 +248,22 @@ class CLEMImageSeries(SQLModel, table=True): # type: ignore
247248
foreign_key="session.id", default=None, unique=False
248249
)
249250

251+
# Type of data (atlas/overview or grid square)
252+
data_type: Optional[str] = Field(default=None) # "atlas" or "grid_square"
253+
254+
# Link to data collection group
255+
data_collection_group: Optional["DataCollectionGroup"] = Relationship(
256+
back_populates="clem_image_series"
257+
)
258+
dcg_id: Optional[int] = Field(foreign_key="datacollectiongroup.id", default=None)
259+
dcg_name: Optional[str] = Field(default=None)
260+
261+
# Link to grid squares
262+
grid_square: Optional["GridSquare"] = Relationship(
263+
back_populates="clem_image_series"
264+
)
265+
grid_square_id: Optional[int] = Field(foreign_key="gridsquare.id", default=None)
266+
250267
# The parent LIF file this series originates from, if any
251268
parent_lif: Optional["CLEMLIFFile"] = Relationship(
252269
back_populates="child_series",
@@ -270,18 +287,27 @@ class CLEMImageSeries(SQLModel, table=True): # type: ignore
270287
default=None,
271288
)
272289

273-
# Databases of the image stacks that comprise this series
290+
# Image stack entries that are part of this series
274291
child_stacks: List["CLEMImageStack"] = Relationship(
275292
back_populates="parent_series",
276293
sa_relationship_kwargs={"cascade": "delete"},
277294
) # One to many
295+
number_of_members: Optional[int] = Field(default=None)
278296

279-
# Process checklist for series
280-
number_of_members: int = (
281-
0 # Expected number of image stacks belonging to this series
282-
)
297+
# Shape and resolution information
298+
pixels_x: Optional[int] = Field(default=None)
299+
pixels_y: Optional[int] = Field(default=None)
300+
pixel_size: Optional[float] = Field(default=None)
301+
units: Optional[str] = Field(default=None)
302+
303+
# Extent of the imaged area in real space
304+
x0: Optional[float] = Field(default=None)
305+
x1: Optional[float] = Field(default=None)
306+
y0: Optional[float] = Field(default=None)
307+
y1: Optional[float] = Field(default=None)
308+
309+
# Composite images
283310
composite_created: bool = False # Has a composite image been created?
284-
composite_image: Optional[str] = None # Full path to composite image
285311

286312

287313
class CLEMImageStack(SQLModel, table=True): # type: ignore
@@ -389,6 +415,10 @@ class DataCollectionGroup(SQLModel, table=True): # type: ignore
389415
back_populates="data_collection_group",
390416
sa_relationship_kwargs={"cascade": "delete"},
391417
)
418+
clem_image_series: List["CLEMImageSeries"] = Relationship(
419+
back_populates="data_collection_group",
420+
sa_relationship_kwargs={"cascade": "delete"},
421+
)
392422
notification_parameters: List["NotificationParameter"] = Relationship(
393423
back_populates="data_collection_group",
394424
sa_relationship_kwargs={"cascade": "delete"},
@@ -591,6 +621,9 @@ class GridSquare(SQLModel, table=True): # type: ignore
591621
pixel_size: Optional[float] = None
592622
image: str = ""
593623
session: Optional[Session] = Relationship(back_populates="grid_squares")
624+
clem_image_series: List["CLEMImageSeries"] = Relationship(
625+
back_populates="grid_square", sa_relationship_kwargs={"cascade": "delete"}
626+
)
594627
foil_holes: List["FoilHole"] = Relationship(
595628
back_populates="grid_square", sa_relationship_kwargs={"cascade": "delete"}
596629
)

src/murfey/util/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,19 @@ class Base(BaseModel):
128128
class GridSquareParameters(BaseModel):
129129
tag: str
130130
x_location: Optional[float] = None
131+
x_location_scaled: Optional[int] = None
131132
y_location: Optional[float] = None
133+
y_location_scaled: Optional[int] = None
132134
x_stage_position: Optional[float] = None
133135
y_stage_position: Optional[float] = None
134136
readout_area_x: Optional[int] = None
135137
readout_area_y: Optional[int] = None
136138
thumbnail_size_x: Optional[int] = None
137139
thumbnail_size_y: Optional[int] = None
138140
height: Optional[int] = None
141+
height_scaled: Optional[int] = None
139142
width: Optional[int] = None
143+
width_scaled: Optional[int] = None
140144
pixel_size: Optional[float] = None
141145
image: str = ""
142146
angle: Optional[float] = None

src/murfey/workflows/clem/register_align_and_merge_results.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ def register_align_and_merge_result(
8787
session_id=session_id,
8888
series_name=result.series_name,
8989
)
90-
clem_img_series.composite_image = str(result.composite_image)
9190
clem_img_series.composite_created = True
9291
murfey_db.add(clem_img_series)
9392
murfey_db.commit()

0 commit comments

Comments
 (0)