from collections import OrderedDict
from .CloneValidation import CloneValidation
[docs]
class Clone:
"""Gather all information necessary to validate a clone.
Parameters
----------
name : str
Name of the clone. Could be for instance a microplate well.
digestions : dict
A dictionary ``{digestion: CloneObservation}`` where ``digestion`` is
of the form ``('EcoRI', 'BamHI')``.
construct_id : str
ID of the construct to be validated. This is used to group clones
by construct in the validation reports.
"""
def __init__(self, name, digestions, construct_id=None):
"""Initialize."""
self.name = name
self.digestions = digestions
self.construct_id = construct_id
[docs]
def validate_bands(
self,
bands_by_digestion,
relative_tolerance=0.1,
min_band_cutoff=None,
max_band_cutoff=None,
):
"""Return a validation result (comparison of observed and expected).
The result is a CloneValidation object.
Parameters
----------
bands_by_digestion : dict
A dictionary ``{digestion: [bands]}`` where ``digestion`` is
of the form ``('EcoRI', 'BamHI')``, and bands is a list of band sizes.
relative_tolerance : float
Tolerance, as a ratio of the full ladder span. If =0.1, then the
discrepancy will have a value of 1 when a band's nearest
correspondent in the other pattern is more than 10% of the ladder
span apart.
min_band_cutoff : int, optional
Discrepancies involving at least one band below this minimal band
size will be ignored. By default, it will be set to the smallest
band size in the ladder.
max_band_cutoff : int, optional
Discrepancies involving at least one band above this minimum band
size will be ignored. By default, it will be corrected to the largest
band size in the ladder.
"""
for digestion, observation in self.digestions.items():
discrepancies = {
digestion: observation.patterns_discrepancy(
other_bands=bands_by_digestion[digestion],
relative_tolerance=relative_tolerance,
min_band_cutoff=min_band_cutoff,
max_band_cutoff=max_band_cutoff,
)
for digestion, observation in self.digestions.items()
}
return CloneValidation(self, bands_by_digestion, discrepancies=discrepancies)
@staticmethod
def from_bands_observations(
observations, constructs_map, digestions_map, clones_map=None
):
if isinstance(observations, (dict, OrderedDict)):
observations = list(observations.values())
if clones_map is None:
clones_map = {name: name for name in constructs_map}
clones = OrderedDict()
for obs in observations:
if obs.name not in clones_map:
continue
clone_name = clones_map[obs.name]
if clone_name not in clones:
clones[clone_name] = Clone(
name=clone_name,
construct_id=constructs_map.get(clone_name, "no_clone"),
digestions={},
)
digestion = digestions_map[obs.name]
clones[clone_name].digestions[digestion] = obs
return clones