Source code for bioarch.occupational_markers

#!/usr/bin/env python


import logging
from typing import Any, List, Union


import pandas as pd


from .left_right import LeftRight, Optional


logger = logging.getLogger(__name__)


[docs]class EnthesialMarker(object): """docstring for EnthesialMarker""" def __init__(self, value: Union[int, float], is_s: bool = False, is_oe: bool = False): self.value = float(value) # 0-3 in 0.5 increments self.is_s = is_s # 0.5-3 in 0.5 increments ie "s0.5" self.is_oe = is_oe # 0.5-3 in 0.5 increments ie "oe0.5" if self.is_s and self.is_oe: raise ValueError('Can not be both "s" and "oe" EnthesialMarker') if self.is_s or self.is_oe: if self.value < 0.5 or self.value > 3: raise ValueError(f'Invalid EnthesialMarker value, s/oe should be within 0.5 to 3: {self.value}') else: if self.value < 0 or self.value > 3: raise ValueError(f'Invalid EnthesialMarker value, non s/oe should be within 0 to 3: {self.value}') if self.value % 0.5 != 0.0: raise ValueError(f'Invalid EnthesialMarker value, not a 0.5 increment: {self.value}')
[docs] @staticmethod def parse(value: Any) -> Optional['EnthesialMarker']: if value is None: return None original_value = value is_s = False is_oe = False if isinstance(value, str): value = value.lower() if value.startswith('r'): value = value[1:] elif value.startswith('s'): is_s = True value = value[1:] elif value.startswith('oe'): # TODO: double check logic is_oe = True value = value[2:] elif value.startswith('0e'): # TODO: double check logic logger.warning('Bad EnthesialMarker: %s', value) is_oe = True value = value[2:] elif value.startswith('eo'): # TODO: double check logic logger.warning('Bad EnthesialMarker: %s', value) is_oe = True value = value[2:] elif value.startswith('o'): # TODO: double check logic logger.warning('Bad EnthesialMarker: %s', value) is_oe = True value = value[1:] elif value.startswith('e'): # TODO: double check logic logger.warning('Bad EnthesialMarker: %s', value) is_oe = True value = value[1:] try: value = float(value) except ValueError as e: raise ValueError(f'Unknown EnthesialMarker: "{original_value}"') from e if isinstance(value, int): value = float(value) if isinstance(value, float): if value > 6.0: value -= 6.0 is_oe = True if value > 3.0: value -= 3.0 is_s = True if not isinstance(value, float): raise ValueError(f'Unknown EnthesialMarker: "{original_value}"') return EnthesialMarker(value, is_s=is_s, is_oe=is_oe)
[docs] def as_num(self) -> float: val = self.value if self.is_oe: val += 6.0 if self.is_s: val += 3.0 return val
[docs] @staticmethod def avg(left: Optional['EnthesialMarker'], right: Optional['EnthesialMarker']) -> Optional['EnthesialMarker']: return left if right is None else right
def __eq__(self, other: Any): if other is None: return False if type(other) != type(self): # pylint: disable=C0123 raise NotImplementedError return ((self.value, self.is_s, self.is_oe) == (other.value, other.is_s, other.is_oe)) # pylint: disable=C0325 def __repr__(self): return f'{self.__class__.__name__}: {self}' def __str__(self): s = 's' if self.is_s else '' oe = 'oe' if self.is_oe else '' return f'{s}{oe}{self.value}'
[docs]class OccupationalMarkers(object): # pylint: disable=R0902 """docstring for OccupationalMarkers""" def __init__(self, c_trapezius: LeftRight[EnthesialMarker], c_o_deltiod: LeftRight[EnthesialMarker], c_o_pectoralis_major: LeftRight[EnthesialMarker], c_costoclaviclar_lig: LeftRight[EnthesialMarker], c_subcalvius: LeftRight[EnthesialMarker], c_conoid_lig: LeftRight[EnthesialMarker], c_trapezoid_lig: LeftRight[EnthesialMarker], s_pectoralis_minor: LeftRight[EnthesialMarker], s_levator_scapulae: LeftRight[EnthesialMarker], s_triceps_long_head: LeftRight[EnthesialMarker], s_trapezius: LeftRight[EnthesialMarker], h_subscapularis: LeftRight[EnthesialMarker], h_teres_major: LeftRight[EnthesialMarker], h_latissimus_dorsi: LeftRight[EnthesialMarker], h_pectoralis_major: LeftRight[EnthesialMarker], h_deltoid: LeftRight[EnthesialMarker], h_coracobrachialis: LeftRight[EnthesialMarker], h_supraspinatus: LeftRight[EnthesialMarker], h_infraspinatus: LeftRight[EnthesialMarker], h_teres_minor: LeftRight[EnthesialMarker], h_o_extensor: LeftRight[EnthesialMarker], h_o_flexor: LeftRight[EnthesialMarker], u_brachialis: LeftRight[EnthesialMarker], u_o_pronator_quadrataus: LeftRight[EnthesialMarker], u_triceps_brachii: LeftRight[EnthesialMarker], u_anconeus: LeftRight[EnthesialMarker], u_o_supinator: LeftRight[EnthesialMarker], r_biceps_brachii: LeftRight[EnthesialMarker], r_supinator: LeftRight[EnthesialMarker], r_pronator_teres: LeftRight[EnthesialMarker], r_pronator_quadratus: LeftRight[EnthesialMarker], r_brachoradialis: LeftRight[EnthesialMarker], f_gluteus_minimus: LeftRight[EnthesialMarker], f_gluteus_medius: LeftRight[EnthesialMarker], f_piriformus: LeftRight[EnthesialMarker], f_obturator_internus: LeftRight[EnthesialMarker], f_obturator_externus: LeftRight[EnthesialMarker], f_quadratis_femoris: LeftRight[EnthesialMarker], f_ilioposas: LeftRight[EnthesialMarker], f_gluteus_maximus: LeftRight[EnthesialMarker], f_pectineus: LeftRight[EnthesialMarker], f_o_vastus_medialis: LeftRight[EnthesialMarker], f_o_vastus_lateralis: LeftRight[EnthesialMarker], f_adductor_magnus: LeftRight[EnthesialMarker], f_o_gastrocnemius: LeftRight[EnthesialMarker], f_o_plantaris: LeftRight[EnthesialMarker], f_o_popliteus: LeftRight[EnthesialMarker], t_tensor_fascia_latae: LeftRight[EnthesialMarker], t_quadriceps: LeftRight[EnthesialMarker], t_sartorius: LeftRight[EnthesialMarker], t_gracilis: LeftRight[EnthesialMarker], t_semitendinosus: LeftRight[EnthesialMarker], t_o_tibialus_anterior: LeftRight[EnthesialMarker], t_biceps_femoris: LeftRight[EnthesialMarker], t_semimembranosus: LeftRight[EnthesialMarker], t_popliteus: LeftRight[EnthesialMarker], t_o_soleus: LeftRight[EnthesialMarker], t_o_tibialis_posterior: LeftRight[EnthesialMarker], t_o_flexor_digitorium: LeftRight[EnthesialMarker], f_biceps_femoris: LeftRight[EnthesialMarker], f_o_extensor_muscles: LeftRight[EnthesialMarker], f_o_flexor_muscles: LeftRight[EnthesialMarker], f_o_peroneus_longus: LeftRight[EnthesialMarker], f_o_peronus_brevis: LeftRight[EnthesialMarker], f_o_soleus: LeftRight[EnthesialMarker], p_quadriceps: LeftRight[EnthesialMarker], c_achilles: LeftRight[EnthesialMarker]): self.c_trapezius = c_trapezius self.c_o_deltiod = c_o_deltiod self.c_o_pectoralis_major = c_o_pectoralis_major self.c_costoclaviclar_lig = c_costoclaviclar_lig self.c_subcalvius = c_subcalvius self.c_conoid_lig = c_conoid_lig self.c_trapezoid_lig = c_trapezoid_lig self.s_pectoralis_minor = s_pectoralis_minor self.s_levator_scapulae = s_levator_scapulae self.s_triceps_long_head = s_triceps_long_head self.s_trapezius = s_trapezius self.h_subscapularis = h_subscapularis self.h_teres_major = h_teres_major self.h_latissimus_dorsi = h_latissimus_dorsi self.h_pectoralis_major = h_pectoralis_major self.h_deltoid = h_deltoid self.h_coracobrachialis = h_coracobrachialis self.h_supraspinatus = h_supraspinatus self.h_infraspinatus = h_infraspinatus self.h_teres_minor = h_teres_minor self.h_o_extensor = h_o_extensor self.h_o_flexor = h_o_flexor self.u_brachialis = u_brachialis self.u_o_pronator_quadrataus = u_o_pronator_quadrataus self.u_triceps_brachii = u_triceps_brachii self.u_anconeus = u_anconeus self.u_o_supinator = u_o_supinator self.r_biceps_brachii = r_biceps_brachii self.r_supinator = r_supinator self.r_pronator_teres = r_pronator_teres self.r_pronator_quadratus = r_pronator_quadratus self.r_brachoradialis = r_brachoradialis self.f_gluteus_minimus = f_gluteus_minimus self.f_gluteus_medius = f_gluteus_medius self.f_piriformus = f_piriformus self.f_obturator_internus = f_obturator_internus self.f_obturator_externus = f_obturator_externus self.f_quadratis_femoris = f_quadratis_femoris self.f_ilioposas = f_ilioposas self.f_gluteus_maximus = f_gluteus_maximus self.f_pectineus = f_pectineus self.f_o_vastus_medialis = f_o_vastus_medialis self.f_o_vastus_lateralis = f_o_vastus_lateralis self.f_adductor_magnus = f_adductor_magnus self.f_o_gastrocnemius = f_o_gastrocnemius self.f_o_plantaris = f_o_plantaris self.f_o_popliteus = f_o_popliteus self.t_tensor_fascia_latae = t_tensor_fascia_latae self.t_quadriceps = t_quadriceps self.t_sartorius = t_sartorius self.t_gracilis = t_gracilis self.t_semitendinosus = t_semitendinosus self.t_o_tibialus_anterior = t_o_tibialus_anterior self.t_biceps_femoris = t_biceps_femoris self.t_semimembranosus = t_semimembranosus self.t_popliteus = t_popliteus self.t_o_soleus = t_o_soleus self.t_o_tibialis_posterior = t_o_tibialis_posterior self.t_o_flexor_digitorium = t_o_flexor_digitorium self.f_biceps_femoris = f_biceps_femoris self.f_o_extensor_muscles = f_o_extensor_muscles self.f_o_flexor_muscles = f_o_flexor_muscles self.f_o_peroneus_longus = f_o_peroneus_longus self.f_o_peronus_brevis = f_o_peronus_brevis self.f_o_soleus = f_o_soleus self.p_quadriceps = p_quadriceps self.c_achilles = c_achilles
[docs] @staticmethod def empty() -> 'OccupationalMarkers': markers: List[LeftRight[EnthesialMarker]] = [LeftRight(None, None)] * 67 return OccupationalMarkers(*markers)
[docs] def to_pd_data_frame(self, index) -> pd.Series: data = { 'id': pd.Series([index]), } for key, value in self.__dict__.items(): data[f'{key}_left'] = value.left.as_num() if value.left else None data[f'{key}_right'] = value.right.as_num() if value.right else None value_avg = value.avg() data[f'{key}_avg'] = value_avg.as_num() if value_avg else None lr_df = pd.DataFrame.from_dict(data).set_index('id') for side in ('left', 'right', 'avg'): df = lr_df[[c for c in lr_df.columns if c.endswith(f'_{side}')]].copy() lr_df[f'min_{side}'] = df.min(axis=1) lr_df[f'max_{side}'] = df.max(axis=1) lr_df[f'mean_{side}'] = df.mean(axis=1) lr_df[f'count_{side}'] = df.count(axis=1) return lr_df
if __name__ == "__main__": raise RuntimeError('No main available')