Skip to content

Renaming Run to Shot #85

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/source/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ API Reference
:maxdepth: 2

lyse_functions
run
shot
sequence
dataframe_utilities
analysis_subprocess
2 changes: 1 addition & 1 deletion docs/source/api/lyse_functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ Lyse Helper Functions
.. automodule:: lyse
:members:
:undoc-members:
:exclude-members: Run, Sequence
:exclude-members: Shot, Run, Sequence
6 changes: 3 additions & 3 deletions docs/source/api/run.rst → docs/source/api/shot.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Run
Shot
==========

.. autoclass:: lyse.Run
.. autoclass:: lyse.Shot
:members:
:undoc-members:
:inherited-members:
:show-inheritance:

.. automethod:: lyse.Run.__init__
.. automethod:: lyse.Shot.__init__
8 changes: 4 additions & 4 deletions docs/source/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ An analysis on a single shot
# Image attributes are also stored in this series:
w_x2 = ser['side','absorption','OD','Gaussian_XW']

# If we want actual measurement data, we'll have to instantiate a Run object:
run = Run(path)
# If we want actual measurement data, we'll have to instantiate a Shot object:
shot = Shot(path)

# Obtaining a trace:
t, mot_fluorecence = run.get_trace('mot fluorecence')
t, mot_fluorecence = shot.get_trace('mot fluorecence')

# Now we might do some analysis on this data. Say we've written a
# linear fit function (or we're calling some other libaries linear
Expand All @@ -51,7 +51,7 @@ An analysis on a single shot

# We might wish to save this result so that we can compare it across
# shots in a multishot analysis:
run.save_result('mot loadrate', c)
shot.save_result('mot loadrate', c)


An analysis on multiple shots
Expand Down
2 changes: 1 addition & 1 deletion docs/source/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Introduction

**Lyse** is a data analysis system which gets *your code* running on experimental data as it is acquired. It is fundamenally based around the ideas of experimental *shots* and analysis *routines*. A shot is one trial of an experiment, and a routine is a ``Python`` script, written by you, that does something with the measurement data from one or more shots.

Analysis routines can be either *single-shot* or *multi-shot*. This determines what data and functions are available to your code when it runs. A single-shot routine has access to the data from only one shot, and functions available for saving results only to the hdf5 file for that shot. A a multi-shot routine has access to the entire dataset from all the runs that are currently loaded into **lyse**, and has functions available for saving results to an hdf5 file which does not belong to any of the shots---it's a file that exists only to save the "meta results".
Analysis routines can be either *single-shot* or *multi-shot*. This determines what data and functions are available to your code when it runs. A single-shot routine has access to the data from only one shot, and functions available for saving results only to the hdf5 file for that shot. A a multi-shot routine has access to the entire dataset from all the shots that are currently loaded into **lyse**, and has functions available for saving results to an hdf5 file which does not belong to any of the shots---it's a file that exists only to save the "meta results".

Actually things are far less magical than that. The only enforced difference between a single shot routine and a multi-shot routine is a single variable provided to your code when **lyse** runs it. Your code runs in a perfectly clean ``Python`` environment with this one exception: a variable in the global namespace called ``path``, which is a path to an hdf5 file. If you have told **lyse** that your routine is a singleshot one, then this path will point to the hdf5 file for the current shot being analysed. On the other hand, if you've told **lyse** that your routine is a multishot one, then it will be the path to an h5 file that has been selected in **lyse** for saving results to.

Expand Down
84 changes: 60 additions & 24 deletions lyse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@

from lyse.dataframe_utilities import get_series_from_shot as _get_singleshot
from labscript_utils.dict_diff import dict_diff
import copy
import os
import socket
import pickle as pickle
import inspect
import sys
import threading
import warnings

import labscript_utils.h5_lock, h5py
from labscript_utils.labconfig import LabConfig
Expand Down Expand Up @@ -79,7 +81,7 @@ class _RoutineStorage(object):
def data(filepath=None, host='localhost', port=_lyse_port, timeout=5, n_sequences=None, filter_kwargs=None):
"""Get data from the lyse dataframe or a file.

This function allows for either extracting information from a run's hdf5
This function allows for either extracting information from a shots's hdf5
file, or retrieving data from lyse's dataframe. If `filepath` is provided
then data will be read from that file and returned as a pandas series. If
`filepath` is not provided then the dataframe in lyse, or a portion of it,
Expand All @@ -97,11 +99,11 @@ def data(filepath=None, host='localhost', port=_lyse_port, timeout=5, n_sequence
that method.

Args:
filepath (str, optional): The path to a run's hdf5 file. If a value
filepath (str, optional): The path to a shot's hdf5 file. If a value
other than `None` is provided, then this function will return a
pandas series containing data associated with the run. In particular
pandas series containing data associated with the shot. In particular
it will contain the globals, singleshot results, multishot results,
etc. that would appear in the run's row in the Lyse dataframe, but
etc. that would appear in the shot's row in the Lyse dataframe, but
the values will be read from the file rather than extracted from the
lyse dataframe. If `filepath` is `None, then this function will
instead return a section of the lyse dataframe. Note that if
Expand Down Expand Up @@ -203,10 +205,10 @@ def _rangeindex_to_multiindex(df, inplace):
df.sort_index(inplace=True)
return df

def globals_diff(run1, run2, group=None):
return dict_diff(run1.get_globals(group), run2.get_globals(group))
def globals_diff(shot1, shot2, group=None):
return dict_diff(shot1.get_globals(group), shot2.get_globals(group))

class Run(object):
class Shot(object):
"""A class for saving/retrieving data to/from a shot's hdf5 file.

This class implements methods that allow the user to retrieve data from a
Expand All @@ -229,9 +231,9 @@ def __init__(self,h5_path,no_write=False):

try:
if not self.no_write:
# The group where this run's results will be stored in the h5
# The group where this shot's results will be stored in the h5
# file will be the name of the python script which is
# instantiating this Run object. Iterate from innermost caller
# instantiating this Shot object. Iterate from innermost caller
# to outermost. The name of the script will be one frame in
# from analysis_subprocess.py.
analysis_subprocess_path = os.path.join(
Expand All @@ -256,7 +258,7 @@ def __init__(self,h5_path,no_write=False):
self.set_group(group)
except KeyError:
# sys.stderr.write('Warning: to write results, call '
# 'Run.set_group(groupname), specifying the name of the group '
# 'Shot.set_group(groupname), specifying the name of the group '
# 'you would like to save results to. This normally comes from '
# 'the filename of your script, but since you\'re in interactive '
# 'mode, there is no script name.\n')
Expand Down Expand Up @@ -284,7 +286,7 @@ def no_write(self):
def group(self):
"""str: The group in the hdf5 file in which results are saved by default.

When a `Run` instance is created from within a lyse singleshot or
When a `Shot` instance is created from within a lyse singleshot or
multishot routine, `group` will be set to the name of the running
routine. If created from outside a lyse script it will be set to `None`.
To change the default group for saving results, use the `set_group()`
Expand Down Expand Up @@ -313,7 +315,7 @@ def _create_group_if_not_exists(self, h5_path, location, groupname):
create_group = True
if create_group:
if self.no_write:
msg = "Cannot create group; this run is read-only."
msg = "Cannot create group; this shot is read-only."
raise PermissionError(msg)
with h5py.File(h5_path, 'r+') as h5_file:
# Catch the ValueError raised if the group was created by
Expand Down Expand Up @@ -566,10 +568,10 @@ def save_results(self, *args, **kwargs):
for the optional arguments of `self.save_result()`.

Examples:
>>> run = Run('path/to/an/hdf5/file.h5') # doctest: +SKIP
>>> shot = Shot('path/to/an/hdf5/file.h5') # doctest: +SKIP
>>> a = 5
>>> b = 2.48
>>> run.save_results('result', a, 'other_result', b, overwrite=False) # doctest: +SKIP
>>> shot.save_results('result', a, 'other_result', b, overwrite=False) # doctest: +SKIP
"""
names = args[::2]
values = args[1::2]
Expand Down Expand Up @@ -703,12 +705,25 @@ def globals_groups(self):
except KeyError:
return []

def globals_diff(self, other_run, group=None):
return globals_diff(self, other_run, group)
def globals_diff(self, other_shot, group=None):
return globals_diff(self, other_shot, group)


class Sequence(Run):
def __init__(self, h5_path, run_paths, no_write=False):

class Run(Shot):
def __init__(self, *args, **kwargs):
msg = """The 'Run' class has been renamed to 'Shot' (but is otherwise
compatible). 'Run' will be removed in lyse v4.0. Please update your
analysis code to use the 'Shot' class.
"""
warnings.warn(dedent(msg), DeprecationWarning)
super().__init__(*args, **kwargs)

def globals_diff(self, other_run, group=None):
return globals_diff(self, other_run, group)


class Sequence(Shot):
def __init__(self, h5_path, shot_paths, no_write=False):
# Ensure file exists without affecting its last modification time if it
# already exists.
try:
Expand All @@ -724,15 +739,36 @@ def __init__(self, h5_path, run_paths, no_write=False):

super().__init__(h5_path, no_write=no_write)

if isinstance(run_paths, pandas.DataFrame):
run_paths = run_paths['filepath']
self.runs = {path: Run(path,no_write=True) for path in run_paths}
if isinstance(shot_paths, pandas.DataFrame):
shot_paths = shot_paths['filepath']
self.__shots = {path: Shot(path,no_write=True) for path in shot_paths}

@property
def runs(self):
"""This property is deprecated and will be removed in lyse v4.0

Use the :attr:`shots` attribute instead.
"""
msg = """The 'runs' attribute has been renamed to 'shots'. 'runs' will be
removed in lyse v4.0. Please update your analysis code to use the 'shots'
attribute.
"""
warnings.warn(dedent(msg), DeprecationWarning)
return copy.copy(self.__shots)

@property
def shots(self):
"""A dictionary containing :class:`Shot` instances.

The dictionary is keyed by filepaths specified in the :code:`shot_paths`
argument at instantiation time."""
return copy.copy(self.__shots)

def get_trace(self,*args):
return {path:run.get_trace(*args) for path,run in self.runs.items()}
return {path:shot.get_trace(*args) for path,shot in self.shots.items()}

def get_result_array(self,*args):
return {path:run.get_result_array(*args) for path,run in self.runs.items()}
return {path:shot.get_result_array(*args) for path,shot in self.shots.items()}

def get_traces(self,*args):
raise NotImplementedError('If you want to use this feature please ask me to implement it! -Chris')
Expand Down