class RampZMagHintsTheme: "RampBeadStatusTheme" name: str = "ramp.zmaghints" height: int = 80 columns: List[List] = dflt([["val", "Consensus", 160, "0.00"], ["err", "Uncertainty", 160, "0.00"], ["zmag", "Z magnet (mm)", 160, "0.00"]]) units: List[str] = dflt(["(µm)", "(% strand size)"]) rows: List[float] = dflt([50, 66, 80, 95]) @property def width(self) -> int: "the width of the widget" return sum(i[2] for i in self.columns) # pylint: disable=not-an-iterable
class RampZMagResultsTheme: "RampBeadStatusTheme" name: str = "ramp.zmageresults" step: float = .01 value: float = -.4 heights: Tuple[int, ...] = (48, 150) width: int = 500 title: str = "Loosing {bead:.3f} ± {err:.3f} {unit} with Zmag =" ranges: List[float] = dflt([.05, .1, .2, .5, 1.]) alpha = .5 color = 'yellow' units: List[str] = dflt(RampZMagHintsTheme().units) columns: List[List] = dflt([["closing", "Closing ≥", 40, "0%"], ["count", "Count", 40, "0"], ["percent", "(%)", 40, "0%"], ["beads", "Beads", 180, ""]])
class MessagesListWidgetTheme: "MessagesListWidgetTheme" name: str = "qc.messages" height: int = 150 labels: Dict[str, str] = dflt(NAMES) columns: List[List] = dflt([ ['bead', u'Bead', '0', 65], ['type', u'Type', '', (320-65)//3], ['cycles', u'Cycles', '0', (320-65)//3], ['message', u'Message', '', (320-65)//3] ]) @property def width(self) -> int: "return the full width" return sum([i[-1] for i in self.columns]) # pylint: disable=not-an-iterable
class QCHairpinSizeTheme: "RampBeadStatusTheme" name: str = "qc.hairpinsize" title: str = "Hairpins bin size" binsize: float = .1 binstart: float = .05 binend: float = 1. binstep: float = .05 headers: bool = False tableheight: int = 125 sliderheight: int = 48 columns: List[List] = dflt([ ["z", "Δz (µm)", 60, ""], ["count", "Count", 40, "0"], ["percent", "(%)", 40, ""], ["beads", "Beads", 180, ""] ]) @property def width(self) -> int: "return the full width" return sum(i[2] for i in self.columns) # pylint: disable=not-an-iterable def __post_init__(self): # pylint: disable=unsubscriptable-object cols = self.columns if not self.headers: cols[2][-1] = cols[0][-1] = "" else: if cols[2][-1] == "": cols[2][-1] = "0" if cols[0][-1] == "": cols[2][-1] = "0.00"
class PeakIDPathTheme: "PeakIDPathTheme" name: str = "hybridstat.peaks.idpath" title: str = "" dialogtitle: str = 'Select an id file path' placeholder: str = 'Id file path' filechecks: int = 500 width: int = 225 height: int = 32 tableerror: List[str] = dflt(['File extension must be .xlsx', 'warning'])
class PeaksStatsWidgetTheme: "PeaksStatsWidgetTheme" name: str = "hybridstat.peaks.stats" line: str = _LINE openhairpin: str = ' & open hairpin' orientation: str = '-+ ' style: Dict[str, Any] = dflt({}) lines: List[List[str]] = dflt([['Cycles', '.0f'], ['Stretch (base/µm)', '.3f'], ['Bias (µm)', '.4f'], ['σ[HF] (µm)', '.4f'], ['σ[Peaks] (µm)', '.4f'], ['Average Skew ', '.2f'], ['Peak count', '.0f'], ['Baseline (µm)', '.3f'], ['Singlestrand (µm)', '.3f'], ['Events per Cycle', '.1f'], ['Down Time Φ₅ (s)', '.1f'], ['Sites found', ''], ['Silhouette', '.1f'], ['reduced χ²', '.1f']]) height: int = 20 * 14 width: int = 230
class SequenceTickerTheme: "sequence ticker theme" name: str = "sequence.ticker" standoff: int = -2 grid: dict = dflt({ 'color': { 'dark': ('lightgray', 'lightgreen'), 'basic': ('gray', 'lightgreen') }, 'width': (1, 1), 'alpha': (.8, .8), 'dash': ('solid', 'solid') })
class QCBeadStatusTheme: "RampBeadStatusTheme" name: str = "qc.status" status: Dict[str, str] = dflt({i: i for i in ("ok", "fixed", "bad", "missing")}) tableheight: int = 102 headers: bool = False columns: List[List] = dflt([["status", "Status", 60, ""], ["count", "Count", 40, "0"], ["percent", "(%)", 40, ""], ["beads", "Beads", 180, ""]]) @property def width(self) -> int: "return the full width" return sum(i[2] for i in self.columns) # pylint: disable=not-an-iterable def __post_init__(self): cols = self.columns[2] # pylint: disable=unsubscriptable-object if not self.headers: cols[-1] = "" elif cols[-1] == "": cols[-1] = "0"
class PeakListTheme: "PeakListTheme" name: str = "hybridstat.peaks.list" height: int = 400 colwidth: int = 60 refid: str = '0.0000' columns: List[List[str]] = dflt( [['z', 'Z (µm)', '0.0000'], ['bases', 'Z (base)', '0.0'], ['id', 'Hairpin', '0'], ['orient', 'Strand', ''], ['distance', 'Distance', '0.0'], ['count', PeaksPlotTheme.xlabel, '0.0'], ['duration', PeaksPlotTheme.xtoplabel, '0.000'], ['sigma', 'σ (µm)', '0.0000'], ['skew', 'skew', '0.00']]) @property def width(self) -> int: "the table width" return self.colwidth * len(self.columns)
class TaskDescriptor: "Access to a task" _LABEL = '%({self.attrname}){self.fmt}' __NONE = type('_None', (), {}) label: str = "" fmt: str = "" keys: List[str] = dflt([]) attrname: str = "" def __post_init__(self): if not self.fmt: ix1, ix2 = self.label.rfind("%("), self.label.rfind(")") self.fmt = self.label[ix2 + 1:] self.keys = self.label[ix1 + 2:ix2].split(".") self.label = self.label[:ix1].strip() if isinstance(self.keys, str): self.keys = self.keys.split('.') if self.keys[0] == 'task': self.keys = self.keys[1:] if len(self.keys) == 2 and self.keys[-1] == 'disabled': self.keys = self.keys[:1] if len(self.keys) == 1: self.fmt = 'b' assert len(self.keys) >= 1 assert len(self.fmt) assert len(self.label) def __set_name__(self, _, name): self.attrname = name def __model(self, obj): return getattr(getattr(obj, '_model'), self.keys[0]) def get(self, obj, wherefrom="default"): """ Gets the attribute in the task. Use config = True to access the default value """ mdl = self.__model(obj) mdl = ( getattr(mdl, 'task', mdl) if wherefrom == "model" else mdl.configtask if wherefrom == "config" else mdl.defaultconfigtask) if len(self.keys) == 1: return False if mdl is None else not mdl.disabled if '|' not in self.fmt and 'o' in self.fmt: for key in self.keys[1:]: mdl = getattr(mdl, key, None) else: for key in self.keys[1:]: mdl = getattr(mdl, key) if self.fmt == 'b' and not isinstance(mdl, bool): return mdl is not None return mdl def getdefault(self, obj): """ Gets the attribute in the task. Use config = True to access the default value """ return self.get(obj) def __get__(self, obj, tpe): if obj is None: return self return self.get( obj, 'config' if self.__model(obj).task is None else 'model') def __set__(self, obj, val): outp = getattr(obj, '_get_output')() if len(self.keys) == 1: outp.setdefault(self.keys[0], {})['disabled'] = not val return tsk = self.__model(obj).tasktype if len(self.keys) == 2: mdl = getattr(tsk, self.keys[1]) if self.fmt == "b" and not isinstance(mdl, bool): val = deepcopy(mdl) if val else None outp.setdefault(self.keys[0], {})[self.keys[1]] = val return mdl = outp.setdefault(self.keys[0], {}).get(self.keys[1], self.__NONE) if mdl is self.__NONE: mdl = deepcopy(getattr(tsk, self.keys[1])) outp[self.keys[0]][self.keys[1]] = mdl for key in self.keys[2:-1]: mdl = getattr(mdl, key) attr = getattr(type(mdl)(), self.keys[-1]) if self.fmt == "b" and not isinstance(attr, bool): val = deepcopy(attr) if val else None setattr(mdl, self.keys[-1], val) def line(self) -> Tuple[str, str]: "return the line for this descriptor" return self.label, self._LABEL.format(self=self)