Workflow¶
These scripts provide examples for automating a specific workflow.
Automated bead catching: 1 bead¶
"""Automated bead catching: 1 bead"""
import bluelake as bl
match_score = bl.timeline["Tracking Match Score"]["Bead 1"]
bl.shutters.clear(1) # to get rid of any existing bead
bl.microstage.move_to("beads") # must match the label in the UI
bl.fluidics.open(1, 2, 3, 6) # list of valves to open matching the UI
match_threshold = 80 # % minimal match score
while match_score.latest_value < match_threshold:
# We only want to clear the trap if there's a bead there, so > 0% match
if 0 < match_score.latest_value < match_threshold:
print("Rejected bead with match score:", match_score.latest_value)
bl.shutters.clear(1) # bad bead, BAD bead
bl.pause(0.5) # seconds
bl.microstage.move_to("buffer")
bl.fluidics.close(1, 2, 3, 6)
Automated bead catching: 2 beads¶
"""Automated bead catching: 2 beads"""
import bluelake as bl
match_score1 = bl.timeline["Tracking Match Score"]["Bead 1"]
match_score2 = bl.timeline["Tracking Match Score"]["Bead 2"]
match_scores = [match_score1, match_score2]
target_shutters = [1, 2]
bl.shutters.clear(*target_shutters) # to get rid of any existing beads
bl.microstage.move_to("beads") # must match the label in the UI
bl.fluidics.open(1, 2, 3, 6) # list of valves to open matching the UI
# Note: `match_score1` does not map directly to trap 1. `match_score1` and `match_score2`
# sort beads from left to right, up to down. When `match_score1.latest_value > 0` we can't
# be sure whether that corresponds to the bead in trap 1 or in trap 2. So to catch 2 beads
# we need to make sure both are good or clear both traps even if just one is bad.
match_threshold = 80 # % minimal match score
while any(m.latest_value < match_threshold for m in match_scores):
if any(0 < m.latest_value < match_threshold for m in match_scores):
bl.shutters.clear(*target_shutters) # bad beads
bl.pause(1)
bl.microstage.move_to("buffer")
bl.fluidics.close(1, 2, 3, 6)
DNA fishing¶
"""Fish for DNA"""
import bluelake as bl
force1 = bl.timeline["Force LF"]["Trap 1"]
while force1.latest_value < 15: # [pN]
bl.mirror1.move_by(dx=-1.0) # [um]
bl.mirror1.move_by(dx=+1.0) # [um]
print("caught molecule")
bl.microstage.move_to("buffer")
bl.fluidics.stop_flow()
Catch 2 beads and fish for DNA¶
"""Catch 2 beads and then fish for DNA"""
import bluelake as bl
def catch_2_beads(match_threshold=80):
"""Catch 2 beads that satisfy the minimal match threshold in %"""
match_score1 = bl.timeline["Tracking Match Score"]["Bead 1"]
match_score2 = bl.timeline["Tracking Match Score"]["Bead 2"]
match_scores = [match_score1, match_score2]
target_shutters = [1, 2]
bl.shutters.clear(*target_shutters) # to get rid of any existing beads
bl.microstage.move_to("beads") # must match the label in the UI
bl.fluidics.open(1, 2, 3, 6) # list of valves to open matching the UI
while any(m.latest_value < match_threshold for m in match_scores):
if any(0 < m.latest_value < match_threshold for m in match_scores):
bl.shutters.clear(*target_shutters) # bad beads
bl.pause(1)
bl.microstage.move_to("buffer")
bl.fluidics.close(1, 2, 3, 6)
def goto_distance(target):
"""Move trap 1 until it reaches the `target` distance from trap 2"""
distance = bl.timeline["Distance"]["Distance 1"]
dx = distance.latest_value - target
while abs(dx) > 0.2: # um
if dx <= 0:
bl.mirror1.move_by(dx=+0.1)
else:
bl.mirror1.move_by(dx=-0.1)
dx = distance.latest_value - target
def fish_for_dna(min_distance_um, max_distance_um, force_threshold):
"""Oscillate trap 1 until the force reaches the given threshold"""
bl.microstage.move_to("DNA")
goto_distance(min_distance_um)
bl.fluidics.open(1, 2, 3, 6)
bl.pause(1)
bl.reset_force()
goto_distance(max_distance_um)
force2 = bl.timeline["Force LF"]["Trap 2"]
while force2.latest_value < force_threshold:
goto_distance(min_distance_um)
bl.reset_force()
goto_distance(max_distance_um)
bl.fluidics.close(1, 2, 3, 6)
bl.microstage.move_to("buffer")
goto_distance(min_distance_um)
bl.reset_force()
catch_2_beads()
fish_for_dna(min_distance_um=10, max_distance_um=10, force_threshold=10)
FRAP (fluorescence recovery after photobleaching)¶
"""FRAP scan sequence -- scan presets are set from the UI, this script just executes them
Note that the presets contain the scan volume and timings, but not the
laser power -- it's set separately from the script.
Instructions:
1. Set the confocal volume and timings for the initial scan and save it as
a preset called "reference".
2. Set a new confocal volume and timings and save as "bleach".
3. Save a final preset called "image" to observe the sample after bleaching.
4. Set the laser power for the 3 stages in script below.
5. Run the script.
"""
import bluelake as bl
def increment_frap_count():
"""Add or increment a FRAP counter for the timeline markers"""
if not hasattr(bl, "frap_count"):
bl.frap_count = 0
bl.frap_count += 1
increment_frap_count()
bl.timeline.mark_begin(f"FRAP {bl.frap_count}")
try:
# Scan 1:
# Before using this script you must save a scan preset and name it
# "reference" (or anything else that matches the `start_scan()` below).
bl.excitation.blue_laser.power_level = 15 # % power
# and/or: `excitation.red_laser.power_level = 20` # % power
bl.confocal.start_scan("reference")
bl.confocal.wait()
# Scan 2:
# As above, this starts a scan preset called "bleach". You must save
# this preset in the UI before starting the script.
bl.excitation.blue_laser.power_level = 90 # % power
bl.confocal.start_scan("bleach")
bl.confocal.wait()
# Scan 3:
# The previous two were single-frame scans, but this one is usually
# multi-frame (again, set this in the UI and save it). It can also
# be useful to increase the "Image time" in the UI. Effectively,
# this adds a pause between frames in order to avoid bleaching if
# the recovery is slow.
bl.excitation.blue_laser.power_level = 15 # % power
bl.confocal.start_scan("image")
bl.confocal.wait()
finally:
bl.timeline.mark_end()