# pylint: disable=C0116,C0103,E0401,W0631
"""Miscellaneous useful functions.
In particular, methods for converting to and from plate coordinates.
"""
import numpy as np
from fuzzywuzzy import process
[docs]
def round_at(value, rounding=None):
"""Round value to the nearest rounding.
:param value: the value to round.
"""
if rounding is None:
return value
return np.round(value / rounding) * rounding
[docs]
def replace_nans_in_dict(dictionary, replace_by="null"):
"""Replace NaNs in a dictionary with a string.
:param dictionary: the dictionary
:type dictionary: dict
:param replace_by: replacement
:type replace_by: str
"""
for key, value in dictionary.items():
if isinstance(value, dict):
replace_nans_in_dict(value, replace_by=replace_by)
elif value is np.nan:
dictionary[key] = replace_by
[docs]
def human_seq_size(n):
"Return the given sequence as a human friendly 35b, 1.4k, 15k, etc."
if n < 1000:
return "%db" % n
if n < 10000:
return "%.1fk" % (n / 1000)
return "%dk" % np.round(n / 1000)
unit_factors = {
prefix + unit: factor
for unit in "glL"
for prefix, factor in [("", 1), ("m", 1e-3), ("u", 1e-6), ("n", 1e-9)]
}
volume_values_and_units = sorted(
[(value, unit) for (unit, value) in unit_factors.items() if unit.endswith("L")]
)
[docs]
def find_best_volume_unit(vols):
"""Find the best volume unit for a list of volumes."""
med = np.median(vols)
for value, unit in volume_values_and_units:
if (not unit.endswith("g")) and (med <= 999 * value):
return unit
return unit
[docs]
def human_volume(vol, unit="auto"):
"""Return a human-readable volume."""
if unit == "auto":
unit = find_best_volume_unit([vol])
vol = np.round(vol / unit_factors[unit], 2)
if int(vol) == vol:
return "%d %s" % (vol, unit)
return "%s %s" % (("%.02f" % vol).rstrip("0"), unit)
def dicts_to_columns(dicts):
return {key: [d[key] for d in dicts] for key in dicts[0]}
def did_you_mean(name, other_names, limit=5, min_score=50):
if isinstance(name, (list, tuple)):
return {
n: did_you_mean(n, other_names, limit=limit, min_score=min_score)
for n in name
}
results = process.extract(name, list(other_names), limit=limit)
return [e for (e, score) in results if score >= min_score]